X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=InternetSecure.pm;h=b6632edaca0bccbc994058ecae7046ac809f4a3a;hb=df677a47383944a67d88371a83d18d557602f3cd;hp=a7b1d0f5d23a83a220b268298e3ae5c822b8c837;hpb=227f87ababc68077ac00d2fb5ee52f080370cbff;p=Business-OnlinePayment-InternetSecure.git diff --git a/InternetSecure.pm b/InternetSecure.pm index a7b1d0f..b6632ed 100755 --- a/InternetSecure.pm +++ b/InternetSecure.pm @@ -12,17 +12,17 @@ use XML::Simple qw(xml_in xml_out); use base qw(Business::OnlinePayment Exporter); -our $VERSION = '0.01'; +our $VERSION = '0.03'; use constant SUCCESS_CODES => qw(2000 90000 900P1); use constant CARD_TYPES => { - VI => 'Visa', + AM => 'American Express', + JB => 'JCB', MC => 'MasterCard', - AX => 'American Express', # FIXME: AM? NN => 'Discover', - # JB? + VI => 'Visa', }; @@ -39,36 +39,36 @@ sub set_defaults { $self->path('/process.cgi'); $self->build_subs(qw( - receipt_number sales_number uuid guid + receipt_number order_number uuid guid date card_type cardholder - total_amount taxes - avs_response cvv2_response + total_amount tax_amounts + avs_code cvv2_response )); - # Just in case someone tries to call taxes() *before* submit() - $self->taxes( {} ); + # Just in case someone tries to call tax_amounts() *before* submit() + $self->tax_amounts( {} ); } -# OnlinePayment's get_fields now filters out undefs in 3.x. :( -# -sub get_fields { - my ($self, @fields) = @_; - - my %content = $self->content; +# Backwards-compatible support for renamed fields +sub avs_response { shift()->avs_code(@_) } +sub sales_number { shift()->order_number(@_) } - my %new = map +($_ => $content{$_}), @fields; - return %new; -} - -# Combine get_fields and remap_fields for convenience +# Combine get_fields and remap_fields for convenience. Unlike OnlinePayment's +# remap_fields, this doesn't modify content(), and can therefore be called +# more than once. Also, unlike OnlinePayment's get_fields in 3.x, this doesn't +# exclude undefs. # sub get_remap_fields { my ($self, %map) = @_; - $self->remap_fields(reverse %map); - my %data = $self->get_fields(keys %map); + my %content = $self->content(); + my %data; + + while (my ($to, $from) = each %map) { + $data{$to} = $content{$from}; + } return %data; } @@ -108,9 +108,16 @@ sub prod_string { my @flags = ($currency); - foreach (split ' ' => uc($data{taxes} || '')) { - croak "Unknown tax code $_" unless /^(GST|PST|HST)$/; - push @flags, $_; + my @taxes; + if (ref $data{taxes}) { + @taxes = @{ $data{taxes} }; + } elsif ($data{taxes}) { + @taxes = split ' ' => $data{taxes}; + } + + foreach (@taxes) { + croak "Unknown tax code $_" unless /^(GST|PST|HST)$/i; + push @flags, uc $_; } if ($self->test_transaction) { @@ -133,11 +140,18 @@ sub to_xml { my %content = $self->content; - $self->required_fields(qw(action card_number exp_date)); + # Backwards-compatible support for exp_date + if (exists $content{exp_date} && ! exists $content{expiration}) { + $content{expiration} = delete $content{exp_date}; + $self->content(%content); + } + + $self->required_fields(qw(action card_number expiration)); - croak 'Unsupported transaction type' - if $content{type} && $content{type} !~ - /^(Visa|MasterCard|American Express|Discover)$/i; + croak "Unsupported transaction type: $content{type}" + if $content{type} && + ! grep lc($content{type}) eq lc($_), + values %{+CARD_TYPES}; croak 'Unsupported action' unless $content{action} =~ /^Normal Authori[zs]ation$/i; @@ -146,8 +160,6 @@ sub to_xml { croak "Unknown currency code ", $content{currency} unless $content{currency} =~ /^(CAD|USD)$/; - $content{taxes} = uc($content{taxes} || ''); - my %data = $self->get_remap_fields(qw( xxxCard_Number card_number @@ -177,7 +189,7 @@ sub to_xml { $data{xxxCard_Number} =~ tr/- //d; $data{xxxCard_Number} =~ s/^[^3-6]/4/ if $self->test_transaction; - my ($y, $m) = $self->parse_expdate($content{exp_date}); + my ($y, $m) = $self->parse_expdate($content{expiration}); $data{xxxCCYear} = sprintf '%.4u' => $y; $data{xxxCCMonth} = sprintf '%.2u' => $m; @@ -205,13 +217,14 @@ sub to_xml { ); } - xml_out(\%data, + # The encode() makes sure to a) strip off non-Latin-1 characters, and + # b) turn off the utf8 flag, which confuses XML::Simple + encode('ISO-8859-1', xml_out(\%data, NoAttr => 1, - NumericEscape => 2, RootName => 'TranxRequest', SuppressEmpty => undef, XMLDecl => '', - ); + )); } # Map the various fields from the response, and put their values into our @@ -226,10 +239,10 @@ sub infuse { } } -sub extract_taxes { +sub extract_tax_amounts { my ($self, $response) = @_; - my %taxes; + my %tax_amounts; my $products = $response->{Products}; return unless $products; @@ -240,11 +253,11 @@ sub extract_taxes { grep($_ eq '{TAX}', @$flags) && grep($_ eq '{CALCULATED}', @$flags)) { - $taxes{ $node->{code} } = $node->{subtotal}; + $tax_amounts{ $node->{code} } = $node->{subtotal}; } } - return %taxes; + return %tax_amounts; } # Parse the server's response and set various fields @@ -267,11 +280,11 @@ sub parse_response { result_code => 'Page', error_message => 'Verbiage', authorization => 'ApprovalCode', - avs_response => 'AVSResponseCode', + avs_code => 'AVSResponseCode', cvv2_response => 'CVV2ResponseCode', receipt_number => 'ReceiptNumber', - sales_number => 'SalesOrderNumber', + order_number => 'SalesOrderNumber', uuid => 'GUID', guid => 'GUID', @@ -291,7 +304,7 @@ sub parse_response { $self->card_type(CARD_TYPES->{$self->card_type}); - $self->taxes( { $self->extract_taxes($response) } ); + $self->tax_amounts( { $self->extract_tax_amounts($response) } ); return $self; } @@ -345,7 +358,7 @@ Business::OnlinePayment::InternetSecure - InternetSecure backend for Business::O type => 'Visa', # Optional card_number => '4111 1111 1111 1111', - exp_date => '2004-07', + expiration => '2004-07', cvv2 => '000', # Optional name => "Fr\x{e9}d\x{e9}ric Bri\x{e8}re", @@ -419,6 +432,8 @@ Transaction type, being one of the following: =item - Discover +=item - JCB + =back (This is actually ignored for the moment, and can be left blank or undefined.) @@ -427,7 +442,7 @@ Transaction type, being one of the following: Credit card number. Spaces and dashes are automatically removed. -=item exp_date (required) +=item expiration (required) Credit card expiration date. Since C does not specify any syntax, this module is rather lax regarding what it will accept. The @@ -465,10 +480,12 @@ C (default) or C. =item taxes -Taxes to be added automatically to B by InternetSecure. +Taxes to be added automatically to B by InternetSecure. Available +taxes are C, C and C. -Available taxes are C, C and C. Multiple taxes can specified -by concatenating them with spaces, such as C. +This argument can either be a single string of taxes concatenated with spaces +(such as C), or a reference to an array of taxes (such as C<[ "GST", +"PST" ]>). =item name / company / address / city / state / zip / country / phone / email @@ -506,7 +523,7 @@ B() instead.) Receipt number (a string, actually) of this transaction, unique to all InternetSecure transactions. -=item sales_number() +=item order_number() Sales order number of this transaction. This is a number, unique to each merchant, which is incremented by 1 each time. @@ -524,7 +541,7 @@ B() is provided as an alias to this method. Authorization code for this transaction. -=item avs_response() / cvv2_response() +=item avs_code() / cvv2_response() Results of the AVS and CVV2 checks. See the InternetSecure documentation for the list of possible values. @@ -537,10 +554,11 @@ Date and time of the transaction. Format is C. Total amount billed for this order, including taxes. -=item taxes() +=item tax_amounts() -Returns a I to a hash that maps tax names (such as C) to the -amount that was billed for each. +Returns a I to a hash that maps taxes, which were listed under the +B argument to B(), to the amount that was calculated by +InternetSecure. =item cardholder() @@ -562,6 +580,8 @@ following: =item - Discover +=item - JCB + =back @@ -579,7 +599,7 @@ the following fields: =over 4 -=item amount +=item amount (required) Unit price of this product. @@ -608,15 +628,13 @@ be left undefined. =head2 Character encoding -Since communication to/from InternetSecure is encoded with UTF-8, all Unicode -characters are theoretically available when submitting information via -B(). (Further restrictions may be imposed by InternetSecure itself.) +When using non-ASCII characters, all data provided to B() should +have been decoded beforehand via the C module, unless your data is in +ISO-8859-1 and you haven't meddled with the C pragma. (Please +don't.) -When using non-ASCII characters, all data provided to B() should either -be in the current native encoding (typically latin-1, unless it was modified -via the C pragma), or be decoded via the C module. -Conversely, all data returned after calling B() will be automatically -decoded. +InternetSecure currently does not handle characters outside of ISO-8859-1, so +these will be replaced with C before being transmitted. =head1 EXPORT