Bug 23971: (follow-up) Add additional basket logging
[koha-ffzg.git] / C4 / Acquisition.pm
index d7f0e25..bd5c307 100644 (file)
@@ -20,17 +20,21 @@ package C4::Acquisition;
 
 use Modern::Perl;
 use Carp;
 
 use Modern::Perl;
 use Carp;
+use Text::CSV_XS;
 use C4::Context;
 use C4::Debug;
 use C4::Suggestions;
 use C4::Biblio;
 use C4::Contract;
 use C4::Debug;
 use C4::Context;
 use C4::Debug;
 use C4::Suggestions;
 use C4::Biblio;
 use C4::Contract;
 use C4::Debug;
+use C4::Log qw(logaction);
 use C4::Templates qw(gettemplate);
 use Koha::DateUtils qw( dt_from_string output_pref );
 use C4::Templates qw(gettemplate);
 use Koha::DateUtils qw( dt_from_string output_pref );
+use Koha::Acquisition::Baskets;
 use Koha::Acquisition::Booksellers;
 use Koha::Acquisition::Orders;
 use Koha::Biblios;
 use Koha::Acquisition::Booksellers;
 use Koha::Acquisition::Orders;
 use Koha::Biblios;
+use Koha::Exceptions;
 use Koha::Items;
 use Koha::Number::Price;
 use Koha::Libraries;
 use Koha::Items;
 use Koha::Number::Price;
 use Koha::Libraries;
@@ -50,7 +54,7 @@ BEGIN {
     require Exporter;
     @ISA    = qw(Exporter);
     @EXPORT = qw(
     require Exporter;
     @ISA    = qw(Exporter);
     @EXPORT = qw(
-        &GetBasket &NewBasket &CloseBasket &ReopenBasket &DelBasket &ModBasket
+        &GetBasket &NewBasket &ReopenBasket &ModBasket
         &GetBasketAsCSV &GetBasketGroupAsCSV
         &GetBasketsByBookseller &GetBasketsByBasketgroup
         &GetBasketsInfosByBookseller
         &GetBasketAsCSV &GetBasketGroupAsCSV
         &GetBasketsByBookseller &GetBasketsByBasketgroup
         &GetBasketsInfosByBookseller
@@ -63,12 +67,11 @@ BEGIN {
         &ModBasketgroup &NewBasketgroup &DelBasketgroup &GetBasketgroup &CloseBasketgroup
         &GetBasketgroups &ReOpenBasketgroup
 
         &ModBasketgroup &NewBasketgroup &DelBasketgroup &GetBasketgroup &CloseBasketgroup
         &GetBasketgroups &ReOpenBasketgroup
 
-        &DelOrder &ModOrder &GetOrder &GetOrders &GetOrdersByBiblionumber
-        &GetLateOrders &GetOrderFromItemnumber
+        &ModOrder &GetOrder &GetOrders &GetOrdersByBiblionumber
+        &GetOrderFromItemnumber
         &SearchOrders &GetHistory &GetRecentAcqui
         &ModReceiveOrder &CancelReceipt
         &TransferOrder
         &SearchOrders &GetHistory &GetRecentAcqui
         &ModReceiveOrder &CancelReceipt
         &TransferOrder
-        &GetLastOrderNotReceivedFromSubscriptionid &GetLastOrderReceivedFromSubscriptionid
         &ModItemOrder
 
         &GetParcels
         &ModItemOrder
 
         &GetParcels
@@ -83,8 +86,6 @@ BEGIN {
         &DelInvoice
         &MergeInvoices
 
         &DelInvoice
         &MergeInvoices
 
-        &GetItemnumbersFromOrder
-
         &AddClaim
         &GetBiblioCountByBasketno
 
         &AddClaim
         &GetBiblioCountByBasketno
 
@@ -93,6 +94,9 @@ BEGIN {
         &NotifyOrderUsers
 
         &FillWithDefaultValues
         &NotifyOrderUsers
 
         &FillWithDefaultValues
+
+        &get_rounded_price
+        &get_rounding_sql
     );
 }
 
     );
 }
 
@@ -120,28 +124,6 @@ sub GetOrderFromItemnumber {
 
 }
 
 
 }
 
-# Returns the itemnumber(s) associated with the ordernumber given in parameter
-sub GetItemnumbersFromOrder {
-    my ($ordernumber) = @_;
-    my $dbh          = C4::Context->dbh;
-    my $query        = "SELECT itemnumber FROM aqorders_items WHERE ordernumber=?";
-    my $sth = $dbh->prepare($query);
-    $sth->execute($ordernumber);
-    my @tab;
-
-    while (my $order = $sth->fetchrow_hashref) {
-    push @tab, $order->{'itemnumber'};
-    }
-
-    return @tab;
-
-}
-
-
-
-
-
-
 =head1 NAME
 
 C4::Acquisition - Koha functions for dealing with orders and acquisitions
 =head1 NAME
 
 C4::Acquisition - Koha functions for dealing with orders and acquisitions
@@ -222,29 +204,13 @@ sub NewBasket {
     $basketbooksellernote ||= q{};
     ModBasketHeader( $basket, $basketname, $basketnote, $basketbooksellernote,
         $basketcontractnumber, $booksellerid, $deliveryplace, $billingplace, $is_standing, $create_items );
     $basketbooksellernote ||= q{};
     ModBasketHeader( $basket, $basketname, $basketnote, $basketbooksellernote,
         $basketcontractnumber, $booksellerid, $deliveryplace, $billingplace, $is_standing, $create_items );
-    return $basket;
-}
-
-#------------------------------------------------------------#
-
-=head3 CloseBasket
-
-  &CloseBasket($basketno);
-
-close a basket (becomes unmodifiable, except for receives)
-
-=cut
 
 
-sub CloseBasket {
-    my ($basketno) = @_;
-    my $dbh        = C4::Context->dbh;
-    $dbh->do('UPDATE aqbasket SET closedate=now() WHERE basketno=?', {}, $basketno );
+    # Log the basket creation
+    if (C4::Context->preference("AcqLog")) {
+        logaction('ACQUISITIONS', 'ADD_BASKET', $basket);
+    }
 
 
-    $dbh->do(
-q{UPDATE aqorders SET orderstatus = 'ordered' WHERE basketno = ? AND orderstatus NOT IN ( 'complete', 'cancelled')},
-        {}, $basketno
-    );
-    return;
+    return $basket;
 }
 
 =head3 ReopenBasket
 }
 
 =head3 ReopenBasket
@@ -266,6 +232,15 @@ sub ReopenBasket {
         WHERE basketno = ?
         AND orderstatus NOT IN ( 'complete', 'cancelled' )
         }, {}, $basketno);
         WHERE basketno = ?
         AND orderstatus NOT IN ( 'complete', 'cancelled' )
         }, {}, $basketno);
+
+    # Log the basket reopening
+    if (C4::Context->preference("AcqLog")) {
+        logaction(
+            'ACQUISITIONS',
+            'REOPEN_BASKET',
+            $basketno
+        );
+    }
     return;
 }
 
     return;
 }
 
@@ -293,7 +268,7 @@ sub GetBasketAsCSV {
     my @rows;
     if ($csv_profile_id) {
         my $csv_profile = Koha::CsvProfiles->find( $csv_profile_id );
     my @rows;
     if ($csv_profile_id) {
         my $csv_profile = Koha::CsvProfiles->find( $csv_profile_id );
-        die "There is no valid csv profile given" unless $csv_profile;
+        Koha::Exceptions::ObjectNotFound->throw( 'There is no valid csv profile given') unless $csv_profile;
 
         my $csv = Text::CSV_XS->new({'quote_char'=>'"','escape_char'=>'"','sep_char'=>$csv_profile->csv_separator,'binary'=>1});
         my $csv_profile_content = $csv_profile->content;
 
         my $csv = Text::CSV_XS->new({'quote_char'=>'"','escape_char'=>'"','sep_char'=>$csv_profile->csv_separator,'binary'=>1});
         my $csv_profile_content = $csv_profile->content;
@@ -505,32 +480,6 @@ sub ReOpenBasketgroup {
 
 #------------------------------------------------------------#
 
 
 #------------------------------------------------------------#
 
-
-=head3 DelBasket
-
-  &DelBasket($basketno);
-
-Deletes the basket that has basketno field $basketno in the aqbasket table.
-
-=over
-
-=item C<$basketno> is the primary key of the basket in the aqbasket table.
-
-=back
-
-=cut
-
-sub DelBasket {
-    my ( $basketno ) = @_;
-    my $query = "DELETE FROM aqbasket WHERE basketno=?";
-    my $dbh = C4::Context->dbh;
-    my $sth = $dbh->prepare($query);
-    $sth->execute($basketno);
-    return;
-}
-
-#------------------------------------------------------------#
-
 =head3 ModBasket
 
   &ModBasket($basketinfo);
 =head3 ModBasket
 
   &ModBasket($basketinfo);
@@ -567,6 +516,15 @@ sub ModBasket {
     my $sth = $dbh->prepare($query);
     $sth->execute(@params);
 
     my $sth = $dbh->prepare($query);
     $sth->execute(@params);
 
+    # Log the basket update
+    if (C4::Context->preference("AcqLog")) {
+        logaction(
+            'ACQUISITIONS',
+            'MODIFY_BASKET',
+            $basketinfo->{'basketno'}
+        );
+    }
+
     return;
 }
 
     return;
 }
 
@@ -624,6 +582,17 @@ sub ModBasketHeader {
         my $sth2 = $dbh->prepare($query2);
         $sth2->execute($contractnumber,$basketno);
     }
         my $sth2 = $dbh->prepare($query2);
         $sth2->execute($contractnumber,$basketno);
     }
+
+    # Log the basket update
+    if (C4::Context->preference("AcqLog")) {
+        logaction(
+            'ACQUISITIONS',
+            'MODIFY_BASKET_HEADER',
+            $basketno
+        );
+    }
+
+    return;
     return;
 }
 
     return;
 }
 
@@ -692,7 +661,7 @@ sub GetBasketsInfosByBookseller {
 
     my $dbh = C4::Context->dbh;
     my $query = q{
 
     my $dbh = C4::Context->dbh;
     my $query = q{
-        SELECT aqbasket.*,
+        SELECT aqbasket.basketno, aqbasket.basketname, aqbasket.note, aqbasket.booksellernote, aqbasket.contractnumber, aqbasket.creationdate, aqbasket.closedate, aqbasket.booksellerid, aqbasket.authorisedby, aqbasket.booksellerinvoicenumber, aqbasket.basketgroupid, aqbasket.deliveryplace, aqbasket.billingplace, aqbasket.branch, aqbasket.is_standing, aqbasket.create_items,
           SUM(aqorders.quantity) AS total_items,
           SUM(
             IF ( aqorders.orderstatus = 'cancelled', aqorders.quantity, 0 )
           SUM(aqorders.quantity) AS total_items,
           SUM(
             IF ( aqorders.orderstatus = 'cancelled', aqorders.quantity, 0 )
@@ -703,15 +672,24 @@ sub GetBasketsInfosByBookseller {
               AND aqorders.datecancellationprinted IS NULL
             , aqorders.quantity
             , 0)
               AND aqorders.datecancellationprinted IS NULL
             , aqorders.quantity
             , 0)
-          ) AS expected_items
+          ) AS expected_items,
+        SUM( aqorders.uncertainprice ) AS uncertainprices
         FROM aqbasket
           LEFT JOIN aqorders ON aqorders.basketno = aqbasket.basketno
         WHERE booksellerid = ?};
 
         FROM aqbasket
           LEFT JOIN aqorders ON aqorders.basketno = aqbasket.basketno
         WHERE booksellerid = ?};
 
+    $query.=" GROUP BY aqbasket.basketno, aqbasket.basketname, aqbasket.note, aqbasket.booksellernote, aqbasket.contractnumber, aqbasket.creationdate, aqbasket.closedate, aqbasket.booksellerid, aqbasket.authorisedby, aqbasket.booksellerinvoicenumber, aqbasket.basketgroupid, aqbasket.deliveryplace, aqbasket.billingplace, aqbasket.branch, aqbasket.is_standing, aqbasket.create_items";
+
     unless ( $allbaskets ) {
     unless ( $allbaskets ) {
-        $query.=" AND (closedate IS NULL OR (aqorders.quantity > aqorders.quantityreceived AND datecancellationprinted IS NULL))";
+        # Don't show the basket if it's NOT CLOSED or is FULLY RECEIVED
+        $query.=" HAVING (closedate IS NULL OR (
+          SUM(
+            IF(aqorders.datereceived IS NULL
+              AND aqorders.datecancellationprinted IS NULL
+            , aqorders.quantity
+            , 0)
+            ) > 0))"
     }
     }
-    $query.=" GROUP BY aqbasket.basketno";
 
     my $sth = $dbh->prepare($query);
     $sth->execute($supplierid);
 
     my $sth = $dbh->prepare($query);
     $sth->execute($supplierid);
@@ -795,6 +773,16 @@ sub ModBasketUsers {
     foreach my $basketuser_id (@basketusers_ids) {
         $sth->execute($basketno, $basketuser_id);
     }
     foreach my $basketuser_id (@basketusers_ids) {
         $sth->execute($basketno, $basketuser_id);
     }
+
+    # Log the basket update
+    if (C4::Context->preference("AcqLog")) {
+        logaction(
+            'ACQUISITIONS',
+            'MODIFY_BASKET_USERS',
+            $basketno
+        );
+    }
+
     return;
 }
 
     return;
 }
 
@@ -1146,15 +1134,14 @@ sub GetOrders {
     if ($cancelled) {
         $orderby ||= q|biblioitems.publishercode, biblio.title|;
         $query .= q|
     if ($cancelled) {
         $orderby ||= q|biblioitems.publishercode, biblio.title|;
         $query .= q|
-            AND (datecancellationprinted IS NOT NULL
-               AND datecancellationprinted <> '0000-00-00')
+            AND datecancellationprinted IS NOT NULL
         |;
     }
     else {
         $orderby ||=
           q|aqorders.datecancellationprinted desc, aqorders.timestamp desc|;
         $query .= q|
         |;
     }
     else {
         $orderby ||=
           q|aqorders.datecancellationprinted desc, aqorders.timestamp desc|;
         $query .= q|
-            AND (datecancellationprinted IS NULL OR datecancellationprinted='0000-00-00')
+            AND datecancellationprinted IS NULL
         |;
     }
 
         |;
     }
 
@@ -1233,8 +1220,6 @@ sub GetOrder {
                 biblioitems.publishercode,
                 aqorders.rrp              AS unitpricesupplier,
                 aqorders.ecost            AS unitpricelib,
                 biblioitems.publishercode,
                 aqorders.rrp              AS unitpricesupplier,
                 aqorders.ecost            AS unitpricelib,
-                aqorders.claims_count     AS claims_count,
-                aqorders.claimed_date     AS claimed_date,
                 aqbudgets.budget_name     AS budget,
                 aqbooksellers.name        AS supplier,
                 aqbooksellers.id          AS supplierid,
                 aqbudgets.budget_name     AS budget,
                 aqbooksellers.name        AS supplier,
                 aqbooksellers.id          AS supplierid,
@@ -1258,70 +1243,6 @@ sub GetOrder {
     return $result_set->[0];
 }
 
     return $result_set->[0];
 }
 
-=head3 GetLastOrderNotReceivedFromSubscriptionid
-
-  $order = &GetLastOrderNotReceivedFromSubscriptionid($subscriptionid);
-
-Returns a reference-to-hash describing the last order not received for a subscription.
-
-=cut
-
-sub GetLastOrderNotReceivedFromSubscriptionid {
-    my ( $subscriptionid ) = @_;
-    my $dbh                = C4::Context->dbh;
-    my $query              = qq|
-        SELECT * FROM aqorders
-        LEFT JOIN subscription
-            ON ( aqorders.subscriptionid = subscription.subscriptionid )
-        WHERE aqorders.subscriptionid = ?
-            AND aqorders.datereceived IS NULL
-        LIMIT 1
-    |;
-    my $result_set =
-      $dbh->selectall_arrayref( $query, { Slice => {} }, $subscriptionid );
-
-    # result_set assumed to contain 1 match
-    return $result_set->[0];
-}
-
-=head3 GetLastOrderReceivedFromSubscriptionid
-
-  $order = &GetLastOrderReceivedFromSubscriptionid($subscriptionid);
-
-Returns a reference-to-hash describing the last order received for a subscription.
-
-=cut
-
-sub GetLastOrderReceivedFromSubscriptionid {
-    my ( $subscriptionid ) = @_;
-    my $dbh                = C4::Context->dbh;
-    my $query              = qq|
-        SELECT * FROM aqorders
-        LEFT JOIN subscription
-            ON ( aqorders.subscriptionid = subscription.subscriptionid )
-        WHERE aqorders.subscriptionid = ?
-            AND aqorders.datereceived =
-                (
-                    SELECT MAX( aqorders.datereceived )
-                    FROM aqorders
-                    LEFT JOIN subscription
-                        ON ( aqorders.subscriptionid = subscription.subscriptionid )
-                        WHERE aqorders.subscriptionid = ?
-                            AND aqorders.datereceived IS NOT NULL
-                )
-        ORDER BY ordernumber DESC
-        LIMIT 1
-    |;
-    my $result_set =
-      $dbh->selectall_arrayref( $query, { Slice => {} }, $subscriptionid, $subscriptionid );
-
-    # result_set assumed to contain 1 match
-    return $result_set->[0];
-
-}
-
-#------------------------------------------------------------#
-
 =head3 ModOrder
 
   &ModOrder(\%hashref);
 =head3 ModOrder
 
   &ModOrder(\%hashref);
@@ -1357,7 +1278,7 @@ sub ModOrder {
     foreach my $orderinfokey (grep(!/ordernumber/, keys %$orderinfo)){
         # ... and skip hash entries that are not in the aqorders table
         # FIXME : probably not the best way to do it (would be better to have a correct hash)
     foreach my $orderinfokey (grep(!/ordernumber/, keys %$orderinfo)){
         # ... and skip hash entries that are not in the aqorders table
         # FIXME : probably not the best way to do it (would be better to have a correct hash)
-        next unless grep(/^$orderinfokey$/, @$colnames);
+        next unless grep { $_ eq $orderinfokey } @$colnames;
             $query .= "$orderinfokey=?, ";
             push(@params, $orderinfo->{$orderinfokey});
     }
             $query .= "$orderinfokey=?, ";
             push(@params, $orderinfo->{$orderinfokey});
     }
@@ -1406,8 +1327,8 @@ sub ModItemOrder {
             user                 => $user,
             invoice              => $invoice,
             budget_id            => $budget_id,
             user                 => $user,
             invoice              => $invoice,
             budget_id            => $budget_id,
+            datereceived         => $datereceived,
             received_itemnumbers => \@received_itemnumbers,
             received_itemnumbers => \@received_itemnumbers,
-            order_internalnote   => $order_internalnote,
         }
     );
 
         }
     );
 
@@ -1430,10 +1351,18 @@ sub ModReceiveOrder {
     my $quantrec       = $params->{quantityreceived};
     my $user           = $params->{user};
     my $budget_id      = $params->{budget_id};
     my $quantrec       = $params->{quantityreceived};
     my $user           = $params->{user};
     my $budget_id      = $params->{budget_id};
+    my $datereceived   = $params->{datereceived};
     my $received_items = $params->{received_items};
 
     my $dbh = C4::Context->dbh;
     my $received_items = $params->{received_items};
 
     my $dbh = C4::Context->dbh;
-    my $datereceived = ( $invoice and $invoice->{datereceived} ) ? $invoice->{datereceived} : dt_from_string;
+    $datereceived = output_pref(
+        {
+            dt => ( $datereceived ? dt_from_string( $datereceived ) : dt_from_string ),
+            dateformat => 'iso',
+            dateonly => 1,
+        }
+    );
+
     my $suggestionid = GetSuggestionFromBiblionumber( $biblionumber );
     if ($suggestionid) {
         ModSuggestion( {suggestionid=>$suggestionid,
     my $suggestionid = GetSuggestionFromBiblionumber( $biblionumber );
     if ($suggestionid) {
         ModSuggestion( {suggestionid=>$suggestionid,
@@ -1458,22 +1387,29 @@ sub ModReceiveOrder {
             UPDATE aqorders
             SET quantity = ?,
                 orderstatus = 'partial'|;
             UPDATE aqorders
             SET quantity = ?,
                 orderstatus = 'partial'|;
-        $query .= q|, order_internalnote = ?| if defined $order->{order_internalnote};
         $query .= q| WHERE ordernumber = ?|;
         my $sth = $dbh->prepare($query);
 
         $sth->execute(
             ( $is_standing ? 1 : ($order->{quantity} - $quantrec) ),
         $query .= q| WHERE ordernumber = ?|;
         my $sth = $dbh->prepare($query);
 
         $sth->execute(
             ( $is_standing ? 1 : ($order->{quantity} - $quantrec) ),
-            ( defined $order->{order_internalnote} ? $order->{order_internalnote} : () ),
             $order->{ordernumber}
         );
 
             $order->{ordernumber}
         );
 
+        if ( not $order->{subscriptionid} && defined $order->{order_internalnote} ) {
+            $dbh->do(
+                q|UPDATE aqorders
+                SET order_internalnote = ?
+                WHERE ordernumber = ?|, {},
+                $order->{order_internalnote}, $order->{ordernumber}
+            );
+        }
+
         # Recalculate tax_value
         $dbh->do(q|
             UPDATE aqorders
             SET
         # Recalculate tax_value
         $dbh->do(q|
             UPDATE aqorders
             SET
-                tax_value_on_ordering = quantity * ecost_tax_excluded * tax_rate_on_ordering,
-                tax_value_on_receiving = quantity * unitprice_tax_excluded * tax_rate_on_receiving
+                tax_value_on_ordering = quantity * | . get_rounding_sql(q|ecost_tax_excluded|) . q| * tax_rate_on_ordering,
+                tax_value_on_receiving = quantity * | . get_rounding_sql(q|unitprice_tax_excluded|) . q| * tax_rate_on_receiving
             WHERE ordernumber = ?
         |, undef, $order->{ordernumber});
 
             WHERE ordernumber = ?
         |, undef, $order->{ordernumber});
 
@@ -1485,8 +1421,8 @@ sub ModReceiveOrder {
         $order->{tax_rate_on_ordering} //= 0;
         $order->{unitprice_tax_excluded} //= 0;
         $order->{tax_rate_on_receiving} //= 0;
         $order->{tax_rate_on_ordering} //= 0;
         $order->{unitprice_tax_excluded} //= 0;
         $order->{tax_rate_on_receiving} //= 0;
-        $order->{tax_value_on_ordering} = $order->{quantity} * $order->{ecost_tax_excluded} * $order->{tax_rate_on_ordering};
-        $order->{tax_value_on_receiving} = $order->{quantity} * $order->{unitprice_tax_excluded} * $order->{tax_rate_on_receiving};
+        $order->{tax_value_on_ordering} = $order->{quantity} * get_rounded_price($order->{ecost_tax_excluded}) * $order->{tax_rate_on_ordering};
+        $order->{tax_value_on_receiving} = $order->{quantity} * get_rounded_price($order->{unitprice_tax_excluded}) * $order->{tax_rate_on_receiving};
         $order->{datereceived} = $datereceived;
         $order->{invoiceid} = $invoice->{invoiceid};
         $order->{orderstatus} = 'complete';
         $order->{datereceived} = $datereceived;
         $order->{invoiceid} = $invoice->{invoiceid};
         $order->{orderstatus} = 'complete';
@@ -1508,6 +1444,10 @@ sub ModReceiveOrder {
         |;
 
         $query .= q|
         |;
 
         $query .= q|
+            , replacementprice = ?
+        | if defined $order->{replacementprice};
+
+        $query .= q|
             , unitprice = ?, unitprice_tax_included = ?, unitprice_tax_excluded = ?
         | if defined $order->{unitprice};
 
             , unitprice = ?, unitprice_tax_included = ?, unitprice_tax_excluded = ?
         | if defined $order->{unitprice};
 
@@ -1528,6 +1468,10 @@ sub ModReceiveOrder {
         my $sth = $dbh->prepare( $query );
         my @params = ( $quantrec, $datereceived, $invoice->{invoiceid}, ( $budget_id ? $budget_id : $order->{budget_id} ) );
 
         my $sth = $dbh->prepare( $query );
         my @params = ( $quantrec, $datereceived, $invoice->{invoiceid}, ( $budget_id ? $budget_id : $order->{budget_id} ) );
 
+        if ( defined $order->{replacementprice} ) {
+            push @params, $order->{replacementprice};
+        }
+
         if ( defined $order->{unitprice} ) {
             push @params, $order->{unitprice}, $order->{unitprice_tax_included}, $order->{unitprice_tax_excluded};
         }
         if ( defined $order->{unitprice} ) {
             push @params, $order->{unitprice}, $order->{unitprice_tax_included}, $order->{unitprice_tax_excluded};
         }
@@ -1591,8 +1535,8 @@ sub CancelReceipt {
 
     my $parent_ordernumber = $order->{'parent_ordernumber'};
 
 
     my $parent_ordernumber = $order->{'parent_ordernumber'};
 
-    my @itemnumbers = GetItemnumbersFromOrder( $ordernumber );
     my $order_obj = Koha::Acquisition::Orders->find( $ordernumber ); # FIXME rewrite all this subroutine using this object
     my $order_obj = Koha::Acquisition::Orders->find( $ordernumber ); # FIXME rewrite all this subroutine using this object
+    my @itemnumbers = $order_obj->items->get_column('itemnumber');
 
     if($parent_ordernumber == $ordernumber || not $parent_ordernumber) {
         # The order line has no parent, just mark it as not received
 
     if($parent_ordernumber == $ordernumber || not $parent_ordernumber) {
         # The order line has no parent, just mark it as not received
@@ -1610,48 +1554,50 @@ sub CancelReceipt {
     } else {
         # The order line has a parent, increase parent quantity and delete
         # the order line.
     } 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 = ?,
-                orderstatus = 'ordered'
-            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;
-        }
+        unless ( $order_obj->basket->is_standing ) {
+            $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 = ?,
+                    orderstatus = 'ordered'
+                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;
+            }
 
 
-        # Recalculate tax_value
-        $dbh->do(q|
-            UPDATE aqorders
-            SET
-                tax_value_on_ordering = quantity * ecost_tax_excluded * tax_rate_on_ordering,
-                tax_value_on_receiving = quantity * unitprice_tax_excluded * tax_rate_on_receiving
-            WHERE ordernumber = ?
-        |, undef, $parent_ordernumber);
+            # Recalculate tax_value
+            $dbh->do(q|
+                UPDATE aqorders
+                SET
+                    tax_value_on_ordering = quantity * | . get_rounding_sql(q|ecost_tax_excluded|) . q| * tax_rate_on_ordering,
+                    tax_value_on_receiving = quantity * | . get_rounding_sql(q|unitprice_tax_excluded|) . q| * tax_rate_on_receiving
+                WHERE ordernumber = ?
+            |, undef, $parent_ordernumber);
+        }
 
         _cancel_items_receipt( $order_obj, $parent_ordernumber );
         # Delete order line
 
         _cancel_items_receipt( $order_obj, $parent_ordernumber );
         # Delete order line
@@ -1668,9 +1614,9 @@ sub CancelReceipt {
         my @affects = split q{\|}, C4::Context->preference("AcqItemSetSubfieldsWhenReceiptIsCancelled");
         if ( @affects ) {
             for my $in ( @itemnumbers ) {
         my @affects = split q{\|}, C4::Context->preference("AcqItemSetSubfieldsWhenReceiptIsCancelled");
         if ( @affects ) {
             for my $in ( @itemnumbers ) {
-                my $item = Koha::Items->find( $in );
+                my $item = Koha::Items->find( $in ); # FIXME We do not need that, we already have Koha::Items from $order_obj->items
                 my $biblio = $item->biblio;
                 my $biblio = $item->biblio;
-                my ( $itemfield ) = GetMarcFromKohaField( 'items.itemnumber', $biblio->frameworkcode );
+                my ( $itemfield ) = GetMarcFromKohaField( 'items.itemnumber' );
                 my $item_marc = C4::Items::GetMarcItem( $biblio->biblionumber, $in );
                 for my $affect ( @affects ) {
                     my ( $sf, $v ) = split q{=}, $affect, 2;
                 my $item_marc = C4::Items::GetMarcItem( $biblio->biblionumber, $in );
                 for my $affect ( @affects ) {
                     my ( $sf, $v ) = split q{=}, $affect, 2;
@@ -1690,7 +1636,7 @@ sub _cancel_items_receipt {
     my ( $order, $parent_ordernumber ) = @_;
     $parent_ordernumber ||= $order->ordernumber;
 
     my ( $order, $parent_ordernumber ) = @_;
     $parent_ordernumber ||= $order->ordernumber;
 
-    my @itemnumbers = GetItemnumbersFromOrder($order->ordernumber); # FIXME Must be $order->items
+    my $items = $order->items;
     if ( $order->basket->effective_create_items eq 'receiving' ) {
         # Remove items that were created at receipt
         my $query = qq{
     if ( $order->basket->effective_create_items eq 'receiving' ) {
         # Remove items that were created at receipt
         my $query = qq{
@@ -1700,13 +1646,13 @@ sub _cancel_items_receipt {
         };
         my $dbh = C4::Context->dbh;
         my $sth = $dbh->prepare($query);
         };
         my $dbh = C4::Context->dbh;
         my $sth = $dbh->prepare($query);
-        foreach my $itemnumber (@itemnumbers) {
-            $sth->execute($itemnumber, $itemnumber);
+        while ( my $item = $items->next ) {
+            $sth->execute($item->itemnumber, $item->itemnumber);
         }
     } else {
         # Update items
         }
     } else {
         # Update items
-        foreach my $itemnumber (@itemnumbers) {
-            ModItemOrder($itemnumber, $parent_ordernumber);
+        while ( my $item = $items->next ) {
+            ModItemOrder($item->itemnumber, $parent_ordernumber);
         }
     }
 }
         }
     }
 }
@@ -1877,67 +1823,6 @@ sub SearchOrders {
 
 #------------------------------------------------------------#
 
 
 #------------------------------------------------------------#
 
-=head3 DelOrder
-
-  &DelOrder($biblionumber, $ordernumber);
-
-Cancel the order with the given order and biblio numbers. It does not
-delete any entries in the aqorders table, it merely marks them as
-cancelled.
-
-=cut
-
-sub DelOrder {
-    my ( $bibnum, $ordernumber, $delete_biblio, $reason ) = @_;
-
-    my $error;
-    my $dbh = C4::Context->dbh;
-    my $query = "
-        UPDATE aqorders
-        SET    datecancellationprinted=now(), orderstatus='cancelled'
-    ";
-    if($reason) {
-        $query .= ", cancellationreason = ? ";
-    }
-    $query .= "
-        WHERE biblionumber=? AND ordernumber=?
-    ";
-    my $sth = $dbh->prepare($query);
-    if($reason) {
-        $sth->execute($reason, $bibnum, $ordernumber);
-    } else {
-        $sth->execute( $bibnum, $ordernumber );
-    }
-    $sth->finish;
-
-    my @itemnumbers = GetItemnumbersFromOrder( $ordernumber );
-    foreach my $itemnumber (@itemnumbers){
-        my $delcheck = C4::Items::DelItemCheck( $bibnum, $itemnumber );
-
-        if($delcheck != 1) {
-            $error->{'delitem'} = 1;
-        }
-    }
-
-    if($delete_biblio) {
-        # We get the number of remaining items
-        my $biblio = Koha::Biblios->find( $bibnum );
-        my $itemcount = $biblio->items->count;
-
-        # If there are no items left,
-        if ( $itemcount == 0 ) {
-            # We delete the record
-            my $delcheck = DelBiblio($bibnum);
-
-            if($delcheck) {
-                $error->{'delbiblio'} = 1;
-            }
-        }
-    }
-
-    return $error;
-}
-
 =head3 TransferOrder
 
     my $newordernumber = TransferOrder($ordernumber, $basketno);
 =head3 TransferOrder
 
     my $newordernumber = TransferOrder($ordernumber, $basketno);
@@ -2000,6 +1885,41 @@ sub TransferOrder {
     return $newordernumber;
 }
 
     return $newordernumber;
 }
 
+=head3 get_rounding_sql
+
+    $rounding_sql = get_rounding_sql($column_name);
+
+returns the correct SQL routine based on OrderPriceRounding system preference.
+
+=cut
+
+sub get_rounding_sql {
+    my ( $round_string ) = @_;
+    my $rounding_pref = C4::Context->preference('OrderPriceRounding') // q{};
+    if ( $rounding_pref eq "nearest_cent"  ) {
+        return "CAST($round_string*100 AS SIGNED)/100";
+    }
+    return $round_string;
+}
+
+=head3 get_rounded_price
+
+    $rounded_price = get_rounded_price( $price );
+
+returns a price rounded as specified in OrderPriceRounding system preference.
+
+=cut
+
+sub get_rounded_price {
+    my ( $price ) =  @_;
+    my $rounding_pref = C4::Context->preference('OrderPriceRounding') // q{};
+    if( $rounding_pref eq 'nearest_cent' ) {
+        return Koha::Number::Price->new( $price )->round();
+    }
+    return $price;
+}
+
+
 =head2 FUNCTIONS ABOUT PARCELS
 
 =head3 GetParcels
 =head2 FUNCTIONS ABOUT PARCELS
 
 =head3 GetParcels
@@ -2090,132 +2010,6 @@ sub GetParcels {
 
 #------------------------------------------------------------#
 
 
 #------------------------------------------------------------#
 
-=head3 GetLateOrders
-
-  @results = &GetLateOrders;
-
-Searches for bookseller with late orders.
-
-return:
-the table of supplier with late issues. This table is full of hashref.
-
-=cut
-
-sub GetLateOrders {
-    my $delay      = shift;
-    my $supplierid = shift;
-    my $branch     = shift;
-    my $estimateddeliverydatefrom = shift;
-    my $estimateddeliverydateto = shift;
-
-    my $dbh = C4::Context->dbh;
-
-    #BEWARE, order of parenthesis and LEFT JOIN is important for speed
-    my $dbdriver = C4::Context->config("db_scheme") || "mysql";
-
-    my @query_params = ();
-    my $select = "
-    SELECT aqbasket.basketno,
-        aqorders.ordernumber,
-        DATE(aqbasket.closedate)  AS orderdate,
-        aqbasket.basketname       AS basketname,
-        aqbasket.basketgroupid    AS basketgroupid,
-        aqbasketgroups.name       AS basketgroupname,
-        aqorders.rrp              AS unitpricesupplier,
-        aqorders.ecost            AS unitpricelib,
-        aqorders.claims_count     AS claims_count,
-        aqorders.claimed_date     AS claimed_date,
-        aqbudgets.budget_name     AS budget,
-        borrowers.branchcode      AS branch,
-        aqbooksellers.name        AS supplier,
-        aqbooksellers.id          AS supplierid,
-        biblio.author, biblio.title,
-        biblioitems.publishercode AS publisher,
-        biblioitems.publicationyear,
-        ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) AS estimateddeliverydate,
-    ";
-    my $from = "
-    FROM
-        aqorders LEFT JOIN biblio     ON biblio.biblionumber         = aqorders.biblionumber
-        LEFT JOIN biblioitems         ON biblioitems.biblionumber    = biblio.biblionumber
-        LEFT JOIN aqbudgets           ON aqorders.budget_id          = aqbudgets.budget_id,
-        aqbasket LEFT JOIN borrowers  ON aqbasket.authorisedby       = borrowers.borrowernumber
-        LEFT JOIN aqbooksellers       ON aqbasket.booksellerid       = aqbooksellers.id
-        LEFT JOIN aqbasketgroups      ON aqbasket.basketgroupid      = aqbasketgroups.id
-        WHERE aqorders.basketno = aqbasket.basketno
-        AND ( datereceived = ''
-            OR datereceived IS NULL
-            OR aqorders.quantityreceived < aqorders.quantity
-        )
-        AND aqbasket.closedate IS NOT NULL
-        AND (aqorders.datecancellationprinted IS NULL OR aqorders.datecancellationprinted='0000-00-00')
-    ";
-    my $having = "";
-    if ($dbdriver eq "mysql") {
-        $select .= "
-        aqorders.quantity - COALESCE(aqorders.quantityreceived,0)                 AS quantity,
-        (aqorders.quantity - COALESCE(aqorders.quantityreceived,0)) * aqorders.rrp AS subtotal,
-        DATEDIFF(CAST(now() AS date),closedate) AS latesince
-        ";
-        if ( defined $delay ) {
-            $from .= " AND (closedate <= DATE_SUB(CAST(now() AS date),INTERVAL ? DAY)) " ;
-            push @query_params, $delay;
-        }
-        $having = "HAVING quantity <> 0";
-    } else {
-        # FIXME: account for IFNULL as above
-        $select .= "
-                aqorders.quantity                AS quantity,
-                aqorders.quantity * aqorders.rrp AS subtotal,
-                (CAST(now() AS date) - closedate)            AS latesince
-        ";
-        if ( defined $delay ) {
-            $from .= " AND (closedate <= (CAST(now() AS date) -(INTERVAL ? DAY)) ";
-            push @query_params, $delay;
-        }
-    }
-    if (defined $supplierid) {
-        $from .= ' AND aqbasket.booksellerid = ? ';
-        push @query_params, $supplierid;
-    }
-    if (defined $branch) {
-        $from .= ' AND borrowers.branchcode LIKE ? ';
-        push @query_params, $branch;
-    }
-
-    if ( defined $estimateddeliverydatefrom or defined $estimateddeliverydateto ) {
-        $from .= ' AND aqbooksellers.deliverytime IS NOT NULL ';
-    }
-    if ( defined $estimateddeliverydatefrom ) {
-        $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) >= ?';
-        push @query_params, $estimateddeliverydatefrom;
-    }
-    if ( defined $estimateddeliverydateto ) {
-        $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) <= ?';
-        push @query_params, $estimateddeliverydateto;
-    }
-    if ( defined $estimateddeliverydatefrom and not defined $estimateddeliverydateto ) {
-        $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) <= CAST(now() AS date)';
-    }
-    if (C4::Context->preference("IndependentBranches")
-            && !C4::Context->IsSuperLibrarian() ) {
-        $from .= ' AND borrowers.branchcode LIKE ? ';
-        push @query_params, C4::Context->userenv->{branch};
-    }
-    $from .= " AND orderstatus <> 'cancelled' ";
-    my $query = "$select $from $having\nORDER BY latesince, basketno, borrowers.branchcode, supplier";
-    $debug and print STDERR "GetLateOrders query: $query\nGetLateOrders args: " . join(" ",@query_params);
-    my $sth = $dbh->prepare($query);
-    $sth->execute(@query_params);
-    my @results;
-    while (my $data = $sth->fetchrow_hashref) {
-        push @results, $data;
-    }
-    return @results;
-}
-
-#------------------------------------------------------------#
-
 =head3 GetHistory
 
   \@order_loop = GetHistory( %params );
 =head3 GetHistory
 
   \@order_loop = GetHistory( %params );
@@ -2236,6 +2030,8 @@ params:
   budget
   orderstatus (note that orderstatus '' will retrieve orders
                of any status except cancelled)
   budget
   orderstatus (note that orderstatus '' will retrieve orders
                of any status except cancelled)
+  is_standing
+  managing_library
   biblionumber
   get_canceled_order (if set to a true value, cancelled orders will
                       be included)
   biblionumber
   get_canceled_order (if set to a true value, cancelled orders will
                       be included)
@@ -2256,7 +2052,9 @@ returns:
                 'ordernumber'      => '1',
                 'quantity'         => 1,
                 'quantityreceived' => undef,
                 'ordernumber'      => '1',
                 'quantity'         => 1,
                 'quantityreceived' => undef,
-                'title'            => 'The Adventures of Huckleberry Finn'
+                'title'            => 'The Adventures of Huckleberry Finn',
+                'managing_library' => 'CPL'
+                'is_standing'      => '1'
             }
 
 =cut
             }
 
 =cut
@@ -2277,17 +2075,36 @@ sub GetHistory {
     my $basketgroupname = $params{basketgroupname};
     my $budget = $params{budget};
     my $orderstatus = $params{orderstatus};
     my $basketgroupname = $params{basketgroupname};
     my $budget = $params{budget};
     my $orderstatus = $params{orderstatus};
+    my $is_standing = $params{is_standing};
     my $biblionumber = $params{biblionumber};
     my $get_canceled_order = $params{get_canceled_order} || 0;
     my $ordernumber = $params{ordernumber};
     my $search_children_too = $params{search_children_too} || 0;
     my $created_by = $params{created_by} || [];
     my $biblionumber = $params{biblionumber};
     my $get_canceled_order = $params{get_canceled_order} || 0;
     my $ordernumber = $params{ordernumber};
     my $search_children_too = $params{search_children_too} || 0;
     my $created_by = $params{created_by} || [];
+    my $managing_library = $params{managing_library};
+    my $ordernumbers = $params{ordernumbers} || [];
+    my $additional_fields = $params{additional_fields} // [];
 
 
-    my @order_loop;
     my $total_qty         = 0;
     my $total_qtyreceived = 0;
     my $total_price       = 0;
 
     my $total_qty         = 0;
     my $total_qtyreceived = 0;
     my $total_price       = 0;
 
+    #get variation of isbn
+    my @isbn_params;
+    my @isbns;
+    if ($isbn){
+        if ( C4::Context->preference("SearchWithISBNVariations") ){
+            @isbns = C4::Koha::GetVariationsOfISBN( $isbn );
+            foreach my $isb (@isbns){
+                push @isbn_params, '?';
+            }
+        }
+        unless (@isbns){
+            push @isbns, $isbn;
+            push @isbn_params, '?';
+        }
+    }
+
     my $dbh   = C4::Context->dbh;
     my $query ="
         SELECT
     my $dbh   = C4::Context->dbh;
     my $query ="
         SELECT
@@ -2299,7 +2116,9 @@ sub GetHistory {
             aqbasket.basketname,
             aqbasket.basketgroupid,
             aqbasket.authorisedby,
             aqbasket.basketname,
             aqbasket.basketgroupid,
             aqbasket.authorisedby,
+            aqbasket.is_standing,
             concat( borrowers.firstname,' ',borrowers.surname) AS authorisedbyname,
             concat( borrowers.firstname,' ',borrowers.surname) AS authorisedbyname,
+            branch as managing_library,
             aqbasketgroups.name as groupname,
             aqbooksellers.name,
             aqbasket.creationdate,
             aqbasketgroups.name as groupname,
             aqbooksellers.name,
             aqbasket.creationdate,
@@ -2334,7 +2153,7 @@ sub GetHistory {
     $query .= " WHERE 1 ";
 
     unless ($get_canceled_order or (defined $orderstatus and $orderstatus eq 'cancelled')) {
     $query .= " WHERE 1 ";
 
     unless ($get_canceled_order or (defined $orderstatus and $orderstatus eq 'cancelled')) {
-        $query .= " AND (datecancellationprinted is NULL or datecancellationprinted='0000-00-00') ";
+        $query .= " AND datecancellationprinted IS NULL ";
     }
 
     my @query_params  = ();
     }
 
     my @query_params  = ();
@@ -2355,10 +2174,13 @@ sub GetHistory {
         push @query_params, "%$author%";
     }
 
         push @query_params, "%$author%";
     }
 
-    if ( $isbn ) {
-        $query .= " AND biblioitems.isbn LIKE ? ";
-        push @query_params, "%$isbn%";
+    if ( @isbns ) {
+        $query .= " AND ( biblioitems.isbn LIKE " . join (" OR biblioitems.isbn LIKE ", @isbn_params ) . ")";
+        foreach my $isb (@isbns){
+            push @query_params, "%$isb%";
+        }
     }
     }
+
     if ( $ean ) {
         $query .= " AND biblioitems.ean = ? ";
         push @query_params, "$ean";
     if ( $ean ) {
         $query .= " AND biblioitems.ean = ? ";
         push @query_params, "$ean";
@@ -2388,6 +2210,11 @@ sub GetHistory {
         push @query_params, "$orderstatus";
     }
 
         push @query_params, "$orderstatus";
     }
 
+    if ( $is_standing ) {
+        $query .= " AND is_standing = ? ";
+        push @query_params, $is_standing;
+    }
+
     if ($basket) {
         if ($basket =~ m/^\d+$/) {
             $query .= " AND aqorders.basketno = ? ";
     if ($basket) {
         if ($basket =~ m/^\d+$/) {
             $query .= " AND aqorders.basketno = ? ";
@@ -2423,6 +2250,23 @@ sub GetHistory {
         push @query_params, @$created_by;
     }
 
         push @query_params, @$created_by;
     }
 
+    if ( $managing_library ) {
+        $query .= " AND aqbasket.branch = ? ";
+        push @query_params, $managing_library;
+    }
+
+    if ( @$ordernumbers ) {
+        $query .= ' AND (aqorders.ordernumber IN ( ' . join (',', ('?') x @$ordernumbers ) . '))';
+        push @query_params, @$ordernumbers;
+    }
+    if ( @$additional_fields ) {
+        my @baskets = Koha::Acquisition::Baskets->filter_by_additional_fields($additional_fields);
+
+        return [] unless @baskets;
+
+        # No parameterization because record IDs come directly from DB
+        $query .= ' AND aqbasket.basketno IN ( ' . join( ',', map { $_->basketno } @baskets ) . ' )';
+    }
 
     if ( C4::Context->preference("IndependentBranches") ) {
         unless ( C4::Context->IsSuperLibrarian() ) {
 
     if ( C4::Context->preference("IndependentBranches") ) {
         unless ( C4::Context->IsSuperLibrarian() ) {
@@ -2518,7 +2362,8 @@ sub GetInvoices {
 
     my $dbh = C4::Context->dbh;
     my $query = qq{
 
     my $dbh = C4::Context->dbh;
     my $query = qq{
-        SELECT aqinvoices.*, aqbooksellers.name AS suppliername,
+        SELECT aqinvoices.invoiceid, aqinvoices.invoicenumber, aqinvoices.booksellerid, aqinvoices.shipmentdate, aqinvoices.billingdate, aqinvoices.closedate, aqinvoices.shipmentcost, aqinvoices.shipmentcost_budgetid, aqinvoices.message_id,
+            aqbooksellers.name AS suppliername,
           COUNT(
             DISTINCT IF(
               aqorders.datereceived IS NOT NULL,
           COUNT(
             DISTINCT IF(
               aqorders.datereceived IS NOT NULL,
@@ -2604,11 +2449,11 @@ sub GetInvoices {
     }
 
     $query .= " WHERE " . join(" AND ", @bind_strs) if @bind_strs;
     }
 
     $query .= " WHERE " . join(" AND ", @bind_strs) if @bind_strs;
-    $query .= " GROUP BY aqinvoices.invoiceid ";
+    $query .= " GROUP BY aqinvoices.invoiceid, aqinvoices.invoicenumber, aqinvoices.booksellerid, aqinvoices.shipmentdate, aqinvoices.billingdate, aqinvoices.closedate, aqinvoices.shipmentcost, aqinvoices.shipmentcost_budgetid, aqinvoices.message_id, aqbooksellers.name";
 
     if($args{order_by}) {
         my ($column, $direction) = split / /, $args{order_by};
 
     if($args{order_by}) {
         my ($column, $direction) = split / /, $args{order_by};
-        if(grep /^$column$/, @columns) {
+        if(grep  { $_ eq $column } @columns) {
             $direction ||= 'ASC';
             $query .= " ORDER BY $column $direction";
         }
             $direction ||= 'ASC';
             $query .= " ORDER BY $column $direction";
         }
@@ -2732,7 +2577,7 @@ sub AddInvoice {
     my @set_strs;
     my @set_args;
     foreach my $key (keys %invoice) {
     my @set_strs;
     my @set_args;
     foreach my $key (keys %invoice) {
-        if(0 < grep(/^$key$/, @columns)) {
+        if(0 < grep { $_ eq $key } @columns) {
             push @set_strs, "$key = ?";
             push @set_args, ($invoice{$key} || undef);
         }
             push @set_strs, "$key = ?";
             push @set_args, ($invoice{$key} || undef);
         }
@@ -2782,7 +2627,7 @@ sub ModInvoice {
     my @set_strs;
     my @set_args;
     foreach my $key (keys %invoice) {
     my @set_strs;
     my @set_args;
     foreach my $key (keys %invoice) {
-        if(0 < grep(/^$key$/, @columns)) {
+        if(0 < grep { $_ eq $key } @columns) {
             push @set_strs, "$key = ?";
             push @set_args, ($invoice{$key} || undef);
         }
             push @set_strs, "$key = ?";
             push @set_args, ($invoice{$key} || undef);
         }
@@ -2922,7 +2767,7 @@ sub GetBiblioCountByBasketno {
         SELECT COUNT( DISTINCT( biblionumber ) )
         FROM   aqorders
         WHERE  basketno = ?
         SELECT COUNT( DISTINCT( biblionumber ) )
         FROM   aqorders
         WHERE  basketno = ?
-            AND (datecancellationprinted IS NULL OR datecancellationprinted='0000-00-00')
+            AND datecancellationprinted IS NULL
         ";
 
     my $sth = $dbh->prepare($query);
         ";
 
     my $sth = $dbh->prepare($query);
@@ -2930,8 +2775,40 @@ sub GetBiblioCountByBasketno {
     return $sth->fetchrow;
 }
 
     return $sth->fetchrow;
 }
 
-# Note this subroutine should be moved to Koha::Acquisition::Order
-# Will do when a DBIC decision will be taken.
+=head3 populate_order_with_prices
+
+$order = populate_order_with_prices({
+    order        => $order #a hashref with the order values
+    booksellerid => $booksellerid #FIXME - should obtain from order basket
+    receiving    => 1 # boolean representing order stage, should pass only this or ordering
+    ordering     => 1 # boolean representing order stage
+});
+
+
+Sets calculated values for an order - all values are stored with full precision
+regardless of rounding preference except for tax value which is calculated
+on rounded values if requested
+
+For ordering the values set are:
+    rrp_tax_included
+    rrp_tax_excluded
+    ecost_tax_included
+    ecost_tax_excluded
+    tax_value_on_ordering
+For receiving the value set are:
+    unitprice_tax_included
+    unitprice_tax_excluded
+    tax_value_on_receiving
+
+Note: When receiving, if the rounded value of the unitprice matches the rounded
+value of the ecost then then ecost (full precision) is used.
+
+Returns a hashref of the order
+
+FIXME: Move this to Koha::Acquisition::Order.pm
+
+=cut
+
 sub populate_order_with_prices {
     my ($params) = @_;
 
 sub populate_order_with_prices {
     my ($params) = @_;
 
@@ -2949,38 +2826,49 @@ sub populate_order_with_prices {
     if ($ordering) {
         $order->{tax_rate_on_ordering} //= $order->{tax_rate};
         if ( $bookseller->listincgst ) {
     if ($ordering) {
         $order->{tax_rate_on_ordering} //= $order->{tax_rate};
         if ( $bookseller->listincgst ) {
-            # The user entered the rrp tax included
+
+            # The user entered the prices tax included
+            $order->{unitprice} += 0;
+            $order->{unitprice_tax_included} = $order->{unitprice};
             $order->{rrp_tax_included} = $order->{rrp};
 
             $order->{rrp_tax_included} = $order->{rrp};
 
-            # rrp tax excluded = rrp tax included / ( 1 + tax rate )
+            # price tax excluded = price tax included / ( 1 + tax rate )
+            $order->{unitprice_tax_excluded} = $order->{unitprice_tax_included} / ( 1 + $order->{tax_rate_on_ordering} );
             $order->{rrp_tax_excluded} = $order->{rrp_tax_included} / ( 1 + $order->{tax_rate_on_ordering} );
 
             $order->{rrp_tax_excluded} = $order->{rrp_tax_included} / ( 1 + $order->{tax_rate_on_ordering} );
 
+            # ecost tax included = rrp tax included  ( 1 - discount )
+            $order->{ecost_tax_included} = $order->{rrp_tax_included} * ( 1 - $discount );
+
             # ecost tax excluded = rrp tax excluded * ( 1 - discount )
             $order->{ecost_tax_excluded} = $order->{rrp_tax_excluded} * ( 1 - $discount );
 
             # ecost tax excluded = rrp tax excluded * ( 1 - discount )
             $order->{ecost_tax_excluded} = $order->{rrp_tax_excluded} * ( 1 - $discount );
 
-            # ecost tax included = rrp tax included  ( 1 - discount )
-            $order->{ecost_tax_included} = $order->{rrp_tax_included} * ( 1 - $discount );
+            # tax value = quantity * ecost tax excluded * tax rate
+            # we should use the unitprice if included
+            my $cost_tax_included = $order->{unitprice_tax_included} || $order->{ecost_tax_included};
+            my $cost_tax_excluded = $order->{unitprice_tax_excluded} || $order->{ecost_tax_excluded};
+            $order->{tax_value_on_ordering} = ( get_rounded_price($cost_tax_included) - get_rounded_price($cost_tax_excluded) ) * $order->{quantity};
+
         }
         else {
         }
         else {
-            # The user entered the rrp tax excluded
+            # The user entered the prices tax excluded
+            $order->{unitprice_tax_excluded} = $order->{unitprice};
             $order->{rrp_tax_excluded} = $order->{rrp};
 
             $order->{rrp_tax_excluded} = $order->{rrp};
 
-            # rrp tax included = rrp tax excluded * ( 1 - tax rate )
+            # price tax included = price tax excluded * ( 1 - tax rate )
+            $order->{unitprice_tax_included} = $order->{unitprice_tax_excluded} * ( 1 + $order->{tax_rate_on_ordering} );
             $order->{rrp_tax_included} = $order->{rrp_tax_excluded} * ( 1 + $order->{tax_rate_on_ordering} );
 
             # ecost tax excluded = rrp tax excluded * ( 1 - discount )
             $order->{ecost_tax_excluded} = $order->{rrp_tax_excluded} * ( 1 - $discount );
 
             $order->{rrp_tax_included} = $order->{rrp_tax_excluded} * ( 1 + $order->{tax_rate_on_ordering} );
 
             # ecost tax excluded = rrp tax excluded * ( 1 - discount )
             $order->{ecost_tax_excluded} = $order->{rrp_tax_excluded} * ( 1 - $discount );
 
-            # ecost tax included = rrp tax excluded * ( 1 + tax rate ) * ( 1 - discount )
-            $order->{ecost_tax_included} =
-                $order->{rrp_tax_excluded} *
-                ( 1 + $order->{tax_rate_on_ordering} ) *
-                ( 1 - $discount );
-        }
+            # ecost tax included = rrp tax excluded * ( 1 + tax rate ) * ( 1 - discount ) = ecost tax excluded * ( 1 + tax rate )
+            $order->{ecost_tax_included} = $order->{ecost_tax_excluded} * ( 1 + $order->{tax_rate_on_ordering} );
 
 
-        # tax value = quantity * ecost tax excluded * tax rate
-        $order->{tax_value_on_ordering} =
-            $order->{quantity} * $order->{ecost_tax_excluded} * $order->{tax_rate_on_ordering};
+            # tax value = quantity * ecost tax included * tax rate
+            # we should use the unitprice if included
+            my $cost_tax_excluded = $order->{unitprice_tax_excluded} || $order->{ecost_tax_excluded};
+            $order->{tax_value_on_ordering} = $order->{quantity} * get_rounded_price($cost_tax_excluded) * $order->{tax_rate_on_ordering};
+        }
     }
 
     if ($receiving) {
     }
 
     if ($receiving) {
@@ -3014,7 +2902,7 @@ sub populate_order_with_prices {
         }
 
         # tax value = quantity * unit price tax excluded * tax rate
         }
 
         # tax value = quantity * unit price tax excluded * tax rate
-        $order->{tax_value_on_receiving} = $order->{quantity} * $order->{unitprice_tax_excluded} * $order->{tax_rate_on_receiving};
+        $order->{tax_value_on_receiving} = $order->{quantity} * get_rounded_price($order->{unitprice_tax_excluded}) * $order->{tax_rate_on_receiving};
     }
 
     return $order;
     }
 
     return $order;
@@ -3122,42 +3010,59 @@ sub NotifyOrderUsers {
 
 =head3 FillWithDefaultValues
 
 
 =head3 FillWithDefaultValues
 
-FillWithDefaultValues( $marc_record );
+FillWithDefaultValues( $marc_record, $params );
 
 This will update the record with default value defined in the ACQ framework.
 For all existing fields, if a default value exists and there are no subfield, it will be created.
 If the field does not exist, it will be created too.
 
 
 This will update the record with default value defined in the ACQ framework.
 For all existing fields, if a default value exists and there are no subfield, it will be created.
 If the field does not exist, it will be created too.
 
+If the parameter only_mandatory => 1 is passed via $params, only the mandatory
+defaults are being applied to the record.
+
 =cut
 
 sub FillWithDefaultValues {
 =cut
 
 sub FillWithDefaultValues {
-    my ($record) = @_;
+    my ( $record, $params ) = @_;
+    my $mandatory = $params->{only_mandatory};
     my $tagslib = C4::Biblio::GetMarcStructure( 1, 'ACQ', { unsafe => 1 } );
     if ($tagslib) {
         my ($itemfield) =
     my $tagslib = C4::Biblio::GetMarcStructure( 1, 'ACQ', { unsafe => 1 } );
     if ($tagslib) {
         my ($itemfield) =
-          C4::Biblio::GetMarcFromKohaField( 'items.itemnumber', '' );
+          C4::Biblio::GetMarcFromKohaField( 'items.itemnumber' );
         for my $tag ( sort keys %$tagslib ) {
             next unless $tag;
             next if $tag == $itemfield;
             for my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
                 next if IsMarcStructureInternal($tagslib->{$tag}{$subfield});
         for my $tag ( sort keys %$tagslib ) {
             next unless $tag;
             next if $tag == $itemfield;
             for my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
                 next if IsMarcStructureInternal($tagslib->{$tag}{$subfield});
+                next if $mandatory && !$tagslib->{$tag}{$subfield}{mandatory};
                 my $defaultvalue = $tagslib->{$tag}{$subfield}{defaultvalue};
                 if ( defined $defaultvalue and $defaultvalue ne '' ) {
                     my @fields = $record->field($tag);
                     if (@fields) {
                         for my $field (@fields) {
                 my $defaultvalue = $tagslib->{$tag}{$subfield}{defaultvalue};
                 if ( defined $defaultvalue and $defaultvalue ne '' ) {
                     my @fields = $record->field($tag);
                     if (@fields) {
                         for my $field (@fields) {
-                            unless ( defined $field->subfield($subfield) ) {
+                            if ( $field->is_control_field ) {
+                                $field->update($defaultvalue) if not defined $field->data;
+                            }
+                            elsif ( not defined $field->subfield($subfield) ) {
                                 $field->add_subfields(
                                     $subfield => $defaultvalue );
                             }
                         }
                     }
                     else {
                                 $field->add_subfields(
                                     $subfield => $defaultvalue );
                             }
                         }
                     }
                     else {
-                        $record->insert_fields_ordered(
-                            MARC::Field->new(
-                                $tag, '', '', $subfield => $defaultvalue
-                            )
-                        );
+                        if ( $tag < 10 ) { # is_control_field
+                            $record->insert_fields_ordered(
+                                MARC::Field->new(
+                                    $tag, $defaultvalue
+                                )
+                            );
+                        }
+                        else {
+                            $record->insert_fields_ordered(
+                                MARC::Field->new(
+                                    $tag, '', '', $subfield => $defaultvalue
+                                )
+                            );
+                        }
                     }
                 }
             }
                     }
                 }
             }