a2449a81be
Rebasing was a nightmare, so I'm squashing the sign off follow-ups to ease the pain with any future rebases Includes: Bug 23051: (follow-up) Refactor renewal code As per Nick's first point in comment #20, the code that tests for renewability and renews items has been refactored into it's own function. Bug 23051: (follow-up) Provide feedback For renewals that fail when a fine is being paid off, this patch causes any errors to be passed back to the template for display. Addresses the second point in Nick's comment #20 Bug 23051: (follow-up) Fix unit tests As raised by Nick in comment #35 Bug 23051: (follow-up) Fix/improve feedback This follow up patch addresses the following parts of Nick's feedback in comment #35: - it would be nice to get feedback on what was successfully renewed as well - In general I think I would prefer to see 'ok' and 'not_ok' returned as a single 'renewal_results' array - There is no listing of errors if I use the 'pay' button on an individual fine Bug 23051: (follow-up) Refactor methods This follow up patch addresses the following parts of Nick's feedback in comment #35: - I don't really like that the functions are internal functions and then exported - I think the pref description should highlight that if 'RenewalPeriodBase' is set to due date, there may be doubled charges Bug 23051: (follow-up) Add SIP summary This follow up patch addresses the following parts of Nick's feedback in comment #35: - Ideally SIP would get feedback in a screen message Bug 23051: (follow-up) Renewing in OPAC This follow up patch addresses the following parts of Nick's feedback in comment #35: - I am also not sure about the code path if a patron paid fines on the opac (via paypal etc.) but renewals are not allowed on the opac. We've introduced the syspref RenewAccruingItemInOpac (default is off) which, when enabled, will cause items attached to fines that are paid off in the OPAC (via payment plugins), to be automatically renewed. Signed-off-by: Nick Clemens <nick@bywatersolutions.com> Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
382 lines
22 KiB
Text
382 lines
22 KiB
Text
[% USE raw %]
|
|
[% USE Asset %]
|
|
[% USE Koha %]
|
|
[% USE Branches %]
|
|
[% USE KohaDates %]
|
|
[% USE ColumnsSettings %]
|
|
[% USE AuthorisedValues %]
|
|
[% USE Price %]
|
|
[% USE Branches %]
|
|
[% SET footerjs = 1 %]
|
|
|
|
[% PROCESS 'accounts.inc' %]
|
|
|
|
[% INCLUDE 'doc-head-open.inc' %]
|
|
<title>Koha › Patrons › Account for [% INCLUDE 'patron-title.inc' no_html = 1 %]</title>
|
|
[% INCLUDE 'doc-head-close.inc' %]
|
|
</head>
|
|
|
|
<body id="pat_borraccount" class="pat">
|
|
[% INCLUDE 'header.inc' %]
|
|
[% INCLUDE 'patron-search.inc' %]
|
|
|
|
<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> › <a href="/cgi-bin/koha/members/members-home.pl">Patrons</a> › Account for [% INCLUDE 'patron-title.inc' %]</div>
|
|
|
|
<div class="main container-fluid">
|
|
<div class="row">
|
|
<div class="col-sm-10 col-sm-push-2">
|
|
<main>
|
|
|
|
[% INCLUDE 'members-toolbar.inc' %]
|
|
<form action="/cgi-bin/koha/members/boraccount.pl" method="get"><input type="hidden" name="borrowernumber" id="borrowernumber" value="[% patron.borrowernumber | html %]" /></form>
|
|
|
|
<!-- The manual invoice and credit buttons -->
|
|
<div class="statictabs">
|
|
<ul>
|
|
<li class="active"><a href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% patron.borrowernumber | uri %]">Transactions</a></li>
|
|
<li><a href="/cgi-bin/koha/members/pay.pl?borrowernumber=[% patron.borrowernumber | uri %]" >Make a payment</a></li>
|
|
<li><a href="/cgi-bin/koha/members/maninvoice.pl?borrowernumber=[% patron.borrowernumber | uri %]" >Create manual invoice</a></li>
|
|
<li><a href="/cgi-bin/koha/members/mancredit.pl?borrowernumber=[% patron.borrowernumber | uri %]" >Create manual credit</a></li>
|
|
</ul>
|
|
<div class="tabs-container">
|
|
[% INCLUDE 'renew_results.inc' renew_results=renew_results %]
|
|
<!-- The table with the account items -->
|
|
<table id="table_account_fines">
|
|
<thead>
|
|
<tr>
|
|
<th class="title-string">Date</th>
|
|
<th>Account type</th>
|
|
<th>Description of charges</th>
|
|
<th>Barcode</th>
|
|
<th>Due date</th>
|
|
<th>Return date</th>
|
|
<th>Home library</th>
|
|
<th>Note</th>
|
|
<th>Amount</th>
|
|
<th>Outstanding</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
|
|
<!-- FIXME: Shouldn't hardcode dollar signs, since Euro or Pound might be needed -->
|
|
[% FOREACH account IN accounts %]
|
|
|
|
<tr>
|
|
<td><span title="[% account.date | html %]">[% account.date |$KohaDates %]</span></td>
|
|
<td>[% PROCESS account_type_description account=account %]</td>
|
|
<td>
|
|
[%- IF account.payment_type %][% AuthorisedValues.GetByCode('PAYMENT_TYPE', account.payment_type) | html %][% END %]
|
|
[%- IF account.description %][% account.description | html %][% END %]
|
|
[% IF ( account.itemnumber ) %]<a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=[% account.item.biblionumber | uri %]&itemnumber=[% account.itemnumber | uri %]">[% account.item.biblio.title | html %]</a>[% END %]</td>
|
|
<td>[% IF ( account.itemnumber ) %]<a href="/cgi-bin/koha/catalogue/moredetail.pl?itemnumber=[% account.itemnumber | uri %]&biblionumber=[% account.item.biblionumber | uri %]#item[% account.itemnumber | uri %]">[% account.item.barcode | html %]</a>[% END %]</td>
|
|
<td>[% IF ( account.issue_id ) %][% account.checkout.date_due | $KohaDates as_due_date => 1 %][% END %]</td>
|
|
<td>[% IF ( account.issue_id ) %][% account.checkout.returndate | $KohaDates with_hours => 1 %][% END %]</td>
|
|
<td>[% IF account.itemnumber %][% Branches.GetName( account.item.homebranch ) | html %][% END %]</td>
|
|
<td>[% account.note | html_line_break %]</td>
|
|
[% IF account.amount <= 0 %]<td class="credit" style="text-align: right;">[% ELSE %]<td class="debit" style="text-align: right;">[% END %][% account.amount | $Price %]</td>
|
|
[% IF account.amountoutstanding <= 0 %]<td class="credit" style="text-align: right;">[% ELSE %]<td class="debit" style="text-align: right;">[% END %][% account.amountoutstanding | $Price %]</td>
|
|
<td class="actions">
|
|
[% IF ( account.is_credit ) %]
|
|
<a target="_blank" href="printfeercpt.pl?action=print&accountlines_id=[% account.accountlines_id | uri %]&borrowernumber=[% account.borrowernumber | uri %]" class="btn btn-default btn-xs"><i class="fa fa-print"></i> Print</a>
|
|
[% ELSE %]
|
|
<a target="_blank" href="printinvoice.pl?action=print&accountlines_id=[% account.accountlines_id | uri %]&borrowernumber=[% account.borrowernumber | uri %]" class="btn btn-default btn-xs"><i class="fa fa-print"></i> Print</a>
|
|
[% END %]
|
|
<a href="accountline-details.pl?accountlines_id=[% account.accountlines_id | uri %]" class="btn btn-default btn-xs"><i class="fa fa-list"></i> Details</a>
|
|
[% IF account.is_credit %]
|
|
<a href="boraccount.pl?action=void&accountlines_id=[% account.accountlines_id | uri %]&borrowernumber=[% account.borrowernumber | uri %]" class="btn btn-default btn-xs void"><i class="fa fa-ban"></i> Void</a>
|
|
[% END %]
|
|
[% 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') && !(account.debit_type_code == 'PAYOUT') %]
|
|
<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 %]
|
|
[% IF CAN_user_updatecharges_discount && account.is_debit && ( account.amountoutstanding == account.amount ) && !(account.debit_type_code == 'PAYOUT') %]
|
|
<button type="button" data-toggle="modal" data-target="#applyDiscountModal" 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-percent"></i> Apply discount</button>
|
|
[% END %]
|
|
</td>
|
|
</tr>
|
|
|
|
[% END %]
|
|
<tfoot>
|
|
<tr>
|
|
<td colspan="9">Total due</td>
|
|
[% IF ( totalcredit ) %]
|
|
<td class="credit" style="text-align: right;">[% total | $Price %]</td>
|
|
[% ELSE %]
|
|
<td class="debit"style="text-align: right;">[% total | $Price %]</td>
|
|
[% END %]
|
|
<td></td>
|
|
</tr>
|
|
</tfoot>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
</main>
|
|
</div> <!-- /.col-sm-10.col-sm-push-2 -->
|
|
|
|
<div class="col-sm-2 col-sm-pull-10">
|
|
<aside>
|
|
[% INCLUDE 'circ-menu.inc' %]
|
|
</aside>
|
|
</div> <!-- /.col-sm-2.col-sm-pull-10 -->
|
|
</div> <!-- /.row -->
|
|
|
|
<!-- Issue payout modal -->
|
|
<div class="modal" id="issuePayoutModal" tabindex="-1" role="dialog" aria-labelledby="issuePayoutLabel">
|
|
<form id="payout_form" action="/cgi-bin/koha/members/boraccount.pl" method="get" enctype="multipart/form-data" class="validated">
|
|
<input type="hidden" name="accountlines_id" value="" id="payoutline">
|
|
<input type="hidden" name="action" value="payout">
|
|
<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">×</span></button>
|
|
<h4 class="modal-title" id="issuePayoutLabel">Issue payout</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<fieldset class="rows">
|
|
<ol>
|
|
<li>
|
|
<span id="paid" class="label">Outstanding credit: </span><span>[% payout.amount | $Price %]</span>
|
|
</li>
|
|
<li>
|
|
<label class="required" for="amount">Returned to patron: </label>
|
|
<input type="number" step="0.01" id="amount" name="amount" min="0.00" required="required">
|
|
<span class="required">Required</span>
|
|
</li>
|
|
[% SET payment_types = AuthorisedValues.GetAuthValueDropbox('PAYMENT_TYPE') %]
|
|
[% SET excluded = ['SIP00', 'SIP01', 'SIP02'] %]
|
|
[% IF payment_types > 3 %]
|
|
<li>
|
|
<label for="transaction_type">Transaction type: </label>
|
|
<select name="transaction_type" id="payout_transaction_type">
|
|
[% FOREACH pt IN payment_types %]
|
|
[% UNLESS excluded.grep("^$pt.authorised_value\$").size %]
|
|
<option value="[% pt.authorised_value | html %]">[% pt.lib | html %]</option>
|
|
[% END %]
|
|
[% END %]
|
|
</select>
|
|
</li>
|
|
[% END %]
|
|
|
|
[% IF Koha.Preference('UseCashRegisters') %]
|
|
<li>
|
|
<label for="registerid">Cash register: </label>
|
|
<select name="registerid" id="payout_registerid">
|
|
[% FOREACH register IN registers %]
|
|
[% IF register.id == registerid %]
|
|
<option value="[% register.id | html %]" selected="selected">[% register.name | html %]</option>
|
|
[% ELSE %]
|
|
<option value="[% register.id | html %]">[% register.name | html %]</option>
|
|
[% END %]
|
|
[% END %]
|
|
</select>
|
|
</li>
|
|
[% END %]
|
|
|
|
</ol>
|
|
</fieldset> <!-- /.rows -->
|
|
</div> <!-- /.modal-body -->
|
|
<div class="modal-footer">
|
|
<input type="hidden" name="op" value="payout">
|
|
<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> <!-- /#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">×</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="refund_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="registerid">Cash register: </label>
|
|
<select name="registerid" id="refund_registerid">
|
|
[% FOREACH register IN registers %]
|
|
[% IF register.id == registerid %]
|
|
<option value="[% register.id | html %]" selected="selected">[% register.name | html %]</option>
|
|
[% ELSE %]
|
|
<option value="[% register.id | html %]">[% register.name | html %]</option>
|
|
[% END %]
|
|
[% END %]
|
|
</select>
|
|
</li>
|
|
[% END %]
|
|
|
|
</ol>
|
|
</fieldset> <!-- /.rows -->
|
|
</div> <!-- /.modal-body -->
|
|
<div class="modal-footer">
|
|
<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 -->
|
|
|
|
<!-- Apply discount modal -->
|
|
<div class="modal" id="applyDiscountModal" tabindex="-1" role="dialog" aria-labelledby="applyDiscountLabel">
|
|
<form id="discount_form" action="/cgi-bin/koha/members/boraccount.pl" method="get" enctype="multipart/form-data" class="validated">
|
|
<input type="hidden" name="accountlines_id" value="" id="discountline">
|
|
<input type="hidden" name="action" value="discount">
|
|
<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">×</span></button>
|
|
<h4 class="modal-title" id="applyDiscountLabel">Apply discount</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<fieldset class="rows">
|
|
<ol>
|
|
<li>
|
|
<span id="item" class="label">Account type: </span><span></span>
|
|
</li>
|
|
<li>
|
|
<span id="charged" class="label">Amount charged: </span><span></span>
|
|
</li>
|
|
<li>
|
|
<label class="required" for="amount">Discount to apply: </label>
|
|
<input type="number" step="0.01" id="discount" name="amount" min="0.00" required="required">
|
|
<span class="required">Required</span>
|
|
</li>
|
|
</ol>
|
|
</fieldset> <!-- /.rows -->
|
|
</div> <!-- /.modal-body -->
|
|
<div class="modal-footer">
|
|
<input type="hidden" name="op" value="discount">
|
|
<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> <!-- /#discount_form -->
|
|
</div> <!-- /#applyDiscountModal -->
|
|
|
|
[% MACRO jsinclude BLOCK %]
|
|
[% INCLUDE 'datatables.inc' %]
|
|
[% INCLUDE 'columns_settings.inc' %]
|
|
[% INCLUDE 'str/members-menu.inc' %]
|
|
[% Asset.js("js/members-menu.js") | $raw %]
|
|
<script>
|
|
$(document).ready(function() {
|
|
[% IF payment_id && Koha.Preference('FinePaymentAutoPopup') %]
|
|
window.open('/cgi-bin/koha/members/printfeercpt.pl?action=print&change_given=[% change_given | html %]&accountlines_id=[% payment_id | html %]&borrowernumber=[% patron.borrowernumber | html %]', '_blank');
|
|
[% END %]
|
|
|
|
var txtActivefilter = _("Filter paid transactions");
|
|
var txtInactivefilter = _("Show all transactions");
|
|
var columns_settings = [% ColumnsSettings.GetColumns('members', 'fines', 'account-fines', 'json') | $raw %];
|
|
var table_account_fines = KohaTable("table_account_fines", {
|
|
"sPaginationType": "full",
|
|
'aaSorting': [[0, 'desc']],
|
|
"sDom": 'C<"top pager"ilpfB><"#filter_c">tr<"bottom pager"ip>',
|
|
"aoColumnDefs": [
|
|
{ "sType": "title-string", "aTargets" : [ "title-string" ] },
|
|
{ "bSortable": false, "bSearchable": false, "aTargets": [-1] }
|
|
]
|
|
}, columns_settings);
|
|
$("#filter_c").html('<p><a href="#" id="filter_transacs"><i class="fa fa-filter"></i> '+txtActivefilter+'</a>');
|
|
$('#filter_transacs').click(function(e) {
|
|
e.preventDefault();
|
|
if ($(this).hasClass('filtered')) {
|
|
var filteredValue = '';
|
|
$(this).html('<i class="fa fa-filter"></i> '+txtActivefilter);
|
|
} else { //Not filtered. Let's do it!
|
|
var filteredValue = '^((?!0.00).*)$'; //Filter not matching 0.00 http://stackoverflow.com/a/406408
|
|
$(this).html('<i class="fa fa-filter"></i> '+txtInactivefilter);
|
|
}
|
|
table_account_fines.fnFilter(filteredValue, 9, true, false);
|
|
$(this).toggleClass('filtered');
|
|
});
|
|
|
|
$(".void").on("click",function(e){
|
|
if( confirm( _("Are you sure you want to void this credit?") ) ) {
|
|
return true;
|
|
} else {
|
|
e.preventDefault();
|
|
}
|
|
});
|
|
|
|
$("#issuePayoutModal").on("shown.bs.modal", function(e){
|
|
var button = $(e.relatedTarget);
|
|
var accountline = button.data('accountline');
|
|
$('#payoutline').val(accountline);
|
|
var amount = button.data('amount') * -1;
|
|
$("#paid + span").replaceWith(amount);
|
|
$("#amount").attr({ "value": amount, "max": amount });
|
|
$("#amount, #payout_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, #refund_transaction_type").focus();
|
|
});
|
|
|
|
$("#applyDiscountModal").on("shown.bs.modal", function(e){
|
|
var button = $(e.relatedTarget);
|
|
var item = button.data('item');
|
|
$("#item + span").replaceWith(item);
|
|
var accountline = button.data('accountline');
|
|
$('#discountline').val(accountline);
|
|
var amount = button.data('amount');
|
|
$("#charged + span").replaceWith(amount);
|
|
$("#discount").attr({ "max": amount });
|
|
$("#discount").focus();
|
|
});
|
|
});
|
|
</script>
|
|
[% END %]
|
|
|
|
[% INCLUDE 'intranet-bottom.inc' %]
|