Bug 20538: Move categories.js out of language directory
[koha.git] / C4 / Acquisition.pm
index 01b815a..a257017 100644 (file)
@@ -22,30 +22,31 @@ use Modern::Perl;
 use Carp;
 use C4::Context;
 use C4::Debug;
 use Carp;
 use C4::Context;
 use C4::Debug;
-use C4::Dates qw(format_date format_date_in_iso);
 use C4::Suggestions;
 use C4::Biblio;
 use C4::Contract;
 use C4::Debug;
 use C4::Templates qw(gettemplate);
 use Koha::DateUtils qw( dt_from_string output_pref );
 use C4::Suggestions;
 use C4::Biblio;
 use C4::Contract;
 use C4::Debug;
 use C4::Templates qw(gettemplate);
 use Koha::DateUtils qw( dt_from_string output_pref );
-use Koha::Acquisition::Order;
-use Koha::Acquisition::Bookseller;
+use Koha::Acquisition::Booksellers;
+use Koha::Acquisition::Orders;
+use Koha::Biblios;
+use Koha::Items;
 use Koha::Number::Price;
 use Koha::Number::Price;
+use Koha::Libraries;
+use Koha::CsvProfiles;
+use Koha::Patrons;
 
 
-use C4::Koha qw( subfield_is_koha_internal_p );
+use C4::Koha;
 
 use MARC::Field;
 use MARC::Record;
 
 use Time::localtime;
 
 use MARC::Field;
 use MARC::Record;
 
 use Time::localtime;
-use HTML::Entities;
 
 
-use vars qw($VERSION @ISA @EXPORT);
+use vars qw(@ISA @EXPORT);
 
 BEGIN {
 
 BEGIN {
-    # set the version for version checking
-    $VERSION = 3.07.00.049;
     require Exporter;
     @ISA    = qw(Exporter);
     @EXPORT = qw(
     require Exporter;
     @ISA    = qw(Exporter);
     @EXPORT = qw(
@@ -188,8 +189,8 @@ sub GetBasket {
 
 =head3 NewBasket
 
 
 =head3 NewBasket
 
-  $basket = &NewBasket( $booksellerid, $authorizedby, $basketname, 
-      $basketnote, $basketbooksellernote, $basketcontractnumber, $deliveryplace, $billingplace );
+  $basket = &NewBasket( $booksellerid, $authorizedby, $basketname,
+      $basketnote, $basketbooksellernote, $basketcontractnumber, $deliveryplace, $billingplace, $is_standing, $create_items );
 
 Create a new basket in aqbasket table
 
 
 Create a new basket in aqbasket table
 
@@ -208,7 +209,7 @@ The other parameters are optional, see ModBasketHeader for more info on them.
 sub NewBasket {
     my ( $booksellerid, $authorisedby, $basketname, $basketnote,
         $basketbooksellernote, $basketcontractnumber, $deliveryplace,
 sub NewBasket {
     my ( $booksellerid, $authorisedby, $basketname, $basketnote,
         $basketbooksellernote, $basketcontractnumber, $deliveryplace,
-        $billingplace ) = @_;
+        $billingplace, $is_standing, $create_items ) = @_;
     my $dbh = C4::Context->dbh;
     my $query =
         'INSERT INTO aqbasket (creationdate,booksellerid,authorisedby) '
     my $dbh = C4::Context->dbh;
     my $query =
         'INSERT INTO aqbasket (creationdate,booksellerid,authorisedby) '
@@ -220,7 +221,7 @@ sub NewBasket {
     $basketnote           ||= q{};
     $basketbooksellernote ||= q{};
     ModBasketHeader( $basket, $basketname, $basketnote, $basketbooksellernote,
     $basketnote           ||= q{};
     $basketbooksellernote ||= q{};
     ModBasketHeader( $basket, $basketname, $basketnote, $basketbooksellernote,
-        $basketcontractnumber, $booksellerid, $deliveryplace, $billingplace );
+        $basketcontractnumber, $booksellerid, $deliveryplace, $billingplace, $is_standing, $create_items );
     return $basket;
 }
 
     return $basket;
 }
 
@@ -237,24 +238,13 @@ close a basket (becomes unmodifiable, except for receives)
 sub CloseBasket {
     my ($basketno) = @_;
     my $dbh        = C4::Context->dbh;
 sub CloseBasket {
     my ($basketno) = @_;
     my $dbh        = C4::Context->dbh;
-    my $query = "
-        UPDATE aqbasket
-        SET    closedate=now()
-        WHERE  basketno=?
-    ";
-    my $sth = $dbh->prepare($query);
-    $sth->execute($basketno);
+    $dbh->do('UPDATE aqbasket SET closedate=now() WHERE basketno=?', {}, $basketno );
 
 
-    my @orders = GetOrders($basketno);
-    foreach my $order (@orders) {
-        $query = qq{
-            UPDATE aqorders
-            SET orderstatus = 'ordered'
-            WHERE ordernumber = ?;
-        };
-        $sth = $dbh->prepare($query);
-        $sth->execute($order->{'ordernumber'});
-    }
+    $dbh->do(
+q{UPDATE aqorders SET orderstatus = 'ordered' WHERE basketno = ? AND orderstatus NOT IN ( 'complete', 'cancelled')},
+        {}, $basketno
+    );
+    return;
 }
 
 =head3 ReopenBasket
 }
 
 =head3 ReopenBasket
@@ -268,24 +258,15 @@ reopen a basket
 sub ReopenBasket {
     my ($basketno) = @_;
     my $dbh        = C4::Context->dbh;
 sub ReopenBasket {
     my ($basketno) = @_;
     my $dbh        = C4::Context->dbh;
-    my $query = "
-        UPDATE aqbasket
-        SET    closedate=NULL
-        WHERE  basketno=?
-    ";
-    my $sth = $dbh->prepare($query);
-    $sth->execute($basketno);
+    $dbh->do( q{UPDATE aqbasket SET closedate=NULL WHERE  basketno=?}, {}, $basketno );
 
 
-    my @orders = GetOrders($basketno);
-    foreach my $order (@orders) {
-        $query = qq{
-            UPDATE aqorders
-            SET orderstatus = 'new'
-            WHERE ordernumber = ?;
-        };
-        $sth = $dbh->prepare($query);
-        $sth->execute($order->{'ordernumber'});
-    }
+    $dbh->do( q{
+        UPDATE aqorders
+        SET orderstatus = 'new'
+        WHERE basketno = ?
+        AND orderstatus NOT IN ( 'complete', 'cancelled' )
+        }, {}, $basketno);
+    return;
 }
 
 #------------------------------------------------------------#
 }
 
 #------------------------------------------------------------#
@@ -301,7 +282,7 @@ $cgi parameter is needed for column name translation
 =cut
 
 sub GetBasketAsCSV {
 =cut
 
 sub GetBasketAsCSV {
-    my ($basketno, $cgi) = @_;
+    my ($basketno, $cgi, $csv_profile_id) = @_;
     my $basket = GetBasket($basketno);
     my @orders = GetOrders($basketno);
     my $contract = GetContract({
     my $basket = GetBasket($basketno);
     my @orders = GetOrders($basketno);
     my $contract = GetContract({
@@ -309,45 +290,95 @@ sub GetBasketAsCSV {
     });
 
     my $template = C4::Templates::gettemplate("acqui/csv/basket.tt", "intranet", $cgi);
     });
 
     my $template = C4::Templates::gettemplate("acqui/csv/basket.tt", "intranet", $cgi);
-
     my @rows;
     my @rows;
-    foreach my $order (@orders) {
-        my $bd = GetBiblioData( $order->{'biblionumber'} );
-        my $row = {
-            contractname => $contract->{'contractname'},
-            ordernumber => $order->{'ordernumber'},
-            entrydate => $order->{'entrydate'},
-            isbn => $order->{'isbn'},
-            author => $bd->{'author'},
-            title => $bd->{'title'},
-            publicationyear => $bd->{'publicationyear'},
-            publishercode => $bd->{'publishercode'},
-            collectiontitle => $bd->{'collectiontitle'},
-            notes => $order->{'order_vendornote'},
-            quantity => $order->{'quantity'},
-            rrp => $order->{'rrp'},
-            deliveryplace => C4::Branch::GetBranchName( $basket->{'deliveryplace'} ),
-            billingplace => C4::Branch::GetBranchName( $basket->{'billingplace'} ),
-        };
-        foreach(qw(
-            contractname author title publishercode collectiontitle notes
-            deliveryplace billingplace
-        ) ) {
-            # Double the quotes to not be interpreted as a field end
-            $row->{$_} =~ s/"/""/g if $row->{$_};
+    if ($csv_profile_id) {
+        my $csv_profile = Koha::CsvProfiles->find( $csv_profile_id );
+        die "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 ( @headers, @fields );
+        while ( $csv_profile_content =~ /
+            ([^=\|]+) # header
+            =?
+            ([^\|]*) # fieldname (table.row or row)
+            \|? /gxms
+        ) {
+            my $header = $1;
+            my $field = ($2 eq '') ? $1 : $2;
+
+            $header =~ s/^\s+|\s+$//g; # Trim whitespaces
+            push @headers, $header;
+
+            $field =~ s/[^\.]*\.{1}//; # Remove the table name if exists.
+            $field =~ s/^\s+|\s+$//g; # Trim whitespaces
+            push @fields, $field;
+        }
+        for my $order (@orders) {
+            my @row;
+            my $biblio = Koha::Biblios->find( $order->{biblionumber} );
+            my $biblioitem = $biblio->biblioitem;
+            $order = { %$order, %{ $biblioitem->unblessed } };
+            if ($contract) {
+                $order = {%$order, %$contract};
+            }
+            $order = {%$order, %$basket, %{ $biblio->unblessed }};
+            for my $field (@fields) {
+                push @row, $order->{$field};
+            }
+            push @rows, \@row;
+        }
+        my $content = join( $csv_profile->csv_separator, @headers ) . "\n";
+        for my $row ( @rows ) {
+            $csv->combine(@$row);
+            my $string = $csv->string;
+            $content .= $string . "\n";
         }
         }
-        push @rows, $row;
+        return $content;
     }
     }
+    else {
+        foreach my $order (@orders) {
+            my $biblio = Koha::Biblios->find( $order->{biblionumber} );
+            my $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'},
+            };
+            for my $place ( qw( deliveryplace billingplace ) ) {
+                if ( my $library = Koha::Libraries->find( $row->{deliveryplace} ) ) {
+                    $row->{$place} = $library->branchname
+                }
+            }
+            foreach(qw(
+                contractname author title publishercode collectiontitle notes
+                deliveryplace billingplace
+            ) ) {
+                # Double the quotes to not be interpreted as a field end
+                $row->{$_} =~ s/"/""/g if $row->{$_};
+            }
+            push @rows, $row;
+         }
 
 
-    @rows = sort {
-        if(defined $a->{publishercode} and defined $b->{publishercode}) {
-            $a->{publishercode} cmp $b->{publishercode};
-        }
-    } @rows;
+        @rows = sort {
+            if(defined $a->{publishercode} and defined $b->{publishercode}) {
+                $a->{publishercode} cmp $b->{publishercode};
+            }
+        } @rows;
 
 
-    $template->param(rows => \@rows);
+        $template->param(rows => \@rows);
 
 
-    return $template->output;
+        return $template->output;
+    }
 }
 
 
 }
 
 
@@ -373,37 +404,47 @@ sub GetBasketGroupAsCSV {
         my $contract   = GetContract({
             contractnumber => $basket->{contractnumber}
         });
         my $contract   = GetContract({
             contractnumber => $basket->{contractnumber}
         });
-        my $bookseller = Koha::Acquisition::Bookseller->fetch({ id => $basket->{booksellerid} });
+        my $bookseller = Koha::Acquisition::Booksellers->find( $basket->{booksellerid} );
         my $basketgroup = GetBasketgroup( $$basket{basketgroupid} );
 
         foreach my $order (@orders) {
         my $basketgroup = GetBasketgroup( $$basket{basketgroupid} );
 
         foreach my $order (@orders) {
-            my $bd = GetBiblioData( $order->{'biblionumber'} );
+            my $biblio = Koha::Biblios->find( $order->{biblionumber} );
+            my $biblioitem = $biblio->biblioitem;
             my $row = {
             my $row = {
-                clientnumber => $bookseller->{accountnumber},
+                clientnumber => $bookseller->accountnumber,
                 basketname => $basket->{basketname},
                 ordernumber => $order->{ordernumber},
                 basketname => $basket->{basketname},
                 ordernumber => $order->{ordernumber},
-                author => $bd->{author},
-                title => $bd->{title},
-                publishercode => $bd->{publishercode},
-                publicationyear => $bd->{publicationyear},
-                collectiontitle => $bd->{collectiontitle},
+                author => $biblio->author,
+                title => $biblio->title,
+                publishercode => $biblioitem->publishercode,
+                publicationyear => $biblioitem->publicationyear,
+                collectiontitle => $biblioitem->collectiontitle,
                 isbn => $order->{isbn},
                 quantity => $order->{quantity},
                 isbn => $order->{isbn},
                 quantity => $order->{quantity},
-                rrp => $order->{rrp},
-                discount => $bookseller->{discount},
-                ecost => $order->{ecost},
+                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},
                 notes => $order->{order_vendornote},
                 entrydate => $order->{entrydate},
-                booksellername => $bookseller->{name},
-                bookselleraddress => $bookseller->{address1},
-                booksellerpostal => $bookseller->{postal},
+                booksellername => $bookseller->name,
+                bookselleraddress => $bookseller->address1,
+                booksellerpostal => $bookseller->postal,
                 contractnumber => $contract->{contractnumber},
                 contractname => $contract->{contractname},
                 contractnumber => $contract->{contractnumber},
                 contractname => $contract->{contractname},
-                basketgroupdeliveryplace => C4::Branch::GetBranchName( $basketgroup->{deliveryplace} ),
-                basketgroupbillingplace => C4::Branch::GetBranchName( $basketgroup->{billingplace} ),
-                basketdeliveryplace => C4::Branch::GetBranchName( $basket->{deliveryplace} ),
-                basketbillingplace => C4::Branch::GetBranchName( $basket->{billingplace} ),
             };
             };
+            my $temp = {
+                basketgroupdeliveryplace => $basketgroup->{deliveryplace},
+                basketgroupbillingplace  => $basketgroup->{billingplace},
+                basketdeliveryplace      => $basket->{deliveryplace},
+                basketbillingplace       => $basket->{billingplace},
+            };
+            for my $place (qw( basketgroupdeliveryplace basketgroupbillingplace basketdeliveryplace basketbillingplace )) {
+                if ( my $library = Koha::Libraries->find( $temp->{$place} ) ) {
+                    $row->{$place} = $library->branchname;
+                }
+            }
             foreach(qw(
                 basketname author title publishercode collectiontitle notes
                 booksellername bookselleraddress booksellerpostal contractname
             foreach(qw(
                 basketname author title publishercode collectiontitle notes
                 booksellername bookselleraddress booksellerpostal contractname
@@ -555,21 +596,28 @@ Modifies a basket's header.
 
 =item C<$billingplace> is the "billingplace" field in the aqbasket table.
 
 
 =item C<$billingplace> is the "billingplace" field in the aqbasket table.
 
+=item C<$is_standing> is the "is_standing" field in the aqbasket table.
+
+=item C<$create_items> should be set to 'ordering', 'receiving' or 'cataloguing' (or undef, in which
+case the AcqCreateItem syspref takes precedence).
+
 =back
 
 =cut
 
 sub ModBasketHeader {
 =back
 
 =cut
 
 sub ModBasketHeader {
-    my ($basketno, $basketname, $note, $booksellernote, $contractnumber, $booksellerid, $deliveryplace, $billingplace) = @_;
+    my ($basketno, $basketname, $note, $booksellernote, $contractnumber, $booksellerid, $deliveryplace, $billingplace, $is_standing, $create_items) = @_;
+
+    $is_standing ||= 0;
     my $query = qq{
         UPDATE aqbasket
     my $query = qq{
         UPDATE aqbasket
-        SET basketname=?, note=?, booksellernote=?, booksellerid=?, deliveryplace=?, billingplace=?
+        SET basketname=?, note=?, booksellernote=?, booksellerid=?, deliveryplace=?, billingplace=?, is_standing=?, create_items=?
         WHERE basketno=?
     };
 
     my $dbh = C4::Context->dbh;
     my $sth = $dbh->prepare($query);
         WHERE basketno=?
     };
 
     my $dbh = C4::Context->dbh;
     my $sth = $dbh->prepare($query);
-    $sth->execute($basketname, $note, $booksellernote, $booksellerid, $deliveryplace, $billingplace, $basketno);
+    $sth->execute($basketname, $note, $booksellernote, $booksellerid, $deliveryplace, $billingplace, $is_standing, $create_items || undef, $basketno);
 
     if ( $contractnumber ) {
         my $query2 ="UPDATE aqbasket SET contractnumber=? WHERE basketno=?";
 
     if ( $contractnumber ) {
         my $query2 ="UPDATE aqbasket SET contractnumber=? WHERE basketno=?";
@@ -644,7 +692,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 )
@@ -663,7 +711,7 @@ sub GetBasketsInfosByBookseller {
     unless ( $allbaskets ) {
         $query.=" AND (closedate IS NULL OR (aqorders.quantity > aqorders.quantityreceived AND datecancellationprinted IS NULL))";
     }
     unless ( $allbaskets ) {
         $query.=" AND (closedate IS NULL OR (aqorders.quantity > aqorders.quantityreceived AND datecancellationprinted IS NULL))";
     }
-    $query.=" GROUP BY aqbasket.basketno";
+    $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";
 
     my $sth = $dbh->prepare($query);
     $sth->execute($supplierid);
 
     my $sth = $dbh->prepare($query);
     $sth->execute($supplierid);
@@ -760,7 +808,7 @@ AcqViewBaskets, user permissions and basket properties (creator, users list,
 branch).
 
 First parameter can be either a borrowernumber or a hashref as returned by
 branch).
 
 First parameter can be either a borrowernumber or a hashref as returned by
-C4::Members::GetMember.
+Koha::Patron->unblessed
 
 Second parameter can be either a basketno or a hashref as returned by
 C4::Acquisition::GetBasket.
 
 Second parameter can be either a basketno or a hashref as returned by
 C4::Acquisition::GetBasket.
@@ -777,7 +825,10 @@ sub CanUserManageBasket {
     my ($borrower, $basket, $userflags) = @_;
 
     if (!ref $borrower) {
     my ($borrower, $basket, $userflags) = @_;
 
     if (!ref $borrower) {
-        $borrower = C4::Members::GetMember(borrowernumber => $borrower);
+        # FIXME This needs to be replaced
+        # We should not accept both scalar and array
+        # Tests need to be updated
+        $borrower = Koha::Patrons->find( $borrower )->unblessed;
     }
     if (!ref $basket) {
         $basket = GetBasket($basket);
     }
     if (!ref $basket) {
         $basket = GetBasket($basket);
@@ -815,8 +866,8 @@ sub CanUserManageBasket {
 
         if ($AcqViewBaskets eq 'user'
         && $basket->{authorisedby} != $borrowernumber
 
         if ($AcqViewBaskets eq 'user'
         && $basket->{authorisedby} != $borrowernumber
-        && grep($borrowernumber, GetBasketUsers($basketno)) == 0) {
-            return 0;
+        && ! grep { $borrowernumber eq $_ } GetBasketUsers($basketno)) {
+             return 0;
         }
 
         if ($AcqViewBaskets eq 'branch' && defined $basket->{branch}
         }
 
         if ($AcqViewBaskets eq 'branch' && defined $basket->{branch}
@@ -1285,8 +1336,7 @@ table of the Koha database.
 sub ModOrder {
     my $orderinfo = shift;
 
 sub ModOrder {
     my $orderinfo = shift;
 
-    die "Ordernumber is required"     if $orderinfo->{'ordernumber'} eq  '' ;
-    die "Biblionumber is required"  if  $orderinfo->{'biblionumber'} eq '';
+    die "Ordernumber is required" if $orderinfo->{'ordernumber'} eq '';
 
     my $dbh = C4::Context->dbh;
     my @params;
 
     my $dbh = C4::Context->dbh;
     my @params;
@@ -1348,52 +1398,42 @@ sub ModItemOrder {
 
 =head3 ModReceiveOrder
 
 
 =head3 ModReceiveOrder
 
-  &ModReceiveOrder({
-    biblionumber => $biblionumber,
-    ordernumber => $ordernumber,
-    quantityreceived => $quantityreceived,
-    user => $user,
-    cost => $cost,
-    ecost => $ecost,
-    invoiceid => $invoiceid,
-    rrp => $rrp,
-    budget_id => $budget_id,
-    datereceived => $datereceived,
-    received_itemnumbers => \@received_itemnumbers,
-    order_internalnote => $order_internalnote,
-    order_vendornote => $order_vendornote,
-   });
+    my ( $date_received, $new_ordernumber ) = ModReceiveOrder(
+        {
+            biblionumber         => $biblionumber,
+            order                => $order,
+            quantityreceived     => $quantityreceived,
+            user                 => $user,
+            invoice              => $invoice,
+            budget_id            => $budget_id,
+            received_itemnumbers => \@received_itemnumbers,
+            order_internalnote   => $order_internalnote,
+        }
+    );
 
 Updates an order, to reflect the fact that it was received, at least
 
 Updates an order, to reflect the fact that it was received, at least
-in part. All arguments not mentioned below update the fields with the
-same name in the aqorders table of the Koha database.
+in part.
 
 If a partial order is received, splits the order into two.
 
 
 If a partial order is received, splits the order into two.
 
-Updates the order with bibilionumber C<$biblionumber> and ordernumber
-C<$ordernumber>.
+Updates the order with biblionumber C<$biblionumber> and ordernumber
+C<$order->{ordernumber}>.
 
 =cut
 
 
 sub ModReceiveOrder {
 
 =cut
 
 
 sub ModReceiveOrder {
-    my ( $params ) = @_;
-    my $biblionumber = $params->{biblionumber};
-    my $ordernumber = $params->{ordernumber};
-    my $quantrec = $params->{quantityreceived};
-    my $user = $params->{user};
-    my $cost = $params->{cost};
-    my $ecost = $params->{ecost};
-    my $invoiceid = $params->{invoiceid};
-    my $rrp = $params->{rrp};
-    my $budget_id = $params->{budget_id};
-    my $datereceived = $params->{datereceived};
+    my ($params)       = @_;
+    my $biblionumber   = $params->{biblionumber};
+    my $order          = { %{ $params->{order} } }; # Copy the order, we don't want to modify it
+    my $invoice        = $params->{invoice};
+    my $quantrec       = $params->{quantityreceived};
+    my $user           = $params->{user};
+    my $budget_id      = $params->{budget_id};
     my $received_items = $params->{received_items};
     my $received_items = $params->{received_items};
-    my $order_internalnote = $params->{order_internalnote};
-    my $order_vendornote = $params->{order_vendornote};
 
     my $dbh = C4::Context->dbh;
 
     my $dbh = C4::Context->dbh;
-    $datereceived = C4::Dates->output('iso') unless $datereceived;
+    my $datereceived = ( $invoice and $invoice->{datereceived} ) ? $invoice->{datereceived} : dt_from_string;
     my $suggestionid = GetSuggestionFromBiblionumber( $biblionumber );
     if ($suggestionid) {
         ModSuggestion( {suggestionid=>$suggestionid,
     my $suggestionid = GetSuggestionFromBiblionumber( $biblionumber );
     if ($suggestionid) {
         ModSuggestion( {suggestionid=>$suggestionid,
@@ -1402,16 +1442,14 @@ sub ModReceiveOrder {
                         );
     }
 
                         );
     }
 
-    my $result_set = $dbh->selectall_arrayref(
-q{SELECT * FROM aqorders WHERE biblionumber=? AND aqorders.ordernumber=?},
-        { Slice => {} }, $biblionumber, $ordernumber
-    );
+    my $result_set = $dbh->selectrow_arrayref(
+            q{SELECT aqbasket.is_standing
+            FROM aqbasket
+            WHERE basketno=?},{ Slice => {} }, $order->{basketno});
+    my $is_standing = $result_set->[0];  # we assume we have a unique basket
 
 
-    # we assume we have a unique order
-    my $order = $result_set->[0];
-
-    my $new_ordernumber = $ordernumber;
-    if ( $order->{quantity} > $quantrec ) {
+    my $new_ordernumber = $order->{ordernumber};
+    if ( $is_standing || $order->{quantity} > $quantrec ) {
         # Split order line in two parts: the first is the original order line
         # without received items (the quantity is decreased),
         # the second part is a new order line with quantity=quantityrec
         # Split order line in two parts: the first is the original order line
         # without received items (the quantity is decreased),
         # the second part is a new order line with quantity=quantityrec
@@ -1420,29 +1458,39 @@ q{SELECT * FROM aqorders WHERE biblionumber=? AND aqorders.ordernumber=?},
             UPDATE aqorders
             SET quantity = ?,
                 orderstatus = 'partial'|;
             UPDATE aqorders
             SET quantity = ?,
                 orderstatus = 'partial'|;
-        $query .= q|, order_internalnote = ?| if defined $order_internalnote;
-        $query .= q|, order_vendornote = ?| if defined $order_vendornote;
+        $query .= q|, order_internalnote = ?| if defined $order->{order_internalnote};
         $query .= q| WHERE ordernumber = ?|;
         my $sth = $dbh->prepare($query);
 
         $sth->execute(
         $query .= q| WHERE ordernumber = ?|;
         my $sth = $dbh->prepare($query);
 
         $sth->execute(
-            $order->{quantity} - $quantrec,
-            ( defined $order_internalnote ? $order_internalnote : () ),
-            ( defined $order_vendornote ? $order_vendornote : () ),
-            $ordernumber
+            ( $is_standing ? 1 : ($order->{quantity} - $quantrec) ),
+            ( defined $order->{order_internalnote} ? $order->{order_internalnote} : () ),
+            $order->{ordernumber}
         );
 
         );
 
-        delete $order->{'ordernumber'};
-        $order->{'budget_id'} = ( $budget_id || $order->{'budget_id'} );
-        $order->{'quantity'} = $quantrec;
-        $order->{'quantityreceived'} = $quantrec;
-        $order->{'datereceived'} = $datereceived;
-        $order->{'invoiceid'} = $invoiceid;
-        $order->{'unitprice'} = $cost;
-        $order->{'rrp'} = $rrp;
-        $order->{ecost} = $ecost;
-        $order->{'orderstatus'} = 'complete';
-        $new_ordernumber = Koha::Acquisition::Order->new($order)->insert->{ordernumber};
+        # 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, $order->{ordernumber});
+
+        delete $order->{ordernumber};
+        $order->{budget_id} = ( $budget_id || $order->{budget_id} );
+        $order->{quantity} = $quantrec;
+        $order->{quantityreceived} = $quantrec;
+        $order->{ecost_tax_excluded} //= 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->{datereceived} = $datereceived;
+        $order->{invoiceid} = $invoice->{invoiceid};
+        $order->{orderstatus} = 'complete';
+        $new_ordernumber = Koha::Acquisition::Order->new($order)->store->ordernumber; # TODO What if the store fails?
 
         if ($received_items) {
             foreach my $itemnumber (@$received_items) {
 
         if ($received_items) {
             foreach my $itemnumber (@$received_items) {
@@ -1451,29 +1499,57 @@ q{SELECT * FROM aqorders WHERE biblionumber=? AND aqorders.ordernumber=?},
         }
     } else {
         my $query = q|
         }
     } else {
         my $query = q|
-            update aqorders
-            set quantityreceived=?,datereceived=?,invoiceid=?,
-                unitprice=?,rrp=?,ecost=?,budget_id=?,orderstatus='complete'|;
-        $query .= q|, order_internalnote = ?| if defined $order_internalnote;
-        $query .= q|, order_vendornote = ?| if defined $order_vendornote;
+            UPDATE aqorders
+            SET quantityreceived = ?,
+                datereceived = ?,
+                invoiceid = ?,
+                budget_id = ?,
+                orderstatus = 'complete'
+        |;
+
+        $query .= q|
+            , unitprice = ?, unitprice_tax_included = ?, unitprice_tax_excluded = ?
+        | if defined $order->{unitprice};
+
+        $query .= q|
+            ,tax_value_on_receiving = ?
+        | if defined $order->{tax_value_on_receiving};
+
+        $query .= q|
+            ,tax_rate_on_receiving = ?
+        | if defined $order->{tax_rate_on_receiving};
+
+        $query .= q|
+            , order_internalnote = ?
+        | if defined $order->{order_internalnote};
+
         $query .= q| where biblionumber=? and ordernumber=?|;
         $query .= q| where biblionumber=? and ordernumber=?|;
+
         my $sth = $dbh->prepare( $query );
         my $sth = $dbh->prepare( $query );
-        $sth->execute(
-            $quantrec,
-            $datereceived,
-            $invoiceid,
-            $cost,
-            $rrp,
-            $ecost,
-            ( $budget_id ? $budget_id : $order->{budget_id} ),
-            ( defined $order_internalnote ? $order_internalnote : () ),
-            ( defined $order_vendornote ? $order_vendornote : () ),
-            $biblionumber,
-            $ordernumber
-        );
+        my @params = ( $quantrec, $datereceived, $invoice->{invoiceid}, ( $budget_id ? $budget_id : $order->{budget_id} ) );
+
+        if ( defined $order->{unitprice} ) {
+            push @params, $order->{unitprice}, $order->{unitprice_tax_included}, $order->{unitprice_tax_excluded};
+        }
+
+        if ( defined $order->{tax_value_on_receiving} ) {
+            push @params, $order->{tax_value_on_receiving};
+        }
+
+        if ( defined $order->{tax_rate_on_receiving} ) {
+            push @params, $order->{tax_rate_on_receiving};
+        }
+
+        if ( defined $order->{order_internalnote} ) {
+            push @params, $order->{order_internalnote};
+        }
+
+        push @params, ( $biblionumber, $order->{ordernumber} );
+
+        $sth->execute( @params );
 
         # All items have been received, sent a notification to users
 
         # All items have been received, sent a notification to users
-        NotifyOrderUsers( $ordernumber );
+        NotifyOrderUsers( $order->{ordernumber} );
 
     }
     return ($datereceived, $new_ordernumber);
 
     }
     return ($datereceived, $new_ordernumber);
@@ -1516,6 +1592,7 @@ sub CancelReceipt {
     my $parent_ordernumber = $order->{'parent_ordernumber'};
 
     my @itemnumbers = GetItemnumbersFromOrder( $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
 
     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
@@ -1529,7 +1606,7 @@ sub CancelReceipt {
         };
         $sth = $dbh->prepare($query);
         $sth->execute(0, undef, undef, $ordernumber);
         };
         $sth = $dbh->prepare($query);
         $sth->execute(0, undef, undef, $ordernumber);
-        _cancel_items_receipt( $ordernumber );
+        _cancel_items_receipt( $order_obj );
     } 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.
@@ -1566,7 +1643,17 @@ sub CancelReceipt {
                 " receipt";
             return;
         }
                 " receipt";
             return;
         }
-        _cancel_items_receipt( $ordernumber, $parent_ordernumber );
+
+        # 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);
+
+        _cancel_items_receipt( $order_obj, $parent_ordernumber );
         # Delete order line
         $query = qq{
             DELETE FROM aqorders
         # Delete order line
         $query = qq{
             DELETE FROM aqorders
@@ -1577,21 +1664,21 @@ sub CancelReceipt {
 
     }
 
 
     }
 
-    if(C4::Context->preference('AcqCreateItem') eq 'ordering') {
+    if( $order_obj->basket->effective_create_items eq 'ordering' ) {
         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 $biblionumber = C4::Biblio::GetBiblionumberFromItemnumber( $in );
-                my $frameworkcode = GetFrameworkCode($biblionumber);
-                my ( $itemfield ) = GetMarcFromKohaField( 'items.itemnumber', $frameworkcode );
-                my $item = C4::Items::GetMarcItem( $biblionumber, $in );
+                my $item = Koha::Items->find( $in );
+                my $biblio = $item->biblio;
+                my ( $itemfield ) = GetMarcFromKohaField( 'items.itemnumber', $biblio->frameworkcode );
+                my $item_marc = C4::Items::GetMarcItem( $biblio->biblionumber, $in );
                 for my $affect ( @affects ) {
                     my ( $sf, $v ) = split q{=}, $affect, 2;
                 for my $affect ( @affects ) {
                     my ( $sf, $v ) = split q{=}, $affect, 2;
-                    foreach ( $item->field($itemfield) ) {
+                    foreach ( $item_marc->field($itemfield) ) {
                         $_->update( $sf => $v );
                     }
                 }
                         $_->update( $sf => $v );
                     }
                 }
-                C4::Items::ModItemFromMarc( $item, $biblionumber, $in );
+                C4::Items::ModItemFromMarc( $item_marc, $biblio->biblionumber, $in );
             }
         }
     }
             }
         }
     }
@@ -1600,11 +1687,11 @@ sub CancelReceipt {
 }
 
 sub _cancel_items_receipt {
 }
 
 sub _cancel_items_receipt {
-    my ( $ordernumber, $parent_ordernumber ) = @_;
-    $parent_ordernumber ||= $ordernumber;
+    my ( $order, $parent_ordernumber ) = @_;
+    $parent_ordernumber ||= $order->ordernumber;
 
 
-    my @itemnumbers = GetItemnumbersFromOrder($ordernumber);
-    if(C4::Context->preference('AcqCreateItem') eq 'receiving') {
+    my @itemnumbers = GetItemnumbersFromOrder($order->ordernumber); # FIXME Must be $order->items
+    if ( $order->basket->effective_create_items eq 'receiving' ) {
         # Remove items that were created at receipt
         my $query = qq{
             DELETE FROM items, aqorders_items
         # Remove items that were created at receipt
         my $query = qq{
             DELETE FROM items, aqorders_items
@@ -1631,17 +1718,22 @@ sub _cancel_items_receipt {
 @results = &SearchOrders({
     ordernumber => $ordernumber,
     search => $search,
 @results = &SearchOrders({
     ordernumber => $ordernumber,
     search => $search,
-    biblionumber => $biblionumber,
     ean => $ean,
     booksellerid => $booksellerid,
     basketno => $basketno,
     ean => $ean,
     booksellerid => $booksellerid,
     basketno => $basketno,
+    basketname => $basketname,
+    basketgroupname => $basketgroupname,
     owner => $owner,
     pending => $pending
     ordered => $ordered
     owner => $owner,
     pending => $pending
     ordered => $ordered
+    biblionumber => $biblionumber,
+    budget_id => $budget_id
 });
 
 });
 
-Searches for orders.
+Searches for orders filtered by criteria.
 
 
+C<$ordernumber> Finds matching orders or transferred orders by ordernumber.
+C<$search> Finds orders matching %$search% in title, author, or isbn.
 C<$owner> Finds order for the logged in user.
 C<$pending> Finds pending orders. Ignores completed and cancelled orders.
 C<$ordered> Finds orders to receive only (status 'ordered' or 'partial').
 C<$owner> Finds order for the logged in user.
 C<$pending> Finds pending orders. Ignores completed and cancelled orders.
 C<$ordered> Finds orders to receive only (status 'ordered' or 'partial').
@@ -1676,6 +1768,8 @@ sub SearchOrders {
                biblio.*,
                biblioitems.isbn,
                biblioitems.biblioitemnumber,
                biblio.*,
                biblioitems.isbn,
                biblioitems.biblioitemnumber,
+               biblioitems.publishercode,
+               biblioitems.publicationyear,
                aqbasket.authorisedby,
                aqbasket.booksellerid,
                aqbasket.closedate,
                aqbasket.authorisedby,
                aqbasket.booksellerid,
                aqbasket.closedate,
@@ -1692,7 +1786,7 @@ sub SearchOrders {
             LEFT JOIN biblioitems ON biblioitems.biblionumber=biblio.biblionumber
     };
 
             LEFT JOIN biblioitems ON biblioitems.biblionumber=biblio.biblionumber
     };
 
-    # If we search on ordernumber, we retrieve the transfered order if a transfer has been done.
+    # If we search on ordernumber, we retrieve the transferred order if a transfer has been done.
     $query .= q{
             LEFT JOIN aqorders_transfers ON aqorders_transfers.ordernumber_to = aqorders.ordernumber
     } if $ordernumber;
     $query .= q{
             LEFT JOIN aqorders_transfers ON aqorders_transfers.ordernumber_to = aqorders.ordernumber
     } if $ordernumber;
@@ -1702,10 +1796,20 @@ sub SearchOrders {
     };
 
     if ( $pending or $ordered ) {
     };
 
     if ( $pending or $ordered ) {
-        $query .= q{ AND (quantity > quantityreceived OR quantityreceived is NULL)};
-    }
-    if ( $ordered ) {
-        $query .= q{ AND aqorders.orderstatus IN ( "ordered", "partial" )};
+        $query .= q{
+            AND (
+                ( aqbasket.is_standing AND aqorders.orderstatus IN ( "new", "ordered", "partial" ) )
+                OR (
+                    ( quantity > quantityreceived OR quantityreceived is NULL )
+        };
+
+        if ( $ordered ) {
+            $query .= q{ AND aqorders.orderstatus IN ( "ordered", "partial" )};
+        }
+        $query .= q{
+                )
+            )
+        };
     }
 
     my $userenv = C4::Context->userenv;
     }
 
     my $userenv = C4::Context->userenv;
@@ -1808,7 +1912,7 @@ sub DelOrder {
 
     my @itemnumbers = GetItemnumbersFromOrder( $ordernumber );
     foreach my $itemnumber (@itemnumbers){
 
     my @itemnumbers = GetItemnumbersFromOrder( $ordernumber );
     foreach my $itemnumber (@itemnumbers){
-        my $delcheck = C4::Items::DelItemCheck( $dbh, $bibnum, $itemnumber );
+        my $delcheck = C4::Items::DelItemCheck( $bibnum, $itemnumber );
 
         if($delcheck != 1) {
             $error->{'delitem'} = 1;
 
         if($delcheck != 1) {
             $error->{'delitem'} = 1;
@@ -1817,7 +1921,8 @@ sub DelOrder {
 
     if($delete_biblio) {
         # We get the number of remaining items
 
     if($delete_biblio) {
         # We get the number of remaining items
-        my $itemcount = C4::Items::GetItemsCount($bibnum);
+        my $biblio = Koha::Biblios->find( $bibnum );
+        my $itemcount = $biblio->items->count;
 
         # If there are no items left,
         if ( $itemcount == 0 ) {
 
         # If there are no items left,
         if ( $itemcount == 0 ) {
@@ -1838,11 +1943,11 @@ sub DelOrder {
     my $newordernumber = TransferOrder($ordernumber, $basketno);
 
 Transfer an order line to a basket.
     my $newordernumber = TransferOrder($ordernumber, $basketno);
 
 Transfer an order line to a basket.
-Mark $ordernumber as cancelled with an internal note 'Cancelled and transfered
+Mark $ordernumber as cancelled with an internal note 'Cancelled and transferred
 to BOOKSELLER on DATE' and create new order with internal note
 to BOOKSELLER on DATE' and create new order with internal note
-'Transfered from BOOKSELLER on DATE'.
+'Transferred from BOOKSELLER on DATE'.
 Move all attached items to the new order.
 Move all attached items to the new order.
-Received orders cannot be transfered.
+Received orders cannot be transferred.
 Return the ordernumber of created order.
 
 =cut
 Return the ordernumber of created order.
 
 =cut
@@ -1852,8 +1957,11 @@ sub TransferOrder {
 
     return unless ($ordernumber and $basketno);
 
 
     return unless ($ordernumber and $basketno);
 
-    my $order = GetOrder( $ordernumber );
-    return if $order->{datereceived};
+    my $order = Koha::Acquisition::Orders->find( $ordernumber ) or return;
+    return if $order->datereceived;
+
+    $order = $order->unblessed;
+
     my $basket = GetBasket($basketno);
     return unless $basket;
 
     my $basket = GetBasket($basketno);
     return unless $basket;
 
@@ -1862,17 +1970,17 @@ sub TransferOrder {
 
     $query = q{
         UPDATE aqorders
 
     $query = q{
         UPDATE aqorders
-        SET datecancellationprinted = CAST(NOW() AS date)
+        SET datecancellationprinted = CAST(NOW() AS date), orderstatus = ?
         WHERE ordernumber = ?
     };
     $sth = $dbh->prepare($query);
         WHERE ordernumber = ?
     };
     $sth = $dbh->prepare($query);
-    $rv = $sth->execute($ordernumber);
+    $rv = $sth->execute('cancelled', $ordernumber);
 
     delete $order->{'ordernumber'};
     delete $order->{parent_ordernumber};
     $order->{'basketno'} = $basketno;
 
 
     delete $order->{'ordernumber'};
     delete $order->{parent_ordernumber};
     $order->{'basketno'} = $basketno;
 
-    my $newordernumber = Koha::Acquisition::Order->new($order)->insert->{ordernumber};
+    my $newordernumber = Koha::Acquisition::Order->new($order)->store->ordernumber;
 
     $query = q{
         UPDATE aqorders_items
 
     $query = q{
         UPDATE aqorders_items
@@ -2042,7 +2150,6 @@ sub GetLateOrders {
         AND aqbasket.closedate IS NOT NULL
         AND (aqorders.datecancellationprinted IS NULL OR aqorders.datecancellationprinted='0000-00-00')
     ";
         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,
     if ($dbdriver eq "mysql") {
         $select .= "
         aqorders.quantity - COALESCE(aqorders.quantityreceived,0)                 AS quantity,
@@ -2053,11 +2160,7 @@ sub GetLateOrders {
             $from .= " AND (closedate <= DATE_SUB(CAST(now() AS date),INTERVAL ? DAY)) " ;
             push @query_params, $delay;
         }
             $from .= " AND (closedate <= DATE_SUB(CAST(now() AS date),INTERVAL ? DAY)) " ;
             push @query_params, $delay;
         }
-        $having = "
-        HAVING quantity          <> 0
-            AND unitpricesupplier <> 0
-            AND unitpricelib      <> 0
-        ";
+        $from .= " AND aqorders.quantity - COALESCE(aqorders.quantityreceived,0) <> 0";
     } else {
         # FIXME: account for IFNULL as above
         $select .= "
     } else {
         # FIXME: account for IFNULL as above
         $select .= "
@@ -2069,6 +2172,7 @@ sub GetLateOrders {
             $from .= " AND (closedate <= (CAST(now() AS date) -(INTERVAL ? DAY)) ";
             push @query_params, $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 = ? ';
     }
     if (defined $supplierid) {
         $from .= ' AND aqbasket.booksellerid = ? ';
@@ -2099,7 +2203,7 @@ sub GetLateOrders {
         push @query_params, C4::Context->userenv->{branch};
     }
     $from .= " AND orderstatus <> 'cancelled' ";
         push @query_params, C4::Context->userenv->{branch};
     }
     $from .= " AND orderstatus <> 'cancelled' ";
-    my $query = "$select $from $having\nORDER BY latesince, basketno, borrowers.branchcode, supplier";
+    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);
     $debug and print STDERR "GetLateOrders query: $query\nGetLateOrders args: " . join(" ",@query_params);
     my $sth = $dbh->prepare($query);
     $sth->execute(@query_params);
@@ -2184,6 +2288,22 @@ sub GetHistory {
     my $total_qtyreceived = 0;
     my $total_price       = 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
@@ -2251,10 +2371,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";
@@ -2335,7 +2458,7 @@ sub GetHistory {
 
   $results = GetRecentAcqui($days);
 
 
   $results = GetRecentAcqui($days);
 
-C<$results> is a ref to a table which containts hashref
+C<$results> is a ref to a table which contains hashref
 
 =cut
 
 
 =cut
 
@@ -2414,7 +2537,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,
@@ -2494,9 +2618,13 @@ sub GetInvoices {
         push @bind_strs, " borrowers.branchcode = ? ";
         push @bind_args, $args{branchcode};
     }
         push @bind_strs, " borrowers.branchcode = ? ";
         push @bind_args, $args{branchcode};
     }
+    if($args{message_id}) {
+        push @bind_strs, " aqinvoices.message_id = ? ";
+        push @bind_args, $args{message_id};
+    }
 
     $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};
@@ -2576,6 +2704,7 @@ sub GetInvoiceDetails {
         SELECT aqorders.*,
                 biblio.*,
                 biblio.copyrightdate,
         SELECT aqorders.*,
                 biblio.*,
                 biblio.copyrightdate,
+                biblioitems.isbn,
                 biblioitems.publishercode,
                 biblioitems.publicationyear,
                 aqbasket.basketname,
                 biblioitems.publishercode,
                 biblioitems.publicationyear,
                 aqbasket.basketname,
@@ -2618,7 +2747,7 @@ sub AddInvoice {
     return unless(%invoice and $invoice{invoicenumber});
 
     my @columns = qw(invoicenumber booksellerid shipmentdate billingdate
     return unless(%invoice and $invoice{invoicenumber});
 
     my @columns = qw(invoicenumber booksellerid shipmentdate billingdate
-        closedate shipmentcost shipmentcost_budgetid);
+        closedate shipmentcost shipmentcost_budgetid message_id);
 
     my @set_strs;
     my @set_args;
 
     my @set_strs;
     my @set_args;
@@ -2719,7 +2848,7 @@ sub CloseInvoice {
 
 Reopen an invoice
 
 
 Reopen an invoice
 
-Equivalent to ModInvoice(invoiceid => $invoiceid, closedate => C4::Dates->new()->output('iso'))
+Equivalent to ModInvoice(invoiceid => $invoiceid, closedate => output_pref({ dt=>dt_from_string, dateonly=>1, otputpref=>'iso' }))
 
 =cut
 
 
 =cut
 
@@ -2821,9 +2950,6 @@ sub GetBiblioCountByBasketno {
     return $sth->fetchrow;
 }
 
     return $sth->fetchrow;
 }
 
-# This is *not* the good way to calcul prices
-# But it's how it works at the moment into Koha
-# This will be fixed later.
 # Note this subroutine should be moved to Koha::Acquisition::Order
 # Will do when a DBIC decision will be taken.
 sub populate_order_with_prices {
 # Note this subroutine should be moved to Koha::Acquisition::Order
 # Will do when a DBIC decision will be taken.
 sub populate_order_with_prices {
@@ -2833,61 +2959,82 @@ sub populate_order_with_prices {
     my $booksellerid = $params->{booksellerid};
     return unless $booksellerid;
 
     my $booksellerid = $params->{booksellerid};
     return unless $booksellerid;
 
-    my $bookseller = Koha::Acquisition::Bookseller->fetch({ id => $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;
 
 
     my $receiving = $params->{receiving};
     my $ordering  = $params->{ordering};
     my $discount  = $order->{discount};
     $discount /= 100 if $discount > 1;
 
-    $order->{rrp}   = Koha::Number::Price->new( $order->{rrp} )->round;
-    $order->{ecost} = Koha::Number::Price->new( $order->{ecost} )->round;
     if ($ordering) {
     if ($ordering) {
-        if ( $bookseller->{listincgst} ) {
-            $order->{rrpgsti} = $order->{rrp};
-            $order->{rrpgste} = Koha::Number::Price->new(
-                $order->{rrpgsti} / ( 1 + $order->{gstrate} ) )->round;
-            $order->{ecostgsti} = $order->{ecost};
-            $order->{ecostgste} = Koha::Number::Price->new(
-                $order->{ecost} / ( 1 + $order->{gstrate} ) )->round;
-            $order->{gstvalue} = Koha::Number::Price->new(
-                ( $order->{ecostgsti} - $order->{ecostgste} ) *
-                  $order->{quantity} )->round;
-            $order->{totalgste} = $order->{ecostgste} * $order->{quantity};
-            $order->{totalgsti} = $order->{ecostgsti} * $order->{quantity};
+        $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 {
         }
         else {
-            $order->{rrpgste} = $order->{rrp};
-            $order->{rrpgsti} = Koha::Number::Price->new(
-                $order->{rrp} * ( 1 + $order->{gstrate} ) )->round;
-            $order->{ecostgste} = $order->{ecost};
-            $order->{ecostgsti} = Koha::Number::Price->new(
-                $order->{ecost} * ( 1 + $order->{gstrate} ) )->round;
-            $order->{gstvalue} = Koha::Number::Price->new(
-                ( $order->{ecostgsti} - $order->{ecostgste} ) *
-                  $order->{quantity} )->round;
-            $order->{totalgste} = $order->{ecostgste} * $order->{quantity};
-            $order->{totalgsti} = $order->{ecostgsti} * $order->{quantity};
+            # 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} * $order->{ecost_tax_excluded} * $order->{tax_rate_on_ordering};
     }
 
     if ($receiving) {
     }
 
     if ($receiving) {
-        if ( $bookseller->{listincgst} ) {
-            $order->{unitpricegsti} = Koha::Number::Price->new( $order->{unitprice} )->round;
-            $order->{unitpricegste} = Koha::Number::Price->new(
-              $order->{unitpricegsti} / ( 1 + $order->{gstrate} ) )->round;
+        $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 {
         }
         else {
-            $order->{unitpricegste} = Koha::Number::Price->new( $order->{unitprice} )->round;
-            $order->{unitpricegsti} = Koha::Number::Price->new(
-              $order->{unitpricegste} * ( 1 + $order->{gstrate} ) )->round;
+            # 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} );
         }
         }
-        $order->{gstvalue} = Koha::Number::Price->new(
-          ( $order->{unitpricegsti} - $order->{unitpricegste} )
-          * $order->{quantityreceived} )->round;
 
 
-        $order->{totalgste} = $order->{unitpricegste} * $order->{quantity};
-        $order->{totalgsti} = $order->{unitpricegsti} * $order->{quantity};
+        # 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};
     }
 
     return $order;
     }
 
     return $order;
@@ -2965,16 +3112,17 @@ sub NotifyOrderUsers {
 
     my $order = GetOrder( $ordernumber );
     for my $borrowernumber (@borrowernumbers) {
 
     my $order = GetOrder( $ordernumber );
     for my $borrowernumber (@borrowernumbers) {
-        my $borrower = C4::Members::GetMember( borrowernumber => $borrowernumber );
-        my $branch = C4::Branch::GetBranchDetail( $borrower->{branchcode} );
-        my $biblio = C4::Biblio::GetBiblio( $order->{biblionumber} );
+        my $patron = Koha::Patrons->find( $borrowernumber );
+        my $library = $patron->library->unblessed;
+        my $biblio = Koha::Biblios->find( $order->{biblionumber} )->unblessed;
         my $letter = C4::Letters::GetPreparedLetter(
             module      => 'acquisition',
             letter_code => 'ACQ_NOTIF_ON_RECEIV',
         my $letter = C4::Letters::GetPreparedLetter(
             module      => 'acquisition',
             letter_code => 'ACQ_NOTIF_ON_RECEIV',
-            branchcode  => $branch->{branchcode},
+            branchcode  => $library->{branchcode},
+            lang        => $patron->lang,
             tables      => {
             tables      => {
-                'branches'    => $branch,
-                'borrowers'   => $borrower,
+                'branches'    => $library,
+                'borrowers'   => $patron->unblessed,
                 'biblio'      => $biblio,
                 'aqorders'    => $order,
             },
                 'biblio'      => $biblio,
                 'aqorders'    => $order,
             },
@@ -3004,7 +3152,7 @@ If the field does not exist, it will be created too.
 
 sub FillWithDefaultValues {
     my ($record) = @_;
 
 sub FillWithDefaultValues {
     my ($record) = @_;
-    my $tagslib = C4::Biblio::GetMarcStructure( 1, 'ACQ' );
+    my $tagslib = C4::Biblio::GetMarcStructure( 1, 'ACQ', { unsafe => 1 } );
     if ($tagslib) {
         my ($itemfield) =
           C4::Biblio::GetMarcFromKohaField( 'items.itemnumber', '' );
     if ($tagslib) {
         my ($itemfield) =
           C4::Biblio::GetMarcFromKohaField( 'items.itemnumber', '' );
@@ -3012,7 +3160,7 @@ sub FillWithDefaultValues {
             next unless $tag;
             next if $tag == $itemfield;
             for my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
             next unless $tag;
             next if $tag == $itemfield;
             for my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
-                next if ( subfield_is_koha_internal_p($subfield) );
+                next if IsMarcStructureInternal($tagslib->{$tag}{$subfield});
                 my $defaultvalue = $tagslib->{$tag}{$subfield}{defaultvalue};
                 if ( defined $defaultvalue and $defaultvalue ne '' ) {
                     my @fields = $record->field($tag);
                 my $defaultvalue = $tagslib->{$tag}{$subfield}{defaultvalue};
                 if ( defined $defaultvalue and $defaultvalue ne '' ) {
                     my @fields = $record->field($tag);