Bug 33146: Unit tests
[koha-ffzg.git] / C4 / Acquisition.pm
index 4d33a68..6873a67 100644 (file)
@@ -19,17 +19,18 @@ package C4::Acquisition;
 
 
 use Modern::Perl;
-use Carp;
+use Carp qw( carp croak );
+use Text::CSV_XS;
 use C4::Context;
-use C4::Debug;
-use C4::Suggestions;
-use C4::Biblio;
-use C4::Contract;
-use C4::Debug;
+use C4::Suggestions qw( GetSuggestion GetSuggestionFromBiblionumber ModSuggestion );
+use C4::Biblio qw( GetMarcFromKohaField GetMarcStructure IsMarcStructureInternal );
+use C4::Contract qw( GetContract );
+use C4::Log qw( logaction );
 use C4::Templates qw(gettemplate);
-use Koha::DateUtils qw( dt_from_string output_pref );
+use Koha::DateUtils qw( dt_from_string );
 use Koha::Acquisition::Baskets;
 use Koha::Acquisition::Booksellers;
+use Koha::Acquisition::Invoices;
 use Koha::Acquisition::Orders;
 use Koha::Biblios;
 use Koha::Exceptions;
@@ -42,59 +43,57 @@ use Koha::Patrons;
 use C4::Koha;
 
 use MARC::Field;
-use MARC::Record;
+use JSON qw( to_json );
 
-use Time::localtime;
-
-use vars qw(@ISA @EXPORT);
 
+our (@ISA, @EXPORT_OK);
 BEGIN {
     require Exporter;
-    @ISA    = qw(Exporter);
-    @EXPORT = qw(
-        &GetBasket &NewBasket &CloseBasket &ReopenBasket &DelBasket &ModBasket
-        &GetBasketAsCSV &GetBasketGroupAsCSV
-        &GetBasketsByBookseller &GetBasketsByBasketgroup
-        &GetBasketsInfosByBookseller
-
-        &GetBasketUsers &ModBasketUsers
-        &CanUserManageBasket
-
-        &ModBasketHeader
-
-        &ModBasketgroup &NewBasketgroup &DelBasketgroup &GetBasketgroup &CloseBasketgroup
-        &GetBasketgroups &ReOpenBasketgroup
-
-        &DelOrder &ModOrder &GetOrder &GetOrders &GetOrdersByBiblionumber
-        &GetLateOrders &GetOrderFromItemnumber
-        &SearchOrders &GetHistory &GetRecentAcqui
-        &ModReceiveOrder &CancelReceipt
-        &TransferOrder
-        &GetLastOrderNotReceivedFromSubscriptionid &GetLastOrderReceivedFromSubscriptionid
-        &ModItemOrder
-
-        &GetParcels
-
-        &GetInvoices
-        &GetInvoice
-        &GetInvoiceDetails
-        &AddInvoice
-        &ModInvoice
-        &CloseInvoice
-        &ReopenInvoice
-        &DelInvoice
-        &MergeInvoices
-
-        &AddClaim
-        &GetBiblioCountByBasketno
-
-        &GetOrderUsers
-        &ModOrderUsers
-        &NotifyOrderUsers
-
-        &FillWithDefaultValues
-
-        &get_rounded_price
+    @ISA       = qw(Exporter);
+    @EXPORT_OK = qw(
+      GetBasket NewBasket ReopenBasket ModBasket
+      GetBasketAsCSV GetBasketGroupAsCSV
+      GetBasketsByBookseller GetBasketsByBasketgroup
+      GetBasketsInfosByBookseller
+
+      GetBasketUsers ModBasketUsers
+      CanUserManageBasket
+
+      ModBasketHeader
+
+      ModBasketgroup NewBasketgroup DelBasketgroup GetBasketgroup CloseBasketgroup
+      GetBasketgroups ReOpenBasketgroup
+
+      ModOrder GetOrder GetOrders GetOrdersByBiblionumber
+      GetOrderFromItemnumber
+      SearchOrders GetHistory GetRecentAcqui
+      ModReceiveOrder CancelReceipt
+      TransferOrder
+      ModItemOrder
+
+      GetParcels
+
+      GetInvoices
+      GetInvoice
+      GetInvoiceDetails
+      AddInvoice
+      ModInvoice
+      CloseInvoice
+      ReopenInvoice
+      DelInvoice
+      MergeInvoices
+
+      AddClaim
+      GetBiblioCountByBasketno
+
+      GetOrderUsers
+      ModOrderUsers
+      NotifyOrderUsers
+
+      FillWithDefaultValues
+
+      get_rounded_price
+      get_rounding_sql
     );
 }
 
@@ -200,31 +199,22 @@ sub NewBasket {
     $basketname           ||= q{}; # default to empty strings
     $basketnote           ||= q{};
     $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
+    # Log the basket creation
+    if (C4::Context->preference("AcquisitionLog")) {
+        my $created = Koha::Acquisition::Baskets->find( $basket );
+        logaction(
+            'ACQUISITIONS',
+            'ADD_BASKET',
+            $basket,
+            to_json($created->unblessed)
+        );
+    }
 
-sub CloseBasket {
-    my ($basketno) = @_;
-    my $dbh        = C4::Context->dbh;
-    $dbh->do('UPDATE aqbasket SET closedate=now() WHERE basketno=?', {}, $basketno );
+    ModBasketHeader( $basket, $basketname, $basketnote, $basketbooksellernote,
+        $basketcontractnumber, $booksellerid, $deliveryplace, $billingplace, $is_standing, $create_items );
 
-    $dbh->do(
-q{UPDATE aqorders SET orderstatus = 'ordered' WHERE basketno = ? AND orderstatus NOT IN ( 'complete', 'cancelled')},
-        {}, $basketno
-    );
-    return;
+    return $basket;
 }
 
 =head3 ReopenBasket
@@ -246,6 +236,17 @@ sub ReopenBasket {
         WHERE basketno = ?
         AND orderstatus NOT IN ( 'complete', 'cancelled' )
         }, {}, $basketno);
+
+    # Log the basket reopening
+    if (C4::Context->preference("AcquisitionLog")) {
+        my $reopened = Koha::Acquisition::Baskets->find( $basketno );
+        logaction(
+            'ACQUISITIONS',
+            'REOPEN_BASKET',
+            $basketno,
+            to_json($reopened->unblessed)
+        );
+    }
     return;
 }
 
@@ -275,7 +276,9 @@ sub GetBasketAsCSV {
         my $csv_profile = Koha::CsvProfiles->find( $csv_profile_id );
         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 $delimiter = $csv_profile->csv_separator;
+        $delimiter = "\t" if $delimiter eq "\\t";
+        my $csv = Text::CSV_XS->new({'quote_char'=>'"','escape_char'=>'"','sep_char'=>$delimiter,'binary'=>1});
         my $csv_profile_content = $csv_profile->content;
         my ( @headers, @fields );
         while ( $csv_profile_content =~ /
@@ -308,7 +311,7 @@ sub GetBasketAsCSV {
             }
             push @rows, \@row;
         }
-        my $content = join( $csv_profile->csv_separator, @headers ) . "\n";
+        my $content = join( $delimiter, @headers ) . "\n";
         for my $row ( @rows ) {
             $csv->combine(@$row);
             my $string = $csv->string;
@@ -319,20 +322,23 @@ sub GetBasketAsCSV {
     else {
         foreach my $order (@orders) {
             my $biblio = Koha::Biblios->find( $order->{biblionumber} );
-            my $biblioitem = $biblio->biblioitem;
+            my $biblioitem;
+            if ($biblio) {
+                $biblioitem = $biblio->biblioitem;
+            }
             my $row = {
-                contractname => $contract->{'contractname'},
-                ordernumber => $order->{'ordernumber'},
-                entrydate => $order->{'entrydate'},
-                isbn => $order->{'isbn'},
-                author => $biblio->author,
-                title => $biblio->title,
-                publicationyear => $biblioitem->publicationyear,
-                publishercode => $biblioitem->publishercode,
-                collectiontitle => $biblioitem->collectiontitle,
-                notes => $order->{'order_vendornote'},
-                quantity => $order->{'quantity'},
-                rrp => $order->{'rrp'},
+                contractname    => $contract->{'contractname'},
+                ordernumber     => $order->{'ordernumber'},
+                entrydate       => $order->{'entrydate'},
+                isbn            => $order->{'isbn'},
+                author          => $biblio     ? $biblio->author              : q{},
+                title           => $biblio     ? $biblio->title               : q{},
+                publicationyear => $biblioitem ? $biblioitem->publicationyear : q{},
+                publishercode   => $biblioitem ? $biblioitem->publishercode   : q{},
+                collectiontitle => $biblioitem ? $biblioitem->collectiontitle : q{},
+                notes           => $order->{'order_vendornote'},
+                quantity        => $order->{'quantity'},
+                rrp             => $order->{'rrp'},
             };
             for my $place ( qw( deliveryplace billingplace ) ) {
                 if ( my $library = Koha::Libraries->find( $row->{deliveryplace} ) ) {
@@ -389,30 +395,33 @@ sub GetBasketGroupAsCSV {
 
         foreach my $order (@orders) {
             my $biblio = Koha::Biblios->find( $order->{biblionumber} );
-            my $biblioitem = $biblio->biblioitem;
+            my $biblioitem;
+            if ($biblio) {
+                $biblioitem = $biblio->biblioitem;
+            }
             my $row = {
-                clientnumber => $bookseller->accountnumber,
-                basketname => $basket->{basketname},
-                ordernumber => $order->{ordernumber},
-                author => $biblio->author,
-                title => $biblio->title,
-                publishercode => $biblioitem->publishercode,
-                publicationyear => $biblioitem->publicationyear,
-                collectiontitle => $biblioitem->collectiontitle,
-                isbn => $order->{isbn},
-                quantity => $order->{quantity},
-                rrp_tax_included => $order->{rrp_tax_included},
-                rrp_tax_excluded => $order->{rrp_tax_excluded},
-                discount => $bookseller->discount,
+                clientnumber       => $bookseller->accountnumber,
+                basketname         => $basket->{basketname},
+                ordernumber        => $order->{ordernumber},
+                author             => $biblio     ? $biblio->author              : q{},
+                title              => $biblio     ? $biblio->title               : q{},
+                publishercode      => $biblioitem ? $biblioitem->publishercode   : q{},
+                publicationyear    => $biblioitem ? $biblioitem->publicationyear : q{},
+                collectiontitle    => $biblioitem ? $biblioitem->collectiontitle : q{},
+                isbn               => $order->{isbn},
+                quantity           => $order->{quantity},
+                rrp_tax_included   => $order->{rrp_tax_included},
+                rrp_tax_excluded   => $order->{rrp_tax_excluded},
+                discount           => $bookseller->discount,
                 ecost_tax_included => $order->{ecost_tax_included},
                 ecost_tax_excluded => $order->{ecost_tax_excluded},
-                notes => $order->{order_vendornote},
-                entrydate => $order->{entrydate},
-                booksellername => $bookseller->name,
-                bookselleraddress => $bookseller->address1,
-                booksellerpostal => $bookseller->postal,
-                contractnumber => $contract->{contractnumber},
-                contractname => $contract->{contractname},
+                notes              => $order->{order_vendornote},
+                entrydate          => $order->{entrydate},
+                booksellername     => $bookseller->name,
+                bookselleraddress  => $bookseller->address1,
+                booksellerpostal   => $bookseller->postal,
+                contractnumber     => $contract->{contractnumber},
+                contractname       => $contract->{contractname},
             };
             my $temp = {
                 basketgroupdeliveryplace => $basketgroup->{deliveryplace},
@@ -485,32 +494,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);
@@ -547,6 +530,19 @@ sub ModBasket {
     my $sth = $dbh->prepare($query);
     $sth->execute(@params);
 
+    # Log the basket update
+    if (C4::Context->preference("AcquisitionLog")) {
+        my $modified = Koha::Acquisition::Baskets->find(
+            $basketinfo->{basketno}
+        );
+        logaction(
+            'ACQUISITIONS',
+            'MODIFY_BASKET',
+            $basketinfo->{basketno},
+            to_json($modified->unblessed)
+        );
+    }
+
     return;
 }
 
@@ -604,6 +600,20 @@ sub ModBasketHeader {
         my $sth2 = $dbh->prepare($query2);
         $sth2->execute($contractnumber,$basketno);
     }
+
+    # Log the basket update
+    if (C4::Context->preference("AcquisitionLog")) {
+        my $modified = Koha::Acquisition::Baskets->find(
+            $basketno
+        );
+        logaction(
+            'ACQUISITIONS',
+            'MODIFY_BASKET_HEADER',
+            $basketno,
+            to_json($modified->unblessed)
+        );
+    }
+
     return;
 }
 
@@ -680,10 +690,11 @@ sub GetBasketsInfosByBookseller {
           COUNT(DISTINCT aqorders.biblionumber) AS total_biblios,
           SUM(
             IF(aqorders.datereceived IS NULL
-              AND (aqorders.datecancellationprinted IS NULL OR aqorders.datecancellationprinted='0000-00-00')
+              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 = ?};
@@ -695,7 +706,7 @@ sub GetBasketsInfosByBookseller {
         $query.=" HAVING (closedate IS NULL OR (
           SUM(
             IF(aqorders.datereceived IS NULL
-              AND (aqorders.datecancellationprinted IS NULL OR aqorders.datecancellationprinted='0000-00-00')
+              AND aqorders.datecancellationprinted IS NULL
             , aqorders.quantity
             , 0)
             ) > 0))"
@@ -783,6 +794,20 @@ sub ModBasketUsers {
     foreach my $basketuser_id (@basketusers_ids) {
         $sth->execute($basketno, $basketuser_id);
     }
+
+    # Log the basket update
+    if (C4::Context->preference("AcquisitionLog")) {
+        logaction(
+            'ACQUISITIONS',
+            'MODIFY_BASKET_USERS',
+            $basketno,
+            to_json({
+                basketno    => $basketno,
+                basketusers => @basketusers_ids
+            })
+        );
+    }
+
     return;
 }
 
@@ -1134,15 +1159,14 @@ sub GetOrders {
     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|
-            AND (datecancellationprinted IS NULL OR datecancellationprinted='0000-00-00')
+            AND datecancellationprinted IS NULL
         |;
     }
 
@@ -1221,13 +1245,11 @@ sub GetOrder {
                 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,
                 biblioitems.publishercode AS publisher,
-                ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) AS estimateddeliverydate,
+                ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) AS calculateddeliverydate,
                 DATE(aqbasket.closedate)  AS orderdate,
                 aqorders.quantity - COALESCE(aqorders.quantityreceived,0)                 AS quantity_to_receive,
                 (aqorders.quantity - COALESCE(aqorders.quantityreceived,0)) * aqorders.rrp AS subtotal,
@@ -1246,70 +1268,6 @@ sub GetOrder {
     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);
@@ -1345,7 +1303,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)
-        next unless grep(/^$orderinfokey$/, @$colnames);
+        next unless grep { $_ eq $orderinfokey } @$colnames;
             $query .= "$orderinfokey=?, ";
             push(@params, $orderinfo->{$orderinfokey});
     }
@@ -1394,8 +1352,8 @@ sub ModItemOrder {
             user                 => $user,
             invoice              => $invoice,
             budget_id            => $budget_id,
+            datereceived         => $datereceived,
             received_itemnumbers => \@received_itemnumbers,
-            order_internalnote   => $order_internalnote,
         }
     );
 
@@ -1418,10 +1376,16 @@ sub ModReceiveOrder {
     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 $datereceived = ( $invoice and $invoice->{datereceived} ) ? $invoice->{datereceived} : dt_from_string;
+    $datereceived = $datereceived ? dt_from_string( $datereceived ) : dt_from_string;
+    $datereceived = $datereceived->ymd;
+
+    $order->{invoice_unitprice} ||= $order->{unitprice};
+    $order->{invoice_currency}  ||= Koha::Acquisition::Currencies->get_active->currency;
+
     my $suggestionid = GetSuggestionFromBiblionumber( $biblionumber );
     if ($suggestionid) {
         ModSuggestion( {suggestionid=>$suggestionid,
@@ -1454,19 +1418,29 @@ sub ModReceiveOrder {
             $order->{ordernumber}
         );
 
-        if ( not $order->{subscriptionid} && defined $order->{order_internalnote} ) {
-            $dbh->do(q|UPDATE aqorders
-                SET order_internalnote = ?|, {}, $order->{order_internalnote});
-        }
-
         # Recalculate tax_value
-        $dbh->do(q|
+        $query = 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
+                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
+        |;
+
+        my @params;
+        if ( not $order->{subscriptionid} && defined $order->{order_internalnote} )
+        {
+            $query .= q|, order_internalnote = ?|;
+            push @params, $order->{order_internalnote};
+        }
+
+        $query .= q|, invoice_unitprice = ?, invoice_currency = ?|;
+        push @params, $order->{invoice_unitprice}, $order->{invoice_currency};
+
+        $query .= q|
             WHERE ordernumber = ?
-        |, undef, $order->{ordernumber});
+        |;
+
+        $dbh->do($query, undef, @params, $order->{ordernumber});
 
         delete $order->{ordernumber};
         $order->{budget_id} = ( $budget_id || $order->{budget_id} );
@@ -1518,6 +1492,10 @@ sub ModReceiveOrder {
             , order_internalnote = ?
         | if defined $order->{order_internalnote};
 
+        $query .= q|
+            , invoice_unitprice = ?, invoice_currency = ?
+        |;
+
         $query .= q| where biblionumber=? and ordernumber=?|;
 
         my $sth = $dbh->prepare( $query );
@@ -1543,6 +1521,8 @@ sub ModReceiveOrder {
             push @params, $order->{order_internalnote};
         }
 
+        push @params, $order->{invoice_unitprice}, $order->{invoice_currency};
+
         push @params, ( $biblionumber, $order->{ordernumber} );
 
         $sth->execute( @params );
@@ -1609,48 +1589,50 @@ sub CancelReceipt {
     } 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 * | . _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);
+            # 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
@@ -1669,7 +1651,7 @@ sub CancelReceipt {
             for my $in ( @itemnumbers ) {
                 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 ( $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;
@@ -1876,68 +1858,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 $order = Koha::Acquisition::Orders->find($ordernumber);
-    my $items = $order->items;
-    while ( my $item = $items->next ) { # Should be moved to Koha::Acquisition::Order->delete
-        my $delcheck = C4::Items::DelItemCheck( $bibnum, $item->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);
@@ -2000,19 +1920,21 @@ sub TransferOrder {
     return $newordernumber;
 }
 
-=head3 _get_rounding_sql
+=head3 get_rounding_sql
 
-    $rounding_sql = _get_rounding_sql("mysql_variable_to_round_string");
+    $rounding_sql = get_rounding_sql($column_name);
 
 returns the correct SQL routine based on OrderPriceRounding system preference.
 
 =cut
 
-sub _get_rounding_sql {
+sub get_rounding_sql {
     my ( $round_string ) = @_;
-    my $rounding_pref = C4::Context->preference('OrderPriceRounding');
-    if ( $rounding_pref eq "nearest_cent"  ) { return ("CAST($round_string*100 AS INTEGER)/100"); }
-    else                                     { return ("$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
@@ -2025,9 +1947,11 @@ returns a price rounded as specified in OrderPriceRounding system preference.
 
 sub get_rounded_price {
     my ( $price ) =  @_;
-    my $rounding_pref = C4::Context->preference('OrderPriceRounding');
-    if( $rounding_pref eq 'nearest_cent' ) { return Koha::Number::Price->new( $price )->round(); }
-    else                                   { return $price; }
+    my $rounding_pref = C4::Context->preference('OrderPriceRounding') // q{};
+    if( $rounding_pref eq 'nearest_cent' ) {
+        return Koha::Number::Price->new( $price )->round();
+    }
+    return $price;
 }
 
 
@@ -2121,132 +2045,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')
-    ";
-    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;
-        }
-        $from .= " AND aqorders.quantity - COALESCE(aqorders.quantityreceived,0) <> 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;
-        }
-        $from .= " AND aqorders.quantity <> 0";
-    }
-    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 \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 );
@@ -2267,6 +2065,8 @@ params:
   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)
@@ -2287,7 +2087,9 @@ returns:
                 '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
@@ -2299,8 +2101,11 @@ sub GetHistory {
     my $title = $params{title};
     my $author = $params{author};
     my $isbn   = $params{isbn};
+    my $issn   = $params{issn};
     my $ean    = $params{ean};
     my $name = $params{name};
+    my $internalnote = $params{internalnote};
+    my $vendornote = $params{vendornote};
     my $from_placed_on = $params{from_placed_on};
     my $to_placed_on = $params{to_placed_on};
     my $basket = $params{basket};
@@ -2308,15 +2113,16 @@ sub GetHistory {
     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 $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;
@@ -2337,6 +2143,20 @@ sub GetHistory {
         }
     }
 
+    #get variation of issn
+    my @issn_params;
+    my @issns;
+    if ($issn){
+        if ( C4::Context->preference("SearchWithISSNVariations") ){
+            @issns = C4::Koha::GetVariationsOfISSN( $issn );
+            push @issn_params, ('?') x @issns;
+        }
+        unless (@issns){
+            push @issns, $issn;
+            push @issn_params, '?';
+        }
+    }
+
     my $dbh   = C4::Context->dbh;
     my $query ="
         SELECT
@@ -2348,7 +2168,9 @@ sub GetHistory {
             aqbasket.basketname,
             aqbasket.basketgroupid,
             aqbasket.authorisedby,
+            aqbasket.is_standing,
             concat( borrowers.firstname,' ',borrowers.surname) AS authorisedbyname,
+            branch as managing_library,
             aqbasketgroups.name as groupname,
             aqbooksellers.name,
             aqbasket.creationdate,
@@ -2363,6 +2185,8 @@ sub GetHistory {
             aqorders.biblionumber,
             aqorders.orderstatus,
             aqorders.parent_ordernumber,
+            aqorders.order_internalnote,
+            aqorders.order_vendornote,
             aqbudgets.budget_name
             ";
     $query .= ", aqbudgets.budget_id AS budget" if defined $budget;
@@ -2383,7 +2207,7 @@ sub GetHistory {
     $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  = ();
@@ -2411,6 +2235,13 @@ sub GetHistory {
         }
     }
 
+    if ( @issns ) {
+        $query .= " AND ( biblioitems.issn LIKE " . join (" OR biblioitems.issn LIKE ", @issn_params ) . ")";
+        foreach my $isn (@issns){
+            push @query_params, "%$isn%";
+        }
+    }
+
     if ( $ean ) {
         $query .= " AND biblioitems.ean = ? ";
         push @query_params, "$ean";
@@ -2440,6 +2271,11 @@ sub GetHistory {
         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 = ? ";
@@ -2450,6 +2286,16 @@ sub GetHistory {
         }
     }
 
+    if ( $internalnote ) {
+        $query .= " AND aqorders.order_internalnote LIKE ? ";
+        push @query_params, "%$internalnote%";
+    }
+
+    if ( $vendornote ) {
+        $query .= " AND aqorders.order_vendornote LIKE ?";
+        push @query_params, "%$vendornote%";
+    }
+
     if ($booksellerinvoicenumber) {
         $query .= " AND aqinvoices.invoicenumber LIKE ? ";
         push @query_params, "%$booksellerinvoicenumber%";
@@ -2475,12 +2321,17 @@ sub GetHistory {
         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);
+        my @baskets = Koha::Acquisition::Baskets->filter_by_additional_fields($additional_fields)->as_list;
 
         return [] unless @baskets;
 
@@ -2577,6 +2428,18 @@ asc is the default if omitted
 sub GetInvoices {
     my %args = @_;
 
+    my $additional_fields = $args{additional_fields} // [];
+    my $matching_invoice_ids_for_additional_fields = [];
+    if ( @$additional_fields ) {
+        my @invoices = Koha::Acquisition::Invoices->filter_by_additional_fields($additional_fields)->as_list;
+
+        return () unless @invoices;
+
+        $matching_invoice_ids_for_additional_fields = [ map {
+            $_->id
+        } @invoices ];
+    }
+
     my @columns = qw(invoicenumber booksellerid shipmentdate billingdate
         closedate shipmentcost shipmentcost_budgetid);
 
@@ -2669,11 +2532,23 @@ sub GetInvoices {
     }
 
     $query .= " WHERE " . join(" AND ", @bind_strs) if @bind_strs;
+
+    # Handle additional fields filtering
+    if ( @$additional_fields ) {
+        my $operator = ' WHERE';
+        if ( @bind_strs ) { # there's a WHERE already
+            $operator = ' AND';
+        }
+        $query .= "$operator aqinvoices.invoiceid IN ("
+            . join( ', ', @$matching_invoice_ids_for_additional_fields )
+        . ')';
+    }
+
     $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(grep /^$column$/, @columns) {
+        if(grep  { $_ eq $column } @columns) {
             $direction ||= 'ASC';
             $query .= " ORDER BY $column $direction";
         }
@@ -2797,7 +2672,7 @@ sub AddInvoice {
     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);
         }
@@ -2847,7 +2722,7 @@ sub ModInvoice {
     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);
         }
@@ -2893,7 +2768,7 @@ sub CloseInvoice {
 
 Reopen an invoice
 
-Equivalent to ModInvoice(invoiceid => $invoiceid, closedate => output_pref({ dt=>dt_from_string, dateonly=>1, otputpref=>'iso' }))
+Equivalent to ModInvoice(invoiceid => $invoiceid, closedate => $closedate );
 
 =cut
 
@@ -2987,7 +2862,7 @@ sub GetBiblioCountByBasketno {
         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);
@@ -2995,96 +2870,6 @@ sub GetBiblioCountByBasketno {
     return $sth->fetchrow;
 }
 
-# Note this subroutine should be moved to Koha::Acquisition::Order
-# Will do when a DBIC decision will be taken.
-sub populate_order_with_prices {
-    my ($params) = @_;
-
-    my $order        = $params->{order};
-    my $booksellerid = $params->{booksellerid};
-    return unless $booksellerid;
-
-    my $bookseller = Koha::Acquisition::Booksellers->find( $booksellerid );
-
-    my $receiving = $params->{receiving};
-    my $ordering  = $params->{ordering};
-    my $discount  = $order->{discount};
-    $discount /= 100 if $discount > 1;
-
-    if ($ordering) {
-        $order->{tax_rate_on_ordering} //= $order->{tax_rate};
-        if ( $bookseller->listincgst ) {
-            # The user entered the rrp tax included
-            $order->{rrp_tax_included} = $order->{rrp};
-
-            # rrp tax excluded = rrp tax included / ( 1 + tax rate )
-            $order->{rrp_tax_excluded} = $order->{rrp_tax_included} / ( 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 included  ( 1 - discount )
-            $order->{ecost_tax_included} = $order->{rrp_tax_included} * ( 1 - $discount );
-        }
-        else {
-            # The user entered the rrp tax excluded
-            $order->{rrp_tax_excluded} = $order->{rrp};
-
-            # rrp tax included = rrp tax excluded * ( 1 - tax rate )
-            $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 );
-        }
-
-        # tax value = quantity * ecost tax excluded * tax rate
-        $order->{tax_value_on_ordering} =
-            $order->{quantity} * get_rounded_price($order->{ecost_tax_excluded}) * $order->{tax_rate_on_ordering};
-    }
-
-    if ($receiving) {
-        $order->{tax_rate_on_receiving} //= $order->{tax_rate};
-        if ( $bookseller->invoiceincgst ) {
-            # Trick for unitprice. If the unit price rounded value is the same as the ecost rounded value
-            # we need to keep the exact ecost value
-            if ( Koha::Number::Price->new( $order->{unitprice} )->round == Koha::Number::Price->new( $order->{ecost_tax_included} )->round ) {
-                $order->{unitprice} = $order->{ecost_tax_included};
-            }
-
-            # The user entered the unit price tax included
-            $order->{unitprice_tax_included} = $order->{unitprice};
-
-            # unit price tax excluded = unit price tax included / ( 1 + tax rate )
-            $order->{unitprice_tax_excluded} = $order->{unitprice_tax_included} / ( 1 + $order->{tax_rate_on_receiving} );
-        }
-        else {
-            # Trick for unitprice. If the unit price rounded value is the same as the ecost rounded value
-            # we need to keep the exact ecost value
-            if ( Koha::Number::Price->new( $order->{unitprice} )->round == Koha::Number::Price->new( $order->{ecost_tax_excluded} )->round ) {
-                $order->{unitprice} = $order->{ecost_tax_excluded};
-            }
-
-            # The user entered the unit price tax excluded
-            $order->{unitprice_tax_excluded} = $order->{unitprice};
-
-
-            # unit price tax included = unit price tax included * ( 1 + tax rate )
-            $order->{unitprice_tax_included} = $order->{unitprice_tax_excluded} * ( 1 + $order->{tax_rate_on_receiving} );
-        }
-
-        # tax value = quantity * unit price tax excluded * tax rate
-        $order->{tax_value_on_receiving} = $order->{quantity} * get_rounded_price($order->{unitprice_tax_excluded}) * $order->{tax_rate_on_receiving};
-    }
-
-    return $order;
-}
-
 =head3 GetOrderUsers
 
     $order_users_ids = &GetOrderUsers($ordernumber);
@@ -3187,42 +2972,59 @@ sub NotifyOrderUsers {
 
 =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.
 
+If the parameter only_mandatory => 1 is passed via $params, only the mandatory
+defaults are being applied to the record.
+
 =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) =
-          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});
+                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) {
-                            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 {
-                        $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
+                                )
+                            );
+                        }
                     }
                 }
             }