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>
280 lines
9.9 KiB
Perl
Executable file
280 lines
9.9 KiB
Perl
Executable file
#!/usr/bin/perl
|
|
# Copyright 2009,2010 PTFS Inc.
|
|
# Copyright 2011 PTFS-Europe Ltd
|
|
#
|
|
# This file is part of Koha.
|
|
#
|
|
# Koha is free software; you can redistribute it and/or modify it
|
|
# under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# Koha is distributed in the hope that it will be useful, but
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with Koha; if not, see <http://www.gnu.org/licenses>.
|
|
|
|
use Modern::Perl;
|
|
use URI::Escape;
|
|
use CGI qw ( -utf8 );
|
|
|
|
use C4::Context;
|
|
use C4::Auth;
|
|
use C4::Output;
|
|
use C4::Members;
|
|
use C4::Accounts;
|
|
use C4::Koha;
|
|
|
|
use Koha::Cash::Registers;
|
|
use Koha::Patrons;
|
|
use Koha::Patron::Categories;
|
|
use Koha::AuthorisedValues;
|
|
use Koha::Account;
|
|
use Koha::Token;
|
|
use Koha::DateUtils;
|
|
|
|
my $input = CGI->new();
|
|
|
|
my $payment_id = $input->param('payment_id');
|
|
my $writeoff_individual = $input->param('writeoff_individual');
|
|
my $change_given = $input->param('change_given');
|
|
my $type = scalar $input->param('type') || 'PAYMENT';
|
|
|
|
my $updatecharges_permissions = ($writeoff_individual || $type eq 'writeoff') ? 'writeoff' : 'remaining_permissions';
|
|
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
|
|
{ template_name => 'members/paycollect.tt',
|
|
query => $input,
|
|
type => 'intranet',
|
|
authnotrequired => 0,
|
|
flagsrequired => { borrowers => 'edit_borrowers', updatecharges => $updatecharges_permissions },
|
|
debug => 1,
|
|
}
|
|
);
|
|
|
|
# get borrower details
|
|
my $borrowernumber = $input->param('borrowernumber');
|
|
my $logged_in_user = Koha::Patrons->find( $loggedinuser );
|
|
my $patron = Koha::Patrons->find( $borrowernumber );
|
|
output_and_exit_if_error( $input, $cookie, $template, { module => 'members', logged_in_user => $logged_in_user, current_patron => $patron } );
|
|
|
|
my $borrower = $patron->unblessed;
|
|
my $account = $patron->account;
|
|
my $category = $patron->category;
|
|
my $user = $input->remote_user;
|
|
|
|
my $library_id = C4::Context->userenv->{'branch'};
|
|
my $total_due = $account->outstanding_debits->total_outstanding;
|
|
|
|
my $total_paid = $input->param('paid');
|
|
my $total_collected = $input->param('collected');
|
|
|
|
my $selected_lines = $input->param('selected'); # comes from pay.pl
|
|
my $pay_individual = $input->param('pay_individual');
|
|
my $selected_accts = $input->param('selected_accts'); # comes from paycollect.pl
|
|
my $payment_note = uri_unescape scalar $input->param('payment_note');
|
|
my $payment_type = scalar $input->param('payment_type');
|
|
my $accountlines_id;
|
|
|
|
my $registerid;
|
|
if ( C4::Context->preference('UseCashRegisters') ) {
|
|
$registerid = $input->param('registerid');
|
|
my $registers = Koha::Cash::Registers->search(
|
|
{ branch => $library_id, archived => 0 },
|
|
{ order_by => { '-asc' => 'name' } }
|
|
);
|
|
|
|
if ( !$registers->count ) {
|
|
$template->param( error_registers => 1 );
|
|
}
|
|
else {
|
|
|
|
if ( !$registerid ) {
|
|
my $default_register = Koha::Cash::Registers->find(
|
|
{ branch => $library_id, branch_default => 1 } );
|
|
$registerid = $default_register->id if $default_register;
|
|
}
|
|
$registerid = $registers->next->id if !$registerid;
|
|
|
|
$template->param(
|
|
registerid => $registerid,
|
|
registers => $registers,
|
|
);
|
|
}
|
|
}
|
|
|
|
if ( $pay_individual || $writeoff_individual ) {
|
|
if ($pay_individual) {
|
|
$template->param( pay_individual => 1 );
|
|
} elsif ($writeoff_individual) {
|
|
$template->param( writeoff_individual => 1 );
|
|
}
|
|
my $debit_type_code = $input->param('debit_type_code');
|
|
$accountlines_id = $input->param('accountlines_id');
|
|
my $amount = $input->param('amount');
|
|
my $amountoutstanding = $input->param('amountoutstanding');
|
|
my $itemnumber = $input->param('itemnumber');
|
|
my $description = $input->param('description');
|
|
my $title = $input->param('title');
|
|
$total_due = $amountoutstanding;
|
|
$template->param(
|
|
debit_type_code => $debit_type_code,
|
|
accountlines_id => $accountlines_id,
|
|
amount => $amount,
|
|
amountoutstanding => $amountoutstanding,
|
|
title => $title,
|
|
itemnumber => $itemnumber,
|
|
individual_description => $description,
|
|
payment_note => $payment_note,
|
|
);
|
|
} elsif ($selected_lines) {
|
|
$total_due = $input->param('amt');
|
|
$template->param(
|
|
selected_accts => $selected_lines,
|
|
amt => $total_due,
|
|
selected_accts_notes => scalar $input->param('notes'),
|
|
);
|
|
}
|
|
|
|
my @selected_accountlines;
|
|
if ( $selected_accts ) {
|
|
if ( $selected_accts =~ /^([\d,]*).*/ ) {
|
|
$selected_accts = $1; # ensure passing no junk
|
|
}
|
|
my @acc = split /,/, $selected_accts;
|
|
|
|
@selected_accountlines = Koha::Account::Lines->search(
|
|
{
|
|
borrowernumber => $borrowernumber,
|
|
amountoutstanding => { '<>' => 0 },
|
|
accountlines_id => { 'in' => \@acc },
|
|
},
|
|
{ order_by => 'date' }
|
|
);
|
|
|
|
$total_due = 0; # Reset and recalculate total due
|
|
map { $total_due += $_->amountoutstanding } @selected_accountlines;
|
|
}
|
|
|
|
|
|
if ( $total_paid and $total_paid ne '0.00' ) {
|
|
$total_paid = $total_due if (abs($total_paid - $total_due) < 0.01) && C4::Context->preference('RoundFinesAtPayment');
|
|
if ( $total_paid < 0 or $total_paid > $total_due ) {
|
|
$template->param(
|
|
error_over => 1,
|
|
total_due => $total_due
|
|
);
|
|
} elsif ( $total_collected < $total_paid && !( $writeoff_individual || $type eq 'writeoff') ) {
|
|
$template->param(
|
|
error_under => 1,
|
|
total_paid => $total_paid
|
|
);
|
|
} else {
|
|
output_and_exit( $input, $cookie, $template, 'wrong_csrf_token' )
|
|
unless Koha::Token->new->check_csrf( {
|
|
session_id => $input->cookie('CGISESSID'),
|
|
token => scalar $input->param('csrf_token'),
|
|
});
|
|
|
|
my $url;
|
|
my $pay_result;
|
|
if ($pay_individual) {
|
|
my $line = Koha::Account::Lines->find($accountlines_id);
|
|
$pay_result = $account->pay(
|
|
{
|
|
lines => [$line],
|
|
amount => $total_paid,
|
|
library_id => $library_id,
|
|
note => $payment_note,
|
|
interface => C4::Context->interface,
|
|
payment_type => $payment_type,
|
|
cash_register => $registerid
|
|
}
|
|
);
|
|
$payment_id = $pay_result->{payment_id};
|
|
|
|
$url = "/cgi-bin/koha/members/pay.pl";
|
|
} else {
|
|
if ($selected_accts) {
|
|
if ( $total_paid > $total_due ) {
|
|
$template->param(
|
|
error_over => 1,
|
|
total_due => $total_due
|
|
);
|
|
} else {
|
|
my $note = $input->param('selected_accts_notes');
|
|
|
|
$pay_result = $account->pay(
|
|
{
|
|
type => $type,
|
|
amount => $total_paid,
|
|
library_id => $library_id,
|
|
lines => \@selected_accountlines,
|
|
note => $note,
|
|
interface => C4::Context->interface,
|
|
payment_type => $payment_type,
|
|
cash_register => $registerid
|
|
}
|
|
);
|
|
}
|
|
$payment_id = $pay_result->{payment_id};
|
|
}
|
|
else {
|
|
my $note = $input->param('selected_accts_notes');
|
|
$pay_result = $payment_id = $account->pay(
|
|
{
|
|
amount => $total_paid,
|
|
library_id => $library_id,
|
|
note => $note,
|
|
payment_type => $payment_type,
|
|
interface => C4::Context->interface,
|
|
payment_type => $payment_type,
|
|
cash_register => $registerid
|
|
}
|
|
);
|
|
}
|
|
$payment_id = $pay_result->{payment_id};
|
|
|
|
$url = "/cgi-bin/koha/members/boraccount.pl";
|
|
}
|
|
# It's possible renewals took place, parse any renew results
|
|
# and pass on
|
|
my @renew_result = ();
|
|
foreach my $ren( @{$pay_result->{renew_result}} ) {
|
|
my $str = "renew_result=$ren->{itemnumber},$ren->{success},";
|
|
my $app = $ren->{success} ?
|
|
uri_escape(
|
|
output_pref({ dt => $ren->{due_date}, as_due_date => 1 })
|
|
) : $ren->{error};
|
|
push @renew_result, "${str}${app}";
|
|
}
|
|
my $append = scalar @renew_result ? '&' . join('&', @renew_result) : '';
|
|
|
|
$url .= "?borrowernumber=$borrowernumber&payment_id=$payment_id&change_given=${change_given}${append}";
|
|
|
|
print $input->redirect($url);
|
|
}
|
|
} else {
|
|
$total_paid = '0.00'; #TODO not right with pay_individual
|
|
}
|
|
|
|
$template->param(%$borrower);
|
|
|
|
if ( $input->param('error_over') ) {
|
|
$template->param( error_over => 1, total_due => scalar $input->param('amountoutstanding') );
|
|
}
|
|
|
|
$template->param(
|
|
payment_id => $payment_id,
|
|
|
|
type => $type,
|
|
borrowernumber => $borrowernumber, # some templates require global
|
|
patron => $patron,
|
|
total => $total_due,
|
|
|
|
csrf_token => Koha::Token->new->generate_csrf( { session_id => scalar $input->cookie('CGISESSID') } ),
|
|
);
|
|
|
|
output_html_with_http_headers $input, $cookie, $template->output;
|