Initial git commit of release 0.62
This commit is contained in:
		
						commit
						925e625e76
					
				
					 30 changed files with 5489 additions and 0 deletions
				
			
		
							
								
								
									
										178
									
								
								Changes
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								Changes
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,178 @@ | |||
| Revision history for Perl extension Business::PayPal::API. | ||||
| 
 | ||||
| Release 0.62 - last scottw release | ||||
| ---------------------------- | ||||
| revision 1.24 | ||||
| date: 2009/07/28 18:00:58;  author: scott;  state: Exp;  lines: +44 -4 | ||||
| - 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. | ||||
| 
 | ||||
| Release 0.61 | ||||
| ---------------------------- | ||||
| revision 1.23 | ||||
| date: 2008/05/05 15:10:40;  author: scott;  state: Exp;  lines: +37 -5 | ||||
| - timeout setting available | ||||
| - additional troubleshooting documentation (auth error handling, URL munging) | ||||
| ---------------------------- | ||||
| revision 1.4 [DirectPayments.pm] | ||||
| date: 2008/05/05 15:11:14;  author: scott;  state: Exp;  lines: +34 -2 | ||||
| - add shipto parameters | ||||
| ---------------------------- | ||||
| revision 1.12 [ExpressCheckout.pm] | ||||
| date: 2008/05/05 15:11:51;  author: scott;  state: Exp;  lines: +11 -3 | ||||
| - MaxAmount parameter take currencyID attribute (Sandbox) | ||||
| ---------------------------- | ||||
| revision 1.1 [RecurringPayments.pm] | ||||
| date: 2008/05/05 15:15:04;  author: scott;  state: Exp; | ||||
| - add base for RecurringPayments (not working yet) | ||||
| 
 | ||||
| Release 0.51 | ||||
| ---------------------------- | ||||
| revision 1.22 | ||||
| date: 2007/09/27 20:32:31;  author: scott;  state: Exp;  lines: +18 -6 | ||||
| - [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) | ||||
| 
 | ||||
| Release 0.51 | ||||
| ---------------------------- | ||||
| revision 1.10 | ||||
| date: 2007/08/29 20:56:42;  author: scott;  state: Exp;  lines: +4 -2 | ||||
| - fix PayerStatus location in DOM, add AddressStatus element (patch: Michael Hendricks) | ||||
| 
 | ||||
| Release 0.50 | ||||
| ---------------------------- | ||||
| revision 1.20 | ||||
| date: 2007/05/21 21:59:33;  author: scott;  state: Exp;  lines: +5 -5 | ||||
| - minor doc changes | ||||
| - new Mass Pay API module included | ||||
| ---------------------------- | ||||
| 
 | ||||
| Release 0.41 | ||||
| ---------------------------- | ||||
| revision 1.19 | ||||
| date: 2007/05/15 20:46:56;  author: scott;  state: Exp;  lines: +34 -12 | ||||
| - some minor documentation additions | ||||
| 
 | ||||
| Release 0.40 | ||||
| ---------------------------- | ||||
| revision 1.18 | ||||
| date: 2006/10/06 17:53:44;  author: scott;  state: Exp;  lines: +2 -2 | ||||
| - version bump | ||||
| ---------------------------- | ||||
| revision 1.17 | ||||
| date: 2006/10/06 17:49:50;  author: scott;  state: Exp;  lines: +42 -38 | ||||
| - 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 | ||||
| ---------------------------- | ||||
| revision 1.16 | ||||
| date: 2006/07/06 15:25:21;  author: scott;  state: Exp;  lines: +9 -2 | ||||
| - add acknowledgement and pointers to example code from Andy Spiegl and others | ||||
| 
 | ||||
| Release 0.33 | ||||
| ---------------------------- | ||||
| revision 1.15 | ||||
| date: 2006/07/05 18:05:39;  author: scott;  state: Exp;  lines: +2 -2 | ||||
| - 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). | ||||
| 
 | ||||
| Release 0.32 | ||||
| ---------------------------- | ||||
| revision 1.14 | ||||
| date: 2006/07/03 15:46:24;  author: scott;  state: Exp;  lines: +16 -1 | ||||
| - acknowledgements section | ||||
| ---------------------------- | ||||
| revision 1.13 | ||||
| date: 2006/07/03 15:40:16;  author: scott;  state: Exp;  lines: +11 -2 | ||||
| - fix for 3-token auth | ||||
| 
 | ||||
| Release 0.31 | ||||
| ---------------------------- | ||||
| revision 1.12 | ||||
| date: 2006/06/29 02:36:24;  author: scott;  state: Exp;  lines: +2 -2 | ||||
| - fix StateOrProvince typo [rt.cpan.org #20176] | ||||
| 
 | ||||
| Release 0.30 | ||||
| ---------------------------- | ||||
| revision 1.11 | ||||
| date: 2006/04/18 16:23:18;  author: scott;  state: Exp;  lines: +2 -2 | ||||
| - added DirectPayments API by Daniel Hembree. Thanks Daniel! | ||||
| 
 | ||||
| Release 0.23 | ||||
| ---------------------------- | ||||
| revision 1.10 | ||||
| date: 2006/04/04 19:29:08;  author: scott;  state: Exp;  lines: +12 -5 | ||||
| - typo fix | ||||
| - wrap soap call in eval for safety (if ssl neg. fails w/ paypal, it croaks) | ||||
| - version bump | ||||
| 
 | ||||
| Release 0.22 | ||||
| ---------------------------- | ||||
| revision 1.9 | ||||
| date: 2006/03/28 18:05:03;  author: scott;  state: Exp;  lines: +54 -44 | ||||
| - documentation updates | ||||
| 
 | ||||
| Release 0.21 | ||||
| ---------------------------- | ||||
| revision 1.8 | ||||
| date: 2006/03/24 17:12:59;  author: scott;  state: Exp;  lines: +14 -4 | ||||
| - fix fault printing | ||||
| - fix getFieldsList record population | ||||
| 
 | ||||
| Release 0.20 | ||||
| ---------------------------- | ||||
| revision 1.7 | ||||
| date: 2006/03/23 17:28:10;  author: scott;  state: Exp;  lines: +90 -9 | ||||
| - allow subclass methods to be imported into API.pm namespace | ||||
| ---------------------------- | ||||
| revision 1.6 | ||||
| date: 2006/03/22 23:20:09;  author: scott;  state: Exp;  lines: +2 -2 | ||||
| - version bump | ||||
| ---------------------------- | ||||
| revision 1.5 | ||||
| date: 2006/03/22 23:19:03;  author: scott;  state: Exp;  lines: +40 -13 | ||||
| - add GetTransactionDetails API | ||||
| - add TransactionSearch API | ||||
| - getFieldList() for API.pm | ||||
| ---------------------------- | ||||
| revision 1.4 | ||||
| date: 2006/03/21 22:15:11;  author: scott;  state: Exp;  lines: +2 -2 | ||||
| - bump version | ||||
| ---------------------------- | ||||
| revision 1.3 | ||||
| date: 2006/03/21 22:05:19;  author: scott;  state: Exp;  lines: +55 -31 | ||||
| - minor debugging changes | ||||
| - documentation update for developers | ||||
| - note about using IO::Socket::SSL (don't) | ||||
| ---------------------------- | ||||
| revision 1.2 | ||||
| date: 2006/03/16 23:33:49;  author: scott;  state: Exp;  lines: +184 -26 | ||||
| - initial checkin of API and subclasses | ||||
| - all tests working, documentation done | ||||
| ---------------------------- | ||||
| revision 1.1 | ||||
| date: 2006/03/15 23:33:53;  author: scott;  state: Exp; | ||||
| - moved from Business::PayPal::WPP::ExpressCheckout | ||||
| - uses API.pm for authorization/authentication and other common functions | ||||
| ============================================================================= | ||||
							
								
								
									
										30
									
								
								MANIFEST
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								MANIFEST
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | |||
| Changes | ||||
| Makefile.PL | ||||
| MANIFEST | ||||
| README | ||||
| eg/paypal-checkout-example.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/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 | ||||
| t/API.pl | ||||
| t/Business-PayPal-API.t | ||||
| t/DirectPayments.t | ||||
| t/ExpressCheckout.t | ||||
| t/ExpressOrder.t | ||||
| t/GetTransactionDetails.t | ||||
| t/MassPay.t | ||||
| t/RecurringPayments.t | ||||
| t/RefundTransaction.t | ||||
| t/TransactionSearch.t | ||||
| auth.sample.3token | ||||
| auth.sample.cert | ||||
| META.yml | ||||
							
								
								
									
										11
									
								
								META.yml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								META.yml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | |||
| # http://module-build.sourceforge.net/META-spec.html | ||||
| #XXXXXXX This is a prototype!!!  It will change in the future!!! XXXXX# | ||||
| name:         Business-PayPal-API | ||||
| version:      0.62 | ||||
| version_from: lib/Business/PayPal/API.pm | ||||
| installdirs:  site | ||||
| requires: | ||||
|     SOAP::Lite:                    0.67 | ||||
| 
 | ||||
| distribution_type: module | ||||
| generated_by: ExtUtils::MakeMaker version 6.30 | ||||
							
								
								
									
										12
									
								
								Makefile.PL
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								Makefile.PL
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| use 5.008001; | ||||
| use ExtUtils::MakeMaker; | ||||
| # See lib/ExtUtils/MakeMaker.pm for details of how to influence | ||||
| # the contents of the Makefile that is written. | ||||
| WriteMakefile( | ||||
|     NAME              => 'Business::PayPal::API', | ||||
|     VERSION_FROM      => 'lib/Business/PayPal/API.pm', | ||||
|     PREREQ_PM         => { SOAP::Lite => 0.67 }, | ||||
|     ($] >= 5.005 ? | ||||
|       (ABSTRACT_FROM  => 'lib/Business/PayPal/API.pm', | ||||
|        AUTHOR         => 'Scott Wiersdorf <scott@perlcode.org>') : ()), | ||||
| ); | ||||
							
								
								
									
										62
									
								
								README
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								README
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,62 @@ | |||
| Business-PayPal-API version 0.62 | ||||
| ================================ | ||||
| 
 | ||||
| INSTALLATION | ||||
| 
 | ||||
| To install this module type the following: | ||||
| 
 | ||||
|    perl Makefile.PL | ||||
|    make | ||||
|    WPP_TEST=auth.txt make test | ||||
|    make install | ||||
| 
 | ||||
| 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 | ||||
| 
 | ||||
| Acquiring these things is your job, not mine. Read PayPal's | ||||
| and this module's documentation to learn more. | ||||
| 
 | ||||
| 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. | ||||
| 
 | ||||
| USAGE | ||||
| 
 | ||||
|   use Business::PayPal::API qw( ExpressCheckout ); | ||||
| 
 | ||||
|   my $pp = new Business::PayPal::API( Username => 'my_api.username.tld', | ||||
|                                       Password => 'API_PASSWORD', | ||||
|                                       CertFile => '/path/to/cert.pem', | ||||
|                                       KeyFile  => '/path/to/key.pem', ); | ||||
| 
 | ||||
|   ... | ||||
|   my %details = $pp->GetExpressCheckoutDetails( $token ); | ||||
| 
 | ||||
| DEPENDENCIES | ||||
| 
 | ||||
| This module requires these other modules and libraries: | ||||
| 
 | ||||
|   SOAP::Lite 0.67 or later. | ||||
|   Crypt::SSLeay required for certificate auth | ||||
| 
 | ||||
| COPYRIGHT AND LICENCE | ||||
| 
 | ||||
| This package except those modules listed below are copyright (C) 2006 | ||||
| by Scott Wiersdorf | ||||
| 
 | ||||
| AuthorizationRequest, CaptureRequest, DirectPayments, | ||||
| ReauthorizationRequest, and VoidRequest modules are copyright (C) 2006 | ||||
| by Daniel Hembree | ||||
| 
 | ||||
| This library 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. | ||||
							
								
								
									
										3
									
								
								auth.sample.3token
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								auth.sample.3token
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | |||
| Username  = test1_api.mydomain.tld | ||||
| Password  = XXXXXXXXXXXXXXXX | ||||
| Signature = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | ||||
							
								
								
									
										4
									
								
								auth.sample.cert
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								auth.sample.cert
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | |||
| Username = test1_api.mydomain.tld | ||||
| Password = myapipassword | ||||
| CertFile = /www/var/cert_key_pem.txt | ||||
| KeyFile  = /www/var/cert_key_pem.txt | ||||
							
								
								
									
										784
									
								
								eg/paypal-checkout-example.pl
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										784
									
								
								eg/paypal-checkout-example.pl
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,784 @@ | |||
| #!/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<paypal-checkout> [--help|--usage] [--version] [--manpage] [--debug] | ||||
|  [--username] [--password] [--signature] | ||||
|  [--step] | ||||
|  [--OrderTotal] [--OrderDescription] [--InvoiceID] [--BuyerEmail] | ||||
|  [--Token] | ||||
| 
 | ||||
| 
 | ||||
| =head1 DESCRIPTION | ||||
| 
 | ||||
| B<paypal-checkout> 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<Schritt 1> | ||||
| 
 | ||||
|  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<Schritt 2> | ||||
| 
 | ||||
| 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<Schritt 3> | ||||
| 
 | ||||
| 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<MaxAmount> 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<SOAP::Lite>, L<Business::PayPal::API>, L<Business::PayPal::API::ExpressCheckout>, | ||||
| L<https://www.paypal.com/IntegrationCenter/ic_expresscheckout.html>, | ||||
| L<https://developer.paypal.com/en_US/pdf/PP_APIReference.pdf> | ||||
| 
 | ||||
| =head1 AUTHOR | ||||
| 
 | ||||
| Dr. Andy Spiegl E<lt>paypalcheckout.Spiegl@kascada.comE<gt> | ||||
| 
 | ||||
| =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 | ||||
							
								
								
									
										800
									
								
								lib/Business/PayPal/API.pm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										800
									
								
								lib/Business/PayPal/API.pm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,800 @@ | |||
| package Business::PayPal::API; | ||||
| 
 | ||||
| use 5.008001; | ||||
| use strict; | ||||
| use warnings; | ||||
| 
 | ||||
| use SOAP::Lite 0.67; # +trace => 'all'; | ||||
| use Carp qw(carp); | ||||
| 
 | ||||
| our $VERSION = '0.62'; | ||||
| our $CVS_VERSION = '$Id: API.pm,v 1.24 2009/07/28 18:00:58 scott Exp $'; | ||||
| our $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     () { '3.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}   ||= 0; | ||||
| 
 | ||||
|     $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} )->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"; | ||||
| 	} | ||||
| 
 | ||||
| #	$Soap{$self}->readable( $Debug ); | ||||
| #	$Soap{$self}->outputxml( $Debug ); | ||||
| 
 | ||||
| 	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? | ||||
|         require Data::Dumper; | ||||
|         print STDERR Data::Dumper::Dumper($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 | ||||
|         next if $trans_id{$response{TransactionID}}; | ||||
|         $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: | ||||
|     ## <snip> | ||||
|     ## 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. | ||||
|     ## </snip> | ||||
|     ## | ||||
|     ## 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} eq '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; | ||||
| __END__ | ||||
| 
 | ||||
| =head1 NAME | ||||
| 
 | ||||
| Business::PayPal::API - PayPal API | ||||
| 
 | ||||
| =head1 SYNOPSIS | ||||
| 
 | ||||
|   use Business::PayPal::API qw( ExpressCheckout GetTransactionDetails ); | ||||
| 
 | ||||
|   ## certificate authentication | ||||
|   my $pp = new Business::PayPal::API | ||||
|             ( 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 = new Business::PayPal::API | ||||
|             ( 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 = new Business::PayPal::API | ||||
|             ( Username   => 'my_api1.domain.tld', | ||||
|               Password   => 'Xdkis9k3jDFk39fj29sD9',  ## supplied by PayPal | ||||
|               Signature  => 'f7d03YCpEjIF3s9Dk23F2V1C1vbYYR3ALqc7jm0UrCcYm-3ksdiDwjfSeii',  ## ditto | ||||
|               sandbox    => 1 ); | ||||
| 
 | ||||
|   my %response = $pp->SetExpressCheckout( ... ); | ||||
| 
 | ||||
| 
 | ||||
| =head1 DESCRIPTION | ||||
| 
 | ||||
| B<Business::PayPal::API> supports both certificate authentication and | ||||
| the new 3-token "Signature" authentication. | ||||
| 
 | ||||
| It also support PayPal's development I<sandbox> for testing. See the | ||||
| B<sandbox> parameter to B<new()> below for details. | ||||
| 
 | ||||
| B<Business::PayPal::API> can import other B<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( ... ); | ||||
| 
 | ||||
| and more concisely: | ||||
| 
 | ||||
|   use Business::PayPal::API qw( RefundTransaction ); | ||||
|   my $pp = new Business::PayPal::API( ... ); | ||||
|   $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<API> object used to invoke various | ||||
| PayPal APIs with the same object: | ||||
| 
 | ||||
|   use Business::PayPal::API qw( GetTransactionDetails  | ||||
|                                 TransactionSearch  | ||||
|                                 RefundTransaction ); | ||||
|   my $pp = new Business::PayPal::API( ... ); | ||||
|   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<Business::PayPal::API::*> subclasses, see each | ||||
| subclass's individual documentation. | ||||
| 
 | ||||
| =head2 new | ||||
| 
 | ||||
| Creates a new B<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. | ||||
| 
 | ||||
| =over 4 | ||||
| 
 | ||||
| =item B<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 I<PayPal API Reference> and I<PayPal Sandbox User | ||||
| Guide> for details on creating a PayPal business account and sandbox | ||||
| account for testing. | ||||
| 
 | ||||
| =item B<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". | ||||
| 
 | ||||
| =item B<Subject> | ||||
| 
 | ||||
| Optional. This is used by PayPal to authenticate 3rd party billers | ||||
| using your account. See the documents in L<SEE ALSO>. | ||||
| 
 | ||||
| =item B<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. | ||||
| 
 | ||||
| =item B<PKCS12File> | ||||
| 
 | ||||
| Required for PKCS#12 certificate authentication, unless the | ||||
| B<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 B<HTTPS_PKCS12_FILE> environment | ||||
| variable. You may set this environment variable yourself and leave | ||||
| this field blank. | ||||
| 
 | ||||
| =item B<PKCS12Password> | ||||
| 
 | ||||
| Required for PKCS#12 certificate authentication, unless the | ||||
| B<HTTPS_PKCS12_PASSWORD> environment variable is already set. | ||||
| 
 | ||||
| This contains the PKCS#12 password for the key specified in | ||||
| B<PKCS12File>. It is used to set the B<HTTPS_PKCS12_PASSWORD> | ||||
| environment variable. You may set this environment variable yourself | ||||
| and leave this field blank. | ||||
| 
 | ||||
| =item B<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 | ||||
| B<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 | ||||
| B<CertFile> and B<KeyFile> to the same path. | ||||
| 
 | ||||
| =item B<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 | ||||
| B<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 | ||||
| B<CertFile> and B<KeyFile> to the same path. | ||||
| 
 | ||||
| =item B<sandbox> | ||||
| 
 | ||||
| Required. If set to true (default), B<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 | ||||
| B<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 L<SEE ALSO> for references. | ||||
| 
 | ||||
| PayPal's sandbox reference: | ||||
| 
 | ||||
| L<https://www.paypal.com/IntegrationCenter/ic_sandbox.html> | ||||
| 
 | ||||
| =back | ||||
| 
 | ||||
| =head1 ERROR HANDLING | ||||
| 
 | ||||
| Every API call should return an B<Ack> response, whether I<Success>, | ||||
| I<Failure>, or otherwise (depending on the API call). If it returns | ||||
| any non-success value, you can find an I<Errors> entry in your return | ||||
| hash, whose value is a listref 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<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 B<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 I<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). | ||||
| 
 | ||||
| =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. | ||||
| 
 | ||||
|    * 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<PKCS12*> parameters or B<CertFile> or B<KeyFile> | ||||
|      parameters in your constructor AND that none of the corresponding | ||||
|      B<HTTPS_*> 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 = new Business::PayPal::API... | ||||
| 
 | ||||
|    * 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 => '<![CDATA[http://domain.tld/prog?arg1=foo&arg2=bar]]>' | ||||
| 
 | ||||
| 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<Business::PayPal::API> by setting it's 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<outputxml()>, let me know. | ||||
| 
 | ||||
| =head1 DEVELOPMENT | ||||
| 
 | ||||
| If you are a developer wanting to extend B<Business::PayPal::API> for | ||||
| other PayPal API calls, you can review any of the included modules | ||||
| (e.g., F<RefundTransaction.pm> or F<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 B<@EXPORT_OK> variable. This is I<not> used by B<Exporter> | ||||
| (we don't load Exporter at all): it is a special variable used by | ||||
| B<Business::PayPal::API> to know which methods to import when | ||||
| B<Business::PayPal::API> is run like this: | ||||
| 
 | ||||
|   use Business::PayPal::API qw( SomeAPI ); | ||||
| 
 | ||||
| That is, B<Business::PayPal::API> 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 = new Business::PayPal::API( ... ); | ||||
|   $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 = new Business::PayPal::API::SomeAPI( ... ); ## 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 <paypalcheckout.Spiegl@kascada.com> has kindly donated | ||||
| some example code (in German) for the ExpressCheckout API which may be | ||||
| found in the F<eg> directory of this archive. Additional code examples | ||||
| for other APIs may be found in the F<t> 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 occuring. | ||||
| 
 | ||||
| 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<DoExpressCheckoutPayment> and similar fudging may | ||||
| be found in B<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!). | ||||
| 
 | ||||
| =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. | ||||
| 
 | ||||
| Danny's contact information may be found in the AUTHOR section of the | ||||
| above modules. | ||||
| 
 | ||||
| =item * <jshiles at base16consulting daught com> | ||||
| 
 | ||||
| for finding some API typos in the ExpressCheckout API | ||||
| 
 | ||||
| =item * Andy Spiegl <paypalcheckout.Spiegl@kascada.com> | ||||
| 
 | ||||
| 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 <oready at drjays daught com> | ||||
| 
 | ||||
| for the heads-up on the newest 3-token auth URI as well as a pile of | ||||
| documentation inconsistencies. | ||||
| 
 | ||||
| =item * Michael Hendricks <michael at ndrix daught org> | ||||
| 
 | ||||
| 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<UniqueId> parameter. | ||||
| 
 | ||||
| =item * Jonathon Wright via email | ||||
| 
 | ||||
| for patches for B<ExpressCheckout> and B<RecurringPayments> that | ||||
| implement I<BillingAgreement> and I<DoReferenceTransaction> API | ||||
| calls. | ||||
| 
 | ||||
| =back | ||||
| 
 | ||||
| =head1 SEE ALSO | ||||
| 
 | ||||
| L<SOAP::Lite>, L<https://www.paypal.com/IntegrationCenter/ic_pro_home.html>, | ||||
| L<https://www.paypal.com/IntegrationCenter/ic_expresscheckout.html>, | ||||
| L<https://www.sandbox.paypal.com/en_US/pdf/PP_Sandbox_UserGuide.pdf>, | ||||
| L<https://developer.paypal.com/en_US/pdf/PP_APIReference.pdf> | ||||
| 
 | ||||
| =head1 AUTHOR | ||||
| 
 | ||||
| Scott Wiersdorf, E<lt>scott@perlcode.orgE<gt> | ||||
| 
 | ||||
| =head1 COPYRIGHT AND LICENSE | ||||
| 
 | ||||
| Copyright (C) 2006, 2007 by Scott Wiersdorf | ||||
| 
 | ||||
| This library 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 | ||||
							
								
								
									
										144
									
								
								lib/Business/PayPal/API/AuthorizationRequest.pm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								lib/Business/PayPal/API/AuthorizationRequest.pm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,144 @@ | |||
| package Business::PayPal::API::AuthorizationRequest; | ||||
| 
 | ||||
| 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 $VERSION = '0.11'; | ||||
| our $CVS_VERSION = '$Id: AuthorizationRequest.pm,v 1.1 2006/10/06 17:49:51 scott Exp $'; | ||||
| 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; | ||||
| __END__ | ||||
| 
 | ||||
| =head1 NAME | ||||
| 
 | ||||
| Business::PayPal::API::AuthorizationRequest - PayPal AuthorizationRequest API | ||||
| 
 | ||||
| =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<Business::PayPal::API::AuthorizationRequest> implements PayPal's | ||||
| B<AuthorizationRequest> 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<sandbox>. Please see L<Business::PayPal::API> 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<AuthorizationRequest> 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<currencyID> 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<ERROR HANDLING> section of B<Business::PayPal::API> for | ||||
| information on handling errors. | ||||
| 
 | ||||
| =head2 EXPORT | ||||
| 
 | ||||
| None by default. | ||||
| 
 | ||||
| =head1 SEE ALSO | ||||
| 
 | ||||
| L<https://developer.paypal.com/en_US/pdf/PP_APIReference.pdf> | ||||
| 
 | ||||
| =head1 AUTHOR | ||||
| 
 | ||||
| Danny Hembree E<lt>danny@dynamical.orgE<gt> | ||||
| 
 | ||||
| =head1 COPYRIGHT AND LICENSE | ||||
| 
 | ||||
| Copyright (C) 2006 by Danny Hembree | ||||
| 
 | ||||
| This library is free software; you can redistribute it and/or modify | ||||
| it under the same terms as Perl itself, either Perl version 5.8.5 or, | ||||
| at your option, any later version of Perl 5 you may have available. | ||||
| 
 | ||||
| 
 | ||||
| =cut | ||||
							
								
								
									
										170
									
								
								lib/Business/PayPal/API/CaptureRequest.pm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								lib/Business/PayPal/API/CaptureRequest.pm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,170 @@ | |||
| package Business::PayPal::API::CaptureRequest; | ||||
| 
 | ||||
| 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 $VERSION = '0.11'; | ||||
| our $CVS_VERSION = '$Id: CaptureRequest.pm,v 1.2 2007/10/16 19:09:26 scott Exp $'; | ||||
| 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; | ||||
| __END__ | ||||
| 
 | ||||
| =head1 NAME | ||||
| 
 | ||||
| Business::PayPal::API::CaptureRequest - PayPal CaptureRequest API | ||||
| 
 | ||||
| =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<Business::PayPal::API::DoCaptureRequest> implements PayPal's | ||||
| B<CaptureRequest> 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<sandbox>. Please see L<Business::PayPal::API> for details | ||||
| on using the PayPal sandbox. | ||||
| 
 | ||||
| =head2 CaptureRequest | ||||
| 
 | ||||
| Implements PayPal's B<CaptureRequest> 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<currencyID> setting is 'USD' if not otherwise specified. The | ||||
| default B<CompleteType> 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<ERROR HANDLING> section of B<Business::PayPal::API> for | ||||
| information on handling errors. | ||||
| 
 | ||||
| =head2 EXPORT | ||||
| 
 | ||||
| None by default. | ||||
| 
 | ||||
| =head1 SEE ALSO | ||||
| 
 | ||||
| L<https://developer.paypal.com/en_US/pdf/PP_APIReference.pdf> | ||||
| 
 | ||||
| =head1 AUTHOR | ||||
| 
 | ||||
| Danny Hembree E<lt>danny-hembree@dynamical.orgE<gt> | ||||
| 
 | ||||
| =head1 COPYRIGHT AND LICENSE | ||||
| 
 | ||||
| Copyright (C) 2006 by Danny Hembree | ||||
| 
 | ||||
| This library is free software; you can redistribute it and/or modify | ||||
| it under the same terms as Perl itself, either Perl version 5.8.5 or, | ||||
| at your option, any later version of Perl 5 you may have available. | ||||
| 
 | ||||
| 
 | ||||
| =cut | ||||
							
								
								
									
										293
									
								
								lib/Business/PayPal/API/DirectPayments.pm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										293
									
								
								lib/Business/PayPal/API/DirectPayments.pm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,293 @@ | |||
| package Business::PayPal::API::DirectPayments; | ||||
| 
 | ||||
| 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 $VERSION = '0.03'; | ||||
| our $CVS_VERSION = '$Id: DirectPayments.pm,v 1.5 2009/07/28 18:00:59 scott Exp $'; | ||||
| 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; | ||||
| 
 | ||||
| __END__ | ||||
| 
 | ||||
| =head1 NAME | ||||
| 
 | ||||
| Business::PayPal::API::DirectPayments - PayPal DirectPayments API | ||||
| 
 | ||||
| =head1 SYNOPSIS | ||||
| 
 | ||||
|     use Business::PayPal::API qw(DirectPayments); | ||||
|      | ||||
|     ## see Business::PayPal::API documentation for parameters | ||||
|      | ||||
|     my $pp = new Business::PayPal::API( | ||||
|                         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<Business::PayPal::API::DirectPayments> implements PayPal's | ||||
| B<DirectPayments> 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<sandbox>. Please see L<Business::PayPal::API> for details | ||||
| on using the PayPal sandbox. | ||||
| 
 | ||||
| =head2 DoDirectPaymentRequest | ||||
| 
 | ||||
| Implements PayPal's B<DoDirectPaymentRequest> 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<Ack> | ||||
| element and TransactionID are the most useful return values. | ||||
| 
 | ||||
| Example: | ||||
| 
 | ||||
|   my %resp = $pp->DoDirectPaymentRequest( | ||||
|                     PaymentAction => 'Sale', | ||||
|                     OrderTotal    => '10.99', | ||||
|                     ... | ||||
|              ); | ||||
| 
 | ||||
|   unless( $resp{Ack} ne 'Success' ) { | ||||
|       for my $error ( @{$response{Errors}} ) { | ||||
|           warn "Error: " . $error->{LongMessage} . "\n"; | ||||
|       } | ||||
|   } | ||||
| 
 | ||||
| =head2 ERROR HANDLING | ||||
| 
 | ||||
| See the B<ERROR HANDLING> section of B<Business::PayPal::API> for | ||||
| information on handling errors. | ||||
| 
 | ||||
| =head2 EXPORT | ||||
| 
 | ||||
| None by default. | ||||
| 
 | ||||
| =head1 SEE ALSO | ||||
| 
 | ||||
| L<https://developer.paypal.com/en_US/pdf/PP_APIReference.pdf> | ||||
| 
 | ||||
| =head1 AUTHOR | ||||
| 
 | ||||
| Daniel Hembree E<lt>danny@dynamical.orgE<gt> | ||||
| 
 | ||||
| =head1 COPYRIGHT AND LICENSE | ||||
| 
 | ||||
| Copyright (C) 2006 by Daniel P. Hembree | ||||
| 
 | ||||
| This library is free software; you can redistribute it and/or modify | ||||
| it under the same terms as Perl itself, either Perl version 5.8.5 or, | ||||
| at your option, any later version of Perl 5 you may have available. | ||||
| 
 | ||||
| 
 | ||||
| =cut | ||||
							
								
								
									
										553
									
								
								lib/Business/PayPal/API/ExpressCheckout.pm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										553
									
								
								lib/Business/PayPal/API/ExpressCheckout.pm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,553 @@ | |||
| package Business::PayPal::API::ExpressCheckout; | ||||
| 
 | ||||
| use 5.008001; | ||||
| use strict; | ||||
| use warnings; | ||||
| 
 | ||||
| use SOAP::Lite 0.67; | ||||
| use Business::PayPal::API (); | ||||
| 
 | ||||
| our @ISA = qw(Business::PayPal::API); | ||||
| our $VERSION = '0.14'; | ||||
| our $CVS_VERSION = '$Id: ExpressCheckout.pm,v 1.13 2009/07/28 18:00:59 scott Exp $'; | ||||
| 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} ); | ||||
|         } | ||||
|         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', | ||||
|                        FirstName       => 'PayerInfo/PayerName/FirstName', | ||||
|                        LastName        => 'PayerInfo/PayerName/LastName', | ||||
|                        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', | ||||
|                      } ); | ||||
| 
 | ||||
|     return %details; | ||||
| } | ||||
| 
 | ||||
| sub DoExpressCheckoutPayment { | ||||
|     my $self = shift; | ||||
|     my %args = @_; | ||||
| 
 | ||||
|     my %types = ( Token                     => 'xs:string', | ||||
| 		  PaymentAction             => '',                 ## NOTA BENE! | ||||
| 		  PayerID                   => 'ebl:UserIDType', | ||||
| 		  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', | ||||
| 		     ); | ||||
| 
 | ||||
|     ##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} ), | ||||
| 				   ), ); | ||||
| 
 | ||||
|     ## | ||||
|     ## 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', | ||||
|                       } ); | ||||
| 
 | ||||
|     return %response; | ||||
| } | ||||
| 
 | ||||
| 1; | ||||
| __END__ | ||||
| 
 | ||||
| =head1 NAME | ||||
| 
 | ||||
| Business::PayPal::API::ExpressCheckout - PayPal Express Checkout API | ||||
| 
 | ||||
| =head1 SYNOPSIS | ||||
| 
 | ||||
|   use Business::PayPal::API::ExpressCheckout; | ||||
| 
 | ||||
|   ## see Business::PayPal::API documentation for parameters | ||||
|   my $pp = new Business::PayPal::API::ExpressCheckout ( ... ); | ||||
| 
 | ||||
|   my %resp = $pp->SetExpressCheckout | ||||
|                ( OrderTotal => '55.43',   ## defaults to USD | ||||
|                  ReturnURL  => 'http://site.tld/return.html', | ||||
|                  CancelURL  => 'http://site.tld/canceltation.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<Business::PayPal::API::ExpressCheckout> implements PayPal's | ||||
| B<Express Checkout 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<sandbox>. Please see L<Business::PayPal::API> for details | ||||
| on using the PayPal sandbox. | ||||
| 
 | ||||
| =head2 SetExpressCheckout | ||||
| 
 | ||||
| Implements PayPal's "Website Payment Pro" B<SetExpressCheckout> 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       =>      '<![CDATA[http://example.com/p?cmd=checkout]]>', | ||||
|         CancelURL       =>      'http://example.com', | ||||
|         PaymentAction   =>      'Authorization', | ||||
|         AddressOverride =>      1, | ||||
|         Address         =>      $address, | ||||
|   ); | ||||
| 
 | ||||
| =head2 GetExpressCheckoutDetails | ||||
| 
 | ||||
| Implements PayPal's WPP B<SetExpressCheckout> 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<SetExpressCheckout>. | ||||
| 
 | ||||
| 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<SetExpressCheckout> 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<ERROR HANDLING> section of B<Business::PayPal::API> for | ||||
| information on handling errors. | ||||
| 
 | ||||
| =head1 EXAMPLES | ||||
| 
 | ||||
| Andy Spiegl <paypalcheckout.Spiegl@kascada.com> has kindly donated | ||||
| some example code (in German) which may be found in the F<eg> | ||||
| directory of this archive. Additional code examples may be found in | ||||
| the F<t> test directory. | ||||
| 
 | ||||
| =head2 EXPORT | ||||
| 
 | ||||
| None by default. | ||||
| 
 | ||||
| =head1 SEE ALSO | ||||
| 
 | ||||
| L<SOAP::Lite>, L<Business::PayPal::API>, | ||||
| L<https://www.paypal.com/IntegrationCenter/ic_expresscheckout.html>, | ||||
| L<https://developer.paypal.com/en_US/pdf/PP_APIReference.pdf> | ||||
| 
 | ||||
| =head1 AUTHOR | ||||
| 
 | ||||
| Scott Wiersdorf, E<lt>scott@perlcode.orgE<gt> | ||||
| 
 | ||||
| =head1 COPYRIGHT AND LICENSE | ||||
| 
 | ||||
| Copyright (C) 2006 by Scott Wiersdorf | ||||
| 
 | ||||
| This library 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 | ||||
							
								
								
									
										295
									
								
								lib/Business/PayPal/API/GetTransactionDetails.pm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										295
									
								
								lib/Business/PayPal/API/GetTransactionDetails.pm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,295 @@ | |||
| package Business::PayPal::API::GetTransactionDetails; | ||||
| 
 | ||||
| use 5.008001; | ||||
| use strict; | ||||
| use warnings; | ||||
| 
 | ||||
| use SOAP::Lite 0.67; | ||||
| use Business::PayPal::API (); | ||||
| 
 | ||||
| our @ISA = qw(Business::PayPal::API); | ||||
| our $VERSION = '0.12'; | ||||
| our $CVS_VERSION = '$Id: GetTransactionDetails.pm,v 1.5 2009/07/28 18:00:59 scott Exp $'; | ||||
| 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', | ||||
| 
 | ||||
|                        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', | ||||
|                                                Options  => 'Options', | ||||
|                                              } ); | ||||
| 
 | ||||
|     if( scalar(@$paymentitems) > 1 ) { | ||||
|         $response{PaymentItems} = $paymentitems; | ||||
|     } | ||||
| 
 | ||||
|     return %response; | ||||
| } | ||||
| 
 | ||||
| 1; | ||||
| __END__ | ||||
| 
 | ||||
| =head1 NAME | ||||
| 
 | ||||
| Business::PayPal::API::GetTransactionDetails - PayPal GetTransactionDetails API | ||||
| 
 | ||||
| =head1 SYNOPSIS | ||||
| 
 | ||||
|   use Business::PayPal::API::GetTransactionDetails; | ||||
|   my $pp = new Business::PayPal::API::GetTransactionDetails ( ... ); | ||||
| 
 | ||||
| or | ||||
| 
 | ||||
|   ## see Business::PayPal::API documentation for parameters | ||||
|   use Business::PayPal::API qw(GetTransactionDetails); | ||||
|   my $pp = new Business::PayPal::API( ... ); | ||||
| 
 | ||||
|   my %response = $pp->GetTransactionDetails( TransactionID => $transid, ); | ||||
| 
 | ||||
| =head1 DESCRIPTION | ||||
| 
 | ||||
| B<Business::PayPal::API::GetTransactionDetails> implements PayPal's | ||||
| B<GetTransactionDetails> 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<sandbox>. Please see L<Business::PayPal::API> for details | ||||
| on using the PayPal sandbox. | ||||
| 
 | ||||
| =head2 GetTransactionDetails | ||||
| 
 | ||||
| Implements PayPal's B<GetTransactionDetails> 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   => '...', | ||||
|                     }, | ||||
|                     { 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"; | ||||
|   } | ||||
| 
 | ||||
| =head2 ERROR HANDLING | ||||
| 
 | ||||
| See the B<ERROR HANDLING> section of B<Business::PayPal::API> for | ||||
| information on handling errors. | ||||
| 
 | ||||
| =head2 EXPORT | ||||
| 
 | ||||
| None by default. | ||||
| 
 | ||||
| =head1 SEE ALSO | ||||
| 
 | ||||
| L<https://developer.paypal.com/en_US/pdf/PP_APIReference.pdf> | ||||
| 
 | ||||
| =head1 AUTHOR | ||||
| 
 | ||||
| Scot Wiersdorf E<lt>scott@perlcode.orgE<gt> | ||||
| 
 | ||||
| =head1 COPYRIGHT AND LICENSE | ||||
| 
 | ||||
| Copyright (C) 2006 by Scott Wiersdorf | ||||
| 
 | ||||
| This library is free software; you can redistribute it and/or modify | ||||
| it under the same terms as Perl itself, either Perl version 5.8.5 or, | ||||
| at your option, any later version of Perl 5 you may have available. | ||||
| 
 | ||||
| 
 | ||||
| =cut | ||||
							
								
								
									
										188
									
								
								lib/Business/PayPal/API/MassPay.pm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								lib/Business/PayPal/API/MassPay.pm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,188 @@ | |||
| package Business::PayPal::API::MassPay; | ||||
| 
 | ||||
| use 5.008001; | ||||
| use strict; | ||||
| use warnings; | ||||
| 
 | ||||
| use SOAP::Lite 0.67; | ||||
| use Business::PayPal::API (); | ||||
| 
 | ||||
| our @ISA = qw(Business::PayPal::API); | ||||
| our $VERSION = '0.03'; | ||||
| our $CVS_VERSION = '$Id: MassPay.pm,v 1.3 2009/07/28 18:00:59 scott Exp $'; | ||||
| 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; | ||||
| __END__ | ||||
| 
 | ||||
| 
 | ||||
| =head1 NAME | ||||
| 
 | ||||
| Business::PayPal::API::MassPay - PayPal MassPay API | ||||
| 
 | ||||
| =head1 SYNOPSIS | ||||
| 
 | ||||
|   use Business::PayPal::API::MassPay; | ||||
| 
 | ||||
|   ## see Business::PayPal::API documentation for parameters | ||||
|   my $pp = new Business::PayPal::API::MassPay ( ... ); | ||||
| 
 | ||||
|   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<Business::PayPal::API::MassPay> implements PayPal's B<Mass Pay> 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<sandbox>. Please see L<Business::PayPal::API> for details on using | ||||
| the PayPal sandbox. | ||||
| 
 | ||||
| =head2 MassPay | ||||
| 
 | ||||
| Implements PayPal's B<Mass Pay> API call. Supported parameters | ||||
| include: | ||||
| 
 | ||||
|   EmailSubject | ||||
|   MassPayItems | ||||
| 
 | ||||
| The B<MassPayItem> 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} eq 'Success' ) { | ||||
|     die "Failed: " . $resp{Errors}[0]{LongMessage} . "\n"; | ||||
|   } | ||||
| 
 | ||||
| =head2 ERROR HANDLING | ||||
| 
 | ||||
| See the B<ERROR HANDLING> section of B<Business::PayPal::API> for | ||||
| information on handling errors. | ||||
| 
 | ||||
| =head1 EXPORT | ||||
| 
 | ||||
| None by default. | ||||
| 
 | ||||
| =head1 SEE ALSO | ||||
| 
 | ||||
| L<https://developer.paypal.com/en_US/pdf/PP_APIReference.pdf> | ||||
| 
 | ||||
| =head1 AUTHOR | ||||
| 
 | ||||
| Scot Wiersdorf E<lt>scott@perlcode.orgE<gt> | ||||
| 
 | ||||
| =head1 COPYRIGHT AND LICENSE | ||||
| 
 | ||||
| Copyright (C) 2007 by Scott Wiersdorf | ||||
| 
 | ||||
| This library is free software; you can redistribute it and/or modify | ||||
| it under the same terms as Perl itself, either Perl version 5.8.5 or, | ||||
| at your option, any later version of Perl 5 you may have available. | ||||
| 
 | ||||
| 
 | ||||
| =cut | ||||
							
								
								
									
										143
									
								
								lib/Business/PayPal/API/ReauthorizationRequest.pm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								lib/Business/PayPal/API/ReauthorizationRequest.pm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,143 @@ | |||
| package Business::PayPal::API::ReauthorizationRequest; | ||||
| 
 | ||||
| use 5.008001; | ||||
| use strict; | ||||
| use warnings; | ||||
| 
 | ||||
| use SOAP::Lite 0.67; | ||||
| use Business::PayPal::API (); | ||||
| 
 | ||||
| our @ISA = qw(Business::PayPal::API); | ||||
| our $VERSION = '0.12'; | ||||
| our $CVS_VERSION = '$Id: ReauthorizationRequest.pm,v 1.2 2007/09/27 20:32:32 scott Exp $'; | ||||
| 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; | ||||
| __END__ | ||||
| 
 | ||||
| =head1 NAME | ||||
| 
 | ||||
| Business::PayPal::API::ReauthorizationRequest - PayPal ReauthorizationRequest API | ||||
| 
 | ||||
| =head1 SYNOPSIS | ||||
| 
 | ||||
|   use Business::PayPal::API::ReauthorizationRequest; | ||||
| 
 | ||||
|   ## see Business::PayPal::API documentation for parameters | ||||
|   my $pp = new Business::PayPal::API::ReauthorizationRequest ( ... ); | ||||
| 
 | ||||
|   my %response = $pp->DoReauthorizationRequest ( | ||||
|                                          AuthorizationID => $transid, | ||||
|                                          Amount          => $amount, | ||||
|                                          CurrencyID      => $currencyID | ||||
|                                          ); | ||||
|   | ||||
| =head1 DESCRIPTION | ||||
| 
 | ||||
| B<Business::PayPal::API::ReauthorizationRequest> implements PayPal's | ||||
| B<DoReauthorizationRequest> 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<sandbox>. Please see L<Business::PayPal::API> for details | ||||
| on using the PayPal sandbox. | ||||
| 
 | ||||
| =head2 DoReauthorizationRequest | ||||
| 
 | ||||
| Implements PayPal's B<DoReauthorizationRequest> 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<currencyID> 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} ne 'Success' ) { | ||||
|       for my $error ( @{$response{Errors}} ) { | ||||
|           warn "Error: " . $error->{LongMessage} . "\n"; | ||||
|       } | ||||
|   } | ||||
| 
 | ||||
| =head2 ERROR HANDLING | ||||
| 
 | ||||
| See the B<ERROR HANDLING> section of B<Business::PayPal::API> for | ||||
| information on handling errors. | ||||
| 
 | ||||
| =head2 EXPORT | ||||
| 
 | ||||
| None by default. | ||||
| 
 | ||||
| =head1 SEE ALSO | ||||
| 
 | ||||
| L<https://developer.paypal.com/en_US/pdf/PP_APIReference.pdf> | ||||
| 
 | ||||
| =head1 AUTHOR | ||||
| 
 | ||||
| Danny Hembree E<lt>danny@dynamical.orgE<gt> | ||||
| 
 | ||||
| =head1 COPYRIGHT AND LICENSE | ||||
| 
 | ||||
| Copyright (C) 2006 by Danny Hembree | ||||
| 
 | ||||
| This library is free software; you can redistribute it and/or modify | ||||
| it under the same terms as Perl itself, either Perl version 5.8.5 or, | ||||
| at your option, any later version of Perl 5 you may have available. | ||||
| 
 | ||||
| 
 | ||||
| =cut | ||||
							
								
								
									
										579
									
								
								lib/Business/PayPal/API/RecurringPayments.pm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										579
									
								
								lib/Business/PayPal/API/RecurringPayments.pm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,579 @@ | |||
| package Business::PayPal::API::RecurringPayments; | ||||
| 
 | ||||
| use 5.008001; | ||||
| use strict; | ||||
| use warnings; | ||||
| 
 | ||||
| use SOAP::Lite 0.67; | ||||
| use Business::PayPal::API (); | ||||
| 
 | ||||
| our @ISA = qw(Business::PayPal::API); | ||||
| our $VERSION = '0.02'; | ||||
| our $CVS_VERSION = '$Id: RecurringPayments.pm,v 1.2 2009/07/28 18:00:59 scott Exp $'; | ||||
| 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 | ||||
|               ( $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      => 'ns:BillingPeriodType', | ||||
|                           TrialBillingFrequency   => 'xs:int', | ||||
|                           TrialTotalBillingCycles => 'xs:int', | ||||
|                           TrialAmount             => 'cc:AmountType', | ||||
|                           TrialShippingAmount     => 'cc:AmountType', | ||||
|                           TrialTaxAmount          => 'cc:AmountType', ); | ||||
| 
 | ||||
|     my %paymentbilltype = ( PaymentBillingPeriod      => '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         => 'xs:string', | ||||
|                           CCPayerStatus     => 'xs:string', | ||||
|                           CCPayerName       => 'xs:string', | ||||
|                           CCPayerCountry    => 'xs:string', | ||||
|                           CCPayerPhone      => 'xs:string', | ||||
|                           CCPayerBusiness   => 'xs:string', | ||||
| #                          Address         => 'ns:AddressType', | ||||
|                          ); | ||||
| 
 | ||||
|     ## 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:string', ); | ||||
| 
 | ||||
|     ## 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; | ||||
| __END__ | ||||
| 
 | ||||
| =head1 NAME | ||||
| 
 | ||||
| Business::PayPal::API::RecurringPayments - PayPal RecurringPayments API | ||||
| 
 | ||||
| =head1 SYNOPSIS | ||||
| 
 | ||||
| use Business::PayPal::API::RecurringPayments; | ||||
| 
 | ||||
| my $pp = new Business::PayPal::API::RecurringPayments( ... ); | ||||
| 
 | ||||
| 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<DoReferenceTransaction> 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<https://developer.paypal.com/en_US/pdf/PP_APIReference.pdf> | ||||
| 
 | ||||
| =head1 AUTHOR | ||||
| 
 | ||||
| Scot Wiersdorf E<lt>scott@perlcode.orgE<gt> | ||||
| 
 | ||||
| =head1 COPYRIGHT AND LICENSE | ||||
| 
 | ||||
| Copyright (C) 2007 by Scott Wiersdorf | ||||
| 
 | ||||
| This library is free software; you can redistribute it and/or modify | ||||
| it under the same terms as Perl itself, either Perl version 5.8.5 or, | ||||
| at your option, any later version of Perl 5 you may have available. | ||||
| 
 | ||||
| =cut | ||||
							
								
								
									
										158
									
								
								lib/Business/PayPal/API/RefundTransaction.pm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								lib/Business/PayPal/API/RefundTransaction.pm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,158 @@ | |||
| package Business::PayPal::API::RefundTransaction; | ||||
| 
 | ||||
| use 5.008001; | ||||
| use strict; | ||||
| use warnings; | ||||
| 
 | ||||
| use SOAP::Lite 0.67; | ||||
| use Business::PayPal::API (); | ||||
| 
 | ||||
| our @ISA = qw(Business::PayPal::API); | ||||
| our $VERSION = '0.11'; | ||||
| our $CVS_VERSION = '$Id: RefundTransaction.pm,v 1.4 2006/03/24 17:11:50 scott Exp $'; | ||||
| 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; | ||||
| __END__ | ||||
| 
 | ||||
| =head1 NAME | ||||
| 
 | ||||
| Business::PayPal::API::RefundTransaction - PayPal RefundTransaction API | ||||
| 
 | ||||
| =head1 SYNOPSIS | ||||
| 
 | ||||
|   use Business::PayPal::API::RefundTransaction; | ||||
| 
 | ||||
|   ## see Business::PayPal::API documentation for parameters | ||||
|   my $pp = new Business::PayPal::API::RefundTransaction ( ... ); | ||||
| 
 | ||||
|   my %response = $pp->RefundTransaction( TransactionID => $transid, | ||||
|                                          RefundType    => 'Full', | ||||
|                                          Memo          => "Please come again!" ); | ||||
| 
 | ||||
| =head1 DESCRIPTION | ||||
| 
 | ||||
| B<Business::PayPal::API::RefundTransaction> implements PayPal's | ||||
| B<RefundTransaction> 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<sandbox>. Please see L<Business::PayPal::API> for details | ||||
| on using the PayPal sandbox. | ||||
| 
 | ||||
| =head2 RefundTransaction | ||||
| 
 | ||||
| Implements PayPal's B<RefundTransaction> 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<currencyID> setting is 'USD' if not otherwise specified. The | ||||
| default B<RefundType> setting is 'Full' if not otherwise specified. | ||||
| 
 | ||||
| If B<RefundType> is set to 'Full', B<Amount> is ignored (even if | ||||
| set). If B<RefundType> is set to 'Partial', B<Amount> is required. | ||||
| 
 | ||||
| Returns a hash containing the results of the transaction. The B<Ack> | ||||
| 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<not> | ||||
| returned with this API call). | ||||
| 
 | ||||
| Example: | ||||
| 
 | ||||
|   my %resp = $pp->RefundTransaction( TransactionID => $trans_id, | ||||
|                                      RefundType    => 'Partial', | ||||
|                                      Amount        => '15.00', ); | ||||
| 
 | ||||
|   unless( $resp{Ack} ne 'Success' ) { | ||||
|       for my $error ( @{$response{Errors}} ) { | ||||
|           warn "Error: " . $error->{LongMessage} . "\n"; | ||||
|       } | ||||
|   } | ||||
| 
 | ||||
| =head2 ERROR HANDLING | ||||
| 
 | ||||
| See the B<ERROR HANDLING> section of B<Business::PayPal::API> for | ||||
| information on handling errors. | ||||
| 
 | ||||
| =head2 EXPORT | ||||
| 
 | ||||
| None by default. | ||||
| 
 | ||||
| =head1 SEE ALSO | ||||
| 
 | ||||
| L<https://developer.paypal.com/en_US/pdf/PP_APIReference.pdf> | ||||
| 
 | ||||
| =head1 AUTHOR | ||||
| 
 | ||||
| Scot Wiersdorf E<lt>scott@perlcode.orgE<gt> | ||||
| 
 | ||||
| =head1 COPYRIGHT AND LICENSE | ||||
| 
 | ||||
| Copyright (C) 2006 by Scott Wiersdorf | ||||
| 
 | ||||
| This library is free software; you can redistribute it and/or modify | ||||
| it under the same terms as Perl itself, either Perl version 5.8.5 or, | ||||
| at your option, any later version of Perl 5 you may have available. | ||||
| 
 | ||||
| 
 | ||||
| =cut | ||||
							
								
								
									
										179
									
								
								lib/Business/PayPal/API/TransactionSearch.pm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								lib/Business/PayPal/API/TransactionSearch.pm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,179 @@ | |||
| package Business::PayPal::API::TransactionSearch; | ||||
| 
 | ||||
| use 5.008001; | ||||
| use strict; | ||||
| use warnings; | ||||
| 
 | ||||
| use SOAP::Lite 0.67; | ||||
| use Business::PayPal::API (); | ||||
| 
 | ||||
| our @ISA = qw(Business::PayPal::API); | ||||
| our $VERSION = '0.11'; | ||||
| our $CVS_VERSION = '$Id: TransactionSearch.pm,v 1.3 2006/03/24 17:11:37 scott Exp $'; | ||||
| 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', | ||||
|                   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; | ||||
| __END__ | ||||
| 
 | ||||
| =head1 NAME | ||||
| 
 | ||||
| Business::PayPal::API::TransactionSearch - PayPal TransactionSearch API | ||||
| 
 | ||||
| =head1 SYNOPSIS | ||||
| 
 | ||||
|   use Business::PayPal::API::TransactionSearch; | ||||
| 
 | ||||
|   ## see Business::PayPal::API documentation for parameters | ||||
|   my $pp = new Business::PayPal::API::TransactionSearch ( ... ); | ||||
| 
 | ||||
|   my %response = $pp->TransactionSearch( StartDate => '1998-01-01T00:00:00Z', | ||||
|                                          TransactionID => $transid, ); | ||||
| 
 | ||||
| =head1 DESCRIPTION | ||||
| 
 | ||||
| B<Business::PayPal::API::TransactionSearch> implements PayPal's | ||||
| B<TransactionSearch> 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<sandbox>. Please see L<Business::PayPal::API> for details | ||||
| on using the PayPal sandbox. | ||||
| 
 | ||||
| =head2 TransactionSearch | ||||
| 
 | ||||
| Implements PayPal's B<TransactionSearch> 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<ERROR HANDLING> section of B<Business::PayPal::API> for | ||||
| information on handling errors. | ||||
| 
 | ||||
| =head2 EXPORT | ||||
| 
 | ||||
| None by default. | ||||
| 
 | ||||
| =head1 SEE ALSO | ||||
| 
 | ||||
| L<https://developer.paypal.com/en_US/pdf/PP_APIReference.pdf> | ||||
| 
 | ||||
| =head1 AUTHOR | ||||
| 
 | ||||
| Scot Wiersdorf E<lt>scott@perlcode.orgE<gt> | ||||
| 
 | ||||
| =head1 COPYRIGHT AND LICENSE | ||||
| 
 | ||||
| Copyright (C) 2006 by Scott Wiersdorf | ||||
| 
 | ||||
| This library is free software; you can redistribute it and/or modify | ||||
| it under the same terms as Perl itself, either Perl version 5.8.5 or, | ||||
| at your option, any later version of Perl 5 you may have available. | ||||
| 
 | ||||
| 
 | ||||
| =cut | ||||
							
								
								
									
										136
									
								
								lib/Business/PayPal/API/VoidRequest.pm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								lib/Business/PayPal/API/VoidRequest.pm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,136 @@ | |||
| package Business::PayPal::API::VoidRequest; | ||||
| 
 | ||||
| use 5.008001; | ||||
| use strict; | ||||
| use warnings; | ||||
| 
 | ||||
| use SOAP::Lite 0.67; | ||||
| use Business::PayPal::API (); | ||||
| 
 | ||||
| our @ISA = qw(Business::PayPal::API); | ||||
| our $VERSION = '0.12'; | ||||
| our $CVS_VERSION = '$Id: VoidRequest.pm,v 1.2 2007/09/27 20:32:32 scott Exp $'; | ||||
| 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; | ||||
| __END__ | ||||
| 
 | ||||
| =head1 NAME | ||||
| 
 | ||||
| Business::PayPal::API::VoidRequest - PayPal VoidRequest API | ||||
| 
 | ||||
| =head1 SYNOPSIS | ||||
| 
 | ||||
|   use Business::PayPal::API::VoidRequest; | ||||
| 
 | ||||
|   ## see Business::PayPal::API documentation for parameters | ||||
|   my $pp = new Business::PayPal::API::VoidRequest ( ... ); | ||||
| 
 | ||||
|   my %response = $pp->DoVoidRequest( AuthorizationID => $transid | ||||
|                                      Note            => "Please come again!" ); | ||||
| 
 | ||||
| =head1 DESCRIPTION | ||||
| 
 | ||||
| B<Business::PayPal::API::VoidRequest> implements PayPal's | ||||
| B<VoidRequest> 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<sandbox>. Please see L<Business::PayPal::API> for details | ||||
| on using the PayPal sandbox. | ||||
| 
 | ||||
| =head2 DoVoidRequest | ||||
| 
 | ||||
| Implements PayPal's B<DoVoidRequest> API call. Supported | ||||
| parameters include: | ||||
| 
 | ||||
|   AuthorizationID | ||||
|   Note | ||||
| 
 | ||||
| The B<AuthorizationID> is the original ID. Not a subsequent ID from a | ||||
| B<ReAuthorizationRequest>. The note is a 255 character message for | ||||
| whatever purpose you deem fit. | ||||
| 
 | ||||
| Returns a hash containing the results of the transaction. The B<Ack> | ||||
| 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<not> | ||||
| returned with this API call). | ||||
| 
 | ||||
| Example: | ||||
| 
 | ||||
|   my %resp = $pp->DoVoidRequest( AuthorizationID => $trans_id, | ||||
|                                  Note            => 'Sorry about that.' ); | ||||
| 
 | ||||
|   unless( $resp{Ack} ne 'Success' ) { | ||||
|       for my $error ( @{$response{Errors}} ) { | ||||
|           warn "Error: " . $error->{LongMessage} . "\n"; | ||||
|       } | ||||
|   } | ||||
| 
 | ||||
| =head2 ERROR HANDLING | ||||
| 
 | ||||
| See the B<ERROR HANDLING> section of B<Business::PayPal::API> for | ||||
| information on handling errors. | ||||
| 
 | ||||
| =head2 EXPORT | ||||
| 
 | ||||
| None by default. | ||||
| 
 | ||||
| =head1 SEE ALSO | ||||
| 
 | ||||
| L<https://developer.paypal.com/en_US/pdf/PP_APIReference.pdf> | ||||
| 
 | ||||
| =head1 AUTHOR | ||||
| 
 | ||||
| Danny Hembree E<lt>danny@dynamical.orgE<gt> | ||||
| 
 | ||||
| =head1 COPYRIGHT AND LICENSE | ||||
| 
 | ||||
| Copyright (C) 2006 by Danny Hembree | ||||
| 
 | ||||
| This library is free software; you can redistribute it and/or modify | ||||
| it under the same terms as Perl itself, either Perl version 5.8.5 or, | ||||
| at your option, any later version of Perl 5 you may have available. | ||||
| 
 | ||||
| 
 | ||||
| =cut | ||||
							
								
								
									
										53
									
								
								t/API.pl
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								t/API.pl
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,53 @@ | |||
| =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 make test | ||||
| 
 | ||||
| =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 | ||||
| 		      ); | ||||
| 
 | ||||
|     my %patterns = (); | ||||
|     @patterns{map { qr/^$_\b/i } @variables} = @variables; | ||||
| 
 | ||||
|     while( <FILE> ) { | ||||
|         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; | ||||
							
								
								
									
										5
									
								
								t/Business-PayPal-API.t
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								t/Business-PayPal-API.t
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | |||
| use Test::More tests => 1; | ||||
| BEGIN { use_ok('Business::PayPal::API') }; | ||||
| 
 | ||||
| ######################### | ||||
| 
 | ||||
							
								
								
									
										199
									
								
								t/DirectPayments.t
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								t/DirectPayments.t
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,199 @@ | |||
| #!/usr/bin/perl | ||||
| use strict; | ||||
| use warnings; | ||||
| 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 => '9'; | ||||
| } | ||||
| 
 | ||||
| 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 Partial Refund on Sale | ||||
| 
 | ||||
| #$Business::PayPal::API::Debug=1; | ||||
| $ppsale = new Business::PayPal::API(%args); | ||||
| %respsale = $ppsale->DoDirectPaymentRequest ( | ||||
|                         PaymentAction    => 'Sale', | ||||
|                         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(is( $respsale{'Ack'}, 'Success', 'Direct Payment Sale')) { | ||||
|             $transale = $respsale{'TransactionID'}; | ||||
| #$Business::PayPal::API::Debug=1; | ||||
|             $pprefund = new Business::PayPal::API(%args); | ||||
|             %resprefund = $pprefund->RefundTransaction ( | ||||
|                             TransactionID => $transale, | ||||
|                             RefundType    => 'Partial', | ||||
|                             Amount        => '3.00', | ||||
|                             Memo          => 'Partial three dollar refund', | ||||
|                             ); | ||||
| #$Business::PayPal::API::Debug=0; | ||||
|             is( $resprefund{'Ack'}, 'Success', 'Partial Refund for sale'); | ||||
|       } | ||||
| 
 | ||||
| #Test Full Refund on Sale | ||||
| 
 | ||||
| #$Business::PayPal::API::Debug=1; | ||||
| $ppsale = new Business::PayPal::API(%args); | ||||
| %respsale = $ppsale->DoDirectPaymentRequest ( | ||||
|                         PaymentAction    => 'Sale', | ||||
|                         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(is( $respsale{'Ack'}, 'Success', 'Direct Payment Sale')) { | ||||
|             $transale = $respsale{'TransactionID'}; | ||||
| #$Business::PayPal::API::Debug=1; | ||||
|             $pprefund1 = new Business::PayPal::API(%args); | ||||
|             %resprefund1 = $pprefund1->RefundTransaction ( | ||||
|                             TransactionID => $transale, | ||||
|                             RefundType    => 'Full', | ||||
|                             Memo          => 'Full refund', | ||||
|                             ); | ||||
| #$Business::PayPal::API::Debug=0; | ||||
|             is( $resprefund1{'Ack'}, 'Success', 'Full Refund for sale'); | ||||
|       } | ||||
| 
 | ||||
| #Basic Authorization and Capture | ||||
| 
 | ||||
| %args=do_args(); | ||||
| #$Business::PayPal::API::Debug=0; | ||||
| $ppbasic = new Business::PayPal::API(%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( is( $respbasic{'Ack'}, 'Success', 'Direct Payment Basic Authorization') ) { | ||||
|     $tranbasic = $respbasic{'TransactionID'}; | ||||
| 
 | ||||
|     #Test Partial Capture | ||||
|     #$Business::PayPal::API::Debug=1; | ||||
|     $ppcap = new Business::PayPal::API(%args); | ||||
| 
 | ||||
|     %respcap = $ppcap->DoCaptureRequest ( | ||||
| 					 AuthorizationID => $tranbasic, | ||||
| 					 CompleteType    => 'NotComplete', | ||||
| 					 Amount        => '3.00', | ||||
| 					 Note          => 'Partial Capture', | ||||
| 					); | ||||
|     #$Business::PayPal::API::Debug=0; | ||||
|     is( $respcap{'Ack'}, 'Success', 'Partial Capture'); | ||||
| 
 | ||||
|     #Test Full Capture | ||||
|     #$Business::PayPal::API::Debug=1; | ||||
|     $ppcap1 = new Business::PayPal::API(%args); | ||||
|     %respcap1 = $ppcap1->DoCaptureRequest ( | ||||
| 					   AuthorizationID => $tranbasic, | ||||
| 					   CompleteType    => 'Complete', | ||||
| 					   Amount          => '6.00', | ||||
| 					  ); | ||||
|     #$Business::PayPal::API::Debug=0; | ||||
|     is( $respcap1{'Ack'}, 'Success', 'Full Capture'); | ||||
| } | ||||
| else { skip( "direct payment auth failed", 2 ) } | ||||
| 
 | ||||
| #Test Void | ||||
| $ppbasic = new Business::PayPal::API(%args); | ||||
| %respbasic = $ppbasic->DoDirectPaymentRequest ( | ||||
|                         PaymentAction    => 'Authorization', | ||||
|                         OrderTotal    => 18.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 = new Business::PayPal::API(%args); | ||||
| %respvoid = $ppvoid->DoVoidRequest ( AuthorizationID => $respbasic{TransactionID}, | ||||
| 				     Note            => 'Authorization Void', ); | ||||
| #$Business::PayPal::API::Debug=0; | ||||
| is( $respvoid{'Ack'}, 'Success', 'Authorization Voided'); | ||||
							
								
								
									
										92
									
								
								t/ExpressCheckout.t
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								t/ExpressCheckout.t
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,92 @@ | |||
| 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://www.google.com/', | ||||
|     CancelURL  => 'http://www.google.com/',  | ||||
|     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 = <STDIN>; 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); | ||||
| 
 | ||||
| is( $payinfo{Ack}, 'Success', "successful payment" ); | ||||
| is( $payinfo{Token}, $token, "payment ok" ); | ||||
| is( $payinfo{GrossAmount}, 55.43, "amount correct" ); | ||||
							
								
								
									
										112
									
								
								t/ExpressOrder.t
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								t/ExpressOrder.t
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,112 @@ | |||
| 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://www.google.com/', | ||||
|     CancelURL  => 'http://www.google.com/',  | ||||
|     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 = <STDIN>; 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(is( $payinfo{Ack}, '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); | ||||
|     is( $resp{Ack}, 'Success', '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' ); | ||||
|                                                                                  | ||||
|     is( $resp1{Ack}, 'Success', 'Successful order void' ); | ||||
|     } | ||||
							
								
								
									
										44
									
								
								t/GetTransactionDetails.t
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								t/GetTransactionDetails.t
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,44 @@ | |||
| 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 = <STDIN>; chomp $transid; | ||||
| 
 | ||||
| die "Need a transaction id.\n" unless $transid; | ||||
| 
 | ||||
| #$Business::PayPal::API::Debug = 1; | ||||
| my %resp = $pp->GetTransactionDetails( TransactionID => $transid ); | ||||
| 
 | ||||
| is( $resp{Ack}, 'Success', "transaction received" ); | ||||
							
								
								
									
										37
									
								
								t/MassPay.t
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								t/MassPay.t
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,37 @@ | |||
| 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." } ] ); | ||||
| 
 | ||||
| is( $resp{Ack}, '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." } ] ); | ||||
| 
 | ||||
| is( $resp{Ack}, 'Success', "successful payments" ); | ||||
							
								
								
									
										123
									
								
								t/RecurringPayments.t
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								t/RecurringPayments.t
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,123 @@ | |||
| # -*- 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 => 4; | ||||
| } | ||||
| 
 | ||||
| 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', | ||||
| 
 | ||||
|    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" ); | ||||
| is( $response{Ack}, '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 = <STDIN>; 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 => '12-31-08', | ||||
|     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; | ||||
| 
 | ||||
| is( $details{Ack}, "Success", "details ok" ); | ||||
| 
 | ||||
							
								
								
									
										55
									
								
								t/RefundTransaction.t
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								t/RefundTransaction.t
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,55 @@ | |||
| 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 = <STDIN>; chomp $transid; | ||||
| 
 | ||||
| die "Need a transaction id.\n" unless $transid; | ||||
| 
 | ||||
| my %resp = $pp->RefundTransaction( TransactionID => $transid, | ||||
|                                    RefundType    => 'Full', | ||||
|                                    Memo          => 'Fancy refund time.' ); | ||||
| 
 | ||||
| is( $resp{Ack}, '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_ | ||||
| } | ||||
							
								
								
									
										47
									
								
								t/TransactionSearch.t
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								t/TransactionSearch.t
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,47 @@ | |||
| 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. | ||||
| 
 | ||||
| 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 = <STDIN>; chomp $transid; | ||||
| 
 | ||||
| die "Need a transaction id.\n" unless $transid; | ||||
| 
 | ||||
| my $startdate = '1998-01-01T00:00:00Z';  ## before PayPal | ||||
| 
 | ||||
| #$Business::PayPal::API::Debug = 1; | ||||
| my $resp = $pp->TransactionSearch( StartDate    => $startdate, | ||||
|                                    TransactionID => $transid, ); | ||||
| 
 | ||||
| ok( scalar @$resp, "matching transaction(s) found" ); | ||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Daniel Hembree
						Daniel Hembree