complete rewrite, version 0.10
authorMark Wells <mark@freeside.biz>
Fri, 28 Jun 2013 23:33:04 +0000 (16:33 -0700)
committerMark Wells <mark@freeside.biz>
Fri, 28 Jun 2013 23:33:04 +0000 (16:33 -0700)
.gitignore [new file with mode: 0644]
Changes
MANIFEST
Makefile.PL
OnlineThirdPartyPayment.pm
notes_for_module_writers
t/pod.t [deleted file]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..9788afa
--- /dev/null
@@ -0,0 +1,6 @@
+blib/
+*.sw?
+Makefile
+Makefile.old
+MYMETA.yml
+pm_to_blib
diff --git a/Changes b/Changes
index b43b667..b8826bf 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,7 @@
 Revision history for Perl extension Business::OnlineThirdPartyPayment.
 
+0.10  unrelesed
+        - complete rewrite
 0.01  unreleased
        - original version; created by jeff
 
index 2580e9d..ab566f1 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -4,6 +4,4 @@ MANIFEST
 Makefile.PL
 OnlineThirdPartyPayment.pm
 t/00load.t
-t/pod.t
 notes_for_module_writers
-META.yml                                 Module meta-data (added by MakeMaker)
index 53f13e8..526b4f0 100644 (file)
@@ -4,7 +4,7 @@ use ExtUtils::MakeMaker;
 WriteMakefile(
     'NAME'         => 'Business::OnlineThirdPartyPayment',
     'VERSION_FROM' => 'OnlineThirdPartyPayment.pm', # finds $VERSION
-    'AUTHOR'       => 'Jeff Finucane <business-onlinethirdpartypayment@weasellips.com>',
+    'AUTHOR'       => 'Mark Wells <mark@freeside.biz>',
     'PREREQ_PM'    => { 
                         'Business::OnlinePayment' => 3,
                         'Test::More' => 0.42,
index b642ffd..8ada8d5 100644 (file)
@@ -7,28 +7,21 @@ use base qw(Business::OnlinePayment);
 
 require 5.005;
 
-$VERSION = '3.00_09';
+$VERSION = 0.10;
 $VERSION = eval $VERSION; # modperlstyle: convert the string into a number
 
 my %fields = (
-    authorization        => undef,
-    error_message        => undef,
-    failure_status       => undef,
-    fraud_detect         => undef,  # unsupported
-    is_success           => undef,
-    maximum_risk         => undef,  # unsupported
-    path                 => undef,
-    port                 => undef,
-    require_avs          => undef,
-    result_code          => undef,
-    server               => undef,
-    server_response      => undef,
-    test_transaction     => undef,
-    transaction_type     => undef,
-    fraud_score          => undef,  # unsupported
-    fraud_transaction_id => undef,  # unsupported
-    popup_url            => undef,
-    collectitems         => undef,
+    is_success          => undef,
+    token               => undef,
+    redirect            => undef,
+    post_params         => undef,
+    statustext          => undef,
+    order_number        => undef,
+    authorization       => undef,
+    error_message       => undef,
+    test_transaction    => undef,
+    return_url          => undef,
+    cancel_url          => undef,
 );
 
 sub new {
@@ -58,127 +51,177 @@ sub new {
     return $self;
 }
 
-sub reference {
-    my($self) = @_;
-
-    croak("Processor subclass did not override reference function");
-}
-
 1;
 
 __END__
 
 =head1 NAME
 
-Business::OnlineThirdPartyPayment - Perl extension for third party web page based online payment processing
+Business::OnlineThirdPartyPayment - Common interface to browser-based 
+online payment processors
 
 =head1 SYNOPSIS
 
   use Business::OnlineThirdPartyPayment;
+  use CGI;
 
-  my $transaction =
-    new Business::OnlineThirdPartyPayment($processor, %processor_info);
-  $transaction->content(
-                        type        => 'CC',
-                        action      => 'Authorization Only',
-                        amount      => '49.95',
-                        reference   => '3735928559',
-                       );
-  $transaction->submit();
-  
-  if($transaction->is_success()) {
-    print "Success!  Redirect browser to ". $transaction->popup_url();
+  my %processor_info = (
+    'return_url'  => 'https://www.example.com/payment/return',
+    'cancel_url'  => 'https://www.example.com/payment/cancel',
+    # ... other processor-specific values
+  );
+
+  my $txn = Business::OnlineThirdPartyPayment->new('MyBank', %processor_info);
+  # start a payment
+  $txn->create( customer_id     => 4030,
+                invoice_number  => 10318,
+                amount          => 49.95,
+                currency        => 'CAD',
+                description     => 'Internet Services',
+              );
+
+  if ( $txn->is_success} ) {
+    store_payment_id($txn->token); # keep it somewhere
+    print CGI->redirect( $txn->redirect );
   } else {
-    print "Card was rejected: ", $transaction->error_message(), "\n";
+    die $txn->error_message;
   }
 
-  #when the provider calls us back via HTTP
-  use CGI;
-  my $cgi = new CGI;  #initialized to current page
+  ...
+  # then, at /payment/return...
+  my $txn = Business::OnlineThirdPartyPayment->new('MyBank', %processor_info);
+  $txn->token( get_payment_id($cgi) ); # probably from a session cookie
+  my %params = $cgi->Vars;
+
+  $txn->execute(%params);
   
-  my $reference = $transaction->reference($cgi->Vars);
-  $transaction->content(
-                        type        => 'CC',
-                        action      => 'Post Authorization',
-                        reference   => $reference,
-                       );
-  $transaction->submit();
-  if($transaction->is_success()) {
-    print "Card processed scucessfully: ", $transaction->authorization(), "\n";
+  if ( $txn->is_success ) {
+    store_payment_success($txn->order_number, $txn->authorization);
+    print "Your payment was successful!\n";
   } else {
-    print "Card was rejected: ", $transaction->error_message(), "\n";
+    store_payment_failure($txn->order_number, $txn->error_message);
+    print "Your payment failed.\n";
   }
 
-  
-
 =head1 DESCRIPTION
 
 Business::OnlineThirdPartyPayment is a generic module for processing payments
 through online credit card processors, electronic cash systems, etc. through
-which the payors web browser is redirected.  It is a subclass of
-L<Business::OnlinePayment>
+which the payer's web browser is redirected.
+
+=head1 METHODS
 
-=head1 METHODS AND FUNCTIONS
+=head2 new($module, %processor_options)
 
-=head2 new($processor, %processor_options);
+Class method.  Create a Business::OnlineThirdPartyPayment object.
+$module is required, and defines the gateway module to use.  The 
+other options are processor-specific, but should always include:
 
-Create a new Business::OnlineThirdPartyPayment object, $processor is required,
-and defines the online processor to use.  If necessary, processor
-options can be specified, currently supported options are 'Server',
-'Port', and 'Path', which specify how to find the online processor
-(https://server:port/path), but individual processor modules should
-supply reasonable defaults for this information, override the defaults
-only if absolutely necessary (especially path), as the processor
-module was probably written with a specific target script in mind.
+=over 4
+
+=item return_url - The callback URL to redirect the user to after completing 
+a payment.
+
+=item cancel_url - The URL to redirect the user to if they choose not to 
+complete the payment.
+
+=back
 
-=head2 content(%content);
+=head2 create(%content)
 
-The information necessary for the transaction, this tends to vary a
-little depending on the processor, so we have chosen to use a system
-which defines specific fields in the frontend which get mapped to the
-correct fields in the backend.  Currently defined fields are:
+Tell the gateway module to start a transaction.  This may involve 
+communicating with the gateway, or it may happen entirely locally.
+%content is a hash containing some of the following:
 
-=head3 PROCESSOR FIELDS
+=head3 TRANSACTION FIELDS
 
 =over 4
 
-=item * reference
+=item amount - The amount of the transaction, as a decimal number. Required.
+
+=item description - A description of the purchase. Required.
+
+=item invoice_number - Your invoice number, if this payment is associated
+with a specific invoice.
+
+=item currency - Currency, specified as an ISO 4217 three-letter code, such 
+as USD, CAD, EUR, AUD, DKK, GBP, JPY, NZD, etc.
+
+=item customer_id - The customer number, if any.
+
+=item email - Customer's email address.
 
-A unique reference for this transaction.
+=item customer_ip - IP address from which the transaction originated.
 
 =back
 
 For additional fields, see L<Business::OnlinePayment> and the specific
 processor module used.
 
-=head2 submit();
+C<create()> sets properties of the transaction object to indicate the 
+result.  These will always include:
 
-Submit the transaction to the processor for completion
+=over 4
+
+=item is_success - 1 if the transaction was created successfully, 0 
+otherwise.
+
+=item error_message - a text description of any error that occurred.
+Since the payer hasn't provided a payment account or any other 
+information at this stage, this is probably not meaningful to them.
+
+=item token - a reference string that will be used to identify
+this transaction later.  If is_success is true, you I<must> store this 
+value in your merchant system and pass it to execute() later.  Merchant 
+systems should allow at least 256 characters for this string.
+
+=item statustext - a freeform text field for any state information 
+that the gateway needs to receive to complete the transaction.
 
-=head2 is_success();
+=item redirect - a URL to redirect the payer to.
 
-Returns true if the transaction was submitted successfully, false if
-it failed (or undef if it has not been submitted yet).
+=item post_params - the content of an HTTP POST request to send to the 
+URL.  Since HTTP redirects can't include POST content, in this case the 
+front-end system must provide another way (a self-submitting form) to 
+induce the purchaser's browser to make the request.
 
-=head2 test_transaction();
+=back
+
+=head2 execute(%params)
+
+Complete the transaction.  This should be called from the web server
+(from 'return_url').  %params must contain any query parameters passed 
+in the redirect, and token should be set on the object.
 
-Most processors provide a test mode, where submitted transactions will
-not actually be charged or added to your batch, calling this function
-with a true argument will turn that mode on if the processor supports
-it, or generate a fatal error if the processor does not support a test
-mode (which is probably better than accidentally making real charges).
+execute() will set the transaction fields to indicate the result:
+
+=over 4
+
+=item is_success: 1 if the payment was successful, 0 if it was not.
+
+=item error_message: An error message describing the reason for failure.
+Unlike the message returned from C<create()>, this probably is meaningful
+to the user, though the gateway may already have shown it to them.
+
+=item order_number: The transaction ID number assigned by the processor.
+
+=item authorization: The credit card or other authorization number 
+returned by the gateway.  This may be needed to refund the payment or 
+for other customer service issues.
+
+=back
+
+If C<is_success> is true, the merchant system should record this as 
+a successful payment and apply it to the customer's account.
 
 =head1 AUTHOR
 
-Jeff Finucane <business-onlinethirdpartypayment@weasellips>
+Mark Wells <mark@freeside.biz>, based in part on code by Jeff Finucane.
 
 =head1 COPYRIGHT
 
-Partially based on code from Business::OnlinePayment.
-
 Copyright (c) 1999-2004 Jason Kohles.
-Copyright (c) 2004 Ivan Kohler
-Copyright (c) 2007-2009 Freeside Internet Services, Inc.
+Copyright (c) 2007-2013 Freeside Internet Services, Inc.
 
 All rights reserved. This program is free software; you can redistribute
 it and/or modify it under the same terms as Perl itself.
@@ -193,6 +236,4 @@ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
 L<Business::OnlinePayment>, http://420.am/business-onlinepayment/
 
-For verification of credit card checksums, see L<Business::CreditCard>.
-
 =cut
index 57bd098..91c1acb 100644 (file)
@@ -7,27 +7,47 @@ NOTE:
     You should read the notes in Business::OnlinePayment first.
 
 Create a subclass of Business::OnlineThirdPartyPayment called
-Business::OnlinePayment::(processor name).  You should override at least
-the set_defaults, submit, and reference methods.
-
-See Business::OnlineThirdPartyPayment::Interswitchng as an example.
-
-submit: 
-  This method functions with both a "Authorize Only" and "Post Authorization"
-action.  The former must, at a minumum, ensure that popup_url will return
-an appropriate value when submit also sets is_successful.
-
-  Nothing has happened at this point other than verifying the data is valid
-and providing the caller with a redirection url.
-
-  When called with "Post Authorization" steps are taken to verify that funds
-have been authorized by the processor.
-
-reference:
-  This method is called with a hash of key/value pairs, typically as the
-result of a HTTP GET or POST, but by whatever mechanism the processor provides.
-The return value must be the unique reference provided to the "Authorize Only"
-submit.  Since the usage consists of submit(action=>'Authorize Only'),
-reference(key=>value...), submit(action=>'Post Authorization'), this may be
-the appropriate time to set the state of the object for some processors.
+Business::OnlineThirdPartyPayment::(processor name).  You should override at
+least the set_defaults, create, and execute methods.
+
+See Business::OnlineThirdPartyPayment::PayPal as an example.
+
+create(%content):
+This method's primary functions are:
+- to determine/create the URL the purchaser must visit to make payment, and
+- to assign a token to the transaction.
+
+%content will always include 'amount' (the amount of the payment) and 
+'description' (a text description of the product being purchased).
+
+If the processor requires the merchant to initiate the transaction (e.g.
+PayPal), then create() should do that, and store the transaction ID assigned
+by the processor in 'token'.  Otherwise, create() can simply assign a 
+semi-random, unique string to 'token', and additionally pass it to the 
+processor as the order number or other identifier.
+
+The URL the purchaser needs to visit should be assigned to the 'redirect'
+property of the object.  If the processor expects to receive the transaction
+parameters from the purchaser's browser in the form of a POST request,
+create() can store them in a hashref in the 'post_params' property.
+
+execute(%params):
+This method's primary function is to determine whether the transaction
+was successful.  The 'token' property should already be set to whatever it 
+was after the initial create().  %params is everything passed back by the 
+processor to the callback URL.
+
+If the merchant is required to confirm or "capture" the payment after 
+authorization, execute() should do that.  (PayPal again.)  Other processors
+(see B:OTP:FCMB for an example) provide a separate API to query the 
+transaction status; execute() should do that.  In either case, it should
+set the 'is_success' property to 0 or 1, and set 'error_message' if the 
+payment failed, or 'order_number' and 'authorization' if it succeeded.
+
+set_defaults(%arguments):
+This is called from the constructor.  The build_subs() method of 
+Business::OnlinePayment is available for creating accessor methods.
+In general, modules should look for the merchant ID in 'username', any
+password or shared secret in 'password', and the callback URL in
+'return_url'.
 
diff --git a/t/pod.t b/t/pod.t
deleted file mode 100644 (file)
index 2c9935c..0000000
--- a/t/pod.t
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-use warnings;
-use Test::More;
-
-eval "use Test::Pod 1.00";
-plan skip_all => "Test::Pod 1.00 required for testing POD" if $@;
-all_pod_files_ok();