44580f432ce95522a9bf1201c27e4bc8eb347931
[working/Evergreen.git] / Open-ILS / src / perlmods / lib / OpenILS / SIP / Transaction / FeePayment.pm
1 # ---------------------------------------------------------------
2 # Copyright (C) 2011 Merrimack Valley Library Consortium
3 # Jason Stephenson <jstephenson@mvlc.org>
4
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
9
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 # ---------------------------------------------------------------
15 #
16 # An object to handle fee payment
17 #
18
19 package OpenILS::SIP::Transaction::FeePayment;
20
21 use warnings;
22 use strict;
23
24 use POSIX qw(strftime);
25
26 use OpenILS::SIP;
27 use OpenILS::SIP::Transaction;
28 use OpenILS::SIP::Msg qw/:const/;
29 use Sys::Syslog qw(syslog);
30
31 use OpenILS::Application::AppUtils;
32 my $U = 'OpenILS::Application::AppUtils';
33
34
35 our @ISA = qw(OpenILS::SIP::Transaction);
36
37 # Most fields are handled by the Transaction superclass
38 my %fields = (
39               sip_payment_type => undef,
40               fee_id => 0,
41               patron_password => undef,
42              );
43
44 sub new {
45     my $class = shift;
46
47     my $self = $class->SUPER::new(@_);
48
49     foreach my $element (keys %fields) {
50         $self->{_permitted}->{$element} = $fields{$element};
51     }
52
53     @{$self}{keys %fields} = values %fields;
54     return bless $self, $class;
55 }
56
57 sub do_fee_payment {
58     my $self = shift;
59
60     # Just in case something completely unexpected happens, we'll
61     # reject the payment to be 'safe.'
62     $self->ok(0);
63
64     # If the SC sends over a fee id, we try to pay that
65     # fee/transaction on the patron's record.
66     if ($self->fee_id) {
67         my $bill;
68         $bill = $U->simplereq('open-ils.actor', 'open-ils.actor.user.transaction.retrieve', $self->{authtoken}, $self->fee_id);
69         syslog('LOG_DEBUG', 'OILS: open-ils.actor.user.transaction.retrieve returned ' . OpenSRF::Utils::JSON->perl2JSON($bill));
70         # If we got an event or the bill belongs to another patron, set bill to undef.
71         $bill = undef if ($U->event_code($bill) || $bill->usr != $self->patron->internal_id);
72
73         # Attempt the payment here.
74         if ($bill && $bill->balance_owed >= $self->fee_amount) {
75             # We only attempt payment if the balance_owed on the bill
76             # is greater than or equal to the amount paid by the
77             # client.
78             my $payref = [ [$bill->id, $self->fee_amount] ];
79             my $resp = $self->pay_bills($payref);
80             syslog('LOG_INFO', 'OILS: pay_bills returned ' . OpenSRF::Utils::JSON->perl2JSON($resp));
81             if ($U->event_code($resp)) {
82                 $self->ok(0);
83                 $self->screen_msg(($resp->{descr} || $resp->{textcode}));
84             } else {
85                 $self->ok(1);
86             }
87         } else {
88             $self->ok(0);
89             if ($bill) {
90                 # The payment had to be greater than the bill balance
91                 # to end up here. We don't allow credits or
92                 # overpayment.
93                 $self->sreen_msg(OILS_SIP_MSG_OVERPAYMENT);
94             }
95             else {
96                 # In this case, the bill was not found or did not
97                 # belong to the patron.
98                 $self->screen_msg(OILS_SIP_MSG_NO_BILL);
99             }
100         }
101     } else {
102         # We attempt to pay as many of the patron's bills as possible with the payment provided.
103         my $results = $U->simplereq('open-ils.actor', 'open-ils.actor.user.transactions.history.have_balance', $self->{authtoken}, $self->patron->internal_id);
104         if ($results && ref($results) eq 'ARRAY') {
105             syslog('LOG_INFO', 'OILS: ' . scalar @$results . " bills found for " . $self->patron->internal_id);
106
107             # If we get an empty array, we report not bills found and
108             # quit.
109             unless (@$results) {
110                 $self->ok(0);
111                 $self->screen_msg(OILS_SIP_MSG_NO_BILL);
112                 return $self->ok;
113             }
114
115             # We fill an array with the payment information as
116             # open-ils.circ.money.payment expects it, i.e. an arrayref
117             # with the bill_id and payment amount of its members. To
118             # actually pay the bils, we pass the reference to this
119             # array to our pay_bils method.
120             my @payments = ();
121
122             # Pay each bill from the fee_amount provided until we
123             # either run out of bills or the input payment balance
124             # hits zero.
125             my $amount_paid = $self->fee_amount; # If this hits zero, we're done.
126             foreach my $bill (@{$results}) {
127                 my $payment;
128                 syslog('LOG_INFO', 'OILS: bill '. $bill->id . ' amount ' . $bill->balance_owed);
129                 if ($bill->balance_owed >= $amount_paid) {
130                     # We owe as much as or more than we have money
131                     # left, so pay what we have left.
132                     $payment = $amount_paid;
133                     $amount_paid = 0;
134                 } else {
135                     # This bill is for less than the amount we have
136                     # left, so pay the full bill amount.
137                     $payment = $bill->balance_owed;
138                     $amount_paid -= $bill->balance_owed;
139                 }
140                 # Add the payment to our array.
141                 push(@payments, [$bill->id, $payment]);
142                 # Leave if we ran out of money.
143                 last if ($amount_paid == 0);
144             }
145             if (@payments && $amount_paid == 0) {
146                 # pay the bills with a reference to our payments
147                 # array.
148                 my $resp = $self->pay_bills(\@payments);
149                 syslog('LOG_INFO', 'OILS: pay_bills returned ' . OpenSRF::Utils::JSON->perl2JSON($resp));
150                 if ($U->event_code($resp)) {
151                     $self->ok(0);
152                     $self->screen_msg(($resp->{descr} || $resp->{textcode}));
153                 } else {
154                     $self->ok(1);
155                 }
156             } else {
157                 $self->ok(0);
158                 if (scalar(@payments) == 0) {
159                     # We didn't find any bills for the patron.
160                     $self->screen_msg(OILS_SIP_MSG_NO_BILL);
161                 } else {
162                     # We have an overpayment
163                     $self->screen_msg(OILS_SIP_MSG_OVERPAYMENT);
164                 }
165             }
166         } else {
167             $self->ok(0);
168             if ($results && $U->event_code($results)) {
169                 $self->screen_msg(OILS_SIP_MSG_BILL_ERR);
170             } else {
171                 $self->screen_msg(OILS_SIP_MSG_NO_BILL);
172             }
173         }
174     }
175     return $self->ok;
176 }
177
178 # Takes array ref of array ref of [billid, payment_amount] to pay in
179 # batch.
180 sub pay_bills {
181     my ($self, $paymentref) = @_;
182     my $user = $self->patron->{user};
183     return $U->simplereq('open-ils.circ', 'open-ils.circ.money.payment', $self->{authtoken},
184                          { payment_type => "cash_payment", userid => $user->id, note => "via SIP2",
185                            payments => $paymentref}, $user->last_xact_id);
186 }
187
188
189 1;