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