From 3052d7e4c1a712976b4883ff94aef1e52855d264 Mon Sep 17 00:00:00 2001 From: Julian Maurice Date: Wed, 8 Aug 2012 11:06:45 +0200 Subject: [PATCH] Bug 7583: Cancel a receipt In acqui/parcel.pl, there is now the possibility to cancel a receipt. In "Already received" table, just click on "Cancel receipt" and the order line will go back to pending orders. If it was a partial receipt, order line is merged to its 'parent' line. Attached items are modified so that they become attached to the merged order line. If AcqCreateItem is 'receiving', attached items are deleted. If an order line was first partially received, and then completed. You must cancel the 'parent' order line before cancelling the 'child'. Signed-off-by: Marc Veron The patch behaves like expected, and the feature is really helpfull. Just a tiny remark about the following message: ------------- Cannot cancel receipt. Possible reasons : You are trying to cancel the receipt of an order line whose parent order line is already received. Cancel this parent order line and retry. ------------- Maybe it would be good - to explain a little bit more why it happend and re-word the message for non technical people (not everybody understands 'parent' the same way) - prevent the situation to happen (e.g. forbid order lines to be deleted if they are already received) - but that would be in the scope of an other bug, I think. I think such things could be fixed in the future during the ongoing work for Acquisitions module. Signing off. --- C4/Acquisition.pm | 180 ++++++++++++++++---- acqui/finishreceive.pl | 24 ++- acqui/parcel.pl | 14 +- installer/data/mysql/kohastructure.sql | 1 + installer/data/mysql/updatedatabase.pl | 15 ++ .../intranet-tmpl/prog/en/modules/acqui/parcel.tt | 19 +++ 6 files changed, 213 insertions(+), 40 deletions(-) diff --git a/C4/Acquisition.pm b/C4/Acquisition.pm index fc1e817..21e7640 100644 --- a/C4/Acquisition.pm +++ b/C4/Acquisition.pm @@ -56,7 +56,7 @@ BEGIN { &NewOrder &DelOrder &ModOrder &GetPendingOrders &GetOrder &GetOrders &GetOrderNumber &GetLateOrders &GetOrderFromItemnumber &SearchOrder &GetHistory &GetRecentAcqui - &ModReceiveOrder &ModOrderBiblioitemNumber + &ModReceiveOrder &CancelReceipt &ModOrderBiblioitemNumber &GetCancelledOrders &NewOrderItem &ModOrderItem &ModItemOrder @@ -1042,6 +1042,14 @@ sub NewOrder { } my $ordernumber=InsertInTable("aqorders",$orderinfo); + if (not $orderinfo->{parent_ordernumber}) { + my $sth = $dbh->prepare(" + UPDATE aqorders + SET parent_ordernumber = ordernumber + WHERE ordernumber = ? + "); + $sth->execute($ordernumber); + } return ( $orderinfo->{'basketno'}, $ordernumber ); } @@ -1259,6 +1267,7 @@ sub ModReceiveOrder { $invoiceno, $freight, $rrp, $budget_id, $datereceived, $received_items ) = @_; + my $dbh = C4::Context->dbh; $datereceived = C4::Dates->output('iso') unless $datereceived; my $suggestionid = GetSuggestionFromBiblionumber( $biblionumber ); @@ -1277,40 +1286,37 @@ sub ModReceiveOrder { my $order = $sth->fetchrow_hashref(); $sth->finish(); + my $new_ordernumber = $ordernumber; if ( $order->{quantity} > $quantrec ) { + # Split order line in two parts: the first is the original order line + # without received items (the quantity is decreased), + # the second part is a new order line with quantity=quantityrec + # (entirely received) $sth=$dbh->prepare(" UPDATE aqorders - SET quantityreceived=? - , datereceived=? - , booksellerinvoicenumber=? - , unitprice=? - , freight=? - , rrp=? - , quantity=? - WHERE biblionumber=? AND ordernumber=?"); - - $sth->execute($quantrec,$datereceived,$invoiceno,$cost,$freight,$rrp,$quantrec,$biblionumber,$ordernumber); + SET quantity = ? + WHERE ordernumber = ? + "); + + $sth->execute($order->{quantity} - $quantrec, $ordernumber); $sth->finish; - # create a new order for the remaining items, and set its bookfund. - foreach my $orderkey ( "linenumber", "allocation" ) { - delete($order->{'$orderkey'}); - } - $order->{'quantity'} -= $quantrec; - $order->{'quantityreceived'} = 0; - my $newOrder = NewOrder($order); - # Change ordernumber in aqorders_items for items not received - my @orderitems = GetItemnumbersFromOrder( $order->{'ordernumber'} ); - my $count = scalar @orderitems; - - for (my $i=0; $i<$count; $i++){ - foreach (@$received_items){ - splice (@orderitems, $i, 1) if ($orderitems[$i] == $_); + delete $order->{'ordernumber'}; + $order->{'quantity'} = $quantrec; + $order->{'quantityreceived'} = $quantrec; + $order->{'datereceived'} = $datereceived; + $order->{'booksellerinvoicenumber'} = $invoiceno; + $order->{'unitprice'} = $cost; + $order->{'freight'} = $freight; + $order->{'rrp'} = $rrp; + $order->{'orderstatus'} = 3; # totally received + $new_ordernumber = NewOrder($order); + + if ($received_items) { + foreach my $itemnumber (@$received_items) { + ModItemOrder($itemnumber, $new_ordernumber); } } - foreach (@orderitems) { - ModItemOrder($_, $newOrder); - } } else { $sth=$dbh->prepare("update aqorders set quantityreceived=?,datereceived=?,booksellerinvoicenumber=?, @@ -1319,8 +1325,123 @@ sub ModReceiveOrder { $sth->execute($quantrec,$datereceived,$invoiceno,$cost,$freight,$rrp,$biblionumber,$ordernumber); $sth->finish; } - return $datereceived; + return ($datereceived, $new_ordernumber); } + +=head3 CancelReceipt + + my $parent_ordernumber = CancelReceipt($ordernumber); + + Cancel an order line receipt and update the parent order line, as if no + receipt was made. + If items are created at receipt (AcqCreateItem = receiving) then delete + these items. + +=cut + +sub CancelReceipt { + my $ordernumber = shift; + + return unless $ordernumber; + + my $dbh = C4::Context->dbh; + my $query = qq{ + SELECT datereceived, parent_ordernumber, quantity + FROM aqorders + WHERE ordernumber = ? + }; + my $sth = $dbh->prepare($query); + $sth->execute($ordernumber); + my $order = $sth->fetchrow_hashref; + unless($order) { + warn "CancelReceipt: order $ordernumber does not exist"; + return; + } + unless($order->{'datereceived'}) { + warn "CancelReceipt: order $ordernumber is not received"; + return; + } + + my $parent_ordernumber = $order->{'parent_ordernumber'}; + + if($parent_ordernumber == $ordernumber || not $parent_ordernumber) { + # The order line has no parent, just mark it as not received + $query = qq{ + UPDATE aqorders + SET quantityreceived = ?, + datereceived = ?, + booksellerinvoicenumber = ? + WHERE ordernumber = ? + }; + $sth = $dbh->prepare($query); + $sth->execute(0, undef, undef, $ordernumber); + } else { + # The order line has a parent, increase parent quantity and delete + # the order line. + $query = qq{ + SELECT quantity, datereceived + FROM aqorders + WHERE ordernumber = ? + }; + $sth = $dbh->prepare($query); + $sth->execute($parent_ordernumber); + my $parent_order = $sth->fetchrow_hashref; + unless($parent_order) { + warn "Parent order $parent_ordernumber does not exist."; + return; + } + if($parent_order->{'datereceived'}) { + warn "CancelReceipt: parent order is received.". + " Can't cancel receipt."; + return; + } + $query = qq{ + UPDATE aqorders + SET quantity = ? + WHERE ordernumber = ? + }; + $sth = $dbh->prepare($query); + my $rv = $sth->execute( + $order->{'quantity'} + $parent_order->{'quantity'}, + $parent_ordernumber + ); + unless($rv) { + warn "Cannot update parent order line, so do not cancel". + " receipt"; + return; + } + if(C4::Context->preference('AcqCreateItem') eq 'receiving') { + # Remove items that were created at receipt + $query = qq{ + DELETE FROM items, aqorders_items + USING items, aqorders_items + WHERE items.itemnumber = ? AND aqorders_items.itemnumber = ? + }; + $sth = $dbh->prepare($query); + my @itemnumbers = GetItemnumbersFromOrder($ordernumber); + foreach my $itemnumber (@itemnumbers) { + $sth->execute($itemnumber, $itemnumber); + } + } else { + # Update items + my @itemnumbers = GetItemnumbersFromOrder($ordernumber); + foreach my $itemnumber (@itemnumbers) { + ModItemOrder($itemnumber, $parent_ordernumber); + } + } + # Delete order line + $query = qq{ + DELETE FROM aqorders + WHERE ordernumber = ? + }; + $sth = $dbh->prepare($query); + $sth->execute($ordernumber); + + } + + return $parent_ordernumber; +} + #------------------------------------------------------------# =head3 SearchOrder @@ -1464,6 +1585,7 @@ sub GetParcel { firstname, aqorders.biblionumber, aqorders.ordernumber, + aqorders.parent_ordernumber, aqorders.quantity, aqorders.quantityreceived, aqorders.unitprice, diff --git a/acqui/finishreceive.pl b/acqui/finishreceive.pl index 84391f5..bfd8010 100755 --- a/acqui/finishreceive.pl +++ b/acqui/finishreceive.pl @@ -58,6 +58,20 @@ my $note = $input->param("note"); #need old recievedate if we update the order, parcel.pl only shows the right parcel this way FIXME if ($quantityrec > $origquantityrec ) { + my @received_items = (); + if(C4::Context->preference('AcqCreateItem') eq 'ordering') { + @received_items = $input->param('items_to_receive'); + } + + my $new_ordernumber = $ordernumber; + # save the quantity received. + if ( $quantityrec > 0 ) { + ($datereceived, $new_ordernumber) = ModReceiveOrder( + $biblionumber, $ordernumber, $quantityrec, $user, $unitprice, + $invoiceno, $freight, $replacement, undef, $datereceived, + \@received_items); + } + # now, add items if applicable if (C4::Context->preference('AcqCreateItem') eq 'receiving') { @@ -91,17 +105,9 @@ if ($quantityrec > $origquantityrec ) { $itemhash{$item}->{'indicator'},'ITEM'); my $record=MARC::Record::new_from_xml($xml, 'UTF-8'); my (undef,$bibitemnum,$itemnumber) = AddItemFromMarc($record,$biblionumber); - NewOrderItem($itemnumber, $ordernumber); + NewOrderItem($itemnumber, $new_ordernumber); } } - - my @received_items = (); - if(C4::Context->preference('AcqCreateItem') eq 'ordering') { - @received_items = $input->param('items_to_receive'); - } - - # save the quantity received. - $datereceived = ModReceiveOrder($biblionumber,$ordernumber, $quantityrec ,$user,$unitprice,$invoiceno,$freight,$replacement,undef,$datereceived, \@received_items); } update_item( $_ ) foreach GetItemnumbersFromOrder( $ordernumber ); diff --git a/acqui/parcel.pl b/acqui/parcel.pl index 527aa3c..850fe94 100755 --- a/acqui/parcel.pl +++ b/acqui/parcel.pl @@ -78,8 +78,10 @@ my $invoice=$input->param('invoice') || ''; my $freight=$input->param('freight'); my $input_gst = ($input->param('gst') eq '' ? undef : $input->param('gst')); my $gst= $input_gst // $bookseller->{gstrate} // C4::Context->preference("gist") // 0; -my $datereceived = ($input->param('op') eq ('new' or "search")) ? C4::Dates->new($input->param('datereceived')) - : C4::Dates->new($input->param('datereceived'), 'iso'); +my $op = $input->param('op') // ''; +my $datereceived = ($op eq ('new' or 'search' ) + ? C4::Dates->new($input->param('datereceived')) + : C4::Dates->new($input->param('datereceived'), 'iso'); $datereceived = C4::Dates->new() unless $datereceived; my $code = $input->param('code'); my @rcv_err = $input->param('error'); @@ -98,6 +100,14 @@ my ($template, $loggedinuser, $cookie) debug => 1, }); +if($op eq 'cancelreceipt') { + my $ordernumber = $input->param('ordernumber'); + my $parent_ordernumber = CancelReceipt($ordernumber); + unless($parent_ordernumber) { + $template->param(error_cancelling_receipt => 1); + } +} + # If receiving error, report the error (coming from finishrecieve.pl(sic)). if( scalar(@rcv_err) ) { my $cnt=0; diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index 91d42a2..eb28a16 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -2773,6 +2773,7 @@ CREATE TABLE `aqorders` ( -- information related to the basket line items `uncertainprice` tinyint(1), -- was this price uncertain (1 for yes, 0 for no) `claims_count` int(11) default 0, -- count of claim letters generated `claimed_date` date default NULL, -- last date a claim was generated + parent_ordernumber int(11) default NULL, -- ordernumber of parent order line, or same as ordernumber if no parent PRIMARY KEY (`ordernumber`), KEY `basketno` (`basketno`), KEY `biblionumber` (`biblionumber`), diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl index 25cd367..adb6a20 100755 --- a/installer/data/mysql/updatedatabase.pl +++ b/installer/data/mysql/updatedatabase.pl @@ -5696,6 +5696,21 @@ if (C4::Context->preference("Version") < TransformToNum($DBversion)) { SetVersion($DBversion); } +$DBversion = "XXX"; +if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) { + $dbh->do(" + ALTER TABLE aqorders + ADD parent_ordernumber int(11) DEFAULT NULL + "); + $dbh->do(" + UPDATE aqorders + SET parent_ordernumber = ordernumber; + "); + print "Upgrade to $DBversion done (Adding parent_ordernumber in aqorders)\n"; + SetVersion($DBversion); +} + + =head1 FUNCTIONS =head2 TableExists($table) diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/parcel.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/parcel.tt index 1b6543a..946e65a 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/parcel.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/parcel.tt @@ -161,6 +161,20 @@ [% END %] [% END %] + [% IF (error_cancelling_receipt) %] +
+ Cannot cancel receipt. Possible reasons : +
    +
  • + You are trying to cancel the receipt of an order line whose parent + order line is already received. Cancel this parent order line and + retry. +
  • +
  • Parent order line has been deleted.
  • +
+
+ [% END %] +

Invoice number: [% invoice %] Received by: [% loggedinusername %] On: [% formatteddatereceived %]

@@ -269,6 +283,7 @@

Already received

+ [% IF ( loop_received ) %]
@@ -282,6 +297,7 @@ + @@ -290,6 +306,7 @@ + [% IF ( totalfreight ) %] @@ -317,6 +334,7 @@ + @@ -339,6 +357,7 @@ + [% END %] -- 1.7.10.4
Est cost Actual cost TOTAL
  [% totalprice %] [% tototal %]
[% totalquantity %]   [% grandtot %]
[% loop_receive.ecost %] [% loop_receive.unitprice %] [% loop_receive.total %]Cancel receipt