579 lines
22 KiB
Perl
579 lines
22 KiB
Perl
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
|
|
( $self->version_req, #$API_VERSION,
|
|
SOAP::Data->name( SetCustomerBillingAgreementRequestDetails => \SOAP::Data->value(@scba)
|
|
)->attr( {xmlns => $self->C_xmlns_ebay} ),
|
|
)
|
|
)->type( 'ns:SetCustomerBillingAgreementRequestDetailsType' );
|
|
|
|
my $som = $self->doCall( SetCustomerBillingAgreementReq => $request )
|
|
or return;
|
|
|
|
my $path = '/Envelope/Body/SetCustomerBillingAgreementResponse';
|
|
|
|
my %response = ();
|
|
unless( $self->getBasic($som, $path, \%response) ) {
|
|
$self->getErrors($som, $path, \%response);
|
|
return %response;
|
|
}
|
|
|
|
$self->getFields($som, $path, \%response, { Token => 'Token' });
|
|
|
|
return %response;
|
|
}
|
|
|
|
sub GetBillingAgreementCustomerDetails {
|
|
my $self = shift;
|
|
my $token = shift;
|
|
|
|
my $request = SOAP::Data
|
|
->name( GetBillingAgreementCustomerDetailsRequest => \SOAP::Data->value
|
|
( $self->version_req,
|
|
SOAP::Data->name( Token => $token )
|
|
->type('xs:string')->attr( {xmlns => $self->C_xmlns_ebay} ),
|
|
)
|
|
)->type( 'ns:GetBillingAgreementCustomerDetailsResponseType' );
|
|
|
|
my $som = $self->doCall( GetBillingAgreementCustomerDetailsReq => $request )
|
|
or return;
|
|
|
|
my $path = '/Envelope/Body/GetBillingAgreementCustomerDetailsResponse';
|
|
|
|
my %details = ();
|
|
unless( $self->getBasic($som, $path, \%details) ) {
|
|
$self->getErrors($som, $path, \%details);
|
|
return %details;
|
|
}
|
|
|
|
$self->getFields($som,
|
|
"$path/GetBillingAgreementCustomerDetailsResponseDetails",
|
|
\%details,
|
|
{ Token => 'Token',
|
|
|
|
Payer => 'PayerInfo/Payer',
|
|
PayerID => 'PayerInfo/PayerID',
|
|
PayerStatus => 'PayerInfo/PayerStatus', ## 'unverified'
|
|
PayerBusiness => 'PayerInfo/PayerBusiness',
|
|
|
|
Name => 'PayerInfo/Address/Name',
|
|
AddressOwner => 'PayerInfo/Address/AddressOwner', ## 'PayPal'
|
|
AddressStatus => 'PayerInfo/Address/AddressStatus', ## 'none'
|
|
Street1 => 'PayerInfo/Address/Street1',
|
|
Street2 => 'PayerInfo/Address/Street2',
|
|
StateOrProvince => 'PayerInfo/Address/StateOrProvince',
|
|
PostalCode => 'PayerInfo/Address/PostalCode',
|
|
CountryName => 'PayerInfo/Address/CountryName',
|
|
|
|
Salutation => 'PayerInfo/PayerName/Salutation',
|
|
FirstName => 'PayerInfo/PayerName/FirstName',
|
|
MiddleName => 'PayerInfo/PayerName/MiddleName',
|
|
LastName => 'PayerInfo/PayerName/LastName',
|
|
Suffix => 'PayerInfo/PayerName/Suffix',
|
|
} );
|
|
|
|
return %details;
|
|
}
|
|
|
|
sub CreateRecurringPaymentsProfile {
|
|
my $self = shift;
|
|
my %args = @_;
|
|
|
|
## RecurringPaymentProfileDetails
|
|
my %profiledetailstype = ( SubscriberName => 'xs:string',
|
|
SubscriberShipperAddress => 'ns:AddressType',
|
|
BillingStartDate => 'xs:dateTime', ## MM-DD-YY
|
|
ProfileReference => 'xs:string', );
|
|
|
|
## ScheduleDetailsType
|
|
my %schedtype = ( Description => 'xs:string',
|
|
ActivationDetails => 'ns:ActivationDetailsType',
|
|
TrialPeriod => 'ns:BillingPeriodDetailsType',
|
|
PaymentPeriod => 'ns:BillingPeriodDetailsType',
|
|
MaxFailedPayments => 'xs:int',
|
|
AutoBillOutstandingAmount => 'ns:AutoBillType', ); ## NoAutoBill or AddToNextBilling
|
|
|
|
## activation details
|
|
my %activationdetailstype = ( InitialAmount => 'cc:BasicAmountType',
|
|
FailedInitialAmountAction => 'ns:FailedPaymentAction', ); ## ContinueOnFailure or CancelOnFailure
|
|
|
|
## BillingPeriodDetailsType
|
|
my %trialbilltype = ( TrialBillingPeriod => 'xs:string', ##'ns:BillingPeriodType',
|
|
TrialBillingFrequency => 'xs:int',
|
|
TrialTotalBillingCycles => 'xs:int',
|
|
TrialAmount => 'cc:AmountType',
|
|
TrialShippingAmount => 'cc:AmountType',
|
|
TrialTaxAmount => 'cc:AmountType', );
|
|
|
|
my %paymentbilltype = ( PaymentBillingPeriod => 'xs:string', ##'ns:BillingPeriodType',
|
|
PaymentBillingFrequency => 'xs:int',
|
|
PaymentTotalBillingCycles => 'xs:int',
|
|
PaymentAmount => 'cc:AmountType',
|
|
PaymentShippingAmount => 'cc:AmountType',
|
|
PaymentTaxAmount => 'cc:AmountType', );
|
|
|
|
## AddressType
|
|
my %payaddrtype = ( CCPayerName => 'xs:string',
|
|
CCPayerStreet1 => 'xs:string',
|
|
CCPayerStreet2 => 'xs:string',
|
|
CCPayerCityName => 'xs:string',
|
|
CCPayerStateOrProvince => 'xs:string',
|
|
CCPayerCountry => 'xs:string', ## ebl:CountryCodeType
|
|
CCPayerPostalCode => 'xs:string',
|
|
CCPayerPhone => 'xs:string', );
|
|
|
|
my %shipaddrtype = ( SubscriberShipperName => 'xs:string',
|
|
SubscriberShipperStreet1 => 'xs:string',
|
|
SubscriberShipperStreet2 => 'xs:string',
|
|
SubscriberShipperCityName => 'xs:string',
|
|
SubscriberShipperStateOrProvince => 'xs:string',
|
|
SubscriberShipperCountry => 'xs:string', ## ebl:CountryCodeType
|
|
SubscriberShipperPostalCode => 'xs:string',
|
|
SubscriberShipperPhone => 'xs:string', );
|
|
|
|
## credit card payer
|
|
my %payerinfotype = ( CCPayer => 'ns:EmailAddressType',
|
|
CCPayerID => 'ebl:UserIDType',
|
|
CCPayerStatus => 'xs:string',
|
|
CCPayerName => 'xs:string',
|
|
CCPayerCountry => 'xs:string',
|
|
CCPayerPhone => 'xs:string',
|
|
CCPayerBusiness => 'xs:string',
|
|
CCAddress => 'xs:string',
|
|
);
|
|
|
|
## credit card details
|
|
my %creditcarddetailstype = ( CardOwner => 'ns:PayerInfoType',
|
|
CreditCardType => 'ebl:CreditCardType', ## Visa, MasterCard, Discover, Amex, Switch, Solo
|
|
CreditCardNumber => 'xs:string',
|
|
ExpMonth => 'xs:int',
|
|
ExpYear => 'xs:int',
|
|
CVV2 => 'xs:string',
|
|
StartMonth => 'xs:string',
|
|
StartYear => 'xs:string',
|
|
IssueNumber => 'xs:int', );
|
|
|
|
## this gets pushed onto scheduledetails
|
|
my @activationdetailstype = ();
|
|
for my $field ( keys %activationdetailstype ) {
|
|
next unless exists $args{$field};
|
|
my $real_field = $field;
|
|
push @activationdetailstype, SOAP::Data->name( $real_field => $args{$field} )->type( $activationdetailstype{$field} );
|
|
}
|
|
|
|
## this gets pushed onto scheduledetails
|
|
my @trialbilltype = ();
|
|
for my $field ( keys %trialbilltype ) {
|
|
next unless exists $args{$field};
|
|
(my $real_field = $field) =~ s/^Trial//;
|
|
push @trialbilltype, SOAP::Data->name( $real_field => $args{$field} )->type( $trialbilltype{$field} );
|
|
}
|
|
|
|
## this gets pushed onto scheduledetails
|
|
my @paymentbilltype = ();
|
|
for my $field ( keys %paymentbilltype ) {
|
|
next unless exists $args{$field};
|
|
(my $real_field = $field) =~ s/^Payment//;
|
|
push @paymentbilltype, SOAP::Data->name( $real_field => $args{$field} )->type( $paymentbilltype{$field} );
|
|
}
|
|
|
|
## this gets pushed onto the top
|
|
my @sched = ();
|
|
for my $field ( keys %schedtype ) {
|
|
next unless exists $args{$field};
|
|
push @sched, SOAP::Data->name( $field => $args{$field} )->type( $schedtype{$field} );
|
|
}
|
|
push @sched, SOAP::Data->name( TrialPeriod => \SOAP::Data->value(@trialbilltype) ); #->type( 'ns:BillingPeriodDetailsType' );
|
|
push @sched, SOAP::Data->name( PaymentPeriod => \SOAP::Data->value(@paymentbilltype) ); #->type( 'ns:BillingPeriodDetailsType' );
|
|
|
|
## this gets pushed into profile details
|
|
my @shipaddr = ();
|
|
for my $field ( keys %shipaddrtype ) {
|
|
next unless exists $args{$field};
|
|
(my $real_field = $field) =~ s/^SubscriberShipper//;
|
|
push @shipaddr, SOAP::Data->name( $real_field => $args{$field} )->type( $shipaddrtype{$field} );
|
|
}
|
|
|
|
## this gets pushed into payerinfo (from creditcarddetails)
|
|
my @payeraddr = ();
|
|
for my $field ( keys %payaddrtype ) {
|
|
next unless $args{$field};
|
|
(my $real_field = $field) =~ s/^CCPayer//;
|
|
push @payeraddr, SOAP::Data->name( $real_field => $args{$field} )->type( payaddrtype{$field} );
|
|
}
|
|
|
|
## credit card type
|
|
my @creditcarddetails = ();
|
|
for my $field ( keys %creditcarddetailstype ) {
|
|
next unless $args{$field};
|
|
(my $real_field = $field) =~ s/^CC//;
|
|
push @payeraddr, SOAP::Data->name( $real_field => $args{$field} )->type( payaddrtype{$field} );
|
|
}
|
|
|
|
## this gets pushed onto the top
|
|
my @profdetail = ();
|
|
for my $field ( keys %profiledetailstype ) {
|
|
next unless exists $args{$field};
|
|
push @profdetail, SOAP::Data->name( $field => $args{$field} )->type( $profiledetailstype{$field} );
|
|
}
|
|
push @profdetail, SOAP::Data->name( SubscriberShipperAddress => \SOAP::Data->value(@shipaddr) );
|
|
|
|
## crappard?
|
|
my @crpprd = ();
|
|
push @crpprd, SOAP::Data->name( Token => $args{Token} );
|
|
push @crpprd, SOAP::Data->name( CreditCardDetails => \SOAP::Data->value(@creditcarddetails) ); #->type( 'ns:CreditCardDetailsType' );
|
|
push @crpprd, SOAP::Data->name( RecurringPaymentProfileDetails => \SOAP::Data->value(@profdetail) ); #->type( 'ns:RecurringPaymentProfileDetailsType' );
|
|
push @crpprd, SOAP::Data->name( ScheduleDetails => \SOAP::Data->value(@sched) ); #->type( 'ns:ScheduleDetailsType' );
|
|
|
|
my $request = SOAP::Data->name
|
|
( CreateRecurringPaymentsProfileRequest => \SOAP::Data->value
|
|
# ( $API_VERSION,
|
|
( $self->version_req,
|
|
SOAP::Data->name( CreateRecurringPaymentsProfileRequestDetails => \SOAP::Data->value(@crpprd)
|
|
)->attr( {xmlns => $self->C_xmlns_ebay} )
|
|
)
|
|
); #->type( 'ns:CreateRecurringPaymentsProfileRequestType' );
|
|
|
|
my $som = $self->doCall( CreateRecurringPaymentsProfileReq => $request )
|
|
or return;
|
|
|
|
my $path = '/Envelope/Body/CreateRecurringPaymentsProfileResponse';
|
|
|
|
my %response = ();
|
|
unless( $self->getBasic($som, $path, \%response) ) {
|
|
$self->getErrors($som, $path, \%response);
|
|
return %response;
|
|
}
|
|
|
|
$self->getFields($som, $path, \%response, { Token => 'Token' });
|
|
|
|
return %response;
|
|
}
|
|
|
|
sub DoReferenceTransaction {
|
|
my $self = shift;
|
|
my %args = @_;
|
|
|
|
my %types = ( ReferenceID => 'xs:string',
|
|
PaymentAction => '', ## NOTA BENE!
|
|
currencyID => '',
|
|
);
|
|
|
|
## PaymentDetails
|
|
my %pd_types = ( OrderTotal => 'ebl:BasicAmountType',
|
|
OrderDescription => 'xs:string',
|
|
ItemTotal => 'ebl:BasicAmountType',
|
|
ShippingTotal => 'ebl:BasicAmountType',
|
|
HandlingTotal => 'ebl:BasicAmountType',
|
|
TaxTotal => 'ebl:BasicAmountType',
|
|
Custom => 'xs:string',
|
|
InvoiceID => 'xs:string',
|
|
ButtonSource => 'xs:string',
|
|
NotifyURL => 'xs:string',
|
|
);
|
|
|
|
## ShipToAddress
|
|
my %st_types = ( ST_Name => 'xs:string',
|
|
ST_Street1 => 'xs:string',
|
|
ST_Street2 => 'xs:string',
|
|
ST_CityName => 'xs:string',
|
|
ST_StateOrProvince => 'xs:string',
|
|
ST_Country => 'xs:string',
|
|
ST_PostalCode => 'xs:string',
|
|
ST_Phone => 'xs:string',
|
|
);
|
|
|
|
##PaymentDetailsItem
|
|
my %pdi_types = ( PDI_Name => 'xs:string',
|
|
PDI_Description => 'xs:string',
|
|
PDI_Amount => 'ebl:BasicAmountType',
|
|
PDI_Number => 'xs:string',
|
|
PDI_Quantity => 'xs:string',
|
|
PDI_Tax => 'ebl:BasicAmountType',
|
|
);
|
|
|
|
$args{PaymentAction} ||= 'Sale';
|
|
$args{currencyID} ||= 'USD';
|
|
|
|
my @payment_details = ( );
|
|
|
|
## push OrderTotal here and delete it (i.e., and all others that have special attrs)
|
|
push @payment_details, SOAP::Data->name( OrderTotal => $args{OrderTotal} )
|
|
->type( $pd_types{OrderTotal} )
|
|
->attr( { currencyID => $args{currencyID},
|
|
xmlns => $self->C_xmlns_ebay } );
|
|
|
|
## don't process it again
|
|
delete $pd_types{OrderTotal};
|
|
|
|
for my $field ( keys %pd_types ) {
|
|
if( $args{$field} ) {
|
|
push @payment_details,
|
|
SOAP::Data->name( $field => $args{$field} )
|
|
->type( $pd_types{$field} );
|
|
}
|
|
}
|
|
|
|
##
|
|
## ShipToAddress
|
|
##
|
|
my @ship_types = ();
|
|
for my $field ( keys %st_types ) {
|
|
if( $args{$field} ) {
|
|
(my $name = $field) =~ s/^ST_//;
|
|
push @ship_types,
|
|
SOAP::Data->name( $name => $args{$field} )
|
|
->type( $st_types{$field} );
|
|
}
|
|
}
|
|
|
|
if( scalar @ship_types ) {
|
|
push @payment_details,
|
|
SOAP::Data->name( ShipToAddress => \SOAP::Data->value
|
|
( @ship_types )->type('ebl:AddressType')
|
|
->attr( {xmlns => $self->C_xmlns_ebay} ),
|
|
);
|
|
}
|
|
|
|
##
|
|
## PaymentDetailsItem
|
|
##
|
|
my @payment_details_item = ();
|
|
for my $field ( keys %pdi_types ) {
|
|
if( $args{$field} ) {
|
|
(my $name = $field) =~ s/^PDI_//;
|
|
push @payment_details_item,
|
|
SOAP::Data->name( $name => $args{$field} )
|
|
->type( $pdi_types{$field} );
|
|
}
|
|
}
|
|
|
|
if( scalar @payment_details_item ) {
|
|
push @payment_details,
|
|
SOAP::Data->name( PaymentDetailsItem => \SOAP::Data->value
|
|
( @payment_details_item )->type('ebl:PaymentDetailsItemType')
|
|
->attr( {xmlns => $self->C_xmlns_ebay} ),
|
|
);
|
|
}
|
|
|
|
##
|
|
## ReferenceTransactionPaymentDetails
|
|
##
|
|
my @reference_details = (
|
|
SOAP::Data->name( ReferenceID => $args{ReferenceID} )
|
|
->type($types{ReferenceID})->attr( {xmlns => $self->C_xmlns_ebay} ),
|
|
SOAP::Data->name( PaymentAction => $args{PaymentAction} )
|
|
->type($types{PaymentAction})->attr( {xmlns => $self->C_xmlns_ebay} ),
|
|
SOAP::Data->name( PaymentDetails => \SOAP::Data->value
|
|
( @payment_details )->type('ebl:PaymentDetailsType')
|
|
->attr( {xmlns => $self->C_xmlns_ebay} ),
|
|
), );
|
|
|
|
##
|
|
## the main request object
|
|
##
|
|
my $request = SOAP::Data
|
|
->name( DoReferenceTransactionRequest => \SOAP::Data->value
|
|
( $self->version_req,
|
|
SOAP::Data->name( DoReferenceTransactionRequestDetails => \SOAP::Data->value
|
|
( @reference_details )->type( 'ns:DoReferenceTransactionRequestDetailsType' )
|
|
)->attr( {xmlns => $self->C_xmlns_ebay} ),
|
|
)
|
|
);
|
|
|
|
my $som = $self->doCall( DoReferenceTransactionReq => $request )
|
|
or return;
|
|
|
|
my $path = '/Envelope/Body/DoReferenceTransactionResponse';
|
|
|
|
my %response = ();
|
|
unless( $self->getBasic($som, $path, \%response) ) {
|
|
$self->getErrors($som, $path, \%response);
|
|
return %response;
|
|
}
|
|
|
|
$self->getFields( $som,
|
|
"$path/DoReferenceTransactionResponseDetails",
|
|
\%response,
|
|
{ BillingAgreementID => 'BillingAgreementID',
|
|
TransactionID => 'PaymentInfo/TransactionID',
|
|
TransactionType => 'PaymentInfo/TransactionType',
|
|
PaymentType => 'PaymentInfo/PaymentType',
|
|
PaymentDate => 'PaymentInfo/PaymentDate',
|
|
GrossAmount => 'PaymentInfo/GrossAmount',
|
|
FeeAmount => 'PaymentInfo/FeeAmount',
|
|
SettleAmount => 'PaymentInfo/SettleAmount',
|
|
TaxAmount => 'PaymentInfo/TaxAmount',
|
|
ExchangeRate => 'PaymentInfo/ExchangeRate',
|
|
PaymentStatus => 'PaymentInfo/PaymentStatus',
|
|
PendingReason => 'PaymentInfo/PendingReason',
|
|
ReasonCode => 'PaymentInfor/ReasonCode',
|
|
} );
|
|
|
|
return %response;
|
|
}
|
|
|
|
1;
|
|
__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
|