Bugzilla – Attachment 19865 Details for
Bug 10401
Add ability to merge invoices
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 10401: Add ability to merge invoices
Bug-10401-Add-ability-to-merge-invoices.patch (text/plain), 17.14 KB, created by
Jared Camins-Esakov
on 2013-07-23 13:21:38 UTC
(
hide
)
Description:
Bug 10401: Add ability to merge invoices
Filename:
MIME Type:
Creator:
Jared Camins-Esakov
Created:
2013-07-23 13:21:38 UTC
Size:
17.14 KB
patch
obsolete
>From 3eee9ce901a0dd86d0406d4d56542254c040c63f Mon Sep 17 00:00:00 2001 >From: Jared Camins-Esakov <jcamins@cpbibliography.com> >Date: Wed, 19 Jun 2013 15:19:06 -0400 >Subject: [PATCH] Bug 10401: Add ability to merge invoices > >Given how easy it is to accidentally receive items from one invoice on >multiple invoices, the ability to merge invoices can be quite handy. >This patch adds that ability to Koha's Acquisitions module. > >To test: >1) Apply patch. >2) Run unit test: > > prove t/db_dependent/Acquisition/Invoices.t >3) Create two invoices from the same vendor for merging, and receive at > least one order on each. >4) Do a search on the Invoices page that brings up both the invoices you > created. >5) Check the boxes next to the two invoices. >6) Click "Merge selected invoices." >7) Choose which invoice you want to keep (the default will be the first). >8) Click "Merge." >9) Confirm that the resulting invoice has all the orders you received > listed on it. >10) Sign off. >--- > C4/Acquisition.pm | 26 ++++ > acqui/invoice.pl | 3 + > acqui/invoices.pl | 9 ++ > .../intranet-tmpl/prog/en/css/staff-global.css | 28 +++- > .../prog/en/modules/acqui/invoices.tt | 93 +++++++++++- > t/db_dependent/Acquisition/Invoices.t | 156 ++++++++++++++++++++ > 6 files changed, 308 insertions(+), 7 deletions(-) > create mode 100644 t/db_dependent/Acquisition/Invoices.t > >diff --git a/C4/Acquisition.pm b/C4/Acquisition.pm >index 1a210b5..68bb2fe 100644 >--- a/C4/Acquisition.pm >+++ b/C4/Acquisition.pm >@@ -72,6 +72,7 @@ BEGIN { > &CloseInvoice > &ReopenInvoice > &DelInvoice >+ &MergeInvoices > > &GetItemnumbersFromOrder > >@@ -2553,6 +2554,31 @@ sub DelInvoice { > return; > } > >+=head3 MergeInvoices >+ >+ MergeInvoices($invoiceid, \@sourceids); >+ >+Merge the invoices identified by the IDs in \@sourceids into >+the invoice identified by $invoiceid. >+ >+=cut >+ >+sub MergeInvoices { >+ my ($invoiceid, $sourceids) = @_; >+ >+ return unless $invoiceid; >+ foreach my $sourceid (@$sourceids) { >+ next if $sourceid == $invoiceid; >+ my $source = GetInvoiceDetails($sourceid); >+ foreach my $order (@{$source->{'orders'}}) { >+ $order->{'invoiceid'} = $invoiceid; >+ ModOrder($order); >+ } >+ DelInvoice($source->{'invoiceid'}); >+ } >+ return; >+} >+ > 1; > __END__ > >diff --git a/acqui/invoice.pl b/acqui/invoice.pl >index e38e02d..5971ed1 100755 >--- a/acqui/invoice.pl >+++ b/acqui/invoice.pl >@@ -83,6 +83,9 @@ elsif ( $op && $op eq 'mod' ) { > ReopenInvoice($invoiceid); > } elsif ($input->param('close')) { > CloseInvoice($invoiceid); >+ } elsif ($input->param('merge')) { >+ my @sources = $input->param('merge'); >+ MergeInvoices($invoiceid, \@sources); > } > $template->param( modified => 1 ); > } >diff --git a/acqui/invoices.pl b/acqui/invoices.pl >index f30e374..451cf05 100755 >--- a/acqui/invoices.pl >+++ b/acqui/invoices.pl >@@ -36,6 +36,7 @@ use C4::Output; > use C4::Acquisition qw/GetInvoices/; > use C4::Bookseller qw/GetBookSeller/; > use C4::Branch qw/GetBranches/; >+use C4::Budgets; > > my $input = CGI->new; > my ( $template, $loggedinuser, $cookie, $flags ) = get_template_and_user( >@@ -121,6 +122,14 @@ foreach ( sort keys %$branches ) { > }; > } > >+my $budgets = GetBudgets(); >+my @budgets_loop; >+foreach my $budget (@$budgets) { >+ push @budgets_loop, $budget if CanUserUseBudget( $loggedinuser, $budget, $flags ); >+} >+ >+$template->{'VARS'}->{'budgets_loop'} = \@budgets_loop; >+ > $template->param( > do_search => ( $op and $op eq 'do_search' ) ? 1 : 0, > invoices => $invoices, >diff --git a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css b/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css >index 0fa93ab..15ca462 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css >+++ b/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css >@@ -1556,11 +1556,11 @@ div#header_search input.submit { > padding : .1em; > } > >-input[type=submit]:active, input[type=button]:active, button.submit:active { >+input[type=submit]:active, input[type=button]:active, button.submit:active, a.submit:active { > border : 1px inset #999999; > } > >-input[type=submit], input[type=reset], input[type=button], input.submit, button.submit { >+input[type=submit], input[type=reset], input[type=button], input.submit, button.submit, a.submit { > border: 1px outset #999999; > border-top-color: #666; > border-left-color: #666; >@@ -1581,16 +1581,21 @@ input[type=submit]:disabled, > input[type=reset]:disabled, > input[type=button]:disabled, > input.submit:disabled, >-button.submit:disabled { >+button.submit:disabled, >+a.submit:disabled { > color : #999; > border : 1px solid #C0C0C0; > background : #EEE none; > } > >-input[type=reset]:active, input[type=button]:active, input.submit:active, button.submit:active { >+input[type=reset]:active, input[type=button]:active, input.submit:active, button.submit:active, a.submit:active { > border : 1px inset #999999; > } > >+a.submit { >+ display: inline-block; >+} >+ > ul li input.submit { > font-size : 87%; > padding : 2px; >@@ -2589,4 +2594,17 @@ fieldset.rows table.mceListBox { > text-indent: 100%; > white-space: nowrap; > overflow: hidden; >-} >\ No newline at end of file >+} >+ >+#merge_invoices { >+ display: none; >+ margin: 1em auto; >+} >+ >+#merge { >+ margin: 0.5em 0 0 0; >+} >+ >+#merge_table tr.active td { >+ background-color: #FFFFCC; >+} >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/invoices.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/invoices.tt >index 16c1b61..9e168f0 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/invoices.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/invoices.tt >@@ -20,9 +20,58 @@ $(document).ready(function() { > bFilter: false, > sDom: "t", > aoColumnDefs: [ >- { "bSortable": false, "aTargets": [6] } >+ { "bSortable": false, "aTargets": [0, 7] } > ] > })); >+ >+ $('#merge').click(function (ev) { >+ var booksellerid; >+ var mismatch; >+ var invoices = [ ]; >+ if ($('.select-invoice:checked').size() < 2) { >+ alert(_("You must select at least two invoices to merge.")); >+ return false; >+ } >+ $('.select-invoice:checked').each(function () { >+ var row = $(this).parents('tr'); >+ booksellerid = booksellerid || $(row).attr('data-booksellerid'); >+ if (booksellerid !== $(row).attr('data-booksellerid')) { >+ mismatch = true; >+ } >+ invoices.push({ 'invoiceid': $(row).attr('data-invoiceid'), >+ 'invoicenumber': $(row).find('td:nth-child(2) a').text(), >+ 'shipmentdate': $(row).attr('data-shipmentdate'), >+ 'billingdate': $(row).attr('data-billingdate'), >+ 'shipmentcost': $(row).attr('data-shipmentcost'), >+ 'shipment_budgetid': $(row).attr('data-shipment_budgetid'), >+ 'closedate': $(row).attr('data-closedate'), }); >+ $('#merge_invoice_form').append('<input type="hidden" name="merge" value="' + $(row).attr('data-invoiceid') + '" />'); >+ }); >+ if (mismatch) { >+ alert(_("All invoices for merging must be from the same vendor")); >+ } else { >+ $('#merge_table tbody').empty(); >+ $.each(invoices, function (idx, invoice) { >+ var row = $('<tr data-invoiceid="' + invoice.invoiceid + '"><td>' + invoice.invoicenumber + '</td><td>' + invoice.shipmentdate + '</td><td>' + invoice.billingdate + '</td><td>' + invoice.shipmentcost + '</td></tr>'); >+ $(row).appendTo('#merge_table tbody'); >+ $(row).click(function () { >+ $('#merge_table tbody tr').removeClass('active'); >+ $(this).addClass('active'); >+ $('#merge_invoicenumber').text(invoice.invoicenumber); >+ $.each(['invoiceid', 'shipmentdate', 'billingdate', 'shipmentcost', 'shipment_budgetid'], function (idx, prop) { >+ $('#merge_' + prop).val(invoice[prop]); >+ }); >+ if (invoice.closedate) { >+ $('#merge_status').text(_("Closed on " + invoice.closedate + "")); >+ } else { >+ $('#merge_status').text(_("Open")); >+ } >+ }); >+ }); >+ $('#merge_table tbody tr:first').click(); >+ $('#merge_invoices').show(); >+ } >+ }); > }); > //]]> > </script> >@@ -45,6 +94,7 @@ $(document).ready(function() { > <table id="resultst"> > <thead> > <tr> >+ <th> </th> > <th>Invoice no.</th> > <th>Vendor</th> > <th>Billing date</th> >@@ -56,7 +106,8 @@ $(document).ready(function() { > </thead> > <tbody> > [% FOREACH invoice IN invoices %] >- <tr> >+ <tr data-invoiceid="[% invoice.invoiceid %]" data-booksellerid="[% invoice.booksellerid %]" data-shipmentdate="[% invoice.shipmentdate | $KohaDates %]" data-billingdate="[% invoice.billingdate | $KohaDates %]" data-shipmentcost="[% invoice.shipmentcost %]" data-shipment_budgetid="[% invoice.shipmentcost_budgetid %]" data-closedate="[% invoice.closedate | $KohaDates %]"> >+ <td><input type="checkbox" class="select-invoice" value="[% invoice.invoiceid %]"></input></td> > <td><a href="/cgi-bin/koha/acqui/invoice.pl?invoiceid=[% invoice.invoiceid %]">[% invoice.invoicenumber %]</a></td> > <td><a href="/cgi-bin/koha/acqui/supplier.pl?booksellerid=[% invoice.booksellerid %]">[% invoice.suppliername %]</a></td> > <td> >@@ -88,6 +139,44 @@ $(document).ready(function() { > [% END %] > </tbody> > </table> >+ <a class="submit" id="merge" href="#merge_invoices">Merge selected invoices</a> >+ <div id="merge_invoices"> >+ <form id="merge_invoice_form" action="/cgi-bin/koha/acqui/invoice.pl" method="post"> >+ <fieldset class="rows"> >+ <ol> >+ <li><h2>Merge invoices</h2></li> >+ <li><table id="merge_table"> >+ <thead><tr><th>Invoice no.</th><th>Shipment date</th><th>Billing date</th><th>Shipment cost</th></tr></thead> >+ <tbody> >+ </tbody> >+ </table></li> >+ <li><label for="merge_invoicenumber">Invoice number:</label><span id="merge_invoicenumber"></span></li> >+ <li><label for="merge_shipmentdate">Shipment date:</label> >+ <input type="text" size="10" id="merge_shipmentdate" name="shipmentdate" value="" readonly="readonly" class="datepicker" /></li> >+ >+ <li><label for="merge_billingdate">Billing date:</label> >+ <input type="text" size="10" id="merge_billingdate" name="billingdate" value="" readonly="readonly" class="datepicker" /></li> >+ >+ <li><label for="merge_shipmentcost">Shipment cost:</label> >+ <input type="text" size="10" id="merge_shipmentcost" name="shipmentcost" value="" /></li> >+ <li><label for="merge_shipment_budgetid">Fund:</label> >+ <select id="merge_shipment_budgetid" name="shipment_budget_id"> >+ <option value="">No fund</option> >+ [% FOREACH budget IN budgets_loop %] >+ <option value="[% budget.budget_id %]"> >+ [% budget.budget_name %] >+ </option> >+ [% END %] >+ </select></li> >+ >+ <li><span class="label">Status:</span> <span id="merge_status"></span></li> >+ <li><input type="submit" value="Merge" /></li> >+ </ol> >+ <input type="hidden" name="op" value="mod" /> >+ <input type="hidden" id="merge_invoiceid" name="invoiceid" value="" /> >+ </fieldset> >+ </form> >+ </div> > [% ELSE %] > <p>Sorry, but there is no results for your search.</p> > <p>Search was: >diff --git a/t/db_dependent/Acquisition/Invoices.t b/t/db_dependent/Acquisition/Invoices.t >new file mode 100644 >index 0000000..6b3e080 >--- /dev/null >+++ b/t/db_dependent/Acquisition/Invoices.t >@@ -0,0 +1,156 @@ >+#!/usr/bin/perl >+# >+# This Koha test module is a stub! >+# Add more tests here!!! >+ >+use strict; >+use warnings; >+ >+use C4::Bookseller qw( GetBookSellerFromId ); >+use C4::Biblio qw( AddBiblio ); >+ >+use Test::More tests => 14; >+ >+BEGIN { >+ use_ok('C4::Acquisition'); >+} >+ >+my $dbh = C4::Context->dbh; >+$dbh->{AutoCommit} = 0; >+$dbh->{RaiseError} = 1; >+ >+my $booksellerid = C4::Bookseller::AddBookseller( >+ { >+ name => "my vendor", >+ address1 => "bookseller's address", >+ phone => "0123456", >+ active => 1 >+ } >+); >+ >+my $booksellerinfo = GetBookSellerFromId( $booksellerid ); >+my $basketno = NewBasket($booksellerid, 1); >+my $basket = GetBasket($basketno); >+ >+my $budgetid = C4::Budgets::AddBudget( >+ { >+ budget_code => "budget_code_test_getordersbybib", >+ budget_name => "budget_name_test_getordersbybib", >+ } >+); >+my $budget = C4::Budgets::GetBudget( $budgetid ); >+ >+my ($ordernumber1, $ordernumber2, $ordernumber3); >+my ($biblionumber1, $biblioitemnumber1) = AddBiblio(MARC::Record->new, ''); >+my ($biblionumber2, $biblioitemnumber2) = AddBiblio(MARC::Record->new, ''); >+my ($biblionumber3, $biblioitemnumber3) = AddBiblio(MARC::Record->new, ''); >+( undef, $ordernumber1 ) = C4::Acquisition::NewOrder( >+ { >+ basketno => $basketno, >+ quantity => 2, >+ biblionumber => $biblionumber1, >+ budget_id => $budget->{budget_id}, >+ } >+); >+ >+( undef, $ordernumber2 ) = C4::Acquisition::NewOrder( >+ { >+ basketno => $basketno, >+ quantity => 1, >+ biblionumber => $biblionumber2, >+ budget_id => $budget->{budget_id}, >+ } >+); >+ >+( undef, $ordernumber3 ) = C4::Acquisition::NewOrder( >+ { >+ basketno => $basketno, >+ quantity => 1, >+ biblionumber => $biblionumber3, >+ budget_id => $budget->{budget_id}, >+ ecost => 42, >+ rrp => 42, >+ } >+); >+ >+my $invoiceid1 = AddInvoice(invoicenumber => 'invoice1', booksellerid => $booksellerid, unknown => "unknown"); >+my $invoiceid2 = AddInvoice(invoicenumber => 'invoice2', booksellerid => $booksellerid, unknown => "unknown"); >+ >+my ($datereceived, $new_ordernumber) = ModReceiveOrder( >+ $biblionumber1, >+ $ordernumber1, >+ 2, >+ undef, >+ 12, >+ 12, >+ $invoiceid1, >+ 42 >+ ); >+ >+($datereceived, $new_ordernumber) = ModReceiveOrder( >+ $biblionumber2, >+ $ordernumber2, >+ 1, >+ undef, >+ 5, >+ 5, >+ $invoiceid2, >+ 42 >+ ); >+ >+($datereceived, $new_ordernumber) = ModReceiveOrder( >+ $biblionumber3, >+ $ordernumber3, >+ 1, >+ undef, >+ 12, >+ 12, >+ $invoiceid2, >+ 42 >+ ); >+ >+ >+my $invoice1 = GetInvoiceDetails($invoiceid1); >+my $invoice2 = GetInvoiceDetails($invoiceid2); >+ >+is(scalar @{$invoice1->{'orders'}}, 1, 'Invoice1 has only one order'); >+is(scalar @{$invoice2->{'orders'}}, 2, 'Invoice2 has only two orders'); >+ >+my @invoices = GetInvoices(); >+cmp_ok(scalar @invoices, '>=', 2, 'GetInvoices returns at least two invoices'); >+ >+@invoices = GetInvoices(invoicenumber => 'invoice2'); >+cmp_ok(scalar @invoices, '>=', 1, 'GetInvoices returns at least one invoice when a specific invoice is requested'); >+ >+my $invoicesummary1 = GetInvoice($invoiceid1); >+is($invoicesummary1->{'invoicenumber'}, 'invoice1', 'GetInvoice retrieves correct invoice'); >+is($invoicesummary1->{'invoicenumber'}, $invoice1->{'invoicenumber'}, 'GetInvoice and GetInvoiceDetails retrieve same information'); >+ >+ModInvoice(invoiceid => $invoiceid1, invoicenumber => 'invoice11'); >+$invoice1 = GetInvoiceDetails($invoiceid1); >+is($invoice1->{'invoicenumber'}, 'invoice11', 'ModInvoice changed invoice number'); >+ >+is($invoice1->{'closedate'}, undef, 'Invoice is not closed before CloseInvoice call'); >+CloseInvoice($invoiceid1); >+$invoice1 = GetInvoiceDetails($invoiceid1); >+isnt($invoice1->{'closedate'}, undef, 'Invoice is closed after CloseInvoice call'); >+ReopenInvoice($invoiceid1); >+$invoice1 = GetInvoiceDetails($invoiceid1); >+is($invoice1->{'closedate'}, undef, 'Invoice is open after ReopenInvoice call'); >+ >+ >+MergeInvoices($invoiceid1, [ $invoiceid2 ]); >+ >+my $mergedinvoice = GetInvoiceDetails($invoiceid1); >+is(scalar @{$mergedinvoice->{'orders'}}, 3, 'Merged invoice has three orders'); >+ >+my $invoiceid3 = AddInvoice(invoicenumber => 'invoice3', booksellerid => $booksellerid, unknown => "unknown"); >+my $invoicecount = GetInvoices(); >+DelInvoice($invoiceid3); >+@invoices = GetInvoices(); >+is(scalar @invoices, $invoicecount - 1, 'DelInvoice deletes invoice'); >+is(GetInvoice($invoiceid3), undef, 'DelInvoice deleted correct invoice'); >+ >+END { >+ $dbh and $dbh->rollback; >+} >-- >1.7.9.5
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 10401
:
19523
|
19865
|
20558
|
20720
|
21001