fix URL in execute method; update deps
[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 = URI->new('https://' . $host .
95     '/customerportal/MerchantServices/UpayTransactionStatus.ashx');
96   $url->query_form('MERCHANT_ID'  => $self->username,
97                    'ORDER_ID'     => $self->token);
98   my $ua = LWP::UserAgent->new;
99   warn "Querying transaction status at $url\n" if $DEBUG;
100   my $response = $ua->get($url);
101
102   if ( $response->is_success ) {
103
104     local $@;
105     my $parser = XML::LibXML->new;
106     my $doc = eval { $parser->parse_string($response->content) };
107     if ( $@ ) {
108       die "malformed response to transaction status request: $@\n".
109           ($DEBUG ? ("\n\n".$response->content) : '');
110     }
111     my $root = $doc->documentElement;
112     my %hash = map { $_->nodeName => $_->textContent }
113                $root->nonBlankChildNodes;
114
115     warn Dumper \%hash if $DEBUG > 2;
116     if ( $hash{StatusCode} == 0 ) {
117       $self->is_success(1);
118       $self->authorization($hash{PaymentRef});
119     } else {
120       $self->is_success(0);
121       $self->error_message($hash{Status} . ' - ' . $hash{ResponseDescription});
122     }
123   } else {
124     die "No confirmation received: ".$response->status_line;
125   }
126 }
127
128 1;
129 __END__
130
131 =head1 NAME
132
133 Business::OnlineThirdPartyPayment::FCMB
134
135 =head1 DESCRIPTION
136
137 Business::OnlineThirdPartyPayment interface to the First City Monument Bank
138 (Nigeria) web-based payment processing system.
139
140 =head1 NOTES
141
142 =over 4
143
144 =item FCMB requires the callback URL to be configured statically;
145 I<return_url> and I<cancel_url> parameters will be ignored.
146
147 =item Set I<username> to your merchant ID (5 digits).  No password is needed.
148
149 =item The only required transaction fields are currency (NGN, USD, or UKP),
150 amount, description, and email.
151
152 =item The 'faker' directory contains a simple mock-up of the FCMB interface
153 for testing.  This was created from the documentation, without reference
154 to the real FCMB system, and is NOT known to be accurate.
155
156 =back
157
158 =head1 AUTHOR
159
160 Mark Wells <mark@freeside.biz>
161
162 =head1 SEE ALSO
163
164 perl(1). L<Business::OnlineThirdPartyPayment>.
165
166 =cut
167