use bind variables in C4::Acquisition::GetPendingOrders
[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 C4::Context;
23 use C4::Dates qw(format_date);
24 use MARC::Record;
25 use C4::Suggestions;
26 use Time::localtime;
27
28 use vars qw($VERSION @ISA @EXPORT);
29
30 BEGIN {
31         # set the version for version checking
32         $VERSION = 3.01;
33         require Exporter;
34         @ISA    = qw(Exporter);
35         @EXPORT = qw(
36                 &GetBasket &NewBasket &CloseBasket
37                 &GetPendingOrders &GetOrder &GetOrders
38                 &GetOrderNumber &GetLateOrders &NewOrder &DelOrder
39                 &SearchOrder &GetHistory &GetRecentAcqui
40                 &ModOrder &ModReceiveOrder &ModOrderBiblioNumber
41                 &GetParcels &GetParcel
42         );
43 }
44
45 # used in receiveorder subroutine
46 # to provide library specific handling
47 my $library_name = C4::Context->preference("LibraryName");
48
49 =head1 NAME
50
51 C4::Acquisition - Koha functions for dealing with orders and acquisitions
52
53 =head1 SYNOPSIS
54
55 use C4::Acquisition;
56
57 =head1 DESCRIPTION
58
59 The functions in this module deal with acquisitions, managing book
60 orders, basket and parcels.
61
62 =head1 FUNCTIONS
63
64 =over 2
65
66 =head2 FUNCTIONS ABOUT BASKETS
67
68 =over 2
69
70 =head3 GetBasket
71
72 =over 4
73
74 $aqbasket = &GetBasket($basketnumber);
75
76 get all basket informations in aqbasket for a given basket
77
78 return :
79 informations for a given basket returned as a hashref.
80
81 =back
82
83 =back
84
85 =cut
86
87 sub GetBasket {
88     my ($basketno) = @_;
89     my $dbh        = C4::Context->dbh;
90     my $query = "
91         SELECT  aqbasket.*,
92                 concat( b.firstname,' ',b.surname) AS authorisedbyname,
93                 b.branchcode AS branch
94         FROM    aqbasket
95         LEFT JOIN borrowers b ON aqbasket.authorisedby=b.borrowernumber
96         WHERE basketno=?
97     ";
98     my $sth=$dbh->prepare($query);
99     $sth->execute($basketno);
100     my $basket = $sth->fetchrow_hashref;
101         return ( $basket );
102 }
103
104 #------------------------------------------------------------#
105
106 =head3 NewBasket
107
108 =over 4
109
110 $basket = &NewBasket();
111
112 Create a new basket in aqbasket table
113
114 =back
115
116 =cut
117
118 # FIXME : this function seems to be unused.
119
120 sub NewBasket {
121     my ( $booksellerid, $authorisedby ) = @_;
122     my $dbh = C4::Context->dbh;
123     my $query = "
124         INSERT INTO aqbasket
125                 (creationdate,booksellerid,authorisedby)
126         VALUES  (now(),'$booksellerid','$authorisedby')
127     ";
128     my $sth =
129       $dbh->do($query);
130
131 #find & return basketno MYSQL dependant, but $dbh->last_insert_id always returns null :-(
132     my $basket = $dbh->{'mysql_insertid'};
133     return $basket;
134 }
135
136 #------------------------------------------------------------#
137
138 =head3 CloseBasket
139
140 =over 4
141
142 &CloseBasket($basketno);
143
144 close a basket (becomes unmodifiable,except for recieves)
145
146 =back
147
148 =cut
149
150 sub CloseBasket {
151     my ($basketno) = @_;
152     my $dbh        = C4::Context->dbh;
153     my $query = "
154         UPDATE aqbasket
155         SET    closedate=now()
156         WHERE  basketno=?
157     ";
158     my $sth = $dbh->prepare($query);
159     $sth->execute($basketno);
160 }
161
162 #------------------------------------------------------------#
163
164 =back
165
166 =head2 FUNCTIONS ABOUT ORDERS
167
168 =over 2
169
170 =cut
171
172 #------------------------------------------------------------#
173
174 =head3 GetPendingOrders
175
176 =over 4
177
178 $orders = &GetPendingOrders($booksellerid, $grouped);
179
180 Finds pending orders from the bookseller with the given ID. Ignores
181 completed and cancelled orders.
182
183 C<$orders> is a reference-to-array; each element is a
184 reference-to-hash with the following fields:
185 C<$grouped> is a boolean that, if set to 1 will group all order lines of the same basket
186 in a single result line 
187
188 =over 2
189
190 =item C<authorizedby>
191
192 =item C<entrydate>
193
194 =item C<basketno>
195
196 These give the value of the corresponding field in the aqorders table
197 of the Koha database.
198
199 =back
200
201 =back
202
203 Results are ordered from most to least recent.
204
205 =cut
206
207 sub GetPendingOrders {
208     my ($supplierid,$grouped) = @_;
209     my $dbh = C4::Context->dbh;
210     my $strsth = "
211         SELECT    ".($grouped?"count(*),":"")."aqbasket.basketno,
212                     surname,firstname,aqorders.*,
213                     aqbasket.closedate, aqbasket.creationdate
214         FROM      aqorders
215         LEFT JOIN aqbasket ON aqbasket.basketno=aqorders.basketno
216         LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber
217         WHERE booksellerid=?
218             AND (quantity > quantityreceived OR quantityreceived is NULL)
219             AND datecancellationprinted IS NULL
220             AND (to_days(now())-to_days(closedate) < 180 OR closedate IS NULL)
221     ";
222     ## FIXME  Why 180 days ???
223     my @query_params = ( $supplierid );
224     if ( C4::Context->preference("IndependantBranches") ) {
225         my $userenv = C4::Context->userenv;
226         if ( ($userenv) && ( $userenv->{flags} != 1 ) ) {
227             warn 'in branch';
228             $strsth .= " and (borrowers.branchcode = ?
229                           or borrowers.branchcode  = '')";
230             push @query_params, $userenv->{branch};
231  
232         }
233     }
234     $strsth .= " group by aqbasket.basketno" if $grouped;
235     $strsth .= " order by aqbasket.basketno";
236
237     my $sth = $dbh->prepare($strsth);
238     $sth->execute( @query_params );
239     my $results = $sth->fetchall_arrayref({});
240     $sth->finish;
241     return $results;
242 }
243
244 #------------------------------------------------------------#
245
246 =head3 GetOrders
247
248 =over 4
249
250 @orders = &GetOrders($basketnumber, $orderby);
251
252 Looks up the pending (non-cancelled) orders with the given basket
253 number. If C<$booksellerID> is non-empty, only orders from that seller
254 are returned.
255
256 return :
257 C<&basket> returns a two-element array. C<@orders> is an array of
258 references-to-hash, whose keys are the fields from the aqorders,
259 biblio, and biblioitems tables in the Koha database.
260
261 =back
262
263 =cut
264
265 sub GetOrders {
266     my ( $basketno, $orderby ) = @_;
267     my $dbh   = C4::Context->dbh;
268     my $query  ="
269          SELECT  aqorderbreakdown.*,
270                 biblio.*,biblioitems.publishercode,
271                 aqorders.*,
272                 aqbookfund.bookfundname,
273                 biblio.title
274         FROM    aqorders
275             LEFT JOIN aqorderbreakdown ON aqorders.ordernumber=aqorderbreakdown.ordernumber
276             LEFT JOIN aqbookfund       ON aqbookfund.bookfundid=aqorderbreakdown.bookfundid
277             LEFT JOIN biblio           ON biblio.biblionumber=aqorders.biblionumber
278             LEFT JOIN biblioitems      ON biblioitems.biblionumber=biblio.biblionumber
279         WHERE   basketno=?
280             AND (datecancellationprinted IS NULL OR datecancellationprinted='0000-00-00')
281     ";
282
283     $orderby = "biblioitems.publishercode,biblio.title" unless $orderby;
284     $query .= " ORDER BY $orderby";
285     my $sth = $dbh->prepare($query);
286     $sth->execute($basketno);
287     my @results;
288
289     while ( my $data = $sth->fetchrow_hashref ) {
290         push @results, $data;
291     }
292     $sth->finish;
293     return @results;
294 }
295
296 #------------------------------------------------------------#
297
298 =head3 GetOrderNumber
299
300 =over 4
301
302 $ordernumber = &GetOrderNumber($biblioitemnumber, $biblionumber);
303
304 Looks up the ordernumber with the given biblionumber and biblioitemnumber.
305
306 Returns the number of this order.
307
308 =item C<$ordernumber> is the order number.
309
310 =back
311
312 =cut
313 sub GetOrderNumber {
314     my ( $biblionumber,$biblioitemnumber ) = @_;
315     my $dbh = C4::Context->dbh;
316     my $query = "
317         SELECT ordernumber
318         FROM   aqorders
319         WHERE  biblionumber=?
320         AND    biblioitemnumber=?
321     ";
322     my $sth = $dbh->prepare($query);
323     $sth->execute( $biblionumber, $biblioitemnumber );
324
325     return $sth->fetchrow;
326 }
327
328 #------------------------------------------------------------#
329
330 =head3 GetOrder
331
332 =over 4
333
334 $order = &GetOrder($ordernumber);
335
336 Looks up an order by order number.
337
338 Returns a reference-to-hash describing the order. The keys of
339 C<$order> are fields from the biblio, biblioitems, aqorders, and
340 aqorderbreakdown tables of the Koha database.
341
342 =back
343
344 =cut
345
346 sub GetOrder {
347     my ($ordnum) = @_;
348     my $dbh      = C4::Context->dbh;
349     my $query = "
350         SELECT *
351         FROM   aqorders
352         LEFT JOIN aqorderbreakdown ON aqorders.ordernumber=aqorderbreakdown.ordernumber
353         LEFT JOIN biblio on           biblio.biblionumber=aqorders.biblionumber
354         LEFT JOIN biblioitems on       biblioitems.biblionumber=aqorders.biblionumber
355         WHERE aqorders.ordernumber=?
356
357     ";
358     my $sth= $dbh->prepare($query);
359     $sth->execute($ordnum);
360     my $data = $sth->fetchrow_hashref;
361     $sth->finish;
362     return $data;
363 }
364
365 #------------------------------------------------------------#
366
367 =head3 NewOrder
368
369 =over 4
370
371   &NewOrder($basket, $biblionumber, $title, $quantity, $listprice,
372     $booksellerid, $who, $notes, $bookfund, $biblioitemnumber, $rrp,
373     $ecost, $gst, $budget, $unitprice, $subscription,
374     $booksellerinvoicenumber, $purchaseorder);
375
376 Adds a new order to the database. Any argument that isn't described
377 below is the new value of the field with the same name in the aqorders
378 table of the Koha database.
379
380 C<$ordnum> is a "minimum order number." After adding the new entry to
381 the aqorders table, C<&neworder> finds the first entry in aqorders
382 with order number greater than or equal to C<$ordnum>, and adds an
383 entry to the aqorderbreakdown table, with the order number just found,
384 and the book fund ID of the newly-added order.
385
386 C<$budget> is effectively ignored.
387
388 C<$subscription> may be either "yes", or anything else for "no".
389
390 =back
391
392 =cut
393
394 sub NewOrder {
395    my (
396         $basketno,  $bibnum,       $title,        $quantity,
397         $listprice, $booksellerid, $authorisedby, $notes,
398         $bookfund,  $bibitemnum,   $rrp,          $ecost,
399         $gst,       $budget,       $cost,         $sub,
400         $invoice,   $sort1,        $sort2,        $purchaseorder
401       )
402       = @_;
403
404     my $year  = localtime->year() + 1900;
405     my $month = localtime->mon() + 1;       # months starts at 0, add 1
406
407     if ( !$budget || $budget eq 'now' ) {
408         $budget = "now()";
409     }
410
411     # if month is july or more, budget start is 1 jul, next year.
412     elsif ( $month >= '7' ) {
413         ++$year;                            # add 1 to year , coz its next year
414         $budget = "'$year-07-01'";
415     }
416     else {
417
418         # START OF NEW BUDGET, 1ST OF JULY, THIS YEAR
419         $budget = "'$year-07-01'";
420     }
421
422     if ( $sub eq 'yes' ) {
423         $sub = 1;
424     }
425     else {
426         $sub = 0;
427     }
428
429     # if $basket empty, it's also a new basket, create it
430     unless ($basketno) {
431         $basketno = NewBasket( $booksellerid, $authorisedby );
432     }
433
434     my $dbh = C4::Context->dbh;
435     my $query = "
436         INSERT INTO aqorders
437            ( biblionumber,title,basketno,quantity,listprice,notes,
438            biblioitemnumber,rrp,ecost,gst,unitprice,subscription,sort1,sort2,budgetdate,entrydate,purchaseordernumber)
439         VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,$budget,now(),? )
440     ";
441     my $sth = $dbh->prepare($query);
442
443     $sth->execute(
444         $bibnum, $title,      $basketno, $quantity, $listprice,
445         $notes,  $bibitemnum, $rrp,      $ecost,    $gst,
446         $cost,   $sub,        $sort1,    $sort2,        $purchaseorder
447     );
448     $sth->finish;
449
450     #get ordnum MYSQL dependant, but $dbh->last_insert_id returns null
451     my $ordnum = $dbh->{'mysql_insertid'};
452     $query = "
453         INSERT INTO aqorderbreakdown (ordernumber,bookfundid)
454         VALUES (?,?)
455     ";
456     $sth = $dbh->prepare($query);
457     $sth->execute( $ordnum, $bookfund );
458     $sth->finish;
459     return ( $basketno, $ordnum );
460 }
461
462 #------------------------------------------------------------#
463
464 =head3 ModOrder
465
466 =over 4
467
468 &ModOrder($title, $ordernumber, $quantity, $listprice,
469     $biblionumber, $basketno, $supplier, $who, $notes,
470     $bookfundid, $bibitemnum, $rrp, $ecost, $gst, $budget,
471     $unitprice, $booksellerinvoicenumber);
472
473 Modifies an existing order. Updates the order with order number
474 C<$ordernumber> and biblionumber C<$biblionumber>. All other arguments
475 update the fields with the same name in the aqorders table of the Koha
476 database.
477
478 Entries with order number C<$ordernumber> in the aqorderbreakdown
479 table are also updated to the new book fund ID.
480
481 =back
482
483 =cut
484
485 sub ModOrder {
486     my (
487         $title,      $ordnum,   $quantity, $listprice, $bibnum,
488         $basketno,   $supplier, $who,      $notes,     $bookfund,
489         $bibitemnum, $rrp,      $ecost,    $gst,       $budget,
490         $cost,       $invoice,  $sort1,    $sort2,     $purchaseorder
491       )
492       = @_;
493     my $dbh = C4::Context->dbh;
494     my $query = "
495         UPDATE aqorders
496         SET    title=?,
497                quantity=?,listprice=?,basketno=?,
498                rrp=?,ecost=?,unitprice=?,booksellerinvoicenumber=?,
499                notes=?,sort1=?, sort2=?, purchaseordernumber=?
500         WHERE  ordernumber=? AND biblionumber=?
501     ";
502     my $sth = $dbh->prepare($query);
503     $sth->execute(
504         $title, $quantity, $listprice, $basketno, $rrp,
505         $ecost, $cost,     $invoice,   $notes,    $sort1,
506         $sort2, $purchaseorder,
507                 $ordnum,   $bibnum
508     );
509     $sth->finish;
510     $query = "
511         UPDATE aqorderbreakdown
512         SET    bookfundid=?
513         WHERE  ordernumber=?
514     ";
515     $sth = $dbh->prepare($query);
516
517     unless ( $sth->execute( $bookfund, $ordnum ) )
518     {    # zero rows affected [Bug 734]
519         my $query ="
520             INSERT INTO aqorderbreakdown
521                      (ordernumber,bookfundid)
522             VALUES   (?,?)
523         ";
524         $sth = $dbh->prepare($query);
525         $sth->execute( $ordnum, $bookfund );
526     }
527     $sth->finish;
528 }
529
530 #------------------------------------------------------------#
531
532 =head3 ModOrderBiblioNumber
533
534 =over 4
535
536 &ModOrderBiblioNumber($biblioitemnumber,$ordnum, $biblionumber);
537
538 Modifies the biblioitemnumber for an existing order.
539 Updates the order with order number C<$ordernum> and biblionumber C<$biblionumber>.
540
541 =back
542
543 =cut
544
545 sub ModOrderBiblioNumber {
546     my ($biblioitemnumber,$ordnum, $biblionumber) = @_;
547     my $dbh = C4::Context->dbh;
548     my $query = "
549       UPDATE aqorders
550       SET    biblioitemnumber = ?
551       WHERE  ordernumber = ?
552       AND biblionumber =  ?";
553     my $sth = $dbh->prepare($query);
554     $sth->execute( $biblioitemnumber, $ordnum, $biblionumber );
555 }
556
557 #------------------------------------------------------------#
558
559 =head3 ModReceiveOrder
560
561 =over 4
562
563 &ModReceiveOrder($biblionumber, $ordernumber, $quantityreceived, $user,
564     $unitprice, $booksellerinvoicenumber, $biblioitemnumber,
565     $freight, $bookfund, $rrp);
566
567 Updates an order, to reflect the fact that it was received, at least
568 in part. All arguments not mentioned below update the fields with the
569 same name in the aqorders table of the Koha database.
570
571 If a partial order is received, splits the order into two.  The received
572 portion must have a booksellerinvoicenumber.  
573
574 Updates the order with bibilionumber C<$biblionumber> and ordernumber
575 C<$ordernumber>.
576
577 Also updates the book fund ID in the aqorderbreakdown table.
578
579 =back
580
581 =cut
582
583
584 sub ModReceiveOrder {
585     my (
586         $biblionumber,    $ordnum,  $quantrec, $user, $cost,
587         $invoiceno, $freight, $rrp, $bookfund, $datereceived
588       )
589       = @_;
590     my $dbh = C4::Context->dbh;
591 #     warn "DATE BEFORE : $daterecieved";
592 #    $daterecieved=POSIX::strftime("%Y-%m-%d",CORE::localtime) unless $daterecieved;
593 #     warn "DATE REC : $daterecieved";
594         $datereceived = C4::Dates->output('iso') unless $datereceived;
595     my $suggestionid = GetSuggestionFromBiblionumber( $dbh, $biblionumber );
596     if ($suggestionid) {
597         ModStatus( $suggestionid, 'AVAILABLE', '', $biblionumber );
598     }
599     # Allows libraries to change their bookfund during receiving orders
600     # allows them to adjust budgets
601     if ( C4::Context->preference("LooseBudgets") && $bookfund ) {
602         my $query = "
603             UPDATE aqorderbreakdown
604             SET    bookfundid=?
605             WHERE  ordernumber=?
606         ";
607         my $sth = $dbh->prepare($query);
608         $sth->execute( $bookfund, $ordnum );
609         $sth->finish;
610     }
611    
612         my $sth=$dbh->prepare("SELECT * FROM aqorders  LEFT JOIN aqorderbreakdown ON aqorders.ordernumber=aqorderbreakdown.ordernumber
613                                                         WHERE biblionumber=? AND aqorders.ordernumber=?");
614     $sth->execute($biblionumber,$ordnum);
615     my $order = $sth->fetchrow_hashref();
616     $sth->finish();
617         
618         if ( $order->{quantity} > $quantrec ) {
619         $sth=$dbh->prepare("update aqorders 
620                                                         set quantityreceived=?,datereceived=?,booksellerinvoicenumber=?, 
621                                                                 unitprice=?,freight=?,rrp=?,quantity=?
622                             where biblionumber=? and ordernumber=?");
623         $sth->execute($quantrec,$datereceived,$invoiceno,$cost,$freight,$rrp,$quantrec,$biblionumber,$ordnum);
624         $sth->finish;
625         # create a new order for the remaining items, and set its bookfund.
626         my $newOrder = NewOrder($order->{'basketno'},$order->{'biblionumber'},$order->{'title'}, $order->{'quantity'} - $quantrec,    
627                     $order->{'listprice'},$order->{'booksellerid'},$order->{'authorisedby'},$order->{'notes'},   
628                     $order->{'bookfundid'},$order->{'biblioitemnumber'},$order->{'rrp'},$order->{'ecost'},$order->{'gst'},
629                     $order->{'budget'},$order->{'unitcost'},$order->{'sub'},'',$order->{'sort1'},$order->{'sort2'},$order->{'purchaseordernumber'});
630     
631         $sth=$dbh->prepare(" insert into aqorderbreakdown (ordernumber, branchcode, bookfundid) values (?,?,?)"); 
632         $sth->execute($newOrder,$order->{branch},$order->{bookfundid});
633     } else {
634         $sth=$dbh->prepare("update aqorders 
635                                                         set quantityreceived=?,datereceived=?,booksellerinvoicenumber=?, 
636                                                                 unitprice=?,freight=?,rrp=?
637                             where biblionumber=? and ordernumber=?");
638         $sth->execute($quantrec,$datereceived,$invoiceno,$cost,$freight,$rrp,$biblionumber,$ordnum);
639         $sth->finish;
640     }
641     return $datereceived;
642 }
643 #------------------------------------------------------------#
644
645 =head3 SearchOrder
646
647 @results = &SearchOrder($search, $biblionumber, $complete);
648
649 Searches for orders.
650
651 C<$search> may take one of several forms: if it is an ISBN,
652 C<&ordersearch> returns orders with that ISBN. If C<$search> is an
653 order number, C<&ordersearch> returns orders with that order number
654 and biblionumber C<$biblionumber>. Otherwise, C<$search> is considered
655 to be a space-separated list of search terms; in this case, all of the
656 terms must appear in the title (matching the beginning of title
657 words).
658
659 If C<$complete> is C<yes>, the results will include only completed
660 orders. In any case, C<&ordersearch> ignores cancelled orders.
661
662 C<&ordersearch> returns an array.
663 C<@results> is an array of references-to-hash with the following keys:
664
665 =over 4
666
667 =item C<author>
668
669 =item C<seriestitle>
670
671 =item C<branchcode>
672
673 =item C<bookfundid>
674
675 =back
676
677 =cut
678
679 sub SearchOrder {
680     my ( $search, $id, $biblionumber, $catview ) = @_;
681     my $dbh = C4::Context->dbh;
682     my @data = split( ' ', $search );
683     my @searchterms;
684     if ($id) {
685         @searchterms = ($id);
686     }
687     map { push( @searchterms, "$_%", "%$_%" ) } @data;
688     push( @searchterms, $search, $search, $biblionumber );
689     my $query;
690   ### FIXME  THIS CAN raise a problem if more THAN ONE biblioitem is linked to one biblio  
691     if ($id) {  
692         $query =
693           "SELECT *,biblio.title 
694            FROM aqorders 
695            LEFT JOIN biblio ON aqorders.biblionumber=biblio.biblionumber 
696            LEFT JOIN biblioitems ON biblioitems.biblionumber=biblio.biblionumber 
697            LEFT JOIN aqbasket ON aqorders.basketno = aqbasket.basketno
698             WHERE aqbasket.booksellerid = ?
699             AND ((datecancellationprinted is NULL)
700             OR (datecancellationprinted = '0000-00-00'))
701             AND (("
702           . (
703             join( " AND ",
704                 map { "(biblio.title like ? or biblio.title like ?)" } @data )
705           )
706           . ") OR biblioitems.isbn=? OR (aqorders.ordernumber=? AND aqorders.biblionumber=?)) ";
707
708     }
709     else {
710         $query =
711           " SELECT *,biblio.title
712             FROM   aqorders
713             LEFT JOIN biblio ON biblio.biblionumber=aqorders.biblionumber
714             LEFT JOIN aqbasket on aqorders.basketno=aqbasket.basketno
715             LEFT JOIN biblioitems ON biblioitems.biblionumber=biblio.biblionumber      
716             WHERE  ((datecancellationprinted is NULL)
717             OR     (datecancellationprinted = '0000-00-00'))
718             AND    (aqorders.quantityreceived < aqorders.quantity OR aqorders.quantityreceived is NULL)
719             AND (("
720           . (
721             join( " AND ",
722                 map { "(biblio.title like ? OR biblio.title like ?)" } @data )
723           )
724           . ") or biblioitems.isbn=? OR (aqorders.ordernumber=? AND aqorders.biblionumber=?)) ";
725     }
726     $query .= " GROUP BY aqorders.ordernumber";
727     ### $query
728     my $sth = $dbh->prepare($query);
729     $sth->execute(@searchterms);
730     my @results = ();
731     my $query2 = "
732         SELECT *
733         FROM   biblio
734         WHERE  biblionumber=?
735     ";
736     my $sth2 = $dbh->prepare($query2);
737     my $query3 = "
738         SELECT *
739         FROM   aqorderbreakdown
740         WHERE  ordernumber=?
741     ";
742     my $sth3 = $dbh->prepare($query3);
743
744     while ( my $data = $sth->fetchrow_hashref ) {
745         $sth2->execute( $data->{'biblionumber'} );
746         my $data2 = $sth2->fetchrow_hashref;
747         $data->{'author'}      = $data2->{'author'};
748         $data->{'seriestitle'} = $data2->{'seriestitle'};
749         $sth3->execute( $data->{'ordernumber'} );
750         my $data3 = $sth3->fetchrow_hashref;
751         $data->{'branchcode'} = $data3->{'branchcode'};
752         $data->{'bookfundid'} = $data3->{'bookfundid'};
753         push( @results, $data );
754     }
755     ### @results
756     $sth->finish;
757     $sth2->finish;
758     $sth3->finish;
759     return @results;
760 }
761
762 #------------------------------------------------------------#
763
764 =head3 DelOrder
765
766 =over 4
767
768 &DelOrder($biblionumber, $ordernumber);
769
770 Cancel the order with the given order and biblio numbers. It does not
771 delete any entries in the aqorders table, it merely marks them as
772 cancelled.
773
774 =back
775
776 =cut
777
778 sub DelOrder {
779     my ( $bibnum, $ordnum ) = @_;
780     my $dbh = C4::Context->dbh;
781     my $query = "
782         UPDATE aqorders
783         SET    datecancellationprinted=now()
784         WHERE  biblionumber=? AND ordernumber=?
785     ";
786     my $sth = $dbh->prepare($query);
787     $sth->execute( $bibnum, $ordnum );
788     $sth->finish;
789 }
790
791
792 =back
793
794 =head2 FUNCTIONS ABOUT PARCELS
795
796 =over 2
797
798 =cut
799
800 #------------------------------------------------------------#
801
802 =head3 GetParcel
803
804 =over 4
805
806 @results = &GetParcel($booksellerid, $code, $date);
807
808 Looks up all of the received items from the supplier with the given
809 bookseller ID at the given date, for the given code (bookseller Invoice number). Ignores cancelled and completed orders.
810
811 C<@results> is an array of references-to-hash. The keys of each element are fields from
812 the aqorders, biblio, and biblioitems tables of the Koha database.
813
814 C<@results> is sorted alphabetically by book title.
815
816 =back
817
818 =cut
819
820 sub GetParcel {
821     #gets all orders from a certain supplier, orders them alphabetically
822     my ( $supplierid, $code, $datereceived ) = @_;
823     my $dbh     = C4::Context->dbh;
824     my @results = ();
825     $code .= '%'
826       if $code;  # add % if we search on a given code (otherwise, let him empty)
827     my $strsth ="
828         SELECT  authorisedby,
829                 creationdate,
830                 aqbasket.basketno,
831                 closedate,surname,
832                 firstname,
833                 aqorders.biblionumber,
834                 aqorders.title,
835                 aqorders.ordernumber,
836                 aqorders.quantity,
837                 aqorders.quantityreceived,
838                 aqorders.unitprice,
839                 aqorders.listprice,
840                 aqorders.rrp,
841                 aqorders.ecost
842         FROM aqorders 
843         LEFT JOIN aqbasket ON aqbasket.basketno=aqorders.basketno
844         LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber
845         WHERE 
846             aqbasket.booksellerid=?
847             AND aqorders.booksellerinvoicenumber LIKE  \"$code\"
848             AND aqorders.datereceived= \'$datereceived\'";
849
850     if ( C4::Context->preference("IndependantBranches") ) {
851         my $userenv = C4::Context->userenv;
852         if ( ($userenv) && ( $userenv->{flags} != 1 ) ) {
853             $strsth .=
854                 " AND (borrowers.branchcode = '"
855               . $userenv->{branch}
856               . "' OR borrowers.branchcode ='')";
857         }
858     }
859     $strsth .= " ORDER BY aqbasket.basketno";
860     ### parcelinformation : $strsth
861  #   warn "STH : $strsth";
862     my $sth = $dbh->prepare($strsth);
863     $sth->execute($supplierid);
864     while ( my $data = $sth->fetchrow_hashref ) {
865         push( @results, $data );
866     }
867     ### countparcelbiblio: scalar(@results)
868     $sth->finish;
869
870     return @results;
871 }
872
873 #------------------------------------------------------------#
874
875 =head3 GetParcels
876
877 =over 4
878
879 $results = &GetParcels($bookseller, $order, $code, $datefrom, $dateto);
880 get a lists of parcels.
881
882 * Input arg :
883
884 =item $bookseller
885 is the bookseller this function has to get parcels.
886
887 =item $order
888 To know on what criteria the results list has to be ordered.
889
890 =item $code
891 is the booksellerinvoicenumber.
892
893 =item $datefrom & $dateto
894 to know on what date this function has to filter its search.
895
896 * return:
897 a pointer on a hash list containing parcel informations as such :
898
899 =item Creation date
900
901 =item Last operation
902
903 =item Number of biblio
904
905 =item Number of items
906
907 =back
908
909 =cut
910
911 sub GetParcels {
912     my ($bookseller,$order, $code, $datefrom, $dateto) = @_;
913     my $dbh    = C4::Context->dbh;
914     my $strsth ="
915         SELECT  aqorders.booksellerinvoicenumber,
916                 datereceived,purchaseordernumber,
917                 count(DISTINCT biblionumber) AS biblio,
918                 sum(quantity) AS itemsexpected,
919                 sum(quantityreceived) AS itemsreceived
920         FROM   aqorders LEFT JOIN aqbasket ON aqbasket.basketno = aqorders.basketno
921         WHERE aqbasket.booksellerid = $bookseller and datereceived IS NOT NULL
922     ";
923
924     $strsth .= "and aqorders.booksellerinvoicenumber like \"$code%\" " if ($code);
925
926     $strsth .= "and datereceived >=" . $dbh->quote($datefrom) . " " if ($datefrom);
927
928     $strsth .= "and datereceived <=" . $dbh->quote($dateto) . " " if ($dateto);
929
930     $strsth .= "group by aqorders.booksellerinvoicenumber,datereceived ";
931     $strsth .= "order by $order " if ($order);
932 ### $strsth
933     my $sth = $dbh->prepare($strsth);
934
935     $sth->execute;
936     my $results = $sth->fetchall_arrayref({});
937     $sth->finish;
938     return @$results;
939 }
940
941 #------------------------------------------------------------#
942
943 =head3 GetLateOrders
944
945 =over 4
946
947 @results = &GetLateOrders;
948
949 Searches for bookseller with late orders.
950
951 return:
952 the table of supplier with late issues. This table is full of hashref.
953
954 =back
955
956 =cut
957
958 sub GetLateOrders {
959     my $delay      = shift;
960     my $supplierid = shift;
961     my $branch     = shift;
962
963     my $dbh = C4::Context->dbh;
964
965     #BEWARE, order of parenthesis and LEFT JOIN is important for speed
966     my $strsth;
967     my $dbdriver = C4::Context->config("db_scheme") || "mysql";
968
969     #    warn " $dbdriver";
970     if ( $dbdriver eq "mysql" ) {
971         $strsth = "
972             SELECT aqbasket.basketno,aqorders.ordernumber,
973                 DATE(aqbasket.closedate) AS orderdate,
974                 aqorders.quantity - IFNULL(aqorders.quantityreceived,0) AS quantity,
975                 aqorders.rrp AS unitpricesupplier,
976                 aqorders.ecost AS unitpricelib,
977                 (aqorders.quantity - IFNULL(aqorders.quantityreceived,0)) * aqorders.rrp AS subtotal,
978                 aqbookfund.bookfundname AS budget,
979                 borrowers.branchcode AS branch,
980                 aqbooksellers.name AS supplier,
981                 aqorders.title,
982                 biblio.author,
983                 biblioitems.publishercode AS publisher,
984                 biblioitems.publicationyear,
985                 DATEDIFF(CURDATE( ),closedate) AS latesince
986             FROM  (((
987                 (aqorders LEFT JOIN biblio ON biblio.biblionumber = aqorders.biblionumber)
988             LEFT JOIN biblioitems ON  biblioitems.biblionumber=biblio.biblionumber)
989             LEFT JOIN aqorderbreakdown ON aqorders.ordernumber = aqorderbreakdown.ordernumber)
990             LEFT JOIN aqbookfund ON aqorderbreakdown.bookfundid = aqbookfund.bookfundid),
991             (aqbasket LEFT JOIN borrowers ON aqbasket.authorisedby = borrowers.borrowernumber)
992             LEFT JOIN aqbooksellers ON aqbasket.booksellerid = aqbooksellers.id
993             WHERE aqorders.basketno = aqbasket.basketno
994             AND (closedate < DATE_SUB(CURDATE( ),INTERVAL $delay DAY))
995             AND ((datereceived = '' OR datereceived is null)
996             OR (aqorders.quantityreceived < aqorders.quantity) )
997         ";
998         $strsth .= " AND aqbasket.booksellerid = $supplierid " if ($supplierid);
999         $strsth .= " AND borrowers.branchcode like \'" . $branch . "\'"
1000           if ($branch);
1001         $strsth .=
1002           " AND borrowers.branchcode like \'"
1003           . C4::Context->userenv->{branch} . "\'"
1004           if ( C4::Context->preference("IndependantBranches")
1005             && C4::Context->userenv
1006             && C4::Context->userenv->{flags} != 1 );
1007         $strsth .=" HAVING quantity<>0
1008                     AND unitpricesupplier<>0
1009                     AND unitpricelib<>0
1010                     ORDER BY latesince,basketno,borrowers.branchcode, supplier
1011         ";
1012     }
1013     else {
1014         $strsth = "
1015             SELECT aqbasket.basketno,
1016                    DATE(aqbasket.closedate) AS orderdate,
1017                     aqorders.quantity, aqorders.rrp AS unitpricesupplier,
1018                     aqorders.ecost as unitpricelib,
1019                     aqorders.quantity * aqorders.rrp AS subtotal
1020                     aqbookfund.bookfundname AS budget,
1021                     borrowers.branchcode AS branch,
1022                     aqbooksellers.name AS supplier,
1023                     biblio.title,
1024                     biblio.author,
1025                     biblioitems.publishercode AS publisher,
1026                     biblioitems.publicationyear,
1027                     (CURDATE -  closedate) AS latesince
1028                     FROM(( (
1029                         (aqorders LEFT JOIN biblio on biblio.biblionumber = aqorders.biblionumber)
1030                         LEFT JOIN biblioitems on  biblioitems.biblionumber=biblio.biblionumber)
1031                         LEFT JOIN aqorderbreakdown on aqorders.ordernumber = aqorderbreakdown.ordernumber)
1032                         LEFT JOIN aqbookfund ON aqorderbreakdown.bookfundid = aqbookfund.bookfundid),
1033                         (aqbasket LEFT JOIN borrowers on aqbasket.authorisedby = borrowers.borrowernumber) LEFT JOIN aqbooksellers ON aqbasket.booksellerid = aqbooksellers.id
1034                     WHERE aqorders.basketno = aqbasket.basketno
1035                     AND (closedate < (CURDATE -(INTERVAL $delay DAY))
1036                     AND ((datereceived = '' OR datereceived is null)
1037                     OR (aqorders.quantityreceived < aqorders.quantity) ) ";
1038         $strsth .= " AND aqbasket.booksellerid = $supplierid " if ($supplierid);
1039
1040         $strsth .= " AND borrowers.branchcode like \'" . $branch . "\'" if ($branch);
1041         $strsth .=" AND borrowers.branchcode like \'". C4::Context->userenv->{branch} . "\'"
1042             if (C4::Context->preference("IndependantBranches") && C4::Context->userenv->{flags} != 1 );
1043         $strsth .=" ORDER BY latesince,basketno,borrowers.branchcode, supplier";
1044     }
1045     my $sth = $dbh->prepare($strsth);
1046     $sth->execute;
1047     my @results;
1048     my $hilighted = 1;
1049     while ( my $data = $sth->fetchrow_hashref ) {
1050         $data->{hilighted} = $hilighted if ( $hilighted > 0 );
1051         $data->{orderdate} = format_date( $data->{orderdate} );
1052         push @results, $data;
1053         $hilighted = -$hilighted;
1054     }
1055     $sth->finish;
1056     return @results;
1057 }
1058
1059 #------------------------------------------------------------#
1060
1061 =head3 GetHistory
1062
1063 =over 4
1064
1065 (\@order_loop, $total_qty, $total_price, $total_qtyreceived)=&GetHistory( $title, $author, $name, $from_placed_on, $to_placed_on )
1066
1067 this function get the search history.
1068
1069 =back
1070
1071 =cut
1072
1073 sub GetHistory {
1074     my ( $title, $author, $name, $from_placed_on, $to_placed_on ) = @_;
1075     my @order_loop;
1076     my $total_qty         = 0;
1077     my $total_qtyreceived = 0;
1078     my $total_price       = 0;
1079
1080 # don't run the query if there are no parameters (list would be too long for sure !)
1081     if ( $title || $author || $name || $from_placed_on || $to_placed_on ) {
1082         my $dbh   = C4::Context->dbh;
1083         my $query ="
1084             SELECT
1085                 biblio.title,
1086                 biblio.author,
1087                 aqorders.basketno,
1088                 name,aqbasket.creationdate,
1089                 aqorders.datereceived,
1090                 aqorders.quantity,
1091                 aqorders.quantityreceived,
1092                 aqorders.ecost,
1093                 aqorders.ordernumber,
1094                 aqorders.booksellerinvoicenumber as invoicenumber,
1095                 aqbooksellers.id as id,
1096                 aqorders.biblionumber
1097             FROM aqorders 
1098             LEFT JOIN aqbasket ON aqorders.basketno=aqbasket.basketno 
1099             LEFT JOIN aqbooksellers ON aqbasket.booksellerid=aqbooksellers.id
1100             LEFT JOIN biblio ON biblio.biblionumber=aqorders.biblionumber";
1101
1102         $query .= " LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber"
1103           if ( C4::Context->preference("IndependantBranches") );
1104
1105         $query .= " WHERE 1 ";
1106         $query .= " AND biblio.title LIKE " . $dbh->quote( "%" . $title . "%" )
1107           if $title;
1108
1109         $query .=
1110           " AND biblio.author LIKE " . $dbh->quote( "%" . $author . "%" )
1111           if $author;
1112
1113         $query .= " AND name LIKE " . $dbh->quote( "%" . $name . "%" ) if $name;
1114
1115         $query .= " AND creationdate >" . $dbh->quote($from_placed_on)
1116           if $from_placed_on;
1117
1118         $query .= " AND creationdate<" . $dbh->quote($to_placed_on)
1119           if $to_placed_on;
1120         $query .= " AND (datecancellationprinted is NULL or datecancellationprinted='0000-00-00')";
1121
1122         if ( C4::Context->preference("IndependantBranches") ) {
1123             my $userenv = C4::Context->userenv;
1124             if ( ($userenv) && ( $userenv->{flags} != 1 ) ) {
1125                 $query .=
1126                     " AND (borrowers.branchcode = '"
1127                   . $userenv->{branch}
1128                   . "' OR borrowers.branchcode ='')";
1129             }
1130         }
1131         $query .= " ORDER BY booksellerid";
1132         my $sth = $dbh->prepare($query);
1133         $sth->execute;
1134         my $cnt = 1;
1135         while ( my $line = $sth->fetchrow_hashref ) {
1136             $line->{count} = $cnt++;
1137             $line->{toggle} = 1 if $cnt % 2;
1138             push @order_loop, $line;
1139             $line->{creationdate} = format_date( $line->{creationdate} );
1140             $line->{datereceived} = format_date( $line->{datereceived} );
1141             $total_qty         += $line->{'quantity'};
1142             $total_qtyreceived += $line->{'quantityreceived'};
1143             $total_price       += $line->{'quantity'} * $line->{'ecost'};
1144         }
1145     }
1146     return \@order_loop, $total_qty, $total_price, $total_qtyreceived;
1147 }
1148
1149 =head2 GetRecentAcqui
1150
1151    $results = GetRecentAcqui($days);
1152
1153    C<$results> is a ref to a table which containts hashref
1154
1155 =cut
1156
1157 sub GetRecentAcqui {
1158     my $limit  = shift;
1159     my $dbh    = C4::Context->dbh;
1160     my $query = "
1161         SELECT *
1162         FROM   biblio
1163         ORDER BY timestamp DESC
1164         LIMIT  0,".$limit;
1165
1166     my $sth = $dbh->prepare($query);
1167     $sth->execute;
1168     my @results;
1169     while(my $data = $sth->fetchrow_hashref){
1170         push @results,$data;
1171     }
1172     return \@results;
1173 }
1174
1175 1;
1176 __END__
1177
1178 =back
1179
1180 =head1 AUTHOR
1181
1182 Koha Developement team <info@koha.org>
1183
1184 =cut