Business-PayPal-API-0.76/000755 000765 000024 00000000000 13077411465 015130 5ustar00olafstaff000000 000000 Business-PayPal-API-0.76/auth.sample.3token000644 000765 000024 00000000277 13077411465 020504 0ustar00olafstaff000000 000000 Username = test1_api.mydomain.tld Password = XXXXXXXXXXXXXXXX Signature = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX SellerEmail = email-of-business-test-account@mydomain.tld Business-PayPal-API-0.76/auth.sample.cert000644 000765 000024 00000000277 13077411465 020236 0ustar00olafstaff000000 000000 Username = test1_api.mydomain.tld Password = myapipassword CertFile = /www/var/cert_key_pem.txt KeyFile = /www/var/cert_key_pem.txt SellerEmail = email-of-business-test-account@mydomain.tld Business-PayPal-API-0.76/Changes000644 000765 000024 00000013072 13077411465 016426 0ustar00olafstaff000000 000000 Revision history for Perl module Business::PayPal::API 0.76 2017-04-24 11:00:58-04:00 America/Toronto - Fix path to Salutation field in GetExpressCheckoutDetailsResponseDetails 0.75 2017-04-04 12:39:37-04:00 America/Toronto - Allow setting of proxy when connecting to PayPal. 0.74 2016-01-23 - Avoid depending on IPC::System::Simple 0.73 2015-11-06 - Set the types of the Address hashref in SetExpressCheckout (Marco Pessotto) - Add eg/get-transaction-details.pl and eg/search-transactions.pl (Olaf Alders) 0.72 2015-10-23 - Release non-trial version of 0.71_03 0.71_03 2015-10-12 - Adds IPC::System::Simple to prereqs 0.71_02 2015-10-09 - Merge in changes from Ron Phipps. - Reduce SOAP version requirement. - Protection eligibility support. - Merge in changes from Tomas Doran. - CPAN packaging enhancements. - Extract out more payer details from XML. (PayerName, NameSuffix, PayerCountry). - Fix https://rt.cpan.org/Public/Bug/Display.html?id=67386 - Options fields of GetTransactionDetails are now returned as a hash, containing the actual options data, rather than array of empty strings. - Default to a non-zero timeout https://rt.cpan.org/Ticket/Display.html?id=107638 and https://rt.cpan.org/Ticket/Display.html?id=105049 (Thanks to JT Smith) 0.70 2012-11-13 - First OALDERS release - Fixes RT #70424 (Syntax deprecated in perl v5.14) 0.68 2010-03-12 - First hembreed release - I've moved the module's scm to http://github.com/hembreed/Business-PayPal-API so others may share my pain. CPAN will be updated from there. - API.pm 1. Changed eq 'Success' to =~ /Success/ to accomodate variations introduced by PayPal. 2. Changed test for duplicates to test for defined variable first. This was causing errors in 5.10+ perl versions. - t/*t Changed test for Success in all test modules as above - t/RecurringPayments Corrected errors in type definitions and testing. Needs more work. - TransactionSearch Corrected test instructions and code to allow transaction searches using the transactionID. This works for some types of transactions but not others as per PayPal. It is the only way to get MassPayment information. 0.62 2009-07-28 - last SCOTTW release - getFields() returns an array ref if multiple values are returned from PayPal, otherwise it behaves as it always did, returning a non-ref scalar. - BillingAgreement information returned in ExpressCheckout - Fix GetTransactionDetails 'PII_SalesTax' parameter - Fix GetTransactionDetails to return multiple PaymentItems - Fix MassPay to use the correct UniqueID parameter - Add DoReferenceTransaction to RecurringPayments API - Lots of credit given to great folks with patches in API docs - Thanks everyone! I'm handing this module off to Danny Hembree for maintenance now. 0.61 2008-05-05 - timeout setting available - additional troubleshooting documentation (auth error handling, URL munging) - add shipto parameters - MaxAmount parameter take currencyID attribute (Sandbox) - add base for RecurringPayments (not working yet) 0.52 2007-09-27 - [API.pm] add three-token signature testing URI (Oliver Ready) - [DirectPayments.pm] add ShippingTotal field (patch: Michael Hendricks) - [VoidRequest.pm] documentation fixes for method call (Oliver Ready) - [ReauthorizationRequest.pm] documentation fixes for method call (Oliver Ready) 0.51 2007-08-29 - fix PayerStatus location in DOM, add AddressStatus element (patch: Michael Hendricks) 0.50 2007-05-21 - minor doc changes - new Mass Pay API module included 0.41 2007-05-15 - some minor documentation additions 0.40 2006-10-06 - version bump - using PayPal API version 2.0 - note about SSL requirements of LWP - minor documentation cleanup - DirectPayments tests added - New modules (with tests!) from Danny Hembree: AuthorizationRequest.pm CaptureRequest.pm ReauthorizationRequest.pm VoidRequest.pm - add acknowledgement and pointers to example code from Andy Spiegl and others 0.33 2006-07-05 - fix documentation regarding SetExpressCheckout (returns a hash, not a scalar). If you were following the code in the SYNOPSIS for ExpressCheckout and getting a token with '3/8' or '4/8', you should change the $token to %response, since SetExpressCheckout() returns a hash (big thanks to Andy Spiegl for finding this). 0.32 2006-07-03 - acknowledgements section - fix for 3-token auth 0.31 2006-06-28 - fix StateOrProvince typo [rt.cpan.org #20176] 0.30 2006-04-18 - added DirectPayments API by Daniel Hembree. Thanks Daniel! 0.23 2006-04-04 - typo fix - wrap soap call in eval for safety (if ssl neg. fails w/ paypal, it croaks) - version bump 0.22 2006-03-28 - documentation updates 0.21 2006-03-24 - fix fault printing - fix getFieldsList record population 0.20 2006-03-23 - allow subclass methods to be imported into API.pm namespace - add GetTransactionDetails API - add TransactionSearch API - getFieldList() for API.pm - minor debugging changes - documentation update for developers - note about using IO::Socket::SSL (don't) - initial checkin of API and subclasses - all tests working, documentation done - moved from Business::PayPal::WPP::ExpressCheckout - uses API.pm for authorization/authentication and other common functions Business-PayPal-API-0.76/CONTRIBUTING.md000644 000765 000024 00000001445 13077411465 017365 0ustar00olafstaff000000 000000 # SANDBOX TESTING To test this module type the following: WPP_TEST=auth.txt prove -lvr t Please notice that this module requires you have several things before you can test it: - a sandbox personal PayPal account - a sandbox business PayPal account - API credentials (either a certificate or signature) - auth.txt, which contains your API credentials Read PayPal's and this module's documentation to learn more about how to acquire PayPal sandbox credentials. If you do not set the WPP_TEST environment variable, sandbox tests will be skipped. The format of the authentication tokens file defined by WPP_TEST may be found in the Business::PayPal::API documentation under "TESTING". Sample auth.txt files may be found in 'auth.sample.3token' and 'auth.sample.cert' in this distribution. Business-PayPal-API-0.76/CONTRIBUTORS000644 000765 000024 00000001050 13077411465 017004 0ustar00olafstaff000000 000000 # BUSINESS-PAYPAL-API CONTRIBUTORS # This is the (likely incomplete) list of people who have helped make this distribution what it is, either via code contributions, patches, bug reports, help with troubleshooting, etc. A huge 'thank you' to all of them. * Andrew Maltsev * Daniel Hembree * Danny Hembree * Dave Lambley * Dave Lambley * David Steinbrunner * Gregory Oschwald * Marco Pessotto * Mohammad S Anwar * Neil Bowers * Olaf Alders * Ron Phipps * Tomas Doran (t0m) * William Lindley Business-PayPal-API-0.76/cpanfile000644 000765 000024 00000001454 13077411465 016640 0ustar00olafstaff000000 000000 requires "Carp" => "0"; requires "Data::Printer" => "0"; requires "SOAP::Lite" => "0.67"; requires "perl" => "5.008001"; requires "strict" => "0"; requires "warnings" => "0"; on 'test' => sub { requires "Cwd" => "0"; requires "ExtUtils::MakeMaker" => "0"; requires "File::Spec" => "0"; requires "List::AllUtils" => "0"; requires "Test::More" => "0"; requires "Test::Most" => "0"; requires "autodie" => "0"; requires "perl" => "5.008001"; }; on 'test' => sub { recommends "CPAN::Meta" => "2.120900"; }; on 'configure' => sub { requires "ExtUtils::MakeMaker" => "0"; requires "perl" => "5.008001"; }; on 'develop' => sub { requires "Test::CPAN::Changes" => "0.19"; requires "Test::Code::TidyAll" => "0.50"; requires "Test::More" => "0.88"; requires "Test::Spelling" => "0.12"; }; Business-PayPal-API-0.76/debian/000755 000765 000024 00000000000 13077411465 016352 5ustar00olafstaff000000 000000 Business-PayPal-API-0.76/dist.ini000644 000765 000024 00000000626 13077411465 016600 0ustar00olafstaff000000 000000 name = Business-PayPal-API author = Scott Wiersdorf author = Danny Hembree author = Bradley M. Kuhn license = Perl_5 copyright_holder = Scott Wiersdorf, Danny Hembree, Bradley M. Kuhn copyright_year = 2006-2017 version = 0.76 main_module = lib/Business/PayPal/API.pm [@Author::OALDERS] -remove = PodCoverageTests -remove = Test::Synopsis Business-PayPal-API-0.76/eg/000755 000765 000024 00000000000 13077411465 015523 5ustar00olafstaff000000 000000 Business-PayPal-API-0.76/INSTALL000644 000765 000024 00000002255 13077411465 016165 0ustar00olafstaff000000 000000 This is the Perl distribution Business-PayPal-API. Installing Business-PayPal-API is straightforward. ## Installation with cpanm If you have cpanm, you only need one line: % cpanm Business::PayPal::API If it does not have permission to install modules to the current perl, cpanm will automatically set up and install to a local::lib in your home directory. See the local::lib documentation (https://metacpan.org/pod/local::lib) for details on enabling it in your environment. ## Installing with the CPAN shell Alternatively, if your CPAN shell is set up, you should just be able to do: % cpan Business::PayPal::API ## Manual installation As a last resort, you can manually install it. Download the tarball, untar it, then build it: % perl Makefile.PL % make && make test Then install it: % make install If your perl is system-managed, you can create a local::lib in your home directory to install modules to. For details, see the local::lib documentation: https://metacpan.org/pod/local::lib ## Documentation Business-PayPal-API documentation is available as POD. You can run perldoc from a shell to read the documentation: % perldoc Business::PayPal::API Business-PayPal-API-0.76/lib/000755 000765 000024 00000000000 13077411465 015676 5ustar00olafstaff000000 000000 Business-PayPal-API-0.76/LICENSE000644 000765 000024 00000044045 13077411465 016144 0ustar00olafstaff000000 000000 This software is copyright (c) 2006-2017 by Scott Wiersdorf, Danny Hembree, Bradley M. Kuhn. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. Terms of the Perl programming language system itself a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" --- The GNU General Public License, Version 1, February 1989 --- This software is Copyright (c) 2006-2017 by Scott Wiersdorf, Danny Hembree, Bradley M. Kuhn. This is free software, licensed under: The GNU General Public License, Version 1, February 1989 GNU GENERAL PUBLIC LICENSE Version 1, February 1989 Copyright (C) 1989 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The license agreements of most software companies try to keep users at the mercy of those companies. By contrast, our General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. The General Public License applies to the Free Software Foundation's software and to any other program whose authors commit to using it. You can use it for your programs, too. When we speak of free software, we are referring to freedom, not price. Specifically, the General Public License is designed to make sure that you have the freedom to give away or sell copies of free software, that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of a such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must tell them their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any work containing the Program or a portion of it, either verbatim or with modifications. Each licensee is addressed as "you". 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this General Public License and to the absence of any warranty; and give any other recipients of the Program a copy of this General Public License along with the Program. You may charge a fee for the physical act of transferring a copy. 2. You may modify your copy or copies of the Program or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above, provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains the Program or any part thereof, either with or without modifications, to be licensed at no charge to all third parties under the terms of this General Public License (except that you may choose to grant warranty protection to some or all third parties, at your option). c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the simplest and most usual way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this General Public License. d) You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. Mere aggregation of another independent work with the Program (or its derivative) on a volume of a storage or distribution medium does not bring the other work under the scope of these terms. 3. You may copy and distribute the Program (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 1 and 2 above provided that you also do one of the following: a) accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Paragraphs 1 and 2 above; or, b) accompany it with a written offer, valid for at least three years, to give any third party free (except for a nominal charge for the cost of distribution) a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Paragraphs 1 and 2 above; or, c) accompany it with the information you received as to where the corresponding source code may be obtained. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form alone.) Source code for a work means the preferred form of the work for making modifications to it. For an executable file, complete source code means all the source code for all modules it contains; but, as a special exception, it need not include source code for modules which are standard libraries that accompany the operating system on which the executable file runs, or for standard header files or definitions files that accompany that operating system. 4. You may not copy, modify, sublicense, distribute or transfer the Program except as expressly provided under this General Public License. Any attempt otherwise to copy, modify, sublicense, distribute or transfer the Program is void, and will automatically terminate your rights to use the Program under this License. However, parties who have received copies, or rights to use copies, from you under this General Public License will not have their licenses terminated so long as such parties remain in full compliance. 5. By copying, distributing or modifying the Program (or any work based on the Program) you indicate your acceptance of this license to do so, and all its terms and conditions. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. 7. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of the license which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the license, you may choose any version ever published by the Free Software Foundation. 8. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to humanity, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19xx name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (a program to direct compilers to make passes at assemblers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice That's all there is to it! --- The Artistic License 1.0 --- This software is Copyright (c) 2006-2017 by Scott Wiersdorf, Danny Hembree, Bradley M. Kuhn. This is free software, licensed under: The Artistic License 1.0 The Artistic License Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: - "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. - "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. - "Copyright Holder" is whoever is named in the copyright or copyrights for the package. - "You" is you, if you're thinking about copying or distributing this Package. - "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) - "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as ftp.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. 7. C or perl subroutines supplied by you and linked into this Package shall not be considered part of this Package. 8. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End Business-PayPal-API-0.76/Makefile.PL000644 000765 000024 00000003106 13077411465 017102 0ustar00olafstaff000000 000000 # This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v6.008. use strict; use warnings; use 5.008001; use ExtUtils::MakeMaker; my %WriteMakefileArgs = ( "ABSTRACT" => "PayPal SOAP API client with sandbox support", "AUTHOR" => "Scott Wiersdorf , Danny Hembree , Bradley M. Kuhn ", "CONFIGURE_REQUIRES" => { "ExtUtils::MakeMaker" => 0 }, "DISTNAME" => "Business-PayPal-API", "LICENSE" => "perl", "MIN_PERL_VERSION" => "5.008001", "NAME" => "Business::PayPal::API", "PREREQ_PM" => { "Carp" => 0, "Data::Printer" => 0, "SOAP::Lite" => "0.67", "strict" => 0, "warnings" => 0 }, "TEST_REQUIRES" => { "Cwd" => 0, "ExtUtils::MakeMaker" => 0, "File::Spec" => 0, "List::AllUtils" => 0, "Test::More" => 0, "Test::Most" => 0, "autodie" => 0 }, "VERSION" => "0.76", "test" => { "TESTS" => "t/*.t t/advanced/*.t t/basic/*.t" } ); my %FallbackPrereqs = ( "Carp" => 0, "Cwd" => 0, "Data::Printer" => 0, "ExtUtils::MakeMaker" => 0, "File::Spec" => 0, "List::AllUtils" => 0, "SOAP::Lite" => "0.67", "Test::More" => 0, "Test::Most" => 0, "autodie" => 0, "strict" => 0, "warnings" => 0 ); unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) { delete $WriteMakefileArgs{TEST_REQUIRES}; delete $WriteMakefileArgs{BUILD_REQUIRES}; $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs; } delete $WriteMakefileArgs{CONFIGURE_REQUIRES} unless eval { ExtUtils::MakeMaker->VERSION(6.52) }; WriteMakefile(%WriteMakefileArgs); Business-PayPal-API-0.76/MANIFEST000644 000765 000024 00000002747 13077411465 016273 0ustar00olafstaff000000 000000 # This file was automatically generated by Dist::Zilla::Plugin::Manifest v6.008. CONTRIBUTING.md CONTRIBUTORS Changes INSTALL LICENSE MANIFEST META.json META.yml Makefile.PL README.md auth.sample.3token auth.sample.cert cpanfile debian/compat debian/control debian/copyright debian/rules dist.ini eg/get-transaction-details.pl eg/lib/Example/Role/Auth.pm eg/lib/Example/TransactionFetcher.pm eg/lib/Example/TransactionSearcher.pm eg/myapp.pl eg/paypal-checkout-example.pl eg/search-transactions.pl lib/Business/PayPal/API.pm lib/Business/PayPal/API/AuthorizationRequest.pm lib/Business/PayPal/API/CaptureRequest.pm lib/Business/PayPal/API/DirectPayments.pm lib/Business/PayPal/API/ExpressCheckout.pm lib/Business/PayPal/API/GetBalance.pm lib/Business/PayPal/API/GetTransactionDetails.pm lib/Business/PayPal/API/MassPay.pm lib/Business/PayPal/API/ReauthorizationRequest.pm lib/Business/PayPal/API/RecurringPayments.pm lib/Business/PayPal/API/RefundTransaction.pm lib/Business/PayPal/API/TransactionSearch.pm lib/Business/PayPal/API/VoidRequest.pm perlcriticrc perltidyrc t/00-report-prereqs.dd t/00-report-prereqs.t t/API.pl t/advanced/ExpressCheckout.t t/advanced/ExpressOrder.t t/advanced/GetTransactionDetails.t t/advanced/OptionFields.t t/advanced/RefundTransaction.t t/advanced/TransactionSearch.t t/author-pod-spell.t t/author-tidyall.t t/basic/Business-PayPal-API.t t/basic/DirectPayments.t t/basic/MassPay.t t/basic/RecurringPayments.t t/basic/SubscriptionPayments.t t/release-cpan-changes.t tidyall.ini Business-PayPal-API-0.76/META.json000644 000765 000024 00000005440 13077411465 016554 0ustar00olafstaff000000 000000 { "abstract" : "PayPal SOAP API client with sandbox support", "author" : [ "Scott Wiersdorf ", "Danny Hembree ", "Bradley M. Kuhn " ], "dynamic_config" : 0, "generated_by" : "Dist::Zilla version 6.008, CPAN::Meta::Converter version 2.150005", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Business-PayPal-API", "no_index" : { "directory" : [ "examples", "t", "xt" ] }, "prereqs" : { "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0", "perl" : "5.008001" } }, "develop" : { "requires" : { "Test::CPAN::Changes" : "0.19", "Test::Code::TidyAll" : "0.50", "Test::More" : "0.88", "Test::Spelling" : "0.12" } }, "runtime" : { "requires" : { "Carp" : "0", "Data::Printer" : "0", "SOAP::Lite" : "0.67", "perl" : "5.008001", "strict" : "0", "warnings" : "0" } }, "test" : { "recommends" : { "CPAN::Meta" : "2.120900" }, "requires" : { "Cwd" : "0", "ExtUtils::MakeMaker" : "0", "File::Spec" : "0", "List::AllUtils" : "0", "Test::More" : "0", "Test::Most" : "0", "autodie" : "0", "perl" : "5.008001" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/oalders/business-paypal-api/issues" }, "homepage" : "https://github.com/oalders/business-paypal-api", "repository" : { "type" : "git", "url" : "https://github.com/oalders/business-paypal-api.git", "web" : "https://github.com/oalders/business-paypal-api" } }, "version" : "0.76", "x_contributors" : [ "Andrew Maltsev ", "Daniel Hembree ", "Danny Hembree ", "Dave Lambley ", "Dave Lambley ", "David Steinbrunner ", "Gregory Oschwald ", "Marco Pessotto ", "Mohammad S Anwar ", "Neil Bowers ", "Olaf Alders ", "Ron Phipps ", "Tomas Doran (t0m) ", "William Lindley " ], "x_serialization_backend" : "Cpanel::JSON::XS version 3.0225" } Business-PayPal-API-0.76/META.yml000644 000765 000024 00000003266 13077411465 016410 0ustar00olafstaff000000 000000 --- abstract: 'PayPal SOAP API client with sandbox support' author: - 'Scott Wiersdorf ' - 'Danny Hembree ' - 'Bradley M. Kuhn ' build_requires: Cwd: '0' ExtUtils::MakeMaker: '0' File::Spec: '0' List::AllUtils: '0' Test::More: '0' Test::Most: '0' autodie: '0' perl: '5.008001' configure_requires: ExtUtils::MakeMaker: '0' perl: '5.008001' dynamic_config: 0 generated_by: 'Dist::Zilla version 6.008, CPAN::Meta::Converter version 2.150005' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Business-PayPal-API no_index: directory: - examples - t - xt requires: Carp: '0' Data::Printer: '0' SOAP::Lite: '0.67' perl: '5.008001' strict: '0' warnings: '0' resources: bugtracker: https://github.com/oalders/business-paypal-api/issues homepage: https://github.com/oalders/business-paypal-api repository: https://github.com/oalders/business-paypal-api.git version: '0.76' x_contributors: - 'Andrew Maltsev ' - 'Daniel Hembree ' - 'Danny Hembree ' - 'Dave Lambley ' - 'Dave Lambley ' - 'David Steinbrunner ' - 'Gregory Oschwald ' - 'Marco Pessotto ' - 'Mohammad S Anwar ' - 'Neil Bowers ' - 'Olaf Alders ' - 'Ron Phipps ' - 'Tomas Doran (t0m) ' - 'William Lindley ' x_serialization_backend: 'YAML::Tiny version 1.69' Business-PayPal-API-0.76/perlcriticrc000644 000765 000024 00000004405 13077411465 017543 0ustar00olafstaff000000 000000 severity = 3 verbose = 11 theme = core + pbp + bugs + maintenance + cosmetic + complexity + security + tests + moose exclude = Subroutines::ProhibitCallsToUndeclaredSubs [BuiltinFunctions::ProhibitStringySplit] severity = 3 [CodeLayout::RequireTrailingCommas] severity = 3 [ControlStructures::ProhibitCStyleForLoops] severity = 3 [InputOutput::RequireCheckedSyscalls] functions = :builtins exclude_functions = sleep severity = 3 [Moose::RequireCleanNamespace] modules = Moose Moose::Role MooseX::Role::Parameterized Moose::Util::TypeConstraints cleaners = namespace::autoclean [NamingConventions::Capitalization] package_exemptions = [A-Z]\w+|minFraud file_lexical_variables = [A-Z]\w+|[^A-Z]+ global_variables = :starts_with_upper scoped_lexical_variables = [A-Z]\w+|[^A-Z]+ severity = 3 # Given our code base, leaving this at 5 would be a huge pain [Subroutines::ProhibitManyArgs] max_arguments = 10 [RegularExpressions::ProhibitComplexRegexes] max_characters = 200 [RegularExpressions::ProhibitUnusualDelimiters] severity = 3 [Subroutines::ProhibitUnusedPrivateSubroutines] private_name_regex = _(?!build)\w+ skip_when_using = Moo::Role Moose::Role MooseX::Role::Parameterized Role::Tiny Test::Class::Moose::Role [TestingAndDebugging::ProhibitNoWarnings] allow = redefine [ValuesAndExpressions::ProhibitEmptyQuotes] severity = 3 [ValuesAndExpressions::ProhibitInterpolationOfLiterals] severity = 3 [ValuesAndExpressions::RequireUpperCaseHeredocTerminator] severity = 3 [Variables::ProhibitPackageVars] add_packages = Test::Builder [TestingAndDebugging::RequireUseStrict] [TestingAndDebugging::RequireUseWarnings] [-ControlStructures::ProhibitCascadingIfElse] [-ErrorHandling::RequireCarping] [-InputOutput::RequireBriefOpen] [-ValuesAndExpressions::ProhibitConstantPragma] # No need for /xsm everywhere [-RegularExpressions::RequireDotMatchAnything] [-RegularExpressions::RequireExtendedFormatting] [-RegularExpressions::RequireLineBoundaryMatching] [-Subroutines::ProhibitExplicitReturnUndef] # http://stackoverflow.com/questions/2275317/why-does-perlcritic-dislike-using-shift-to-populate-subroutine-variables [-Subroutines::RequireArgUnpacking] [-Subroutines::RequireFinalReturn] # "use v5.14" is more readable than "use 5.014" [-ValuesAndExpressions::ProhibitVersionStrings] Business-PayPal-API-0.76/perltidyrc000644 000765 000024 00000000330 13077411465 017230 0ustar00olafstaff000000 000000 --blank-lines-before-packages=0 --iterations=2 --no-outdent-long-comments -b -bar -boc -ci=4 -i=4 -l=78 -nolq -se -wbb="% + - * / x != == >= <= =~ !~ < > | & >= < = **= += *= &= <<= &&= -= /= |= >>= ||= .= %= ^= x=" Business-PayPal-API-0.76/README.md000644 000765 000024 00000045065 13077411465 016421 0ustar00olafstaff000000 000000 # NAME Business::PayPal::API - PayPal SOAP API client with sandbox support # VERSION version 0.76 # SYNOPSIS use Business::PayPal::API qw( ExpressCheckout GetTransactionDetails ); ## certificate authentication my $pp = Business::PayPal::API->new( Username => 'my_api1.domain.tld', Password => 'this_is_my_password', PKCS12File => '/path/to/cert.pkcs12', PKCS12Password => '(pkcs12 password)', sandbox => 1, ); ## PEM cert authentication my $pp = Business::PayPal::API->new( Username => 'my_api1.domain.tld', Password => 'this_is_my_password', CertFile => '/path/to/cert.pem', KeyFile => '/path/to/cert.pem', sandbox => 1, ); ## 3-token (Signature) authentication my $pp = Business::PayPal::API->new( Username => 'my_api1.domain.tld', Password => 'Xdkis9k3jDFk39fj29sD9', ## supplied by PayPal Signature => 'f7d03YCpEjIF3s9Dk23F2V1C1vbYYR3ALqc7jm0UrCcYm-3ksdiDwjfSeii', ## ditto sandbox => 1, ); my %response = $pp->SetExpressCheckout( ... ); # DESCRIPTION **Business::PayPal::API** supports both certificate authentication and the new 3-token "Signature" authentication. It also supports PayPal's development _sandbox_ for testing. See the **sandbox** parameter to **new()** below for details. **Business::PayPal::API** can import other **API** derived classes: use Business::PayPal::API qw( RefundTransaction ); This allows for much more concise and intuitive usage. For example, these two statements are equivalent: use Business::PayPal::API::RefundTransaction; my $pp = Business::PayPal::API::RefundTransaction->new( ... ); $pp->RefundTransaction( ... ); and more concisely: use Business::PayPal::API qw( RefundTransaction ); my $pp = Business::PayPal::API->new( ... ); $pp->RefundTransaction( ... ); The advantage of this becomes clear when you need to use multiple API calls in your program; this allows you to use the same object to invoke the various methods, instead of creating a new object for each subclass. Here is an example of a **API** object used to invoke various PayPal APIs with the same object: use Business::PayPal::API qw( GetTransactionDetails TransactionSearch RefundTransaction ); my $pp = Business::PayPal::API->new( ... ); my $records = $pp->TransactionSearch( ... ); my %details = $pp->GetTransactionDetails( ... ); my %resp = $pp->RefundTransaction( ... ); However, you may certainly use just the subclass if that's all you need. Every subclass should work as its own self-contained API. For details on **Business::PayPal::API::\*** subclasses, see each subclass's individual documentation. ## new Creates a new **Business::PayPal::API** object. A note about certificate authentication: PayPal (and this module) support either PKCS#12 certificate authentication or PEM certificate authentication. See options below. - **Username** Required. This is the PayPal API username, usually in the form of 'my\_api1.mydomain.tld'. You can find or create your API credentials by logging into PayPal (if you want to do testing, as you should, you should also create a developer sandbox account) and going to: My Account -> Profile -> API Access -> Request API Credentials Please see the _PayPal API Reference_ and _PayPal Sandbox User Guide_ for details on creating a PayPal business account and sandbox account for testing. - **Password** Required. If you use certificate authentication, this is the PayPal API password created when you setup your certificate. If you use 3-token (Signature) authentication, this is the password PayPal assigned you, along with the "API User Name" and "Signature Hash". - **Subject** Optional. This is used by PayPal to authenticate 3rd party billers using your account. See the documents in ["SEE ALSO"](#see-also). - **Signature** Required for 3-token (Signature) authentication. This is the "Signature Hash" you received when you did "Request API Credentials" in your PayPal Business Account. - **PKCS12File** Required for PKCS#12 certificate authentication, unless the **HTTPS\_PKCS12\_FILE** environment variable is already set. This contains the path to your private key for PayPal authentication. It is used to set the **HTTPS\_PKCS12\_FILE** environment variable. You may set this environment variable yourself and leave this field blank. - **PKCS12Password** Required for PKCS#12 certificate authentication, unless the **HTTPS\_PKCS12\_PASSWORD** environment variable is already set. This contains the PKCS#12 password for the key specified in **PKCS12File**. It is used to set the **HTTPS\_PKCS12\_PASSWORD** environment variable. You may set this environment variable yourself and leave this field blank. - **CertFile** Required for PEM certificate authentication, unless the HTTPS\_CERT\_FILE environment variable is already set. This contains the path to your PEM format certificate given to you from PayPal (and accessible in the same location that your Username and Password and/or Signature Hash are found) and is used to set the **HTTPS\_CERT\_FILE** environment variable. You may set this environment variable yourself and leave this field blank. You may combine both certificate and private key into one file and set **CertFile** and **KeyFile** to the same path. - **KeyFile** Required for PEM certificate authentication, unless the HTTPS\_KEY\_FILE environment variable is already set. This contains the path to your PEM format private key given to you from PayPal (and accessible in the same location that your Username and Password and/or Signature Hash are found) and is used to set the **HTTPS\_KEY\_FILE** environment variable. You may set this environment variable yourself and leave this field blank. You may combine both certificate and private key into one file and set **CertFile** and **KeyFile** to the same path. - **sandbox** Required. If set to true (default), **Business::PayPal::API** will connect to PayPal's development sandbox, instead of PayPal's live site. \*You must explicitly set this to false (0) to access PayPal's live site\*. If you use PayPal's development sandbox for testing, you must have already signed up as a PayPal developer and created a Business sandbox account and a Buyer sandbox account (and make sure both of them have **Verified** status in the sandbox). When testing with the sandbox, you will use different usernames, passwords, and certificates (if using certificate authentication) than you will when accessing PayPal's live site. Please see the PayPal documentation for details. See ["SEE ALSO"](#see-also) for references. PayPal's sandbox reference: [https://www.paypal.com/IntegrationCenter/ic\_sandbox.html](https://www.paypal.com/IntegrationCenter/ic_sandbox.html) - **proxy\_url** Optional. When set, the proxy at the specified URL will be used for outbound connections. - **timeout** Optional. Set the timeout in seconds. Defaults to 30 seconds. # NAME Business::PayPal::API - PayPal API # ERROR HANDLING Every API call should return an **Ack** response, whether _Success_, _Failure_, or otherwise (depending on the API call). If it returns any non-success value, you can find an _Errors_ entry in your return hash, whose value is an arrayref of hashrefs: [ { ErrorCode => 10002, LongMessage => "Invalid security header" }, { ErrorCode => 10030, LongMessage => "Some other error" }, ] You can retrieve these errors like this: %response = $pp->doSomeAPICall(); if( $response{Ack} ne 'Success' ) { for my $err ( @{$response{Errors}} ) { warn "Error: " . $err->{LongMessage} . "\n"; } } # TESTING Testing the **Business::PayPal::API::\*** modules requires that you create a file containing your PayPal Developer Sandbox authentication credentials (e.g., API certificate authentication or 3-Token authentication signature, etc.) and setting the **WPP\_TEST** environment variable to point to this file. The format for this file is as follows: Username = your_api.username.com Password = your_api_password and then ONE of the following options: a) supply 3-token authentication signature Signature = xxxxxxxxxxxxxxxxxxxxxxxx b) supply PEM certificate credentials CertFile = /path/to/cert_key_pem.txt KeyFile = /path/to/cert_key_pem.txt c) supply PKCS#12 certificate credentials PKCS12File = /path/to/cert.p12 PKCS12Password = pkcs12_password You may also set the appropriate HTTPS\_\* environment variables for b) and c) above (e.g., HTTPS\_CERT\_FILE, HTTPS\_KEY\_FILE, HTTPS\_PKCS12\_File, HTTPS\_PKCS12\_PASSWORD) in lieu of putting this information in a file. Then use "WPP\_TEST=my\_auth.txt make test" (for Bourne shell derivates) or "setenv WPP\_TEST my\_auth.txt && make test" (for C-shell derivates). See 'auth.sample.\*' files in this package for an example of the file format. Variables are case-\*sensitive\*. Any of the following variables are recognized: Username Password Signature Subject CertFile KeyFile PKCS12File PKCS12Password BuyerEmail Note: PayPal authentication may _fail_ if you set the certificate environment variables and attempt to connect using 3-token authentication (i.e., PayPal will use the first authentication credentials presented to it, and if they fail, the connection is aborted). # TROUBLESHOOTING ## PayPal Authentication Errors If you are experiencing PayPal authentication errors (e.g., "Security header is not valid", "SSL negotiation failed", etc.), you should make sure: * your username and password match those found in your PayPal Business account sandbox (this is not the same as your regular account). * you're not trying to use your live username and password for sandbox testing and vice versa. * you are using a US Business Sandbox account, you may also need to have "PayPal Payments Pro" enabled. * if the sandbox works but "live" does not, make sure you've turned off the 'sandbox' parameter correctly. Otherwise you'll be passing your PayPal sandbox credentials to PayPal's live site (which won't work). * if you use certificate authentication, your certificate must be the correct one (live or sandbox) depending on what you're doing. * if you use 3-Token authentication (i.e., Signature), you don't have any B parameters or B or B parameters in your constructor AND that none of the corresponding B environment variables are set. PayPal prefers certificate authentication since it occurs at connection time; if it fails, it will not try Signature authentication. Try clearing your environment: ## delete all HTTPS, SSL env delete $ENV{$_} for grep { /^(HTTPS|SSL)/ } keys %ENV; ## now put our own HTTPS env back in $ENV{HTTPS_CERT_FILE} = '/var/path/to/cert.pem'; ## create our paypal object my $pp = Business::PayPal::API->new(...) * if you have already loaded Net::SSLeay (or IO::Socket::SSL), then Net::HTTPS will prefer to use IO::Socket::SSL. I don't know how to get SOAP::Lite to work with IO::Socket::SSL (e.g., Crypt::SSLeay uses HTTPS_* environment variables), so until then, you can use this hack: local $IO::Socket::SSL::VERSION = undef; $pp->DoExpressCheckoutPayment(...); This will tell Net::HTTPS to ignore the fact that IO::Socket::SSL is already loaded for this scope and import Net::SSL (part of the Crypt::SSLeay package) for its 'configure()' method. * if you receive a message like "500 Can't connect to api.sandbox.paypal.com:443 (Illegal seek)", you'll need to make sure you have Crypt::SSLeay installed. It seems that other crypto modules don't do the certificate authentication quite as well, and LWP needs this to negotiate the SSL connection with PayPal. See the DEBUGGING section below for further hints. ## PayPal Munging URLs PayPal seems to be munging my URLs when it returns. SOAP::Lite follows the XML specification carefully, and encodes '&' and '<' characters before applying them to the SOAP document. PayPal does not properly URL-decode HTML entities '&amp;' and '&lt;' on the way back, so if you have an ampersand in your ReturnURL (for example), your customers will be redirected here: http://domain.tld/prog?arg1=foo&arg2=bar instead of here: http://domain.tld/prog?arg1=foo&arg2=bar Solution: Use CDATA tags to wrap your request: ReturnURL => '' You may also use semicolons instead of ampersands to separate your URL arguments: ReturnURL => 'http://domain.tld/prog?arg1=foo;arg2=bar' (thanks to Ollie Ready) # DEBUGGING You can see the raw SOAP XML sent and received by **Business::PayPal::API** by setting its **$Debug** variable: $Business::PayPal::API::Debug = 1; $pp->SetExpressCheckout( %args ); this will print the XML being sent, and dump a Perl data structure of the SOM received on STDERR (so check your error\_log if running inside a web server). If anyone knows how to turn a SOAP::SOM object into XML without setting **outputxml()**, let me know. # DEVELOPMENT If you are a developer wanting to extend **Business::PayPal::API** for other PayPal API calls, you can review any of the included modules (e.g., `RefundTransaction.pm` or `ExpressCheckout.pm`) for examples on how to do this until I have more time to write a more complete document. But in a nutshell: package Business::PayPal::API::SomeAPI; use 5.008001; use strict; use warnings; use SOAP::Lite 0.67; use Business::PayPal::API (); our @ISA = qw(Business::PayPal::API); our @EXPORT_OK = qw( SomeAPIMethod ); sub SomeAPIMethod { ... } Notice the **@EXPORT\_OK** variable. This is _not_ used by **Exporter** (we don't load Exporter at all): it is a special variable used by **Business::PayPal::API** to know which methods to import when **Business::PayPal::API** is run like this: use Business::PayPal::API qw( SomeAPI ); That is, **Business::PayPal::API** will import any subroutine into its own namespace from the **@EXPORT\_OK** array. Now it can be used like this: use Business::PayPal::API qw( SomeAPI ); my $pp = Business::PayPal::API->new( ... ); $pp->SomeAPIMethod( ... ); Of course, we also do a 'use Business::PayPal::API' in the module so that it can be used as a standalone module, if necessary: use Business::PayPal::API::SomeAPI; my $pp = Business::PayPal::API::SomeAPI->new( ... ); ## same args as superclass $pp->SomeAPIMethod( ... ); Adding the **@EXPORT\_OK** array in your module allows your module to be used in the most convenient way for the given circumstances. # EXAMPLES Andy Spiegl has kindly donated some example code (in German) for the ExpressCheckout API which may be found in the `eg` directory of this archive. Additional code examples for other APIs may be found in the `t` test directory. # EXPORT None by default. # CAVEATS Because I haven't figured out how to make SOAP::Lite read the WSDL definitions directly and simply implement those (help, anyone?), I have essentially recreated all of those WSDL structures internally in this module. (Note - 6 Oct 2006: SOAP::Lite's WSDL support is moving ahead, but slowly. The methods used by this API are considered "best practice" and are safe to use). As with all web services, if PayPal stop supporting their API endpoint, this module \*may stop working\*. You can help me keep this module up-to-date if you notice such an event occurring. Also, I didn't implement a big fat class hierarchy to make this module "academically" correct. You'll notice that I fudged colliding parameter names in **DoExpressCheckoutPayment** and similar fudging may be found in **GetTransactionDetails**. The good news is that this was written quickly, works, and is dead-simple to use. The bad news is that this sort of collision might occur again as more and more data is sent in the API (call it 'eBay API bloat'). I'm willing to take the risk this will be rare (PayPal--please make it rare!). # ACKNOWLEDGEMENTS Wherein I acknowledge all the good folks who have contributed to this module in some way: - Daniel P. Hembree for authoring the AuthorizationRequest, CaptureRequest, DirectPayments, ReauthorizationRequest, and VoidRequest extensions. - <jshiles at base16consulting daught com> for finding some API typos in the ExpressCheckout API - Andy Spiegl for giving me the heads-up on PayPal's new 3-token auth URI and for a sample command-line program (found in the 'eg' directory) demonstrating the ExpressCheckout API. - Ollie Ready <oready at drjays daught com> for the heads-up on the newest 3-token auth URI as well as a pile of documentation inconsistencies. - Michael Hendricks <michael at ndrix daught org> for a patch that adds ShippingTotal to the DirectPayments module. - Erik Aronesty, Drew Simpson via rt.cpan.org (#28596) for a patch to fix getFields() when multiple items are returned - Sebastian Böhm via email, SDC via rt.cpan.org (#38915) for a heads-up that the PayPal documentation for MassPay API was wrong regarding the _UniqueId_ parameter. - Jonathon Wright via email for patches for **ExpressCheckout** and **RecurringPayments** that implement _BillingAgreement_ and _DoReferenceTransaction_ API calls. # SEE ALSO [SOAP::Lite](https://metacpan.org/pod/SOAP::Lite), [PayPal User Guide](https://developer.paypal.com/webapps/developer/docs/classic/products), [PayPal API Reference](https://developer.paypal.com/webapps/developer/docs/api/overview) # AUTHORS - Scott Wiersdorf - Danny Hembree - Bradley M. Kuhn # COPYRIGHT AND LICENSE This software is copyright (c) 2006-2017 by Scott Wiersdorf, Danny Hembree, Bradley M. Kuhn. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. # POD ERRORS Hey! **The above document had some coding errors, which are explained below:** - Around line 205: '=item' outside of any '=over' - Around line 214: You forgot a '=back' before '=head1' Business-PayPal-API-0.76/t/000755 000765 000024 00000000000 13077411465 015373 5ustar00olafstaff000000 000000 Business-PayPal-API-0.76/tidyall.ini000644 000765 000024 00000000550 13077411465 017273 0ustar00olafstaff000000 000000 [PerlTidy] select = **/*.{pl,pm,t,psgi} ignore = .build/**/* ignore = Business-PayPal-API-*/**/* ignore = blib/**/* ignore = t/00-* ignore = t/author-* ignore = t/release-* ignore = t/zzz-* ignore = xt/**/* argv = --profile=$ROOT/perltidyrc [SortLines::Naturally] select = .gitignore select = .stopwords [UniqueLines] select = .gitignore select = .stopwords Business-PayPal-API-0.76/t/00-report-prereqs.dd000644 000765 000024 00000003470 13077411465 021117 0ustar00olafstaff000000 000000 do { my $x = { 'configure' => { 'requires' => { 'ExtUtils::MakeMaker' => '0', 'perl' => '5.008001' } }, 'develop' => { 'requires' => { 'Test::CPAN::Changes' => '0.19', 'Test::Code::TidyAll' => '0.50', 'Test::More' => '0.88', 'Test::Spelling' => '0.12' } }, 'runtime' => { 'requires' => { 'Carp' => '0', 'Data::Printer' => '0', 'SOAP::Lite' => '0.67', 'perl' => '5.008001', 'strict' => '0', 'warnings' => '0' } }, 'test' => { 'recommends' => { 'CPAN::Meta' => '2.120900' }, 'requires' => { 'Cwd' => '0', 'ExtUtils::MakeMaker' => '0', 'File::Spec' => '0', 'List::AllUtils' => '0', 'Test::More' => '0', 'Test::Most' => '0', 'autodie' => '0', 'perl' => '5.008001' } } }; $x; }Business-PayPal-API-0.76/t/00-report-prereqs.t000644 000765 000024 00000012714 13077411465 020774 0ustar00olafstaff000000 000000 #!perl use strict; use warnings; # This test was generated by Dist::Zilla::Plugin::Test::ReportPrereqs 0.025 use Test::More tests => 1; use ExtUtils::MakeMaker; use File::Spec; # from $version::LAX my $lax_version_re = qr/(?: undef | (?: (?:[0-9]+) (?: \. | (?:\.[0-9]+) (?:_[0-9]+)? )? | (?:\.[0-9]+) (?:_[0-9]+)? ) | (?: v (?:[0-9]+) (?: (?:\.[0-9]+)+ (?:_[0-9]+)? )? | (?:[0-9]+)? (?:\.[0-9]+){2,} (?:_[0-9]+)? ) )/x; # hide optional CPAN::Meta modules from prereq scanner # and check if they are available my $cpan_meta = "CPAN::Meta"; my $cpan_meta_pre = "CPAN::Meta::Prereqs"; my $HAS_CPAN_META = eval "require $cpan_meta; $cpan_meta->VERSION('2.120900')" && eval "require $cpan_meta_pre"; ## no critic # Verify requirements? my $DO_VERIFY_PREREQS = 1; sub _max { my $max = shift; $max = ( $_ > $max ) ? $_ : $max for @_; return $max; } sub _merge_prereqs { my ($collector, $prereqs) = @_; # CPAN::Meta::Prereqs object if (ref $collector eq $cpan_meta_pre) { return $collector->with_merged_prereqs( CPAN::Meta::Prereqs->new( $prereqs ) ); } # Raw hashrefs for my $phase ( keys %$prereqs ) { for my $type ( keys %{ $prereqs->{$phase} } ) { for my $module ( keys %{ $prereqs->{$phase}{$type} } ) { $collector->{$phase}{$type}{$module} = $prereqs->{$phase}{$type}{$module}; } } } return $collector; } my @include = qw( ); my @exclude = qw( ); # Add static prereqs to the included modules list my $static_prereqs = do 't/00-report-prereqs.dd'; # Merge all prereqs (either with ::Prereqs or a hashref) my $full_prereqs = _merge_prereqs( ( $HAS_CPAN_META ? $cpan_meta_pre->new : {} ), $static_prereqs ); # Add dynamic prereqs to the included modules list (if we can) my ($source) = grep { -f } 'MYMETA.json', 'MYMETA.yml'; if ( $source && $HAS_CPAN_META && (my $meta = eval { CPAN::Meta->load_file($source) } ) ) { $full_prereqs = _merge_prereqs($full_prereqs, $meta->prereqs); } else { $source = 'static metadata'; } my @full_reports; my @dep_errors; my $req_hash = $HAS_CPAN_META ? $full_prereqs->as_string_hash : $full_prereqs; # Add static includes into a fake section for my $mod (@include) { $req_hash->{other}{modules}{$mod} = 0; } for my $phase ( qw(configure build test runtime develop other) ) { next unless $req_hash->{$phase}; next if ($phase eq 'develop' and not $ENV{AUTHOR_TESTING}); for my $type ( qw(requires recommends suggests conflicts modules) ) { next unless $req_hash->{$phase}{$type}; my $title = ucfirst($phase).' '.ucfirst($type); my @reports = [qw/Module Want Have/]; for my $mod ( sort keys %{ $req_hash->{$phase}{$type} } ) { next if $mod eq 'perl'; next if grep { $_ eq $mod } @exclude; my $file = $mod; $file =~ s{::}{/}g; $file .= ".pm"; my ($prefix) = grep { -e File::Spec->catfile($_, $file) } @INC; my $want = $req_hash->{$phase}{$type}{$mod}; $want = "undef" unless defined $want; $want = "any" if !$want && $want == 0; my $req_string = $want eq 'any' ? 'any version required' : "version '$want' required"; if ($prefix) { my $have = MM->parse_version( File::Spec->catfile($prefix, $file) ); $have = "undef" unless defined $have; push @reports, [$mod, $want, $have]; if ( $DO_VERIFY_PREREQS && $HAS_CPAN_META && $type eq 'requires' ) { if ( $have !~ /\A$lax_version_re\z/ ) { push @dep_errors, "$mod version '$have' cannot be parsed ($req_string)"; } elsif ( ! $full_prereqs->requirements_for( $phase, $type )->accepts_module( $mod => $have ) ) { push @dep_errors, "$mod version '$have' is not in required range '$want'"; } } } else { push @reports, [$mod, $want, "missing"]; if ( $DO_VERIFY_PREREQS && $type eq 'requires' ) { push @dep_errors, "$mod is not installed ($req_string)"; } } } if ( @reports ) { push @full_reports, "=== $title ===\n\n"; my $ml = _max( map { length $_->[0] } @reports ); my $wl = _max( map { length $_->[1] } @reports ); my $hl = _max( map { length $_->[2] } @reports ); if ($type eq 'modules') { splice @reports, 1, 0, ["-" x $ml, "", "-" x $hl]; push @full_reports, map { sprintf(" %*s %*s\n", -$ml, $_->[0], $hl, $_->[2]) } @reports; } else { splice @reports, 1, 0, ["-" x $ml, "-" x $wl, "-" x $hl]; push @full_reports, map { sprintf(" %*s %*s %*s\n", -$ml, $_->[0], $wl, $_->[1], $hl, $_->[2]) } @reports; } push @full_reports, "\n"; } } } if ( @full_reports ) { diag "\nVersions for all modules listed in $source (including optional ones):\n\n", @full_reports; } if ( @dep_errors ) { diag join("\n", "\n*** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ***\n", "The following REQUIRED prerequisites were not satisfied:\n", @dep_errors, "\n" ); } pass; # vim: ts=4 sts=4 sw=4 et: Business-PayPal-API-0.76/t/advanced/000755 000765 000024 00000000000 13077411465 017140 5ustar00olafstaff000000 000000 Business-PayPal-API-0.76/t/API.pl000644 000765 000024 00000002415 13077411465 016343 0ustar00olafstaff000000 000000 =pod The tester must supply their own PayPal sandbox seller authentication (either using certificates or 3-token auth), as well as the buyer sandbox account (email address). Should we set env variables, prompt for them, or have them in a conf file? Prompt for them, but we should allow for an input file as an env variable: WPP_TEST=auth.txt prove -lvr t =cut sub do_args { unless ( $ENV{WPP_TEST} && -f $ENV{WPP_TEST} ) { die "See the TESTING section in `perldoc Business::PayPal::API documentation`\n"; exit; } my %args = (); open FILE, "<", $ENV{WPP_TEST} or die "Could not open $ENV{WPP_TEST}: $!\n"; my @variables = qw( Username Password Signature Subject timeout CertFile KeyFile PKCS12File PKCS12Password BuyerEmail SellerEmail ); my %patterns = (); @patterns{ map { qr/^$_\b/i } @variables } = @variables; while () { chomp; MATCH: for my $pat ( keys %patterns ) { next unless $_ =~ $pat; ( my $value = $_ ) =~ s/$pat\s*=\s*(.+)/$1/; $args{ $patterns{$pat} } = $value; delete $patterns{$pat}; last MATCH; } } close FILE; ## leave this! $args{sandbox} = 1; return %args; } 1; Business-PayPal-API-0.76/t/author-pod-spell.t000644 000765 000024 00000002617 13077411465 020765 0ustar00olafstaff000000 000000 BEGIN { unless ($ENV{AUTHOR_TESTING}) { print qq{1..0 # SKIP these tests are for testing by the author\n}; exit } } use strict; use warnings; use Test::More; # generated by Dist::Zilla::Plugin::Test::PodSpelling 2.007004 use Test::Spelling 0.12; use Pod::Wordlist; add_stopwords(); all_pod_files_spelling_ok( qw( bin lib ) ); __DATA__ API Ack Alders Alders' Andrew Anwar Aronesty AuthorizationID AuthorizationRequest AuthorizeRequest BillingAgreement Bourne Bowers Bradley Business Böhm CDATA CaptureRequest CertFile CompleteType Daniel Danny Dave David DirectPayment DirectPayments DoDirectPaymentRequest DoExpressCheckoutPayment DoReauthorization DoReauthorizationRequest DoReferenceTransaction DoVoidRequest Doran ExpressCheckout GetBalance GetExpressCheckoutDetails GetTransactionDetails Gregory GrossAmount Hembree KeyFile Kuhn Lambley Lindley Maltsev Marco MassPay MassPayItem Mohammad Neil Olaf Oschwald PEM PKCS PayPal PaymentItem PaymentItems Pessotto Phipps ReAuthorizationRequest ReauthorizationRequest RecurringPayments RefundTransaction RefundType ReturnURL Ron SDC SOM Scott SetExpressCheckout ShippingTotal Spiegl StartDate Steinbrunner Tomas TransactionID TransactionSearch USD UniqueId VoidRequest WPP WSDL Wiersdorf William am auth billers bkuhn currencyID danny daught davel derivates drjays dsteinbrunner eg goschwald lib melmothx mohammad ndrix neil olaf ron scott t0m wlindley Business-PayPal-API-0.76/t/author-tidyall.t000644 000765 000024 00000000724 13077411465 020525 0ustar00olafstaff000000 000000 BEGIN { unless ($ENV{AUTHOR_TESTING}) { print qq{1..0 # SKIP these tests are for testing by the author\n}; exit } } # This file was automatically generated by Dist::Zilla::Plugin::Test::TidyAll v$VERSION use Test::More 0.88; use Test::Code::TidyAll 0.24; tidyall_ok( verbose => ( exists $ENV{TEST_TIDYALL_VERBOSE} ? $ENV{TEST_TIDYALL_VERBOSE} : 0 ), jobs => ( exists $ENV{TEST_TIDYALL_JOBS} ? $ENV{TEST_TIDYALL_JOBS} : 1 ), ); done_testing; Business-PayPal-API-0.76/t/basic/000755 000765 000024 00000000000 13077411465 016454 5ustar00olafstaff000000 000000 Business-PayPal-API-0.76/t/release-cpan-changes.t000644 000765 000024 00000000553 13077411465 021530 0ustar00olafstaff000000 000000 BEGIN { unless ($ENV{RELEASE_TESTING}) { print qq{1..0 # SKIP these tests are for release candidate testing\n}; exit } } use strict; use warnings; # this test was generated with Dist::Zilla::Plugin::Test::CPAN::Changes 0.012 use Test::More 0.96 tests => 1; use Test::CPAN::Changes; subtest 'changes_ok' => sub { changes_file_ok('Changes'); }; Business-PayPal-API-0.76/t/basic/Business-PayPal-API.t000644 000765 000024 00000000141 13077411465 022223 0ustar00olafstaff000000 000000 use Test::More tests => 1; BEGIN { use_ok('Business::PayPal::API') } ######################### Business-PayPal-API-0.76/t/basic/DirectPayments.t000644 000765 000024 00000012336 13077411465 021601 0ustar00olafstaff000000 000000 #!/usr/bin/perl use strict; use warnings; use Test::Most; if ( !$ENV{WPP_TEST} || !-f $ENV{WPP_TEST} ) { plan skip_all => 'No WPP_TEST env var set. Please see README to run tests'; } else { plan tests => '7'; } use Business::PayPal::API qw( DirectPayments CaptureRequest ReauthorizationRequest VoidRequest RefundTransaction ); my @methlist = qw( DirectPayments CaptureRequest ReauthorizationRequest VoidRequest RefundTransaction); use_ok( 'Business::PayPal::API', @methlist ); require 't/API.pl'; my %args = do_args(); my ( $transale, $tranvoid, $tranbasic, $tranrefund ); my ( $ppsale, $ppvoid, $ppbasic, $pprefund, $pprefund1, $ppcap, $ppcap1 ); my ( %respsale, %resprefund, %resprefund1, %respbasic, %respcap, %respcap1, %respvoid ); #Test Full Refund on Sale #$Business::PayPal::API::Debug=1; $ppsale = Business::PayPal::API->new(%args); %respsale = $ppsale->DoDirectPaymentRequest( PaymentAction => 'Sale', OrderTotal => 11.87, TaxTotal => 0.0, ItemTotal => 0.0, CreditCardType => 'Visa', CreditCardNumber => '4561435600988217', ExpMonth => '01', ExpYear => +(localtime)[5] + 1901, CVV2 => '123', FirstName => 'JP', LastName => 'Morgan', Street1 => '1st Street LaCausa', Street2 => '', CityName => 'La', StateOrProvince => 'CA', PostalCode => '90210', Country => 'US', Payer => 'mall@example.org', CurrencyID => 'USD', IPAddress => '10.0.0.1', MerchantSessionID => '10113301', ); #$Business::PayPal::API::Debug=0; if ( like( $respsale{'Ack'}, qr/Success/, 'Direct Payment Sale' ) ) { $transale = $respsale{'TransactionID'}; #$Business::PayPal::API::Debug=1; $pprefund = Business::PayPal::API->new(%args); %resprefund = $pprefund->RefundTransaction( TransactionID => $transale, RefundType => 'Full', Memo => 'Full direct sale refund', ); #$Business::PayPal::API::Debug=0; like( $resprefund{'Ack'}, qr/Success/, 'Full Refund For Sale' ); } #Basic Authorization and Capture %args = do_args(); #$Business::PayPal::API::Debug=0; $ppbasic = Business::PayPal::API->new(%args); %respbasic = $ppbasic->DoDirectPaymentRequest( PaymentAction => 'Authorization', OrderTotal => 13.87, TaxTotal => 0.0, ItemTotal => 0.0, CreditCardType => 'Visa', CreditCardNumber => '4561435600988217', ExpMonth => '01', ExpYear => +(localtime)[5] + 1901, CVV2 => '123', FirstName => 'JP', LastName => 'Morgan', Street1 => '1st Street LaCausa', Street2 => '', CityName => 'La', StateOrProvince => 'CA', PostalCode => '90210', Country => 'US', Payer => 'mall@example.org', CurrencyID => 'USD', IPAddress => '10.0.0.1', MerchantSessionID => '10113301', ); #$Business::PayPal::API::Debug=0; if ( like( $respbasic{'Ack'}, qr/Success/, 'Direct Payment Basic Authorization' ) ) { $tranbasic = $respbasic{'TransactionID'}; #Test Partial Capture #$Business::PayPal::API::Debug=1; $ppcap = Business::PayPal::API->new(%args); %respcap = $ppcap->DoCaptureRequest( AuthorizationID => $tranbasic, CompleteType => 'NotComplete', Amount => '3.00', Note => 'Partial Capture', ); #$Business::PayPal::API::Debug=0; like( $respcap{'Ack'}, qr/Success/, 'Partial Capture' ); #Test Full Capture #$Business::PayPal::API::Debug=1; $ppcap1 = Business::PayPal::API->new(%args); %respcap1 = $ppcap1->DoCaptureRequest( AuthorizationID => $tranbasic, CompleteType => 'Complete', Amount => '6.00', ); #$Business::PayPal::API::Debug=0; like( $respcap1{'Ack'}, qr/Success/, 'Full Capture' ); } else { skip( "direct payment auth failed", 2 ) } #Test Void $ppbasic = Business::PayPal::API->new(%args); %respbasic = $ppbasic->DoDirectPaymentRequest( PaymentAction => 'Authorization', OrderTotal => 17.37, TaxTotal => 0.0, ItemTotal => 0.0, CreditCardType => 'Visa', CreditCardNumber => '4561435600988217', ExpMonth => '01', ExpYear => +(localtime)[5] + 1901, CVV2 => '123', FirstName => 'JP', LastName => 'Morgan', Street1 => '1st Street LaCausa', Street2 => '', CityName => 'La', StateOrProvince => 'CA', PostalCode => '90210', Country => 'US', Payer => 'mall@example.org', CurrencyID => 'USD', IPAddress => '10.0.0.1', MerchantSessionID => '10113301', ); #$Business::PayPal::API::Debug=1; $ppvoid = Business::PayPal::API->new(%args); %respvoid = $ppvoid->DoVoidRequest( AuthorizationID => $respbasic{TransactionID}, Note => 'Authorization Void', ); #$Business::PayPal::API::Debug=0; like( $respvoid{'Ack'}, qr/Success/, 'Authorization Voided' ); Business-PayPal-API-0.76/t/basic/MassPay.t000644 000765 000024 00000002516 13077411465 020222 0ustar00olafstaff000000 000000 use Test::More; if ( !$ENV{WPP_TEST} || !-f $ENV{WPP_TEST} ) { plan skip_all => 'No WPP_TEST env var set. Please see README to run tests'; } else { plan tests => 3; } use_ok('Business::PayPal::API::MassPay'); ######################### require 't/API.pl'; my %args = do_args(); my $pp = new Business::PayPal::API::MassPay(%args); #$Business::PayPal::API::Debug = 1; my %resp = $pp->MassPay( EmailSubject => "This is the subject; nice eh?", MassPayItems => [ { ReceiverEmail => 'joe@test.tld', Amount => '24.00', UniqueID => "123456", Note => "Enjoy the money. Don't spend it all in one place." } ] ); like( $resp{Ack}, qr/Success/, "successful payment" ); %resp = $pp->MassPay( EmailSubject => "This is the subject; nice eh?", MassPayItems => [ { ReceiverEmail => 'bob@test.tld', Amount => '25.00', UniqueID => "123457", Note => "Enjoy the money. Don't spend it all in one place." }, { ReceiverEmail => 'foo@test.tld', Amount => '42.00', UniqueID => "123458", Note => "Enjoy the money. Don't spend it all in one place." } ] ); like( $resp{Ack}, qr/Success/, "successful payments" ); Business-PayPal-API-0.76/t/basic/RecurringPayments.t000644 000765 000024 00000006623 13077411465 022331 0ustar00olafstaff000000 000000 # -*- mode: cperl -*- use Test::More; if ( !$ENV{WPP_TEST} || !-f $ENV{WPP_TEST} ) { plan skip_all => 'No WPP_TEST env var set. Please see README to run tests'; } else { plan tests => 3; } use_ok('Business::PayPal::API::RecurringPayments'); ######################### require 't/API.pl'; my %args = do_args(); my $pp = new Business::PayPal::API::RecurringPayments(%args); #$Business::PayPal::API::Debug = 1; my %response = $pp->SetCustomerBillingAgreement( BillingType => 'RecurringPayments', BillingAgreementDescription => '10.00 per month for 1 year', ReturnURL => 'http://www.google.com/', CancelURL => 'http://www.google.com/', BuyerEmail => $args{BuyerEmail}, ); #$Business::PayPal::API::Debug = 0; my $token = $response{Token}; ok( $token, "Got token" ); like( $response{Ack}, qr/Success/, "SetCustomerBillingAgreement successful" ); exit; die "No token from PayPal! Check your authentication information and try again." unless $token; my $pp_url = "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_customer-billing-agreement&token=$token"; =pod print STDERR <<"_TOKEN_"; Now paste the following URL into your browser (you'll need to have another browser window already logged into the PayPal developer site): $pp_url Login to PayPal as the Buyer you specified in '$ENV{WPP_TEST}' and proceed to checkout (this authorizes the transaction represented by the token). When finished, PayPal will redirect you to a non-existent URL: http://localhost/return.html?token=$token&PayerID=XXXXXXXXXXXXX Notice the *PayerID* URL argument (XXXXXXXXXXXXX) on the redirect from PayPal. _TOKEN_ print STDERR "\nType or paste that PayerID here and hit Enter: \n"; my $payerid = ; chomp $payerid; die "Need a PayerID.\n" unless $payerid; =cut ## CreateRecurringPaymentsProfile #$Business::PayPal::API::Debug = 1; my %profile = $pp->CreateRecurringPaymentsProfile( Token => $token, ## RecurringPaymentProfileDetails SubscriberName => 'Joe Schmoe', SubscriberShipperName => 'Schmoe House', SubscriberShipperStreet1 => '1234 Street St.', SubscriberShipperCityName => 'Orem', SubscriberShipperStateOrProvince => 'UT', SubscriberShipperPostalCode => '84222', SubscriberShipperCountry => 'USA', SubscriberShipperPhone => '123-123-1234', BillingStartDate => '2009-12-01Z', ProfileReference => 'BH12341234', ## ScheduleDetails Description => '12 Month Hosting Package: We Love You!', InitialAmount => '12.34', TrialBillingPeriod => 'Month', TrialBillingFrequency => 1, TrialTotalBillingCycles => 1, TrialAmount => 0.00, TrialShippingAmount => 0.00, TrialTaxAmount => 0.00, PaymentBillingPeriod => 'Year', PaymentBillingFrequency => 1, PaymentTotalBillingCycles => 1, PaymentAmount => 95.40, PaymentShippingAmount => 0.00, PaymentTaxAmount => 0.00, # MaxFailedPayments => 1, # AutoBillOutstandingAmount => 'AddToNextBilling', ); #$Business::PayPal::API::Debug = 0; ## GetBillingAgreementCustomerDetails #$Business::PayPal::API::Debug = 1; my %details = $pp->GetBillingAgreementCustomerDetails($token); #$Business::PayPal::API::Debug = 0; like( $details{Ack}, qr/Success/, "details ok" ); Business-PayPal-API-0.76/t/basic/SubscriptionPayments.t000644 000765 000024 00000007374 13077411465 023061 0ustar00olafstaff000000 000000 use strict; use warnings; use autodie qw(:file); use Cwd; use List::AllUtils; use Test::More; if ( !$ENV{WPP_TEST} || !-f $ENV{WPP_TEST} ) { plan skip_all => 'No WPP_TEST env var set. Please see README to run tests'; } else { plan tests => 5; } use_ok('Business::PayPal::API::TransactionSearch'); ######################### require 't/API.pl'; my %args = do_args(); =pod The following four tests shows the methodology to use TransactionSearch to find transactions that are part of the same ProfileID. This method was discovered by trial-and-error. Specifically, it's somewhat odd that TransactionSearch is used with the parameter of 'ProfileID' with the value set to a specific TransactionID to find the ProfileID via the "Created" transaction. Then, in turn, that ProfileID can find the subscription payments related to the original transaction. This works, and seems to be correct, albeit odd. =cut open SUBSCRIPTION_PAY_HTML, '>', 'subscription-payment.html'; print SUBSCRIPTION_PAY_HTML <<_SUBSCRIPTION_PAYMENT_DATA_
_SUBSCRIPTION_PAYMENT_DATA_ ; close SUBSCRIPTION_PAY_HTML; my $cwd = getcwd; print STDERR <<"_PROFILEID_"; Please note the next series of tests will not succeeed unless there is at least one transaction that is part of a subscription payments in your business account. if you haven't made one yet, you can visit: file:///$cwd/subscription-payment.html and use the sandbox buyer account to make the payment. _PROFILEID_ my $start_date = '1998-01-01T01:45:10.00Z'; my $ts = Business::PayPal::API::TransactionSearch->new(%args); my $resp = $ts->TransactionSearch( StartDate => $start_date ); ok( scalar @{$resp} > 0, 'Some transactions found' ); my ( $profileID, %possible_txn_ids ); foreach my $record ( @{$resp} ) { if ( $record->{Type} =~ /Recurring/ ) { if ( $record->{Status} =~ /Completed/ ) { $possible_txn_ids{ $record->{TransactionID} } = $record; } elsif ( $record->{Status} =~ /Created/ ) { $profileID = $record->{TransactionID}; } } } ok( defined $profileID, 'Subscription Payment Creation Record and ProfileID Found' ); ok( scalar keys %possible_txn_ids > 0, 'Subscription Payment Transactions Found' ); my $date_search_res = $ts->TransactionSearch( ProfileID => $profileID, StartDate => $start_date, ); # One of these will need to be in the possibleTransactionID list (i.e., we're # assuming that at least one payment has occured in this repeating). ok( List::AllUtils::any { defined $possible_txn_ids{ $_->{TransactionID} } } @{$date_search_res}, 'Found one payment transaction under the given Profile ID' ); Business-PayPal-API-0.76/t/advanced/ExpressCheckout.t000644 000765 000024 00000004733 13077411465 022453 0ustar00olafstaff000000 000000 use Test::More; if ( !$ENV{WPP_TEST} || !-f $ENV{WPP_TEST} ) { plan skip_all => 'No WPP_TEST env var set. Please see README to run tests'; } else { plan tests => 6; } use_ok('Business::PayPal::API::ExpressCheckout'); ######################### require 't/API.pl'; my %args = do_args(); ## we're passing more to new() than we normally would because we're ## using %args elsewhere below. See documentation for the correct ## arguments. my $pp = new Business::PayPal::API::ExpressCheckout(%args); ## ## set checkout info ## #$Business::PayPal::API::Debug = 1; my %response = $pp->SetExpressCheckout( OrderTotal => '55.43', ReturnURL => 'http://127.0.0.1:3000', CancelURL => 'http://127.0.0.1:3000', Custom => "This field is custom. Isn't that great?", PaymentAction => 'Sale', BuyerEmail => $args{BuyerEmail}, ## from %args ); #$Business::PayPal::API::Debug = 0; my $token = $response{Token}; ok( $token, "Got token" ); die "No token from PayPal! Check your authentication information and try again." unless $token; my $pp_url = "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=$token"; print STDERR <<"_TOKEN_"; Now paste the following URL into your browser (you'll need to have another browser window already logged into the PayPal developer site): $pp_url Login to PayPal as the Buyer you specified in '$ENV{WPP_TEST}' and proceed to checkout (this authorizes the transaction represented by the token). When finished, PayPal will redirect you to a non-existent URL: http://localhost/return.html?token=$token&PayerID=XXXXXXXXXXXXX Notice the *PayerID* URL argument (XXXXXXXXXXXXX) on the redirect from PayPal. _TOKEN_ print STDERR "\nType or paste that PayerID here and hit Enter: \n"; my $payerid = ; chomp $payerid; die "Need a PayerID.\n" unless $payerid; ## ## get checkout details ## my %details = $pp->GetExpressCheckoutDetails($token); is( $details{Token}, $token, "details ok" ); #use Data::Dumper; #print STDERR Dumper \%details; $details{PayerID} = $payerid; my %payment = ( Token => $details{Token}, PaymentAction => 'Sale', PayerID => $details{PayerID}, OrderTotal => '55.43', ); ## ## do checkout ## my %payinfo = $pp->DoExpressCheckoutPayment(%payment); like( $payinfo{Ack}, qr/Success/, "successful payment" ); is( $payinfo{Token}, $token, "payment ok" ); is( $payinfo{GrossAmount}, 55.43, "amount correct" ); Business-PayPal-API-0.76/t/advanced/ExpressOrder.t000644 000765 000024 00000006561 13077411465 021762 0ustar00olafstaff000000 000000 use Test::More; if ( !$ENV{WPP_TEST} || !-f $ENV{WPP_TEST} ) { plan skip_all => 'No WPP_TEST env var set. Please see README to run tests'; } else { plan tests => 8; } use_ok('Business::PayPal::API::ExpressCheckout'); ######################### require 't/API.pl'; my %args = do_args(); ## we're passing more to new() than we normally would because we're ## using %args elsewhere below. See documentation for the correct ## arguments. my $pp = new Business::PayPal::API::ExpressCheckout(%args); ## ## set checkout info ## #$Business::PayPal::API::Debug = 1; my %response = $pp->SetExpressCheckout( OrderTotal => '55.43', ReturnURL => 'http://127.0.0.1:3000', CancelURL => 'http://127.0.0.1:3000', Custom => "This field is custom. Isn't that great?", PaymentAction => 'Order', BuyerEmail => $args{BuyerEmail}, ## from %args ); #$Business::PayPal::API::Debug = 0; my $token = $response{Token}; ok( $token, "Got token" ); die "No token from PayPal! Check your authentication information and try again." unless $token; my $pp_url = "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=$token"; print STDERR <<"_TOKEN_"; Now paste the following URL into your browser (you will need to have another browser window already logged into the PayPal developer site): $pp_url Login to PayPal as the Buyer you specified in '$ENV{WPP_TEST}' and proceed to checkout (this authorizes the transaction represented by the token). When finished, PayPal will redirect you to a non-existent URL: http://localhost/return.html?token=$token&PayerID=XXXXXXXXXXXXX Notice the *PayerID* URL argument (XXXXXXXXXXXXX) on the redirect from PayPal. Once completed, The Payer account and Payee account can be checked for an order, authorization, and void. _TOKEN_ print STDERR "\nType or paste that PayerID here and hit Enter: \n"; my $payerid = ; chomp $payerid; die "Need a PayerID.\n" unless $payerid; ## ## get checkout details ## my %details = $pp->GetExpressCheckoutDetails($token); is( $details{Token}, $token, "details ok" ); #use Data::Dumper; #print STDERR Dumper \%details; $details{PayerID} = $payerid; my %payment = ( Token => $details{Token}, PaymentAction => 'Order', PayerID => $details{PayerID}, OrderTotal => '55.43', ); ## ## do checkout ## #$Business::PayPal::API::Debug = 1; my %payinfo = $pp->DoExpressCheckoutPayment(%payment); #$Business::PayPal::API::Debug = 0; #If Order is successful then authorize it, then void it. if ( like( $payinfo{Ack}, qr/Success/, "successful payment" ) ) { my $transid = $payinfo{TransactionID}; my $amount = '25.43'; use_ok('Business::PayPal::API::AuthorizationRequest'); %args = do_args(); #$Business::PayPal::API::Debug = 1; $ppauth = new Business::PayPal::API::AuthorizationRequest(%args); my %resp = $ppauth->DoAuthorizationRequest( TransactionID => $transid, Amount => $amount ); like( $resp{Ack}, qr/Succes/, 'Successful order authorization' ); use_ok('Business::PayPal::API::VoidRequest'); %args = do_args(); my $ppvoid = new Business::PayPal::API::VoidRequest(%args); %resp1 = $ppvoid->DoVoidRequest( AuthorizationID => $transid, Note => 'Voided' ); like( $resp1{Ack}, qr/Success/, 'Successful order void' ); } Business-PayPal-API-0.76/t/advanced/GetTransactionDetails.t000644 000765 000024 00000002211 13077411465 023554 0ustar00olafstaff000000 000000 use Test::More; if ( !$ENV{WPP_TEST} || !-f $ENV{WPP_TEST} ) { plan skip_all => 'No WPP_TEST env var set. Please see README to run tests'; } else { plan tests => 2; } use_ok('Business::PayPal::API::GetTransactionDetails'); ######################### require 't/API.pl'; my %args = do_args(); my $pp = new Business::PayPal::API::GetTransactionDetails(%args); print STDERR <<"_TRANSID_"; Please login to the PayPal Developer's site, and start a sandbox in the Business account you want to test. Review the Business accounts transaction history: My Account -> History (tab) Click the 'Details' link for a transaction whose status is 'Completed'. Copy the Transaction ID for that transaction. The transaction id may appear like this: Express Checkout Payment Received (ID # 2DE2563K55B16978M) _TRANSID_ print STDERR "\nType or paste that Transaction ID here and hit Enter: \n"; my $transid = ; chomp $transid; die "Need a transaction id.\n" unless $transid; #$Business::PayPal::API::Debug = 1; my %resp = $pp->GetTransactionDetails( TransactionID => $transid ); like( $resp{Ack}, qr/Success/, "transaction received" ); Business-PayPal-API-0.76/t/advanced/OptionFields.t000644 000765 000024 00000010154 13077411465 021725 0ustar00olafstaff000000 000000 use strict; use autodie qw(:file); use Cwd; use Test::More; if ( !$ENV{WPP_TEST} || !-f $ENV{WPP_TEST} ) { plan skip_all => 'No WPP_TEST env var set. Please see README to run tests'; } else { plan tests => 14; } use_ok('Business::PayPal::API::TransactionSearch'); use_ok('Business::PayPal::API::GetTransactionDetails'); sub rndStr { join '', @_[ map { rand @_ } 1 .. shift ]; } ######################### require 't/API.pl'; my %args = do_args(); =pod These tests verify the options work. =cut my $itemName; if ( -f 'options-payment.html' ) { open( OPTIONS_PAY_HTML_READ, "<", "options-payment.html" ); while ( my $line = ) { $itemName = $1 if $line =~ /Field\s*Options\s*Tester:\s*([A-Z]+)/; } close OPTIONS_PAY_HTML_READ; } if ( defined $itemName ) { print STDERR "Using existing test transaction with name \"$itemName\"\n"; } else { $itemName = rndStr( 10, 'A' .. 'Z' ); open( OPTIONS_PAY_HTML, ">", "options-payment.html" ); print OPTIONS_PAY_HTML <<_OPTIONS_PAYMENT_DATA_
_OPTIONS_PAYMENT_DATA_ ; close(OPTIONS_PAY_HTML); my $cwd = getcwd; print STDERR <<"_OPTIONS_LINK_"; Please note the next series of tests will not succeeed unless there is at least one transaction that is part of a subscription payments in your business account. if you haven't made one yet, you can visit: file://$cwd/options-payment.html and use the sandbox buyer account to make the payment. _OPTIONS_LINK_ } my $startdate = '1998-01-01T01:45:10.00Z'; my $ts = new Business::PayPal::API::TransactionSearch(%args); my $td = new Business::PayPal::API::GetTransactionDetails(%args); my $resp = $ts->TransactionSearch( StartDate => $startdate ); my %detail; foreach my $record ( @{$resp} ) { %detail = $td->GetTransactionDetails( TransactionID => $record->{TransactionID} ); last if $detail{PII_Name} =~ /$itemName/; %detail = {}; } like( $detail{PaymentItems}[0]{Name}, qr/$itemName/, 'Found field options test transaction' ); like( $detail{PII_Name}, qr/$itemName/, 'Found field options test transaction' ); =pod Note that the tests below all pass when only two Options are found, even though our HTML file above passes through I options. Yet, if you look at the transaction details in the PayPal sandbox web interface, you'll see that all three Options are present in its record description. Thus, Options beyond the first two appears only partially supported by PayPal. Thus, our tests verify this fact by submitting three of these fields, but expecting only the first two back. More details on this can be found in the L documentation. =cut foreach my $options ( $detail{PaymentItems}[0]{Options}, $detail{PII_Options}[0] ) { ok( scalar( keys %$options ) == 2, "The PaymentItems Options has 2 elements" ); ok( defined $options->{firstOption}, "'firstOption' is present" ); ok( $options->{firstOption} eq 'Yes', "'firstOption' is selected as 'Yes'" ); ok( defined $options->{size}, "'size' option is present" ); ok( $options->{size} eq "Large", "'size' option is selected as 'Large'" ); } Business-PayPal-API-0.76/t/advanced/RefundTransaction.t000644 000765 000024 00000002526 13077411465 022763 0ustar00olafstaff000000 000000 use Test::More; if ( !$ENV{WPP_TEST} || !-f $ENV{WPP_TEST} ) { plan skip_all => 'No WPP_TEST env var set. Please see README to run tests'; } else { plan tests => 2; } use_ok('Business::PayPal::API::RefundTransaction'); ######################### require 't/API.pl'; my %args = do_args(); my $pp = new Business::PayPal::API::RefundTransaction(%args); print STDERR <<"_TRANSID_"; Please login to the PayPal Developer's site, and start a sandbox in the Business account you want to test. Review the Business accounts transaction history: My Account -> History (tab) Follow the 'Details' link for a transaction (whose status is 'Completed') that occurred in the past 60 days. Copy the Transaction ID for that transaction. It may appear like this: Express Checkout Payment Received (ID # 2DE2563K55B16978M) _TRANSID_ print STDERR "\nType or paste that Transaction ID here and hit Enter: \n"; my $transid = ; chomp $transid; die "Need a transaction id.\n" unless $transid; my %resp = $pp->RefundTransaction( TransactionID => $transid, RefundType => 'Full', Memo => 'Fancy refund time.' ); like( $resp{Ack}, qr/Success/, "Successful refund." ); if ( $resp{Ack} ) { print STDERR <<"_REFUND_"; You may now login to your Business sandbox account and verify the transaction was refunded. _REFUND_ } Business-PayPal-API-0.76/t/advanced/TransactionSearch.t000644 000765 000024 00000002750 13077411465 022744 0ustar00olafstaff000000 000000 use Test::More; if ( !$ENV{WPP_TEST} || !-f $ENV{WPP_TEST} ) { plan skip_all => 'No WPP_TEST env var set. Please see README to run tests'; } else { plan tests => 2; } use_ok('Business::PayPal::API::TransactionSearch'); ######################### require 't/API.pl'; my %args = do_args(); my $pp = new Business::PayPal::API::TransactionSearch(%args); print STDERR <<"_TRANSID_"; Please login to the PayPal Developer's site, and start a sandbox in the Business account you want to test. This function will allow you to view MassPayment transactions by transaction ID's. It may fail for other types of transaction ID's. The GetTransactionDetails can be used in those cases but not for Mass Payment transactions. I know, I'm just the messenger. Review the Business accounts transaction history: My Account -> History (tab) Click the 'Details' link for a Mass Payment transaction whose status is 'Processed'. Go to the bottom of the page and click "View Detail". It will give you download choices. Download it however you prefer the copy the Transaction ID from the message. _TRANSID_ print STDERR "\nType or paste that Transaction ID here and hit Enter: \n"; my $transid = ; chomp $transid; die "Need a transaction id.\n" unless $transid; my $startdate = '1998-01-01T01:45:10.00Z'; #$Business::PayPal::API::Debug = 1; my $resp = $pp->TransactionSearch( StartDate => $startdate, TransactionID => $transid, ); ok( scalar @$resp, "Matching Transactions Found" ); Business-PayPal-API-0.76/lib/Business/000755 000765 000024 00000000000 13077411465 017471 5ustar00olafstaff000000 000000 Business-PayPal-API-0.76/lib/Business/PayPal/000755 000765 000024 00000000000 13077411465 020657 5ustar00olafstaff000000 000000 Business-PayPal-API-0.76/lib/Business/PayPal/API/000755 000765 000024 00000000000 13077411465 021270 5ustar00olafstaff000000 000000 Business-PayPal-API-0.76/lib/Business/PayPal/API.pm000644 000765 000024 00000064064 13077411465 021640 0ustar00olafstaff000000 000000 package Business::PayPal::API; $Business::PayPal::API::VERSION = '0.76'; use 5.008001; use strict; use warnings; use Data::Printer; use SOAP::Lite 0.67; # +trace => 'all'; use Carp qw(carp); our $Debug = $ENV{WPP_DEBUG} || 0; ## NOTE: This package exists only until I can figure out how to use ## NOTE: SOAP::Lite's WSDL support for complex types and importing ## NOTE: type definitions, at which point this module will become much ## NOTE: smaller (or non-existent). sub C_api_sandbox () { 'https://api.sandbox.paypal.com/2.0/' } sub C_api_sandbox_3t () { 'https://api-3t.sandbox.paypal.com/2.0/' } sub C_api_live () { 'https://api.paypal.com/2.0/' } sub C_api_live_3t () { 'https://api-3t.paypal.com/2.0/' } sub C_xmlns_pp () { 'urn:ebay:api:PayPalAPI' } sub C_xmlns_ebay () { 'urn:ebay:apis:eBLBaseComponents' } sub C_version () { '61.0' } ## 3.0 adds RecurringPayments ## this is an inside-out object. Make sure you 'delete' additional ## members in DESTROY() as you add them. my %Soap; my %Header; my %H_PKCS12File; ## path to certificate file (pkc12) my %H_PKCS12Password; ## password for certificate file (pkc12) my %H_CertFile; ## PEM certificate my %H_KeyFile; ## PEM private key sub import { my $self = shift; my @modules = @_; for my $module (@modules) { eval("use Business::PayPal::API::$module;"); if ($@) { warn $@; next; } ## import 'exported' subroutines into our namespace no strict 'refs'; for my $sub ( @{ "Business::PayPal::API::" . $module . "::EXPORT_OK" } ) { *{ "Business::PayPal::API::" . $sub } = *{ "Business::PayPal::API::" . $module . "::" . $sub }; } } } sub new { my $class = shift; my %args = @_; my $self = bless \( my $fake ), $class; ## if you add new args, be sure to update the test file's @variables array $args{Username} ||= ''; $args{Password} ||= ''; $args{Signature} ||= ''; $args{Subject} ||= ''; $args{sandbox} = 1 unless exists $args{sandbox}; $args{timeout} ||= 30; $H_PKCS12File{$self} = $args{PKCS12File} || ''; $H_PKCS12Password{$self} = $args{PKCS12Password} || ''; $H_CertFile{$self} = $args{CertFile} || ''; $H_KeyFile{$self} = $args{KeyFile} || ''; my $proxy = ( $args{sandbox} ? ( $args{Signature} ? C_api_sandbox_3t : C_api_sandbox ) : ( $args{Signature} ? C_api_live_3t : C_api_live ) ); $Soap{$self} = SOAP::Lite->proxy( $proxy, timeout => $args{timeout}, ( exists $args{proxy_url} ? ( proxy => [ [ 'http', 'https' ] => $args{proxy_url} ] ) : () ) )->uri(C_xmlns_pp); $Header{$self} = SOAP::Header->name( RequesterCredentials => \SOAP::Header->value( SOAP::Data->name( Credentials => \SOAP::Data->value( SOAP::Data->name( Username => $args{Username} )->type(''), SOAP::Data->name( Password => $args{Password} )->type(''), SOAP::Data->name( Signature => $args{Signature} ) ->type(''), SOAP::Data->name( Subject => $args{Subject} )->type(''), ), )->attr( { xmlns => C_xmlns_ebay } ) ) )->attr( { xmlns => C_xmlns_pp } )->mustUnderstand(1); return $self; } sub DESTROY { my $self = $_[0]; delete $Soap{$self}; delete $Header{$self}; delete $H_PKCS12File{$self}; delete $H_PKCS12Password{$self}; delete $H_CertFile{$self}; delete $H_KeyFile{$self}; my $super = $self->can("SUPER::DESTROY"); goto &$super if $super; } sub version_req { return SOAP::Data->name( Version => C_version )->type('xs:string') ->attr( { xmlns => C_xmlns_ebay } ); } sub doCall { my $self = shift; my $method_name = shift; my $request = shift; my $method = SOAP::Data->name($method_name)->attr( { xmlns => C_xmlns_pp } ); my $som; { $H_PKCS12File{$self} and local $ENV{HTTPS_PKCS12_FILE} = $H_PKCS12File{$self}; $H_PKCS12Password{$self} and local $ENV{HTTPS_PKCS12_PASSWORD} = $H_PKCS12Password{$self}; $H_CertFile{$self} and local $ENV{HTTPS_CERT_FILE} = $H_CertFile{$self}; $H_KeyFile{$self} and local $ENV{HTTPS_KEY_FILE} = $H_KeyFile{$self}; if ($Debug) { print STDERR SOAP::Serializer->envelope( method => $method, $Header{$self}, $request ), "\n"; } no warnings 'redefine'; local *SOAP::Deserializer::typecast = sub { shift; return shift }; eval { $som = $Soap{$self}->call( $Header{$self}, $method => $request ); }; if ($@) { carp $@; return; } } if ($Debug) { ## FIXME: would be nicer to dump a SOM to XML, but how to do that? p( $som->envelope ); } if ( ref($som) && $som->fault ) { carp "Fault: " . $som->faultstring . ( $som->faultdetail ? " (" . $som->faultdetail . ")" : '' ) . "\n"; return; } return $som; } sub getFieldsList { my $self = shift; my $som = shift; my $path = shift; my $fields = shift; return unless $som; my %trans_id = (); my @records = (); for my $rec ( $som->valueof($path) ) { my %response = (); @response{ keys %$fields } = @{$rec}{ keys %$fields }; ## avoid duplicates if ( defined $response{TransactionID} ) { if ( $trans_id{ $response{TransactionID} } ) { next; } else { $trans_id{ $response{TransactionID} } = 1; } } push @records, \%response; } return \@records; } sub getFields { my $self = shift; my $som = shift; my $path = shift; my $response = shift; my $fields = shift; return unless $som; ## kudos to Erik Aronesty via email, Drew Simpson via rt.cpan.org (#28596) ## Erik wrote: ## ## If you want me to write the code for the "flagged" version, i ## can .. i think the '/@' flag is a pretty safe, and obvious flag. ## ## the advantage of the flagged version would be that the caller ## doesn't have to check the returned value ... in the case of a ## field where multiple values are expected. ## ## ## I agree with this on principle and would prefer it, but I voted ## against a special flag, now forcing the caller to check the ## return value, but only for the sake of keeping everything ## consistent with the rest of the API. If Danny Hembree wants to ## go through and implement Erik's suggestion, I'd be in favor of ## it. for my $field ( keys %$fields ) { my @vals = grep { defined } $som->valueof("$path/$fields->{$field}"); next unless @vals; if ( scalar(@vals) == 1 ) { $response->{$field} = $vals[0]; } else { $response->{$field} = \@vals; } } } sub getBasic { my $self = shift; my $som = shift; my $path = shift; my $details = shift; return unless $som; for my $field (qw( Ack Timestamp CorrelationID Version Build )) { $details->{$field} = $som->valueof("$path/$field") || ''; } return $details->{Ack} =~ /Success/; } sub getErrors { my $self = shift; my $som = shift; my $path = shift; my $details = shift; return unless $som; my @errors = (); for my $enode ( $som->valueof("$path/Errors") ) { push @errors, { LongMessage => $enode->{LongMessage}, ErrorCode => $enode->{ErrorCode}, }; } $details->{Errors} = \@errors; return; } 1; # ABSTRACT: PayPal SOAP API client with sandbox support __END__ =pod =encoding UTF-8 =head1 NAME Business::PayPal::API - PayPal SOAP API client with sandbox support =head1 VERSION version 0.76 =head1 SYNOPSIS use Business::PayPal::API qw( ExpressCheckout GetTransactionDetails ); ## certificate authentication my $pp = Business::PayPal::API->new( Username => 'my_api1.domain.tld', Password => 'this_is_my_password', PKCS12File => '/path/to/cert.pkcs12', PKCS12Password => '(pkcs12 password)', sandbox => 1, ); ## PEM cert authentication my $pp = Business::PayPal::API->new( Username => 'my_api1.domain.tld', Password => 'this_is_my_password', CertFile => '/path/to/cert.pem', KeyFile => '/path/to/cert.pem', sandbox => 1, ); ## 3-token (Signature) authentication my $pp = Business::PayPal::API->new( Username => 'my_api1.domain.tld', Password => 'Xdkis9k3jDFk39fj29sD9', ## supplied by PayPal Signature => 'f7d03YCpEjIF3s9Dk23F2V1C1vbYYR3ALqc7jm0UrCcYm-3ksdiDwjfSeii', ## ditto sandbox => 1, ); my %response = $pp->SetExpressCheckout( ... ); =head1 DESCRIPTION B supports both certificate authentication and the new 3-token "Signature" authentication. It also supports PayPal's development I for testing. See the B parameter to B below for details. B can import other B derived classes: use Business::PayPal::API qw( RefundTransaction ); This allows for much more concise and intuitive usage. For example, these two statements are equivalent: use Business::PayPal::API::RefundTransaction; my $pp = Business::PayPal::API::RefundTransaction->new( ... ); $pp->RefundTransaction( ... ); and more concisely: use Business::PayPal::API qw( RefundTransaction ); my $pp = Business::PayPal::API->new( ... ); $pp->RefundTransaction( ... ); The advantage of this becomes clear when you need to use multiple API calls in your program; this allows you to use the same object to invoke the various methods, instead of creating a new object for each subclass. Here is an example of a B object used to invoke various PayPal APIs with the same object: use Business::PayPal::API qw( GetTransactionDetails TransactionSearch RefundTransaction ); my $pp = Business::PayPal::API->new( ... ); my $records = $pp->TransactionSearch( ... ); my %details = $pp->GetTransactionDetails( ... ); my %resp = $pp->RefundTransaction( ... ); However, you may certainly use just the subclass if that's all you need. Every subclass should work as its own self-contained API. For details on B subclasses, see each subclass's individual documentation. =head2 new Creates a new B object. A note about certificate authentication: PayPal (and this module) support either PKCS#12 certificate authentication or PEM certificate authentication. See options below. =over 4 =item B Required. This is the PayPal API username, usually in the form of 'my_api1.mydomain.tld'. You can find or create your API credentials by logging into PayPal (if you want to do testing, as you should, you should also create a developer sandbox account) and going to: My Account -> Profile -> API Access -> Request API Credentials Please see the I and I for details on creating a PayPal business account and sandbox account for testing. =item B Required. If you use certificate authentication, this is the PayPal API password created when you setup your certificate. If you use 3-token (Signature) authentication, this is the password PayPal assigned you, along with the "API User Name" and "Signature Hash". =item B Optional. This is used by PayPal to authenticate 3rd party billers using your account. See the documents in L. =item B Required for 3-token (Signature) authentication. This is the "Signature Hash" you received when you did "Request API Credentials" in your PayPal Business Account. =item B Required for PKCS#12 certificate authentication, unless the B environment variable is already set. This contains the path to your private key for PayPal authentication. It is used to set the B environment variable. You may set this environment variable yourself and leave this field blank. =item B Required for PKCS#12 certificate authentication, unless the B environment variable is already set. This contains the PKCS#12 password for the key specified in B. It is used to set the B environment variable. You may set this environment variable yourself and leave this field blank. =item B Required for PEM certificate authentication, unless the HTTPS_CERT_FILE environment variable is already set. This contains the path to your PEM format certificate given to you from PayPal (and accessible in the same location that your Username and Password and/or Signature Hash are found) and is used to set the B environment variable. You may set this environment variable yourself and leave this field blank. You may combine both certificate and private key into one file and set B and B to the same path. =item B Required for PEM certificate authentication, unless the HTTPS_KEY_FILE environment variable is already set. This contains the path to your PEM format private key given to you from PayPal (and accessible in the same location that your Username and Password and/or Signature Hash are found) and is used to set the B environment variable. You may set this environment variable yourself and leave this field blank. You may combine both certificate and private key into one file and set B and B to the same path. =item B Required. If set to true (default), B will connect to PayPal's development sandbox, instead of PayPal's live site. *You must explicitly set this to false (0) to access PayPal's live site*. If you use PayPal's development sandbox for testing, you must have already signed up as a PayPal developer and created a Business sandbox account and a Buyer sandbox account (and make sure both of them have B status in the sandbox). When testing with the sandbox, you will use different usernames, passwords, and certificates (if using certificate authentication) than you will when accessing PayPal's live site. Please see the PayPal documentation for details. See L for references. PayPal's sandbox reference: L =back =item B Optional. When set, the proxy at the specified URL will be used for outbound connections. =item B Optional. Set the timeout in seconds. Defaults to 30 seconds. =head1 NAME Business::PayPal::API - PayPal API =head1 ERROR HANDLING Every API call should return an B response, whether I, I, or otherwise (depending on the API call). If it returns any non-success value, you can find an I entry in your return hash, whose value is an arrayref of hashrefs: [ { ErrorCode => 10002, LongMessage => "Invalid security header" }, { ErrorCode => 10030, LongMessage => "Some other error" }, ] You can retrieve these errors like this: %response = $pp->doSomeAPICall(); if( $response{Ack} ne 'Success' ) { for my $err ( @{$response{Errors}} ) { warn "Error: " . $err->{LongMessage} . "\n"; } } =head1 TESTING Testing the B modules requires that you create a file containing your PayPal Developer Sandbox authentication credentials (e.g., API certificate authentication or 3-Token authentication signature, etc.) and setting the B environment variable to point to this file. The format for this file is as follows: Username = your_api.username.com Password = your_api_password and then ONE of the following options: a) supply 3-token authentication signature Signature = xxxxxxxxxxxxxxxxxxxxxxxx b) supply PEM certificate credentials CertFile = /path/to/cert_key_pem.txt KeyFile = /path/to/cert_key_pem.txt c) supply PKCS#12 certificate credentials PKCS12File = /path/to/cert.p12 PKCS12Password = pkcs12_password You may also set the appropriate HTTPS_* environment variables for b) and c) above (e.g., HTTPS_CERT_FILE, HTTPS_KEY_FILE, HTTPS_PKCS12_File, HTTPS_PKCS12_PASSWORD) in lieu of putting this information in a file. Then use "WPP_TEST=my_auth.txt make test" (for Bourne shell derivates) or "setenv WPP_TEST my_auth.txt && make test" (for C-shell derivates). See 'auth.sample.*' files in this package for an example of the file format. Variables are case-*sensitive*. Any of the following variables are recognized: Username Password Signature Subject CertFile KeyFile PKCS12File PKCS12Password BuyerEmail Note: PayPal authentication may I if you set the certificate environment variables and attempt to connect using 3-token authentication (i.e., PayPal will use the first authentication credentials presented to it, and if they fail, the connection is aborted). =head1 TROUBLESHOOTING =head2 PayPal Authentication Errors If you are experiencing PayPal authentication errors (e.g., "Security header is not valid", "SSL negotiation failed", etc.), you should make sure: * your username and password match those found in your PayPal Business account sandbox (this is not the same as your regular account). * you're not trying to use your live username and password for sandbox testing and vice versa. * you are using a US Business Sandbox account, you may also need to have "PayPal Payments Pro" enabled. * if the sandbox works but "live" does not, make sure you've turned off the 'sandbox' parameter correctly. Otherwise you'll be passing your PayPal sandbox credentials to PayPal's live site (which won't work). * if you use certificate authentication, your certificate must be the correct one (live or sandbox) depending on what you're doing. * if you use 3-Token authentication (i.e., Signature), you don't have any B parameters or B or B parameters in your constructor AND that none of the corresponding B environment variables are set. PayPal prefers certificate authentication since it occurs at connection time; if it fails, it will not try Signature authentication. Try clearing your environment: ## delete all HTTPS, SSL env delete $ENV{$_} for grep { /^(HTTPS|SSL)/ } keys %ENV; ## now put our own HTTPS env back in $ENV{HTTPS_CERT_FILE} = '/var/path/to/cert.pem'; ## create our paypal object my $pp = Business::PayPal::API->new(...) * if you have already loaded Net::SSLeay (or IO::Socket::SSL), then Net::HTTPS will prefer to use IO::Socket::SSL. I don't know how to get SOAP::Lite to work with IO::Socket::SSL (e.g., Crypt::SSLeay uses HTTPS_* environment variables), so until then, you can use this hack: local $IO::Socket::SSL::VERSION = undef; $pp->DoExpressCheckoutPayment(...); This will tell Net::HTTPS to ignore the fact that IO::Socket::SSL is already loaded for this scope and import Net::SSL (part of the Crypt::SSLeay package) for its 'configure()' method. * if you receive a message like "500 Can't connect to api.sandbox.paypal.com:443 (Illegal seek)", you'll need to make sure you have Crypt::SSLeay installed. It seems that other crypto modules don't do the certificate authentication quite as well, and LWP needs this to negotiate the SSL connection with PayPal. See the DEBUGGING section below for further hints. =head2 PayPal Munging URLs PayPal seems to be munging my URLs when it returns. SOAP::Lite follows the XML specification carefully, and encodes '&' and '<' characters before applying them to the SOAP document. PayPal does not properly URL-decode HTML entities '&' and '<' on the way back, so if you have an ampersand in your ReturnURL (for example), your customers will be redirected here: http://domain.tld/prog?arg1=foo&arg2=bar instead of here: http://domain.tld/prog?arg1=foo&arg2=bar Solution: Use CDATA tags to wrap your request: ReturnURL => '' You may also use semicolons instead of ampersands to separate your URL arguments: ReturnURL => 'http://domain.tld/prog?arg1=foo;arg2=bar' (thanks to Ollie Ready) =head1 DEBUGGING You can see the raw SOAP XML sent and received by B by setting its B<$Debug> variable: $Business::PayPal::API::Debug = 1; $pp->SetExpressCheckout( %args ); this will print the XML being sent, and dump a Perl data structure of the SOM received on STDERR (so check your error_log if running inside a web server). If anyone knows how to turn a SOAP::SOM object into XML without setting B, let me know. =head1 DEVELOPMENT If you are a developer wanting to extend B for other PayPal API calls, you can review any of the included modules (e.g., F or F) for examples on how to do this until I have more time to write a more complete document. But in a nutshell: package Business::PayPal::API::SomeAPI; use 5.008001; use strict; use warnings; use SOAP::Lite 0.67; use Business::PayPal::API (); our @ISA = qw(Business::PayPal::API); our @EXPORT_OK = qw( SomeAPIMethod ); sub SomeAPIMethod { ... } Notice the B<@EXPORT_OK> variable. This is I used by B (we don't load Exporter at all): it is a special variable used by B to know which methods to import when B is run like this: use Business::PayPal::API qw( SomeAPI ); That is, B will import any subroutine into its own namespace from the B<@EXPORT_OK> array. Now it can be used like this: use Business::PayPal::API qw( SomeAPI ); my $pp = Business::PayPal::API->new( ... ); $pp->SomeAPIMethod( ... ); Of course, we also do a 'use Business::PayPal::API' in the module so that it can be used as a standalone module, if necessary: use Business::PayPal::API::SomeAPI; my $pp = Business::PayPal::API::SomeAPI->new( ... ); ## same args as superclass $pp->SomeAPIMethod( ... ); Adding the B<@EXPORT_OK> array in your module allows your module to be used in the most convenient way for the given circumstances. =head1 EXAMPLES Andy Spiegl has kindly donated some example code (in German) for the ExpressCheckout API which may be found in the F directory of this archive. Additional code examples for other APIs may be found in the F test directory. =head1 EXPORT None by default. =head1 CAVEATS Because I haven't figured out how to make SOAP::Lite read the WSDL definitions directly and simply implement those (help, anyone?), I have essentially recreated all of those WSDL structures internally in this module. (Note - 6 Oct 2006: SOAP::Lite's WSDL support is moving ahead, but slowly. The methods used by this API are considered "best practice" and are safe to use). As with all web services, if PayPal stop supporting their API endpoint, this module *may stop working*. You can help me keep this module up-to-date if you notice such an event occurring. Also, I didn't implement a big fat class hierarchy to make this module "academically" correct. You'll notice that I fudged colliding parameter names in B and similar fudging may be found in B. The good news is that this was written quickly, works, and is dead-simple to use. The bad news is that this sort of collision might occur again as more and more data is sent in the API (call it 'eBay API bloat'). I'm willing to take the risk this will be rare (PayPal--please make it rare!). =head1 ACKNOWLEDGEMENTS Wherein I acknowledge all the good folks who have contributed to this module in some way: =over 4 =item * Daniel P. Hembree for authoring the AuthorizationRequest, CaptureRequest, DirectPayments, ReauthorizationRequest, and VoidRequest extensions. =item * for finding some API typos in the ExpressCheckout API =item * Andy Spiegl for giving me the heads-up on PayPal's new 3-token auth URI and for a sample command-line program (found in the 'eg' directory) demonstrating the ExpressCheckout API. =item * Ollie Ready for the heads-up on the newest 3-token auth URI as well as a pile of documentation inconsistencies. =item * Michael Hendricks for a patch that adds ShippingTotal to the DirectPayments module. =item * Erik Aronesty, Drew Simpson via rt.cpan.org (#28596) for a patch to fix getFields() when multiple items are returned =item * Sebastian Böhm via email, SDC via rt.cpan.org (#38915) for a heads-up that the PayPal documentation for MassPay API was wrong regarding the I parameter. =item * Jonathon Wright via email for patches for B and B that implement I and I API calls. =back =head1 SEE ALSO L, L, L =head1 AUTHORS =over 4 =item * Scott Wiersdorf =item * Danny Hembree =item * Bradley M. Kuhn =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2006-2017 by Scott Wiersdorf, Danny Hembree, Bradley M. Kuhn. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Business-PayPal-API-0.76/lib/Business/PayPal/API/AuthorizationRequest.pm000644 000765 000024 00000010173 13077411465 026041 0ustar00olafstaff000000 000000 package Business::PayPal::API::AuthorizationRequest; $Business::PayPal::API::AuthorizationRequest::VERSION = '0.76'; use 5.008001; use strict; use warnings; use SOAP::Lite 0.67; #use SOAP::Lite +trace => 'debug'; use Business::PayPal::API (); our @ISA = qw(Business::PayPal::API); our @EXPORT_OK = qw(DoAuthorizationRequest); sub DoAuthorizationRequest { my $self = shift; my %args = @_; my %types = ( TransactionID => 'xs:string', Amount => 'ebl:BasicAmountType', ); $args{currencyID} ||= 'USD'; my @ref_trans = ( $self->version_req, SOAP::Data->name( TransactionID => $args{TransactionID} ) ->type( $types{TransactionID} ), ); push @ref_trans, SOAP::Data->name( Amount => $args{Amount} )->type( $types{Amount} ) ->attr( { currencyID => $args{currencyID} } ); my $request = SOAP::Data->name( DoAuthorizationRequest => \SOAP::Data->value(@ref_trans) ) ->type("ns:AuthorizationRequestType"); my $som = $self->doCall( DoAuthorizationReq => $request ) or return; my $path = '/Envelope/Body/DoAuthorizationResponse'; my %response = (); unless ( $self->getBasic( $som, $path, \%response ) ) { $self->getErrors( $som, $path, \%response ); return %response; } $self->getFields( $som, $path, \%response, { TransactionID => 'TransactionID', Amount => 'Amount', } ); return %response; } 1; =pod =encoding UTF-8 =head1 NAME Business::PayPal::API::AuthorizationRequest - PayPal AuthorizationRequest API =head1 VERSION version 0.76 =head1 SYNOPSIS use Business::PayPal::API::AuthorizationRequest; ## see Business::PayPal::API documentation for parameters my $pp = new Business::PayPal::API::DoAuthorizationRequest ( ... ); my %response = $pp->DoAuthorizationRequest ( TransactionID => $transid, CurrencyID => $currencyID, Amount => $amout, ); =head1 DESCRIPTION B implements PayPal's B API using SOAP::Lite to make direct API calls to PayPal's SOAP API server. It also implements support for testing via PayPal's I. Please see L for details on using the PayPal sandbox. This request is only used with "Order" type Authorizations. An "Order" must first be placed using the ExpressCheckout module. DirectPayment authorizations can only be used for "Basic" authorizations. =head2 AuthorizationRequest Implements PayPal's B API call. Supported parameters include: TransactionID Amount currencyID (defaults to 'USD' if not supplied) as described in the PayPal "Web Services API Reference" document. The default B setting is 'USD' if not otherwise specified. Returns a hash containing the results of the transaction. Example: my %resp = $pp->DoAuthorizationRequest ( TransactionID => $trans_id, Amount => '15.00', ); unless( $resp{Ack} ne 'Success' ) { for my $error ( @{$response{Errors}} ) { warn "Error: " . $error->{LongMessage} . "\n"; } } =head2 ERROR HANDLING See the B section of B for information on handling errors. =head2 EXPORT None by default. =head1 SEE ALSO L =head1 AUTHORS =over 4 =item * Scott Wiersdorf =item * Danny Hembree =item * Bradley M. Kuhn =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2006-2017 by Scott Wiersdorf, Danny Hembree, Bradley M. Kuhn. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut __END__ # ABSTRACT: PayPal AuthorizationRequest API Business-PayPal-API-0.76/lib/Business/PayPal/API/CaptureRequest.pm000644 000765 000024 00000012644 13077411465 024611 0ustar00olafstaff000000 000000 package Business::PayPal::API::CaptureRequest; $Business::PayPal::API::CaptureRequest::VERSION = '0.76'; use 5.008001; use strict; use warnings; use SOAP::Lite 0.67; #use SOAP::Lite +trace => 'debug'; use Business::PayPal::API (); our @ISA = qw(Business::PayPal::API); our @EXPORT_OK = qw(DoCaptureRequest); sub DoCaptureRequest { my $self = shift; my %args = @_; my %types = ( AuthorizationID => 'xs:string', #The inclusion of the "ebl:CompleteCodeType" here, or any other reasonable type, #causes and error. Assigning a null string allows the module to work normally #with the exception that testing for "Success" fails, one must test for not #being a "Failure"... there may be a life lesson here. CompleteType => '', Amount => 'ebl:BasicAmountType', Note => 'xs:string', ); $args{currencyID} ||= 'USD'; $args{CompleteType} ||= 'Complete'; my @ref_trans = ( $self->version_req, SOAP::Data->name( AuthorizationID => $args{AuthorizationID} ) ->type( $types{AuthorizationID} ), SOAP::Data->name( CompleteType => $args{CompleteType} ) ->type( $types{CompleteType} ), ); if ( $args{Amount} ) { push @ref_trans, SOAP::Data->name( Amount => $args{Amount} ) ->type( $types{Amount} ) ->attr( { currencyID => $args{currencyID} } ); } my $request = SOAP::Data->name( DoCaptureRequest => \SOAP::Data->value(@ref_trans) ) ->type("ns:DoCaptureRequestType"); my $som = $self->doCall( DoCaptureReq => $request ) or return; my $path = '/Envelope/Body/DoCaptureResponse'; my %response = (); unless ( $self->getBasic( $som, $path, \%response ) ) { $self->getErrors( $som, $path, \%response ); return %response; } $path .= '/DoCaptureResponseDetails/PaymentInfo'; $self->getFields( $som, $path, \%response, { TransactionID => 'TransactionID', ParentTransactionID => 'ParentTransactionID', ReceiptID => 'ReceiptID', TransactionType => 'TransactionType', PaymentType => 'PaymentType', PaymentDate => 'PaymentDate', GrossAmount => 'GrossAmount', FeeAmount => 'FeeAmount', SettleAmount => 'SettleAmount', TaxAmount => 'TaxAmount', ExchangeRate => 'ExchangeRate', PaymentStatus => 'PaymentStatus', PendingReason => 'PendingReason', ReasonCode => 'ReasonCode', } ); return %response; } 1; =pod =encoding UTF-8 =head1 NAME Business::PayPal::API::CaptureRequest - PayPal CaptureRequest API =head1 VERSION version 0.76 =head1 SYNOPSIS use Business::PayPal::API::CaptureRequest; ## see Business::PayPal::API documentation for parameters my $pp = new Business::PayPal::API::DoCaptureRequest ( ... ); my %response = $pp->DoCaptureRequest( AuthorizationID => $transid, CompleteType => 'Complete', Amount => '13.00', Note => "Give the fiddler his due." ); =head1 DESCRIPTION B implements PayPal's B API using SOAP::Lite to make direct API calls to PayPal's SOAP API server. It also implements support for testing via PayPal's I. Please see L for details on using the PayPal sandbox. =head2 CaptureRequest Implements PayPal's B API call. Supported parameters include: AuthorizationID CompleteType (defaults to 'Complete' unless set to 'NotComplete') Amount currencyID (Currently must be the default, 'USD') Note ("String, < 255 char, indicating information about the charges.") as described in the PayPal "Web Services API Reference" document. The default B setting is 'USD' if not otherwise specified. The default B setting is 'Complete' if not otherwise specified. Returns a hash containing the results of the transaction. Example: my %resp = $pp->DoCaptureRequest ( AuthorizationID => $auth_id, CompleteType => 'NotComplete', Amount => '15.00', CurrencyID => 'USD', ); if( $resp{Ack} eq 'Failure' ) { for my $error ( @{$response{Errors}} ) { warn "Error: " . $error->{LongMessage} . "\n"; } } =head2 ERROR HANDLING See the B section of B for information on handling errors. =head2 EXPORT None by default. =head1 SEE ALSO L =head1 AUTHORS =over 4 =item * Scott Wiersdorf =item * Danny Hembree =item * Bradley M. Kuhn =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2006-2017 by Scott Wiersdorf, Danny Hembree, Bradley M. Kuhn. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut __END__ # ABSTRACT: PayPal CaptureRequest API Business-PayPal-API-0.76/lib/Business/PayPal/API/DirectPayments.pm000644 000765 000024 00000027167 13077411465 024576 0ustar00olafstaff000000 000000 package Business::PayPal::API::DirectPayments; $Business::PayPal::API::DirectPayments::VERSION = '0.76'; use 5.008001; use strict; use warnings; use SOAP::Lite; #use SOAP::Lite +trace => 'debug'; use Business::PayPal::API (); our @ISA = qw(Business::PayPal::API); our @EXPORT_OK = qw(DoDirectPaymentRequest); sub DoDirectPaymentRequest { my $self = shift; my %args = @_; my %types = ( PaymentAction => '', # Payment Detail OrderTotal => 'xs:string', ItemTotal => 'xsd:string', ShippingTotal => 'xsd:string', TaxTotal => 'xsd:string', InvoiceID => 'xsd:string', ButtonSource => 'xsd:string', # Credit Card CreditCardType => '', CreditCardNumber => 'xsd:string', ExpMonth => 'xs:int', ExpYear => 'xs:int', # CardOwner Payer => 'ns:EmailAddressType', # Payer Name FirstName => 'xs:string', LastName => 'xs:string', # Payer Address Street1 => 'xs:string', Street2 => 'xs:string', CityName => 'xs:string', StateOrProvince => 'xs:string', Country => 'xs:string', PostalCode => 'xs:string', # Shipping Address ShipToName => 'xs:string', ShipToStreet1 => 'xs:string', ShipToStreet2 => 'xs:string', ShipToCityName => 'xs:string', ShipToStateOrProvince => 'xs:string', ShipToCountry => 'xs:string', ShipToPostalCode => 'xs:string', # Misc CVV2 => 'xs:string', IPAddress => 'xs:string', MerchantSessionId => 'xs:string', ); $args{currencyID} ||= 'USD'; $args{PaymentAction} ||= 'Sale'; #Assemble Credit Card Information my @payername = ( SOAP::Data->name( FirstName => $args{FirstName} ), SOAP::Data->name( LastName => $args{LastName} ), ); my @payeraddr = ( SOAP::Data->name( Street1 => $args{Street1} ) ->type( $types{Street1} ), SOAP::Data->name( Street2 => $args{Street2} ) ->type( $types{Street2} ), SOAP::Data->name( CityName => $args{CityName} ) ->type( $types{CityName} ), SOAP::Data->name( StateOrProvince => $args{StateOrProvince} ) ->type( $types{StateOrProvince} ), SOAP::Data->name( Country => $args{Country} ) ->type( $types{Country} ), SOAP::Data->name( PostalCode => $args{PostalCode} ) ->type( $types{PostalCode} ), ); my @shipaddr = ( SOAP::Data->name( Name => $args{ShipToName} ) ->type( $types{ShipToName} ), SOAP::Data->name( Street1 => $args{ShipToStreet1} ) ->type( $types{ShipToStreet1} ), SOAP::Data->name( Street2 => $args{ShipToStreet2} ) ->type( $types{ShipToStreet2} ), SOAP::Data->name( CityName => $args{ShipToCityName} ) ->type( $types{ShipToCityName} ), SOAP::Data->name( StateOrProvince => $args{ShipToStateOrProvince} ) ->type( $types{ShipToStateOrProvince} ), SOAP::Data->name( Country => $args{ShipToCountry} ) ->type( $types{ShipToCountry} ), SOAP::Data->name( PostalCode => $args{ShipToPostalCode} ) ->type( $types{ShipToPostalCode} ), ); my @ccard = ( SOAP::Data->name( CreditCardType => $args{CreditCardType} ) ->type( $types{CreditCardType} ), SOAP::Data->name( CreditCardNumber => $args{CreditCardNumber} ) ->type( $types{CreditCardNumber} ), SOAP::Data->name( ExpMonth => $args{ExpMonth} ) ->type( $types{ExpMonth} ), SOAP::Data->name( ExpYear => $args{ExpYear} ) ->type( $types{ExpYear} ), ); my @ccowner = ( SOAP::Data->name( CardOwner => \SOAP::Data->value( SOAP::Data->name( Payer => $args{Payer} ) ->type( $types{Payer} ), SOAP::Data->name( PayerName => \SOAP::Data->value(@payername) ), SOAP::Data->name( Address => \SOAP::Data->value(@payeraddr) ), ) ) ); push( @ccard, @ccowner ); push( @ccard, SOAP::Data->name( CVV2 => $args{CVV2} )->type( $types{CVV2} ) ); #Assemble Payment Details my @paydetail = ( SOAP::Data->name( OrderTotal => $args{OrderTotal} ) ->attr( { currencyID => $args{currencyID} } ) ->type( $types{currencyID} ), SOAP::Data->name( ItemTotal => $args{ItemTotal} ) ->attr( { currencyID => $args{currencyID} } ) ->type( $types{currencyID} ), SOAP::Data->name( TaxTotal => $args{TaxTotal} ) ->attr( { currencyID => $args{currencyID} } ) ->type( $types{currencyID} ), SOAP::Data->name( ShippingTotal => $args{ShippingTotal} ) ->attr( { currencyID => $args{currencyID} } ) ->type( $types{currencyID} ), SOAP::Data->name( ShipToAddress => \SOAP::Data->value(@shipaddr) ), SOAP::Data->name( InvoiceID => $args{InvoiceID} ) ->type( $types{InvoiceID} ), SOAP::Data->name( ButtonSource => $args{ButtonSource} ) ->type( $types{ButtonSource} ) ); my @payreqdetail = ( SOAP::Data->name( PaymentAction => $args{PaymentAction} )->type(''), SOAP::Data->name( PaymentDetails => \SOAP::Data->value(@paydetail) ), SOAP::Data->name( CreditCard => \SOAP::Data->value(@ccard) ), SOAP::Data->name( IPAddress => $args{IPAddress} ) ->type( $types{IPAddress} ), SOAP::Data->name( MerchantSessionId => $args{MerchantSessionId} ) ->type( $types{MerchantSessionId} ), ); #Assemble request my @reqval = ( SOAP::Data->value( $self->version_req ), SOAP::Data->name( DoDirectPaymentRequestDetails => \SOAP::Data->value(@payreqdetail) )->attr( { xmlns => "urn:ebay:apis:eBLBaseComponents" } ), ); my $request = ( SOAP::Data->name( DoDirectPaymentRequest => \SOAP::Data->value(@reqval) ), ); my $som = $self->doCall( DoDirectPaymentReq => $request ) or return; my $path = '/Envelope/Body/DoDirectPaymentResponse'; my %response = (); unless ( $self->getBasic( $som, $path, \%response ) ) { $self->getErrors( $som, $path, \%response ); return %response; } $self->getFields( $som, $path, \%response, { TransactionID => 'TransactionID', Amount => 'Amount', AVSCode => 'AVSCode', CVV2Code => 'CVV2Code', Timestamp => 'Timestamp', } ); return %response; } 1; =pod =encoding UTF-8 =head1 NAME Business::PayPal::API::DirectPayments - PayPal DirectPayments API =head1 VERSION version 0.76 =head1 SYNOPSIS use Business::PayPal::API qw(DirectPayments); ## see Business::PayPal::API documentation for parameters my $pp = Business::PayPal::API->new( Username => 'name_api1.example.org', Password => 'somepass', CertFile => '/path/to/tester1.cert_key_pem.txt', KeyFile => '/path/to/tester1.cert_key_pem.txt', sandbox => 1, ); my %response = $pp->DoDirectPaymentRequest ( PaymentAction => 'Sale', OrderTotal => 13.59, TaxTotal => 0.0, ShippingTotal => 0.0, ItemTotal => 0.0, HandlingTotal => 0.0, InvoiceID => 'your-tracking-number', CreditCardType => 'Visa', CreditCardNumber => '4561435600988217', ExpMonth => '01', ExpYear => '2007', CVV2 => '123', FirstName => 'James', LastName => 'PuffDaddy', Street1 => '1st Street LaCausa', Street2 => '', CityName => 'La', StateOrProvince => 'Ca', PostalCode => '90210', Country => 'US', Payer => 'Joe@Example.org', ShipToName => 'Jane Doe', ShipToStreet1 => '1234 S. Pleasant St.', ShipToStreet2 => 'Suite #992', ShipToCityName => 'Vacation Town', ShipToStateOrProvince => 'FL', ShipToCountry => 'US', ShipToPostalCode => '12345', CurrencyID => 'USD', IPAddress => '10.0.0.1', MerchantSessionID => '10113301', ); =head1 DESCRIPTION B implements PayPal's B API using SOAP::Lite to make direct API calls to PayPal's SOAP API server. It also implements support for testing via PayPal's I. Please see L for details on using the PayPal sandbox. =head2 DoDirectPaymentRequest Implements PayPal's B API call. Supported parameters include: PaymentAction ( Sale|Authorize, Sale is default ) OrderTotal TaxTotal ShippingTotal ItemTotal HandlingTotal InvoiceID CreditCardType CreditCardNumber ExpMonth ( two digits, leading zero ) ExpYear ( four digits, 20XX ) CVV2 FirstName LastName Street1 Street2 CityName StateOrProvince PostalCode Country Payer ShipToName ShipToStreet1 ShipToStreet2 ShipToCityName ShipToStateOrProvince ShipToCountry ShipToPostalCode CurrencyID (USD is default) IPAddress MerchantSessionID as described in the PayPal "Web Services API Reference" document. Returns a hash containing the results of the transaction. The B element and TransactionID are the most useful return values. Example: my %resp = $pp->DoDirectPaymentRequest( PaymentAction => 'Sale', OrderTotal => '10.99', ... ); unless( $resp{Ack} !~ /Success/ ) { for my $error ( @{$response{Errors}} ) { warn "Error: " . $error->{LongMessage} . "\n"; } } =head2 ERROR HANDLING See the B section of B for information on handling errors. =head2 EXPORT None by default. =head1 SEE ALSO L =head1 AUTHORS =over 4 =item * Scott Wiersdorf =item * Danny Hembree =item * Bradley M. Kuhn =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2006-2017 by Scott Wiersdorf, Danny Hembree, Bradley M. Kuhn. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut __END__ # ABSTRACT: PayPal DirectPayments API Business-PayPal-API-0.76/lib/Business/PayPal/API/ExpressCheckout.pm000644 000765 000024 00000046044 13077411465 024755 0ustar00olafstaff000000 000000 package Business::PayPal::API::ExpressCheckout; $Business::PayPal::API::ExpressCheckout::VERSION = '0.76'; use 5.008001; use strict; use warnings; use SOAP::Lite 0.67; use Business::PayPal::API (); our @ISA = qw(Business::PayPal::API); our @EXPORT_OK = qw( SetExpressCheckout GetExpressCheckoutDetails DoExpressCheckoutPayment ); ## if you specify an InvoiceID, PayPal seems to remember it and not ## allow you to bill twice with it. sub SetExpressCheckout { my $self = shift; my %args = @_; my %types = ( Token => 'ebl:ExpressCheckoutTokenType', OrderTotal => 'cc:BasicAmountType', currencyID => '', MaxAmount => 'cc:BasicAmountType', OrderDescription => 'xs:string', Custom => 'xs:string', InvoiceID => 'xs:string', ReturnURL => 'xs:string', CancelURL => 'xs:string', Address => 'ebl:AddressType', ReqConfirmShipping => 'xs:string', NoShipping => 'xs:string', AddressOverride => 'xs:string', LocaleCode => 'xs:string', PageStyle => 'xs:string', 'cpp-header-image' => 'xs:string', 'cpp-header-border-color' => 'xs:string', 'cpp-header-back-color' => 'xs:string', 'cpp-payflow-color' => 'xs:string', PaymentAction => '', BuyerEmail => 'ebl:EmailAddressType' ); ## billing agreement details type my %badtypes = ( BillingType => '', #'ns:BillingCodeType', BillingAgreementDescription => 'xs:string', PaymentType => '', #'ns:MerchantPullPaymentCodeType', BillingAgreementCustom => 'xs:string', ); ## set some defaults $args{PaymentAction} ||= 'Sale'; $args{currencyID} ||= 'USD'; my $currencyID = delete $args{currencyID}; ## SetExpressCheckoutRequestDetails my @secrd = ( SOAP::Data->name( OrderTotal => delete $args{OrderTotal} ) ->type( $types{OrderTotal} )->attr( { currencyID => $currencyID, xmlns => $self->C_xmlns_ebay } ), SOAP::Data->name( ReturnURL => delete $args{ReturnURL} ) ->type( $types{ReturnURL} ), SOAP::Data->name( CancelURL => delete $args{CancelURL} ) ->type( $types{CancelURL} ), ); ## add all the other fields for my $field ( keys %types ) { next unless defined $args{$field}; if ( $field eq 'MaxAmount' ) { push @secrd, SOAP::Data->name( $field => $args{$field} ) ->type( $types{$field} ) ->attr( { currencyID => $currencyID, xmlns => $self->C_xmlns_ebay } ); } elsif ( $field eq 'Address' ) { my $address = $args{$field}; my %address_types = ( Name => 'xs:string', Street1 => 'xs:string', Street2 => 'xs:string', CityName => 'xs:string', StateOrProvince => 'xs:string', Country => 'xs:string', PostalCode => 'xs:string', ); my @address; foreach my $k ( keys %address_types ) { if ( defined $address->{$k} ) { push @address, SOAP::Data->name( $k => $address->{$k} ) ->type( $address_types{$k} ); } } if (@address) { push @secrd, SOAP::Data->name( $field => \SOAP::Data->value(@address)->type( $types{$field} ) ->attr( { xmlns => $self->C_xmlns_ebay } ) ); } } else { push @secrd, SOAP::Data->name( $field => $args{$field} ) ->type( $types{$field} ); } } my @btypes = (); for my $field ( keys %badtypes ) { next unless $args{$field}; push @btypes, SOAP::Data->name( $field => $args{$field} ) ->type( $badtypes{$field} ); } push @secrd, SOAP::Data->name( BillingAgreementDetails => \SOAP::Data->value(@btypes) ) if $args{'BillingType'}; my $request = SOAP::Data->name( SetExpressCheckoutRequest => \SOAP::Data->value( $self->version_req, SOAP::Data->name( SetExpressCheckoutRequestDetails => \SOAP::Data->value(@secrd) )->attr( { xmlns => $self->C_xmlns_ebay } ), ) )->type('ns:SetExpressCheckoutRequestType'); my $som = $self->doCall( SetExpressCheckoutReq => $request ) or return; my $path = '/Envelope/Body/SetExpressCheckoutResponse'; my %response = (); unless ( $self->getBasic( $som, $path, \%response ) ) { $self->getErrors( $som, $path, \%response ); return %response; } $self->getFields( $som, $path, \%response, { Token => 'Token' } ); return %response; } sub GetExpressCheckoutDetails { my $self = shift; my $token = shift; my $request = SOAP::Data->name( GetExpressCheckoutDetailsRequest => \SOAP::Data->value( $self->version_req, SOAP::Data->name( Token => $token )->type('xs:string') ->attr( { xmlns => $self->C_xmlns_ebay } ), ) )->type('ns:GetExpressCheckoutRequestType'); my $som = $self->doCall( GetExpressCheckoutDetailsReq => $request ) or return; my $path = '/Envelope/Body/GetExpressCheckoutDetailsResponse'; my %details = (); unless ( $self->getBasic( $som, $path, \%details ) ) { $self->getErrors( $som, $path, \%details ); return %details; } $self->getFields( $som, "$path/GetExpressCheckoutDetailsResponseDetails", \%details, { Token => 'Token', Custom => 'Custom', InvoiceID => 'InvoiceID', ContactPhone => 'ContactPhone', Payer => 'PayerInfo/Payer', PayerID => 'PayerInfo/PayerID', PayerStatus => 'PayerInfo/PayerStatus', Salutation => 'PayerInfo/PayerName/Salutation', FirstName => 'PayerInfo/PayerName/FirstName', MiddleName => 'PayerInfo/PayerName/MiddleName', LastName => 'PayerInfo/PayerName/LastName', NameSuffix => 'PayerInfo/PayerName/Suffix', PayerBusiness => 'PayerInfo/PayerBusiness', AddressStatus => 'PayerInfo/Address/AddressStatus', Name => 'PayerInfo/Address/Name', Street1 => 'PayerInfo/Address/Street1', Street2 => 'PayerInfo/Address/Street2', CityName => 'PayerInfo/Address/CityName', StateOrProvince => 'PayerInfo/Address/StateOrProvince', PostalCode => 'PayerInfo/Address/PostalCode', Country => 'PayerInfo/Address/Country', PayerCountry => 'PayerInfo/PayerCountry', } ); return %details; } sub DoExpressCheckoutPayment { my $self = shift; my %args = @_; my %types = ( Token => 'xs:string', PaymentAction => '', ## NOTA BENE! PayerID => 'ebl:UserIDType', currencyID => '', ReturnFMFDetails => 'xs:boolean', ); ## PaymentDetails my %pd_types = ( OrderTotal => 'ebl:BasicAmountType', OrderDescription => 'xs:string', ItemTotal => 'ebl:BasicAmountType', ShippingTotal => 'ebl:BasicAmountType', HandlingTotal => 'ebl:BasicAmountType', TaxTotal => 'ebl:BasicAmountType', Custom => 'xs:string', InvoiceID => 'xs:string', ButtonSource => 'xs:string', NotifyURL => 'xs:string', ); ## ShipToAddress my %st_types = ( ST_Name => 'xs:string', ST_Street1 => 'xs:string', ST_Street2 => 'xs:string', ST_CityName => 'xs:string', ST_StateOrProvince => 'xs:string', ST_Country => 'xs:string', ST_PostalCode => 'xs:string', ); ##PaymentDetailsItem my %pdi_types = ( PDI_Name => 'xs:string', PDI_Amount => 'ebl:BasicAmountType', PDI_Number => 'xs:string', PDI_Quantity => 'xs:string', PDI_Tax => 'ebl:BasicAmountType', ); $args{PaymentAction} ||= 'Sale'; $args{currencyID} ||= 'USD'; my @payment_details = (); ## push OrderTotal here and delete it (i.e., and all others that have special attrs) push @payment_details, SOAP::Data->name( OrderTotal => $args{OrderTotal} ) ->type( $pd_types{OrderTotal} )->attr( { currencyID => $args{currencyID}, xmlns => $self->C_xmlns_ebay } ); ## don't process it again delete $pd_types{OrderTotal}; for my $field ( keys %pd_types ) { if ( $args{$field} ) { push @payment_details, SOAP::Data->name( $field => $args{$field} ) ->type( $pd_types{$field} ); } } ## ## ShipToAddress ## my @ship_types = (); for my $field ( keys %st_types ) { if ( $args{$field} ) { ( my $name = $field ) =~ s/^ST_//; push @ship_types, SOAP::Data->name( $name => $args{$field} ) ->type( $st_types{$field} ); } } if ( scalar @ship_types ) { push @payment_details, SOAP::Data->name( ShipToAddress => \SOAP::Data->value(@ship_types)->type('ebl:AddressType') ->attr( { xmlns => $self->C_xmlns_ebay } ), ); } ## ## PaymentDetailsItem ## my @payment_details_item = (); for my $field ( keys %pdi_types ) { if ( $args{$field} ) { ( my $name = $field ) =~ s/^PDI_//; push @payment_details_item, SOAP::Data->name( $name => $args{$field} ) ->type( $pdi_types{$field} ); } } if ( scalar @payment_details_item ) { push @payment_details, SOAP::Data->name( PaymentDetailsItem => \SOAP::Data->value(@payment_details_item) ->type('ebl:PaymentDetailsItemType') ->attr( { xmlns => $self->C_xmlns_ebay } ), ); } ## ## ExpressCheckoutPaymentDetails ## my @express_details = ( SOAP::Data->name( Token => $args{Token} )->type( $types{Token} ) ->attr( { xmlns => $self->C_xmlns_ebay } ), SOAP::Data->name( PaymentAction => $args{PaymentAction} ) ->type( $types{PaymentAction} ) ->attr( { xmlns => $self->C_xmlns_ebay } ), SOAP::Data->name( PayerID => $args{PayerID} ) ->type( $types{PayerID} ) ->attr( { xmlns => $self->C_xmlns_ebay } ), SOAP::Data->name( PaymentDetails => \SOAP::Data->value(@payment_details) ->type('ebl:PaymentDetailsType') ->attr( { xmlns => $self->C_xmlns_ebay } ), ), SOAP::Data->name( ReturnFMFDetails => $args{ReturnFMFDetails} ) ->type( $types{ReturnFMFDetails} ) ->attr( { xmlns => $self->C_xmlns_ebay } ), ); ## ## the main request object ## my $request = SOAP::Data->name( DoExpressCheckoutPaymentRequest => \SOAP::Data->value( $self->version_req, SOAP::Data->name( DoExpressCheckoutPaymentRequestDetails => \SOAP::Data->value(@express_details) ->type('ns:DoExpressCheckoutPaymentRequestDetailsType') )->attr( { xmlns => $self->C_xmlns_ebay } ), ) ); my $som = $self->doCall( DoExpressCheckoutPaymentReq => $request ) or return; my $path = '/Envelope/Body/DoExpressCheckoutPaymentResponse'; my %response = (); unless ( $self->getBasic( $som, $path, \%response ) ) { $self->getErrors( $som, $path, \%response ); return %response; } $self->getFields( $som, "$path/DoExpressCheckoutPaymentResponseDetails", \%response, { Token => 'Token', BillingAgreementID => 'BillingAgreementID', TransactionID => 'PaymentInfo/TransactionID', TransactionType => 'PaymentInfo/TransactionType', PaymentType => 'PaymentInfo/PaymentType', PaymentDate => 'PaymentInfo/PaymentDate', GrossAmount => 'PaymentInfo/GrossAmount', FeeAmount => 'PaymentInfo/FeeAmount', SettleAmount => 'PaymentInfo/SettleAmount', TaxAmount => 'PaymentInfo/TaxAmount', ExchangeRate => 'PaymentInfo/ExchangeRate', PaymentStatus => 'PaymentInfo/PaymentStatus', PendingReason => 'PaymentInfo/PendingReason', AcceptFilters => 'FMFDetails/AcceptFilters', DenyFilters => 'FMFDetails/DenyFilters', PendingFilters => 'FMFDetails/PendingFilters', ReportsFilters => 'FMFDetails/ReportsFilters', ProtectionEligibility => 'PaymentInfo/ProtectionEligibility', } ); return %response; } 1; =pod =encoding UTF-8 =head1 NAME Business::PayPal::API::ExpressCheckout - PayPal Express Checkout API =head1 VERSION version 0.76 =head1 SYNOPSIS use Business::PayPal::API::ExpressCheckout; ## see Business::PayPal::API documentation for parameters my $pp = Business::PayPal::API::ExpressCheckout->new( ... ); my %resp = $pp->SetExpressCheckout ( OrderTotal => '55.43', ## defaults to USD ReturnURL => 'http://site.tld/return.html', CancelURL => 'http://site.tld/cancellation.html', ); ... time passes, buyer validates the token with PayPal ... my %details = $pp->GetExpressCheckoutDetails($resp{Token}); ## now ask PayPal to xfer the money my %payinfo = $pp->DoExpressCheckoutPayment( Token => $details{Token}, PaymentAction => 'Sale', PayerID => $details{PayerID}, OrderTotal => '55.43' ); =head1 DESCRIPTION B implements PayPal's B using SOAP::Lite to make direct API calls to PayPal's SOAP API server. It also implements support for testing via PayPal's I. Please see L for details on using the PayPal sandbox. =head2 SetExpressCheckout Implements PayPal's "Website Payment Pro" B API call. Supported parameters include: Token OrderTotal currencyID MaxAmount OrderDescription Custom InvoiceID ReturnURL CancelURL Address ReqConfirmShipping NoShipping AddressOverride LocaleCode PageStyle 'cpp-header-image' 'cpp-header-border-color' 'cpp-header-back-color' 'cpp-payflow-color' PaymentAction BuyerEmail BillingType BillingAgreementDescription PaymentType BillingAgreementCustom as described in the PayPal "Web Services API Reference" document. The default currency setting is 'USD' if not otherwise specified. Returns a hash containing a 'Token' key, whose value represents the PayPal transaction token. Required fields: OrderTotal, ReturnURL, CancelURL. my %resp = $pp->SetExpressCheckout(); my $token = $resp{Token}; Example (courtesy Ollie Ready): my $address = { Name => 'Some Customer', Street1 => '888 Test St.', Street2 => 'Suite 9', CityName => 'San Diego', StateOrProvince => 'CA', PostalCode => '92111', Country => 'US', Phone => '123-123-1234', }; my %response = $pp->SetExpressCheckout( OrderTotal => '11.01', ReturnURL => '', CancelURL => 'http://example.com', PaymentAction => 'Authorization', AddressOverride => 1, Address => $address, ); =head2 GetExpressCheckoutDetails Implements PayPal's WPP B API call. Supported parameters include: Token as described in the PayPal "Web Services API Reference" document. This is the same token you received from B. Returns a hash with the following keys: Token Custom InvoiceID ContactPhone Payer PayerID PayerStatus FirstName LastName PayerBusiness AddressStatus Name Street1 Street2 CityName StateOrProvince PostalCode Country Required fields: Token =head2 DoExpressCheckoutPayment Implements PayPal's WPP B API call. Supported parameters include: Token PaymentAction (defaults to 'Sale' if not supplied) PayerID currencyID (defaults to 'USD' if not supplied) OrderTotal OrderDescription ItemTotal ShippingTotal HandlingTotal TaxTotal Custom InvoiceID ButtonSource NotifyURL ST_Name ST_Street1 ST_Street2 ST_CityName ST_StateOrProvince ST_Country ST_PostalCode PDI_Name PDI_Amount PDI_Number PDI_Quantity PDI_Tax as described in the PayPal "Web Services API Reference" document. Returns a hash with the following keys: Token TransactionID TransactionType PaymentType PaymentDate GrossAmount FeeAmount SettleAmount TaxAmount ExchangeRate PaymentStatus PendingReason BillingAgreementID (if BillingType 'MerchantInitiatedBilling' was specified during SetExpressCheckout) Required fields: Token, PayerID, OrderTotal =head2 ERROR HANDLING See the B section of B for information on handling errors. =head1 EXAMPLES Andy Spiegl has kindly donated some example code (in German) which may be found in the F directory of this archive. Additional code examples may be found in the F test directory. =head2 EXPORT None by default. =head1 SEE ALSO L, L, L, L =head1 AUTHORS =over 4 =item * Scott Wiersdorf =item * Danny Hembree =item * Bradley M. Kuhn =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2006-2017 by Scott Wiersdorf, Danny Hembree, Bradley M. Kuhn. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut __END__ # ABSTRACT: PayPal Express Checkout API Business-PayPal-API-0.76/lib/Business/PayPal/API/GetBalance.pm000644 000765 000024 00000003165 13077411465 023620 0ustar00olafstaff000000 000000 package Business::PayPal::API::GetBalance; $Business::PayPal::API::GetBalance::VERSION = '0.76'; use 5.008001; use strict; use warnings; use SOAP::Lite 0.67; use Business::PayPal::API (); our @ISA = qw(Business::PayPal::API); our @EXPORT_OK = qw(GetBalance); ## fake exporter sub GetBalance { my $self = shift; my %args = @_; my @trans = ( $self->version_req, ); my $request = SOAP::Data->name( GetBalanceRequest => \SOAP::Data->value(@trans) ) ->type("ns:GetBalanceRequestType"); my $som = $self->doCall( GetBalanceReq => $request ) or return; my $path = '/Envelope/Body/GetBalanceResponse'; my %response = (); unless ( $self->getBasic( $som, $path, \%response ) ) { $self->getErrors( $som, $path, \%response ); return %response; } $self->getFields( $som, $path, \%response, { Balance => 'Balance', BalanceTimeStamp => 'BalanceTimeStamp', } ); return %response; } 1; =pod =encoding UTF-8 =head1 NAME Business::PayPal::API::GetBalance - PayPal GetBalance API =head1 VERSION version 0.76 =head1 AUTHORS =over 4 =item * Scott Wiersdorf =item * Danny Hembree =item * Bradley M. Kuhn =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2006-2017 by Scott Wiersdorf, Danny Hembree, Bradley M. Kuhn. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut __END__ # ABSTRACT: PayPal GetBalance API Business-PayPal-API-0.76/lib/Business/PayPal/API/GetTransactionDetails.pm000644 000765 000024 00000026663 13077411465 026076 0ustar00olafstaff000000 000000 package Business::PayPal::API::GetTransactionDetails; $Business::PayPal::API::GetTransactionDetails::VERSION = '0.76'; use 5.008001; use strict; use warnings; use SOAP::Lite 0.67; use Business::PayPal::API (); our @ISA = qw(Business::PayPal::API); our @EXPORT_OK = qw(GetTransactionDetails); ## fake exporter sub GetTransactionDetails { my $self = shift; my %args = @_; my @trans = ( $self->version_req, SOAP::Data->name( TransactionID => $args{TransactionID} ) ->type('xs:string'), ); my $request = SOAP::Data->name( GetTransactionDetailsRequest => \SOAP::Data->value(@trans) ) ->type("ns:GetTransactionDetailsRequestType"); my $som = $self->doCall( GetTransactionDetailsReq => $request ) or return; my $path = '/Envelope/Body/GetTransactionDetailsResponse'; my %response = (); unless ( $self->getBasic( $som, $path, \%response ) ) { $self->getErrors( $som, $path, \%response ); return %response; } $path .= '/PaymentTransactionDetails'; $self->getFields( $som, $path, \%response, { Business => '/ReceiverInfo/Business', Receiver => '/ReceiverInfo/Receiver', ReceiverID => '/ReceiverInfo/ReceiverID', Payer => '/PayerInfo/Payer', PayerID => '/PayerInfo/PayerID', PayerStatus => '/PayerInfo/PayerStatus', Salutation => '/PayerInfo/PayerName/Salutation', FirstName => '/PayerInfo/PayerName/FirstName', MiddleName => '/PayerInfo/PayerName/MiddleName', LastName => '/PayerInfo/PayerName/LastName', PayerCountry => '/PayerInfo/PayerCountry', PayerBusiness => '/PayerInfo/PayerBusiness', AddressOwner => '/PayerInfo/Address/AddressOwner', AddressStatus => '/PayerInfo/Address/AddressStatus', ADD_Name => '/PayerInfo/Address/Name', Street1 => '/PayerInfo/Address/Street1', Street2 => '/PayerInfo/Address/Street2', CityName => '/PayerInfo/Address/CityName', StateOrProvince => '/PayerInfo/Address/StateOrProvince', Country => '/PayerInfo/Address/Country', CountryName => '/PayerInfo/Address/CountryName', Phone => '/PayerInfo/Address/Phone', PostalCode => '/PayerInfo/Address/PostalCode', TransactionID => '/PaymentInfo/TransactionID', ParentTransactionID => '/PaymentInfo/ParentTransactionID', ReceiptID => '/PaymentInfo/ReceiptID', TransactionType => '/PaymentInfo/TransactionType', PaymentType => '/PaymentInfo/PaymentType', PaymentDate => '/PaymentInfo/PaymentDate', GrossAmount => '/PaymentInfo/GrossAmount', FeeAmount => '/PaymentInfo/FeeAmount', SettleAmount => '/PaymentInfo/SettleAmount', TaxAmount => '/PaymentInfo/TaxAmount', ExchangeRate => '/PaymentInfo/ExchangeRate', PaymentStatus => '/PaymentInfo/PaymentStatus', PendingReason => '/PaymentInfo/PendingReason', ReasonCode => '/PaymentInfo/ReasonCode', ProtectionEligibility => '/PaymentInfo/ProtectionEligibility', InvoiceID => '/PaymentItemInfo/InvoiceID', Custom => '/PaymentItemInfo/Custom', Memo => '/PaymentItemInfo/Memo', SalesTax => '/PaymentItemInfo/SalesTax', PII_SalesTax => '/PaymentItemInfo/PaymentItem/SalesTax', PII_Name => '/PaymentItemInfo/PaymentItem/Name', PII_Number => '/PaymentItemInfo/PaymentItem/Number', PII_Quantity => '/PaymentItemInfo/PaymentItem/Quantity', PII_Amount => '/PaymentItemInfo/PaymentItem/Amount', PII_Options => '/PaymentItemInfo/PaymentItem/Options', PII_SubscriptionID => '/PaymentItemInfo/Subscription/SubscriptionID', PII_SubscriptionDate => '/PaymentItemInfo/Subscription/SubscriptionDate', PII_EffectiveDate => '/PaymentItemInfo/Subscription/EffectiveDate', PII_RetryTime => '/PaymentItemInfo/Subscription/RetryTime', PII_Username => '/PaymentItemInfo/Subscription/Username', PII_Password => '/PaymentItemInfo/Subscription/Password', PII_Recurrences => '/PaymentItemInfo/Subscription/Recurrences', PII_reattempt => '/PaymentItemInfo/Subscription/reattempt', PII_recurring => '/PaymentItemInfo/Subscription/recurring', PII_Amount => '/PaymentItemInfo/Subscription/Amount', PII_period => '/PaymentItemInfo/Subscription/period', PII_BuyerID => '/PaymentItemInfo/Auction/BuyerID', PII_ClosingDate => '/PaymentItemInfo/Auction/ClosingDate', PII_multiItem => '/PaymentItemInfo/Auction/multiItem', } ); ## multiple payment items my $paymentitems = $self->getFieldsList( $som, $path . '/PaymentItemInfo/PaymentItem', { SalesTax => 'SalesTax', Name => 'Name', Number => 'Number', Quantity => 'Quantity', Amount => 'Amount', } ); if ( scalar(@$paymentitems) > 0 ) { # Options data must be extracted differently. Specifically, the # "interesting" parts of the Options data is not in the values inside # the $som structure (which means $som->valueof(), which # $self->getFieldsList() above calls underneath, won't extract the # useful data, because the values are empty. # The convoluted loop below finds any Options values and matches them # up properly with the correct PaymentItem. Note that the loop is # written this way to account for the fact that there may be multiple # PaymentItems. # Finally, I contemplated placing this loop below in getFieldsList() # with a special-case for Options, but I am not sure it belongs # there. Ultimately, I think this is unique to the # GetTransactionsDetails call in the API, and thus it's more # appropriately placed here. my $ii = 0; my @fulloptions; foreach my $rec ( $som->dataof( $path . '/PaymentItemInfo/PaymentItem' ) ) { my %options; foreach my $subrec ( $rec->value() ) { foreach my $fieldrec ( $$subrec->value() ) { $options{ $fieldrec->attr()->{name} } = $fieldrec->attr()->{value} if ( $fieldrec->name() eq "Options" ); } } $paymentitems->[$ii]{Options} = \%options; push( @fulloptions, \%options ); } # Now, we can save the payment items properly $response{PaymentItems} = $paymentitems; # And set the PII_Options properly too. $response{PII_Options} = \@fulloptions; } return %response; } 1; =pod =encoding UTF-8 =head1 NAME Business::PayPal::API::GetTransactionDetails - PayPal GetTransactionDetails API =head1 VERSION version 0.76 =head1 SYNOPSIS use Business::PayPal::API::GetTransactionDetails; my $pp = Business::PayPal::API::GetTransactionDetails->new( ... ); or # see Business::PayPal::API documentation for parameters use Business::PayPal::API qw(GetTransactionDetails); my $pp = Business::PayPal::API->new( ... ); my %response = $pp->GetTransactionDetails( TransactionID => $transid, ); =head1 DESCRIPTION B implements PayPal's B API using SOAP::Lite to make direct API calls to PayPal's SOAP API server. It also implements support for testing via PayPal's I. Please see L for details on using the PayPal sandbox. =head2 GetTransactionDetails Implements PayPal's B API call. Supported parameters include: TransactionID as described in the PayPal "Web Services API Reference" document. Returns a hash containing the transaction details, including these fields: Business Receiver ReceiverID Payer PayerID PayerStatus Salutation FirstName MiddleName LastName PayerCountry PayerBusiness AddressOwner AddressStatus ADD_Name Street1 Street2 CityName StateOrProvince Country CountryName Phone PostalCode TransactionID ParentTransactionID ReceiptID TransactionType PaymentType PaymentDate GrossAmount FeeAmount SettleAmount TaxAmount ExchangeRate PaymentStatus PendingReason ReasonCode InvoiceID Custom Memo SalesTax PII_SaleTax PII_Name PII_Number PII_Quantity PII_Amount PII_Options PII_SubscriptionID PII_SubscriptionDate PII_EffectiveDate PII_RetryTime PII_Username PII_Password PII_Recurrences PII_reattempt PII_recurring PII_Amount PII_period PII_BuyerID PII_ClosingDate PII_multiItem As described in the API document. Note: some fields have prefixes to remove ambiguity for like-named fields (e.g., "PII_"). If there are multiple PaymentItems, then an additional field 'PaymentItems' will be available with an arrayref of PaymentItem records: PaymentItems => [ { SalesTax => ..., Name => '...', Number => '...', Quantity => '...', Amount => '...', Options => { 'key0' => 'value0', 'key1' => 'value1' }, }, { SalesTax => ..., etc. } ] Example: my %resp = $pp->GetTransactionDetails( TransactionID => $trans_id ); print "Payer: $resp{Payer}\n"; for my $item ( @{ $resp{PaymentItems} } ) { print "Name: " . $item->{Name} . "\n"; print "Amt: " . $item->{Amount} . "\n"; for my $optionname (keys %$item->{Options}) { print "Option: $optionname is " . $item->{Options}{$optionname} . "\n"; } } =head2 PaymentItem Options Limitations Note, BTW, that PayPal has a limitation such that each PaymentItem can contain only two Options. See: L L This hack may be of interest if you want to sneak in four options: L =head2 ERROR HANDLING See the B section of B for information on handling errors. =head2 EXPORT None by default. =head1 SEE ALSO L =head1 AUTHORS =over 4 =item * Scott Wiersdorf =item * Danny Hembree =item * Bradley M. Kuhn =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2006-2017 by Scott Wiersdorf, Danny Hembree, Bradley M. Kuhn. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut __END__ # ABSTRACT: PayPal GetTransactionDetails API Business-PayPal-API-0.76/lib/Business/PayPal/API/MassPay.pm000644 000765 000024 00000012723 13077411465 023210 0ustar00olafstaff000000 000000 package Business::PayPal::API::MassPay; $Business::PayPal::API::MassPay::VERSION = '0.76'; use 5.008001; use strict; use warnings; use SOAP::Lite 0.67; use Business::PayPal::API (); our @ISA = qw(Business::PayPal::API); our @EXPORT_OK = qw( MassPay ); sub MassPay { my $self = shift; my %args = @_; ## set some defaults $args{currencyID} ||= 'USD'; $args{ReceiverType} ||= 'EmailAddress'; $args{MassPayItems} ||= []; $args{Version} ||= "1.0"; my %types = ( EmailSubject => 'xs:string', Version => 'xsd:string', # ReceiverType => 'ebl:ReceiverInfoCodeType', ## EmailAddress | UserID ); my %attr = ( Version => { xmlns => $self->C_xmlns_ebay }, Amount => { currencyID => $args{currencyID} }, ); ## mass pay item my %mpi_type = ( ReceiverEmail => 'ebl:EmailAddressType', ReceiverID => 'xs:string', Amount => 'ebl:BasicAmountType', UniqueId => 'xs:string', Note => 'xs:string', ); my @recipients = @{ $args{MassPayItems} }; my @masspay = (); for my $type ( sort keys %types ) { next unless $args{$type}; if ( $attr{$type} ) { push @masspay, SOAP::Data->name( $type => $args{$type} ) ->type( $types{$type} )->attr( { %{ $attr{$type} } } ); } else { push @masspay, SOAP::Data->name( $type => $args{$type} ) ->type( $types{$type} ); } } if ( $args{ReceiverType} eq 'UserID' ) { delete $mpi_type{ReceiverEmail}; } else { delete $mpi_type{ReceiverID}; } for my $rcpt (@recipients) { my @rcpt = (); for my $type ( keys %mpi_type ) { next unless $mpi_type{$type}; if ( $attr{$type} ) { push @rcpt, SOAP::Data->name( $type => $rcpt->{$type} ) ->type( $mpi_type{$type} )->attr( { %{ $attr{$type} } } ); } else { push @rcpt, SOAP::Data->name( $type => $rcpt->{$type} ) ->type( $mpi_type{$type} ); } } push @masspay, SOAP::Data->name( MassPayItem => \SOAP::Data->value(@rcpt) ) ->type("ns:MassPayRequestItemType"); } my $request = SOAP::Data->name( MassPayRequest => \SOAP::Data->value(@masspay) ) ->type("ns:MassPayRequestType"); my $som = $self->doCall( MassPayReq => $request ) or return; my $path = '/Envelope/Body/MassPayResponse'; my %response = (); unless ( $self->getBasic( $som, $path, \%response ) ) { $self->getErrors( $som, $path, \%response ); return %response; } return %response; } 1; =pod =encoding UTF-8 =head1 NAME Business::PayPal::API::MassPay - PayPal MassPay API =head1 VERSION version 0.76 =head1 SYNOPSIS use Business::PayPal::API::MassPay; ## see Business::PayPal::API documentation for parameters my $pp = Business::PayPal::API::MassPay->new( ... ); my %response = $pp->MassPay( EmailSubject => "Here's your moola", MassPayItems => [ { ReceiverEmail => 'joe@somewhere.tld', Amount => '95.44', Note => 'Thanks for your stuff!' }, { ReceiverEmail => 'bob@elsewhere.tld', Amount => '15.31', Note => 'We owe you one' }, ] ); =head1 DESCRIPTION B implements PayPal's B API using SOAP::Lite to make direct API calls to PayPal's SOAP API server. It also implements support for testing via PayPal's I. Please see L for details on using the PayPal sandbox. =head2 MassPay Implements PayPal's B API call. Supported parameters include: EmailSubject MassPayItems The B parameter is a list reference of hashrefs, each containing the following fields: ReceiverEmail Amount UniqueId Note as described in the PayPal "Web Services API Reference" document. Returns a hash containing the generic response structure (as per the PayPal Web Services API). Example: my %resp = $pp->MassPay( EmailSubject => "This is the subject", MassPayItems => [ { ReceiverEmail => 'joe@test.tld', Amount => '24.00', UniqueId => "123456", Note => "Enjoy the money. Don't spend it all in one place." } ] ); unless( $resp{Ack} !~ /Success/ ) { die "Failed: " . $resp{Errors}[0]{LongMessage} . "\n"; } =head2 ERROR HANDLING See the B section of B for information on handling errors. =head1 EXPORT None by default. =head1 SEE ALSO L =head1 AUTHORS =over 4 =item * Scott Wiersdorf =item * Danny Hembree =item * Bradley M. Kuhn =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2006-2017 by Scott Wiersdorf, Danny Hembree, Bradley M. Kuhn. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut __END__ # ABSTRACT: PayPal MassPay API Business-PayPal-API-0.76/lib/Business/PayPal/API/ReauthorizationRequest.pm000644 000765 000024 00000007761 13077411465 026401 0ustar00olafstaff000000 000000 package Business::PayPal::API::ReauthorizationRequest; $Business::PayPal::API::ReauthorizationRequest::VERSION = '0.76'; use 5.008001; use strict; use warnings; use SOAP::Lite 0.67; use Business::PayPal::API (); our @ISA = qw(Business::PayPal::API); our @EXPORT_OK = qw(DoReauthorizationRequest); sub DoReauthorizationRequest { my $self = shift; my %args = @_; my %types = ( AuthorizationID => 'xs:string', Amount => 'ebl:BasicAmountType', ); $args{currencyID} ||= 'USD'; my @ref_trans = ( $self->version_req, SOAP::Data->name( AuthorizationID => $args{AuthorizationID} ) ->type( $types{AuthorizationID} ), ); push @ref_trans, SOAP::Data->name( Amount => $args{Amount} )->type( $types{Amount} ) ->attr( { currencyID => $args{currencyID} } ); my $request = SOAP::Data->name( DoReauthorizationRequest => \SOAP::Data->value(@ref_trans) ) ->type("ns:ReauthorizationRequestType"); my $som = $self->doCall( DoReauthorizationReq => $request ) or return; my $path = '/Envelope/Body/DoReauthorizationResponse'; my %response = (); unless ( $self->getBasic( $som, $path, \%response ) ) { $self->getErrors( $som, $path, \%response ); return %response; } $self->getFields( $som, $path, \%response, { AuthorizationID => 'AuthorizationID', Amount => 'Amount', } ); return %response; } 1; =pod =encoding UTF-8 =head1 NAME Business::PayPal::API::ReauthorizationRequest - PayPal ReauthorizationRequest API =head1 VERSION version 0.76 =head1 SYNOPSIS use Business::PayPal::API::ReauthorizationRequest; ## see Business::PayPal::API documentation for parameters my $pp = Business::PayPal::API::ReauthorizationRequest->new( ... ); my %response = $pp->DoReauthorizationRequest( AuthorizationID => $transid, Amount => $amount, CurrencyID => $currencyID ); =head1 DESCRIPTION B implements PayPal's B API using SOAP::Lite to make direct API calls to PayPal's SOAP API server. It also implements support for testing via PayPal's I. Please see L for details on using the PayPal sandbox. =head2 DoReauthorizationRequest Implements PayPal's B API call. Supported parameters include: AuthorizationID Amount currencyID (defaults to 'USD' if not supplied) as described in the PayPal "Web Services API Reference" document. The default B setting is 'USD' if not otherwise specified. The DoReauthorization is not allowed before the three day grace period set for the original AuthorizeRequest. Returns a hash containing the results of the transaction. Example: my %resp = $pp->DoReauthorizationRequest ( AuthorizationID => $trans_id, Amount => '15.00', CurrencyID => 'USD' ); unless( $resp{Ack} !~ /Success/ ) { for my $error ( @{$response{Errors}} ) { warn "Error: " . $error->{LongMessage} . "\n"; } } =head2 ERROR HANDLING See the B section of B for information on handling errors. =head2 EXPORT None by default. =head1 SEE ALSO L =head1 AUTHORS =over 4 =item * Scott Wiersdorf =item * Danny Hembree =item * Bradley M. Kuhn =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2006-2017 by Scott Wiersdorf, Danny Hembree, Bradley M. Kuhn. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut __END__ # ABSTRACT: PayPal ReauthorizationRequest API Business-PayPal-API-0.76/lib/Business/PayPal/API/RecurringPayments.pm000644 000765 000024 00000051730 13077411465 025315 0ustar00olafstaff000000 000000 package Business::PayPal::API::RecurringPayments; $Business::PayPal::API::RecurringPayments::VERSION = '0.76'; use 5.008001; use strict; use warnings; use SOAP::Lite 0.67; use Business::PayPal::API (); our @ISA = qw(Business::PayPal::API); our @EXPORT_OK = qw( SetCustomerBillingAgreement GetBillingAgreementCustomerDetails CreateRecurringPaymentsProfile DoReferenceTransaction); our $API_VERSION = '50.0'; sub SetCustomerBillingAgreement { my $self = shift; my %args = @_; ## billing agreement details type my %badtypes = ( BillingType => '', # 'ns:BillingCodeType', BillingAgreementDescription => 'xs:string', PaymentType => '', # 'ns:MerchantPullPaymentCodeType', BillingAgreementCustom => 'xs:string', ); my %types = ( BillingAgreementDetails => 'ns:BillingAgreementDetailsType', ReturnURL => 'xs:string', CancelURL => 'xs:string', LocaleCode => 'xs:string', PageStyle => 'xs:string', 'cpp-header-image' => 'xs:string', 'cpp-header-border-color' => 'xs:string', 'cpp-header-back-color' => 'xs:string', 'cpp-payflow-color' => 'xs:string', PaymentAction => '', BuyerEmail => 'ns:EmailAddressType', ); ## set defaults $args{BillingType} ||= 'RecurringPayments'; $args{PaymentType} ||= 'InstantOnly'; $args{currencyID} ||= 'USD'; my @btypes = (); for my $field ( keys %badtypes ) { next unless $args{$field}; push @btypes, SOAP::Data->name( $field => $args{$field} ) ->type( $badtypes{$field} ); } my @scba = (); for my $field ( keys %types ) { next unless $args{$field}; push @scba, SOAP::Data->name( $field => $args{$field} ) ->type( $types{$field} ); } push @scba, SOAP::Data->name( BillingAgreementDetails => \SOAP::Data->value(@btypes) ); my $request = SOAP::Data->name( SetCustomerBillingAgreementRequest => \SOAP::Data->value( $self->version_req, #$API_VERSION, SOAP::Data->name( SetCustomerBillingAgreementRequestDetails => \SOAP::Data->value(@scba) )->attr( { xmlns => $self->C_xmlns_ebay } ), ) )->type('ns:SetCustomerBillingAgreementRequestDetailsType'); my $som = $self->doCall( SetCustomerBillingAgreementReq => $request ) or return; my $path = '/Envelope/Body/SetCustomerBillingAgreementResponse'; my %response = (); unless ( $self->getBasic( $som, $path, \%response ) ) { $self->getErrors( $som, $path, \%response ); return %response; } $self->getFields( $som, $path, \%response, { Token => 'Token' } ); return %response; } sub GetBillingAgreementCustomerDetails { my $self = shift; my $token = shift; my $request = SOAP::Data->name( GetBillingAgreementCustomerDetailsRequest => \SOAP::Data->value( $self->version_req, SOAP::Data->name( Token => $token )->type('xs:string') ->attr( { xmlns => $self->C_xmlns_ebay } ), ) )->type('ns:GetBillingAgreementCustomerDetailsResponseType'); my $som = $self->doCall( GetBillingAgreementCustomerDetailsReq => $request ) or return; my $path = '/Envelope/Body/GetBillingAgreementCustomerDetailsResponse'; my %details = (); unless ( $self->getBasic( $som, $path, \%details ) ) { $self->getErrors( $som, $path, \%details ); return %details; } $self->getFields( $som, "$path/GetBillingAgreementCustomerDetailsResponseDetails", \%details, { Token => 'Token', Payer => 'PayerInfo/Payer', PayerID => 'PayerInfo/PayerID', PayerStatus => 'PayerInfo/PayerStatus', ## 'unverified' PayerBusiness => 'PayerInfo/PayerBusiness', Name => 'PayerInfo/Address/Name', AddressOwner => 'PayerInfo/Address/AddressOwner', ## 'PayPal' AddressStatus => 'PayerInfo/Address/AddressStatus', ## 'none' Street1 => 'PayerInfo/Address/Street1', Street2 => 'PayerInfo/Address/Street2', StateOrProvince => 'PayerInfo/Address/StateOrProvince', PostalCode => 'PayerInfo/Address/PostalCode', CountryName => 'PayerInfo/Address/CountryName', Salutation => 'PayerInfo/PayerName/Salutation', FirstName => 'PayerInfo/PayerName/FirstName', MiddleName => 'PayerInfo/PayerName/MiddleName', LastName => 'PayerInfo/PayerName/LastName', Suffix => 'PayerInfo/PayerName/Suffix', } ); return %details; } sub CreateRecurringPaymentsProfile { my $self = shift; my %args = @_; ## RecurringPaymentProfileDetails my %profiledetailstype = ( SubscriberName => 'xs:string', SubscriberShipperAddress => 'ns:AddressType', BillingStartDate => 'xs:dateTime', ## MM-DD-YY ProfileReference => 'xs:string', ); ## ScheduleDetailsType my %schedtype = ( Description => 'xs:string', ActivationDetails => 'ns:ActivationDetailsType', TrialPeriod => 'ns:BillingPeriodDetailsType', PaymentPeriod => 'ns:BillingPeriodDetailsType', MaxFailedPayments => 'xs:int', AutoBillOutstandingAmount => 'ns:AutoBillType', ); ## NoAutoBill or AddToNextBilling ## activation details my %activationdetailstype = ( InitialAmount => 'cc:BasicAmountType', FailedInitialAmountAction => 'ns:FailedPaymentAction', ); ## ContinueOnFailure or CancelOnFailure ## BillingPeriodDetailsType my %trialbilltype = ( TrialBillingPeriod => 'xs:string', ##'ns:BillingPeriodType', TrialBillingFrequency => 'xs:int', TrialTotalBillingCycles => 'xs:int', TrialAmount => 'cc:AmountType', TrialShippingAmount => 'cc:AmountType', TrialTaxAmount => 'cc:AmountType', ); my %paymentbilltype = ( PaymentBillingPeriod => 'xs:string', ##'ns:BillingPeriodType', PaymentBillingFrequency => 'xs:int', PaymentTotalBillingCycles => 'xs:int', PaymentAmount => 'cc:AmountType', PaymentShippingAmount => 'cc:AmountType', PaymentTaxAmount => 'cc:AmountType', ); ## AddressType my %payaddrtype = ( CCPayerName => 'xs:string', CCPayerStreet1 => 'xs:string', CCPayerStreet2 => 'xs:string', CCPayerCityName => 'xs:string', CCPayerStateOrProvince => 'xs:string', CCPayerCountry => 'xs:string', ## ebl:CountryCodeType CCPayerPostalCode => 'xs:string', CCPayerPhone => 'xs:string', ); my %shipaddrtype = ( SubscriberShipperName => 'xs:string', SubscriberShipperStreet1 => 'xs:string', SubscriberShipperStreet2 => 'xs:string', SubscriberShipperCityName => 'xs:string', SubscriberShipperStateOrProvince => 'xs:string', SubscriberShipperCountry => 'xs:string', ## ebl:CountryCodeType SubscriberShipperPostalCode => 'xs:string', SubscriberShipperPhone => 'xs:string', ); ## credit card payer my %payerinfotype = ( CCPayer => 'ns:EmailAddressType', CCPayerID => 'ebl:UserIDType', CCPayerStatus => 'xs:string', CCPayerName => 'xs:string', CCPayerCountry => 'xs:string', CCPayerPhone => 'xs:string', CCPayerBusiness => 'xs:string', CCAddress => 'xs:string', ); ## credit card details my %creditcarddetailstype = ( CardOwner => 'ns:PayerInfoType', CreditCardType => 'ebl:CreditCardType' , ## Visa, MasterCard, Discover, Amex, Switch, Solo CreditCardNumber => 'xs:string', ExpMonth => 'xs:int', ExpYear => 'xs:int', CVV2 => 'xs:string', StartMonth => 'xs:string', StartYear => 'xs:string', IssueNumber => 'xs:int', ); ## this gets pushed onto scheduledetails my @activationdetailstype = (); for my $field ( keys %activationdetailstype ) { next unless exists $args{$field}; my $real_field = $field; push @activationdetailstype, SOAP::Data->name( $real_field => $args{$field} ) ->type( $activationdetailstype{$field} ); } ## this gets pushed onto scheduledetails my @trialbilltype = (); for my $field ( keys %trialbilltype ) { next unless exists $args{$field}; ( my $real_field = $field ) =~ s/^Trial//; push @trialbilltype, SOAP::Data->name( $real_field => $args{$field} ) ->type( $trialbilltype{$field} ); } ## this gets pushed onto scheduledetails my @paymentbilltype = (); for my $field ( keys %paymentbilltype ) { next unless exists $args{$field}; ( my $real_field = $field ) =~ s/^Payment//; push @paymentbilltype, SOAP::Data->name( $real_field => $args{$field} ) ->type( $paymentbilltype{$field} ); } ## this gets pushed onto the top my @sched = (); for my $field ( keys %schedtype ) { next unless exists $args{$field}; push @sched, SOAP::Data->name( $field => $args{$field} ) ->type( $schedtype{$field} ); } push @sched, SOAP::Data->name( TrialPeriod => \SOAP::Data->value(@trialbilltype) ) ; #->type( 'ns:BillingPeriodDetailsType' ); push @sched, SOAP::Data->name( PaymentPeriod => \SOAP::Data->value(@paymentbilltype) ) ; #->type( 'ns:BillingPeriodDetailsType' ); ## this gets pushed into profile details my @shipaddr = (); for my $field ( keys %shipaddrtype ) { next unless exists $args{$field}; ( my $real_field = $field ) =~ s/^SubscriberShipper//; push @shipaddr, SOAP::Data->name( $real_field => $args{$field} ) ->type( $shipaddrtype{$field} ); } ## this gets pushed into payerinfo (from creditcarddetails) my @payeraddr = (); for my $field ( keys %payaddrtype ) { next unless $args{$field}; ( my $real_field = $field ) =~ s/^CCPayer//; push @payeraddr, SOAP::Data->name( $real_field => $args{$field} ) ->type( payaddrtype { $field } ); } ## credit card type my @creditcarddetails = (); for my $field ( keys %creditcarddetailstype ) { next unless $args{$field}; ( my $real_field = $field ) =~ s/^CC//; push @payeraddr, SOAP::Data->name( $real_field => $args{$field} ) ->type( payaddrtype { $field } ); } ## this gets pushed onto the top my @profdetail = (); for my $field ( keys %profiledetailstype ) { next unless exists $args{$field}; push @profdetail, SOAP::Data->name( $field => $args{$field} ) ->type( $profiledetailstype{$field} ); } push @profdetail, SOAP::Data->name( SubscriberShipperAddress => \SOAP::Data->value(@shipaddr) ); ## crappard? my @crpprd = (); push @crpprd, SOAP::Data->name( Token => $args{Token} ); push @crpprd, SOAP::Data->name( CreditCardDetails => \SOAP::Data->value(@creditcarddetails) ) ; #->type( 'ns:CreditCardDetailsType' ); push @crpprd, SOAP::Data->name( RecurringPaymentProfileDetails => \SOAP::Data->value(@profdetail) ) ; #->type( 'ns:RecurringPaymentProfileDetailsType' ); push @crpprd, SOAP::Data->name( ScheduleDetails => \SOAP::Data->value(@sched) ) ; #->type( 'ns:ScheduleDetailsType' ); my $request = SOAP::Data->name( CreateRecurringPaymentsProfileRequest => \SOAP::Data->value # ( $API_VERSION, ( $self->version_req, SOAP::Data->name( CreateRecurringPaymentsProfileRequestDetails => \SOAP::Data->value(@crpprd) )->attr( { xmlns => $self->C_xmlns_ebay } ) ) ); #->type( 'ns:CreateRecurringPaymentsProfileRequestType' ); my $som = $self->doCall( CreateRecurringPaymentsProfileReq => $request ) or return; my $path = '/Envelope/Body/CreateRecurringPaymentsProfileResponse'; my %response = (); unless ( $self->getBasic( $som, $path, \%response ) ) { $self->getErrors( $som, $path, \%response ); return %response; } $self->getFields( $som, $path, \%response, { Token => 'Token' } ); return %response; } sub DoReferenceTransaction { my $self = shift; my %args = @_; my %types = ( ReferenceID => 'xs:string', PaymentAction => '', ## NOTA BENE! currencyID => '', ); ## PaymentDetails my %pd_types = ( OrderTotal => 'ebl:BasicAmountType', OrderDescription => 'xs:string', ItemTotal => 'ebl:BasicAmountType', ShippingTotal => 'ebl:BasicAmountType', HandlingTotal => 'ebl:BasicAmountType', TaxTotal => 'ebl:BasicAmountType', Custom => 'xs:string', InvoiceID => 'xs:string', ButtonSource => 'xs:string', NotifyURL => 'xs:string', ); ## ShipToAddress my %st_types = ( ST_Name => 'xs:string', ST_Street1 => 'xs:string', ST_Street2 => 'xs:string', ST_CityName => 'xs:string', ST_StateOrProvince => 'xs:string', ST_Country => 'xs:string', ST_PostalCode => 'xs:string', ST_Phone => 'xs:string', ); ##PaymentDetailsItem my %pdi_types = ( PDI_Name => 'xs:string', PDI_Description => 'xs:string', PDI_Amount => 'ebl:BasicAmountType', PDI_Number => 'xs:string', PDI_Quantity => 'xs:string', PDI_Tax => 'ebl:BasicAmountType', ); $args{PaymentAction} ||= 'Sale'; $args{currencyID} ||= 'USD'; my @payment_details = (); ## push OrderTotal here and delete it (i.e., and all others that have special attrs) push @payment_details, SOAP::Data->name( OrderTotal => $args{OrderTotal} ) ->type( $pd_types{OrderTotal} )->attr( { currencyID => $args{currencyID}, xmlns => $self->C_xmlns_ebay } ); ## don't process it again delete $pd_types{OrderTotal}; for my $field ( keys %pd_types ) { if ( $args{$field} ) { push @payment_details, SOAP::Data->name( $field => $args{$field} ) ->type( $pd_types{$field} ); } } ## ## ShipToAddress ## my @ship_types = (); for my $field ( keys %st_types ) { if ( $args{$field} ) { ( my $name = $field ) =~ s/^ST_//; push @ship_types, SOAP::Data->name( $name => $args{$field} ) ->type( $st_types{$field} ); } } if ( scalar @ship_types ) { push @payment_details, SOAP::Data->name( ShipToAddress => \SOAP::Data->value(@ship_types)->type('ebl:AddressType') ->attr( { xmlns => $self->C_xmlns_ebay } ), ); } ## ## PaymentDetailsItem ## my @payment_details_item = (); for my $field ( keys %pdi_types ) { if ( $args{$field} ) { ( my $name = $field ) =~ s/^PDI_//; push @payment_details_item, SOAP::Data->name( $name => $args{$field} ) ->type( $pdi_types{$field} ); } } if ( scalar @payment_details_item ) { push @payment_details, SOAP::Data->name( PaymentDetailsItem => \SOAP::Data->value(@payment_details_item) ->type('ebl:PaymentDetailsItemType') ->attr( { xmlns => $self->C_xmlns_ebay } ), ); } ## ## ReferenceTransactionPaymentDetails ## my @reference_details = ( SOAP::Data->name( ReferenceID => $args{ReferenceID} ) ->type( $types{ReferenceID} ) ->attr( { xmlns => $self->C_xmlns_ebay } ), SOAP::Data->name( PaymentAction => $args{PaymentAction} ) ->type( $types{PaymentAction} ) ->attr( { xmlns => $self->C_xmlns_ebay } ), SOAP::Data->name( PaymentDetails => \SOAP::Data->value(@payment_details) ->type('ebl:PaymentDetailsType') ->attr( { xmlns => $self->C_xmlns_ebay } ), ), ); ## ## the main request object ## my $request = SOAP::Data->name( DoReferenceTransactionRequest => \SOAP::Data->value( $self->version_req, SOAP::Data->name( DoReferenceTransactionRequestDetails => \SOAP::Data->value(@reference_details) ->type('ns:DoReferenceTransactionRequestDetailsType') )->attr( { xmlns => $self->C_xmlns_ebay } ), ) ); my $som = $self->doCall( DoReferenceTransactionReq => $request ) or return; my $path = '/Envelope/Body/DoReferenceTransactionResponse'; my %response = (); unless ( $self->getBasic( $som, $path, \%response ) ) { $self->getErrors( $som, $path, \%response ); return %response; } $self->getFields( $som, "$path/DoReferenceTransactionResponseDetails", \%response, { BillingAgreementID => 'BillingAgreementID', TransactionID => 'PaymentInfo/TransactionID', TransactionType => 'PaymentInfo/TransactionType', PaymentType => 'PaymentInfo/PaymentType', PaymentDate => 'PaymentInfo/PaymentDate', GrossAmount => 'PaymentInfo/GrossAmount', FeeAmount => 'PaymentInfo/FeeAmount', SettleAmount => 'PaymentInfo/SettleAmount', TaxAmount => 'PaymentInfo/TaxAmount', ExchangeRate => 'PaymentInfo/ExchangeRate', PaymentStatus => 'PaymentInfo/PaymentStatus', PendingReason => 'PaymentInfo/PendingReason', ReasonCode => 'PaymentInfor/ReasonCode', } ); return %response; } 1; =pod =encoding UTF-8 =head1 NAME Business::PayPal::API::RecurringPayments - PayPal RecurringPayments API =head1 VERSION version 0.76 =head1 SYNOPSIS use Business::PayPal::API::RecurringPayments; my $pp = Business::PayPal::API::RecurringPayments->new( ... ); my %resp = $pp->FIXME # Ask PayPal to charge a new transaction from the ReferenceID # This method is used both for Recurring Transactions as well # as for Express Checkout's MerchantInitiatedBilling, where # ReferenceID is the BillingAgreementID returned from # ExpressCheckout->DoExpressCheckoutPayment my %payinfo = $pp->DoReferenceTransaction( ReferenceID => $details{ReferenceID}, PaymentAction => 'Sale', OrderTotal => '55.43' ); =head1 DESCRIPTION THIS MODULE IS NOT COMPLETE YET. PLEASE DO NOT REPORT ANY BUGS RELATED TO IT. =head2 DoReferenceTransaction Implements PayPal's WPP B API call. Supported parameters include: ReferenceID (aka BillingAgreementID) PaymentAction (defaults to 'Sale' if not supplied) currencyID (defaults to 'USD' if not supplied) OrderTotal OrderDescription ItemTotal ShippingTotal HandlingTotal TaxTotal Custom InvoiceID ButtonSource NotifyURL ST_Name ST_Street1 ST_Street2 ST_CityName ST_StateOrProvince ST_Country ST_PostalCode ST_Phone PDI_Name PDI_Description PDI_Amount PDI_Number PDI_Quantity PDI_Tax as described in the PayPal "Web Services API Reference" document. Returns a hash with the following keys: BillingAgreementID TransactionID TransactionType PaymentType PaymentDate GrossAmount FeeAmount SettleAmount TaxAmount ExchangeRate PaymentStatus PendingReason ReasonCode Required fields: ReferenceID, OrderTotal =head1 SEE ALSO L =head1 AUTHORS =over 4 =item * Scott Wiersdorf =item * Danny Hembree =item * Bradley M. Kuhn =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2006-2017 by Scott Wiersdorf, Danny Hembree, Bradley M. Kuhn. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut __END__ # ABSTRACT: PayPal RecurringPayments API Business-PayPal-API-0.76/lib/Business/PayPal/API/RefundTransaction.pm000644 000765 000024 00000011435 13077411465 025263 0ustar00olafstaff000000 000000 package Business::PayPal::API::RefundTransaction; $Business::PayPal::API::RefundTransaction::VERSION = '0.76'; use 5.008001; use strict; use warnings; use SOAP::Lite 0.67; use Business::PayPal::API (); our @ISA = qw(Business::PayPal::API); our @EXPORT_OK = qw(RefundTransaction); sub RefundTransaction { my $self = shift; my %args = @_; my %types = ( TransactionID => 'xs:string', RefundType => '', ## Other | Full | Partial Amount => 'ebl:BasicAmountType', Memo => 'xs:string', ); $args{currencyID} ||= 'USD'; $args{RefundType} ||= 'Full'; my @ref_trans = ( $self->version_req, SOAP::Data->name( TransactionID => $args{TransactionID} ) ->type( $types{TransactionID} ), SOAP::Data->name( RefundType => $args{RefundType} ) ->type( $types{RefundType} ), ); if ( $args{RefundType} ne 'Full' && $args{Amount} ) { push @ref_trans, SOAP::Data->name( Amount => $args{Amount} ) ->type( $types{Amount} ) ->attr( { currencyID => $args{currencyID} } ); } push @ref_trans, SOAP::Data->name( Memo => $args{Memo} )->type( $types{Memo} ) if $args{Memo}; my $request = SOAP::Data->name( RefundTransactionRequest => \SOAP::Data->value(@ref_trans) ) ->type("ns:RefundTransactionRequestType"); my $som = $self->doCall( RefundTransactionReq => $request ) or return; my $path = '/Envelope/Body/RefundTransactionResponse'; my %response = (); unless ( $self->getBasic( $som, $path, \%response ) ) { $self->getErrors( $som, $path, \%response ); return %response; } $self->getFields( $som, $path, \%response, { RefundTransactionID => 'RefundTransactionID', FeeRefundAmount => 'FeeRefundAmount', NetRefundAmount => 'NetRefundAmount', GrossRefundAmount => 'GrossRefundAmount', } ); return %response; } 1; =pod =encoding UTF-8 =head1 NAME Business::PayPal::API::RefundTransaction - PayPal RefundTransaction API =head1 VERSION version 0.76 =head1 SYNOPSIS use Business::PayPal::API::RefundTransaction; ## see Business::PayPal::API documentation for parameters my $pp = Business::PayPal::API::RefundTransaction->new( ... ); my %response = $pp->RefundTransaction( TransactionID => $transid, RefundType => 'Full', Memo => "Please come again!" ); =head1 DESCRIPTION B implements PayPal's B API using SOAP::Lite to make direct API calls to PayPal's SOAP API server. It also implements support for testing via PayPal's I. Please see L for details on using the PayPal sandbox. =head2 RefundTransaction Implements PayPal's B API call. Supported parameters include: TransactionID RefundType (defaults to 'Full' if not supplied) Amount Memo currencyID (defaults to 'USD' if not supplied) as described in the PayPal "Web Services API Reference" document. The default B setting is 'USD' if not otherwise specified. The default B setting is 'Full' if not otherwise specified. If B is set to 'Full', B is ignored (even if set). If B is set to 'Partial', B is required. Returns a hash containing the results of the transaction. The B element is likely the only useful return value at the time of this revision (the Nov. 2005 errata to the Web Services API indicates that the documented fields 'TransactionID', 'GrossAmount', etc. are I returned with this API call). Example: my %resp = $pp->RefundTransaction( TransactionID => $trans_id, RefundType => 'Partial', Amount => '15.00', ); unless( $resp{Ack} !~ /Success/ ) { for my $error ( @{$response{Errors}} ) { warn "Error: " . $error->{LongMessage} . "\n"; } } =head2 ERROR HANDLING See the B section of B for information on handling errors. =head2 EXPORT None by default. =head1 SEE ALSO L =head1 AUTHORS =over 4 =item * Scott Wiersdorf =item * Danny Hembree =item * Bradley M. Kuhn =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2006-2017 by Scott Wiersdorf, Danny Hembree, Bradley M. Kuhn. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut __END__ # ABSTRACT: PayPal RefundTransaction API Business-PayPal-API-0.76/lib/Business/PayPal/API/TransactionSearch.pm000644 000765 000024 00000012202 13077411465 025236 0ustar00olafstaff000000 000000 package Business::PayPal::API::TransactionSearch; $Business::PayPal::API::TransactionSearch::VERSION = '0.76'; use 5.008001; use strict; use warnings; use SOAP::Lite 0.67; use Business::PayPal::API (); our @ISA = qw(Business::PayPal::API); our @EXPORT_OK = qw( TransactionSearch ); sub TransactionSearch { my $self = shift; my %args = @_; my %types = ( StartDate => 'xs:dateTime', EndDate => 'xs:dateTime', Payer => 'ebl:EmailAddressType', Receiver => 'ebl:EmailAddressType', ReceiptID => 'xs:string', ProfileID => 'xs:string', TransactionID => 'xs:string', InvoiceID => 'xs:string', PayerName => 'xs:string', AuctionItemNumer => 'xs:string', TransactionClass => '', Amount => 'ebl:BasicAmountType', CurrencyCode => 'xs:token', Status => '', ); my @trans = ( $self->version_req, SOAP::Data->name( StartDate => $args{StartDate} ) ->type( delete $types{StartDate} ) ); for my $type ( keys %types ) { next unless $args{$type}; push @trans, SOAP::Data->name( $type => $args{$type} )->type( $types{$type} ); } my $request = SOAP::Data->name( TransactionSearchRequest => \SOAP::Data->value(@trans) ) ->type("ns:TransactionSearchRequestType"); my $som = $self->doCall( TransactionSearchReq => $request ) or return; my $path = '/Envelope/Body/TransactionSearchResponse'; my %response = (); unless ( $self->getBasic( $som, $path, \%response ) ) { $self->getErrors( $som, $path, \%response ); return %response; } return $self->getFieldsList( $som, $path . '/PaymentTransactions', { Timestamp => 'Timestamp', Timezone => 'Timezone', Type => 'Type', Payer => 'Payer', PayerDisplayName => 'PayerDisplayName', TransactionID => 'TransactionID', Status => 'Status', GrossAmount => 'GrossAmount', FeeAmount => 'FeeAmount', NetAmount => 'NetAmount', } ); } 1; =pod =encoding UTF-8 =head1 NAME Business::PayPal::API::TransactionSearch - PayPal TransactionSearch API =head1 VERSION version 0.76 =head1 SYNOPSIS use Business::PayPal::API::TransactionSearch; # see Business::PayPal::API documentation for parameters my $pp = Business::PayPal::API::TransactionSearch->new( ... ); my $transactions = $pp->TransactionSearch( StartDate => '1998-01-01T00:00:00Z', TransactionID => $transid, ); my $received = $pp->TransactionSearch( StartDate => '2015-11-13T00:00:00Z', EndDate => '2015-11-13T00:00:00Z', Status => 'Success', TransactionClass => 'Received', ); =head1 DESCRIPTION L implements PayPal's B API using SOAP::Lite to make direct API calls to PayPal's SOAP API server. It also implements support for testing via PayPal's I. Please see L for details on using the PayPal sandbox. =head2 TransactionSearch Implements PayPal's B API call. Supported parameters include: StartDate (required) EndDate Payer Receiver TransactionID PayerName AuctionItemNumber InvoiceID TransactionClass Amount CurrencyCode Status as described in the PayPal "Web Services API Reference" document. The syntax for StartDate is: YYYY-MM-DDTHH:MM:SSZ 'T' and 'Z' are literal characters 'T' and 'Z' respectively, e.g.: 2005-12-22T08:51:28Z Returns a list reference containing up to 100 matching records (as per the PayPal Web Services API). Each record is a hash reference with the following fields: Timestamp Timezone Type Payer PayerDisplayName TransactionID Status GrossAmount FeeAmount NetAmount Example: my $records = $pp->TransactionSearch( StartDate => '2006-03-21T22:29:55Z', InvoiceID => '599294993', ); for my $rec ( @$records ) { print "Record:\n"; print "TransactionID: " . $rec->{TransactionID} . "\n"; print "Payer Email: " . $rec->{Payer} . "\n"; print "Amount: " . $rec->{GrossAmount} . "\n\n"; } =head2 ERROR HANDLING See the B section of L for information on handling errors. =head2 EXPORT None by default. =head1 SEE ALSO L =head1 AUTHORS =over 4 =item * Scott Wiersdorf =item * Danny Hembree =item * Bradley M. Kuhn =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2006-2017 by Scott Wiersdorf, Danny Hembree, Bradley M. Kuhn. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut __END__ # ABSTRACT: PayPal TransactionSearch API Business-PayPal-API-0.76/lib/Business/PayPal/API/VoidRequest.pm000644 000765 000024 00000007153 13077411465 024106 0ustar00olafstaff000000 000000 package Business::PayPal::API::VoidRequest; $Business::PayPal::API::VoidRequest::VERSION = '0.76'; use 5.008001; use strict; use warnings; use SOAP::Lite 0.67; use Business::PayPal::API (); our @ISA = qw(Business::PayPal::API); our @EXPORT_OK = qw(DoVoidRequest); sub DoVoidRequest { my $self = shift; my %args = @_; my %types = ( AuthorizationID => 'xs:string', Note => 'xs:string', ); my @ref_trans = ( $self->version_req, SOAP::Data->name( AuthorizationID => $args{AuthorizationID} ) ->type( $types{AuthorizationID} ), ); if ( $args{Note} ) { push @ref_trans, SOAP::Data->name( Note => $args{Note} )->type( $types{Note} ) if $args{Note}; } my $request = SOAP::Data->name( DoVoidRequest => \SOAP::Data->value(@ref_trans) ) ->type("ns:VoidRequestType"); my $som = $self->doCall( DoVoidReq => $request ) or return; my $path = '/Envelope/Body/DoVoidResponse'; my %response = (); unless ( $self->getBasic( $som, $path, \%response ) ) { $self->getErrors( $som, $path, \%response ); return %response; } $self->getFields( $som, $path, \%response, { AuthorizationID => 'AuthorizationID' } ); return %response; } 1; =pod =encoding UTF-8 =head1 NAME Business::PayPal::API::VoidRequest - PayPal VoidRequest API =head1 VERSION version 0.76 =head1 SYNOPSIS use Business::PayPal::API::VoidRequest; # see Business::PayPal::API documentation for parameters my $pp = Business::PayPal::API::VoidRequest->new( ... ); my %response = $pp->DoVoidRequest( AuthorizationID => $transid Note => "Please come again!" ); =head1 DESCRIPTION B implements PayPal's B API using SOAP::Lite to make direct API calls to PayPal's SOAP API server. It also implements support for testing via PayPal's I. Please see L for details on using the PayPal sandbox. =head2 DoVoidRequest Implements PayPal's B API call. Supported parameters include: AuthorizationID Note The B is the original ID. Not a subsequent ID from a B. The note is a 255 character message for whatever purpose you deem fit. Returns a hash containing the results of the transaction. The B element is likely the only useful return value at the time of this revision (the Nov. 2005 errata to the Web Services API indicates that the documented fields 'AuthorizationID', 'GrossAmount', etc. are I returned with this API call). Example: my %resp = $pp->DoVoidRequest( AuthorizationID => $trans_id, Note => 'Sorry about that.' ); unless( $resp{Ack} !~ /Success/ ) { for my $error ( @{$response{Errors}} ) { warn "Error: " . $error->{LongMessage} . "\n"; } } =head2 ERROR HANDLING See the B section of B for information on handling errors. =head2 EXPORT None by default. =head1 SEE ALSO L =head1 AUTHORS =over 4 =item * Scott Wiersdorf =item * Danny Hembree =item * Bradley M. Kuhn =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2006-2017 by Scott Wiersdorf, Danny Hembree, Bradley M. Kuhn. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut __END__ # ABSTRACT: PayPal VoidRequest API Business-PayPal-API-0.76/eg/get-transaction-details.pl000755 000765 000024 00000000312 13077411465 022604 0ustar00olafstaff000000 000000 #!/usr/bin/env perl; use strict; use warnings; use feature qw( say ); use lib 'eg/lib'; use Example::TransactionFetcher; my $fetcher = Example::TransactionFetcher->new_with_options; $fetcher->find; Business-PayPal-API-0.76/eg/lib/000755 000765 000024 00000000000 13077411465 016271 5ustar00olafstaff000000 000000 Business-PayPal-API-0.76/eg/myapp.pl000755 000765 000024 00000000710 13077411465 017207 0ustar00olafstaff000000 000000 #!/usr/bin/env perl use Mojolicious::Lite; # You can spin this up when testing t/advanced in order to avoid 404s get '/' => sub { my $c = shift; $c->render( template => 'index' ); }; app->start; __DATA__ @@ index.html.ep % layout 'default'; % title 'Welcome'; Welcome to the Mojolicious real-time web framework! @@ layouts/default.html.ep <%= title %> <%= content %> Business-PayPal-API-0.76/eg/paypal-checkout-example.pl000755 000765 000024 00000053015 13077411465 022611 0ustar00olafstaff000000 000000 #!/usr/bin/perl # # paypal-checkout -- Interface zu PayPals ExpressCheckout SOAP-API # ############################################ # # Copyright (C) 2006 by Andy Spiegl, KasCada # # This perl script is free software; you can redistribute it and/or modify # it under the same terms as Perl itself, either Perl version 5.8.6 or, # at your option, any later version of Perl 5 you may have available. # ############################################ # # History: # # v0.1 2005-12-09: erste funktionierende Version # ############################################ my $VERSION = "0.1"; ############################################ use strict; use warnings; use Getopt::Long; use Pod::Usage; use Business::PayPal::API::ExpressCheckout; use Data::Dumper; # security for shell calls: $ENV{'PATH'} = '/bin:/usr/bin'; delete @ENV{ 'IFS', 'CDPATH', 'ENV', 'BASH_ENV' }; ############################################ # globale VARIABLEN ############################################ my $debug = 0; my $errors_occurred = 0; # some self detection my $self = $0; $self =~ s|.*/||; my $hostname = `/bin/hostname -f`; chomp $hostname; $hostname = "none" unless $hostname; my $TMPDIR = $ENV{'TEMP'} || $ENV{'TMPDIR'} || "/tmp"; ############################################ # konfigurierbare VARIABLEN ############################################ # unser PayPal-Username, PayPal-Passwort und PayPal-Signature # werden über das Environment oder als Parameter übergeben. my $pp_username = $ENV{'PP_USERNAME'} if $ENV{'PP_USERNAME'}; my $pp_password = $ENV{'PP_PASSWORD'} if $ENV{'PP_PASSWORD'}; my $pp_signature = $ENV{'PP_SIGNATURE'} if $ENV{'PP_SIGNATURE'}; ############################################ # command line options ############################################ # option defaults my $showhelp = 0; my $showmanpage = 0; my $showversion = 0; my $step = 0; my ( $OrderTotal, $InvoiceID, $BuyerEmail, $OrderDescription ); my $ReturnURL = 'http://blafaselfoo.sonst.was/paypal/return'; my $CancelURL = 'http://blafaselfoo.sonst.was/paypal/cancel'; my $PageStyle = ''; my $cpp_header_image = ''; my $cpp_header_border_color = ''; my $cpp_header_back_color = ''; my $cpp_payflow_color = ''; my $Token; my $PayerID; GetOptions( "help|usage" => \$showhelp, # show usage "manpage" => \$showmanpage, # show manpage "version" => \$showversion, # show programm version "debug+" => \$debug, # (incremental option) "username=s" => \$pp_username, # 3-token PayPal-Zugangsdaten "password=s" => \$pp_password, # 3-token PayPal-Zugangsdaten "signature=s" => \$pp_signature, # 3-token PayPal-Zugangsdaten "step=i" => \$step, # wievielter Schritt des Zahlungsvorgangs "OrderTotal=s" => \$OrderTotal, # Betrag in Euro "OrderDescription=s" => \$OrderDescription, # 127 Zeichen Beschreibung "InvoiceID=s" => \$InvoiceID, # eindeutige Rechnungs-ID "BuyerEmail=s" => \$BuyerEmail, # E-Mail des Kunden "ReturnURL=s" => \$ReturnURL, # redirect-URL nach Kauf "CancelURL=s" => \$CancelURL, # redirect-URL bei Abbruch "PageStyle=s" => \$PageStyle, "cpp_header_image=s" => \$cpp_header_image, "cpp_header_border_color=s" => \$cpp_header_border_color, "cpp_header_back_color=s" => \$cpp_header_back_color, "cpp_payflow_color=s" => \$cpp_payflow_color, "Token=s" => \$Token, # PayPal-Token "PayerID=s" => \$PayerID, # PayPal-PayerID ) or pod2usage( -exitstatus => 1, -verbose => 0 ); # turn off buffering (sinnvoll für Debugging) $| = 1 if $debug; # are there more arguments? if ( $#ARGV >= 0 ) { pod2usage( -message => "ERROR: unknown arguments \"@ARGV\".\n", -exitstatus => 2, -verbose => 0 ); } pod2usage( -exitstatus => 0, -verbose => 1 ) if $showhelp; pod2usage( -exitstatus => 0, -verbose => 2 ) if $showmanpage; if ($showversion) { print "$self - Version: $VERSION\n"; exit; } if ($debug) { print "DEBUG-Modus($debug): schalte $self in Debugmodus.\n"; } ############################################ # Hauptprogramm ############################################ print "Starte $self (v$VERSION)\n" if $debug; # ohne Zugangsdaten können wir gleich aufhören if ( not( $pp_username and $pp_password and $pp_signature ) ) { &error_exit( "Environment-Variablen PP_USER, PP_PASS und PP_SIGNATURE müssen gesetzt sein oder per Parameter angegeben werden.", 5 ); } &print_debug( "PayPal-Username: $pp_username", 1 ); &print_debug( "PayPal-Passwort: $pp_password", 1 ); &print_debug( "PayPal-Signatur: $pp_signature", 1 ); # Authentifizierungsdaten an API-Modul übergeben # see Business::PayPal::API documentation for parameters my $pp = new Business::PayPal::API::ExpressCheckout( Username => $pp_username, Password => $pp_password, Signature => $pp_signature, sandbox => 0 ); if ( $debug >= 2 ) { $Business::PayPal::API::Debug = 1; } # Zahlungsvorgang Schritt 1 if ( $step == 1 ) { # Parameter prüfen ################## if ( not $OrderTotal ) { &error_exit( "OrderTotal fehlt.", 11 ); } &print_debug( "OrderTotal: $OrderTotal:", 1 ); if ( not $OrderDescription ) { &error_exit( "OrderDescription fehlt.", 12 ); } if ( length($OrderDescription) > 127 ) { &print_debug( "Achtung, kürze zu lange OrderDescription auf 127 Zeichen.", 1 ); $OrderDescription = substr( $OrderDescription, 1, 127 ); } &print_debug( "OrderDescription: $OrderDescription", 1 ); if ( not $InvoiceID ) { &error_exit( "InvoiceID fehlt.", 13 ); } &print_debug( "InvoiceID: $InvoiceID:", 1 ); if ( not $BuyerEmail ) { &error_exit( "BuyerEmail fehlt.", 14 ); } &print_debug( "BuyerEmail: $BuyerEmail:", 1 ); if ( not $ReturnURL ) { &error_exit( "ReturnURL nicht angegeben.", 15 ); } &print_debug( "ReturnURL: $ReturnURL:", 1 ); if ( not $CancelURL ) { &error_exit( "CancelURL nicht angegeben.", 16 ); } &print_debug( "CancelURL: $CancelURL:", 1 ); # und jetzt abschicken ###################### my %response = $pp->SetExpressCheckout( OrderTotal => $OrderTotal, MaxAmount => $OrderTotal, # es fällt keine Steuer und kein Shipping an currencyID => 'EUR', InvoiceID => $InvoiceID, NoShipping => 1, LocaleCode => 'de_DE', BuyerEmail => $BuyerEmail, OrderDescription => $OrderDescription, ReturnURL => $ReturnURL, CancelURL => $CancelURL, PageStyle => $PageStyle, 'cpp-header-image' => $cpp_header_image, 'cpp-header-border-color' => $cpp_header_border_color, 'cpp-header-back-color' => $cpp_header_back_color, 'cpp-payflow-color' => $cpp_payflow_color, ); if ( $debug >= 2 ) { print "----SetExpressCheckout---------------\n"; print Data::Dumper->Dump( [ \%response ], [qw(response)] ); print "-------------------------------------\n"; } # hat's geklappt? if ( $response{'Ack'} ne "Success" ) { &error_exit( "PayPal hat \"" . $response{'Ack'} . "\" gemeldet: (" . $response{'Errors'}[0]->{'ErrorCode'} . ") " . $response{'Errors'}[0]->{'LongMessage'} . " (CorrelationID: " . $response{'CorrelationID'} . ")", 18 ); } my $token = $response{'Token'}; print "Token: $token\n"; print "Redirect: https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=$token\n"; foreach my $field ( keys %response ) { next if $field =~ /^Token|Version|Build|Ack$/; print $field, ": ", $response{$field}, "\n"; } } # Zahlungsvorgang Schritt 2 elsif ( $step == 2 ) { # Parameter prüfen ################## if ( not $Token ) { &error_exit( "Token muss angegeben werden.", 20 ); } &print_debug( "Token: $Token:", 1 ); # Kunden Checkout Details von PayPal abholen ############################################ my %details = $pp->GetExpressCheckoutDetails($Token); if ( $debug >= 2 ) { print "------GetExpressCheckoutDetails---------\n"; print Data::Dumper->Dump( [ \%details ], [qw(details)] ); print "----------------------------------------\n"; } # hat's geklappt? if ( $details{Ack} ne "Success" ) { &error_exit( "PayPal hat \"" . $details{'Ack'} . "\" gemeldet: (" . $details{'Errors'}[0]->{'ErrorCode'} . ") " . $details{'Errors'}[0]->{'LongMessage'} . " (CorrelationID: " . $details{'CorrelationID'} . ")", 28 ); } # als erstes die PayerID ausgeben my $PayerID = "(noch unbekannt)"; $PayerID = $details{PayerID} if $details{PayerID}; print "PayerID: $PayerID\n"; foreach my $field ( keys %details ) { next if $field =~ /^PayerID|Token|Version|Build|Ack$/; print $field, ": ", $details{$field}, "\n"; } } # Zahlungsvorgang Schritt 3 elsif ( $step == 3 ) { # Parameter prüfen ################## if ( not $OrderTotal ) { &error_exit( "OrderTotal fehlt.", 6 ); } &print_debug( "OrderTotal: $OrderTotal:", 1 ); if ( not $Token ) { &error_exit( "Token muss angegeben werden.", 30 ); } &print_debug( "Token: $Token:", 1 ); if ( not $PayerID ) { &error_exit( "PayerID muss angegeben werden.", 31 ); } &print_debug( "PayerID: $PayerID:", 1 ); # PayPal zur Ausführung der Zahlung auffordern ############################################## my %payinfo = $pp->DoExpressCheckoutPayment( Token => $Token, PaymentAction => 'Sale', PayerID => $PayerID, currencyID => 'EUR', OrderTotal => $OrderTotal, ); if ( $debug >= 2 ) { print "----DoExpressCheckoutPayment---------------\n"; print Data::Dumper->Dump( [ \%payinfo ], [qw(payinfo)] ); print "-------------------------------------------\n"; } # hat's geklappt? if ( $payinfo{'Ack'} ne "Success" ) { &error_exit( "PayPal hat \"" . $payinfo{'Ack'} . "\" gemeldet: (" . $payinfo{'Errors'}[0]->{'ErrorCode'} . ") " . $payinfo{'Errors'}[0]->{'LongMessage'} . " (CorrelationID: " . $payinfo{'CorrelationID'} . ")", 38 ); } foreach my $field ( keys %payinfo ) { next if $field =~ /^PayerID|Token|Version|Build|Ack$/; print $field, ": ", $payinfo{$field}, "\n"; } } else { print "Parameter \"step\" muss zwischen 1 und 3 liegen.\n"; } &cleanup_and_exit(); ############################################ # Hilfsroutinen ############################################ sub print_error { my ($text) = @_; print STDERR "ERROR: " . $text . "\n"; $errors_occurred++; if ( $errors_occurred > 10 ) { print STDERR "ERROR: Zu viele Fehler ($errors_occurred) aufgetreten -> Abbruch\n"; &cleanup_and_exit(); } } sub print_debug { my ( $text, $debug_level ) = @_; $debug_level = 0 unless $debug_level; if ( $debug >= $debug_level ) { print "DEBUG($debug_level): " . $text . "\n"; } } sub error_exit { my ( $text, $exitcode ) = @_; &print_error($text); &cleanup_and_exit($exitcode); } # nötige Aufräumarbeiten am Ende sub cleanup { &print_debug( "cleanup done.", 1 ); } # Exitcode als optionaler Parameter sub cleanup_and_exit { my ($exitcode) = @_; $exitcode = 0 unless $exitcode; &cleanup(); if ($errors_occurred) { &print_debug( "Fertig, aber es sind $errors_occurred Fehler aufgetreten.\n", 1 ); exit 100 + $errors_occurred unless $exitcode; } &print_debug( "$self (v$VERSION) beendet.\n", 1 ); exit $exitcode; } #---------------------------------------------------------------------------- # Doku #---------------------------------------------------------------------------- __END__ =head1 NAME paypal-checkout -- Interface zu PayPals ExpressCheckout SOAP-API =head1 SYNOPSIS C [--help|--usage] [--version] [--manpage] [--debug] [--username] [--password] [--signature] [--step] [--OrderTotal] [--OrderDescription] [--InvoiceID] [--BuyerEmail] [--Token] =head1 DESCRIPTION B ist ein (mehr oder weniger) komfortables Interface zu PayPals ExpressCheckout SOAP-API, um Zahlungen von Kunden per PayPal entgegenzunehmen. Der Kunde wird dafür zu der PayPal-Webseite weitergeleitet, wo er die Zahlung bestätigen muss und dann zur ursprünglichen Website (also unserer) zurückgeleitet wird, um den Vorgang abzuschliessen. Der Ablauf ist folgender: B paypal-checkout --step 1 \ --OrderTotal '1.23' \ --InvoiceID 'Rechnung12346' \ --OrderDescription '127 bytes to describe the order' \ --ReturnURL 'http://blafaselfoo.sonst.was/paypal/return' \ --CancelURL 'http://blafaselfoo.sonst.was/paypal/cancel' --BuyerEmail 'kunde@seineemailadresse.de' \ Als Antwort kommt dann z.B.: Token: EC-15K077519T503945L Redirect: https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=EC-15K077519T503945L Timestamp: 2006-07-04T18:06:15Z CorrelationID: 5edc524d89b9d Der Kunde wird von PayPal nach seiner Zahlungsbestätigung dann auf die folgende URL zurückgeleitet: http://blafaselfoo.sonst.was/paypal/return?token=EC-15K077519T503945L&PayerID=... Oder wenn er den "Abbrechen"-Knopf drückt hierhin: http://blafaselfoo.sonst.was/paypal/cancel?token=EC-15K077519T503945L [NB: Falls schon ein '?' in der URL vorkommt, wird '&token=...' angehängt] PayPal akzeptiert auch noch diese Parameter zur Gestaltung der Webseite mit unserem Firmenlayout: PageStyle cpp_header_image cpp_header_border_color cpp_header_back_color cpp_payflow_color B Nun können wir uns die Kundendaten von Paypal abholen: paypal-checkout --step 2 \ --Token 'EC-15K077519T503945L' Als Antwort kommt dann z.B.: PayerID: XXXXXXXXXXX FirstName: Heinz-Otto LastName: Meier Payer: kunde@seineemailadresse.de InvoiceID: Rechnung12346 Timestamp: 2006-07-04T16:30:43Z CorrelationID: f585a8a8426b1 Weitere mögliche Felder sind: ContactPhone PayerStatus PayerBusiness Name Street1 Street2 CityName StateOrProvince PostalCode Country "PayerID" ist immer in der ersten Zeile (da diese ID für den 3.Schritt benötigt wird), danach folgen optional alle weiteren Felder, die PayPal über diesen Kunden bekannt gibt. B Und schließlich müssen wir noch die Zahlung endgültig durchführen. Dabei muss die PayerID (s. 2.Schritt) und der Betrag (der auch anders als im 1.Schritt sein darf) nochmals angegeben werden: paypal-checkout --step 3 \ --Token EC-15K077519T503945L \ --PayerID XXXXXXXXXXX \ --OrderTotal '1.23' \ PayPal akzeptiert auch noch diese (momentan nicht implementierten) Parameter: OrderDescription ItemTotal ShippingTotal HandlingTotal TaxTotal InvoiceID ButtonSource (An identification code for use by third-party applications to identify transactions.) NotifyURL (Your URL for receiving Instant Payment Notification (IPN) about this transaction. NOTE: If you do not specify NotifyURL in the request, the notification URL from your Merchant Profile is used, if one exists.) PDI_Name, PDI_Amount, PDI_Number, PDI_Quantity, PDI_Tax (PDI=PaymentDetailsItem) Als Antwort kommt dann z.B.: TaxAmount: 0.00 PaymentType: instant PaymentStatus: Completed PendingReason: none Timestamp: 2006-07-04T16:51:31Z GrossAmount: 0.12 CorrelationID: ec073855c7f6 TransactionID: 4BP770794S779432R TransactionType: express-checkout PaymentDate: 2006-07-04T16:51:30Z Weitere mögliche Felder sind: FeeAmount SettleAmount TaxAmount ExchangeRate =head1 OPTIONS Alle Optionen können mit einem eindeutigen Anfang abgekürzt werden. =over 3 =item B<--debug> Debugmeldungen ausgeben (kann mehrfach angegeben werden, um detailliertere Informationen zu sehen). =item B<--help>, B<--usage> Syntax anzeigen =item B<--manpage> Die komplette Manpage anzeigen =item B<--version> Programmversion anzeigen =back =head3 Optionen für Schritt 1 =over 3 =item B<--OrderTotal> Abzubuchender Betrag in Euro ohne Währungssymbol. Dezimalpunkt ist ein Punkt. Kommas werden als Tausenderpunkte interpretiert. Maximal zulässig sind 10000 US Dollar. Da in unserem Fall keine Steuer und kein Shipping mehr dazukommen wird dieser Betrag auch als C an PayPal übergeben, so dass er dem Kunden auf der PayPal-Seite als endgültiger Betrag angezeigt wird. Leider funktioniert das nicht. Der Kunde sieht auf der PayPal-Seite keinen Betrag! =item B<--OrderDescription> Beschreibender Text zur Zahlung, die dem Kunden auf der PayPal-Seite angezeigt wird. Für unsere Buchhaltung sollten hier zumindest KundenNummer und Rechnungsnummer angegeben sein. Auch der Betrag wäre hier wohl wünschenswert, da der Kunden auf der PayPal-Seite den Betrag nicht angezeigt bekommt! (Warum wohl?) =item B<--InvoiceID> Unsere (eindeutige) Rechnungs-ID. =item B<--BuyerEmail> PayPal beschreibt diesen Parameter so: Email address of the buyer as entered during checkout. PayPal uses this value to pre-fill the PayPal membership sign-up portion of the PayPal login page. Character length and limit: 127 single-byte alphanumeric characters =item B<--ReturnURL> Nach der Zahlungsbestätigung wird der Kunde zu dieser URL weitergeleitet. =item B<--CancelURL> In dem Fall, dass der Kunde die Zahlungsbestätigung abbricht, wird er zu dieser URL weitergeleitet. =item B<--PageStyle> PayPal beschreibt diesen Parameter so: Sets the Custom Payment Page Style for payment pages associated with this button/link. PageStyle corresponds to the HTML variable page_style for customizing payment pages. The value is the same as the Page Style Name you chose when adding or editing the page style from the Profile subtab of the My Account tab of your PayPal account. Character length and limitations: 30 single-byte alphabetic characters. =item B<--cpp-header-image> PayPal beschreibt diesen Parameter so: A URL for the image you want to appear at the top left of the payment page. The image has a maximum size of 750 pixels wide by 90 pixels high. PayPal recommends that you provide an image that is stored on a secure (https) server. Character length and limitations: 127 =item B<--cpp-header-border-color> PayPal beschreibt diesen Parameter so: Sets the border color around the header of the payment page. The border is a 2-pixel perimeter around the header space, which is 750 pixels wide by 90 pixels high. Character length and limitations: Six character HTML hexadecimal color code in ASCII =item B<--cpp-header-back-color> PayPal beschreibt diesen Parameter so: Sets the background color for the header of the payment page. Character length and limitation: Six character HTML hexadecimal color code in ASCII =item B<--cpp-payflow-color> PayPal beschreibt diesen Parameter so: Sets the background color for the payment page. Character length and limitation: Six character HTML hexadecimal color code in ASCII =back =head3 Optionen für Schritt 2 =over 3 =item B<--Token> Zur Identifikation des Zahlungsvorgangs muss das Token aus Schritt 1 an PayPal übergeben werden. =back =head3 Optionen für Schritt 3 =over 3 =item B<--OrderTotal> Abzubuchender Betrag in Euro ohne Währungssymbol. Dezimalpunkt ist ein Punkt. Kommas werden als Tausenderpunkte interpretiert. Maximal zulässig sind 10000 US Dollar. Der Betrag darf den Betrag aus Schritt 1 nicht übersteigen, aber PayPal akzeptiert trotzdem einen höheren Betrag und bucht ihn auch brav ab! Das lädt ja direkt zum Betrug ein! Allerdings bekommt der Kunde danach ja noch eine Bestätigung per E-Mail, in der der richtige Betrag steht. =item B<--Token> Zur Identifikation des Zahlungsvorgangs muss das Token aus Schritt 1 an PayPal übergeben werden. =item B<--PayerID> Zur Identifikation des Zahlungsvorgangs muss die PayerID aus Schritt 2 an PayPal übergeben werden. =back =head1 EXITCODES B<0> Alles bestens Alles andere bedeutet nichts Gutes. =head1 BUGS Ich habe folgendes seltsame Verhalten festgestellt: Wenn ein Kunde _nach_ der Bezahlung nochmal die PayPal-Seite mit der Zahlungsaufforderung aufruft und dort dann auf "Zurück zur Kaufabwicklung des Händlers" klickt, wird er zu dieser URL umgeleitet: http://blafaselfoo.sonst.was/paypal/cancel?submit.x=Zur%C3%BCck+zur+Kaufabwicklung+des+H%C3%A4ndlers&form_charset=UTF-8 =head1 SEE ALSO L, L, L, L, L =head1 AUTHOR Dr. Andy Spiegl Epaypalcheckout.Spiegl@kascada.comE =head1 COPYRIGHT AND LICENSE Copyright (C) 2006 by Andy Spiegl This perl script is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.6 or, at your option, any later version of Perl 5 you may have available. =cut Business-PayPal-API-0.76/eg/search-transactions.pl000755 000765 000024 00000000751 13077411465 022041 0ustar00olafstaff000000 000000 use strict; use warnings; use feature qw( say ); use Data::Printer; use lib 'eg/lib'; use Example::TransactionSearcher; my $searcher = Example::TransactionSearcher->new_with_options(); my $txns = $searcher->search; unless ( @{$txns} ) { say 'no results'; exit; } foreach my $txn ( @{$txns} ) { # remove undef values for my $field ( keys %{$txn} ) { delete $txn->{$field} unless $txn->{$field}; } p $txn; } say scalar @{$txns} . ' results found'; Business-PayPal-API-0.76/eg/lib/Example/000755 000765 000024 00000000000 13077411465 017664 5ustar00olafstaff000000 000000 Business-PayPal-API-0.76/eg/lib/Example/Role/000755 000765 000024 00000000000 13077411465 020565 5ustar00olafstaff000000 000000 Business-PayPal-API-0.76/eg/lib/Example/TransactionFetcher.pm000644 000765 000024 00000000716 13077411465 024014 0ustar00olafstaff000000 000000 package Example::TransactionFetcher; use Moo; use MooX::Options; use Business::PayPal::API::GetTransactionDetails; use Data::Printer; option transaction_id => ( is => 'ro', format => 's', required => 1, doc => 'transaction id', ); with 'Example::Role::Auth'; sub find { my $self = shift; my %response = $self->_client->GetTransactionDetails( TransactionID => $self->transaction_id ); p %response; } 1; Business-PayPal-API-0.76/eg/lib/Example/TransactionSearcher.pm000644 000765 000024 00000003037 13077411465 024167 0ustar00olafstaff000000 000000 package Example::TransactionSearcher; use Moo; use MooX::Options; use feature qw( say ); use Business::PayPal::API::TransactionSearch; use DateTime; use Data::Printer; use String::CamelCase qw( camelize ); # search options option amount => ( is => 'ro', format => 's', required => 0, doc => 'payment amount', ); option end_date => ( is => 'ro', format => 's', required => 0, doc => 'end date for search. eg 2005-12-22T08:51:28Z', ); option start_date => ( is => 'ro', format => 's', required => 0, lazy => 1, doc => 'start date for search. eg 2005-12-22T08:51:28Z', default => sub { DateTime->now->truncate( to => 'day' )->datetime . 'Z' }, ); option payer => ( is => 'ro', format => 's', required => 0, doc => 'payer email address', ); option transaction_id => ( is => 'ro', format => 's', required => 0, doc => 'transaction id', ); with 'Example::Role::Auth'; sub search { my $self = shift; my @terms = ( 'amount', 'end_date', 'payer', 'start_date', ); my %search_terms = map { camelize($_) => $self->$_ } grep { $self->$_ } @terms; $search_terms{TransactionID} = $self->transaction_id if $self->transaction_id; say 'Search terms: '; p %search_terms; my @response = $self->_client->TransactionSearch(%search_terms); unless ( ref $response[0] ) { my %error = @response; p %error; die; } return $response[0]; } 1; Business-PayPal-API-0.76/eg/lib/Example/Role/Auth.pm000644 000765 000024 00000002053 13077411465 022024 0ustar00olafstaff000000 000000 package Example::Role::Auth; use Moo::Role; use MooX::Options; use Business::PayPal::API qw( GetTransactionDetails TransactionSearch ); use Types::Standard qw( InstanceOf ); # credentials option password => ( is => 'ro', format => 's', required => 1, doc => 'password', ); # defaults to boolean if no format specified option sandbox => ( is => 'ro', default => 0, doc => 'use sandbox', ); option signature => ( is => 'ro', format => 's', required => 1, doc => 'signature', ); option username => ( is => 'ro', format => 's', required => 1, doc => 'username', ); has _client => ( is => 'ro', isa => InstanceOf ['Business::PayPal::API'], lazy => 1, builder => '_build_client', ); sub _build_client { my $self = shift; return Business::PayPal::API->new( Password => $self->password, Signature => $self->signature, Username => $self->username, sandbox => $self->sandbox, ); } 1; Business-PayPal-API-0.76/debian/compat000644 000765 000024 00000000002 13077411465 017550 0ustar00olafstaff000000 000000 5 Business-PayPal-API-0.76/debian/control000644 000765 000024 00000002142 13077411465 017754 0ustar00olafstaff000000 000000 Source: libbusiness-paypal-api-perl Section: perl Priority: optional Build-Depends: debhelper (>= 5.0.0) Build-Depends-Indep: perl (>= 5.8.8-12), libsoap-lite-perl Maintainer: Dave Lambley Standards-Version: 3.7.2 Homepage: http://search.cpan.org/dist/Business-PayPal-API/ Package: libbusiness-paypal-api-perl Architecture: all Depends: ${perl:Depends}, ${misc:Depends}, libsoap-lite-perl Description: PayPal API Business::PayPal::API supports both certificate authentication and the new 3-token "Signature" authentication. . It also support PayPal's development sandbox for testing. See the sandbox parameter to new() below for details. . Business::PayPal::API can import other API derived classes: . use Business::PayPal::API qw( RefundTransaction ); . This allows for much more concise and intuitive usage. For example, these two statements are equivalent: . use Business::PayPal::API::RefundTransaction; my $pp = new Business::PayPal::API::RefundTransaction( ... ); $pp->RefundTransaction( ... ); . This description was automagically extracted from the module by dh-make-perl. Business-PayPal-API-0.76/debian/copyright000644 000765 000024 00000001115 13077411465 020303 0ustar00olafstaff000000 000000 This is the debian package for the Business-PayPal-API module. It was created by Dave Lambley using dh-make-perl. It was downloaded from http://search.cpan.org/dist/Business-PayPal-API/ This copyright info was automatically extracted from the perl module. It may not be accurate, so you better check the module sources if don't want to get into legal troubles. The upstream author is: Scott Wiersdorf . The Debian packaging is (C) 2008, Tomas Doran and is licensed under the same terms as the software itself (see above). Business-PayPal-API-0.76/debian/rules000755 000765 000024 00000003573 13077411465 017442 0ustar00olafstaff000000 000000 #!/usr/bin/make -f # This debian/rules file is provided as a template for normal perl # packages. It was created by Marc Brockschmidt for # the Debian Perl Group (http://pkg-perl.alioth.debian.org/) but may # be used freely wherever it is useful. # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 # If set to a true value then MakeMaker's prompt function will # always return the default without waiting for user input. export PERL_MM_USE_DEFAULT=1 PACKAGE=$(shell dh_listpackages) ifndef PERL PERL = /usr/bin/perl endif TMP =$(CURDIR)/debian/$(PACKAGE) build: build-stamp build-stamp: dh_testdir # As this is a architecture independent package, we are not # supposed to install stuff to /usr/lib. MakeMaker creates # the dirs, we prevent this by setting the INSTALLVENDORARCH # and VENDORARCHEXP environment variables. # Add commands to compile the package here $(PERL) Makefile.PL INSTALLDIRS=vendor \ INSTALLVENDORARCH=/usr/share/perl5/ \ VENDORARCHEXP=/usr/share/perl5/ $(MAKE) $(MAKE) test touch $@ clean: dh_testdir dh_testroot dh_clean build-stamp install-stamp # Add commands to clean up after the build process here [ ! -f Makefile ] || $(MAKE) realclean install: install-stamp install-stamp: build-stamp dh_testdir dh_testroot dh_clean -k # Add commands to install the package into debian/$PACKAGE_NAME here $(MAKE) install DESTDIR=$(TMP) PREFIX=/usr touch $@ binary-arch: # We have nothing to do here for an architecture-independent package binary-indep: build install dh_testdir dh_testroot dh_installexamples dh_installdocs README dh_installchangelogs Changes dh_perl dh_compress dh_fixperms dh_installdeb dh_gencontrol dh_md5sums dh_builddeb source diff: @echo >&2 'source and diff are obsolete - use dpkg-source -b'; false binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary