+package Business::OnlineThirdPartyPayment::FCMB;
+
+use strict;
+use base 'Business::OnlineThirdPartyPayment';
+
+use strict;
+use LWP;
+use URI;
+use Data::Dumper;
+use Date::Format 'time2str';
+use XML::LibXML;
+
+our $VERSION = '0.01';
+our $ENDPOINT_SANDBOX = 'localhost';
+our $ENDPOINT_LIVE = 'fcmbwebpay.firstcitygrouponline.com';
+
+our $DEBUG = 3;
+
+# ISO 4217 currency codes (the relevant ones)
+our %ALPHA_TO_NUM = (
+ USD => 840,
+ UKP => 826,
+ NGN => 566,
+);
+
+sub set_defaults {
+ my $self = shift;
+ my %args = @_;
+ $self->build_subs(qw(username password host));
+ if ( $args{debug} ) {
+ $DEBUG = $args{debug};
+ }
+}
+
+sub create {
+ my $self = shift;
+ my %content = @_;
+
+ my %params;
+ $params{'orderId'} = time2str('%Y%m%d%H%M%S', time) . '-' .
+ sprintf('%06d', int(rand(1000000)));
+ $params{'mercId'} = $self->username
+ or die "FCMB merchant ID (username) must be configured\n";
+ $params{'currCode'} = $ALPHA_TO_NUM{$content{currency}};
+ $params{'prod'} = $content{'description'};
+ $params{'email'} = $content{'email'};
+ $params{'amt'} = $content{'amount'};
+
+ my $host = $self->host;
+ if ( $self->test_transaction ) {
+ $host ||= $ENDPOINT_SANDBOX;
+ } else {
+ $host ||= $ENDPOINT_LIVE;
+ }
+ my $url = 'https://' . $host .
+ '/customerportal/MerchantServices/MakePayment.aspx';
+
+ warn Dumper \%params if $DEBUG > 2;
+
+ # we don't post to the url ourselves, just give it to the user
+ $self->is_success(1);
+ $self->redirect($url);
+ $self->post_params(\%params);
+
+ $self->token( $params{'orderId'} );
+}
+
+sub execute {
+ my $self = shift;
+ my %params = @_;
+
+# URL looks like
+# http://merchantA.com/Success?OrderID=988676&TransactionReference=8765678998989779
+ warn Dumper(\%params) if $DEBUG > 2;
+
+ if ($params{'OrderID'}) {
+ $self->token($params{'OrderID'});
+ } else {
+ die 'No order ID returned from processor';
+ }
+ if ($params{'TransactionReference'}) {
+ $self->order_number($params{'TransactionReference'});
+ } else {
+ die 'No transaction reference returned from processor';
+ }
+
+ my $host = $self->host;
+ if ( $self->test_transaction ) {
+ $host ||= $ENDPOINT_SANDBOX;
+ $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;
+ } else {
+ $host ||= $ENDPOINT_LIVE;
+ }
+ my $url = 'https://' . $host .
+ '/customerportal/MerchantServices/UpayTransactionStatus.ashx';
+ my $ua = LWP::UserAgent->new;
+ warn "Querying transaction status at $url\n" if $DEBUG;
+ my $response = $ua->get($url,
+ 'MERCHANT_ID' => $self->username,
+ 'ORDER_ID' => $self->token
+ );
+
+ if ( $response->is_success ) {
+
+ local $@;
+ my $parser = XML::LibXML->new;
+ my $doc = eval { $parser->parse_string($response->content) };
+ if ( $@ ) {
+ die "malformed response to transaction status request: $@\n".
+ ($DEBUG ? ("\n\n".$response->content) : '');
+ }
+ my $root = $doc->documentElement;
+ my %hash = map { $_->nodeName => $_->textContent }
+ $root->nonBlankChildNodes;
+
+ warn Dumper \%hash if $DEBUG > 2;
+ if ( $hash{StatusCode} == 0 ) {
+ $self->is_success(1);
+ $self->authorization($hash{PaymentRef});
+ } else {
+ $self->is_success(0);
+ $self->error_message($hash{Status} . ' - ' . $hash{ResponseDescription});
+ }
+ } else {
+ die "No confirmation received: ".$response->status_line;
+ }
+}
+
+1;
+__END__
+
+=head1 NAME
+
+Business::OnlineThirdPartyPayment::FCMB
+
+=head1 DESCRIPTION
+
+Business::OnlineThirdPartyPayment interface to the First City Monument Bank
+(Nigeria) web-based payment processing system.
+
+=head1 NOTES
+
+=over 4
+
+=item FCMB requires the callback URL to be configured statically;
+I<return_url> and I<cancel_url> parameters will be ignored.
+
+=item Set I<username> to your merchant ID (5 digits). No password is needed.
+
+=item The only required transaction fields are currency (NGN, USD, or UKP),
+amount, description, and email.
+
+=item The 'faker' directory contains a simple mock-up of the FCMB interface
+for testing. This was created from the documentation, without reference
+to the real FCMB system, and is NOT known to be accurate.
+
+=back
+
+=head1 AUTHOR
+
+Mark Wells <mark@freeside.biz>
+
+=head1 SEE ALSO
+
+perl(1). L<Business::OnlineThirdPartyPayment>.
+
+=cut
+