From 0e7434f22b061cd233c7c09cead4f8a3dc744afe Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Wed, 12 Jun 2019 16:45:04 -0400 Subject: [PATCH] JBAS-2297 SIP Refundable payment support Signed-off-by: Bill Erickson --- .../perlmods/lib/OpenILS/Application/AppUtils.pm | 21 ++++++++++ .../perlmods/lib/OpenILS/Application/Circ/Money.pm | 44 ++++++++++++++++++--- .../OpenILS/Application/Circ/RefundablePayment.pm | 45 +++++++++++++++++++--- .../lib/OpenILS/SIP/Transaction/FeePayment.pm | 18 ++++----- 4 files changed, 107 insertions(+), 21 deletions(-) diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm index 053f2e1524..7d56118710 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm @@ -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; diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Money.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Money.pm index 38169bc7a9..22bb887f6c 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Money.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Money.pm @@ -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 diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/RefundablePayment.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/RefundablePayment.pm index 74be080c7e..b2b46fb579 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/RefundablePayment.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/RefundablePayment.pm @@ -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; diff --git a/Open-ILS/src/perlmods/lib/OpenILS/SIP/Transaction/FeePayment.pm b/Open-ILS/src/perlmods/lib/OpenILS/SIP/Transaction/FeePayment.pm index 827572da7e..4e0763e746 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/SIP/Transaction/FeePayment.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/SIP/Transaction/FeePayment.pm @@ -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" -- 2.11.0