From 05e30722f771de5bfdbc425d3f8010246e11126f Mon Sep 17 00:00:00 2001 From: Nick Clemens Date: Wed, 23 Aug 2017 16:13:39 +0000 Subject: [PATCH] Bug 19166 - Add the ability to add adjustments to an invoice This patchset adds the ability to add adjustments to an invoice, one can provide a reason, an adjustment amount, select a budget, and choose whether to encumber the funds before the invoice is closed or not To test: 1 - Create a new invoice with or without a shipping cost 2 - Note there are no existing adjustments 3 - Add an adjustment 4 - Submit the form withno changes, nothing happens 5 - Update the adjustment you created, ensure changes are saved but no extra adjustment created 6 - Add another invoice prodiving only reason or amount (you can have 0 value adjustments) 7 - Verify the adjustment total at bottom is correct 8 - Recieve some orders 9 - Verify totals are correct Conflicts: C4/Budgets.pm --- C4/Budgets.pm | 21 ++++ Koha/InvoiceAdjustment.pm | 44 ++++++++ Koha/InvoiceAdjustments.pm | 51 +++++++++ acqui/invoice.pl | 44 ++++++++ acqui/ordered.pl | 8 ++ acqui/spent.pl | 7 ++ .../intranet-tmpl/prog/en/modules/acqui/invoice.tt | 118 ++++++++++++++++++++- .../intranet-tmpl/prog/en/modules/acqui/ordered.tt | 10 ++ .../intranet-tmpl/prog/en/modules/acqui/spent.tt | 13 ++- t/db_dependent/Koha/InvoiceAdjustments.t | 67 ++++++++++++ 10 files changed, 379 insertions(+), 4 deletions(-) create mode 100644 Koha/InvoiceAdjustment.pm create mode 100644 Koha/InvoiceAdjustments.pm create mode 100644 t/db_dependent/Koha/InvoiceAdjustments.t diff --git a/C4/Budgets.pm b/C4/Budgets.pm index 10f5147..0905576 100644 --- a/C4/Budgets.pm +++ b/C4/Budgets.pm @@ -22,6 +22,7 @@ use strict; use C4::Context; use Koha::Database; use Koha::Patrons; +use Koha::InvoiceAdjustments; use C4::Debug; use vars qw(@ISA @EXPORT); @@ -349,6 +350,11 @@ sub GetBudgetSpent { my ($shipmentcost_sum) = $sth->fetchrow_array; $sum += $shipmentcost_sum; + my $adjustments = Koha::InvoiceAdjustments->search({budget_id => $budget_id, closedate => { '!=' => undef } },{ join => 'invoiceid' }); + while ( my $adj = $adjustments->next ){ + $sum += $adj->adjustment; + } + return $sum; } @@ -365,6 +371,21 @@ sub GetBudgetOrdered { $sth->execute($budget_id); my $sum = $sth->fetchrow_array; + $sth = $dbh->prepare(qq| + SELECT SUM(shipmentcost) AS sum + FROM aqinvoices + WHERE shipmentcost_budgetid = ? + AND closedate IS NULL + |); + $sth->execute($budget_id); + my ($shipmentcost_sum) = $sth->fetchrow_array; + $sum += $shipmentcost_sum; + + my $adjustments = Koha::InvoiceAdjustments->search({budget_id => $budget_id, encumber_open => 1, closedate => undef},{ join => 'invoiceid' }); + while ( my $adj = $adjustments->next ){ + $sum += $adj->adjustment; + } + return $sum; } diff --git a/Koha/InvoiceAdjustment.pm b/Koha/InvoiceAdjustment.pm new file mode 100644 index 0000000..2c02f43 --- /dev/null +++ b/Koha/InvoiceAdjustment.pm @@ -0,0 +1,44 @@ +package Koha::InvoiceAdjustment; + +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Carp; + +use Koha::Database; + +use base qw(Koha::Object); + +=head1 NAME + +Koha::InvoiceAdjustment - Koha Invoice Adjustment class + +=head1 API + +=head2 Class Methods + +=cut + +=head3 type + +=cut + +sub _type { + return 'InvoiceAdjustment'; +} + +1; diff --git a/Koha/InvoiceAdjustments.pm b/Koha/InvoiceAdjustments.pm new file mode 100644 index 0000000..e3f6fbb --- /dev/null +++ b/Koha/InvoiceAdjustments.pm @@ -0,0 +1,51 @@ +package Koha::InvoiceAdjustments; + +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; +use Koha::InvoiceAdjustment; + +use Carp; + +use Koha::Database; + +use Koha::Rating; + +use base qw(Koha::Objects); + +=head1 NAME + +Koha::InvoiceAdjustments - Koha Invoice Adjustments Object set class + +=head1 API + +=head2 Class Methods + +=cut + +=head3 type + +=cut + +sub _type { + return 'InvoiceAdjustment'; +} + +sub object_class { + return 'Koha::InvoiceAdjustment'; +} + +1; diff --git a/acqui/invoice.pl b/acqui/invoice.pl index dd1360f..daf0e66 100755 --- a/acqui/invoice.pl +++ b/acqui/invoice.pl @@ -39,6 +39,7 @@ use Koha::Acquisition::Booksellers; use Koha::Acquisition::Currencies; use Koha::DateUtils; use Koha::Misc::Files; +use Koha::InvoiceAdjustments; my $input = new CGI; my ( $template, $loggedinuser, $cookie, $flags ) = get_template_and_user( @@ -109,7 +110,47 @@ elsif ( $op && $op eq 'delete' ) { exit 0; } } +elsif ( $op && $op eq 'del_adj' ) { + my $adjustment_id = $input->param('adjustment_id'); + my $del_adj = Koha::InvoiceAdjustments->find( $adjustment_id ); + $del_adj->delete() if ($del_adj); +} +elsif ( $op && $op eq 'mod_adj' ) { + my @adjustment_id = $input->multi_param('adjustment_id'); + my @adjustment = $input->multi_param('adjustment'); + my @reason = $input->multi_param('reason'); + my @note = $input->multi_param('note'); + my @budget_id = $input->multi_param('budget_id'); + my @encumber_open = $input->multi_param('encumber_open'); + my %e_open = map { $_ => 1 } @encumber_open; + for( my $i=0; $i < scalar @adjustment; $i++ ){ + if( $adjustment_id[$i] eq 'new' ){ + next unless ( $adjustment[$i] || $reason[$i] ); + my $new_adj = Koha::InvoiceAdjustment->new({ + invoiceid => $invoiceid, + adjustment => $adjustment[$i], + reason => $reason[$i], + note => $note[$i], + budget_id => $budget_id[$i] || undef, + encumber_open => $encumber_open[$i], + }); + $new_adj->store(); + } + else { + my $old_adj = Koha::InvoiceAdjustments->find( $adjustment_id[$i] ); + unless ( $old_adj->adjustment == $adjustment[$i] && $old_adj->reason eq $reason[$i] && $old_adj->budget_id == $budget_id[$i] && $old_adj->encumber_open == $e_open{$adjustment_id[$i]} && $old_adj->note eq $note[$i] ){ + $old_adj->timestamp(undef); + $old_adj->adjustment( $adjustment[$i] ); + $old_adj->reason( $reason[$i] ); + $old_adj->note( $note[$i] ); + $old_adj->budget_id( $budget_id[$i] || undef ); + $old_adj->encumber_open( $e_open{$adjustment_id[$i]} ? 1 : 0 ); + $old_adj->update(); + } + } + } +} my $details = GetInvoiceDetails($invoiceid); my $bookseller = Koha::Acquisition::Booksellers->find( $details->{booksellerid} ); @@ -160,6 +201,9 @@ foreach my $budget (@$budgets) { push @budgets_loop, \%line; } +my $adjustments = Koha::InvoiceAdjustments->search({ invoiceid => $details->{'invoiceid'} }); +if ( $adjustments ) { $template->param( adjustments => $adjustments ); } + $template->param( invoiceid => $details->{'invoiceid'}, invoicenumber => $details->{'invoicenumber'}, diff --git a/acqui/ordered.pl b/acqui/ordered.pl index 5c2cc6d..3ebfda5 100755 --- a/acqui/ordered.pl +++ b/acqui/ordered.pl @@ -33,6 +33,7 @@ use warnings; use CGI qw ( -utf8 ); use C4::Auth; use C4::Output; +use Koha::InvoiceAdjustments; my $dbh = C4::Context->dbh; my $input = new CGI; @@ -96,12 +97,19 @@ while ( my $data = $sth->fetchrow_hashref ) { $total += $subtotal; } } + +my $adjustments = Koha::InvoiceAdjustments->search({budget_id => $fund_id, closedate => undef, encumber_open => 1 }, { join => 'invoiceid' } ); +while ( my $adj = $adjustments->next ){ + $total += $adj->adjustment; +} + $total = sprintf( "%.2f", $total ); $template->{VARS}->{'fund'} = $fund_id; $template->{VARS}->{'ordered'} = \@ordered; $template->{VARS}->{'total'} = $total; $template->{VARS}->{'fund_code'} = $fund_code; +$template->{VARS}->{'adjustments'} = $adjustments; $sth->finish; diff --git a/acqui/spent.pl b/acqui/spent.pl index f31b283..52b6133 100755 --- a/acqui/spent.pl +++ b/acqui/spent.pl @@ -35,6 +35,7 @@ use C4::Output; use strict; use warnings; use CGI qw ( -utf8 ); +use Koha::InvoiceAdjustments; my $dbh = C4::Context->dbh; my $input = new CGI; @@ -119,6 +120,11 @@ while (my $data = $sth->fetchrow_hashref) { } $sth->finish; +my $adjustments = Koha::InvoiceAdjustments->search({budget_id => $bookfund, closedate => { '!=' => undef } }, { join => 'invoiceid' } ); +while ( my $adj = $adjustments->next ){ + $total += $adj->adjustment; +} + $total = sprintf( "%.2f", $total ); $template->param( @@ -126,6 +132,7 @@ $template->param( spent => \@spent, subtotal => $subtotal, shipmentcosts => \@shipmentcosts, + adjustments => $adjustments, total => $total, fund_code => $fund_code ); diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/invoice.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/invoice.tt index 2061814..6d931a6 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/invoice.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/invoice.tt @@ -2,6 +2,8 @@ [% USE KohaDates %] [% USE Price %] [% SET footerjs = 1 %] +[% USE AuthorisedValues %] + [% INCLUDE 'doc-head-open.inc' %] Koha › Acquisitions › Invoice @@ -81,6 +83,112 @@ [% END %] +
+ + + + + + + + + + + + [% IF (adjustments.count > 0) %] + + [% total_adj = 0 %] + [% FOREACH adjustment IN adjustments %] + [% total_adj = total_adj + adjustment.adjustment %] + + + + + + + [% IF adjustment.encumber_open %] + + [% ELSE %] + + [% END %] + + + [% END %] + [% END %] + + + + + + + + + +
IdAmountReasonNoteFundEncumber while invoice open 
Current adjustments
[% adjustment.adjustment_id %] + [% reasons = AuthorisedValues.Get("ADJ_REASON") %] + [% IF reasons %] + + [% ELSE %] +

None

+ + [% END %] +
+ + + + + + + Delete +
Add an adjustment
New + [% reasons = AuthorisedValues.Get("ADJ_REASON") %] + [% IF reasons %] + + [% ELSE %] +

None

+ [% END %] +
+ +
+ + +

Go to receipt page [% IF Koha.Preference('AcqEnableFiles') %]| Manage invoice files[% END %] @@ -161,11 +269,11 @@   - Total + Shipment cost ([% currency.symbol %]) + Total + Adjustments + Shipment cost ([% currency.symbol %]) [% total_quantity %] - [% total_tax_excluded_shipment | $Price %] + [% total_tax_excluded_shipment + total_adj | $Price %] [% total_tax_included_shipment | $Price %]   [% total_tax_value | $Price %] @@ -174,7 +282,11 @@ [% ELSE %] -

No orders yet

+

No orders yet

+ [% IF adjustments.count > 0 || shipmentcost > 0 %] +

Adjustments plus shipping:[% total_adj + shipmentcost | $Price %]

+ [% END %] +
[% END %] [% IF ( (Koha.Preference('AcqEnableFiles')) && files ) %]
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/ordered.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/ordered.tt index 19e9618..51c9de3 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/ordered.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/ordered.tt @@ -84,6 +84,16 @@ [% END %] + [% IF ( adjustments.count > 0 ) %] + [% FOREACH adjustment IN adjustments %] + + + Adjustment cost for invoice [% adjustment.invoiceid %] + [% adjustment.adjustment %] + + [% END %] + + [% END %] Total diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/spent.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/spent.tt index 0b1bdc6..f22b661 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/spent.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/spent.tt @@ -88,11 +88,13 @@ [% END %] - [% IF shipmentcosts.size %] + [% IF shipmentcosts.size || ( adjustments.count > 0 ) %] Sub total [% subtotal %] + [% END %] + [% IF shipmentcosts.size %] [% FOREACH shipmentcost IN shipmentcosts %] @@ -101,6 +103,15 @@ [% END %] [% END %] + [% IF ( adjustments.count > 0 ) %] + [% FOREACH adjustment IN adjustments %] + + + Adjustment cost for invoice [% adjustment.invoiceid %] + [% adjustment.adjustment %] + + [% END %] + [% END %] TOTAL [% total %] diff --git a/t/db_dependent/Koha/InvoiceAdjustments.t b/t/db_dependent/Koha/InvoiceAdjustments.t new file mode 100644 index 0000000..7fadf3e --- /dev/null +++ b/t/db_dependent/Koha/InvoiceAdjustments.t @@ -0,0 +1,67 @@ +#!/usr/bin/perl + +# Copyright 2015 Koha Development team +# +# 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 . + +use Modern::Perl; + +use Test::More tests => 6; + +use Koha::Database; + +use t::lib::TestBuilder; + +BEGIN { + use_ok('Koha::InvoiceAdjustments'); +} + +my $schema = Koha::Database->new->schema; +$schema->storage->txn_begin; + +my $builder = t::lib::TestBuilder->new; +my $nb_of_adjs = Koha::InvoiceAdjustments->search->count; +my $budget_id = $builder->build({source=>'Aqbudget'})->{budget_id}; +my $invoice_id = $builder->build({source=>'Aqinvoice'})->{invoiceid}; + +my $new_adj = Koha::InvoiceAdjustment->new({ + note => 'noted', + invoiceid => $invoice_id, + adjustment => '3', + reason => 'unreasonable', + budget_id => $budget_id, +})->store; + +like( $new_adj->adjustment_id, qr|^\d+$|, 'Adding a new adjustment should have set the adjustment_id'); + +my $new_adj2 = Koha::InvoiceAdjustment->new({ + note => 'not noted', + invoiceid => $invoice_id, + adjustment => '-3', + reason => 'unreasonable', + budget_id => $budget_id, +})->store; + +ok( $new_adj->adjustment_id < $new_adj2->adjustment_id, 'Adding a new adjustment should increment'); +is( Koha::InvoiceAdjustments->search->count, $nb_of_adjs + 2, 'The 2 adjustments should have been added' ); + +my $retrieved_adj = Koha::InvoiceAdjustments->find( $new_adj->adjustment_id ); +is( $retrieved_adj->reason, $new_adj->reason, 'Find an adjustment by id should return the correct adjustment' ); + +$retrieved_adj->delete; +is( Koha::InvoiceAdjustments->search->count, $nb_of_adjs + 1, 'Delete should have deleted the adjustment' ); + +$schema->storage->txn_rollback; -- 2.1.4