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 |