fix POD errors reported by xt/author/podcorrectness.t
[koha.git] / C4 / Acquisition.pm
1 package C4::Acquisition;
2
3 # Copyright 2000-2002 Katipo Communications
4 #
5 # This file is part of Koha.
6 #
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.
11 #
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.
15 #
16 # You should have received a copy of the GNU General Public License along with
17 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
18 # Suite 330, Boston, MA  02111-1307 USA
19
20
21 use strict;
22 use warnings;
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::Debug;
30 use C4::SQLHelper qw(InsertInTable);
31
32 use Time::localtime;
33 use HTML::Entities;
34
35 use vars qw($VERSION @ISA @EXPORT);
36
37 BEGIN {
38     # set the version for version checking
39     $VERSION = 3.01;
40     require Exporter;
41     @ISA    = qw(Exporter);
42     @EXPORT = qw(
43         &GetBasket &NewBasket &CloseBasket &DelBasket &ModBasket
44         &GetBasketAsCSV
45         &GetBasketsByBookseller &GetBasketsByBasketgroup
46
47         &ModBasketHeader
48
49         &ModBasketgroup &NewBasketgroup &DelBasketgroup &GetBasketgroup &CloseBasketgroup
50         &GetBasketgroups &ReOpenBasketgroup
51
52         &NewOrder &DelOrder &ModOrder &GetPendingOrders &GetOrder &GetOrders
53         &GetOrderNumber &GetLateOrders &GetOrderFromItemnumber
54         &SearchOrder &GetHistory &GetRecentAcqui
55         &ModReceiveOrder &ModOrderBiblioitemNumber
56
57         &NewOrderItem &ModOrderItem
58
59         &GetParcels &GetParcel
60         &GetContracts &GetContract
61
62         &GetItemnumbersFromOrder
63     );
64 }
65
66
67
68
69
70 sub GetOrderFromItemnumber {
71     my ($itemnumber) = @_;
72     my $dbh          = C4::Context->dbh;
73     my $query        = qq|
74
75     SELECT  * from aqorders    LEFT JOIN aqorders_items
76     ON (     aqorders.ordernumber = aqorders_items.ordernumber   )
77     WHERE itemnumber = ?  |;
78
79     my $sth = $dbh->prepare($query);
80
81 #    $sth->trace(3);
82
83     $sth->execute($itemnumber);
84
85     my $order = $sth->fetchrow_hashref;
86     return ( $order  );
87
88 }
89
90 # Returns the itemnumber(s) associated with the ordernumber given in parameter
91 sub GetItemnumbersFromOrder {
92     my ($ordernumber) = @_;
93     my $dbh          = C4::Context->dbh;
94     my $query        = "SELECT itemnumber FROM aqorders_items WHERE ordernumber=?";
95     my $sth = $dbh->prepare($query);
96     $sth->execute($ordernumber);
97     my @tab;
98
99     while (my $order = $sth->fetchrow_hashref) {
100     push @tab, $order->{'itemnumber'};
101     }
102
103     return @tab;
104
105 }
106
107
108
109
110
111
112 =head1 NAME
113
114 C4::Acquisition - Koha functions for dealing with orders and acquisitions
115
116 =head1 SYNOPSIS
117
118 use C4::Acquisition;
119
120 =head1 DESCRIPTION
121
122 The functions in this module deal with acquisitions, managing book
123 orders, basket and parcels.
124
125 =head1 FUNCTIONS
126
127 =head2 FUNCTIONS ABOUT BASKETS
128
129 =head3 GetBasket
130
131 =over 4
132
133 $aqbasket = &GetBasket($basketnumber);
134
135 get all basket informations in aqbasket for a given basket
136
137 return :
138 informations for a given basket returned as a hashref.
139
140 =back
141
142 =cut
143
144 sub GetBasket {
145     my ($basketno) = @_;
146     my $dbh        = C4::Context->dbh;
147     my $query = "
148         SELECT  aqbasket.*,
149                 concat( b.firstname,' ',b.surname) AS authorisedbyname,
150                 b.branchcode AS branch
151         FROM    aqbasket
152         LEFT JOIN borrowers b ON aqbasket.authorisedby=b.borrowernumber
153         WHERE basketno=?
154     ";
155     my $sth=$dbh->prepare($query);
156     $sth->execute($basketno);
157     my $basket = $sth->fetchrow_hashref;
158     return ( $basket );
159 }
160
161 #------------------------------------------------------------#
162
163 =head3 NewBasket
164
165 =over 4
166
167 $basket = &NewBasket( $booksellerid, $authorizedby, $basketname, $basketnote, $basketbooksellernote, $basketcontractnumber );
168
169 =back
170
171 Create a new basket in aqbasket table
172
173 =over 2
174
175 =item C<$booksellerid> is a foreign key in the aqbasket table
176
177 =item C<$authorizedby> is the username of who created the basket
178
179 =back
180
181 The other parameters are optional, see ModBasketHeader for more info on them.
182
183 =cut
184
185 # FIXME : this function seems to be unused.
186
187 sub NewBasket {
188     my ( $booksellerid, $authorisedby, $basketname, $basketnote, $basketbooksellernote, $basketcontractnumber ) = @_;
189     my $dbh = C4::Context->dbh;
190     my $query = "
191         INSERT INTO aqbasket
192                 (creationdate,booksellerid,authorisedby)
193         VALUES  (now(),'$booksellerid','$authorisedby')
194     ";
195     my $sth =
196     $dbh->do($query);
197 #find & return basketno MYSQL dependant, but $dbh->last_insert_id always returns null :-(
198     my $basket = $dbh->{'mysql_insertid'};
199     ModBasketHeader($basket, $basketname || '', $basketnote || '', $basketbooksellernote || '', $basketcontractnumber || undef);
200     return $basket;
201 }
202
203 #------------------------------------------------------------#
204
205 =head3 CloseBasket
206
207 =over 4
208
209 &CloseBasket($basketno);
210
211 close a basket (becomes unmodifiable,except for recieves)
212
213 =back
214
215 =cut
216
217 sub CloseBasket {
218     my ($basketno) = @_;
219     my $dbh        = C4::Context->dbh;
220     my $query = "
221         UPDATE aqbasket
222         SET    closedate=now()
223         WHERE  basketno=?
224     ";
225     my $sth = $dbh->prepare($query);
226     $sth->execute($basketno);
227 }
228
229 #------------------------------------------------------------#
230
231 =head3 GetBasketAsCSV
232
233 =over 4
234
235 &GetBasketAsCSV($basketno);
236
237 Export a basket as CSV
238
239 =back
240
241 =cut
242 sub GetBasketAsCSV {
243     my ($basketno) = @_;
244     my $basket = GetBasket($basketno);
245     my @orders = GetOrders($basketno);
246     my $contract = GetContract($basket->{'contractnumber'});
247     my $csv = Text::CSV->new();
248     my $output; 
249
250     # TODO: Translate headers
251     my @headers = qw(contractname ordernumber line entrydate isbn author title publishercode collectiontitle notes quantity rrp);
252
253     $csv->combine(@headers);                                                                                                        
254     $output = $csv->string() . "\n";    
255
256     my @rows;
257     foreach my $order (@orders) {
258         my @cols;
259         my $bd = GetBiblioData($order->{'biblionumber'});
260         push(@cols,
261                 $contract->{'contractname'},
262                 $order->{'ordernumber'},
263                 $order->{'entrydate'}, 
264                 $order->{'isbn'},
265                 $bd->{'author'},
266                 $bd->{'title'},
267                 $bd->{'publishercode'},
268                 $bd->{'collectiontitle'},
269                 $order->{'notes'},
270                 $order->{'quantity'},
271                 $order->{'rrp'},
272             );
273         push (@rows, \@cols);
274     }
275
276     # Sort by publishercode 
277     # TODO: Sort by publishercode then by title
278     @rows = sort { @$a[7] cmp @$b[7] } @rows;
279
280     foreach my $row (@rows) {
281         $csv->combine(@$row);                                                                                                                    
282         $output .= $csv->string() . "\n";    
283
284     }
285                                                                                                                                                       
286     return $output;             
287
288 }
289
290
291 =head3 CloseBasketgroup
292
293 =over 4
294
295 &CloseBasketgroup($basketgroupno);
296
297 close a basketgroup
298
299 =back
300
301 =cut
302
303 sub CloseBasketgroup {
304     my ($basketgroupno) = @_;
305     my $dbh        = C4::Context->dbh;
306     my $sth = $dbh->prepare("
307         UPDATE aqbasketgroups
308         SET    closed=1
309         WHERE  id=?
310     ");
311     $sth->execute($basketgroupno);
312 }
313
314 #------------------------------------------------------------#
315
316 =head3 ReOpenBaskergroup($basketgroupno)
317
318 =over 4
319
320 &ReOpenBaskergroup($basketgroupno);
321
322 reopen a basketgroup
323
324 =back
325
326 =cut
327
328 sub ReOpenBasketgroup {
329     my ($basketgroupno) = @_;
330     my $dbh        = C4::Context->dbh;
331     my $sth = $dbh->prepare("
332         UPDATE aqbasketgroups
333         SET    closed=0
334         WHERE  id=?
335     ");
336     $sth->execute($basketgroupno);
337 }
338
339 #------------------------------------------------------------#
340
341
342 =head3 DelBasket
343
344 =over 4
345
346 &DelBasket($basketno);
347
348 Deletes the basket that has basketno field $basketno in the aqbasket table.
349
350 =over 2
351
352 =item C<$basketno> is the primary key of the basket in the aqbasket table.
353
354 =back
355
356 =back
357
358 =cut
359 sub DelBasket {
360     my ( $basketno ) = @_;
361     my $query = "DELETE FROM aqbasket WHERE basketno=?";
362     my $dbh = C4::Context->dbh;
363     my $sth = $dbh->prepare($query);
364     $sth->execute($basketno);
365     $sth->finish;
366 }
367
368 #------------------------------------------------------------#
369
370 =head3 ModBasket
371
372 =over 4
373
374 &ModBasket($basketinfo);
375
376 Modifies a basket, using a hashref $basketinfo for the relevant information, only $basketinfo->{'basketno'} is required.
377
378 =over 2
379
380 =item C<$basketno> is the primary key of the basket in the aqbasket table.
381
382 =back
383
384 =back
385
386 =cut
387 sub ModBasket {
388     my $basketinfo = shift;
389     my $query = "UPDATE aqbasket SET ";
390     my @params;
391     foreach my $key (keys %$basketinfo){
392         if ($key ne 'basketno'){
393             $query .= "$key=?, ";
394             push(@params, $basketinfo->{$key} || undef );
395         }
396     }
397 # get rid of the "," at the end of $query
398     if (substr($query, length($query)-2) eq ', '){
399         chop($query);
400         chop($query);
401         $query .= ' ';
402     }
403     $query .= "WHERE basketno=?";
404     push(@params, $basketinfo->{'basketno'});
405     my $dbh = C4::Context->dbh;
406     my $sth = $dbh->prepare($query);
407     $sth->execute(@params);
408     $sth->finish;
409 }
410
411 #------------------------------------------------------------#
412
413 =head3 ModBasketHeader
414
415 =over 4
416
417 &ModBasketHeader($basketno, $basketname, $note, $booksellernote, $contractnumber);
418
419 Modifies a basket's header.
420
421 =over 2
422
423 =item C<$basketno> is the "basketno" field in the "aqbasket" table;
424
425 =item C<$basketname> is the "basketname" field in the "aqbasket" table;
426
427 =item C<$note> is the "note" field in the "aqbasket" table;
428
429 =item C<$booksellernote> is the "booksellernote" field in the "aqbasket" table;
430
431 =item C<$contractnumber> is the "contractnumber" (foreign) key in the "aqbasket" table.
432
433 =back
434
435 =back
436
437 =cut
438 sub ModBasketHeader {
439     my ($basketno, $basketname, $note, $booksellernote, $contractnumber) = @_;
440     my $query = "UPDATE aqbasket SET basketname=?, note=?, booksellernote=? WHERE basketno=?";
441     my $dbh = C4::Context->dbh;
442     my $sth = $dbh->prepare($query);
443     $sth->execute($basketname,$note,$booksellernote,$basketno);
444     if ( $contractnumber ) {
445         my $query2 ="UPDATE aqbasket SET contractnumber=? WHERE basketno=?";
446         my $sth2 = $dbh->prepare($query2);
447         $sth2->execute($contractnumber,$basketno);
448         $sth2->finish;
449     }
450     $sth->finish;
451 }
452
453 #------------------------------------------------------------#
454
455 =head3 GetBasketsByBookseller
456
457 =over 4
458
459 @results = &GetBasketsByBookseller($booksellerid, $extra);
460
461 Returns a list of hashes of all the baskets that belong to bookseller 'booksellerid'.
462
463 =over 2
464
465 =item C<$booksellerid> is the 'id' field of the bookseller in the aqbooksellers table
466
467 =item C<$extra> is the extra sql parameters, can be
468
469 - $extra->{groupby}: group baskets by column
470     ex. $extra->{groupby} = aqbasket.basketgroupid
471 - $extra->{orderby}: order baskets by column
472 - $extra->{limit}: limit number of results (can be helpful for pagination)
473
474 =back
475
476 =back
477
478 =cut
479
480 sub GetBasketsByBookseller {
481     my ($booksellerid, $extra) = @_;
482     my $query = "SELECT * FROM aqbasket WHERE booksellerid=?";
483     if ($extra){
484         if ($extra->{groupby}) {
485             $query .= " GROUP by $extra->{groupby}";
486         }
487         if ($extra->{orderby}){
488             $query .= " ORDER by $extra->{orderby}";
489         }
490         if ($extra->{limit}){
491             $query .= " LIMIT $extra->{limit}";
492         }
493     }
494     my $dbh = C4::Context->dbh;
495     my $sth = $dbh->prepare($query);
496     $sth->execute($booksellerid);
497     my $results = $sth->fetchall_arrayref({});
498     $sth->finish;
499     return $results
500 }
501
502 #------------------------------------------------------------#
503
504 =head3 GetBasketsByBasketgroup
505
506 =over 4
507
508 $baskets = &GetBasketsByBasketgroup($basketgroupid);
509
510 =over 2
511
512 Returns a reference to all baskets that belong to basketgroup $basketgroupid.
513
514 =back
515
516 =back
517
518 =cut
519
520 sub GetBasketsByBasketgroup {
521     my $basketgroupid = shift;
522     my $query = "SELECT * FROM aqbasket
523                 LEFT JOIN aqcontract USING(contractnumber) WHERE basketgroupid=?";
524     my $dbh = C4::Context->dbh;
525     my $sth = $dbh->prepare($query);
526     $sth->execute($basketgroupid);
527     my $results = $sth->fetchall_arrayref({});
528     $sth->finish;
529     return $results
530 }
531
532 #------------------------------------------------------------#
533
534 =head3 NewBasketgroup
535
536 =over 4
537
538 $basketgroupid = NewBasketgroup(\%hashref);
539
540 =over 2
541
542 Adds a basketgroup to the aqbasketgroups table, and add the initial baskets to it.
543
544 $hashref->{'booksellerid'} is the 'id' field of the bookseller in the aqbooksellers table,
545
546 $hashref->{'name'} is the 'name' field of the basketgroup in the aqbasketgroups table,
547
548 $hashref->{'basketlist'} is a list reference of the 'id's of the baskets that belong to this group,
549
550 $hashref->{'deliveryplace'} is the 'deliveryplace' field of the basketgroup in the aqbasketgroups table,
551
552 $hashref->{'deliverycomment'} is the 'deliverycomment' field of the basketgroup in the aqbasketgroups table,
553
554 $hashref->{'closed'} is the 'closed' field of the aqbasketgroups table, it is false if 0, true otherwise.
555
556 =back
557
558 =back
559
560 =cut
561
562 sub NewBasketgroup {
563     my $basketgroupinfo = shift;
564     die "booksellerid is required to create a basketgroup" unless $basketgroupinfo->{'booksellerid'};
565     my $query = "INSERT INTO aqbasketgroups (";
566     my @params;
567     foreach my $field ('name', 'deliveryplace', 'deliverycomment', 'closed') {
568         if ( $basketgroupinfo->{$field} ) {
569             $query .= "$field, ";
570             push(@params, $basketgroupinfo->{$field});
571         }
572     }
573     $query .= "booksellerid) VALUES (";
574     foreach (@params) {
575         $query .= "?, ";
576     }
577     $query .= "?)";
578     push(@params, $basketgroupinfo->{'booksellerid'});
579     my $dbh = C4::Context->dbh;
580     my $sth = $dbh->prepare($query);
581     $sth->execute(@params);
582     my $basketgroupid = $dbh->{'mysql_insertid'};
583     if( $basketgroupinfo->{'basketlist'} ) {
584         foreach my $basketno (@{$basketgroupinfo->{'basketlist'}}) {
585             my $query2 = "UPDATE aqbasket SET basketgroupid=? WHERE basketno=?";
586             my $sth2 = $dbh->prepare($query2);
587             $sth2->execute($basketgroupid, $basketno);
588         }
589     }
590     return $basketgroupid;
591 }
592
593 #------------------------------------------------------------#
594
595 =head3 ModBasketgroup
596
597 =over 4
598
599 ModBasketgroup(\%hashref);
600
601 =over 2
602
603 Modifies a basketgroup in the aqbasketgroups table, and add the baskets to it.
604
605 $hashref->{'id'} is the 'id' field of the basketgroup in the aqbasketgroup table, this parameter is mandatory,
606
607 $hashref->{'name'} is the 'name' field of the basketgroup in the aqbasketgroups table,
608
609 $hashref->{'basketlist'} is a list reference of the 'id's of the baskets that belong to this group,
610
611 $hashref->{'billingplace'} is the 'billingplace' field of the basketgroup in the aqbasketgroups table,
612
613 $hashref->{'deliveryplace'} is the 'deliveryplace' field of the basketgroup in the aqbasketgroups table,
614
615 $hashref->{'deliverycomment'} is the 'deliverycomment' field of the basketgroup in the aqbasketgroups table,
616
617 $hashref->{'closed'} is the 'closed' field of the aqbasketgroups table, it is false if 0, true otherwise.
618
619 =back
620
621 =back
622
623 =cut
624
625 sub ModBasketgroup {
626     my $basketgroupinfo = shift;
627     die "basketgroup id is required to edit a basketgroup" unless $basketgroupinfo->{'id'};
628     my $dbh = C4::Context->dbh;
629     my $query = "UPDATE aqbasketgroups SET ";
630     my @params;
631     foreach my $field (qw(name billingplace deliveryplace deliverycomment closed)) {
632         if ( defined $basketgroupinfo->{$field} ) {
633             $query .= "$field=?, ";
634             push(@params, $basketgroupinfo->{$field});
635         }
636     }
637     chop($query);
638     chop($query);
639     $query .= " WHERE id=?";
640     push(@params, $basketgroupinfo->{'id'});
641     my $sth = $dbh->prepare($query);
642     $sth->execute(@params);
643
644     $sth = $dbh->prepare('UPDATE aqbasket SET basketgroupid = NULL WHERE basketgroupid = ?');
645     $sth->execute($basketgroupinfo->{'id'});
646
647     if($basketgroupinfo->{'basketlist'} && @{$basketgroupinfo->{'basketlist'}}){
648         $sth = $dbh->prepare("UPDATE aqbasket SET basketgroupid=? WHERE basketno=?");
649         foreach my $basketno (@{$basketgroupinfo->{'basketlist'}}) {
650             $sth->execute($basketgroupinfo->{'id'}, $basketno);
651             $sth->finish;
652         }
653     }
654     $sth->finish;
655 }
656
657 #------------------------------------------------------------#
658
659 =head3 DelBasketgroup
660
661 =over 4
662
663 DelBasketgroup($basketgroupid);
664
665 =back
666
667 Deletes a basketgroup in the aqbasketgroups table, and removes the reference to it from the baskets,
668
669 =over 2
670
671 =item C<$basketgroupid> is the 'id' field of the basket in the aqbasketgroup table
672
673 =back
674
675 =cut
676
677 sub DelBasketgroup {
678     my $basketgroupid = shift;
679     die "basketgroup id is required to edit a basketgroup" unless $basketgroupid;
680     my $query = "DELETE FROM aqbasketgroups WHERE id=?";
681     my $dbh = C4::Context->dbh;
682     my $sth = $dbh->prepare($query);
683     $sth->execute($basketgroupid);
684     $sth->finish;
685 }
686
687 #------------------------------------------------------------#
688
689
690 =head2 FUNCTIONS ABOUT ORDERS
691
692 =over 2
693
694 =cut
695
696 =back
697
698 =head3 GetBasketgroup
699
700 =over 4
701
702 $basketgroup = &GetBasketgroup($basketgroupid);
703
704 =over 2
705
706 Returns a reference to the hash containing all infermation about the basketgroup.
707
708 =back
709
710 =back
711
712 =cut
713
714 sub GetBasketgroup {
715     my $basketgroupid = shift;
716     die "basketgroup id is required to edit a basketgroup" unless $basketgroupid;
717     my $query = "SELECT * FROM aqbasketgroups WHERE id=?";
718     my $dbh = C4::Context->dbh;
719     my $sth = $dbh->prepare($query);
720     $sth->execute($basketgroupid);
721     my $result = $sth->fetchrow_hashref;
722     $sth->finish;
723     return $result
724 }
725
726 #------------------------------------------------------------#
727
728 =head3 GetBasketgroups
729
730 =over 4
731
732 $basketgroups = &GetBasketgroups($booksellerid);
733
734 =over 2
735
736 Returns a reference to the array of all the basketgroups of bookseller $booksellerid.
737
738 =back
739
740 =back
741
742 =cut
743
744 sub GetBasketgroups {
745     my $booksellerid = shift;
746     die "bookseller id is required to edit a basketgroup" unless $booksellerid;
747     my $query = "SELECT * FROM aqbasketgroups WHERE booksellerid=?";
748     my $dbh = C4::Context->dbh;
749     my $sth = $dbh->prepare($query);
750     $sth->execute($booksellerid);
751     my $results = $sth->fetchall_arrayref({});
752     $sth->finish;
753     return $results
754 }
755
756 #------------------------------------------------------------#
757
758 =head2 FUNCTIONS ABOUT ORDERS
759
760 =cut
761
762 #------------------------------------------------------------#
763
764 =head3 GetPendingOrders
765
766 =over 4
767
768 $orders = &GetPendingOrders($booksellerid, $grouped, $owner);
769
770 Finds pending orders from the bookseller with the given ID. Ignores
771 completed and cancelled orders.
772
773 C<$booksellerid> contains the bookseller identifier
774 C<$grouped> contains 0 or 1. 0 means returns the list, 1 means return the total
775 C<$owner> contains 0 or 1. 0 means any owner. 1 means only the list of orders entered by the user itself.
776
777 C<$orders> is a reference-to-array; each element is a
778 reference-to-hash with the following fields:
779 C<$grouped> is a boolean that, if set to 1 will group all order lines of the same basket
780 in a single result line
781
782 =over 2
783
784 =item C<authorizedby>
785
786 =item C<entrydate>
787
788 =item C<basketno>
789
790 These give the value of the corresponding field in the aqorders table
791 of the Koha database.
792
793 =back
794
795 =back
796
797 Results are ordered from most to least recent.
798
799 =cut
800
801 sub GetPendingOrders {
802     my ($supplierid,$grouped,$owner,$basketno) = @_;
803     my $dbh = C4::Context->dbh;
804     my $strsth = "
805         SELECT    ".($grouped?"count(*),":"")."aqbasket.basketno,
806                     surname,firstname,aqorders.*,biblio.*,biblioitems.isbn,
807                     aqbasket.closedate, aqbasket.creationdate, aqbasket.basketname
808         FROM      aqorders
809         LEFT JOIN aqbasket ON aqbasket.basketno=aqorders.basketno
810         LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber
811         LEFT JOIN biblio ON biblio.biblionumber=aqorders.biblionumber
812         LEFT JOIN biblioitems ON biblioitems.biblionumber=biblio.biblionumber
813         WHERE booksellerid=?
814             AND (quantity > quantityreceived OR quantityreceived is NULL)
815             AND datecancellationprinted IS NULL
816             AND (to_days(now())-to_days(closedate) < 180 OR closedate IS NULL)
817     ";
818     ## FIXME  Why 180 days ???
819     my @query_params = ( $supplierid );
820     my $userenv = C4::Context->userenv;
821     if ( C4::Context->preference("IndependantBranches") ) {
822         if ( ($userenv) && ( $userenv->{flags} != 1 ) ) {
823             $strsth .= " and (borrowers.branchcode = ?
824                         or borrowers.branchcode  = '')";
825             push @query_params, $userenv->{branch};
826         }
827     }
828     if ($owner) {
829         $strsth .= " AND aqbasket.authorisedby=? ";
830         push @query_params, $userenv->{'number'};
831     }
832     if ($basketno) {
833         $strsth .= " AND aqbasket.basketno=? ";
834         push @query_params, $basketno;
835     }
836     $strsth .= " group by aqbasket.basketno" if $grouped;
837     $strsth .= " order by aqbasket.basketno";
838
839     my $sth = $dbh->prepare($strsth);
840     $sth->execute( @query_params );
841     my $results = $sth->fetchall_arrayref({});
842     $sth->finish;
843     return $results;
844 }
845
846 #------------------------------------------------------------#
847
848 =head3 GetOrders
849
850 =over 4
851
852 @orders = &GetOrders($basketnumber, $orderby);
853
854 Looks up the pending (non-cancelled) orders with the given basket
855 number. If C<$booksellerID> is non-empty, only orders from that seller
856 are returned.
857
858 return :
859 C<&basket> returns a two-element array. C<@orders> is an array of
860 references-to-hash, whose keys are the fields from the aqorders,
861 biblio, and biblioitems tables in the Koha database.
862
863 =back
864
865 =cut
866
867 sub GetOrders {
868     my ( $basketno, $orderby ) = @_;
869     my $dbh   = C4::Context->dbh;
870     my $query  ="
871         SELECT biblio.*,biblioitems.*,
872                 aqorders.*,
873                 aqbudgets.*,
874                 biblio.title
875         FROM    aqorders
876             LEFT JOIN aqbudgets        ON aqbudgets.budget_id = aqorders.budget_id
877             LEFT JOIN biblio           ON biblio.biblionumber = aqorders.biblionumber
878             LEFT JOIN biblioitems      ON biblioitems.biblionumber =biblio.biblionumber
879         WHERE   basketno=?
880             AND (datecancellationprinted IS NULL OR datecancellationprinted='0000-00-00')
881     ";
882
883     $orderby = "biblioitems.publishercode,biblio.title" unless $orderby;
884     $query .= " ORDER BY $orderby";
885     my $sth = $dbh->prepare($query);
886     $sth->execute($basketno);
887     my $results = $sth->fetchall_arrayref({});
888     $sth->finish;
889     return @$results;
890 }
891
892 #------------------------------------------------------------#
893
894 =head3 GetOrderNumber
895
896 =over 4
897
898 $ordernumber = &GetOrderNumber($biblioitemnumber, $biblionumber);
899
900 =back
901
902 Looks up the ordernumber with the given biblionumber and biblioitemnumber.
903
904 Returns the number of this order.
905
906 =over 4
907
908 =item C<$ordernumber> is the order number.
909
910 =back
911
912 =cut
913 sub GetOrderNumber {
914     my ( $biblionumber,$biblioitemnumber ) = @_;
915     my $dbh = C4::Context->dbh;
916     my $query = "
917         SELECT ordernumber
918         FROM   aqorders
919         WHERE  biblionumber=?
920         AND    biblioitemnumber=?
921     ";
922     my $sth = $dbh->prepare($query);
923     $sth->execute( $biblionumber, $biblioitemnumber );
924
925     return $sth->fetchrow;
926 }
927
928 #------------------------------------------------------------#
929
930 =head3 GetOrder
931
932 =over 4
933
934 $order = &GetOrder($ordernumber);
935
936 Looks up an order by order number.
937
938 Returns a reference-to-hash describing the order. The keys of
939 C<$order> are fields from the biblio, biblioitems, aqorders tables of the Koha database.
940
941 =back
942
943 =cut
944
945 sub GetOrder {
946     my ($ordernumber) = @_;
947     my $dbh      = C4::Context->dbh;
948     my $query = "
949         SELECT biblioitems.*, biblio.*, aqorders.*
950         FROM   aqorders
951         LEFT JOIN biblio on           biblio.biblionumber=aqorders.biblionumber
952         LEFT JOIN biblioitems on       biblioitems.biblionumber=aqorders.biblionumber
953         WHERE aqorders.ordernumber=?
954
955     ";
956     my $sth= $dbh->prepare($query);
957     $sth->execute($ordernumber);
958     my $data = $sth->fetchrow_hashref;
959     $sth->finish;
960     return $data;
961 }
962
963 #------------------------------------------------------------#
964
965 =head3 NewOrder
966
967 =over 4
968
969 &NewOrder(\%hashref);
970
971 Adds a new order to the database. Any argument that isn't described
972 below is the new value of the field with the same name in the aqorders
973 table of the Koha database.
974
975 =over 4
976
977 =item $hashref->{'basketno'} is the basketno foreign key in aqorders, it is mandatory
978
979
980 =item $hashref->{'ordernumber'} is a "minimum order number."
981
982 =item $hashref->{'budgetdate'} is effectively ignored.
983 If it's undef (anything false) or the string 'now', the current day is used.
984 Else, the upcoming July 1st is used.
985
986 =item $hashref->{'subscription'} may be either "yes", or anything else for "no".
987
988 =item $hashref->{'uncertainprice'} may be 0 for "the price is known" or 1 for "the price is uncertain"
989
990 =item defaults entrydate to Now
991
992 The following keys are used: "biblionumber", "title", "basketno", "quantity", "notes", "biblioitemnumber", "rrp", "ecost", "gst", "unitprice", "subscription", "sort1", "sort2", "booksellerinvoicenumber", "listprice", "budgetdate", "purchaseordernumber", "branchcode", "booksellerinvoicenumber", "bookfundid".
993
994 =back
995
996 =back
997
998 =cut
999
1000 sub NewOrder {
1001     my $orderinfo = shift;
1002 #### ------------------------------
1003     my $dbh = C4::Context->dbh;
1004     my @params;
1005
1006
1007     # if these parameters are missing, we can't continue
1008     for my $key (qw/basketno quantity biblionumber budget_id/) {
1009         die "Mandatory parameter $key missing" unless $orderinfo->{$key};
1010     }
1011
1012     if ( $orderinfo->{'subscription'} eq 'yes' ) {
1013         $orderinfo->{'subscription'} = 1;
1014     } else {
1015         $orderinfo->{'subscription'} = 0;
1016     }
1017     $orderinfo->{'entrydate'} ||= C4::Dates->new()->output("iso");
1018
1019     my $ordernumber=InsertInTable("aqorders",$orderinfo);
1020     return ( $orderinfo->{'basketno'}, $ordernumber );
1021 }
1022
1023
1024
1025 #------------------------------------------------------------#
1026
1027 =head3 NewOrderItem
1028
1029 =over 4
1030
1031 &NewOrderItem();
1032
1033
1034 =back
1035
1036 =cut
1037
1038 sub NewOrderItem {
1039     #my ($biblioitemnumber,$ordernumber, $biblionumber) = @_;
1040     my ($itemnumber, $ordernumber)  = @_;
1041     my $dbh = C4::Context->dbh;
1042     my $query = qq|
1043             INSERT INTO aqorders_items
1044                 (itemnumber, ordernumber)
1045             VALUES (?,?)    |;
1046
1047     my $sth = $dbh->prepare($query);
1048     $sth->execute( $itemnumber, $ordernumber);
1049 }
1050
1051 #------------------------------------------------------------#
1052
1053 =head3 ModOrder
1054
1055 =over 4
1056
1057 &ModOrder(\%hashref);
1058
1059 =over 2
1060
1061 Modifies an existing order. Updates the order with order number
1062 $hashref->{'ordernumber'} and biblionumber $hashref->{'biblionumber'}. All other keys of the hash
1063 update the fields with the same name in the aqorders table of the Koha database.
1064
1065 =back
1066
1067 =back
1068
1069 =cut
1070
1071 sub ModOrder {
1072     my $orderinfo = shift;
1073
1074     die "Ordernumber is required"     if $orderinfo->{'ordernumber'} eq  '' ;
1075     die "Biblionumber is required"  if  $orderinfo->{'biblionumber'} eq '';
1076
1077     my $dbh = C4::Context->dbh;
1078     my @params;
1079 #    delete($orderinfo->{'branchcode'});
1080     # the hash contains a lot of entries not in aqorders, so get the columns ...
1081     my $sth = $dbh->prepare("SELECT * FROM aqorders LIMIT 1;");
1082     $sth->execute;
1083     my $colnames = $sth->{NAME};
1084     my $query = "UPDATE aqorders SET ";
1085
1086     foreach my $orderinfokey (grep(!/ordernumber/, keys %$orderinfo)){
1087         # ... and skip hash entries that are not in the aqorders table
1088         # FIXME : probably not the best way to do it (would be better to have a correct hash)
1089         next unless grep(/^$orderinfokey$/, @$colnames);
1090             $query .= "$orderinfokey=?, ";
1091             push(@params, $orderinfo->{$orderinfokey});
1092     }
1093
1094     $query .= "timestamp=NOW()  WHERE  ordernumber=?";
1095 #   push(@params, $specorderinfo{'ordernumber'});
1096     push(@params, $orderinfo->{'ordernumber'} );
1097     $sth = $dbh->prepare($query);
1098     $sth->execute(@params);
1099     $sth->finish;
1100 }
1101
1102 #------------------------------------------------------------#
1103
1104 =head3 ModOrderItem
1105
1106 =over 4
1107
1108 &ModOrderItem(\%hashref);
1109
1110 =over 2
1111
1112 Modifies the itemnumber in the aqorders_items table. The input hash needs three entities:
1113 - itemnumber: the old itemnumber
1114 - ordernumber: the order this item is attached to
1115 - newitemnumber: the new itemnumber we want to attach the line to
1116
1117 =back
1118
1119 =back
1120
1121 =cut
1122
1123 sub ModOrderItem {
1124     my $orderiteminfo = shift;
1125     if (! $orderiteminfo->{'ordernumber'} || ! $orderiteminfo->{'itemnumber'} || ! $orderiteminfo->{'newitemnumber'}){
1126         die "Ordernumber, itemnumber and newitemnumber is required";
1127     }
1128
1129     my $dbh = C4::Context->dbh;
1130
1131     my $query = "UPDATE aqorders_items set itemnumber=? where itemnumber=? and ordernumber=?";
1132     my @params = ($orderiteminfo->{'newitemnumber'}, $orderiteminfo->{'itemnumber'}, $orderiteminfo->{'ordernumber'});
1133     warn $query;
1134     warn Data::Dumper::Dumper(@params);
1135     my $sth = $dbh->prepare($query);
1136     $sth->execute(@params);
1137     return 0;
1138 }
1139
1140 #------------------------------------------------------------#
1141
1142
1143 =head3 ModOrderBibliotemNumber
1144
1145 =over 4
1146
1147 &ModOrderBiblioitemNumber($biblioitemnumber,$ordernumber, $biblionumber);
1148
1149 Modifies the biblioitemnumber for an existing order.
1150 Updates the order with order number C<$ordernum> and biblionumber C<$biblionumber>.
1151
1152 =back
1153
1154 =cut
1155
1156 #FIXME: is this used at all?
1157 sub ModOrderBiblioitemNumber {
1158     my ($biblioitemnumber,$ordernumber, $biblionumber) = @_;
1159     my $dbh = C4::Context->dbh;
1160     my $query = "
1161     UPDATE aqorders
1162     SET    biblioitemnumber = ?
1163     WHERE  ordernumber = ?
1164     AND biblionumber =  ?";
1165     my $sth = $dbh->prepare($query);
1166     $sth->execute( $biblioitemnumber, $ordernumber, $biblionumber );
1167 }
1168
1169 #------------------------------------------------------------#
1170
1171 =head3 ModReceiveOrder
1172
1173 =over 4
1174
1175 &ModReceiveOrder($biblionumber, $ordernumber, $quantityreceived, $user,
1176     $unitprice, $booksellerinvoicenumber, $biblioitemnumber,
1177     $freight, $bookfund, $rrp);
1178
1179 Updates an order, to reflect the fact that it was received, at least
1180 in part. All arguments not mentioned below update the fields with the
1181 same name in the aqorders table of the Koha database.
1182
1183 If a partial order is received, splits the order into two.  The received
1184 portion must have a booksellerinvoicenumber.
1185
1186 Updates the order with bibilionumber C<$biblionumber> and ordernumber
1187 C<$ordernumber>.
1188
1189 =back
1190
1191 =cut
1192
1193
1194 sub ModReceiveOrder {
1195     my (
1196         $biblionumber,    $ordernumber,  $quantrec, $user, $cost,
1197         $invoiceno, $freight, $rrp, $budget_id, $datereceived
1198     )
1199     = @_;
1200     my $dbh = C4::Context->dbh;
1201 #     warn "DATE BEFORE : $daterecieved";
1202 #    $daterecieved=POSIX::strftime("%Y-%m-%d",CORE::localtime) unless $daterecieved;
1203 #     warn "DATE REC : $daterecieved";
1204     $datereceived = C4::Dates->output('iso') unless $datereceived;
1205     my $suggestionid = GetSuggestionFromBiblionumber( $dbh, $biblionumber );
1206     if ($suggestionid) {
1207         ModSuggestion( {suggestionid=>$suggestionid,
1208                                                 STATUS=>'AVAILABLE',
1209                                                 biblionumber=> $biblionumber}
1210                                                 );
1211     }
1212
1213     my $sth=$dbh->prepare("
1214         SELECT * FROM   aqorders
1215         WHERE           biblionumber=? AND aqorders.ordernumber=?");
1216
1217     $sth->execute($biblionumber,$ordernumber);
1218     my $order = $sth->fetchrow_hashref();
1219     $sth->finish();
1220
1221     if ( $order->{quantity} > $quantrec ) {
1222         $sth=$dbh->prepare("
1223             UPDATE aqorders
1224             SET quantityreceived=?
1225                 , datereceived=?
1226                 , booksellerinvoicenumber=?
1227                 , unitprice=?
1228                 , freight=?
1229                 , rrp=?
1230                 , quantity=?
1231             WHERE biblionumber=? AND ordernumber=?");
1232
1233         $sth->execute($quantrec,$datereceived,$invoiceno,$cost,$freight,$rrp,$quantrec,$biblionumber,$ordernumber);
1234         $sth->finish;
1235
1236         # create a new order for the remaining items, and set its bookfund.
1237         foreach my $orderkey ( "linenumber", "allocation" ) {
1238             delete($order->{'$orderkey'});
1239         }
1240         $order->{'quantity'} -= $quantrec;
1241         $order->{'quantityreceived'} = 0;
1242         my $newOrder = NewOrder($order);
1243 } else {
1244         $sth=$dbh->prepare("update aqorders
1245                             set quantityreceived=?,datereceived=?,booksellerinvoicenumber=?,
1246                                 unitprice=?,freight=?,rrp=?
1247                             where biblionumber=? and ordernumber=?");
1248         $sth->execute($quantrec,$datereceived,$invoiceno,$cost,$freight,$rrp,$biblionumber,$ordernumber);
1249         $sth->finish;
1250     }
1251     return $datereceived;
1252 }
1253 #------------------------------------------------------------#
1254
1255 =head3 SearchOrder
1256
1257 @results = &SearchOrder($search, $biblionumber, $complete);
1258
1259 Searches for orders.
1260
1261 C<$search> may take one of several forms: if it is an ISBN,
1262 C<&ordersearch> returns orders with that ISBN. If C<$search> is an
1263 order number, C<&ordersearch> returns orders with that order number
1264 and biblionumber C<$biblionumber>. Otherwise, C<$search> is considered
1265 to be a space-separated list of search terms; in this case, all of the
1266 terms must appear in the title (matching the beginning of title
1267 words).
1268
1269 If C<$complete> is C<yes>, the results will include only completed
1270 orders. In any case, C<&ordersearch> ignores cancelled orders.
1271
1272 C<&ordersearch> returns an array.
1273 C<@results> is an array of references-to-hash with the following keys:
1274
1275 =over 4
1276
1277 =item C<author>
1278
1279 =item C<seriestitle>
1280
1281 =item C<branchcode>
1282
1283 =item C<bookfundid>
1284
1285 =back
1286
1287 =cut
1288
1289 sub SearchOrder {
1290 #### -------- SearchOrder-------------------------------
1291     my ($ordernumber, $search, $supplierid, $basket) = @_;
1292
1293     my $dbh = C4::Context->dbh;
1294     my @args = ();
1295     my $query =
1296             "SELECT *
1297             FROM aqorders
1298             LEFT JOIN biblio ON aqorders.biblionumber=biblio.biblionumber
1299             LEFT JOIN biblioitems ON biblioitems.biblionumber=biblio.biblionumber
1300             LEFT JOIN aqbasket ON aqorders.basketno = aqbasket.basketno
1301                 WHERE  (datecancellationprinted is NULL)";
1302
1303     if($ordernumber){
1304         $query .= " AND (aqorders.ordernumber=?)";
1305         push @args, $ordernumber;
1306     }
1307     if($search){
1308         $query .= " AND (biblio.title like ? OR biblio.author LIKE ? OR biblioitems.isbn like ?)";
1309         push @args, ("%$search%","%$search%","%$search%");
1310     }
1311     if($supplierid){
1312         $query .= "AND aqbasket.booksellerid = ?";
1313         push @args, $supplierid;
1314     }
1315     if($basket){
1316         $query .= "AND aqorders.basketno = ?";
1317         push @args, $basket;
1318     }
1319
1320     my $sth = $dbh->prepare($query);
1321     $sth->execute(@args);
1322     my $results = $sth->fetchall_arrayref({});
1323     $sth->finish;
1324     return $results;
1325 }
1326
1327 #------------------------------------------------------------#
1328
1329 =head3 DelOrder
1330
1331 =over 4
1332
1333 &DelOrder($biblionumber, $ordernumber);
1334
1335 Cancel the order with the given order and biblio numbers. It does not
1336 delete any entries in the aqorders table, it merely marks them as
1337 cancelled.
1338
1339 =back
1340
1341 =cut
1342
1343 sub DelOrder {
1344     my ( $bibnum, $ordernumber ) = @_;
1345     my $dbh = C4::Context->dbh;
1346     my $query = "
1347         UPDATE aqorders
1348         SET    datecancellationprinted=now()
1349         WHERE  biblionumber=? AND ordernumber=?
1350     ";
1351     my $sth = $dbh->prepare($query);
1352     $sth->execute( $bibnum, $ordernumber );
1353     $sth->finish;
1354 }
1355
1356 =head2 FUNCTIONS ABOUT PARCELS
1357
1358 =cut
1359
1360 #------------------------------------------------------------#
1361
1362 =head3 GetParcel
1363
1364 =over 4
1365
1366 @results = &GetParcel($booksellerid, $code, $date);
1367
1368 Looks up all of the received items from the supplier with the given
1369 bookseller ID at the given date, for the given code (bookseller Invoice number). Ignores cancelled and completed orders.
1370
1371 C<@results> is an array of references-to-hash. The keys of each element are fields from
1372 the aqorders, biblio, and biblioitems tables of the Koha database.
1373
1374 C<@results> is sorted alphabetically by book title.
1375
1376 =back
1377
1378 =cut
1379
1380 sub GetParcel {
1381     #gets all orders from a certain supplier, orders them alphabetically
1382     my ( $supplierid, $code, $datereceived ) = @_;
1383     my $dbh     = C4::Context->dbh;
1384     my @results = ();
1385     $code .= '%'
1386     if $code;  # add % if we search on a given code (otherwise, let him empty)
1387     my $strsth ="
1388         SELECT  authorisedby,
1389                 creationdate,
1390                 aqbasket.basketno,
1391                 closedate,surname,
1392                 firstname,
1393                 aqorders.biblionumber,
1394                 aqorders.ordernumber,
1395                 aqorders.quantity,
1396                 aqorders.quantityreceived,
1397                 aqorders.unitprice,
1398                 aqorders.listprice,
1399                 aqorders.rrp,
1400                 aqorders.ecost,
1401                 biblio.title
1402         FROM aqorders
1403         LEFT JOIN aqbasket ON aqbasket.basketno=aqorders.basketno
1404         LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber
1405         LEFT JOIN biblio ON aqorders.biblionumber=biblio.biblionumber
1406         WHERE
1407             aqbasket.booksellerid = ?
1408             AND aqorders.booksellerinvoicenumber LIKE ?
1409             AND aqorders.datereceived = ? ";
1410
1411     my @query_params = ( $supplierid, $code, $datereceived );
1412     if ( C4::Context->preference("IndependantBranches") ) {
1413         my $userenv = C4::Context->userenv;
1414         if ( ($userenv) && ( $userenv->{flags} != 1 ) ) {
1415             $strsth .= " and (borrowers.branchcode = ?
1416                         or borrowers.branchcode  = '')";
1417             push @query_params, $userenv->{branch};
1418         }
1419     }
1420     $strsth .= " ORDER BY aqbasket.basketno";
1421     # ## parcelinformation : $strsth
1422     my $sth = $dbh->prepare($strsth);
1423     $sth->execute( @query_params );
1424     while ( my $data = $sth->fetchrow_hashref ) {
1425         push( @results, $data );
1426     }
1427     # ## countparcelbiblio: scalar(@results)
1428     $sth->finish;
1429
1430     return @results;
1431 }
1432
1433 #------------------------------------------------------------#
1434
1435 =head3 GetParcels
1436
1437 =over 4
1438
1439 $results = &GetParcels($bookseller, $order, $code, $datefrom, $dateto);
1440 get a lists of parcels.
1441
1442 =back
1443
1444 * Input arg :
1445
1446 =over 4
1447
1448 =item $bookseller
1449 is the bookseller this function has to get parcels.
1450
1451 =item $order
1452 To know on what criteria the results list has to be ordered.
1453
1454 =item $code
1455 is the booksellerinvoicenumber.
1456
1457 =item $datefrom & $dateto
1458 to know on what date this function has to filter its search.
1459
1460 * return:
1461 a pointer on a hash list containing parcel informations as such :
1462
1463 =item Creation date
1464
1465 =item Last operation
1466
1467 =item Number of biblio
1468
1469 =item Number of items
1470
1471 =back
1472
1473 =cut
1474
1475 sub GetParcels {
1476     my ($bookseller,$order, $code, $datefrom, $dateto) = @_;
1477     my $dbh    = C4::Context->dbh;
1478     my @query_params = ();
1479     my $strsth ="
1480         SELECT  aqorders.booksellerinvoicenumber,
1481                 datereceived,purchaseordernumber,
1482                 count(DISTINCT biblionumber) AS biblio,
1483                 sum(quantity) AS itemsexpected,
1484                 sum(quantityreceived) AS itemsreceived
1485         FROM   aqorders LEFT JOIN aqbasket ON aqbasket.basketno = aqorders.basketno
1486         WHERE aqbasket.booksellerid = $bookseller and datereceived IS NOT NULL
1487     ";
1488
1489     if ( defined $code ) {
1490         $strsth .= ' and aqorders.booksellerinvoicenumber like ? ';
1491         # add a % to the end of the code to allow stemming.
1492         push @query_params, "$code%";
1493     }
1494
1495     if ( defined $datefrom ) {
1496         $strsth .= ' and datereceived >= ? ';
1497         push @query_params, $datefrom;
1498     }
1499
1500     if ( defined $dateto ) {
1501         $strsth .=  'and datereceived <= ? ';
1502         push @query_params, $dateto;
1503     }
1504
1505     $strsth .= "group by aqorders.booksellerinvoicenumber,datereceived ";
1506
1507     # can't use a placeholder to place this column name.
1508     # but, we could probably be checking to make sure it is a column that will be fetched.
1509     $strsth .= "order by $order " if ($order);
1510
1511     my $sth = $dbh->prepare($strsth);
1512
1513     $sth->execute( @query_params );
1514     my $results = $sth->fetchall_arrayref({});
1515     $sth->finish;
1516     return @$results;
1517 }
1518
1519 #------------------------------------------------------------#
1520
1521 =head3 GetLateOrders
1522
1523 =over 4
1524
1525 @results = &GetLateOrders;
1526
1527 Searches for bookseller with late orders.
1528
1529 return:
1530 the table of supplier with late issues. This table is full of hashref.
1531
1532 =back
1533
1534 =cut
1535
1536 sub GetLateOrders {
1537     my $delay      = shift;
1538     my $supplierid = shift;
1539     my $branch     = shift;
1540
1541     my $dbh = C4::Context->dbh;
1542
1543     #BEWARE, order of parenthesis and LEFT JOIN is important for speed
1544     my $dbdriver = C4::Context->config("db_scheme") || "mysql";
1545
1546     my @query_params = ($delay);        # delay is the first argument regardless
1547     my $select = "
1548     SELECT aqbasket.basketno,
1549         aqorders.ordernumber,
1550         DATE(aqbasket.closedate)  AS orderdate,
1551         aqorders.rrp              AS unitpricesupplier,
1552         aqorders.ecost            AS unitpricelib,
1553         aqbudgets.budget_name     AS budget,
1554         borrowers.branchcode      AS branch,
1555         aqbooksellers.name        AS supplier,
1556         biblio.author,
1557         biblioitems.publishercode AS publisher,
1558         biblioitems.publicationyear,
1559     ";
1560     my $from = "
1561     FROM
1562         aqorders LEFT JOIN biblio     ON biblio.biblionumber         = aqorders.biblionumber
1563         LEFT JOIN biblioitems         ON biblioitems.biblionumber    = biblio.biblionumber
1564         LEFT JOIN aqbudgets           ON aqorders.budget_id          = aqbudgets.budget_id,
1565         aqbasket LEFT JOIN borrowers  ON aqbasket.authorisedby       = borrowers.borrowernumber
1566         LEFT JOIN aqbooksellers       ON aqbasket.booksellerid       = aqbooksellers.id
1567         WHERE aqorders.basketno = aqbasket.basketno
1568         AND ( datereceived = ''
1569             OR datereceived IS NULL
1570             OR aqorders.quantityreceived < aqorders.quantity
1571         )
1572     ";
1573     my $having = "";
1574     if ($dbdriver eq "mysql") {
1575         $select .= "
1576         aqorders.quantity - IFNULL(aqorders.quantityreceived,0)                 AS quantity,
1577         (aqorders.quantity - IFNULL(aqorders.quantityreceived,0)) * aqorders.rrp AS subtotal,
1578         DATEDIFF(CURDATE( ),closedate) AS latesince
1579         ";
1580         $from .= " AND (closedate <= DATE_SUB(CURDATE( ),INTERVAL ? DAY)) ";
1581         $having = "
1582         HAVING quantity          <> 0
1583             AND unitpricesupplier <> 0
1584             AND unitpricelib      <> 0
1585         ";
1586     } else {
1587         # FIXME: account for IFNULL as above
1588         $select .= "
1589                 aqorders.quantity                AS quantity,
1590                 aqorders.quantity * aqorders.rrp AS subtotal,
1591                 (CURDATE - closedate)            AS latesince
1592         ";
1593         $from .= " AND (closedate <= (CURDATE -(INTERVAL ? DAY)) ";
1594     }
1595     if (defined $supplierid) {
1596         $from .= ' AND aqbasket.booksellerid = ? ';
1597         push @query_params, $supplierid;
1598     }
1599     if (defined $branch) {
1600         $from .= ' AND borrowers.branchcode LIKE ? ';
1601         push @query_params, $branch;
1602     }
1603     if (C4::Context->preference("IndependantBranches")
1604             && C4::Context->userenv
1605             && C4::Context->userenv->{flags} != 1 ) {
1606         $from .= ' AND borrowers.branchcode LIKE ? ';
1607         push @query_params, C4::Context->userenv->{branch};
1608     }
1609     my $query = "$select $from $having\nORDER BY latesince, basketno, borrowers.branchcode, supplier";
1610     $debug and print STDERR "GetLateOrders query: $query\nGetLateOrders args: " . join(" ",@query_params);
1611     my $sth = $dbh->prepare($query);
1612     $sth->execute(@query_params);
1613     my @results;
1614     while (my $data = $sth->fetchrow_hashref) {
1615         $data->{orderdate} = format_date($data->{orderdate});
1616         push @results, $data;
1617     }
1618     return @results;
1619 }
1620
1621 #------------------------------------------------------------#
1622
1623 =head3 GetHistory
1624
1625 =over 4
1626
1627 (\@order_loop, $total_qty, $total_price, $total_qtyreceived) = GetHistory( $title, $author, $name, $from_placed_on, $to_placed_on );
1628
1629 Retreives some acquisition history information
1630
1631 returns:
1632     $order_loop is a list of hashrefs that each look like this:
1633             {
1634                 'author'           => 'Twain, Mark',
1635                 'basketno'         => '1',
1636                 'biblionumber'     => '215',
1637                 'count'            => 1,
1638                 'creationdate'     => 'MM/DD/YYYY',
1639                 'datereceived'     => undef,
1640                 'ecost'            => '1.00',
1641                 'id'               => '1',
1642                 'invoicenumber'    => undef,
1643                 'name'             => '',
1644                 'ordernumber'      => '1',
1645                 'quantity'         => 1,
1646                 'quantityreceived' => undef,
1647                 'title'            => 'The Adventures of Huckleberry Finn'
1648             }
1649     $total_qty is the sum of all of the quantities in $order_loop
1650     $total_price is the cost of each in $order_loop times the quantity
1651     $total_qtyreceived is the sum of all of the quantityreceived entries in $order_loop
1652
1653 =back
1654
1655 =cut
1656
1657 sub GetHistory {
1658     my ( $title, $author, $name, $from_placed_on, $to_placed_on ) = @_;
1659     my @order_loop;
1660     my $total_qty         = 0;
1661     my $total_qtyreceived = 0;
1662     my $total_price       = 0;
1663
1664 # don't run the query if there are no parameters (list would be too long for sure !)
1665     if ( $title || $author || $name || $from_placed_on || $to_placed_on ) {
1666         my $dbh   = C4::Context->dbh;
1667         my $query ="
1668             SELECT
1669                 biblio.title,
1670                 biblio.author,
1671                 aqorders.basketno,
1672                 name,aqbasket.creationdate,
1673                 aqorders.datereceived,
1674                 aqorders.quantity,
1675                 aqorders.quantityreceived,
1676                 aqorders.ecost,
1677                 aqorders.ordernumber,
1678                 aqorders.booksellerinvoicenumber as invoicenumber,
1679                 aqbooksellers.id as id,
1680                 aqorders.biblionumber
1681             FROM aqorders
1682             LEFT JOIN aqbasket ON aqorders.basketno=aqbasket.basketno
1683             LEFT JOIN aqbooksellers ON aqbasket.booksellerid=aqbooksellers.id
1684             LEFT JOIN biblio ON biblio.biblionumber=aqorders.biblionumber";
1685
1686         $query .= " LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber"
1687         if ( C4::Context->preference("IndependantBranches") );
1688
1689         $query .= " WHERE (datecancellationprinted is NULL or datecancellationprinted='0000-00-00') ";
1690
1691         my @query_params  = ();
1692
1693         if ( defined $title ) {
1694             $query .= " AND biblio.title LIKE ? ";
1695             push @query_params, "%$title%";
1696         }
1697
1698         if ( defined $author ) {
1699             $query .= " AND biblio.author LIKE ? ";
1700             push @query_params, "%$author%";
1701         }
1702
1703         if ( defined $name ) {
1704             $query .= " AND name LIKE ? ";
1705             push @query_params, "%$name%";
1706         }
1707
1708         if ( defined $from_placed_on ) {
1709             $query .= " AND creationdate >= ? ";
1710             push @query_params, $from_placed_on;
1711         }
1712
1713         if ( defined $to_placed_on ) {
1714             $query .= " AND creationdate <= ? ";
1715             push @query_params, $to_placed_on;
1716         }
1717
1718         if ( C4::Context->preference("IndependantBranches") ) {
1719             my $userenv = C4::Context->userenv;
1720             if ( ($userenv) && ( $userenv->{flags} != 1 ) ) {
1721                 $query .= " AND (borrowers.branchcode = ? OR borrowers.branchcode ='' ) ";
1722                 push @query_params, $userenv->{branch};
1723             }
1724         }
1725         $query .= " ORDER BY booksellerid";
1726         my $sth = $dbh->prepare($query);
1727         $sth->execute( @query_params );
1728         my $cnt = 1;
1729         while ( my $line = $sth->fetchrow_hashref ) {
1730             $line->{count} = $cnt++;
1731             $line->{toggle} = 1 if $cnt % 2;
1732             push @order_loop, $line;
1733             $line->{creationdate} = format_date( $line->{creationdate} );
1734             $line->{datereceived} = format_date( $line->{datereceived} );
1735             $total_qty         += $line->{'quantity'};
1736             $total_qtyreceived += $line->{'quantityreceived'};
1737             $total_price       += $line->{'quantity'} * $line->{'ecost'};
1738         }
1739     }
1740     return \@order_loop, $total_qty, $total_price, $total_qtyreceived;
1741 }
1742
1743 =head2 GetRecentAcqui
1744
1745 $results = GetRecentAcqui($days);
1746
1747 C<$results> is a ref to a table which containts hashref
1748
1749 =cut
1750
1751 sub GetRecentAcqui {
1752     my $limit  = shift;
1753     my $dbh    = C4::Context->dbh;
1754     my $query = "
1755         SELECT *
1756         FROM   biblio
1757         ORDER BY timestamp DESC
1758         LIMIT  0,".$limit;
1759
1760     my $sth = $dbh->prepare($query);
1761     $sth->execute;
1762     my $results = $sth->fetchall_arrayref({});
1763     return $results;
1764 }
1765
1766 =head3 GetContracts
1767
1768 =over 4
1769
1770 $contractlist = &GetContracts($booksellerid, $activeonly);
1771
1772 =back
1773
1774 Looks up the contracts that belong to a bookseller
1775
1776 Returns a list of contracts
1777
1778 =over 2
1779
1780 =item C<$booksellerid> is the "id" field in the "aqbooksellers" table.
1781
1782 =item C<$activeonly> if exists get only contracts that are still active.
1783
1784 =back
1785
1786 =cut
1787 sub GetContracts {
1788     my ( $booksellerid, $activeonly ) = @_;
1789     my $dbh = C4::Context->dbh;
1790     my $query;
1791     if (! $activeonly) {
1792         $query = "
1793             SELECT *
1794             FROM   aqcontract
1795             WHERE  booksellerid=?
1796         ";
1797     } else {
1798         $query = "SELECT *
1799             FROM aqcontract
1800             WHERE booksellerid=?
1801                 AND contractenddate >= CURDATE( )";
1802     }
1803     my $sth = $dbh->prepare($query);
1804     $sth->execute( $booksellerid );
1805     my @results;
1806     while (my $data = $sth->fetchrow_hashref ) {
1807         push(@results, $data);
1808     }
1809     $sth->finish;
1810     return @results;
1811 }
1812
1813 #------------------------------------------------------------#
1814
1815 =head3 GetContract
1816
1817 =over 4
1818
1819 $contract = &GetContract($contractID);
1820
1821 Looks up the contract that has PRIMKEY (contractnumber) value $contractID
1822
1823 Returns a contract
1824
1825 =back
1826
1827 =cut
1828 sub GetContract {
1829     my ( $contractno ) = @_;
1830     my $dbh = C4::Context->dbh;
1831     my $query = "
1832         SELECT *
1833         FROM   aqcontract
1834         WHERE  contractnumber=?
1835         ";
1836
1837     my $sth = $dbh->prepare($query);
1838     $sth->execute( $contractno );
1839     my $result = $sth->fetchrow_hashref;
1840     return $result;
1841 }
1842
1843 1;
1844 __END__
1845
1846 =head1 AUTHOR
1847
1848 Koha Developement team <info@koha.org>
1849
1850 =cut