1 package Business::OnlinePayment::eSelectPlus;
6 use Business::OnlinePayment 3;
7 use Business::OnlinePayment::HTTPS 0.03;
8 use vars qw($VERSION $DEBUG @ISA);
10 @ISA = qw(Business::OnlinePayment::HTTPS);
17 #$self->server('esqa.moneris.com'); # development
18 $self->server('www3.moneris.com'); # production
20 $self->path('/gateway2/servlet/MpgRequest');
22 $self->build_subs(qw( order_number avs_code ));
23 # avs_code order_type md5 cvv2_response cavv_response
29 if ($self->test_transaction) {
30 $self->server('esqa.moneris.com');
31 $self->{_content}{'login'} = 'store2'; # store[123]
32 $self->{_content}{'password'} = 'yesguy';
35 # BOP field => eSelectPlus field
39 # => 'transaction_type',
41 #password => 'api_token',
61 invoice_number => 'cust_id',
62 #customer_id => 'cust_id',
63 order_number => 'order_id', # must be unique number
64 authorization => 'txn_number' # reference to previous trans
69 my $action = $self->{_content}{'action'};
70 if ( $self->{_content}{'action'} =~ /^\s*normal\s*authorization\s*$/i ) {
72 } elsif ( $self->{_content}{'action'} =~ /^\s*authorization\s*only\s*$/i ) {
74 } elsif ( $self->{_content}{'action'} =~ /^\s*post\s*authorization\s*$/i ) {
75 $action = 'completion';
76 } elsif ( $self->{_content}{'action'} =~ /^\s*void\s*$/i ) {
78 } elsif ( $self->{_content}{'action'} =~ /^\s*credit\s*$/i ) {
79 if ( $self->{_content}{'authorization'} ) {
82 $action = 'ind_refund';
86 if ( $action =~ /^(purchase|preauth|ind_refund)$/ ) {
88 $self->required_fields(
89 qw( login password amount card_number expiration )
92 #cardexpiremonth & cardexpireyear
93 $self->{_content}{'expiration'} =~ /^(\d+)\D+\d*(\d{2})$/
94 or croak "unparsable expiration ". $self->{_content}{expiration};
95 my( $month, $year ) = ( $1, $2 );
96 $month = '0'. $month if $month =~ /^\d$/;
97 $self->{_content}{expdate} = $year.$month;
99 $self->generate_order_id;
101 $self->{_content}{amount} = sprintf('%.2f', $self->{_content}{amount} );
103 } elsif ( $action eq 'completion' || $action eq 'void' ) {
105 $self->required_fields( qw( login password order_number authorization ) );
107 } elsif ( $action eq 'refund' ) {
109 $self->required_fields(
110 qw( login password order_number authorization )
115 # E-Commerce Indicator (see eSelectPlus docs)
116 $self->{_content}{'crypt_type'} ||= 7;
118 #no, values aren't escaped for XML. their "mpgClasses.pl" example doesn't
119 #appear to do so, i dunno
120 tie my %fields, 'Tie::IxHash', $self->get_fields( $self->fields );
122 '<?xml version="1.0"?>'.
124 '<store_id>'. $self->{_content}{'login'}. '</store_id>'.
125 '<api_token>'. $self->{_content}{'password'}. '</api_token>'.
127 join('', map "<$_>$fields{$_}</$_>", keys %fields ).
131 warn "POSTING: ".$post_data if $DEBUG > 1;
133 my( $page, $response, @reply_headers) = $self->https_post( $post_data );
135 #my %reply_headers = @reply_headers;
136 #warn join('', map { " $_ => $reply_headers{$_}\n" } keys %reply_headers )
139 if ($response !~ /^200/) {
141 $response =~ s/[\r\n]+/ /g; # ensure single line
142 $self->is_success(0);
143 my $diag_message = $response || "connection error";
148 # avs_code - eSELECTplus_Perl_IG.pdf Appendix F
149 my %avsTable = ('A' => 'A',
166 my $AvsResultCode = $self->GetXMLProp($page, 'AvsResultCode');
167 $self->avs_code( defined($AvsResultCode) && exists $avsTable{$AvsResultCode}
168 ? $avsTable{$AvsResultCode}
172 #md5 cvv2_response cavv_response ...?
174 $self->server_response($page);
176 my $result = $self->GetXMLProp($page, 'ResponseCode');
178 die "gateway error: ". $self->GetXMLProp( $page, 'Message' )
179 if $result =~ /^null$/i;
181 # New unique reference created by the gateway
182 $self->order_number($self->GetXMLProp($page, 'ReferenceNum'));
183 # Original order_id supplied to the gateway
184 #$self->order_number($self->GetXMLProp($page, 'ReceiptId'));
186 # We (Whizman & DonorWare) do not have enough info about "ISO"
187 # response codes to make use of them.
188 # There may be good reasons why the ISO codes could be preferable,
189 # but we would need more information. For now, the ResponseCode.
190 # $self->result_code( $self->GetXMLProp( $page, 'ISO' ) );
191 $self->result_code( $result );
193 if ( $result =~ /^\d+$/ && $result < 50 ) {
194 $self->is_success(1);
195 $self->authorization($self->GetXMLProp($page, 'AuthCode'));
196 } elsif ( $result =~ /^\d+$/ ) {
197 $self->is_success(0);
198 my $tmp_msg = $self->GetXMLProp( $page, 'Message' );
199 $tmp_msg =~ s/\s{2,}//g;
200 $tmp_msg =~ s/[\*\=]//g;
201 $self->error_message( $tmp_msg );
203 die "unparsable response received from gateway (response $result)".
204 ( $DEBUG ? ": $page" : '' );
209 use vars qw(@oidset);
210 @oidset = ( 'A'..'Z', '0'..'9' );
211 sub generate_order_id {
213 #generate an order_id if order_number not passed
214 unless ( exists ($self->{_content}{order_id})
215 && defined($self->{_content}{order_id})
216 && length ($self->{_content}{order_id})
218 $self->{_content}{'order_id'} =
219 join('', map { $oidset[int(rand(scalar(@oidset)))] } (1..23) );
226 #order is important to this processor
241 my( $self, $raw, $prop ) = @_;
245 ($data) = $raw =~ m"<$prop>(.*?)</$prop>"gsi;
246 #$data =~ s/<.*?>/ /gs;
257 Business::OnlinePayment::eSelectPlus - Moneris eSelect Plus backend module for Business::OnlinePayment
261 use Business::OnlinePayment;
264 # One step transaction, the simple case.
267 my $tx = new Business::OnlinePayment("eSelectPlus");
270 login => 'eSelect Store ID,
271 password => 'eSelect API Token',
272 action => 'Normal Authorization',
273 description => 'Business::OnlinePayment test',
275 name => 'Tofu Beast',
276 address => '123 Anystreet',
280 phone => '420-867-5309',
281 email => 'tofu.beast@example.com',
282 card_number => '4005550000000019',
283 expiration => '08/06',
284 cvv2 => '1234', #optional
288 if($tx->is_success()) {
289 print "Card processed successfully: ".$tx->authorization."\n";
291 print "Card was rejected: ".$tx->error_message."\n";
293 print "AVS code: ". $tx->avs_code. "\n"; # Y - Address and ZIP match
294 # A - Address matches but not ZIP
295 # Z - ZIP matches but not address
297 # E - AVS error or unsupported
298 # R - Retry (timeout)
299 # (empty) - not verified
301 =head1 SUPPORTED TRANSACTION TYPES
303 =head2 CC, Visa, MasterCard, American Express, Discover
305 Content required: type, login, password, action, amount, card_number, expiration.
312 Net::SSLeay _or_ ( Crypt::SSLeay and LWP )
316 For detailed information see L<Business::OnlinePayment>.
322 Ivan Kohler <ivan-eselectplus@420.am>
323 Randall Whitman <www.whizman.com>
327 perl(1). L<Business::OnlinePayment>.