JBAS-2297 SIP Refundable payment support
authorBill Erickson <berickxx@gmail.com>
Wed, 12 Jun 2019 20:45:04 +0000 (16:45 -0400)
committerBill Erickson <berickxx@gmail.com>
Wed, 19 Jun 2019 16:33:50 +0000 (12:33 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Money.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/RefundablePayment.pm
Open-ILS/src/perlmods/lib/OpenILS/SIP/Transaction/FeePayment.pm

index 053f2e1..7d56118 100644 (file)
@@ -2572,5 +2572,26 @@ sub org_operates_on_date {
     return $hoo->$omethod() ne $hoo->$cmethod();
 }
 
+# TODO: Move this into the database
+my @NO_REFUND_CIRC_MODIFIERS = (1, 7, 45, 46, 66, 40, 41); 
+sub circ_is_refundable {
+    my ($class, $circ_id, $e) = @_;
+
+    $e ||= OpenILS::Utils::CStoreEditor->new;
+
+    my $circ = $e->retrieve_action_circulation([$circ_id, 
+        {flesh => 1, flesh_fields => {circ => ['target_copy']}}
+    ]) or return 0;
+
+    my $copy = $circ->target_copy;
+
+    return 0 if $circ->stop_fines ne 'LOST';
+    return 0 if $circ->checkin_time;
+    return 0 if $copy->call_number == -1;
+    return 0 if grep {$_ == $copy->circ_modifier} @NO_REFUND_CIRC_MODIFIERS;
+
+    return 1;
+}
+
 1;
 
index 38169bc..22bb887 100644 (file)
@@ -200,6 +200,10 @@ __PACKAGE__->register_method(
                             ...
                         ]
                     }
+                    secondary_auth_username
+                        -- Used for tracking refundable payment info
+                        -- for payments made via 3rd-party register or kiosk
+                        -- where staff cannot enter secondary auth info.
                 }/, type => 'hash'
             },
             {
@@ -274,17 +278,25 @@ sub make_payments {
     my $note = $payments->{note};
     my $cc_args = $payments->{cc_args};
     my $refundable_args = $payments->{refundable_args} || {};
+    my $secondary_auth_username = $payments->{secondary_auth_username};
     my $check_number = $payments->{check_number};
     my $total_paid = 0;
     my $this_ou = $e->requestor->ws_ou || $e->requestor->home_ou;
     my %orgs;
 
-    return OpenILS::Event->new('BAD_PARAMS', note => 
-        'Secondary auth key required for refundable payment tracking')
-        if (
-            $refundable_args->{transactions} 
-            && !$refundable_args->{secondary_auth_key}
-        );
+    # Should we perform the refundability check ourselves?  Needed
+    # in cases where the caller is not able to check/verify (e.g. credit
+    # card payments, external cash registers).
+    my $check_refundable = 1;
+
+    if ($refundable_args->{transactions}) {
+        # User has already performed the refundable check.
+        $check_refundable = 0;
+
+        return OpenILS::Event->new('BAD_PARAMS', note => 
+            'Secondary auth key required for refundable payment tracking')
+            unless $refundable_args->{secondary_auth_key};
+    }
 
     # unless/until determined by payment processor API
     my ($approval_code, $cc_processor, $cc_order_number) = (undef,undef,undef, undef);
@@ -559,6 +571,18 @@ sub make_payments {
 
         push(@payment_ids, $payment->id);
 
+        if ($check_refundable && $U->circ_is_refundable($transid, $e)) {
+
+            $logger->info(
+                "Payment ".$payment->id." tracked as potentially refundable");
+
+            $refundable_args->{transactions} = [] 
+                unless $refundable_args->{transactions};
+
+            push(@{$refundable_args->{transactions}}, {xact => $transid});
+        }
+
+
         if ($refundable_args->{transactions}) {
             # If this is one of the refundable payments, add the payment
             # ID to the set of per-payment options provided by the caller.
@@ -591,6 +615,14 @@ sub make_payments {
     if ($refundable_args->{transactions}) {
         my $authkey = $refundable_args->{secondary_auth_key};
 
+        if (!$authkey) {
+            # For 3rd-party payments, there will be no auth key.
+            # Generate a dummy key for the refundable API.
+            my $sa = $secondary_auth_username || 'SELF-SERVICE';
+                   $authkey = OpenILS::Application::Circ::RefundablePayment->
+                           create_ldap_auth_entry($sa, $sa, $sa);
+        }
+
         for my $pay_args (@{$refundable_args->{transactions}}) {
             my $pay_id = $pay_args->{payment_id};
             my $evt = OpenILS::Application::Circ::RefundablePayment
index 74be080..b2b46fb 100644 (file)
@@ -93,13 +93,23 @@ sub authenticate_ldap {
         return $ldap_resp->{evt} if $ldap_resp->{evt};
     }
 
+    return create_ldap_auth_entry(
+        undef, $username, $ldap_resp->{staff_name}, $ldap_resp->{staff_email}
+    );
+}
+
+# Credit Card payments are automatically authorized.
+# Creat a dummy auth entry.
+sub create_ldap_auth_entry {
+    my ($class, $username, $name, $email) = @_;
+
     my $key = md5_hex($$.rand().time);
 
     OpenSRF::Utils::Cache->new('global')->put_cache(
         $ldap_key_prefix.$key, {
             username => $username,
-            staff_name => $ldap_resp->{staff_name},
-            staff_email => $ldap_resp->{staff_email}
+            staff_name => $name,
+            staff_email => $email
         }, 
         $ldap_key_timeout
     );
@@ -186,9 +196,7 @@ sub create_refundable_payment {
     my $ldap_auth = OpenSRF::Utils::Cache->new('global')
         ->get_cache($ldap_key_prefix.$secondary_auth_key);
 
-    unless ($ldap_auth && 
-        $ldap_auth->{staff_name} && 
-        $ldap_auth->{staff_email}) {
+    unless ($ldap_auth) {
         $logger->error("Refundable payment attempted with ".
             "invalid secondary auth key: $secondary_auth_key");
         return OpenILS::Event->new('LDAP_AUTH_FAILED');
@@ -508,6 +516,33 @@ sub retrieve_refundable_payment {
 
     return $e->search_money_refundable_payment({payment => $payment_id})->[0]; 
 }
+
+
+__PACKAGE__->register_method(
+    method    => 'circ_is_refundable',
+    api_name  => 'open-ils.circ.refundable_payment.circ.refundable',
+    signature => {
+        desc   => q/Returns 1 if payments toward the requested circulation
+            would be refundable.  Returns 0 otherwise./,
+        params => [
+            {desc => 'Authentication token', type => 'string'},
+            {desc => 'Circulation (circ.id) ID', type => 'number'}
+        ],
+        return => {
+            desc => '1 on true, 0 on false'
+        }
+    }
+);
+
+sub circ_is_refundable {
+    my ($self, $client, $auth, $circ_id) = @_;
+
+    my $e = new_editor(authtoken => $auth);
+    return $e->event unless $e->checkauth;
+    return $e->event unless $e->allowed('STAFF_LOGIN');
+    return $U->circ_is_refundable($circ_id, $e);
+}
+
  
 1;
 
index 827572d..4e0763e 100644 (file)
@@ -192,24 +192,22 @@ sub pay_bills {
     my $ptype = $self->sip_payment_type || '';
     my $rlogin = $self->register_login || '';
 
-    my $params = {
-        userid => $user->id,
-        note => "Via SIP2",
-        payments => $paymentref,
-        payment_type => 'cash_payment'
-    };
-
     if ($rlogin) {
         syslog('LOG_DEBUG', "Register login sent as '$rlogin'"); 
-
         if ($rlogin =~ /\\.+/) { # Windows domain login
             my @parts = split(/\\/, $rlogin);
             $rlogin = $parts[1];
         }
-
-        $params->{note} = "Via SIP2: Register login '$rlogin'";
     }
 
+    my $params = {
+        userid => $user->id,
+        note => $rlogin ? "Via SIP2: Register login '$rlogin'" : "Via SIP2",
+        payments => $paymentref,
+        payment_type => 'cash_payment',
+        secondary_auth_username => $rlogin
+    };
+
     if ($ptype eq '02' || $ptype eq '01') {
         # '01' is "VISA"
         # '02' is "credit card"