use strict;
use Carp;
-use Template;
+use XML::Writer;
use XML::Simple;
use Data::Dumper;
$VERSION = '0.01';
$me = 'Business::OnlinePayment::vSecureProcessing';
-
-# $server: http://dvrotsos2.kattare.com
-
# mapping out all possible endpoints
# but this version will only be building out "charge", "void", & "credit"
my %payment_actions = (
'charge' => {
path => '/vsg2/processpayment',
+ process => 'ProcessPayment',
+ fields => [qw/ Amount Trk1 Trk2 TypeOfSale Cf1 Cf2 Cf AccountNumber ExpirationMonth ExpirationYear Cvv CardHolderFirstName CardHolderLastName AvsZip AvsStreet IndustryType ApplicationId Recurring /]
},
'void' => {
path => '/vsg2/processvoid',
+ process => 'ProcessVoid',
+ fields => [qw( Amount AccountNumber ExpirationMonth ExpirationYear ReferenceNumber TransactionDate IndustryType ApplicationId )]
},
'refund' => {
path => '/vsg2/processrefund',
+ process => 'ProcessRefund',
+ fields => [qw( Amount AccountNumber ExpirationMonth ExpirationYear ApplicationId )]
},
'authorize' => {
path => '/vsg2/processauth',
croak "'$action' is not supported at this time.";
}
- # fill out the template vars
- my $template_vars = {
-
+ # fill in the xml vars
+ my $xml_vars = {
auth => {
- platform => $self->platform,
- userid => $self->userid,
- gid => $self->gid,
- tid => $self->tid
+ Platform => $self->platform,
+ UserId => $self->userid,
+ GID => $self->gid,
+ Tid => $self->tid
},
payment => {
- amount => $content{'amount'},
- track1 => ($content{'track1'}) ? $content{'track1'} : '',
- track2 => ($content{'track2'}) ? $content{'track2'} : '',
- type => ($content{'description'}) ? $content{'description'} : '',
- cf1 => ($content{'UDField1'}) ? $content{'UDField1'} : '',
- cf2 => ($content{'UDField2'}) ? $content{'UDField2'} : '',
- cf3 => '',
- account_number => ($content{'card_number'}) ? $content{'card_number'} : '',
- exp_month => $content{'exp_month'},
- exp_year => $content{'exp_year'},
- cvv => ($content{'cvv'}) ? $content{'cvv'} : ($content{'cvv2'}) ? $content{'cvv2'} : '',
- first_name => ($content{'first_name'}) ? $content{'first_name'} : '',
- last_name => ($content{'last_name'}) ? $content{'last_name'} : '',
- postal_code => ($content{'zip'}) ? $content{'zip'} : '',
- street_address => ($content{'street_number'}) ? $content{'street_number'} : '',
- industry_type => ($content{'IndustryInfo'} && lc($content{'IndustryInfo'}) eq 'ecommerce') ? 'ecom_3' : '',
- invoice_num => ($content{'invoice_number'}) ? $content{'invoice_number'} : '',
- appid => $self->appid(),
- recurring => ($content{'recurring_billing'} && $content{'recurring_billing'} eq 'YES' ) ? 1 : 0,
- response_code => ($content{'response_code'}) ? $content{'response_code'} : '',
- reference_number=> ($content{'ref_num'}) ? $content{'ref_num'} : '',
- token => ($content{'token'}) ? $content{'token'} : '',
- receipt => ($content{'receipt'}) ? $content{'receipt'} : '',
- transaction_date=> ($content{'txn_date'}) ? $content{'txn_date'} : '',
- merchant_data => ($content{'merchant_data'}) ? $content{'merchant_data'} : '',
- },
-
- # we won't be using level2 nor level3. So I'm leaving them blank for now.
- level2 => {
- card_type => '',
- purchase_code => '',
- country_code => '',
- ship_tp_postal_code => '',
- ship_from_postal_code => '',
- sales_tax => '',
- product_description1 => '',
- product_description2 => '',
- product_description3 => '',
- product_description4 => ''
- },
-
- level3 => {
- purchase_order_num => '',
- order_date => '',
- duty_amount => '',
- alt_tax_amount => '',
- discount_amount => '',
- freight_amount => '',
- tax_exempt => '',
- line_item_count => '',
- purchase_items => $self->_parse_line_items()
+ Amount => $content{'amount'},
+ Trk1 => ($content{'track1'}) ? $content{'track1'} : '',
+ Trk2 => ($content{'track2'}) ? $content{'track2'} : '',
+ TypeOfSale => ($content{'description'}) ? $content{'description'} : '',
+ Cf1 => ($content{'UDField1'}) ? $content{'UDField1'} : '',
+ Cf2 => ($content{'UDField2'}) ? $content{'UDField2'} : '',
+ Cf3 => '',
+ AccountNumber => ($content{'card_number'}) ? $content{'card_number'} : '',
+ ExpirationMonth => $content{'exp_month'},
+ ExpirationYear => $content{'exp_year'},
+ Cvv => ($content{'cvv'}) ? $content{'cvv'} : ($content{'cvv2'}) ? $content{'cvv2'} : '',
+ CardHolderFirstName => ($content{'first_name'}) ? $content{'first_name'} : '',
+ CardHolderLastName => ($content{'last_name'}) ? $content{'last_name'} : '',
+ AvsZip => ($content{'zip'}) ? $content{'zip'} : '',
+ AvsStreet => ($content{'street_number'}) ? $content{'street_number'} : '',
+ IndustryType => {
+ IndType => ($content{'IndustryInfo'} && lc($content{'IndustryInfo'}) eq 'ecommerce') ? 'ecom_3' : '',
+ IndInvoice => ($content{'invoice_number'}) ? $content{'invoice_number'} : ''
+ },
+ ApplicationId => $self->appid(),
+ Recurring => ($content{'recurring_billing'} && $content{'recurring_billing'} eq 'YES' ) ? 1 : 0,
+ ReferenceNumber => ($content{'ref_num'}) ? $content{'ref_num'} : '',
+ Token => ($content{'token'}) ? $content{'token'} : '',
+ Receipt => ($content{'receipt'}) ? $content{'receipt'} : '',
+ TransactionDate => ($content{'txn_date'}) ? $content{'txn_date'} : ''
}
+ # we won't be using level2 nor level3. So I'm leaving them out for now.
};
-
# create the list of required fields based on the action
- my @required_fields = qw/ amount /;
+ my @required_fields = qw/ Amount /;
if ($action eq 'charge') {
- push(@required_fields, $_) foreach (qw/ account_number cvv exp_month exp_year /);
+ push(@required_fields, $_) foreach (qw/ AccountNumber Cvv ExpirationMonth ExpirationYear /);
}elsif ($action eq 'void') {
- push(@required_fields, $_) foreach (qw/ reference_number transaction_date /);
+ push(@required_fields, $_) foreach (qw/ ReferenceNumber TransactionDate /);
}elsif ($action eq 'refund') {
- push(@required_fields, $_) foreach (qw/ amount account_number exp_month exp_year /);
+ push(@required_fields, $_) foreach (qw/ Amount AccountNumber ExpirationMonth ExpirationYear /);
}
# check the requirements are met.
my @missing_fields;
foreach my $field (@required_fields) {
- push(@missing_fields, $field) if (!$template_vars->{payment}{$field});
+ push(@missing_fields, $field) if (!$xml_vars->{payment}{$field});
}
if (scalar(@missing_fields)) {
croak "Missing required fields: ".join(', ', @missing_fields);
}
- # read in the appropriate xml template
- my $xml_template = _get_xml_template( $action );
- # create a template object.
- my $tt = Template->new();
- # populate the XML template.
+ my $process_action = $action;
+ $process_action =~ s/\b([a-z])/\u$1/g;
+ $process_action = 'Process'.$process_action;
my $xml_data;
- $tt->process( \$xml_template, $template_vars, \$xml_data ) || croak $tt->error();
+ my $writer = new XML::Writer( OUTPUT => \$xml_data,
+ DATA_MODE => 0,
+ DATA_INDENT => 0,
+ ENCODING => 'utf-8',
+ );
+ $writer->xmlDecl();
+ $writer->startTag('Request');
+ $writer->startTag('MerchantData');
+ foreach my $key ( keys ( %{$xml_vars->{auth}} ) ) {
+ $writer->dataElement( $key, $xml_vars->{auth}{$key} );
+ }
+ $writer->endTag('MerchantData');
+ $writer->startTag($payment_actions{ $self->action }{process});
+ foreach my $key ( @{$payment_actions{ $self->action }{fields}} ) {
+ next if (!$xml_vars->{payment}{$key});
+ if (ref $xml_vars->{payment}{$key} eq '') {
+ $writer->dataElement( $key, $xml_vars->{payment}{$key});
+ }else {
+ $writer->startTag($key);
+ foreach my $key2 (keys %{$xml_vars->{payment}{$key}}) {
+ $writer->dataElement( $key2, $xml_vars->{payment}{$key}{$key2} );
+ }
+ $writer->endTag($key);
+ }
+ }
+ $writer->endTag($payment_actions{ $self->action }{process});
+ $writer->endTag('Request');
+ $writer->end();
warn "XML:\n$xml_data\n" if $DEBUG > 2;
return;
}
-
-}
-
-sub _get_xml_template {
- my $action = shift;
-
- my $xml_template = q|<Request >
- <MerchantData>
- <Platform>[% auth.platform %]</Platform>
- <UserId>[% auth.userid %]</UserId>
- <GID>[% auth.gid %]</GID>
- <Tid>[% auth.tid %]</Tid>
- </MerchantData>
- |;
-
- if ($action eq 'charge') {
- $xml_template .= _get_xml_template_charge();
- }elsif($action eq 'void') {
- $xml_template .= _get_xml_template_void();
- }elsif($action eq 'authorize') {
- $xml_template .= _get_xml_template_auth();
- }elsif($action eq 'authorize_cancel') {
- $xml_template .= _get_xml_template_auth_cancel();
- }elsif($action eq 'refund') {
- $xml_template .= _get_xml_template_refund();
- }elsif($action eq 'capture') {
- $xml_template .= _get_xml_template_capture();
- }elsif($action eq 'create_token') {
- $xml_template .= _get_xml_template_create_token();
- }elsif($action eq 'delete_token') {
- $xml_template .= _get_xml_template_delete_token();
- }elsif($action eq 'query_token') {
- $xml_template .= _get_xml_template_query_token();
- }elsif($action eq 'update_exp_date') {
- $xml_template .= _get_xml_template_update_exp_date();
- }elsif($action eq 'update_token') {
- $xml_template .= _get_xml_template_update_token();
- }
-
- $xml_template .= "</Request>";
- $xml_template =~ s/[\n\t\s]*//g;
-
- return $xml_template;
-}
-
-sub _get_xml_template_charge {
- my $xml_template = q|<ProcessPayment>
- <Amount>[% payment.amount %]</Amount>
- <Trk1>[% payment.track1 %]</Trk1>
- <Trk2>[% payment.track2 %]</Trk2>
- <TypeOfSale>[% payment.type %]</TypeOfSale>
- <Cf1>[% payment.cf1 %]</Cf1>
- <Cf2>[% payment.cf2 %]</Cf2>
- <Cf3>[% payment.cf3 %]</Cf3>
- <AccountNumber>[% payment.account_number %]</AccountNumber>
- <ExpirationMonth>[% payment.exp_month %]</ExpirationMonth>
- <ExpirationYear>[% payment.exp_year %]</ExpirationYear>
- <Cvv>[% payment.cvv %]</Cvv>
- <CardHolderFirstName>[% payment.first_name %]</CardHolderFirstName>
- <CardHolderLastName>[% payment.last_name %]</CardHolderLastName>
- <AvsZip>[% payment.postal_code %]</AvsZip>
- <AvsStreet>[% payment.street_address %]</AvsStreet>
- <IndustryType>
- <IndType >[% payment.industry_type %]</IndType >
- <IndInvoice>[% payment.invoice_num %]</IndInvoice>
- </IndustryType>
- <ApplicationId>[% payment.appid %]</ApplicationId>
- <Recurring>[% payment.recurring %]</Recurring>
- </ProcessPayment>|;
-
- # other options (that we are not using right now):
-# <Level2PurchaseInfo>
-# <Level2CardType>[% level2.card_type %]</Level2CardType >
-# <PurchaseCode>[% level2.purchase_code %]</PurchaseCode>
-# <ShipToCountryCode>[% level2.country_code %]</ShipToCountryCode>
-# <ShipToPostalCode>[% level2.ship_tp_postal_code %]</ShipToPostalCode>
-# <ShipFromPostalCode>[% level2.ship_from_postal_code %]</ShipFromPostalCode>
-# <SalesTax>[% level2.sales_tax %]</SalesTax>
-# <ProductDescription1>[% level2.product_description1 %]</ProductDescription1>
-# <ProductDescription2>[% level2.product_description2 %]</ProductDescription2>
-# <ProductDescription3>[% level2.product_description3 %]</ProductDescription3>
-# <ProductDescription4>[% level2.product_description4 %]</ProductDescription4>
-# </Level2PurchaseInfo>
-# <Level3PurchaseInfo>
-# <PurchaseOrderNumber>[% level3.purchase_order_num %]</PurchaseOrderNumber>
-# <OrderDate>[% level3.order_date %]</OrderDate>
-# <DutyAmount>[% level3.duty_amount %]</DutyAmount>
-# <AlternateTaxAmount>[% level3.alt_tax_amount %]</AlternateTaxAmount>
-# <DiscountAmount>[% level3.discount_amount %]</DiscountAmount>
-# <FreightAmount>[% level3.freight_amount %]</FreightAmount>
-# <TaxExemptFlag>[% level3.tax_exempt %]</TaxExemptFlag>
-# <LineItemCount>[% level3.line_item_count %]</LineItemCount>
-# <PurchaseItems>
-# [% level3.purchase_items %]
-# </PurchaseItems>
-# </Level3PurchaseInfo>
-
- return $xml_template;
-}
-
-sub _parse_line_items {
- my $self = shift;
- my %content = $self->content();
-
- return '' if (!$content{'items'});
-
- my @line_items;
- my $template = q| <LineItem>
- <ItemSequenceNumber>[% seq_num %]</ItemSequenceNumber>
- <ItemCode>[% code %]</ItemCode>
- <ItemDescription>[% desc %]</ItemDescription>
- <ItemQuantity>[% qty %]</ItemQuantity>
- <ItemUnitOfMeasure>[% unit %]</ItemUnitOfMeasure>
- <ItemUnitCost>[% unit_cost %]</ItemUnitCost>
- <ItemAmount>[% amount %]</ItemAmount>
- <ItemDiscountAmount>[% discount_amount %]</ItemDiscountAmount>
- <ItemTaxAmount>[% tax_amount %]</ItemTaxAmount>
- <ItemTaxRate>[% tax_rate %]</ItemTaxRate>
- </LineItem>|;
-
-
- my @items = $content{'items'};
- foreach my $item (@items) {
- # fille in the slots from $template with details in $item
- # push to @line_items
- }
-
- return join("\n", @line_items);
-}
-
-sub _get_xml_template_void {
- my $xml_template = q|<ProcessVoid>
- <Amount>[% payment.amount %]</Amount>
- <AccountNumber>[% payment.account_number %]</AccountNumber>
- <ExpirationMonth>[% payment.exp_month %]</ExpirationMonth>
- <ExpirationYear>[% payment.exp_year %]</ExpirationYear>
- <ReferenceNumber>[% payment.reference_number %]</ReferenceNumber>
- <TransactionDate/>
- <IndustryType1>[% payment.industry_type %]</IndustryType1>
- <ApplicationId>[% payment.appid %]</ApplicationId>
- </ProcessVoid>|;
-
- return $xml_template;
-}
-
-sub _get_xml_template_refund {
- my $xml_template = q|<ProcessRefund>
- <Amount>[% payment.amount %]</Amount>
- <AccountNumber>[% payment.account_number %]</AccountNumber>
- <ExpirationMonth>[% payment.exp_month %]</ExpirationMonth>
- <ExpirationYear>[% payment.exp_year %]</ExpirationYear>
- <ApplicationId>[% payment.appid %]</ApplicationId>
- </ProcessRefund>|;
-
- return $xml_template;
-}
-
-sub _get_xml_template_auth {
- my $xml_template = '';
-
- return $xml_template;
-}
-
-sub _get_xml_template_auth_cancel {
- my $xml_template = '';
-
- return $xml_template;
-}
-
-sub _get_xml_template_capture {
- my $xml_template = '';
-
- return $xml_template;
}
-sub _get_xml_template_create_token {
- my $xml_template = '';
-
- return $xml_template;
-}
-
-sub _get_xml_template_delete_token {
- my $xml_template = '';
-
- return $xml_template;
-}
-
-sub _get_xml_template_query_token {
- my $xml_template = '';
-
- return $xml_template;
-}
-
-sub _get_xml_template_update_exp_date {
- my $xml_template = '';
-
- return $xml_template;
-}
-
-sub _get_xml_template_update_token {
- my $xml_template = '';
-
- return $xml_template;
-}
-
-
1;
__END__