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…
Reference in a new issue