Bug 12059: Prefer to list fields in the query
[koha.git] / C4 / Acquisition.pm
blobd66f1568535d63a8e4ad7594808ab4634a442e97
1 package C4::Acquisition;
3 # Copyright 2000-2002 Katipo Communications
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later
10 # version.
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License along
17 # with Koha; if not, write to the Free Software Foundation, Inc.,
18 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 use Modern::Perl;
22 use Carp;
23 use C4::Context;
24 use C4::Debug;
25 use C4::Dates qw(format_date format_date_in_iso);
26 use MARC::Record;
27 use C4::Suggestions;
28 use C4::Biblio;
29 use C4::Contract;
30 use C4::Debug;
31 use C4::Bookseller qw(GetBookSellerFromId);
32 use C4::Templates qw(gettemplate);
33 use Koha::DateUtils qw( dt_from_string output_pref );
34 use Koha::Acquisition::Order;
36 use Time::localtime;
37 use HTML::Entities;
39 use vars qw($VERSION @ISA @EXPORT);
41 BEGIN {
42 # set the version for version checking
43 $VERSION = 3.07.00.049;
44 require Exporter;
45 @ISA = qw(Exporter);
46 @EXPORT = qw(
47 &GetBasket &NewBasket &CloseBasket &ReopenBasket &DelBasket &ModBasket
48 &GetBasketAsCSV &GetBasketGroupAsCSV
49 &GetBasketsByBookseller &GetBasketsByBasketgroup
50 &GetBasketsInfosByBookseller
52 &GetBasketUsers &ModBasketUsers
53 &CanUserManageBasket
55 &ModBasketHeader
57 &ModBasketgroup &NewBasketgroup &DelBasketgroup &GetBasketgroup &CloseBasketgroup
58 &GetBasketgroups &ReOpenBasketgroup
60 &DelOrder &ModOrder &GetOrder &GetOrders &GetOrdersByBiblionumber
61 &GetLateOrders &GetOrderFromItemnumber
62 &SearchOrders &GetHistory &GetRecentAcqui
63 &ModReceiveOrder &CancelReceipt
64 &GetCancelledOrders &TransferOrder
65 &GetLastOrderNotReceivedFromSubscriptionid &GetLastOrderReceivedFromSubscriptionid
66 &ModItemOrder
68 &GetParcels &GetParcel
70 &GetInvoices
71 &GetInvoice
72 &GetInvoiceDetails
73 &AddInvoice
74 &ModInvoice
75 &CloseInvoice
76 &ReopenInvoice
77 &DelInvoice
78 &MergeInvoices
80 &GetItemnumbersFromOrder
82 &AddClaim
83 &GetBiblioCountByBasketno
91 sub GetOrderFromItemnumber {
92 my ($itemnumber) = @_;
93 my $dbh = C4::Context->dbh;
94 my $query = qq|
96 SELECT * from aqorders LEFT JOIN aqorders_items
97 ON ( aqorders.ordernumber = aqorders_items.ordernumber )
98 WHERE itemnumber = ? |;
100 my $sth = $dbh->prepare($query);
102 # $sth->trace(3);
104 $sth->execute($itemnumber);
106 my $order = $sth->fetchrow_hashref;
107 return ( $order );
111 # Returns the itemnumber(s) associated with the ordernumber given in parameter
112 sub GetItemnumbersFromOrder {
113 my ($ordernumber) = @_;
114 my $dbh = C4::Context->dbh;
115 my $query = "SELECT itemnumber FROM aqorders_items WHERE ordernumber=?";
116 my $sth = $dbh->prepare($query);
117 $sth->execute($ordernumber);
118 my @tab;
120 while (my $order = $sth->fetchrow_hashref) {
121 push @tab, $order->{'itemnumber'};
124 return @tab;
133 =head1 NAME
135 C4::Acquisition - Koha functions for dealing with orders and acquisitions
137 =head1 SYNOPSIS
139 use C4::Acquisition;
141 =head1 DESCRIPTION
143 The functions in this module deal with acquisitions, managing book
144 orders, basket and parcels.
146 =head1 FUNCTIONS
148 =head2 FUNCTIONS ABOUT BASKETS
150 =head3 GetBasket
152 $aqbasket = &GetBasket($basketnumber);
154 get all basket informations in aqbasket for a given basket
156 B<returns:> informations for a given basket returned as a hashref.
158 =cut
160 sub GetBasket {
161 my ($basketno) = @_;
162 my $dbh = C4::Context->dbh;
163 my $query = "
164 SELECT aqbasket.*,
165 concat( b.firstname,' ',b.surname) AS authorisedbyname
166 FROM aqbasket
167 LEFT JOIN borrowers b ON aqbasket.authorisedby=b.borrowernumber
168 WHERE basketno=?
170 my $sth=$dbh->prepare($query);
171 $sth->execute($basketno);
172 my $basket = $sth->fetchrow_hashref;
173 return ( $basket );
176 #------------------------------------------------------------#
178 =head3 NewBasket
180 $basket = &NewBasket( $booksellerid, $authorizedby, $basketname,
181 $basketnote, $basketbooksellernote, $basketcontractnumber, $deliveryplace, $billingplace );
183 Create a new basket in aqbasket table
185 =over
187 =item C<$booksellerid> is a foreign key in the aqbasket table
189 =item C<$authorizedby> is the username of who created the basket
191 =back
193 The other parameters are optional, see ModBasketHeader for more info on them.
195 =cut
197 sub NewBasket {
198 my ( $booksellerid, $authorisedby, $basketname, $basketnote,
199 $basketbooksellernote, $basketcontractnumber, $deliveryplace,
200 $billingplace ) = @_;
201 my $dbh = C4::Context->dbh;
202 my $query =
203 'INSERT INTO aqbasket (creationdate,booksellerid,authorisedby) '
204 . 'VALUES (now(),?,?)';
205 $dbh->do( $query, {}, $booksellerid, $authorisedby );
207 my $basket = $dbh->{mysql_insertid};
208 $basketname ||= q{}; # default to empty strings
209 $basketnote ||= q{};
210 $basketbooksellernote ||= q{};
211 ModBasketHeader( $basket, $basketname, $basketnote, $basketbooksellernote,
212 $basketcontractnumber, $booksellerid, $deliveryplace, $billingplace );
213 return $basket;
216 #------------------------------------------------------------#
218 =head3 CloseBasket
220 &CloseBasket($basketno);
222 close a basket (becomes unmodifiable, except for receives)
224 =cut
226 sub CloseBasket {
227 my ($basketno) = @_;
228 my $dbh = C4::Context->dbh;
229 my $query = "
230 UPDATE aqbasket
231 SET closedate=now()
232 WHERE basketno=?
234 my $sth = $dbh->prepare($query);
235 $sth->execute($basketno);
237 my @orders = GetOrders($basketno);
238 foreach my $order (@orders) {
239 $query = qq{
240 UPDATE aqorders
241 SET orderstatus = 'ordered'
242 WHERE ordernumber = ?;
244 $sth = $dbh->prepare($query);
245 $sth->execute($order->{'ordernumber'});
249 =head3 ReopenBasket
251 &ReopenBasket($basketno);
253 reopen a basket
255 =cut
257 sub ReopenBasket {
258 my ($basketno) = @_;
259 my $dbh = C4::Context->dbh;
260 my $query = "
261 UPDATE aqbasket
262 SET closedate=NULL
263 WHERE basketno=?
265 my $sth = $dbh->prepare($query);
266 $sth->execute($basketno);
268 my @orders = GetOrders($basketno);
269 foreach my $order (@orders) {
270 $query = qq{
271 UPDATE aqorders
272 SET orderstatus = 'new'
273 WHERE ordernumber = ?;
275 $sth = $dbh->prepare($query);
276 $sth->execute($order->{'ordernumber'});
280 #------------------------------------------------------------#
282 =head3 GetBasketAsCSV
284 &GetBasketAsCSV($basketno);
286 Export a basket as CSV
288 $cgi parameter is needed for column name translation
290 =cut
292 sub GetBasketAsCSV {
293 my ($basketno, $cgi) = @_;
294 my $basket = GetBasket($basketno);
295 my @orders = GetOrders($basketno);
296 my $contract = GetContract({
297 contractnumber => $basket->{'contractnumber'}
300 my $template = C4::Templates::gettemplate("acqui/csv/basket.tt", "intranet", $cgi);
302 my @rows;
303 foreach my $order (@orders) {
304 my $bd = GetBiblioData( $order->{'biblionumber'} );
305 my $row = {
306 contractname => $contract->{'contractname'},
307 ordernumber => $order->{'ordernumber'},
308 entrydate => $order->{'entrydate'},
309 isbn => $order->{'isbn'},
310 author => $bd->{'author'},
311 title => $bd->{'title'},
312 publicationyear => $bd->{'publicationyear'},
313 publishercode => $bd->{'publishercode'},
314 collectiontitle => $bd->{'collectiontitle'},
315 notes => $order->{'order_vendornote'},
316 quantity => $order->{'quantity'},
317 rrp => $order->{'rrp'},
318 deliveryplace => C4::Branch::GetBranchName( $basket->{'deliveryplace'} ),
319 billingplace => C4::Branch::GetBranchName( $basket->{'billingplace'} ),
321 foreach(qw(
322 contractname author title publishercode collectiontitle notes
323 deliveryplace billingplace
324 ) ) {
325 # Double the quotes to not be interpreted as a field end
326 $row->{$_} =~ s/"/""/g if $row->{$_};
328 push @rows, $row;
331 @rows = sort {
332 if(defined $a->{publishercode} and defined $b->{publishercode}) {
333 $a->{publishercode} cmp $b->{publishercode};
335 } @rows;
337 $template->param(rows => \@rows);
339 return $template->output;
343 =head3 GetBasketGroupAsCSV
345 =over
347 &GetBasketGroupAsCSV($basketgroupid);
349 Export a basket group as CSV
351 $cgi parameter is needed for column name translation
353 =back
355 =cut
357 sub GetBasketGroupAsCSV {
358 my ($basketgroupid, $cgi) = @_;
359 my $baskets = GetBasketsByBasketgroup($basketgroupid);
361 my $template = C4::Templates::gettemplate('acqui/csv/basketgroup.tt', 'intranet', $cgi);
363 my @rows;
364 for my $basket (@$baskets) {
365 my @orders = GetOrders( $basket->{basketno} );
366 my $contract = GetContract({
367 contractnumber => $basket->{contractnumber}
369 my $bookseller = GetBookSellerFromId( $$basket{booksellerid} );
370 my $basketgroup = GetBasketgroup( $$basket{basketgroupid} );
372 foreach my $order (@orders) {
373 my $bd = GetBiblioData( $order->{'biblionumber'} );
374 my $row = {
375 clientnumber => $bookseller->{accountnumber},
376 basketname => $basket->{basketname},
377 ordernumber => $order->{ordernumber},
378 author => $bd->{author},
379 title => $bd->{title},
380 publishercode => $bd->{publishercode},
381 publicationyear => $bd->{publicationyear},
382 collectiontitle => $bd->{collectiontitle},
383 isbn => $order->{isbn},
384 quantity => $order->{quantity},
385 rrp => $order->{rrp},
386 discount => $bookseller->{discount},
387 ecost => $order->{ecost},
388 notes => $order->{order_vendornote},
389 entrydate => $order->{entrydate},
390 booksellername => $bookseller->{name},
391 bookselleraddress => $bookseller->{address1},
392 booksellerpostal => $bookseller->{postal},
393 contractnumber => $contract->{contractnumber},
394 contractname => $contract->{contractname},
395 basketgroupdeliveryplace => C4::Branch::GetBranchName( $basketgroup->{deliveryplace} ),
396 basketgroupbillingplace => C4::Branch::GetBranchName( $basketgroup->{billingplace} ),
397 basketdeliveryplace => C4::Branch::GetBranchName( $basket->{deliveryplace} ),
398 basketbillingplace => C4::Branch::GetBranchName( $basket->{billingplace} ),
400 foreach(qw(
401 basketname author title publishercode collectiontitle notes
402 booksellername bookselleraddress booksellerpostal contractname
403 basketgroupdeliveryplace basketgroupbillingplace
404 basketdeliveryplace basketbillingplace
405 ) ) {
406 # Double the quotes to not be interpreted as a field end
407 $row->{$_} =~ s/"/""/g if $row->{$_};
409 push @rows, $row;
412 $template->param(rows => \@rows);
414 return $template->output;
418 =head3 CloseBasketgroup
420 &CloseBasketgroup($basketgroupno);
422 close a basketgroup
424 =cut
426 sub CloseBasketgroup {
427 my ($basketgroupno) = @_;
428 my $dbh = C4::Context->dbh;
429 my $sth = $dbh->prepare("
430 UPDATE aqbasketgroups
431 SET closed=1
432 WHERE id=?
434 $sth->execute($basketgroupno);
437 #------------------------------------------------------------#
439 =head3 ReOpenBaskergroup($basketgroupno)
441 &ReOpenBaskergroup($basketgroupno);
443 reopen a basketgroup
445 =cut
447 sub ReOpenBasketgroup {
448 my ($basketgroupno) = @_;
449 my $dbh = C4::Context->dbh;
450 my $sth = $dbh->prepare("
451 UPDATE aqbasketgroups
452 SET closed=0
453 WHERE id=?
455 $sth->execute($basketgroupno);
458 #------------------------------------------------------------#
461 =head3 DelBasket
463 &DelBasket($basketno);
465 Deletes the basket that has basketno field $basketno in the aqbasket table.
467 =over
469 =item C<$basketno> is the primary key of the basket in the aqbasket table.
471 =back
473 =cut
475 sub DelBasket {
476 my ( $basketno ) = @_;
477 my $query = "DELETE FROM aqbasket WHERE basketno=?";
478 my $dbh = C4::Context->dbh;
479 my $sth = $dbh->prepare($query);
480 $sth->execute($basketno);
481 return;
484 #------------------------------------------------------------#
486 =head3 ModBasket
488 &ModBasket($basketinfo);
490 Modifies a basket, using a hashref $basketinfo for the relevant information, only $basketinfo->{'basketno'} is required.
492 =over
494 =item C<$basketno> is the primary key of the basket in the aqbasket table.
496 =back
498 =cut
500 sub ModBasket {
501 my $basketinfo = shift;
502 my $query = "UPDATE aqbasket SET ";
503 my @params;
504 foreach my $key (keys %$basketinfo){
505 if ($key ne 'basketno'){
506 $query .= "$key=?, ";
507 push(@params, $basketinfo->{$key} || undef );
510 # get rid of the "," at the end of $query
511 if (substr($query, length($query)-2) eq ', '){
512 chop($query);
513 chop($query);
514 $query .= ' ';
516 $query .= "WHERE basketno=?";
517 push(@params, $basketinfo->{'basketno'});
518 my $dbh = C4::Context->dbh;
519 my $sth = $dbh->prepare($query);
520 $sth->execute(@params);
522 return;
525 #------------------------------------------------------------#
527 =head3 ModBasketHeader
529 &ModBasketHeader($basketno, $basketname, $note, $booksellernote, $contractnumber, $booksellerid);
531 Modifies a basket's header.
533 =over
535 =item C<$basketno> is the "basketno" field in the "aqbasket" table;
537 =item C<$basketname> is the "basketname" field in the "aqbasket" table;
539 =item C<$note> is the "note" field in the "aqbasket" table;
541 =item C<$booksellernote> is the "booksellernote" field in the "aqbasket" table;
543 =item C<$contractnumber> is the "contractnumber" (foreign) key in the "aqbasket" table.
545 =item C<$booksellerid> is the id (foreign) key in the "aqbooksellers" table for the vendor.
547 =item C<$deliveryplace> is the "deliveryplace" field in the aqbasket table.
549 =item C<$billingplace> is the "billingplace" field in the aqbasket table.
551 =back
553 =cut
555 sub ModBasketHeader {
556 my ($basketno, $basketname, $note, $booksellernote, $contractnumber, $booksellerid, $deliveryplace, $billingplace) = @_;
557 my $query = qq{
558 UPDATE aqbasket
559 SET basketname=?, note=?, booksellernote=?, booksellerid=?, deliveryplace=?, billingplace=?
560 WHERE basketno=?
563 my $dbh = C4::Context->dbh;
564 my $sth = $dbh->prepare($query);
565 $sth->execute($basketname, $note, $booksellernote, $booksellerid, $deliveryplace, $billingplace, $basketno);
567 if ( $contractnumber ) {
568 my $query2 ="UPDATE aqbasket SET contractnumber=? WHERE basketno=?";
569 my $sth2 = $dbh->prepare($query2);
570 $sth2->execute($contractnumber,$basketno);
572 return;
575 #------------------------------------------------------------#
577 =head3 GetBasketsByBookseller
579 @results = &GetBasketsByBookseller($booksellerid, $extra);
581 Returns a list of hashes of all the baskets that belong to bookseller 'booksellerid'.
583 =over
585 =item C<$booksellerid> is the 'id' field of the bookseller in the aqbooksellers table
587 =item C<$extra> is the extra sql parameters, can be
589 $extra->{groupby}: group baskets by column
590 ex. $extra->{groupby} = aqbasket.basketgroupid
591 $extra->{orderby}: order baskets by column
592 $extra->{limit}: limit number of results (can be helpful for pagination)
594 =back
596 =cut
598 sub GetBasketsByBookseller {
599 my ($booksellerid, $extra) = @_;
600 my $query = "SELECT * FROM aqbasket WHERE booksellerid=?";
601 if ($extra){
602 if ($extra->{groupby}) {
603 $query .= " GROUP by $extra->{groupby}";
605 if ($extra->{orderby}){
606 $query .= " ORDER by $extra->{orderby}";
608 if ($extra->{limit}){
609 $query .= " LIMIT $extra->{limit}";
612 my $dbh = C4::Context->dbh;
613 my $sth = $dbh->prepare($query);
614 $sth->execute($booksellerid);
615 return $sth->fetchall_arrayref({});
618 =head3 GetBasketsInfosByBookseller
620 my $baskets = GetBasketsInfosByBookseller($supplierid, $allbaskets);
622 The optional second parameter allbaskets is a boolean allowing you to
623 select all baskets from the supplier; by default only active baskets (open or
624 closed but still something to receive) are returned.
626 Returns in a arrayref of hashref all about booksellers baskets, plus:
627 total_biblios: Number of distinct biblios in basket
628 total_items: Number of items in basket
629 expected_items: Number of non-received items in basket
631 =cut
633 sub GetBasketsInfosByBookseller {
634 my ($supplierid, $allbaskets) = @_;
636 return unless $supplierid;
638 my $dbh = C4::Context->dbh;
639 my $query = q{
640 SELECT aqbasket.*,
641 SUM(aqorders.quantity) AS total_items,
642 SUM(
643 IF ( aqorders.orderstatus = 'cancelled', aqorders.quantity, 0 )
644 ) AS total_items_cancelled,
645 COUNT(DISTINCT aqorders.biblionumber) AS total_biblios,
646 SUM(
647 IF(aqorders.datereceived IS NULL
648 AND aqorders.datecancellationprinted IS NULL
649 , aqorders.quantity
650 , 0)
651 ) AS expected_items
652 FROM aqbasket
653 LEFT JOIN aqorders ON aqorders.basketno = aqbasket.basketno
654 WHERE booksellerid = ?};
656 unless ( $allbaskets ) {
657 $query.=" AND (closedate IS NULL OR (aqorders.quantity > aqorders.quantityreceived AND datecancellationprinted IS NULL))";
659 $query.=" GROUP BY aqbasket.basketno";
661 my $sth = $dbh->prepare($query);
662 $sth->execute($supplierid);
663 my $baskets = $sth->fetchall_arrayref({});
665 # Retrieve the number of biblios cancelled
666 my $cancelled_biblios = $dbh->selectall_hashref( q|
667 SELECT COUNT(DISTINCT(biblionumber)) AS total_biblios_cancelled, aqbasket.basketno
668 FROM aqbasket
669 LEFT JOIN aqorders ON aqorders.basketno = aqbasket.basketno
670 WHERE booksellerid = ?
671 AND aqorders.orderstatus = 'cancelled'
672 GROUP BY aqbasket.basketno
673 |, 'basketno', {}, $supplierid );
674 map {
675 $_->{total_biblios_cancelled} = $cancelled_biblios->{$_->{basketno}}{total_biblios_cancelled} || 0
676 } @$baskets;
678 return $baskets;
681 =head3 GetBasketUsers
683 $basketusers_ids = &GetBasketUsers($basketno);
685 Returns a list of all borrowernumbers that are in basket users list
687 =cut
689 sub GetBasketUsers {
690 my $basketno = shift;
692 return unless $basketno;
694 my $query = qq{
695 SELECT borrowernumber
696 FROM aqbasketusers
697 WHERE basketno = ?
699 my $dbh = C4::Context->dbh;
700 my $sth = $dbh->prepare($query);
701 $sth->execute($basketno);
702 my $results = $sth->fetchall_arrayref( {} );
704 my @borrowernumbers;
705 foreach (@$results) {
706 push @borrowernumbers, $_->{'borrowernumber'};
709 return @borrowernumbers;
712 =head3 ModBasketUsers
714 my @basketusers_ids = (1, 2, 3);
715 &ModBasketUsers($basketno, @basketusers_ids);
717 Delete all users from basket users list, and add users in C<@basketusers_ids>
718 to this users list.
720 =cut
722 sub ModBasketUsers {
723 my ($basketno, @basketusers_ids) = @_;
725 return unless $basketno;
727 my $dbh = C4::Context->dbh;
728 my $query = qq{
729 DELETE FROM aqbasketusers
730 WHERE basketno = ?
732 my $sth = $dbh->prepare($query);
733 $sth->execute($basketno);
735 $query = qq{
736 INSERT INTO aqbasketusers (basketno, borrowernumber)
737 VALUES (?, ?)
739 $sth = $dbh->prepare($query);
740 foreach my $basketuser_id (@basketusers_ids) {
741 $sth->execute($basketno, $basketuser_id);
743 return;
746 =head3 CanUserManageBasket
748 my $bool = CanUserManageBasket($borrower, $basket[, $userflags]);
749 my $bool = CanUserManageBasket($borrowernumber, $basketno[, $userflags]);
751 Check if a borrower can manage a basket, according to system preference
752 AcqViewBaskets, user permissions and basket properties (creator, users list,
753 branch).
755 First parameter can be either a borrowernumber or a hashref as returned by
756 C4::Members::GetMember.
758 Second parameter can be either a basketno or a hashref as returned by
759 C4::Acquisition::GetBasket.
761 The third parameter is optional. If given, it should be a hashref as returned
762 by C4::Auth::getuserflags. If not, getuserflags is called.
764 If user is authorised to manage basket, returns 1.
765 Otherwise returns 0.
767 =cut
769 sub CanUserManageBasket {
770 my ($borrower, $basket, $userflags) = @_;
772 if (!ref $borrower) {
773 $borrower = C4::Members::GetMember(borrowernumber => $borrower);
775 if (!ref $basket) {
776 $basket = GetBasket($basket);
779 return 0 unless ($basket and $borrower);
781 my $borrowernumber = $borrower->{borrowernumber};
782 my $basketno = $basket->{basketno};
784 my $AcqViewBaskets = C4::Context->preference('AcqViewBaskets');
786 if (!defined $userflags) {
787 my $dbh = C4::Context->dbh;
788 my $sth = $dbh->prepare("SELECT flags FROM borrowers WHERE borrowernumber = ?");
789 $sth->execute($borrowernumber);
790 my ($flags) = $sth->fetchrow_array;
791 $sth->finish;
793 $userflags = C4::Auth::getuserflags($flags, $borrower->{userid}, $dbh);
796 unless ($userflags->{superlibrarian}
797 || (ref $userflags->{acquisition} && $userflags->{acquisition}->{order_manage_all})
798 || (!ref $userflags->{acquisition} && $userflags->{acquisition}))
800 if (not exists $userflags->{acquisition}) {
801 return 0;
804 if ( (ref $userflags->{acquisition} && !$userflags->{acquisition}->{order_manage})
805 || (!ref $userflags->{acquisition} && !$userflags->{acquisition}) ) {
806 return 0;
809 if ($AcqViewBaskets eq 'user'
810 && $basket->{authorisedby} != $borrowernumber
811 && grep($borrowernumber, GetBasketUsers($basketno)) == 0) {
812 return 0;
815 if ($AcqViewBaskets eq 'branch' && defined $basket->{branch}
816 && $basket->{branch} ne $borrower->{branchcode}) {
817 return 0;
821 return 1;
824 #------------------------------------------------------------#
826 =head3 GetBasketsByBasketgroup
828 $baskets = &GetBasketsByBasketgroup($basketgroupid);
830 Returns a reference to all baskets that belong to basketgroup $basketgroupid.
832 =cut
834 sub GetBasketsByBasketgroup {
835 my $basketgroupid = shift;
836 my $query = qq{
837 SELECT *, aqbasket.booksellerid as booksellerid
838 FROM aqbasket
839 LEFT JOIN aqcontract USING(contractnumber) WHERE basketgroupid=?
841 my $dbh = C4::Context->dbh;
842 my $sth = $dbh->prepare($query);
843 $sth->execute($basketgroupid);
844 return $sth->fetchall_arrayref({});
847 #------------------------------------------------------------#
849 =head3 NewBasketgroup
851 $basketgroupid = NewBasketgroup(\%hashref);
853 Adds a basketgroup to the aqbasketgroups table, and add the initial baskets to it.
855 $hashref->{'booksellerid'} is the 'id' field of the bookseller in the aqbooksellers table,
857 $hashref->{'name'} is the 'name' field of the basketgroup in the aqbasketgroups table,
859 $hashref->{'basketlist'} is a list reference of the 'id's of the baskets that belong to this group,
861 $hashref->{'billingplace'} is the 'billingplace' field of the basketgroup in the aqbasketgroups table,
863 $hashref->{'deliveryplace'} is the 'deliveryplace' field of the basketgroup in the aqbasketgroups table,
865 $hashref->{'freedeliveryplace'} is the 'freedeliveryplace' field of the basketgroup in the aqbasketgroups table,
867 $hashref->{'deliverycomment'} is the 'deliverycomment' field of the basketgroup in the aqbasketgroups table,
869 $hashref->{'closed'} is the 'closed' field of the aqbasketgroups table, it is false if 0, true otherwise.
871 =cut
873 sub NewBasketgroup {
874 my $basketgroupinfo = shift;
875 die "booksellerid is required to create a basketgroup" unless $basketgroupinfo->{'booksellerid'};
876 my $query = "INSERT INTO aqbasketgroups (";
877 my @params;
878 foreach my $field (qw(name billingplace deliveryplace freedeliveryplace deliverycomment closed)) {
879 if ( defined $basketgroupinfo->{$field} ) {
880 $query .= "$field, ";
881 push(@params, $basketgroupinfo->{$field});
884 $query .= "booksellerid) VALUES (";
885 foreach (@params) {
886 $query .= "?, ";
888 $query .= "?)";
889 push(@params, $basketgroupinfo->{'booksellerid'});
890 my $dbh = C4::Context->dbh;
891 my $sth = $dbh->prepare($query);
892 $sth->execute(@params);
893 my $basketgroupid = $dbh->{'mysql_insertid'};
894 if( $basketgroupinfo->{'basketlist'} ) {
895 foreach my $basketno (@{$basketgroupinfo->{'basketlist'}}) {
896 my $query2 = "UPDATE aqbasket SET basketgroupid=? WHERE basketno=?";
897 my $sth2 = $dbh->prepare($query2);
898 $sth2->execute($basketgroupid, $basketno);
901 return $basketgroupid;
904 #------------------------------------------------------------#
906 =head3 ModBasketgroup
908 ModBasketgroup(\%hashref);
910 Modifies a basketgroup in the aqbasketgroups table, and add the baskets to it.
912 $hashref->{'id'} is the 'id' field of the basketgroup in the aqbasketgroup table, this parameter is mandatory,
914 $hashref->{'name'} is the 'name' field of the basketgroup in the aqbasketgroups table,
916 $hashref->{'basketlist'} is a list reference of the 'id's of the baskets that belong to this group,
918 $hashref->{'billingplace'} is the 'billingplace' field of the basketgroup in the aqbasketgroups table,
920 $hashref->{'deliveryplace'} is the 'deliveryplace' field of the basketgroup in the aqbasketgroups table,
922 $hashref->{'freedeliveryplace'} is the 'freedeliveryplace' field of the basketgroup in the aqbasketgroups table,
924 $hashref->{'deliverycomment'} is the 'deliverycomment' field of the basketgroup in the aqbasketgroups table,
926 $hashref->{'closed'} is the 'closed' field of the aqbasketgroups table, it is false if 0, true otherwise.
928 =cut
930 sub ModBasketgroup {
931 my $basketgroupinfo = shift;
932 die "basketgroup id is required to edit a basketgroup" unless $basketgroupinfo->{'id'};
933 my $dbh = C4::Context->dbh;
934 my $query = "UPDATE aqbasketgroups SET ";
935 my @params;
936 foreach my $field (qw(name billingplace deliveryplace freedeliveryplace deliverycomment closed)) {
937 if ( defined $basketgroupinfo->{$field} ) {
938 $query .= "$field=?, ";
939 push(@params, $basketgroupinfo->{$field});
942 chop($query);
943 chop($query);
944 $query .= " WHERE id=?";
945 push(@params, $basketgroupinfo->{'id'});
946 my $sth = $dbh->prepare($query);
947 $sth->execute(@params);
949 $sth = $dbh->prepare('UPDATE aqbasket SET basketgroupid = NULL WHERE basketgroupid = ?');
950 $sth->execute($basketgroupinfo->{'id'});
952 if($basketgroupinfo->{'basketlist'} && @{$basketgroupinfo->{'basketlist'}}){
953 $sth = $dbh->prepare("UPDATE aqbasket SET basketgroupid=? WHERE basketno=?");
954 foreach my $basketno (@{$basketgroupinfo->{'basketlist'}}) {
955 $sth->execute($basketgroupinfo->{'id'}, $basketno);
958 return;
961 #------------------------------------------------------------#
963 =head3 DelBasketgroup
965 DelBasketgroup($basketgroupid);
967 Deletes a basketgroup in the aqbasketgroups table, and removes the reference to it from the baskets,
969 =over
971 =item C<$basketgroupid> is the 'id' field of the basket in the aqbasketgroup table
973 =back
975 =cut
977 sub DelBasketgroup {
978 my $basketgroupid = shift;
979 die "basketgroup id is required to edit a basketgroup" unless $basketgroupid;
980 my $query = "DELETE FROM aqbasketgroups WHERE id=?";
981 my $dbh = C4::Context->dbh;
982 my $sth = $dbh->prepare($query);
983 $sth->execute($basketgroupid);
984 return;
987 #------------------------------------------------------------#
990 =head2 FUNCTIONS ABOUT ORDERS
992 =head3 GetBasketgroup
994 $basketgroup = &GetBasketgroup($basketgroupid);
996 Returns a reference to the hash containing all information about the basketgroup.
998 =cut
1000 sub GetBasketgroup {
1001 my $basketgroupid = shift;
1002 die "basketgroup id is required to edit a basketgroup" unless $basketgroupid;
1003 my $dbh = C4::Context->dbh;
1004 my $result_set = $dbh->selectall_arrayref(
1005 'SELECT * FROM aqbasketgroups WHERE id=?',
1006 { Slice => {} },
1007 $basketgroupid
1009 return $result_set->[0]; # id is unique
1012 #------------------------------------------------------------#
1014 =head3 GetBasketgroups
1016 $basketgroups = &GetBasketgroups($booksellerid);
1018 Returns a reference to the array of all the basketgroups of bookseller $booksellerid.
1020 =cut
1022 sub GetBasketgroups {
1023 my $booksellerid = shift;
1024 die 'bookseller id is required to edit a basketgroup' unless $booksellerid;
1025 my $query = 'SELECT * FROM aqbasketgroups WHERE booksellerid=? ORDER BY id DESC';
1026 my $dbh = C4::Context->dbh;
1027 my $sth = $dbh->prepare($query);
1028 $sth->execute($booksellerid);
1029 return $sth->fetchall_arrayref({});
1032 #------------------------------------------------------------#
1034 =head2 FUNCTIONS ABOUT ORDERS
1036 =head3 GetOrders
1038 @orders = &GetOrders($basketnumber, $orderby);
1040 Looks up the pending (non-cancelled) orders with the given basket
1041 number. If C<$booksellerID> is non-empty, only orders from that seller
1042 are returned.
1044 return :
1045 C<&basket> returns a two-element array. C<@orders> is an array of
1046 references-to-hash, whose keys are the fields from the aqorders,
1047 biblio, and biblioitems tables in the Koha database.
1049 =cut
1051 sub GetOrders {
1052 my ( $basketno, $orderby ) = @_;
1053 return () unless $basketno;
1054 my $dbh = C4::Context->dbh;
1055 my $query ="
1056 SELECT biblio.*,biblioitems.*,
1057 aqorders.*,
1058 aqbudgets.*,
1059 aqorders_transfers.ordernumber_from AS transferred_from,
1060 aqorders_transfers.timestamp AS transferred_from_timestamp
1061 FROM aqorders
1062 LEFT JOIN aqbudgets ON aqbudgets.budget_id = aqorders.budget_id
1063 LEFT JOIN biblio ON biblio.biblionumber = aqorders.biblionumber
1064 LEFT JOIN biblioitems ON biblioitems.biblionumber =biblio.biblionumber
1065 LEFT JOIN aqorders_transfers ON aqorders_transfers.ordernumber_to = aqorders.ordernumber
1066 WHERE basketno=?
1067 AND (datecancellationprinted IS NULL OR datecancellationprinted='0000-00-00')
1070 $orderby = "biblioitems.publishercode,biblio.title" unless $orderby;
1071 $query .= " ORDER BY $orderby";
1072 my $result_set =
1073 $dbh->selectall_arrayref( $query, { Slice => {} }, $basketno );
1074 return @{$result_set};
1078 #------------------------------------------------------------#
1079 =head3 GetOrdersByBiblionumber
1081 @orders = &GetOrdersByBiblionumber($biblionumber);
1083 Looks up the orders with linked to a specific $biblionumber, including
1084 cancelled orders and received orders.
1086 return :
1087 C<@orders> is an array of references-to-hash, whose keys are the
1088 fields from the aqorders, biblio, and biblioitems tables in the Koha database.
1090 =cut
1092 sub GetOrdersByBiblionumber {
1093 my $biblionumber = shift;
1094 return unless $biblionumber;
1095 my $dbh = C4::Context->dbh;
1096 my $query ="
1097 SELECT biblio.*,biblioitems.*,
1098 aqorders.*,
1099 aqbudgets.*
1100 FROM aqorders
1101 LEFT JOIN aqbudgets ON aqbudgets.budget_id = aqorders.budget_id
1102 LEFT JOIN biblio ON biblio.biblionumber = aqorders.biblionumber
1103 LEFT JOIN biblioitems ON biblioitems.biblionumber =biblio.biblionumber
1104 WHERE aqorders.biblionumber=?
1106 my $result_set =
1107 $dbh->selectall_arrayref( $query, { Slice => {} }, $biblionumber );
1108 return @{$result_set};
1112 #------------------------------------------------------------#
1114 =head3 GetOrder
1116 $order = &GetOrder($ordernumber);
1118 Looks up an order by order number.
1120 Returns a reference-to-hash describing the order. The keys of
1121 C<$order> are fields from the biblio, biblioitems, aqorders tables of the Koha database.
1123 =cut
1125 sub GetOrder {
1126 my ($ordernumber) = @_;
1127 return unless $ordernumber;
1129 my $dbh = C4::Context->dbh;
1130 my $query = qq{SELECT
1131 aqorders.*,
1132 biblio.title,
1133 biblio.author,
1134 aqbasket.basketname,
1135 borrowers.branchcode,
1136 biblioitems.publicationyear,
1137 biblio.copyrightdate,
1138 biblioitems.editionstatement,
1139 biblioitems.isbn,
1140 biblioitems.ean,
1141 biblio.seriestitle,
1142 biblioitems.publishercode,
1143 aqorders.rrp AS unitpricesupplier,
1144 aqorders.ecost AS unitpricelib,
1145 aqorders.claims_count AS claims_count,
1146 aqorders.claimed_date AS claimed_date,
1147 aqbudgets.budget_name AS budget,
1148 aqbooksellers.name AS supplier,
1149 aqbooksellers.id AS supplierid,
1150 biblioitems.publishercode AS publisher,
1151 ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) AS estimateddeliverydate,
1152 DATE(aqbasket.closedate) AS orderdate,
1153 aqorders.quantity - COALESCE(aqorders.quantityreceived,0) AS quantity_to_receive,
1154 (aqorders.quantity - COALESCE(aqorders.quantityreceived,0)) * aqorders.rrp AS subtotal,
1155 DATEDIFF(CURDATE( ),closedate) AS latesince
1156 FROM aqorders LEFT JOIN biblio ON biblio.biblionumber = aqorders.biblionumber
1157 LEFT JOIN biblioitems ON biblioitems.biblionumber = biblio.biblionumber
1158 LEFT JOIN aqbudgets ON aqorders.budget_id = aqbudgets.budget_id,
1159 aqbasket LEFT JOIN borrowers ON aqbasket.authorisedby = borrowers.borrowernumber
1160 LEFT JOIN aqbooksellers ON aqbasket.booksellerid = aqbooksellers.id
1161 WHERE aqorders.basketno = aqbasket.basketno
1162 AND ordernumber=?};
1163 my $result_set =
1164 $dbh->selectall_arrayref( $query, { Slice => {} }, $ordernumber );
1166 # result_set assumed to contain 1 match
1167 return $result_set->[0];
1170 =head3 GetLastOrderNotReceivedFromSubscriptionid
1172 $order = &GetLastOrderNotReceivedFromSubscriptionid($subscriptionid);
1174 Returns a reference-to-hash describing the last order not received for a subscription.
1176 =cut
1178 sub GetLastOrderNotReceivedFromSubscriptionid {
1179 my ( $subscriptionid ) = @_;
1180 my $dbh = C4::Context->dbh;
1181 my $query = qq|
1182 SELECT * FROM aqorders
1183 LEFT JOIN subscription
1184 ON ( aqorders.subscriptionid = subscription.subscriptionid )
1185 WHERE aqorders.subscriptionid = ?
1186 AND aqorders.datereceived IS NULL
1187 LIMIT 1
1189 my $result_set =
1190 $dbh->selectall_arrayref( $query, { Slice => {} }, $subscriptionid );
1192 # result_set assumed to contain 1 match
1193 return $result_set->[0];
1196 =head3 GetLastOrderReceivedFromSubscriptionid
1198 $order = &GetLastOrderReceivedFromSubscriptionid($subscriptionid);
1200 Returns a reference-to-hash describing the last order received for a subscription.
1202 =cut
1204 sub GetLastOrderReceivedFromSubscriptionid {
1205 my ( $subscriptionid ) = @_;
1206 my $dbh = C4::Context->dbh;
1207 my $query = qq|
1208 SELECT * FROM aqorders
1209 LEFT JOIN subscription
1210 ON ( aqorders.subscriptionid = subscription.subscriptionid )
1211 WHERE aqorders.subscriptionid = ?
1212 AND aqorders.datereceived =
1214 SELECT MAX( aqorders.datereceived )
1215 FROM aqorders
1216 LEFT JOIN subscription
1217 ON ( aqorders.subscriptionid = subscription.subscriptionid )
1218 WHERE aqorders.subscriptionid = ?
1219 AND aqorders.datereceived IS NOT NULL
1221 ORDER BY ordernumber DESC
1222 LIMIT 1
1224 my $result_set =
1225 $dbh->selectall_arrayref( $query, { Slice => {} }, $subscriptionid, $subscriptionid );
1227 # result_set assumed to contain 1 match
1228 return $result_set->[0];
1232 #------------------------------------------------------------#
1234 =head3 ModOrder
1236 &ModOrder(\%hashref);
1238 Modifies an existing order. Updates the order with order number
1239 $hashref->{'ordernumber'} and biblionumber $hashref->{'biblionumber'}. All
1240 other keys of the hash update the fields with the same name in the aqorders
1241 table of the Koha database.
1243 =cut
1245 sub ModOrder {
1246 my $orderinfo = shift;
1248 die "Ordernumber is required" if $orderinfo->{'ordernumber'} eq '' ;
1249 die "Biblionumber is required" if $orderinfo->{'biblionumber'} eq '';
1251 my $dbh = C4::Context->dbh;
1252 my @params;
1254 # update uncertainprice to an integer, just in case (under FF, checked boxes have the value "ON" by default)
1255 $orderinfo->{uncertainprice}=1 if $orderinfo->{uncertainprice};
1257 # delete($orderinfo->{'branchcode'});
1258 # the hash contains a lot of entries not in aqorders, so get the columns ...
1259 my $sth = $dbh->prepare("SELECT * FROM aqorders LIMIT 1;");
1260 $sth->execute;
1261 my $colnames = $sth->{NAME};
1262 #FIXME Be careful. If aqorders would have columns with diacritics,
1263 #you should need to decode what you get back from NAME.
1264 #See report 10110 and guided_reports.pl
1265 my $query = "UPDATE aqorders SET ";
1267 foreach my $orderinfokey (grep(!/ordernumber/, keys %$orderinfo)){
1268 # ... and skip hash entries that are not in the aqorders table
1269 # FIXME : probably not the best way to do it (would be better to have a correct hash)
1270 next unless grep(/^$orderinfokey$/, @$colnames);
1271 $query .= "$orderinfokey=?, ";
1272 push(@params, $orderinfo->{$orderinfokey});
1275 $query .= "timestamp=NOW() WHERE ordernumber=?";
1276 push(@params, $orderinfo->{'ordernumber'} );
1277 $sth = $dbh->prepare($query);
1278 $sth->execute(@params);
1279 return;
1282 #------------------------------------------------------------#
1284 =head3 ModItemOrder
1286 ModItemOrder($itemnumber, $ordernumber);
1288 Modifies the ordernumber of an item in aqorders_items.
1290 =cut
1292 sub ModItemOrder {
1293 my ($itemnumber, $ordernumber) = @_;
1295 return unless ($itemnumber and $ordernumber);
1297 my $dbh = C4::Context->dbh;
1298 my $query = qq{
1299 UPDATE aqorders_items
1300 SET ordernumber = ?
1301 WHERE itemnumber = ?
1303 my $sth = $dbh->prepare($query);
1304 return $sth->execute($ordernumber, $itemnumber);
1307 #------------------------------------------------------------#
1309 =head3 GetCancelledOrders
1311 my @orders = GetCancelledOrders($basketno, $orderby);
1313 Returns cancelled orders for a basket
1315 =cut
1317 sub GetCancelledOrders {
1318 my ( $basketno, $orderby ) = @_;
1320 return () unless $basketno;
1322 my $dbh = C4::Context->dbh;
1323 my $query = "
1324 SELECT
1325 biblio.*,
1326 biblioitems.*,
1327 aqorders.*,
1328 aqbudgets.*,
1329 aqorders_transfers.ordernumber_to AS transferred_to,
1330 aqorders_transfers.timestamp AS transferred_to_timestamp
1331 FROM aqorders
1332 LEFT JOIN aqbudgets ON aqbudgets.budget_id = aqorders.budget_id
1333 LEFT JOIN biblio ON biblio.biblionumber = aqorders.biblionumber
1334 LEFT JOIN biblioitems ON biblioitems.biblionumber = biblio.biblionumber
1335 LEFT JOIN aqorders_transfers ON aqorders_transfers.ordernumber_from = aqorders.ordernumber
1336 WHERE basketno = ?
1337 AND (datecancellationprinted IS NOT NULL
1338 AND datecancellationprinted <> '0000-00-00')
1341 $orderby = "aqorders.datecancellationprinted desc, aqorders.timestamp desc"
1342 unless $orderby;
1343 $query .= " ORDER BY $orderby";
1344 my $sth = $dbh->prepare($query);
1345 $sth->execute($basketno);
1346 my $results = $sth->fetchall_arrayref( {} );
1348 return @$results;
1352 #------------------------------------------------------------#
1354 =head3 ModReceiveOrder
1356 &ModReceiveOrder({
1357 biblionumber => $biblionumber,
1358 ordernumber => $ordernumber,
1359 quantityreceived => $quantityreceived,
1360 user => $user,
1361 cost => $cost,
1362 ecost => $ecost,
1363 invoiceid => $invoiceid,
1364 rrp => $rrp,
1365 budget_id => $budget_id,
1366 datereceived => $datereceived,
1367 received_itemnumbers => \@received_itemnumbers,
1368 order_internalnote => $order_internalnote,
1369 order_vendornote => $order_vendornote,
1372 Updates an order, to reflect the fact that it was received, at least
1373 in part. All arguments not mentioned below update the fields with the
1374 same name in the aqorders table of the Koha database.
1376 If a partial order is received, splits the order into two.
1378 Updates the order with bibilionumber C<$biblionumber> and ordernumber
1379 C<$ordernumber>.
1381 =cut
1384 sub ModReceiveOrder {
1385 my ( $params ) = @_;
1386 my $biblionumber = $params->{biblionumber};
1387 my $ordernumber = $params->{ordernumber};
1388 my $quantrec = $params->{quantityreceived};
1389 my $user = $params->{user};
1390 my $cost = $params->{cost};
1391 my $ecost = $params->{ecost};
1392 my $invoiceid = $params->{invoiceid};
1393 my $rrp = $params->{rrp};
1394 my $budget_id = $params->{budget_id};
1395 my $datereceived = $params->{datereceived};
1396 my $received_items = $params->{received_items};
1397 my $order_internalnote = $params->{order_internalnote};
1398 my $order_vendornote = $params->{order_vendornote};
1400 my $dbh = C4::Context->dbh;
1401 $datereceived = C4::Dates->output('iso') unless $datereceived;
1402 my $suggestionid = GetSuggestionFromBiblionumber( $biblionumber );
1403 if ($suggestionid) {
1404 ModSuggestion( {suggestionid=>$suggestionid,
1405 STATUS=>'AVAILABLE',
1406 biblionumber=> $biblionumber}
1410 my $result_set = $dbh->selectall_arrayref(
1411 q{SELECT * FROM aqorders WHERE biblionumber=? AND aqorders.ordernumber=?},
1412 { Slice => {} }, $biblionumber, $ordernumber
1415 # we assume we have a unique order
1416 my $order = $result_set->[0];
1418 my $new_ordernumber = $ordernumber;
1419 if ( $order->{quantity} > $quantrec ) {
1420 # Split order line in two parts: the first is the original order line
1421 # without received items (the quantity is decreased),
1422 # the second part is a new order line with quantity=quantityrec
1423 # (entirely received)
1424 my $query = q|
1425 UPDATE aqorders
1426 SET quantity = ?,
1427 orderstatus = 'partial'|;
1428 $query .= q|, order_internalnote = ?| if defined $order_internalnote;
1429 $query .= q|, order_vendornote = ?| if defined $order_vendornote;
1430 $query .= q| WHERE ordernumber = ?|;
1431 my $sth = $dbh->prepare($query);
1433 $sth->execute(
1434 $order->{quantity} - $quantrec,
1435 ( defined $order_internalnote ? $order_internalnote : () ),
1436 ( defined $order_vendornote ? $order_vendornote : () ),
1437 $ordernumber
1440 delete $order->{'ordernumber'};
1441 $order->{'budget_id'} = ( $budget_id || $order->{'budget_id'} );
1442 $order->{'quantity'} = $quantrec;
1443 $order->{'quantityreceived'} = $quantrec;
1444 $order->{'datereceived'} = $datereceived;
1445 $order->{'invoiceid'} = $invoiceid;
1446 $order->{'unitprice'} = $cost;
1447 $order->{'rrp'} = $rrp;
1448 $order->{ecost} = $ecost;
1449 $order->{'orderstatus'} = 'complete';
1450 $new_ordernumber = Koha::Acquisition::Order->new($order)->insert->{ordernumber};
1452 if ($received_items) {
1453 foreach my $itemnumber (@$received_items) {
1454 ModItemOrder($itemnumber, $new_ordernumber);
1457 } else {
1458 my $query = q|
1459 update aqorders
1460 set quantityreceived=?,datereceived=?,invoiceid=?,
1461 unitprice=?,rrp=?,ecost=?,budget_id=?,orderstatus='complete'|;
1462 $query .= q|, order_internalnote = ?| if defined $order_internalnote;
1463 $query .= q|, order_vendornote = ?| if defined $order_vendornote;
1464 $query .= q| where biblionumber=? and ordernumber=?|;
1465 my $sth = $dbh->prepare( $query );
1466 $sth->execute(
1467 $quantrec,
1468 $datereceived,
1469 $invoiceid,
1470 $cost,
1471 $rrp,
1472 $ecost,
1473 $budget_id,
1474 ( defined $order_internalnote ? $order_internalnote : () ),
1475 ( defined $order_vendornote ? $order_vendornote : () ),
1476 $biblionumber,
1477 $ordernumber
1480 return ($datereceived, $new_ordernumber);
1483 =head3 CancelReceipt
1485 my $parent_ordernumber = CancelReceipt($ordernumber);
1487 Cancel an order line receipt and update the parent order line, as if no
1488 receipt was made.
1489 If items are created at receipt (AcqCreateItem = receiving) then delete
1490 these items.
1492 =cut
1494 sub CancelReceipt {
1495 my $ordernumber = shift;
1497 return unless $ordernumber;
1499 my $dbh = C4::Context->dbh;
1500 my $query = qq{
1501 SELECT datereceived, parent_ordernumber, quantity
1502 FROM aqorders
1503 WHERE ordernumber = ?
1505 my $sth = $dbh->prepare($query);
1506 $sth->execute($ordernumber);
1507 my $order = $sth->fetchrow_hashref;
1508 unless($order) {
1509 warn "CancelReceipt: order $ordernumber does not exist";
1510 return;
1512 unless($order->{'datereceived'}) {
1513 warn "CancelReceipt: order $ordernumber is not received";
1514 return;
1517 my $parent_ordernumber = $order->{'parent_ordernumber'};
1519 my @itemnumbers = GetItemnumbersFromOrder( $ordernumber );
1521 if($parent_ordernumber == $ordernumber || not $parent_ordernumber) {
1522 # The order line has no parent, just mark it as not received
1523 $query = qq{
1524 UPDATE aqorders
1525 SET quantityreceived = ?,
1526 datereceived = ?,
1527 invoiceid = ?,
1528 orderstatus = 'ordered'
1529 WHERE ordernumber = ?
1531 $sth = $dbh->prepare($query);
1532 $sth->execute(0, undef, undef, $ordernumber);
1533 _cancel_items_receipt( $ordernumber );
1534 } else {
1535 # The order line has a parent, increase parent quantity and delete
1536 # the order line.
1537 $query = qq{
1538 SELECT quantity, datereceived
1539 FROM aqorders
1540 WHERE ordernumber = ?
1542 $sth = $dbh->prepare($query);
1543 $sth->execute($parent_ordernumber);
1544 my $parent_order = $sth->fetchrow_hashref;
1545 unless($parent_order) {
1546 warn "Parent order $parent_ordernumber does not exist.";
1547 return;
1549 if($parent_order->{'datereceived'}) {
1550 warn "CancelReceipt: parent order is received.".
1551 " Can't cancel receipt.";
1552 return;
1554 $query = qq{
1555 UPDATE aqorders
1556 SET quantity = ?,
1557 orderstatus = 'ordered'
1558 WHERE ordernumber = ?
1560 $sth = $dbh->prepare($query);
1561 my $rv = $sth->execute(
1562 $order->{'quantity'} + $parent_order->{'quantity'},
1563 $parent_ordernumber
1565 unless($rv) {
1566 warn "Cannot update parent order line, so do not cancel".
1567 " receipt";
1568 return;
1570 _cancel_items_receipt( $ordernumber, $parent_ordernumber );
1571 # Delete order line
1572 $query = qq{
1573 DELETE FROM aqorders
1574 WHERE ordernumber = ?
1576 $sth = $dbh->prepare($query);
1577 $sth->execute($ordernumber);
1581 if(C4::Context->preference('AcqCreateItem') eq 'ordering') {
1582 my @affects = split q{\|}, C4::Context->preference("AcqItemSetSubfieldsWhenReceiptIsCancelled");
1583 if ( @affects ) {
1584 for my $in ( @itemnumbers ) {
1585 my $biblionumber = C4::Biblio::GetBiblionumberFromItemnumber( $in );
1586 my $frameworkcode = GetFrameworkCode($biblionumber);
1587 my ( $itemfield ) = GetMarcFromKohaField( 'items.itemnumber', $frameworkcode );
1588 my $item = C4::Items::GetMarcItem( $biblionumber, $in );
1589 for my $affect ( @affects ) {
1590 my ( $sf, $v ) = split q{=}, $affect, 2;
1591 foreach ( $item->field($itemfield) ) {
1592 $_->update( $sf => $v );
1595 C4::Items::ModItemFromMarc( $item, $biblionumber, $in );
1600 return $parent_ordernumber;
1603 sub _cancel_items_receipt {
1604 my ( $ordernumber, $parent_ordernumber ) = @_;
1605 $parent_ordernumber ||= $ordernumber;
1607 my @itemnumbers = GetItemnumbersFromOrder($ordernumber);
1608 if(C4::Context->preference('AcqCreateItem') eq 'receiving') {
1609 # Remove items that were created at receipt
1610 my $query = qq{
1611 DELETE FROM items, aqorders_items
1612 USING items, aqorders_items
1613 WHERE items.itemnumber = ? AND aqorders_items.itemnumber = ?
1615 my $dbh = C4::Context->dbh;
1616 my $sth = $dbh->prepare($query);
1617 foreach my $itemnumber (@itemnumbers) {
1618 $sth->execute($itemnumber, $itemnumber);
1620 } else {
1621 # Update items
1622 foreach my $itemnumber (@itemnumbers) {
1623 ModItemOrder($itemnumber, $parent_ordernumber);
1628 #------------------------------------------------------------#
1630 =head3 SearchOrders
1632 @results = &SearchOrders({
1633 ordernumber => $ordernumber,
1634 search => $search,
1635 biblionumber => $biblionumber,
1636 ean => $ean,
1637 booksellerid => $booksellerid,
1638 basketno => $basketno,
1639 owner => $owner,
1640 pending => $pending
1641 ordered => $ordered
1644 Searches for orders.
1646 C<$owner> Finds order for the logged in user.
1647 C<$pending> Finds pending orders. Ignores completed and cancelled orders.
1648 C<$ordered> Finds orders to receive only (status 'ordered' or 'partial').
1651 C<@results> is an array of references-to-hash with the keys are fields
1652 from aqorders, biblio, biblioitems and aqbasket tables.
1654 =cut
1656 sub SearchOrders {
1657 my ( $params ) = @_;
1658 my $ordernumber = $params->{ordernumber};
1659 my $search = $params->{search};
1660 my $ean = $params->{ean};
1661 my $booksellerid = $params->{booksellerid};
1662 my $basketno = $params->{basketno};
1663 my $basketname = $params->{basketname};
1664 my $basketgroupname = $params->{basketgroupname};
1665 my $owner = $params->{owner};
1666 my $pending = $params->{pending};
1667 my $ordered = $params->{ordered};
1668 my $biblionumber = $params->{biblionumber};
1669 my $budget_id = $params->{budget_id};
1671 my $dbh = C4::Context->dbh;
1672 my @args = ();
1673 my $query = q{
1674 SELECT aqbasket.basketno,
1675 borrowers.surname,
1676 borrowers.firstname,
1677 biblio.*,
1678 biblioitems.isbn,
1679 biblioitems.biblioitemnumber,
1680 aqbasket.authorisedby,
1681 aqbasket.booksellerid,
1682 aqbasket.closedate,
1683 aqbasket.creationdate,
1684 aqbasket.basketname,
1685 aqbasketgroups.id as basketgroupid,
1686 aqbasketgroups.name as basketgroupname,
1687 aqorders.*
1688 FROM aqorders
1689 LEFT JOIN aqbasket ON aqorders.basketno = aqbasket.basketno
1690 LEFT JOIN aqbasketgroups ON aqbasket.basketgroupid = aqbasketgroups.id
1691 LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber
1692 LEFT JOIN biblio ON aqorders.biblionumber=biblio.biblionumber
1693 LEFT JOIN biblioitems ON biblioitems.biblionumber=biblio.biblionumber
1696 # If we search on ordernumber, we retrieve the transfered order if a transfer has been done.
1697 $query .= q{
1698 LEFT JOIN aqorders_transfers ON aqorders_transfers.ordernumber_to = aqorders.ordernumber
1699 } if $ordernumber;
1701 $query .= q{
1702 WHERE (datecancellationprinted is NULL)
1705 if ( $pending or $ordered ) {
1706 $query .= q{ AND (quantity > quantityreceived OR quantityreceived is NULL)};
1708 if ( $ordered ) {
1709 $query .= q{ AND aqorders.orderstatus IN ( "ordered", "partial" )};
1712 my $userenv = C4::Context->userenv;
1713 if ( C4::Context->preference("IndependentBranches") ) {
1714 unless ( C4::Context->IsSuperLibrarian() ) {
1715 $query .= q{
1716 AND (
1717 borrowers.branchcode = ?
1718 OR borrowers.branchcode = ''
1721 push @args, $userenv->{branch};
1725 if ( $ordernumber ) {
1726 $query .= ' AND ( aqorders.ordernumber = ? OR aqorders_transfers.ordernumber_from = ? ) ';
1727 push @args, ( $ordernumber, $ordernumber );
1729 if ( $biblionumber ) {
1730 $query .= 'AND aqorders.biblionumber = ?';
1731 push @args, $biblionumber;
1733 if( $search ) {
1734 $query .= ' AND (biblio.title LIKE ? OR biblio.author LIKE ? OR biblioitems.isbn LIKE ?)';
1735 push @args, ("%$search%","%$search%","%$search%");
1737 if ( $ean ) {
1738 $query .= ' AND biblioitems.ean = ?';
1739 push @args, $ean;
1741 if ( $booksellerid ) {
1742 $query .= 'AND aqbasket.booksellerid = ?';
1743 push @args, $booksellerid;
1745 if( $basketno ) {
1746 $query .= 'AND aqbasket.basketno = ?';
1747 push @args, $basketno;
1749 if( $basketname ) {
1750 $query .= 'AND aqbasket.basketname LIKE ?';
1751 push @args, "%$basketname%";
1753 if( $basketgroupname ) {
1754 $query .= ' AND aqbasketgroups.name LIKE ?';
1755 push @args, "%$basketgroupname%";
1758 if ( $owner ) {
1759 $query .= ' AND aqbasket.authorisedby=? ';
1760 push @args, $userenv->{'number'};
1763 if ( $budget_id ) {
1764 $query .= ' AND aqorders.budget_id = ?';
1765 push @args, $budget_id;
1768 $query .= ' ORDER BY aqbasket.basketno';
1770 my $sth = $dbh->prepare($query);
1771 $sth->execute(@args);
1772 return $sth->fetchall_arrayref({});
1775 #------------------------------------------------------------#
1777 =head3 DelOrder
1779 &DelOrder($biblionumber, $ordernumber);
1781 Cancel the order with the given order and biblio numbers. It does not
1782 delete any entries in the aqorders table, it merely marks them as
1783 cancelled.
1785 =cut
1787 sub DelOrder {
1788 my ( $bibnum, $ordernumber, $delete_biblio, $reason ) = @_;
1790 my $error;
1791 my $dbh = C4::Context->dbh;
1792 my $query = "
1793 UPDATE aqorders
1794 SET datecancellationprinted=now(), orderstatus='cancelled'
1796 if($reason) {
1797 $query .= ", cancellationreason = ? ";
1799 $query .= "
1800 WHERE biblionumber=? AND ordernumber=?
1802 my $sth = $dbh->prepare($query);
1803 if($reason) {
1804 $sth->execute($reason, $bibnum, $ordernumber);
1805 } else {
1806 $sth->execute( $bibnum, $ordernumber );
1808 $sth->finish;
1810 my @itemnumbers = GetItemnumbersFromOrder( $ordernumber );
1811 foreach my $itemnumber (@itemnumbers){
1812 my $delcheck = C4::Items::DelItemCheck( $dbh, $bibnum, $itemnumber );
1814 if($delcheck != 1) {
1815 $error->{'delitem'} = 1;
1819 if($delete_biblio) {
1820 # We get the number of remaining items
1821 my $itemcount = C4::Items::GetItemsCount($bibnum);
1823 # If there are no items left,
1824 if ( $itemcount == 0 ) {
1825 # We delete the record
1826 my $delcheck = DelBiblio($bibnum);
1828 if($delcheck) {
1829 $error->{'delbiblio'} = 1;
1834 return $error;
1837 =head3 TransferOrder
1839 my $newordernumber = TransferOrder($ordernumber, $basketno);
1841 Transfer an order line to a basket.
1842 Mark $ordernumber as cancelled with an internal note 'Cancelled and transfered
1843 to BOOKSELLER on DATE' and create new order with internal note
1844 'Transfered from BOOKSELLER on DATE'.
1845 Move all attached items to the new order.
1846 Received orders cannot be transfered.
1847 Return the ordernumber of created order.
1849 =cut
1851 sub TransferOrder {
1852 my ($ordernumber, $basketno) = @_;
1854 return unless ($ordernumber and $basketno);
1856 my $order = GetOrder( $ordernumber );
1857 return if $order->{datereceived};
1858 my $basket = GetBasket($basketno);
1859 return unless $basket;
1861 my $dbh = C4::Context->dbh;
1862 my ($query, $sth, $rv);
1864 $query = q{
1865 UPDATE aqorders
1866 SET datecancellationprinted = CAST(NOW() AS date)
1867 WHERE ordernumber = ?
1869 $sth = $dbh->prepare($query);
1870 $rv = $sth->execute($ordernumber);
1872 delete $order->{'ordernumber'};
1873 delete $order->{parent_ordernumber};
1874 $order->{'basketno'} = $basketno;
1876 my $newordernumber = Koha::Acquisition::Order->new($order)->insert->{ordernumber};
1878 $query = q{
1879 UPDATE aqorders_items
1880 SET ordernumber = ?
1881 WHERE ordernumber = ?
1883 $sth = $dbh->prepare($query);
1884 $sth->execute($newordernumber, $ordernumber);
1886 $query = q{
1887 INSERT INTO aqorders_transfers (ordernumber_from, ordernumber_to)
1888 VALUES (?, ?)
1890 $sth = $dbh->prepare($query);
1891 $sth->execute($ordernumber, $newordernumber);
1893 return $newordernumber;
1896 =head2 FUNCTIONS ABOUT PARCELS
1898 =cut
1900 #------------------------------------------------------------#
1902 =head3 GetParcel
1904 @results = &GetParcel($booksellerid, $code, $date);
1906 Looks up all of the received items from the supplier with the given
1907 bookseller ID at the given date, for the given code (bookseller Invoice number). Ignores cancelled and completed orders.
1909 C<@results> is an array of references-to-hash. The keys of each element are fields from
1910 the aqorders, biblio, and biblioitems tables of the Koha database.
1912 C<@results> is sorted alphabetically by book title.
1914 =cut
1916 sub GetParcel {
1917 #gets all orders from a certain supplier, orders them alphabetically
1918 my ( $supplierid, $code, $datereceived ) = @_;
1919 my $dbh = C4::Context->dbh;
1920 my @results = ();
1921 $code .= '%'
1922 if $code; # add % if we search on a given code (otherwise, let him empty)
1923 my $strsth ="
1924 SELECT authorisedby,
1925 creationdate,
1926 aqbasket.basketno,
1927 closedate,surname,
1928 firstname,
1929 aqorders.biblionumber,
1930 aqorders.ordernumber,
1931 aqorders.parent_ordernumber,
1932 aqorders.quantity,
1933 aqorders.quantityreceived,
1934 aqorders.unitprice,
1935 aqorders.listprice,
1936 aqorders.rrp,
1937 aqorders.ecost,
1938 aqorders.gstrate,
1939 biblio.title
1940 FROM aqorders
1941 LEFT JOIN aqbasket ON aqbasket.basketno=aqorders.basketno
1942 LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber
1943 LEFT JOIN biblio ON aqorders.biblionumber=biblio.biblionumber
1944 LEFT JOIN aqinvoices ON aqorders.invoiceid = aqinvoices.invoiceid
1945 WHERE
1946 aqbasket.booksellerid = ?
1947 AND aqinvoices.invoicenumber LIKE ?
1948 AND aqorders.datereceived = ? ";
1950 my @query_params = ( $supplierid, $code, $datereceived );
1951 if ( C4::Context->preference("IndependentBranches") ) {
1952 unless ( C4::Context->IsSuperLibrarian() ) {
1953 $strsth .= " and (borrowers.branchcode = ?
1954 or borrowers.branchcode = '')";
1955 push @query_params, C4::Context->userenv->{branch};
1958 $strsth .= " ORDER BY aqbasket.basketno";
1959 my $result_set = $dbh->selectall_arrayref(
1960 $strsth,
1961 { Slice => {} },
1962 @query_params);
1964 return @{$result_set};
1967 #------------------------------------------------------------#
1969 =head3 GetParcels
1971 $results = &GetParcels($bookseller, $order, $code, $datefrom, $dateto);
1973 get a lists of parcels.
1975 * Input arg :
1977 =over
1979 =item $bookseller
1980 is the bookseller this function has to get parcels.
1982 =item $order
1983 To know on what criteria the results list has to be ordered.
1985 =item $code
1986 is the booksellerinvoicenumber.
1988 =item $datefrom & $dateto
1989 to know on what date this function has to filter its search.
1991 =back
1993 * return:
1994 a pointer on a hash list containing parcel informations as such :
1996 =over
1998 =item Creation date
2000 =item Last operation
2002 =item Number of biblio
2004 =item Number of items
2006 =back
2008 =cut
2010 sub GetParcels {
2011 my ($bookseller,$order, $code, $datefrom, $dateto) = @_;
2012 my $dbh = C4::Context->dbh;
2013 my @query_params = ();
2014 my $strsth ="
2015 SELECT aqinvoices.invoicenumber,
2016 datereceived,purchaseordernumber,
2017 count(DISTINCT biblionumber) AS biblio,
2018 sum(quantity) AS itemsexpected,
2019 sum(quantityreceived) AS itemsreceived
2020 FROM aqorders LEFT JOIN aqbasket ON aqbasket.basketno = aqorders.basketno
2021 LEFT JOIN aqinvoices ON aqorders.invoiceid = aqinvoices.invoiceid
2022 WHERE aqbasket.booksellerid = ? and datereceived IS NOT NULL
2024 push @query_params, $bookseller;
2026 if ( defined $code ) {
2027 $strsth .= ' and aqinvoices.invoicenumber like ? ';
2028 # add a % to the end of the code to allow stemming.
2029 push @query_params, "$code%";
2032 if ( defined $datefrom ) {
2033 $strsth .= ' and datereceived >= ? ';
2034 push @query_params, $datefrom;
2037 if ( defined $dateto ) {
2038 $strsth .= 'and datereceived <= ? ';
2039 push @query_params, $dateto;
2042 $strsth .= "group by aqinvoices.invoicenumber,datereceived ";
2044 # can't use a placeholder to place this column name.
2045 # but, we could probably be checking to make sure it is a column that will be fetched.
2046 $strsth .= "order by $order " if ($order);
2048 my $sth = $dbh->prepare($strsth);
2050 $sth->execute( @query_params );
2051 my $results = $sth->fetchall_arrayref({});
2052 return @{$results};
2055 #------------------------------------------------------------#
2057 =head3 GetLateOrders
2059 @results = &GetLateOrders;
2061 Searches for bookseller with late orders.
2063 return:
2064 the table of supplier with late issues. This table is full of hashref.
2066 =cut
2068 sub GetLateOrders {
2069 my $delay = shift;
2070 my $supplierid = shift;
2071 my $branch = shift;
2072 my $estimateddeliverydatefrom = shift;
2073 my $estimateddeliverydateto = shift;
2075 my $dbh = C4::Context->dbh;
2077 #BEWARE, order of parenthesis and LEFT JOIN is important for speed
2078 my $dbdriver = C4::Context->config("db_scheme") || "mysql";
2080 my @query_params = ();
2081 my $select = "
2082 SELECT aqbasket.basketno,
2083 aqorders.ordernumber,
2084 DATE(aqbasket.closedate) AS orderdate,
2085 aqbasket.basketname AS basketname,
2086 aqbasket.basketgroupid AS basketgroupid,
2087 aqbasketgroups.name AS basketgroupname,
2088 aqorders.rrp AS unitpricesupplier,
2089 aqorders.ecost AS unitpricelib,
2090 aqorders.claims_count AS claims_count,
2091 aqorders.claimed_date AS claimed_date,
2092 aqbudgets.budget_name AS budget,
2093 borrowers.branchcode AS branch,
2094 aqbooksellers.name AS supplier,
2095 aqbooksellers.id AS supplierid,
2096 biblio.author, biblio.title,
2097 biblioitems.publishercode AS publisher,
2098 biblioitems.publicationyear,
2099 ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) AS estimateddeliverydate,
2101 my $from = "
2102 FROM
2103 aqorders LEFT JOIN biblio ON biblio.biblionumber = aqorders.biblionumber
2104 LEFT JOIN biblioitems ON biblioitems.biblionumber = biblio.biblionumber
2105 LEFT JOIN aqbudgets ON aqorders.budget_id = aqbudgets.budget_id,
2106 aqbasket LEFT JOIN borrowers ON aqbasket.authorisedby = borrowers.borrowernumber
2107 LEFT JOIN aqbooksellers ON aqbasket.booksellerid = aqbooksellers.id
2108 LEFT JOIN aqbasketgroups ON aqbasket.basketgroupid = aqbasketgroups.id
2109 WHERE aqorders.basketno = aqbasket.basketno
2110 AND ( datereceived = ''
2111 OR datereceived IS NULL
2112 OR aqorders.quantityreceived < aqorders.quantity
2114 AND aqbasket.closedate IS NOT NULL
2115 AND (aqorders.datecancellationprinted IS NULL OR aqorders.datecancellationprinted='0000-00-00')
2117 my $having = "";
2118 if ($dbdriver eq "mysql") {
2119 $select .= "
2120 aqorders.quantity - COALESCE(aqorders.quantityreceived,0) AS quantity,
2121 (aqorders.quantity - COALESCE(aqorders.quantityreceived,0)) * aqorders.rrp AS subtotal,
2122 DATEDIFF(CAST(now() AS date),closedate) AS latesince
2124 if ( defined $delay ) {
2125 $from .= " AND (closedate <= DATE_SUB(CAST(now() AS date),INTERVAL ? DAY)) " ;
2126 push @query_params, $delay;
2128 $having = "
2129 HAVING quantity <> 0
2130 AND unitpricesupplier <> 0
2131 AND unitpricelib <> 0
2133 } else {
2134 # FIXME: account for IFNULL as above
2135 $select .= "
2136 aqorders.quantity AS quantity,
2137 aqorders.quantity * aqorders.rrp AS subtotal,
2138 (CAST(now() AS date) - closedate) AS latesince
2140 if ( defined $delay ) {
2141 $from .= " AND (closedate <= (CAST(now() AS date) -(INTERVAL ? DAY)) ";
2142 push @query_params, $delay;
2145 if (defined $supplierid) {
2146 $from .= ' AND aqbasket.booksellerid = ? ';
2147 push @query_params, $supplierid;
2149 if (defined $branch) {
2150 $from .= ' AND borrowers.branchcode LIKE ? ';
2151 push @query_params, $branch;
2154 if ( defined $estimateddeliverydatefrom or defined $estimateddeliverydateto ) {
2155 $from .= ' AND aqbooksellers.deliverytime IS NOT NULL ';
2157 if ( defined $estimateddeliverydatefrom ) {
2158 $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) >= ?';
2159 push @query_params, $estimateddeliverydatefrom;
2161 if ( defined $estimateddeliverydateto ) {
2162 $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) <= ?';
2163 push @query_params, $estimateddeliverydateto;
2165 if ( defined $estimateddeliverydatefrom and not defined $estimateddeliverydateto ) {
2166 $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) <= CAST(now() AS date)';
2168 if (C4::Context->preference("IndependentBranches")
2169 && !C4::Context->IsSuperLibrarian() ) {
2170 $from .= ' AND borrowers.branchcode LIKE ? ';
2171 push @query_params, C4::Context->userenv->{branch};
2173 $from .= " AND orderstatus <> 'cancelled' ";
2174 my $query = "$select $from $having\nORDER BY latesince, basketno, borrowers.branchcode, supplier";
2175 $debug and print STDERR "GetLateOrders query: $query\nGetLateOrders args: " . join(" ",@query_params);
2176 my $sth = $dbh->prepare($query);
2177 $sth->execute(@query_params);
2178 my @results;
2179 while (my $data = $sth->fetchrow_hashref) {
2180 push @results, $data;
2182 return @results;
2185 #------------------------------------------------------------#
2187 =head3 GetHistory
2189 \@order_loop = GetHistory( %params );
2191 Retreives some acquisition history information
2193 params:
2194 title
2195 author
2196 name
2197 isbn
2199 from_placed_on
2200 to_placed_on
2201 basket - search both basket name and number
2202 booksellerinvoicenumber
2203 basketgroupname
2204 budget
2205 orderstatus (note that orderstatus '' will retrieve orders
2206 of any status except cancelled)
2207 biblionumber
2208 get_canceled_order (if set to a true value, cancelled orders will
2209 be included)
2211 returns:
2212 $order_loop is a list of hashrefs that each look like this:
2214 'author' => 'Twain, Mark',
2215 'basketno' => '1',
2216 'biblionumber' => '215',
2217 'count' => 1,
2218 'creationdate' => 'MM/DD/YYYY',
2219 'datereceived' => undef,
2220 'ecost' => '1.00',
2221 'id' => '1',
2222 'invoicenumber' => undef,
2223 'name' => '',
2224 'ordernumber' => '1',
2225 'quantity' => 1,
2226 'quantityreceived' => undef,
2227 'title' => 'The Adventures of Huckleberry Finn'
2230 =cut
2232 sub GetHistory {
2233 # don't run the query if there are no parameters (list would be too long for sure !)
2234 croak "No search params" unless @_;
2235 my %params = @_;
2236 my $title = $params{title};
2237 my $author = $params{author};
2238 my $isbn = $params{isbn};
2239 my $ean = $params{ean};
2240 my $name = $params{name};
2241 my $from_placed_on = $params{from_placed_on};
2242 my $to_placed_on = $params{to_placed_on};
2243 my $basket = $params{basket};
2244 my $booksellerinvoicenumber = $params{booksellerinvoicenumber};
2245 my $basketgroupname = $params{basketgroupname};
2246 my $budget = $params{budget};
2247 my $orderstatus = $params{orderstatus};
2248 my $biblionumber = $params{biblionumber};
2249 my $get_canceled_order = $params{get_canceled_order} || 0;
2250 my $ordernumber = $params{ordernumber};
2251 my $search_children_too = $params{search_children_too} || 0;
2253 my @order_loop;
2254 my $total_qty = 0;
2255 my $total_qtyreceived = 0;
2256 my $total_price = 0;
2258 my $dbh = C4::Context->dbh;
2259 my $query ="
2260 SELECT
2261 COALESCE(biblio.title, deletedbiblio.title) AS title,
2262 COALESCE(biblio.author, deletedbiblio.author) AS author,
2263 COALESCE(biblioitems.isbn, deletedbiblioitems.isbn) AS isbn,
2264 COALESCE(biblioitems.ean, deletedbiblioitems.ean) AS ean,
2265 aqorders.basketno,
2266 aqbasket.basketname,
2267 aqbasket.basketgroupid,
2268 aqbasketgroups.name as groupname,
2269 aqbooksellers.name,
2270 aqbasket.creationdate,
2271 aqorders.datereceived,
2272 aqorders.quantity,
2273 aqorders.quantityreceived,
2274 aqorders.ecost,
2275 aqorders.ordernumber,
2276 aqorders.invoiceid,
2277 aqinvoices.invoicenumber,
2278 aqbooksellers.id as id,
2279 aqorders.biblionumber,
2280 aqorders.orderstatus,
2281 aqorders.parent_ordernumber,
2282 aqbudgets.budget_name
2284 $query .= ", aqbudgets.budget_id AS budget" if defined $budget;
2285 $query .= "
2286 FROM aqorders
2287 LEFT JOIN aqbasket ON aqorders.basketno=aqbasket.basketno
2288 LEFT JOIN aqbasketgroups ON aqbasket.basketgroupid=aqbasketgroups.id
2289 LEFT JOIN aqbooksellers ON aqbasket.booksellerid=aqbooksellers.id
2290 LEFT JOIN biblioitems ON biblioitems.biblionumber=aqorders.biblionumber
2291 LEFT JOIN biblio ON biblio.biblionumber=aqorders.biblionumber
2292 LEFT JOIN aqbudgets ON aqorders.budget_id=aqbudgets.budget_id
2293 LEFT JOIN aqinvoices ON aqorders.invoiceid = aqinvoices.invoiceid
2294 LEFT JOIN deletedbiblio ON deletedbiblio.biblionumber=aqorders.biblionumber
2295 LEFT JOIN deletedbiblioitems ON deletedbiblioitems.biblionumber=aqorders.biblionumber
2298 if ( C4::Context->preference("IndependentBranches") ) {
2299 $query .= " LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber";
2302 $query .= " WHERE 1 ";
2304 unless ($get_canceled_order or (defined $orderstatus and $orderstatus eq 'cancelled')) {
2305 $query .= " AND (datecancellationprinted is NULL or datecancellationprinted='0000-00-00') ";
2308 my @query_params = ();
2310 if ( $biblionumber ) {
2311 $query .= " AND biblio.biblionumber = ?";
2312 push @query_params, $biblionumber;
2315 if ( $title ) {
2316 $query .= " AND biblio.title LIKE ? ";
2317 $title =~ s/\s+/%/g;
2318 push @query_params, "%$title%";
2321 if ( $author ) {
2322 $query .= " AND biblio.author LIKE ? ";
2323 push @query_params, "%$author%";
2326 if ( $isbn ) {
2327 $query .= " AND biblioitems.isbn LIKE ? ";
2328 push @query_params, "%$isbn%";
2330 if ( $ean ) {
2331 $query .= " AND biblioitems.ean = ? ";
2332 push @query_params, "$ean";
2334 if ( $name ) {
2335 $query .= " AND aqbooksellers.name LIKE ? ";
2336 push @query_params, "%$name%";
2339 if ( $budget ) {
2340 $query .= " AND aqbudgets.budget_id = ? ";
2341 push @query_params, "$budget";
2344 if ( $from_placed_on ) {
2345 $query .= " AND creationdate >= ? ";
2346 push @query_params, $from_placed_on;
2349 if ( $to_placed_on ) {
2350 $query .= " AND creationdate <= ? ";
2351 push @query_params, $to_placed_on;
2354 if ( defined $orderstatus and $orderstatus ne '') {
2355 $query .= " AND aqorders.orderstatus = ? ";
2356 push @query_params, "$orderstatus";
2359 if ($basket) {
2360 if ($basket =~ m/^\d+$/) {
2361 $query .= " AND aqorders.basketno = ? ";
2362 push @query_params, $basket;
2363 } else {
2364 $query .= " AND aqbasket.basketname LIKE ? ";
2365 push @query_params, "%$basket%";
2369 if ($booksellerinvoicenumber) {
2370 $query .= " AND aqinvoices.invoicenumber LIKE ? ";
2371 push @query_params, "%$booksellerinvoicenumber%";
2374 if ($basketgroupname) {
2375 $query .= " AND aqbasketgroups.name LIKE ? ";
2376 push @query_params, "%$basketgroupname%";
2379 if ($ordernumber) {
2380 $query .= " AND (aqorders.ordernumber = ? ";
2381 push @query_params, $ordernumber;
2382 if ($search_children_too) {
2383 $query .= " OR aqorders.parent_ordernumber = ? ";
2384 push @query_params, $ordernumber;
2386 $query .= ") ";
2390 if ( C4::Context->preference("IndependentBranches") ) {
2391 unless ( C4::Context->IsSuperLibrarian() ) {
2392 $query .= " AND (borrowers.branchcode = ? OR borrowers.branchcode ='' ) ";
2393 push @query_params, C4::Context->userenv->{branch};
2396 $query .= " ORDER BY id";
2398 return $dbh->selectall_arrayref( $query, { Slice => {} }, @query_params );
2401 =head2 GetRecentAcqui
2403 $results = GetRecentAcqui($days);
2405 C<$results> is a ref to a table which containts hashref
2407 =cut
2409 sub GetRecentAcqui {
2410 my $limit = shift;
2411 my $dbh = C4::Context->dbh;
2412 my $query = "
2413 SELECT *
2414 FROM biblio
2415 ORDER BY timestamp DESC
2416 LIMIT 0,".$limit;
2418 my $sth = $dbh->prepare($query);
2419 $sth->execute;
2420 my $results = $sth->fetchall_arrayref({});
2421 return $results;
2424 #------------------------------------------------------------#
2426 =head3 AddClaim
2428 =over
2430 &AddClaim($ordernumber);
2432 Add a claim for an order
2434 =back
2436 =cut
2438 sub AddClaim {
2439 my ($ordernumber) = @_;
2440 my $dbh = C4::Context->dbh;
2441 my $query = "
2442 UPDATE aqorders SET
2443 claims_count = claims_count + 1,
2444 claimed_date = CURDATE()
2445 WHERE ordernumber = ?
2447 my $sth = $dbh->prepare($query);
2448 $sth->execute($ordernumber);
2451 =head3 GetInvoices
2453 my @invoices = GetInvoices(
2454 invoicenumber => $invoicenumber,
2455 supplierid => $supplierid,
2456 suppliername => $suppliername,
2457 shipmentdatefrom => $shipmentdatefrom, # ISO format
2458 shipmentdateto => $shipmentdateto, # ISO format
2459 billingdatefrom => $billingdatefrom, # ISO format
2460 billingdateto => $billingdateto, # ISO format
2461 isbneanissn => $isbn_or_ean_or_issn,
2462 title => $title,
2463 author => $author,
2464 publisher => $publisher,
2465 publicationyear => $publicationyear,
2466 branchcode => $branchcode,
2467 order_by => $order_by
2470 Return a list of invoices that match all given criteria.
2472 $order_by is "column_name (asc|desc)", where column_name is any of
2473 'invoicenumber', 'booksellerid', 'shipmentdate', 'billingdate', 'closedate',
2474 'shipmentcost', 'shipmentcost_budgetid'.
2476 asc is the default if omitted
2478 =cut
2480 sub GetInvoices {
2481 my %args = @_;
2483 my @columns = qw(invoicenumber booksellerid shipmentdate billingdate
2484 closedate shipmentcost shipmentcost_budgetid);
2486 my $dbh = C4::Context->dbh;
2487 my $query = qq{
2488 SELECT aqinvoices.*, aqbooksellers.name AS suppliername,
2489 COUNT(
2490 DISTINCT IF(
2491 aqorders.datereceived IS NOT NULL,
2492 aqorders.biblionumber,
2493 NULL
2495 ) AS receivedbiblios,
2496 COUNT(
2497 DISTINCT IF(
2498 aqorders.subscriptionid IS NOT NULL,
2499 aqorders.subscriptionid,
2500 NULL
2502 ) AS is_linked_to_subscriptions,
2503 SUM(aqorders.quantityreceived) AS receiveditems
2504 FROM aqinvoices
2505 LEFT JOIN aqbooksellers ON aqbooksellers.id = aqinvoices.booksellerid
2506 LEFT JOIN aqorders ON aqorders.invoiceid = aqinvoices.invoiceid
2507 LEFT JOIN aqbasket ON aqbasket.basketno=aqorders.basketno
2508 LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber
2509 LEFT JOIN biblio ON aqorders.biblionumber = biblio.biblionumber
2510 LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
2511 LEFT JOIN subscription ON biblio.biblionumber = subscription.biblionumber
2514 my @bind_args;
2515 my @bind_strs;
2516 if($args{supplierid}) {
2517 push @bind_strs, " aqinvoices.booksellerid = ? ";
2518 push @bind_args, $args{supplierid};
2520 if($args{invoicenumber}) {
2521 push @bind_strs, " aqinvoices.invoicenumber LIKE ? ";
2522 push @bind_args, "%$args{invoicenumber}%";
2524 if($args{suppliername}) {
2525 push @bind_strs, " aqbooksellers.name LIKE ? ";
2526 push @bind_args, "%$args{suppliername}%";
2528 if($args{shipmentdatefrom}) {
2529 push @bind_strs, " aqinvoices.shipmentdate >= ? ";
2530 push @bind_args, $args{shipmentdatefrom};
2532 if($args{shipmentdateto}) {
2533 push @bind_strs, " aqinvoices.shipmentdate <= ? ";
2534 push @bind_args, $args{shipmentdateto};
2536 if($args{billingdatefrom}) {
2537 push @bind_strs, " aqinvoices.billingdate >= ? ";
2538 push @bind_args, $args{billingdatefrom};
2540 if($args{billingdateto}) {
2541 push @bind_strs, " aqinvoices.billingdate <= ? ";
2542 push @bind_args, $args{billingdateto};
2544 if($args{isbneanissn}) {
2545 push @bind_strs, " (biblioitems.isbn LIKE CONCAT('%', ?, '%') OR biblioitems.ean LIKE CONCAT('%', ?, '%') OR biblioitems.issn LIKE CONCAT('%', ?, '%') ) ";
2546 push @bind_args, $args{isbneanissn}, $args{isbneanissn}, $args{isbneanissn};
2548 if($args{title}) {
2549 push @bind_strs, " biblio.title LIKE CONCAT('%', ?, '%') ";
2550 push @bind_args, $args{title};
2552 if($args{author}) {
2553 push @bind_strs, " biblio.author LIKE CONCAT('%', ?, '%') ";
2554 push @bind_args, $args{author};
2556 if($args{publisher}) {
2557 push @bind_strs, " biblioitems.publishercode LIKE CONCAT('%', ?, '%') ";
2558 push @bind_args, $args{publisher};
2560 if($args{publicationyear}) {
2561 push @bind_strs, " ((biblioitems.publicationyear LIKE CONCAT('%', ?, '%')) OR (biblio.copyrightdate LIKE CONCAT('%', ?, '%'))) ";
2562 push @bind_args, $args{publicationyear}, $args{publicationyear};
2564 if($args{branchcode}) {
2565 push @bind_strs, " borrowers.branchcode = ? ";
2566 push @bind_args, $args{branchcode};
2569 $query .= " WHERE " . join(" AND ", @bind_strs) if @bind_strs;
2570 $query .= " GROUP BY aqinvoices.invoiceid ";
2572 if($args{order_by}) {
2573 my ($column, $direction) = split / /, $args{order_by};
2574 if(grep /^$column$/, @columns) {
2575 $direction ||= 'ASC';
2576 $query .= " ORDER BY $column $direction";
2580 my $sth = $dbh->prepare($query);
2581 $sth->execute(@bind_args);
2583 my $results = $sth->fetchall_arrayref({});
2584 return @$results;
2587 =head3 GetInvoice
2589 my $invoice = GetInvoice($invoiceid);
2591 Get informations about invoice with given $invoiceid
2593 Return a hash filled with aqinvoices.* fields
2595 =cut
2597 sub GetInvoice {
2598 my ($invoiceid) = @_;
2599 my $invoice;
2601 return unless $invoiceid;
2603 my $dbh = C4::Context->dbh;
2604 my $query = qq{
2605 SELECT *
2606 FROM aqinvoices
2607 WHERE invoiceid = ?
2609 my $sth = $dbh->prepare($query);
2610 $sth->execute($invoiceid);
2612 $invoice = $sth->fetchrow_hashref;
2613 return $invoice;
2616 =head3 GetInvoiceDetails
2618 my $invoice = GetInvoiceDetails($invoiceid)
2620 Return informations about an invoice + the list of related order lines
2622 Orders informations are in $invoice->{orders} (array ref)
2624 =cut
2626 sub GetInvoiceDetails {
2627 my ($invoiceid) = @_;
2629 if ( !defined $invoiceid ) {
2630 carp 'GetInvoiceDetails called without an invoiceid';
2631 return;
2634 my $dbh = C4::Context->dbh;
2635 my $query = q{
2636 SELECT aqinvoices.*, aqbooksellers.name AS suppliername
2637 FROM aqinvoices
2638 LEFT JOIN aqbooksellers ON aqinvoices.booksellerid = aqbooksellers.id
2639 WHERE invoiceid = ?
2641 my $sth = $dbh->prepare($query);
2642 $sth->execute($invoiceid);
2644 my $invoice = $sth->fetchrow_hashref;
2646 $query = q{
2647 SELECT aqorders.*, biblio.*,
2648 biblio.copyrightdate,
2649 biblioitems.publishercode,
2650 biblioitems.publicationyear,
2651 aqbasket.basketname
2652 FROM aqorders
2653 LEFT JOIN aqbasket ON aqorders.basketno = aqbasket.basketno
2654 LEFT JOIN biblio ON aqorders.biblionumber = biblio.biblionumber
2655 LEFT JOIN biblioitems ON aqorders.biblionumber = biblioitems.biblionumber
2656 WHERE invoiceid = ?
2658 $sth = $dbh->prepare($query);
2659 $sth->execute($invoiceid);
2660 $invoice->{orders} = $sth->fetchall_arrayref({});
2661 $invoice->{orders} ||= []; # force an empty arrayref if fetchall_arrayref fails
2663 return $invoice;
2666 =head3 AddInvoice
2668 my $invoiceid = AddInvoice(
2669 invoicenumber => $invoicenumber,
2670 booksellerid => $booksellerid,
2671 shipmentdate => $shipmentdate,
2672 billingdate => $billingdate,
2673 closedate => $closedate,
2674 shipmentcost => $shipmentcost,
2675 shipmentcost_budgetid => $shipmentcost_budgetid
2678 Create a new invoice and return its id or undef if it fails.
2680 =cut
2682 sub AddInvoice {
2683 my %invoice = @_;
2685 return unless(%invoice and $invoice{invoicenumber});
2687 my @columns = qw(invoicenumber booksellerid shipmentdate billingdate
2688 closedate shipmentcost shipmentcost_budgetid);
2690 my @set_strs;
2691 my @set_args;
2692 foreach my $key (keys %invoice) {
2693 if(0 < grep(/^$key$/, @columns)) {
2694 push @set_strs, "$key = ?";
2695 push @set_args, ($invoice{$key} || undef);
2699 my $rv;
2700 if(@set_args > 0) {
2701 my $dbh = C4::Context->dbh;
2702 my $query = "INSERT INTO aqinvoices SET ";
2703 $query .= join (",", @set_strs);
2704 my $sth = $dbh->prepare($query);
2705 $rv = $sth->execute(@set_args);
2706 if($rv) {
2707 $rv = $dbh->last_insert_id(undef, undef, 'aqinvoices', undef);
2710 return $rv;
2713 =head3 ModInvoice
2715 ModInvoice(
2716 invoiceid => $invoiceid, # Mandatory
2717 invoicenumber => $invoicenumber,
2718 booksellerid => $booksellerid,
2719 shipmentdate => $shipmentdate,
2720 billingdate => $billingdate,
2721 closedate => $closedate,
2722 shipmentcost => $shipmentcost,
2723 shipmentcost_budgetid => $shipmentcost_budgetid
2726 Modify an invoice, invoiceid is mandatory.
2728 Return undef if it fails.
2730 =cut
2732 sub ModInvoice {
2733 my %invoice = @_;
2735 return unless(%invoice and $invoice{invoiceid});
2737 my @columns = qw(invoicenumber booksellerid shipmentdate billingdate
2738 closedate shipmentcost shipmentcost_budgetid);
2740 my @set_strs;
2741 my @set_args;
2742 foreach my $key (keys %invoice) {
2743 if(0 < grep(/^$key$/, @columns)) {
2744 push @set_strs, "$key = ?";
2745 push @set_args, ($invoice{$key} || undef);
2749 my $dbh = C4::Context->dbh;
2750 my $query = "UPDATE aqinvoices SET ";
2751 $query .= join(",", @set_strs);
2752 $query .= " WHERE invoiceid = ?";
2754 my $sth = $dbh->prepare($query);
2755 $sth->execute(@set_args, $invoice{invoiceid});
2758 =head3 CloseInvoice
2760 CloseInvoice($invoiceid);
2762 Close an invoice.
2764 Equivalent to ModInvoice(invoiceid => $invoiceid, closedate => undef);
2766 =cut
2768 sub CloseInvoice {
2769 my ($invoiceid) = @_;
2771 return unless $invoiceid;
2773 my $dbh = C4::Context->dbh;
2774 my $query = qq{
2775 UPDATE aqinvoices
2776 SET closedate = CAST(NOW() AS DATE)
2777 WHERE invoiceid = ?
2779 my $sth = $dbh->prepare($query);
2780 $sth->execute($invoiceid);
2783 =head3 ReopenInvoice
2785 ReopenInvoice($invoiceid);
2787 Reopen an invoice
2789 Equivalent to ModInvoice(invoiceid => $invoiceid, closedate => C4::Dates->new()->output('iso'))
2791 =cut
2793 sub ReopenInvoice {
2794 my ($invoiceid) = @_;
2796 return unless $invoiceid;
2798 my $dbh = C4::Context->dbh;
2799 my $query = qq{
2800 UPDATE aqinvoices
2801 SET closedate = NULL
2802 WHERE invoiceid = ?
2804 my $sth = $dbh->prepare($query);
2805 $sth->execute($invoiceid);
2808 =head3 DelInvoice
2810 DelInvoice($invoiceid);
2812 Delete an invoice if there are no items attached to it.
2814 =cut
2816 sub DelInvoice {
2817 my ($invoiceid) = @_;
2819 return unless $invoiceid;
2821 my $dbh = C4::Context->dbh;
2822 my $query = qq{
2823 SELECT COUNT(*)
2824 FROM aqorders
2825 WHERE invoiceid = ?
2827 my $sth = $dbh->prepare($query);
2828 $sth->execute($invoiceid);
2829 my $res = $sth->fetchrow_arrayref;
2830 if ( $res && $res->[0] == 0 ) {
2831 $query = qq{
2832 DELETE FROM aqinvoices
2833 WHERE invoiceid = ?
2835 my $sth = $dbh->prepare($query);
2836 return ( $sth->execute($invoiceid) > 0 );
2838 return;
2841 =head3 MergeInvoices
2843 MergeInvoices($invoiceid, \@sourceids);
2845 Merge the invoices identified by the IDs in \@sourceids into
2846 the invoice identified by $invoiceid.
2848 =cut
2850 sub MergeInvoices {
2851 my ($invoiceid, $sourceids) = @_;
2853 return unless $invoiceid;
2854 foreach my $sourceid (@$sourceids) {
2855 next if $sourceid == $invoiceid;
2856 my $source = GetInvoiceDetails($sourceid);
2857 foreach my $order (@{$source->{'orders'}}) {
2858 $order->{'invoiceid'} = $invoiceid;
2859 ModOrder($order);
2861 DelInvoice($source->{'invoiceid'});
2863 return;
2866 =head3 GetBiblioCountByBasketno
2868 $biblio_count = &GetBiblioCountByBasketno($basketno);
2870 Looks up the biblio's count that has basketno value $basketno
2872 Returns a quantity
2874 =cut
2876 sub GetBiblioCountByBasketno {
2877 my ($basketno) = @_;
2878 my $dbh = C4::Context->dbh;
2879 my $query = "
2880 SELECT COUNT( DISTINCT( biblionumber ) )
2881 FROM aqorders
2882 WHERE basketno = ?
2883 AND (datecancellationprinted IS NULL OR datecancellationprinted='0000-00-00')
2886 my $sth = $dbh->prepare($query);
2887 $sth->execute($basketno);
2888 return $sth->fetchrow;
2892 __END__
2894 =head1 AUTHOR
2896 Koha Development Team <http://koha-community.org/>
2898 =cut