2321d0927df0d4fe97c5c1eb5263f38af44fd7f1
[Business-OnlineThirdPartyPayment-FCMB.git] / FCMB.pm
1 package Business::OnlineThirdPartyPayment::FCMB;
2
3 use strict;
4 use base 'Business::OnlineThirdPartyPayment';
5
6 use strict;
7 use LWP;
8 use URI;
9 use Data::Dumper;
10 use Date::Format 'time2str';
11 use XML::LibXML;
12
13 our $VERSION = '0.01';
14 our $ENDPOINT_SANDBOX = 'localhost';
15 our $ENDPOINT_LIVE    = 'fcmbwebpay.firstcitygrouponline.com';
16
17 our $DEBUG = 3;
18
19 # ISO 4217 currency codes (the relevant ones)
20 our %ALPHA_TO_NUM = (
21   USD => 840,
22   UKP => 826,
23   NGN => 566,
24 );
25
26 sub set_defaults {
27   my $self = shift;
28   my %args = @_;
29   $self->build_subs(qw(username password host));
30   if ( $args{debug} ) {
31     $DEBUG = $args{debug};
32   }
33 }
34
35 sub create {
36   my $self = shift;
37   my %content = @_;
38
39   my %params;
40   $params{'orderId'}  = time2str('%Y%m%d%H%M%S', time) . '-' .
41                        sprintf('%06d', int(rand(1000000)));
42   $params{'mercId'}   = $self->username
43     or die "FCMB merchant ID (username) must be configured\n";
44   $params{'currCode'} = $ALPHA_TO_NUM{$content{currency}};
45   $params{'prod'}     = $content{'description'};
46   $params{'email'}    = $content{'email'};
47   $params{'amt'}      = $content{'amount'};
48
49   my $host = $self->host;
50   if ( $self->test_transaction ) {
51     $host ||= $ENDPOINT_SANDBOX;
52   } else {
53     $host ||= $ENDPOINT_LIVE;
54   }
55   my $url = 'https://' . $host .
56     '/customerportal/MerchantServices/MakePayment.aspx';
57
58   warn Dumper \%params if $DEBUG > 2;
59
60   # we don't post to the url ourselves, just give it to the user
61   $self->is_success(1);
62   $self->redirect($url);
63   $self->post_params(\%params);
64
65   $self->token( $params{'orderId'} );
66 }
67
68 sub execute {
69   my $self = shift;
70   my %params = @_;
71
72 # URL looks like
73 # http://merchantA.com/Success?OrderID=988676&TransactionReference=8765678998989779
74   warn Dumper(\%params) if $DEBUG > 2;
75  
76   if ($params{'OrderID'}) {
77     $self->token($params{'OrderID'});
78   } else {
79     die 'No order ID returned from processor';
80   }
81   if ($params{'TransactionReference'}) {
82     $self->order_number($params{'TransactionReference'});
83   } else {
84     die 'No transaction reference returned from processor';
85   }
86
87   my $host = $self->host;
88   if ( $self->test_transaction ) {
89     $host ||= $ENDPOINT_SANDBOX;
90     $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;
91   } else {
92     $host ||= $ENDPOINT_LIVE;
93   }
94   my $url = 'https://' . $host .
95     '/customerportal/MerchantServices/UpayTransactionStatus.ashx';
96   my $ua = LWP::UserAgent->new;
97   warn "Querying transaction status at $url\n" if $DEBUG;
98   my $response = $ua->get($url,
99     'MERCHANT_ID'  => $self->username,
100     'ORDER_ID'     => $self->token
101   );
102
103   if ( $response->is_success ) {
104
105     local $@;
106     my $parser = XML::LibXML->new;
107     my $doc = eval { $parser->parse_string($response->content) };
108     if ( $@ ) {
109       die "malformed response to transaction status request: $@\n".
110           ($DEBUG ? ("\n\n".$response->content) : '');
111     }
112     my $root = $doc->documentElement;
113     my %hash = map { $_->nodeName => $_->textContent }
114                $root->nonBlankChildNodes;
115
116     warn Dumper \%hash if $DEBUG > 2;
117     if ( $hash{StatusCode} == 0 ) {
118       $self->is_success(1);
119       $self->authorization($hash{PaymentRef});
120     } else {
121       $self->is_success(0);
122       $self->error_message($hash{Status} . ' - ' . $hash{ResponseDescription});
123     }
124   } else {
125     die "No confirmation received: ".$response->status_line;
126   }
127 }
128
129 1;
130 __END__
131
132 =head1 NAME
133
134 Business::OnlineThirdPartyPayment::FCMB
135
136 =head1 DESCRIPTION
137
138 Business::OnlineThirdPartyPayment interface to the First City Monument Bank
139 (Nigeria) web-based payment processing system.
140
141 =head1 NOTES
142
143 =over 4
144
145 =item FCMB requires the callback URL to be configured statically;
146 I<return_url> and I<cancel_url> parameters will be ignored.
147
148 =item Set I<username> to your merchant ID (5 digits).  No password is needed.
149
150 =item The only required transaction fields are currency (NGN, USD, or UKP),
151 amount, description, and email.
152
153 =item The 'faker' directory contains a simple mock-up of the FCMB interface
154 for testing.  This was created from the documentation, without reference
155 to the real FCMB system, and is NOT known to be accurate.
156
157 =back
158
159 =head1 AUTHOR
160
161 Mark Wells <mark@freeside.biz>
162
163 =head1 SEE ALSO
164
165 perl(1). L<Business::OnlineThirdPartyPayment>.
166
167 =cut
168