More code reshuffling in support of Stripe. Compiles, but testing to come.
authorLebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Thu, 19 Sep 2013 17:19:19 +0000 (13:19 -0400)
committerLebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Thu, 19 Sep 2013 17:19:19 +0000 (13:19 -0400)
Signed-off-by: Lebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/CreditCard.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Money.pm

index f7944e3..2c61830 100644 (file)
@@ -76,18 +76,6 @@ sub bop_args_PayflowPro {
     );
 }
 
-sub get_processor_settings {
-    my $org_unit = shift;
-    my $processor = lc shift;
-
-    # XXX TODO: make this one single cstore request instead of many
-    +{ map { ($_ =>
-        $U->ou_ancestor_setting_value(
-            $org_unit, "credit.processor.${processor}.${_}"
-        )) } qw/enabled login password signature server testmode vendor partner/
-    };
-}
-
 #        argshash (Hash of arguments with these keys):
 #                patron_id: Not a barcode, but a patron's internal ID
 #                       ou: Org unit where transaction happens
index d83a5c1..32e4417 100644 (file)
@@ -27,8 +27,36 @@ use OpenILS::Event;
 use OpenSRF::Utils::Logger qw/:logger/;
 use OpenILS::Utils::CStoreEditor qw/:funcs/;
 use OpenILS::Utils::Penalty;
+use Business::Stripe;
 $Data::Dumper::Indent = 0;
 
+sub get_processor_settings {
+    my $e = shift;
+    my $org_unit = shift;
+    my $processor = lc shift;
+
+    # Get the names of every credit processor setting for our given processor.
+    # They're a little different per processor.
+    my $setting_names = $e->json_query({
+        select => {coust => ["name"]},
+        from => {coust => {}},
+        where => {name => {like => 'credit.processor.${processor}.%'}}
+    }) or return $e->die_event;
+
+    # Make keys for a hash we're going to build out of the last dot-delimited
+    # component of each setting name.
+    ($_->{key} = $_->{name}) =~ s/.+\.(\w+)$/$1/ for @$setting_names;
+
+    # Return a hash with those short keys, and for values the value of
+    # the corresponding OU setting within our scope.
+    return {
+        map {
+            $_->{key} => $U->ou_ancestor_setting_value($org_unit, $_->{name})
+        } @$setting_names
+    };
+}
+
+# process_stripe_or_bop_payment()
 # This is a helper method to make_payments() below (specifically,
 # the credit-card part). It's the first point in the Perl code where
 # we need to care about the distinction between Stripe and the
@@ -37,10 +65,10 @@ $Data::Dumper::Indent = 0;
 # B::OP and doesn't require us to know anything about the payment card
 # info).
 #
-# Return an event for failure, non-event hash from payment processor for
-# success.
+# Return an event in all cases.  That means a success returns a SUCCESS
+# event.
 sub process_stripe_or_bop_payment {
-    my ($user_id, $this_ou, $total_paid, $cc_args) = @_;
+    my ($e, $user_id, $this_ou, $total_paid, $cc_args) = @_;
 
     # A few stanzas to determine which processor we're using and whether we're
     # really adequately set up for it.
@@ -52,23 +80,45 @@ sub process_stripe_or_bop_payment {
         }
     }
 
+    # Make sure the configured credit processor has a safe/correct name.
     return OpenILS::Event->new('CREDIT_PROCESSOR_NOT_ALLOWED')
         unless $cc_args->{processor} =~ /^[a-z0-9_\-]+$/i;
 
-    # XXX TODO: the following line doesn't even compile because get_procsesor_settings() is in the CreditCard package, not this one, and it also won't *work* yet because it looks for settings shaped like they are for the BOP processors, and it needs to be different for stripe.  This is my very next TODO.
-    my $psettings = get_processor_settings(@{$cc_args}{'ou', 'processor'});
-
+    # Get the settings for the processor and make sure they're serviceable.
+    my $psettings = get_processor_settings($e, @{$cc_args}{'ou', 'processor'});
+    return $psettings if defined $U->event_code($psettings);
     return OpenILS::Event->new('CREDIT_PROCESSOR_NOT_ENABLED')
         unless $psettings->{enabled};
 
     # Now we branch. Stripe is one thing, and everything else is another.
 
-    if ($cc_args->{processor} eq 'Stripe') {
-        # Stripe
-        # XXX TODO
-        return OpenILS::Event->new('BAD_PARAMS', note => 'Stripe is XXX TODO');
-    } else {
-        # B::OP style (Paypal/PayflowPro/AuthorizeNet)
+    if ($cc_args->{processor} eq 'Stripe') { # Stripe
+        my $stripe = Business::Stripe->new(-api_key => $psettings->{secretkey});
+        $stripe->charges_create(
+            amount => $total_paid,
+            card => $cc_args->{stripe_token},
+            description => $cc_args->{note}
+        );
+
+        if ($stripe->success) {
+            $logger->info("Stripe payment succeeded");
+            return OpenILS::Event->new(
+                "SUCCESS", payload => {
+                    map { $_ => $stripe->success->{$_} } qw(
+                        invoice customer balance_transaction id created
+                    )
+                }
+            );
+        } else {
+            $logger->info("Stripe payment failed");
+            return OpenILS::Event->new(
+                "CREDIT_PROCESSOR_DECLINED_TRANSACTION",
+                payload => $stripe->error  # XXX what happens if this contains
+                                           # JSON::backportPP::* objects?
+            );
+        }
+
+    } else { # B::OP style (Paypal/PayflowPro/AuthorizeNet)
         return OpenILS::Event->new('BAD_PARAMS', note => 'Need CC number')
             unless $cc_args->{number};
 
@@ -332,10 +382,10 @@ sub make_payments {
         # to call to the payment processor ourselves.
         if ($cc_args->{where_process} == 1) {
             my $response = process_stripe_or_bop_payment(
-                $user_id, $this_ou, $total_paid, $cc_args
+                $e, $user_id, $this_ou, $total_paid, $cc_args
             );
 
-            if ($U->event_code($response)) { # non-success
+            if ($U->event_code($response)) { # non-success (success is 0)
                 $logger->info(
                     "Credit card payment for user $user_id failed: " .
                     $response->{"textcode"} . " " .
@@ -345,13 +395,18 @@ sub make_payments {
                 # We need to save this for later in case there's a failure on
                 # the EG side to store the processor's result.
 
-                # XXX TODO generalize this for Stripe as well as for B::OP style
-                $cc_payload = $response->{"payload"};
-
-                $approval_code = $cc_payload->{"authorization"};
-                $cc_type = $cc_payload->{"card_type"};
-                $cc_processor = $cc_payload->{"processor"};
-                $cc_order_number = $cc_payload->{"order_number"};
+                $cc_payload = $response->{"payload"};   # also used way later
+
+                {
+                    no warnings 'uninitialized';
+                    $cc_type = $cc_payload->{card_type};
+                    $approval_code = $cc_payload->{authorization} ||
+                        $cc_payload->{id};
+                    $cc_processor = $cc_payload->{processor} ||
+                        $cc_args->{processor};
+                    $cc_order_number = $cc_payload->{order_number} ||
+                        $cc_payload->{invoice};
+                };
                 $logger->info("Credit card payment for user $user_id succeeded");
             }
         } else {