X-Git-Url: http://koha-dev.rot13.org:8081/gitweb/?a=blobdiff_plain;f=C4%2FAcquisition.pm;h=bd5c307eefdb66e492e7b2d7f1085146dc2ef344;hb=79c2999c6e916ddc5c4435e4cb7775abe766f025;hp=4c2ead7281ba5496a30ad50103227875b8c28b55;hpb=c59e395b749132080fefb81e5b12f8c0b6654665;p=koha-ffzg.git diff --git a/C4/Acquisition.pm b/C4/Acquisition.pm index 4c2ead7281..bd5c307eef 100644 --- a/C4/Acquisition.pm +++ b/C4/Acquisition.pm @@ -20,19 +20,26 @@ package C4::Acquisition; use Modern::Perl; use Carp; +use Text::CSV_XS; use C4::Context; use C4::Debug; use C4::Suggestions; use C4::Biblio; use C4::Contract; use C4::Debug; +use C4::Log qw(logaction); use C4::Templates qw(gettemplate); use Koha::DateUtils qw( dt_from_string output_pref ); -use Koha::Acquisition::Order; +use Koha::Acquisition::Baskets; use Koha::Acquisition::Booksellers; +use Koha::Acquisition::Orders; use Koha::Biblios; +use Koha::Exceptions; +use Koha::Items; use Koha::Number::Price; use Koha::Libraries; +use Koha::CsvProfiles; +use Koha::Patrons; use C4::Koha; @@ -47,7 +54,7 @@ BEGIN { require Exporter; @ISA = qw(Exporter); @EXPORT = qw( - &GetBasket &NewBasket &CloseBasket &ReopenBasket &DelBasket &ModBasket + &GetBasket &NewBasket &ReopenBasket &ModBasket &GetBasketAsCSV &GetBasketGroupAsCSV &GetBasketsByBookseller &GetBasketsByBasketgroup &GetBasketsInfosByBookseller @@ -60,12 +67,11 @@ BEGIN { &ModBasketgroup &NewBasketgroup &DelBasketgroup &GetBasketgroup &CloseBasketgroup &GetBasketgroups &ReOpenBasketgroup - &DelOrder &ModOrder &GetOrder &GetOrders &GetOrdersByBiblionumber - &GetLateOrders &GetOrderFromItemnumber + &ModOrder &GetOrder &GetOrders &GetOrdersByBiblionumber + &GetOrderFromItemnumber &SearchOrders &GetHistory &GetRecentAcqui &ModReceiveOrder &CancelReceipt &TransferOrder - &GetLastOrderNotReceivedFromSubscriptionid &GetLastOrderReceivedFromSubscriptionid &ModItemOrder &GetParcels @@ -80,8 +86,6 @@ BEGIN { &DelInvoice &MergeInvoices - &GetItemnumbersFromOrder - &AddClaim &GetBiblioCountByBasketno @@ -90,6 +94,9 @@ BEGIN { &NotifyOrderUsers &FillWithDefaultValues + + &get_rounded_price + &get_rounding_sql ); } @@ -117,28 +124,6 @@ sub GetOrderFromItemnumber { } -# Returns the itemnumber(s) associated with the ordernumber given in parameter -sub GetItemnumbersFromOrder { - my ($ordernumber) = @_; - my $dbh = C4::Context->dbh; - my $query = "SELECT itemnumber FROM aqorders_items WHERE ordernumber=?"; - my $sth = $dbh->prepare($query); - $sth->execute($ordernumber); - my @tab; - - while (my $order = $sth->fetchrow_hashref) { - push @tab, $order->{'itemnumber'}; - } - - return @tab; - -} - - - - - - =head1 NAME C4::Acquisition - Koha functions for dealing with orders and acquisitions @@ -187,7 +172,7 @@ sub GetBasket { =head3 NewBasket $basket = &NewBasket( $booksellerid, $authorizedby, $basketname, - $basketnote, $basketbooksellernote, $basketcontractnumber, $deliveryplace, $billingplace, $is_standing ); + $basketnote, $basketbooksellernote, $basketcontractnumber, $deliveryplace, $billingplace, $is_standing, $create_items ); Create a new basket in aqbasket table @@ -206,7 +191,7 @@ The other parameters are optional, see ModBasketHeader for more info on them. sub NewBasket { my ( $booksellerid, $authorisedby, $basketname, $basketnote, $basketbooksellernote, $basketcontractnumber, $deliveryplace, - $billingplace, $is_standing ) = @_; + $billingplace, $is_standing, $create_items ) = @_; my $dbh = C4::Context->dbh; my $query = 'INSERT INTO aqbasket (creationdate,booksellerid,authorisedby) ' @@ -218,28 +203,14 @@ sub NewBasket { $basketnote ||= q{}; $basketbooksellernote ||= q{}; ModBasketHeader( $basket, $basketname, $basketnote, $basketbooksellernote, - $basketcontractnumber, $booksellerid, $deliveryplace, $billingplace, $is_standing ); - return $basket; -} - -#------------------------------------------------------------# - -=head3 CloseBasket - - &CloseBasket($basketno); + $basketcontractnumber, $booksellerid, $deliveryplace, $billingplace, $is_standing, $create_items ); -close a basket (becomes unmodifiable, except for receives) - -=cut - -sub CloseBasket { - my ($basketno) = @_; - my $dbh = C4::Context->dbh; - $dbh->do('UPDATE aqbasket SET closedate=now() WHERE basketno=?', {}, $basketno ); + # Log the basket creation + if (C4::Context->preference("AcqLog")) { + logaction('ACQUISITIONS', 'ADD_BASKET', $basket); + } - $dbh->do( q{UPDATE aqorders SET orderstatus = 'ordered' WHERE basketno = ? AND orderstatus != 'complete'}, - {}, $basketno); - return; + return $basket; } =head3 ReopenBasket @@ -259,8 +230,17 @@ sub ReopenBasket { UPDATE aqorders SET orderstatus = 'new' WHERE basketno = ? - AND orderstatus != 'complete' + AND orderstatus NOT IN ( 'complete', 'cancelled' ) }, {}, $basketno); + + # Log the basket reopening + if (C4::Context->preference("AcqLog")) { + logaction( + 'ACQUISITIONS', + 'REOPEN_BASKET', + $basketno + ); + } return; } @@ -277,7 +257,7 @@ $cgi parameter is needed for column name translation =cut sub GetBasketAsCSV { - my ($basketno, $cgi) = @_; + my ($basketno, $cgi, $csv_profile_id) = @_; my $basket = GetBasket($basketno); my @orders = GetOrders($basketno); my $contract = GetContract({ @@ -285,48 +265,95 @@ sub GetBasketAsCSV { }); my $template = C4::Templates::gettemplate("acqui/csv/basket.tt", "intranet", $cgi); - 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'}, - }; - for my $place ( qw( deliveryplace billingplace ) ) { - if ( my $library = Koha::Libraries->find( $row->{deliveryplace} ) ) { - $row->{$place} = $library->branchname + if ($csv_profile_id) { + 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 $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; } - 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->{$_}; + 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; + } } @@ -356,16 +383,17 @@ sub GetBasketGroupAsCSV { 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 = { clientnumber => $bookseller->accountnumber, 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}, rrp_tax_included => $order->{rrp_tax_included}, @@ -452,32 +480,6 @@ sub ReOpenBasketgroup { #------------------------------------------------------------# - -=head3 DelBasket - - &DelBasket($basketno); - -Deletes the basket that has basketno field $basketno in the aqbasket table. - -=over - -=item C<$basketno> is the primary key of the basket in the aqbasket table. - -=back - -=cut - -sub DelBasket { - my ( $basketno ) = @_; - my $query = "DELETE FROM aqbasket WHERE basketno=?"; - my $dbh = C4::Context->dbh; - my $sth = $dbh->prepare($query); - $sth->execute($basketno); - return; -} - -#------------------------------------------------------------# - =head3 ModBasket &ModBasket($basketinfo); @@ -514,6 +516,15 @@ sub ModBasket { my $sth = $dbh->prepare($query); $sth->execute(@params); + # Log the basket update + if (C4::Context->preference("AcqLog")) { + logaction( + 'ACQUISITIONS', + 'MODIFY_BASKET', + $basketinfo->{'basketno'} + ); + } + return; } @@ -545,27 +556,43 @@ Modifies a basket's header. =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 { - my ($basketno, $basketname, $note, $booksellernote, $contractnumber, $booksellerid, $deliveryplace, $billingplace, $is_standing) = @_; + my ($basketno, $basketname, $note, $booksellernote, $contractnumber, $booksellerid, $deliveryplace, $billingplace, $is_standing, $create_items) = @_; + + $is_standing ||= 0; my $query = qq{ UPDATE aqbasket - SET basketname=?, note=?, booksellernote=?, booksellerid=?, deliveryplace=?, billingplace=?, is_standing=? + SET basketname=?, note=?, booksellernote=?, booksellerid=?, deliveryplace=?, billingplace=?, is_standing=?, create_items=? WHERE basketno=? }; my $dbh = C4::Context->dbh; my $sth = $dbh->prepare($query); - $sth->execute($basketname, $note, $booksellernote, $booksellerid, $deliveryplace, $billingplace, $is_standing, $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=?"; my $sth2 = $dbh->prepare($query2); $sth2->execute($contractnumber,$basketno); } + + # Log the basket update + if (C4::Context->preference("AcqLog")) { + logaction( + 'ACQUISITIONS', + 'MODIFY_BASKET_HEADER', + $basketno + ); + } + + return; return; } @@ -634,7 +661,7 @@ sub GetBasketsInfosByBookseller { 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 ) @@ -645,15 +672,24 @@ sub GetBasketsInfosByBookseller { 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 = ?}; + $query.=" GROUP BY aqbasket.basketno, aqbasket.basketname, aqbasket.note, aqbasket.booksellernote, aqbasket.contractnumber, aqbasket.creationdate, aqbasket.closedate, aqbasket.booksellerid, aqbasket.authorisedby, aqbasket.booksellerinvoicenumber, aqbasket.basketgroupid, aqbasket.deliveryplace, aqbasket.billingplace, aqbasket.branch, aqbasket.is_standing, aqbasket.create_items"; + unless ( $allbaskets ) { - $query.=" AND (closedate IS NULL OR (aqorders.quantity > aqorders.quantityreceived AND datecancellationprinted IS NULL))"; + # Don't show the basket if it's NOT CLOSED or is FULLY RECEIVED + $query.=" HAVING (closedate IS NULL OR ( + SUM( + IF(aqorders.datereceived IS NULL + AND aqorders.datecancellationprinted IS NULL + , aqorders.quantity + , 0) + ) > 0))" } - $query.=" GROUP BY aqbasket.basketno"; my $sth = $dbh->prepare($query); $sth->execute($supplierid); @@ -737,6 +773,16 @@ sub ModBasketUsers { foreach my $basketuser_id (@basketusers_ids) { $sth->execute($basketno, $basketuser_id); } + + # Log the basket update + if (C4::Context->preference("AcqLog")) { + logaction( + 'ACQUISITIONS', + 'MODIFY_BASKET_USERS', + $basketno + ); + } + return; } @@ -750,7 +796,7 @@ AcqViewBaskets, user permissions and basket properties (creator, users list, 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. @@ -767,7 +813,10 @@ sub CanUserManageBasket { 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); @@ -805,8 +854,8 @@ sub CanUserManageBasket { 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} @@ -1085,15 +1134,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 |; } @@ -1172,8 +1220,6 @@ 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, @@ -1197,70 +1243,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); @@ -1296,7 +1278,7 @@ sub ModOrder { foreach my $orderinfokey (grep(!/ordernumber/, keys %$orderinfo)){ # ... and skip hash entries that are not in the aqorders table # FIXME : probably not the best way to do it (would be better to have a correct hash) - next unless grep(/^$orderinfokey$/, @$colnames); + next unless grep { $_ eq $orderinfokey } @$colnames; $query .= "$orderinfokey=?, "; push(@params, $orderinfo->{$orderinfokey}); } @@ -1345,8 +1327,8 @@ sub ModItemOrder { user => $user, invoice => $invoice, budget_id => $budget_id, + datereceived => $datereceived, received_itemnumbers => \@received_itemnumbers, - order_internalnote => $order_internalnote, } ); @@ -1369,10 +1351,18 @@ 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 = output_pref( + { + dt => ( $datereceived ? dt_from_string( $datereceived ) : dt_from_string ), + dateformat => 'iso', + dateonly => 1, + } + ); + my $suggestionid = GetSuggestionFromBiblionumber( $biblionumber ); if ($suggestionid) { ModSuggestion( {suggestionid=>$suggestionid, @@ -1397,22 +1387,29 @@ sub ModReceiveOrder { UPDATE aqorders SET quantity = ?, orderstatus = 'partial'|; - $query .= q|, order_internalnote = ?| if defined $order->{order_internalnote}; $query .= q| WHERE ordernumber = ?|; my $sth = $dbh->prepare($query); $sth->execute( ( $is_standing ? 1 : ($order->{quantity} - $quantrec) ), - ( defined $order->{order_internalnote} ? $order->{order_internalnote} : () ), $order->{ordernumber} ); + if ( not $order->{subscriptionid} && defined $order->{order_internalnote} ) { + $dbh->do( + q|UPDATE aqorders + SET order_internalnote = ? + WHERE ordernumber = ?|, {}, + $order->{order_internalnote}, $order->{ordernumber} + ); + } + # Recalculate tax_value $dbh->do(q| UPDATE aqorders SET - tax_value_on_ordering = quantity * ecost_tax_excluded * tax_rate_on_ordering, - tax_value_on_receiving = quantity * unitprice_tax_excluded * tax_rate_on_receiving + tax_value_on_ordering = quantity * | . get_rounding_sql(q|ecost_tax_excluded|) . q| * tax_rate_on_ordering, + tax_value_on_receiving = quantity * | . get_rounding_sql(q|unitprice_tax_excluded|) . q| * tax_rate_on_receiving WHERE ordernumber = ? |, undef, $order->{ordernumber}); @@ -1424,12 +1421,12 @@ sub ModReceiveOrder { $order->{tax_rate_on_ordering} //= 0; $order->{unitprice_tax_excluded} //= 0; $order->{tax_rate_on_receiving} //= 0; - $order->{tax_value_on_ordering} = $order->{quantity} * $order->{ecost_tax_excluded} * $order->{tax_rate_on_ordering}; - $order->{tax_value_on_receiving} = $order->{quantity} * $order->{unitprice_tax_excluded} * $order->{tax_rate_on_receiving}; + $order->{tax_value_on_ordering} = $order->{quantity} * get_rounded_price($order->{ecost_tax_excluded}) * $order->{tax_rate_on_ordering}; + $order->{tax_value_on_receiving} = $order->{quantity} * get_rounded_price($order->{unitprice_tax_excluded}) * $order->{tax_rate_on_receiving}; $order->{datereceived} = $datereceived; $order->{invoiceid} = $invoice->{invoiceid}; $order->{orderstatus} = 'complete'; - $new_ordernumber = Koha::Acquisition::Order->new($order)->insert->{ordernumber}; + $new_ordernumber = Koha::Acquisition::Order->new($order)->store->ordernumber; # TODO What if the store fails? if ($received_items) { foreach my $itemnumber (@$received_items) { @@ -1447,6 +1444,10 @@ sub ModReceiveOrder { |; $query .= q| + , replacementprice = ? + | if defined $order->{replacementprice}; + + $query .= q| , unitprice = ?, unitprice_tax_included = ?, unitprice_tax_excluded = ? | if defined $order->{unitprice}; @@ -1467,6 +1468,10 @@ sub ModReceiveOrder { my $sth = $dbh->prepare( $query ); my @params = ( $quantrec, $datereceived, $invoice->{invoiceid}, ( $budget_id ? $budget_id : $order->{budget_id} ) ); + if ( defined $order->{replacementprice} ) { + push @params, $order->{replacementprice}; + } + if ( defined $order->{unitprice} ) { push @params, $order->{unitprice}, $order->{unitprice_tax_included}, $order->{unitprice_tax_excluded}; } @@ -1530,7 +1535,8 @@ sub CancelReceipt { my $parent_ordernumber = $order->{'parent_ordernumber'}; - my @itemnumbers = GetItemnumbersFromOrder( $ordernumber ); + my $order_obj = Koha::Acquisition::Orders->find( $ordernumber ); # FIXME rewrite all this subroutine using this object + my @itemnumbers = $order_obj->items->get_column('itemnumber'); if($parent_ordernumber == $ordernumber || not $parent_ordernumber) { # The order line has no parent, just mark it as not received @@ -1544,54 +1550,56 @@ sub CancelReceipt { }; $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. - $query = qq{ - SELECT quantity, datereceived - FROM aqorders - WHERE ordernumber = ? - }; - $sth = $dbh->prepare($query); - $sth->execute($parent_ordernumber); - my $parent_order = $sth->fetchrow_hashref; - unless($parent_order) { - warn "Parent order $parent_ordernumber does not exist."; - return; - } - if($parent_order->{'datereceived'}) { - warn "CancelReceipt: parent order is received.". - " Can't cancel receipt."; - return; - } - $query = qq{ - UPDATE aqorders - SET quantity = ?, - orderstatus = 'ordered' - WHERE ordernumber = ? - }; - $sth = $dbh->prepare($query); - my $rv = $sth->execute( - $order->{'quantity'} + $parent_order->{'quantity'}, - $parent_ordernumber - ); - unless($rv) { - warn "Cannot update parent order line, so do not cancel". - " receipt"; - return; - } + unless ( $order_obj->basket->is_standing ) { + $query = qq{ + SELECT quantity, datereceived + FROM aqorders + WHERE ordernumber = ? + }; + $sth = $dbh->prepare($query); + $sth->execute($parent_ordernumber); + my $parent_order = $sth->fetchrow_hashref; + unless($parent_order) { + warn "Parent order $parent_ordernumber does not exist."; + return; + } + if($parent_order->{'datereceived'}) { + warn "CancelReceipt: parent order is received.". + " Can't cancel receipt."; + return; + } + $query = qq{ + UPDATE aqorders + SET quantity = ?, + orderstatus = 'ordered' + WHERE ordernumber = ? + }; + $sth = $dbh->prepare($query); + my $rv = $sth->execute( + $order->{'quantity'} + $parent_order->{'quantity'}, + $parent_ordernumber + ); + unless($rv) { + warn "Cannot update parent order line, so do not cancel". + " receipt"; + return; + } - # Recalculate tax_value - $dbh->do(q| - UPDATE aqorders - SET - tax_value_on_ordering = quantity * ecost_tax_excluded * tax_rate_on_ordering, - tax_value_on_receiving = quantity * unitprice_tax_excluded * tax_rate_on_receiving - WHERE ordernumber = ? - |, undef, $parent_ordernumber); + # Recalculate tax_value + $dbh->do(q| + UPDATE aqorders + SET + tax_value_on_ordering = quantity * | . get_rounding_sql(q|ecost_tax_excluded|) . q| * tax_rate_on_ordering, + tax_value_on_receiving = quantity * | . get_rounding_sql(q|unitprice_tax_excluded|) . q| * tax_rate_on_receiving + WHERE ordernumber = ? + |, undef, $parent_ordernumber); + } - _cancel_items_receipt( $ordernumber, $parent_ordernumber ); + _cancel_items_receipt( $order_obj, $parent_ordernumber ); # Delete order line $query = qq{ DELETE FROM aqorders @@ -1602,21 +1610,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 $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 ); # FIXME We do not need that, we already have Koha::Items from $order_obj->items + my $biblio = $item->biblio; + 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; - foreach ( $item->field($itemfield) ) { + foreach ( $item_marc->field($itemfield) ) { $_->update( $sf => $v ); } } - C4::Items::ModItemFromMarc( $item, $biblionumber, $in ); + C4::Items::ModItemFromMarc( $item_marc, $biblio->biblionumber, $in ); } } } @@ -1625,11 +1633,11 @@ sub CancelReceipt { } 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 $items = $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 @@ -1638,13 +1646,13 @@ sub _cancel_items_receipt { }; my $dbh = C4::Context->dbh; my $sth = $dbh->prepare($query); - foreach my $itemnumber (@itemnumbers) { - $sth->execute($itemnumber, $itemnumber); + while ( my $item = $items->next ) { + $sth->execute($item->itemnumber, $item->itemnumber); } } else { # Update items - foreach my $itemnumber (@itemnumbers) { - ModItemOrder($itemnumber, $parent_ordernumber); + while ( my $item = $items->next ) { + ModItemOrder($item->itemnumber, $parent_ordernumber); } } } @@ -1815,67 +1823,6 @@ sub SearchOrders { #------------------------------------------------------------# -=head3 DelOrder - - &DelOrder($biblionumber, $ordernumber); - -Cancel the order with the given order and biblio numbers. It does not -delete any entries in the aqorders table, it merely marks them as -cancelled. - -=cut - -sub DelOrder { - my ( $bibnum, $ordernumber, $delete_biblio, $reason ) = @_; - - my $error; - my $dbh = C4::Context->dbh; - my $query = " - UPDATE aqorders - SET datecancellationprinted=now(), orderstatus='cancelled' - "; - if($reason) { - $query .= ", cancellationreason = ? "; - } - $query .= " - WHERE biblionumber=? AND ordernumber=? - "; - my $sth = $dbh->prepare($query); - if($reason) { - $sth->execute($reason, $bibnum, $ordernumber); - } else { - $sth->execute( $bibnum, $ordernumber ); - } - $sth->finish; - - my @itemnumbers = GetItemnumbersFromOrder( $ordernumber ); - foreach my $itemnumber (@itemnumbers){ - my $delcheck = C4::Items::DelItemCheck( $bibnum, $itemnumber ); - - if($delcheck != 1) { - $error->{'delitem'} = 1; - } - } - - if($delete_biblio) { - # We get the number of remaining items - my $biblio = Koha::Biblios->find( $bibnum ); - my $itemcount = $biblio->items->count; - - # If there are no items left, - if ( $itemcount == 0 ) { - # We delete the record - my $delcheck = DelBiblio($bibnum); - - if($delcheck) { - $error->{'delbiblio'} = 1; - } - } - } - - return $error; -} - =head3 TransferOrder my $newordernumber = TransferOrder($ordernumber, $basketno); @@ -1895,8 +1842,11 @@ sub TransferOrder { 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; @@ -1915,7 +1865,7 @@ sub TransferOrder { 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 @@ -1935,6 +1885,41 @@ sub TransferOrder { return $newordernumber; } +=head3 get_rounding_sql + + $rounding_sql = get_rounding_sql($column_name); + +returns the correct SQL routine based on OrderPriceRounding system preference. + +=cut + +sub get_rounding_sql { + my ( $round_string ) = @_; + my $rounding_pref = C4::Context->preference('OrderPriceRounding') // q{}; + if ( $rounding_pref eq "nearest_cent" ) { + return "CAST($round_string*100 AS SIGNED)/100"; + } + return $round_string; +} + +=head3 get_rounded_price + + $rounded_price = get_rounded_price( $price ); + +returns a price rounded as specified in OrderPriceRounding system preference. + +=cut + +sub get_rounded_price { + my ( $price ) = @_; + my $rounding_pref = C4::Context->preference('OrderPriceRounding') // q{}; + if( $rounding_pref eq 'nearest_cent' ) { + return Koha::Number::Price->new( $price )->round(); + } + return $price; +} + + =head2 FUNCTIONS ABOUT PARCELS =head3 GetParcels @@ -2025,132 +2010,6 @@ sub GetParcels { #------------------------------------------------------------# -=head3 GetLateOrders - - @results = &GetLateOrders; - -Searches for bookseller with late orders. - -return: -the table of supplier with late issues. This table is full of hashref. - -=cut - -sub GetLateOrders { - my $delay = shift; - my $supplierid = shift; - my $branch = shift; - my $estimateddeliverydatefrom = shift; - my $estimateddeliverydateto = shift; - - my $dbh = C4::Context->dbh; - - #BEWARE, order of parenthesis and LEFT JOIN is important for speed - my $dbdriver = C4::Context->config("db_scheme") || "mysql"; - - my @query_params = (); - my $select = " - SELECT aqbasket.basketno, - aqorders.ordernumber, - DATE(aqbasket.closedate) AS orderdate, - aqbasket.basketname AS basketname, - aqbasket.basketgroupid AS basketgroupid, - aqbasketgroups.name AS basketgroupname, - aqorders.rrp AS unitpricesupplier, - aqorders.ecost AS unitpricelib, - aqorders.claims_count AS claims_count, - aqorders.claimed_date AS claimed_date, - aqbudgets.budget_name AS budget, - borrowers.branchcode AS branch, - aqbooksellers.name AS supplier, - aqbooksellers.id AS supplierid, - biblio.author, biblio.title, - biblioitems.publishercode AS publisher, - biblioitems.publicationyear, - ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) AS estimateddeliverydate, - "; - my $from = " - FROM - aqorders LEFT JOIN biblio ON biblio.biblionumber = aqorders.biblionumber - LEFT JOIN biblioitems ON biblioitems.biblionumber = biblio.biblionumber - LEFT JOIN aqbudgets ON aqorders.budget_id = aqbudgets.budget_id, - aqbasket LEFT JOIN borrowers ON aqbasket.authorisedby = borrowers.borrowernumber - LEFT JOIN aqbooksellers ON aqbasket.booksellerid = aqbooksellers.id - LEFT JOIN aqbasketgroups ON aqbasket.basketgroupid = aqbasketgroups.id - WHERE aqorders.basketno = aqbasket.basketno - AND ( datereceived = '' - OR datereceived IS NULL - OR aqorders.quantityreceived < aqorders.quantity - ) - AND aqbasket.closedate IS NOT NULL - AND (aqorders.datecancellationprinted IS NULL OR aqorders.datecancellationprinted='0000-00-00') - "; - my $having = ""; - if ($dbdriver eq "mysql") { - $select .= " - aqorders.quantity - COALESCE(aqorders.quantityreceived,0) AS quantity, - (aqorders.quantity - COALESCE(aqorders.quantityreceived,0)) * aqorders.rrp AS subtotal, - DATEDIFF(CAST(now() AS date),closedate) AS latesince - "; - if ( defined $delay ) { - $from .= " AND (closedate <= DATE_SUB(CAST(now() AS date),INTERVAL ? DAY)) " ; - push @query_params, $delay; - } - $having = "HAVING quantity <> 0"; - } else { - # FIXME: account for IFNULL as above - $select .= " - aqorders.quantity AS quantity, - aqorders.quantity * aqorders.rrp AS subtotal, - (CAST(now() AS date) - closedate) AS latesince - "; - if ( defined $delay ) { - $from .= " AND (closedate <= (CAST(now() AS date) -(INTERVAL ? DAY)) "; - push @query_params, $delay; - } - } - if (defined $supplierid) { - $from .= ' AND aqbasket.booksellerid = ? '; - push @query_params, $supplierid; - } - if (defined $branch) { - $from .= ' AND borrowers.branchcode LIKE ? '; - push @query_params, $branch; - } - - if ( defined $estimateddeliverydatefrom or defined $estimateddeliverydateto ) { - $from .= ' AND aqbooksellers.deliverytime IS NOT NULL '; - } - if ( defined $estimateddeliverydatefrom ) { - $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) >= ?'; - push @query_params, $estimateddeliverydatefrom; - } - if ( defined $estimateddeliverydateto ) { - $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) <= ?'; - push @query_params, $estimateddeliverydateto; - } - if ( defined $estimateddeliverydatefrom and not defined $estimateddeliverydateto ) { - $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) <= CAST(now() AS date)'; - } - if (C4::Context->preference("IndependentBranches") - && !C4::Context->IsSuperLibrarian() ) { - $from .= ' AND borrowers.branchcode LIKE ? '; - push @query_params, C4::Context->userenv->{branch}; - } - $from .= " AND orderstatus <> 'cancelled' "; - my $query = "$select $from $having\nORDER BY latesince, basketno, borrowers.branchcode, supplier"; - $debug and print STDERR "GetLateOrders query: $query\nGetLateOrders args: " . join(" ",@query_params); - my $sth = $dbh->prepare($query); - $sth->execute(@query_params); - my @results; - while (my $data = $sth->fetchrow_hashref) { - push @results, $data; - } - return @results; -} - -#------------------------------------------------------------# - =head3 GetHistory \@order_loop = GetHistory( %params ); @@ -2171,6 +2030,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) @@ -2191,7 +2052,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 @@ -2212,17 +2075,36 @@ 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; + #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 @@ -2234,7 +2116,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, @@ -2269,7 +2153,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 = (); @@ -2290,10 +2174,13 @@ sub GetHistory { 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"; @@ -2323,6 +2210,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 = ? "; @@ -2358,6 +2250,23 @@ 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); + + return [] unless @baskets; + + # No parameterization because record IDs come directly from DB + $query .= ' AND aqbasket.basketno IN ( ' . join( ',', map { $_->basketno } @baskets ) . ' )'; + } if ( C4::Context->preference("IndependentBranches") ) { unless ( C4::Context->IsSuperLibrarian() ) { @@ -2374,7 +2283,7 @@ sub GetHistory { $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 @@ -2453,7 +2362,8 @@ sub GetInvoices { 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, @@ -2539,11 +2449,11 @@ sub GetInvoices { } $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(grep /^$column$/, @columns) { + if(grep { $_ eq $column } @columns) { $direction ||= 'ASC'; $query .= " ORDER BY $column $direction"; } @@ -2667,7 +2577,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); } @@ -2717,7 +2627,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); } @@ -2857,7 +2767,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); @@ -2865,8 +2775,40 @@ sub GetBiblioCountByBasketno { return $sth->fetchrow; } -# Note this subroutine should be moved to Koha::Acquisition::Order -# Will do when a DBIC decision will be taken. +=head3 populate_order_with_prices + +$order = populate_order_with_prices({ + order => $order #a hashref with the order values + booksellerid => $booksellerid #FIXME - should obtain from order basket + receiving => 1 # boolean representing order stage, should pass only this or ordering + ordering => 1 # boolean representing order stage +}); + + +Sets calculated values for an order - all values are stored with full precision +regardless of rounding preference except for tax value which is calculated +on rounded values if requested + +For ordering the values set are: + rrp_tax_included + rrp_tax_excluded + ecost_tax_included + ecost_tax_excluded + tax_value_on_ordering +For receiving the value set are: + unitprice_tax_included + unitprice_tax_excluded + tax_value_on_receiving + +Note: When receiving, if the rounded value of the unitprice matches the rounded +value of the ecost then then ecost (full precision) is used. + +Returns a hashref of the order + +FIXME: Move this to Koha::Acquisition::Order.pm + +=cut + sub populate_order_with_prices { my ($params) = @_; @@ -2884,38 +2826,49 @@ sub populate_order_with_prices { if ($ordering) { $order->{tax_rate_on_ordering} //= $order->{tax_rate}; if ( $bookseller->listincgst ) { - # The user entered the rrp tax included + + # The user entered the prices tax included + $order->{unitprice} += 0; + $order->{unitprice_tax_included} = $order->{unitprice}; $order->{rrp_tax_included} = $order->{rrp}; - # rrp tax excluded = rrp tax included / ( 1 + tax rate ) + # price tax excluded = price tax included / ( 1 + tax rate ) + $order->{unitprice_tax_excluded} = $order->{unitprice_tax_included} / ( 1 + $order->{tax_rate_on_ordering} ); $order->{rrp_tax_excluded} = $order->{rrp_tax_included} / ( 1 + $order->{tax_rate_on_ordering} ); + # ecost tax included = rrp tax included ( 1 - discount ) + $order->{ecost_tax_included} = $order->{rrp_tax_included} * ( 1 - $discount ); + # ecost tax excluded = rrp tax excluded * ( 1 - discount ) $order->{ecost_tax_excluded} = $order->{rrp_tax_excluded} * ( 1 - $discount ); - # ecost tax included = rrp tax included ( 1 - discount ) - $order->{ecost_tax_included} = $order->{rrp_tax_included} * ( 1 - $discount ); + # tax value = quantity * ecost tax excluded * tax rate + # we should use the unitprice if included + my $cost_tax_included = $order->{unitprice_tax_included} || $order->{ecost_tax_included}; + my $cost_tax_excluded = $order->{unitprice_tax_excluded} || $order->{ecost_tax_excluded}; + $order->{tax_value_on_ordering} = ( get_rounded_price($cost_tax_included) - get_rounded_price($cost_tax_excluded) ) * $order->{quantity}; + } else { - # The user entered the rrp tax excluded + # The user entered the prices tax excluded + $order->{unitprice_tax_excluded} = $order->{unitprice}; $order->{rrp_tax_excluded} = $order->{rrp}; - # rrp tax included = rrp tax excluded * ( 1 - tax rate ) + # price tax included = price tax excluded * ( 1 - tax rate ) + $order->{unitprice_tax_included} = $order->{unitprice_tax_excluded} * ( 1 + $order->{tax_rate_on_ordering} ); $order->{rrp_tax_included} = $order->{rrp_tax_excluded} * ( 1 + $order->{tax_rate_on_ordering} ); # ecost tax excluded = rrp tax excluded * ( 1 - discount ) $order->{ecost_tax_excluded} = $order->{rrp_tax_excluded} * ( 1 - $discount ); - # ecost tax included = rrp tax excluded * ( 1 - tax rate ) * ( 1 - discount ) - $order->{ecost_tax_included} = - $order->{rrp_tax_excluded} * - ( 1 + $order->{tax_rate_on_ordering} ) * - ( 1 - $discount ); - } + # ecost tax included = rrp tax excluded * ( 1 + tax rate ) * ( 1 - discount ) = ecost tax excluded * ( 1 + tax rate ) + $order->{ecost_tax_included} = $order->{ecost_tax_excluded} * ( 1 + $order->{tax_rate_on_ordering} ); - # tax value = quantity * ecost tax excluded * tax rate - $order->{tax_value_on_ordering} = - $order->{quantity} * $order->{ecost_tax_excluded} * $order->{tax_rate_on_ordering}; + # tax value = quantity * ecost tax included * tax rate + # we should use the unitprice if included + my $cost_tax_excluded = $order->{unitprice_tax_excluded} || $order->{ecost_tax_excluded}; + $order->{tax_value_on_ordering} = $order->{quantity} * get_rounded_price($cost_tax_excluded) * $order->{tax_rate_on_ordering}; + } } if ($receiving) { @@ -2949,7 +2902,7 @@ sub populate_order_with_prices { } # tax value = quantity * unit price tax excluded * tax rate - $order->{tax_value_on_receiving} = $order->{quantity} * $order->{unitprice_tax_excluded} * $order->{tax_rate_on_receiving}; + $order->{tax_value_on_receiving} = $order->{quantity} * get_rounded_price($order->{unitprice_tax_excluded}) * $order->{tax_rate_on_receiving}; } return $order; @@ -3027,17 +2980,17 @@ sub NotifyOrderUsers { my $order = GetOrder( $ordernumber ); for my $borrowernumber (@borrowernumbers) { - my $borrower = C4::Members::GetMember( borrowernumber => $borrowernumber ); - my $library = Koha::Libraries->find( $borrower->{branchcode} )->unblessed; - 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', branchcode => $library->{branchcode}, - lang => $borrower->{lang}, + lang => $patron->lang, tables => { 'branches' => $library, - 'borrowers' => $borrower, + 'borrowers' => $patron->unblessed, 'biblio' => $biblio, 'aqorders' => $order, }, @@ -3057,42 +3010,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 + ) + ); + } } } }