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 <veron@veron.ch>

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.
This commit is contained in:
Julian Maurice 2012-08-08 11:06:45 +02:00 committed by Paul Poulain
parent 5d43aa5911
commit d4cda293b4
6 changed files with 211 additions and 38 deletions

View file

@ -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=?");
SET quantity = ?
WHERE ordernumber = ?
");
$sth->execute($quantrec,$datereceived,$invoiceno,$cost,$freight,$rrp,$quantrec,$biblionumber,$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;
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);
for (my $i=0; $i<$count; $i++){
foreach (@$received_items){
splice (@orderitems, $i, 1) if ($orderitems[$i] == $_);
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,

View file

@ -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 );

View file

@ -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;

View file

@ -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`),

View file

@ -5754,6 +5754,21 @@ if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) {
SetVersion($DBversion)
}
$DBversion = "3.09.00.043";
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)

View file

@ -165,6 +165,20 @@
[% END %]
[% END %]
[% IF (error_cancelling_receipt) %]
<div class="error">
Cannot cancel receipt. Possible reasons :
<ul>
<li>
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.
</li>
<li>Parent order line has been deleted.</li>
</ul>
</div>
[% END %]
<div id="acqui_receive_summary">
<p><strong>Invoice number:</strong> [% invoice %] <strong>Received by:</strong> [% loggedinusername %] <strong>On:</strong> [% formatteddatereceived %]</p>
<!-- TODO: Add date picker, change rcv date. -->
@ -273,6 +287,7 @@
<div id="acqui_receive_receivelist">
<h3>Already received</h3>
[% IF ( loop_received ) %]
<form action="/cgi-bin/koha/acqui/parcel.pl" method="get" name="orderform">
<table id="receivedt">
@ -286,6 +301,7 @@
<th>Est cost</th>
<th>Actual cost</th>
<th>TOTAL</th>
<th></th>
</tr>
</thead>
<tfoot>
@ -294,6 +310,7 @@
<td colspan="2">&nbsp;</td>
<td>[% totalprice %]</td>
<td>[% tototal %]</td>
<td></td>
</tr>
[% IF ( totalfreight ) %]
@ -321,6 +338,7 @@
<td>[% totalquantity %]</td>
<td colspan="2">&nbsp;</td>
<td>[% grandtot %]</td>
<td></td>
</tr>
</tfoot>
<tbody class="filterclass">
@ -343,6 +361,7 @@
<td>[% loop_receive.ecost %]</td>
<td>[% loop_receive.unitprice %]</td>
<td>[% loop_receive.total %]</td>
<td><a href="/cgi-bin/koha/acqui/parcel.pl?invoice=[% loop_receive.invoice %]&booksellerid=[% booksellerid %]&datereceived=[% datereceived %]&op=cancelreceipt&ordernumber=[% loop_receive.ordernumber %]">Cancel receipt</a></td>
</tr>
[% END %]
</tbody>