Bug 23442: Add refund option to patron account page
authorMartin Renvoize <martin.renvoize@ptfs-europe.com>
Thu, 21 Nov 2019 13:09:47 +0000 (13:09 +0000)
committerMartin Renvoize <martin.renvoize@ptfs-europe.com>
Fri, 10 Jan 2020 08:41:18 +0000 (08:41 +0000)
This enhancement adds a refined workflow to allow librarians
to refund payments to patrons and record these refunds on the
patrons account.

The use case is that a patron has paid for something before
then performing an action that may require some level of refund
to be actioned.  Perhaps they are returning a lost and paid for
book.

Test plan:
1) Undertake a series of transactions that result in a debit
   accountline being partially or fully paid off.
2) Note that a new 'Issue refund' button appears next to a
   debit (but only if your user has the refund permission or
   is a superlibrarian)
3) Click the 'Issue refund' button and a modal should appear
   pre-populated with the amount - amountoutstanding.
4) You should be able to edit the amount you wish to refund,
   record the refund or cancel.
5) Signoff

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Josef Moravec <josef.moravec@gmail.com>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>

koha-tmpl/intranet-tmpl/prog/en/modules/members/boraccount.tt
members/boraccount.pl

index dc7f0cc..faf180d 100644 (file)
@@ -87,6 +87,9 @@
         [% IF CAN_user_updatecharges_payout && account.is_credit && ( account.amountoutstanding < 0 ) %]
           <button type="button" data-toggle="modal" data-target="#issuePayoutModal" data-account="[%- PROCESS account_type_description account=account -%]" data-accountline="[% account.accountlines_id | html %]" data-amount="[% account.amountoutstanding | $Price %]" class="btn btn-default btn-xs"><i class="fa fa-money"></i> Issue payout</button>
         [% END %]
+        [% IF CAN_user_updatecharges_refund && account.is_debit && ( account.amountoutstanding != account.amount ) && !(account.status == 'REFUNDED' ) %]
+          <button type="button" data-toggle="modal" data-target="#issueRefundModal" data-item="[%- PROCESS account_type_description account=account -%]" data-accountline="[% account.accountlines_id | html %]" data-amount="[% account.amount | $Price %]" data-amountoutstanding="[% account.amountoutstanding | $Price %]" class="btn btn-default btn-xs"><i class="fa fa-money"></i> Issue refund</button>
+        [% END %]
       </td>
     </tr>
 
         </form> <!-- /#payout_form -->
     </div> <!-- /#issuePayoutModal -->
 
+    <!-- Issue refund modal -->
+    <div class="modal" id="issueRefundModal" tabindex="-1" role="dialog" aria-labelledby="issueRefundLabel">
+        <form  id="refund_form" action="/cgi-bin/koha/members/boraccount.pl" method="get" enctype="multipart/form-data" class="validated">
+            <input type="hidden" name="accountlines_id" value="" id="refundline">
+            <input type="hidden" name="action" value="refund">
+            <input type="hidden" name="borrowernumber" value="[% account.borrowernumber | html %]">
+            <div class="modal-dialog" role="document">
+                <div class="modal-content">
+                    <div class="modal-header">
+                        <button type="button" class="closebtn" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                        <h4 class="modal-title" id="issueRefundLabel">Issue refund</h4>
+                    </div>
+                    <div class="modal-body">
+                        <fieldset class="rows">
+                            <ol>
+                                <li>
+                                    <span id="item" class="label">Account: </span><span></span>
+                                </li>
+                                <li>
+                                    <span id="paid" class="label">Amount paid: </span><span></span>
+                                </li>
+                                <li>
+                                    <label class="required" for="amount">Returned to patron: </label>
+                                    <input type="number" step="0.01" id="returned" name="amount" min="0.00" required="required">
+                                    <span class="required">Required</span>
+                                </li>
+                                [% SET payment_types = AuthorisedValues.GetAuthValueDropbox('PAYMENT_TYPE') %]
+                                <li>
+                                    <label for="transaction_type">Transaction type: </label>
+                                    <select name="transaction_type" id="transaction_type">
+                                        <option value="AC">Account credit</option>
+                                        [% IF payment_types %]
+                                        [% FOREACH pt IN payment_types %]
+                                        <option value="[% pt.authorised_value | html %]">[% pt.lib | html %]</option>
+                                        [% END %]
+                                        [% END %]
+                                    </select>
+                                </li>
+
+                                [% IF Koha.Preference('UseCashRegisters') %]
+                                <li>
+                                    <label for="cash_register">Cash register: </label>
+                                    <select name="cash_register" id="cash_register">
+                                        [% FOREACH register IN registers %]
+                                          [% IF register.id == registerid %]
+                                        <option value="[% register.id %]" selected="selected">[% register.name | html %]</option>
+                                          [% ELSE %]
+                                        <option value="[% register.id %]">[% register.name | html %]</option>
+                                          [% END %]
+                                        [% END %]
+                                    </select>
+                                </li>
+                                [% END %]
+
+                            </ol>
+                        </fieldset> <!-- /.rows -->
+                    </div> <!-- /.modal-body -->
+                    <div class="modal-footer">
+                        <input type="hidden" name="registerid" value="[% register.id | html %]">
+                        <input type="hidden" name="op" value="refund">
+                        <button type="submit" class="btn btn-default">Confirm</button>
+                        <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
+                    </div> <!-- /.modal-footer -->
+                </div> <!-- /.modal-content -->
+            </div> <!-- /.modal-dialog -->
+        </form> <!-- /#refund_form -->
+    </div> <!-- /#issueRefundModal -->
+
 [% MACRO jsinclude BLOCK %]
     [% INCLUDE 'datatables.inc' %]
     [% INCLUDE 'columns_settings.inc' %]
                 $("#amount").attr({ "value": amount, "max": amount });
                 $("#amount, #transaction_type").focus();
             });
+
+            $("#issueRefundModal").on("shown.bs.modal", function(e){
+                var button = $(e.relatedTarget);
+                var item = button.data('item');
+                $("#item + span").replaceWith(item);
+                var accountline = button.data('accountline');
+                $('#refundline').val(accountline);
+                var amount = button.data('amount');
+                var amountoutstanding = button.data('amountoutstanding');
+                var paid = amount - amountoutstanding;
+                $("#paid + span").replaceWith(paid);
+                $("#returned").attr({ "value": paid, "max": paid });
+                $("#returned, #transaction_type").focus();
+            });
         });
     </script>
 [% END %]
index df2ad35..f5d7256 100755 (executable)
@@ -118,6 +118,39 @@ if ( $action eq 'payout' ) {
     );
 }
 
+if ( $action eq 'refund' ) {
+    my $charge_id        = scalar $input->param('accountlines_id');
+    my $charge           = Koha::Account::Lines->find($charge_id);
+    my $amount           = scalar $input->param('amount');
+    my $transaction_type = scalar $input->param('transaction_type');
+    $schema->txn_do(
+        sub {
+
+            my $refund = $charge->reduce(
+                {
+                    reduction_type => 'REFUND',
+                    branch         => $library_id,
+                    staff_id       => $logged_in_user->id,
+                    interface      => 'intranet',
+                    amount         => $amount
+                }
+            );
+            unless ( $transaction_type eq 'AC' ) {
+                my $payout = $refund->payout(
+                    {
+                        payout_type   => $transaction_type,
+                        branch        => $library_id,
+                        staff_id      => $logged_in_user->id,
+                        cash_register => $registerid,
+                        interface     => 'intranet',
+                        amount        => $amount
+                    }
+                );
+            }
+        }
+    );
+}
+
 #get account details
 my $total = $patron->account->balance;