just doing a <= / >= instead of a < / > in history search.
[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 biblioitems.*, biblio.*, aqorderbreakdown.*, aqorders.*
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   If it's undef (anything false) or the string 'now', the current day is used.
386   Else, the upcoming July 1st is used.
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 = undef;
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,
438              notes,        biblioitemnumber, rrp,      ecost,    gst,
439              unitprice,    subscription,     sort1,    sort2,    budgetdate,
440              entrydate,    purchaseordernumber)
441         VALUES ( ?,?,?,?,?,?,?,?,?,?,?,?,?,?,COALESCE(?,NOW()),NOW(),? )
442     ";
443     my $sth = $dbh->prepare($query);
444
445     $sth->execute(
446         $bibnum, $title,      $basketno, $quantity, $listprice,
447         $notes,  $bibitemnum, $rrp,      $ecost,    $gst,
448         $cost,   $sub,        $sort1,    $sort2,    $budget,
449                  $purchaseorder
450     );
451     $sth->finish;
452
453     #get ordnum MYSQL dependant, but $dbh->last_insert_id returns null
454     my $ordnum = $dbh->{'mysql_insertid'};
455     $query = "
456         INSERT INTO aqorderbreakdown (ordernumber,bookfundid)
457         VALUES (?,?)
458     ";
459     $sth = $dbh->prepare($query);
460     $sth->execute( $ordnum, $bookfund );
461     $sth->finish;
462     return ( $basketno, $ordnum );
463 }
464
465 #------------------------------------------------------------#
466
467 =head3 ModOrder
468
469 =over 4
470
471 &ModOrder($title, $ordernumber, $quantity, $listprice,
472     $biblionumber, $basketno, $supplier, $who, $notes,
473     $bookfundid, $bibitemnum, $rrp, $ecost, $gst, $budget,
474     $unitprice, $booksellerinvoicenumber);
475
476 Modifies an existing order. Updates the order with order number
477 C<$ordernumber> and biblionumber C<$biblionumber>. All other arguments
478 update the fields with the same name in the aqorders table of the Koha
479 database.
480
481 Entries with order number C<$ordernumber> in the aqorderbreakdown
482 table are also updated to the new book fund ID.
483
484 =back
485
486 =cut
487
488 sub ModOrder {
489     my (
490         $title,      $ordnum,   $quantity, $listprice, $bibnum,
491         $basketno,   $supplier, $who,      $notes,     $bookfund,
492         $bibitemnum, $rrp,      $ecost,    $gst,       $budget,
493         $cost,       $invoice,  $sort1,    $sort2,     $purchaseorder
494       )
495       = @_;
496     my $dbh = C4::Context->dbh;
497     my $query = "
498         UPDATE aqorders
499         SET    title=?,
500                quantity=?,listprice=?,basketno=?,
501                rrp=?,ecost=?,unitprice=?,booksellerinvoicenumber=?,
502                notes=?,sort1=?, sort2=?, purchaseordernumber=?
503         WHERE  ordernumber=? AND biblionumber=?
504     ";
505     my $sth = $dbh->prepare($query);
506     $sth->execute(
507         $title, $quantity, $listprice, $basketno, $rrp,
508         $ecost, $cost,     $invoice,   $notes,    $sort1,
509         $sort2, $purchaseorder,
510                 $ordnum,   $bibnum
511     );
512     $sth->finish;
513     my $branchcode;  
514     $query = "
515         UPDATE aqorderbreakdown
516         SET    bookfundid=?,branchcode=?
517         WHERE  ordernumber=?
518     ";
519     $sth = $dbh->prepare($query);
520
521     unless ( $sth->execute( $bookfund,$branchcode, $ordnum ) )
522     {    # zero rows affected [Bug 734]
523         my $query ="
524             INSERT INTO aqorderbreakdown
525                      (ordernumber,branchcode,bookfundid)
526             VALUES   (?,?,?)
527         ";
528         $sth = $dbh->prepare($query);
529         $sth->execute( $ordnum,$branchcode, $bookfund );
530     }
531     $sth->finish;
532 }
533
534 #------------------------------------------------------------#
535
536 =head3 ModOrderBiblioNumber
537
538 =over 4
539
540 &ModOrderBiblioNumber($biblioitemnumber,$ordnum, $biblionumber);
541
542 Modifies the biblioitemnumber for an existing order.
543 Updates the order with order number C<$ordernum> and biblionumber C<$biblionumber>.
544
545 =back
546
547 =cut
548
549 sub ModOrderBiblioNumber {
550     my ($biblioitemnumber,$ordnum, $biblionumber) = @_;
551     my $dbh = C4::Context->dbh;
552     my $query = "
553       UPDATE aqorders
554       SET    biblioitemnumber = ?
555       WHERE  ordernumber = ?
556       AND biblionumber =  ?";
557     my $sth = $dbh->prepare($query);
558     $sth->execute( $biblioitemnumber, $ordnum, $biblionumber );
559 }
560
561 #------------------------------------------------------------#
562
563 =head3 ModReceiveOrder
564
565 =over 4
566
567 &ModReceiveOrder($biblionumber, $ordernumber, $quantityreceived, $user,
568     $unitprice, $booksellerinvoicenumber, $biblioitemnumber,
569     $freight, $bookfund, $rrp);
570
571 Updates an order, to reflect the fact that it was received, at least
572 in part. All arguments not mentioned below update the fields with the
573 same name in the aqorders table of the Koha database.
574
575 If a partial order is received, splits the order into two.  The received
576 portion must have a booksellerinvoicenumber.  
577
578 Updates the order with bibilionumber C<$biblionumber> and ordernumber
579 C<$ordernumber>.
580
581 Also updates the book fund ID in the aqorderbreakdown table.
582
583 =back
584
585 =cut
586
587
588 sub ModReceiveOrder {
589     my (
590         $biblionumber,    $ordnum,  $quantrec, $user, $cost,
591         $invoiceno, $freight, $rrp, $bookfund, $datereceived
592       )
593       = @_;
594     my $dbh = C4::Context->dbh;
595 #     warn "DATE BEFORE : $daterecieved";
596 #    $daterecieved=POSIX::strftime("%Y-%m-%d",CORE::localtime) unless $daterecieved;
597 #     warn "DATE REC : $daterecieved";
598         $datereceived = C4::Dates->output('iso') unless $datereceived;
599     my $suggestionid = GetSuggestionFromBiblionumber( $dbh, $biblionumber );
600     if ($suggestionid) {
601         ModStatus( $suggestionid, 'AVAILABLE', '', $biblionumber );
602     }
603     # Allows libraries to change their bookfund during receiving orders
604     # allows them to adjust budgets
605     if ( C4::Context->preference("LooseBudgets") && $bookfund ) {
606         my $query = "
607             UPDATE aqorderbreakdown
608             SET    bookfundid=?
609             WHERE  ordernumber=?
610         ";
611         my $sth = $dbh->prepare($query);
612         $sth->execute( $bookfund, $ordnum );
613         $sth->finish;
614     }
615    
616         my $sth=$dbh->prepare("SELECT * FROM aqorders  LEFT JOIN aqorderbreakdown ON aqorders.ordernumber=aqorderbreakdown.ordernumber
617                                                         WHERE biblionumber=? AND aqorders.ordernumber=?");
618     $sth->execute($biblionumber,$ordnum);
619     my $order = $sth->fetchrow_hashref();
620     $sth->finish();
621         
622         if ( $order->{quantity} > $quantrec ) {
623         $sth=$dbh->prepare("update aqorders 
624                                                         set quantityreceived=?,datereceived=?,booksellerinvoicenumber=?, 
625                                                                 unitprice=?,freight=?,rrp=?,quantity=?
626                             where biblionumber=? and ordernumber=?");
627         $sth->execute($quantrec,$datereceived,$invoiceno,$cost,$freight,$rrp,$quantrec,$biblionumber,$ordnum);
628         $sth->finish;
629         # create a new order for the remaining items, and set its bookfund.
630         my $newOrder = NewOrder($order->{'basketno'},$order->{'biblionumber'},$order->{'title'}, $order->{'quantity'} - $quantrec,    
631                     $order->{'listprice'},$order->{'booksellerid'},$order->{'authorisedby'},$order->{'notes'},   
632                     $order->{'bookfundid'},$order->{'biblioitemnumber'},$order->{'rrp'},$order->{'ecost'},$order->{'gst'},
633                     $order->{'budget'},$order->{'unitcost'},$order->{'sub'},'',$order->{'sort1'},$order->{'sort2'},$order->{'purchaseordernumber'});
634   } else {
635         $sth=$dbh->prepare("update aqorders 
636                                                         set quantityreceived=?,datereceived=?,booksellerinvoicenumber=?, 
637                                                                 unitprice=?,freight=?,rrp=?
638                             where biblionumber=? and ordernumber=?");
639         $sth->execute($quantrec,$datereceived,$invoiceno,$cost,$freight,$rrp,$biblionumber,$ordnum);
640         $sth->finish;
641     }
642     return $datereceived;
643 }
644 #------------------------------------------------------------#
645
646 =head3 SearchOrder
647
648 @results = &SearchOrder($search, $biblionumber, $complete);
649
650 Searches for orders.
651
652 C<$search> may take one of several forms: if it is an ISBN,
653 C<&ordersearch> returns orders with that ISBN. If C<$search> is an
654 order number, C<&ordersearch> returns orders with that order number
655 and biblionumber C<$biblionumber>. Otherwise, C<$search> is considered
656 to be a space-separated list of search terms; in this case, all of the
657 terms must appear in the title (matching the beginning of title
658 words).
659
660 If C<$complete> is C<yes>, the results will include only completed
661 orders. In any case, C<&ordersearch> ignores cancelled orders.
662
663 C<&ordersearch> returns an array.
664 C<@results> is an array of references-to-hash with the following keys:
665
666 =over 4
667
668 =item C<author>
669
670 =item C<seriestitle>
671
672 =item C<branchcode>
673
674 =item C<bookfundid>
675
676 =back
677
678 =cut
679
680 sub SearchOrder {
681     my ( $search, $id, $biblionumber, $catview ) = @_;
682     my $dbh = C4::Context->dbh;
683     my @data = split( ' ', $search );
684     my @searchterms;
685     if ($id) {
686         @searchterms = ($id);
687     }
688     map { push( @searchterms, "$_%", "%$_%" ) } @data;
689     push( @searchterms, $search, $search, $biblionumber );
690     my $query;
691   ### FIXME  THIS CAN raise a problem if more THAN ONE biblioitem is linked to one biblio  
692     if ($id) {  
693         $query =
694           "SELECT *,biblio.title 
695            FROM aqorders 
696            LEFT JOIN biblio ON aqorders.biblionumber=biblio.biblionumber 
697            LEFT JOIN biblioitems ON biblioitems.biblionumber=biblio.biblionumber 
698            LEFT JOIN aqbasket ON aqorders.basketno = aqbasket.basketno
699             WHERE aqbasket.booksellerid = ?
700             AND ((datecancellationprinted is NULL)
701             OR (datecancellationprinted = '0000-00-00'))
702             AND (("
703           . (
704             join( " AND ",
705                 map { "(biblio.title like ? or biblio.title like ?)" } @data )
706           )
707           . ") OR biblioitems.isbn=? OR (aqorders.ordernumber=? AND aqorders.biblionumber=?)) ";
708
709     }
710     else {
711         $query =
712           " SELECT *,biblio.title
713             FROM   aqorders
714             LEFT JOIN biblio ON biblio.biblionumber=aqorders.biblionumber
715             LEFT JOIN aqbasket on aqorders.basketno=aqbasket.basketno
716             LEFT JOIN biblioitems ON biblioitems.biblionumber=biblio.biblionumber      
717             WHERE  ((datecancellationprinted is NULL)
718             OR     (datecancellationprinted = '0000-00-00'))
719             AND    (aqorders.quantityreceived < aqorders.quantity OR aqorders.quantityreceived is NULL)
720             AND (("
721           . (
722             join( " AND ",
723                 map { "(biblio.title like ? OR biblio.title like ?)" } @data )
724           )
725           . ") or biblioitems.isbn=? OR (aqorders.ordernumber=? AND aqorders.biblionumber=?)) ";
726     }
727     $query .= " GROUP BY aqorders.ordernumber";
728     ### $query
729     my $sth = $dbh->prepare($query);
730     $sth->execute(@searchterms);
731     my @results = ();
732     my $query2 = "
733         SELECT *
734         FROM   biblio
735         WHERE  biblionumber=?
736     ";
737     my $sth2 = $dbh->prepare($query2);
738     my $query3 = "
739         SELECT *
740         FROM   aqorderbreakdown
741         WHERE  ordernumber=?
742     ";
743     my $sth3 = $dbh->prepare($query3);
744
745     while ( my $data = $sth->fetchrow_hashref ) {
746         $sth2->execute( $data->{'biblionumber'} );
747         my $data2 = $sth2->fetchrow_hashref;
748         $data->{'author'}      = $data2->{'author'};
749         $data->{'seriestitle'} = $data2->{'seriestitle'};
750         $sth3->execute( $data->{'ordernumber'} );
751         my $data3 = $sth3->fetchrow_hashref;
752         $data->{'branchcode'} = $data3->{'branchcode'};
753         $data->{'bookfundid'} = $data3->{'bookfundid'};
754         push( @results, $data );
755     }
756     ### @results
757     $sth->finish;
758     $sth2->finish;
759     $sth3->finish;
760     return @results;
761 }
762
763 #------------------------------------------------------------#
764
765 =head3 DelOrder
766
767 =over 4
768
769 &DelOrder($biblionumber, $ordernumber);
770
771 Cancel the order with the given order and biblio numbers. It does not
772 delete any entries in the aqorders table, it merely marks them as
773 cancelled.
774
775 =back
776
777 =cut
778
779 sub DelOrder {
780     my ( $bibnum, $ordnum ) = @_;
781     my $dbh = C4::Context->dbh;
782     my $query = "
783         UPDATE aqorders
784         SET    datecancellationprinted=now()
785         WHERE  biblionumber=? AND ordernumber=?
786     ";
787     my $sth = $dbh->prepare($query);
788     $sth->execute( $bibnum, $ordnum );
789     $sth->finish;
790 }
791
792
793 =back
794
795 =head2 FUNCTIONS ABOUT PARCELS
796
797 =over 2
798
799 =cut
800
801 #------------------------------------------------------------#
802
803 =head3 GetParcel
804
805 =over 4
806
807 @results = &GetParcel($booksellerid, $code, $date);
808
809 Looks up all of the received items from the supplier with the given
810 bookseller ID at the given date, for the given code (bookseller Invoice number). Ignores cancelled and completed orders.
811
812 C<@results> is an array of references-to-hash. The keys of each element are fields from
813 the aqorders, biblio, and biblioitems tables of the Koha database.
814
815 C<@results> is sorted alphabetically by book title.
816
817 =back
818
819 =cut
820
821 sub GetParcel {
822     #gets all orders from a certain supplier, orders them alphabetically
823     my ( $supplierid, $code, $datereceived ) = @_;
824     my $dbh     = C4::Context->dbh;
825     my @results = ();
826     $code .= '%'
827       if $code;  # add % if we search on a given code (otherwise, let him empty)
828     my $strsth ="
829         SELECT  authorisedby,
830                 creationdate,
831                 aqbasket.basketno,
832                 closedate,surname,
833                 firstname,
834                 aqorders.biblionumber,
835                 aqorders.title,
836                 aqorders.ordernumber,
837                 aqorders.quantity,
838                 aqorders.quantityreceived,
839                 aqorders.unitprice,
840                 aqorders.listprice,
841                 aqorders.rrp,
842                 aqorders.ecost
843         FROM aqorders 
844         LEFT JOIN aqbasket ON aqbasket.basketno=aqorders.basketno
845         LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber
846         WHERE 
847             aqbasket.booksellerid = ?
848             AND aqorders.booksellerinvoicenumber LIKE ?
849             AND aqorders.datereceived = ? ";
850
851     my @query_params = ( $supplierid, $code, $datereceived );
852     if ( C4::Context->preference("IndependantBranches") ) {
853         my $userenv = C4::Context->userenv;
854         if ( ($userenv) && ( $userenv->{flags} != 1 ) ) {
855             $strsth .= " and (borrowers.branchcode = ?
856                           or borrowers.branchcode  = '')";
857             push @query_params, $userenv->{branch};
858         }
859     }
860     $strsth .= " ORDER BY aqbasket.basketno";
861     ### parcelinformation : $strsth
862     my $sth = $dbh->prepare($strsth);
863     $sth->execute( @query_params );
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 @query_params = ();
915     my $strsth ="
916         SELECT  aqorders.booksellerinvoicenumber,
917                 datereceived,purchaseordernumber,
918                 count(DISTINCT biblionumber) AS biblio,
919                 sum(quantity) AS itemsexpected,
920                 sum(quantityreceived) AS itemsreceived
921         FROM   aqorders LEFT JOIN aqbasket ON aqbasket.basketno = aqorders.basketno
922         WHERE aqbasket.booksellerid = $bookseller and datereceived IS NOT NULL
923     ";
924
925     if ( defined $code ) {
926         $strsth .= ' and aqorders.booksellerinvoicenumber like ? ';
927         # add a % to the end of the code to allow stemming.
928         push @query_params, "$code%";
929     }
930     
931     if ( defined $datefrom ) {
932         $strsth .= ' and datereceived >= ? ';
933         push @query_params, $datefrom;
934     }
935
936     if ( defined $dateto ) {
937         $strsth .=  'and datereceived <= ? ';
938         push @query_params, $dateto;
939     }
940
941     $strsth .= "group by aqorders.booksellerinvoicenumber,datereceived ";
942
943     # can't use a placeholder to place this column name.
944     # but, we could probably be checking to make sure it is a column that will be fetched.
945     $strsth .= "order by $order " if ($order);
946
947     my $sth = $dbh->prepare($strsth);
948
949     $sth->execute( @query_params );
950     my $results = $sth->fetchall_arrayref({});
951     $sth->finish;
952     return @$results;
953 }
954
955 #------------------------------------------------------------#
956
957 =head3 GetLateOrders
958
959 =over 4
960
961 @results = &GetLateOrders;
962
963 Searches for bookseller with late orders.
964
965 return:
966 the table of supplier with late issues. This table is full of hashref.
967
968 =back
969
970 =cut
971
972 sub GetLateOrders {
973     my $delay      = shift;
974     my $supplierid = shift;
975     my $branch     = shift;
976
977     my $dbh = C4::Context->dbh;
978
979     #BEWARE, order of parenthesis and LEFT JOIN is important for speed
980     my $strsth;
981     my $dbdriver = C4::Context->config("db_scheme") || "mysql";
982
983     my @query_params = ();
984
985     #    warn " $dbdriver";
986     if ( $dbdriver eq "mysql" ) {
987         $strsth = "
988             SELECT aqbasket.basketno,aqorders.ordernumber,
989                 DATE(aqbasket.closedate) AS orderdate,
990                 aqorders.quantity - IFNULL(aqorders.quantityreceived,0) AS quantity,
991                 aqorders.rrp AS unitpricesupplier,
992                 aqorders.ecost AS unitpricelib,
993                 (aqorders.quantity - IFNULL(aqorders.quantityreceived,0)) * aqorders.rrp AS subtotal,
994                 aqbookfund.bookfundname AS budget,
995                 borrowers.branchcode AS branch,
996                 aqbooksellers.name AS supplier,
997                 aqorders.title,
998                 biblio.author,
999                 biblioitems.publishercode AS publisher,
1000                 biblioitems.publicationyear,
1001                 DATEDIFF(CURDATE( ),closedate) AS latesince
1002             FROM  (((
1003                 (aqorders LEFT JOIN biblio ON biblio.biblionumber = aqorders.biblionumber)
1004             LEFT JOIN biblioitems ON  biblioitems.biblionumber=biblio.biblionumber)
1005             LEFT JOIN aqorderbreakdown ON aqorders.ordernumber = aqorderbreakdown.ordernumber)
1006             LEFT JOIN aqbookfund ON aqorderbreakdown.bookfundid = aqbookfund.bookfundid),
1007             (aqbasket LEFT JOIN borrowers ON aqbasket.authorisedby = borrowers.borrowernumber)
1008             LEFT JOIN aqbooksellers ON aqbasket.booksellerid = aqbooksellers.id
1009             WHERE aqorders.basketno = aqbasket.basketno
1010             AND (closedate <= DATE_SUB(CURDATE( ),INTERVAL ? DAY))
1011             AND ((datereceived = '' OR datereceived is null)
1012             OR (aqorders.quantityreceived < aqorders.quantity) )
1013         ";
1014
1015         push @query_params, $delay;
1016     
1017         if ( defined $supplierid ) {
1018             $strsth .= ' AND aqbasket.booksellerid = ? ';
1019             push @query_params, $supplierid;
1020         }
1021         
1022         if ( defined $branch ) {
1023             $strsth .= ' AND borrowers.branchcode like ? ';
1024             push @query_params, $branch;
1025         }
1026
1027         if ( C4::Context->preference("IndependantBranches")
1028              && C4::Context->userenv
1029              && C4::Context->userenv->{flags} != 1 ) {
1030             $strsth .= ' AND borrowers.branchcode like ? ';
1031             push @query_params, C4::Context->userenv->{branch};
1032         }
1033         
1034         $strsth .= " HAVING quantity       <> 0
1035                      AND unitpricesupplier <> 0
1036                      AND unitpricelib      <> 0
1037                      ORDER BY latesince, basketno, borrowers.branchcode, supplier ";
1038     } else {
1039         $strsth = "
1040             SELECT aqbasket.basketno,
1041                    DATE(aqbasket.closedate) AS orderdate,
1042                     aqorders.quantity, aqorders.rrp AS unitpricesupplier,
1043                     aqorders.ecost as unitpricelib,
1044                     aqorders.quantity * aqorders.rrp AS subtotal
1045                     aqbookfund.bookfundname AS budget,
1046                     borrowers.branchcode AS branch,
1047                     aqbooksellers.name AS supplier,
1048                     biblio.title,
1049                     biblio.author,
1050                     biblioitems.publishercode AS publisher,
1051                     biblioitems.publicationyear,
1052                     (CURDATE -  closedate) AS latesince
1053                     FROM(( (
1054                         (aqorders LEFT JOIN biblio on biblio.biblionumber = aqorders.biblionumber)
1055                         LEFT JOIN biblioitems on  biblioitems.biblionumber=biblio.biblionumber)
1056                         LEFT JOIN aqorderbreakdown on aqorders.ordernumber = aqorderbreakdown.ordernumber)
1057                         LEFT JOIN aqbookfund ON aqorderbreakdown.bookfundid = aqbookfund.bookfundid),
1058                         (aqbasket LEFT JOIN borrowers on aqbasket.authorisedby = borrowers.borrowernumber) LEFT JOIN aqbooksellers ON aqbasket.booksellerid = aqbooksellers.id
1059                     WHERE aqorders.basketno = aqbasket.basketno
1060                     AND (closedate <= (CURDATE -(INTERVAL $delay DAY))
1061                     AND ((datereceived = '' OR datereceived is null)
1062                     OR (aqorders.quantityreceived < aqorders.quantity) ) ";
1063         $strsth .= " AND aqbasket.booksellerid = $supplierid " if ($supplierid);
1064
1065         $strsth .= " AND borrowers.branchcode like \'" . $branch . "\'" if ($branch);
1066         $strsth .=" AND borrowers.branchcode like \'". C4::Context->userenv->{branch} . "\'"
1067             if (C4::Context->preference("IndependantBranches") && C4::Context->userenv->{flags} != 1 );
1068         $strsth .=" ORDER BY latesince,basketno,borrowers.branchcode, supplier";
1069     }
1070     my $sth = $dbh->prepare($strsth);
1071     $sth->execute( @query_params );
1072     my @results;
1073     my $hilighted = 1;
1074     while ( my $data = $sth->fetchrow_hashref ) {
1075         $data->{hilighted} = $hilighted if ( $hilighted > 0 );
1076         $data->{orderdate} = format_date( $data->{orderdate} );
1077         push @results, $data;
1078         $hilighted = -$hilighted;
1079     }
1080     $sth->finish;
1081     return @results;
1082 }
1083
1084 #------------------------------------------------------------#
1085
1086 =head3 GetHistory
1087
1088 =over 4
1089
1090 (\@order_loop, $total_qty, $total_price, $total_qtyreceived) = GetHistory( $title, $author, $name, $from_placed_on, $to_placed_on );
1091
1092   Retreives some acquisition history information
1093
1094   returns:
1095     $order_loop is a list of hashrefs that each look like this:
1096               {
1097                 'author'           => 'Twain, Mark',
1098                 'basketno'         => '1',
1099                 'biblionumber'     => '215',
1100                 'count'            => 1,
1101                 'creationdate'     => 'MM/DD/YYYY',
1102                 'datereceived'     => undef,
1103                 'ecost'            => '1.00',
1104                 'id'               => '1',
1105                 'invoicenumber'    => undef,
1106                 'name'             => '',
1107                 'ordernumber'      => '1',
1108                 'quantity'         => 1,
1109                 'quantityreceived' => undef,
1110                 'title'            => 'The Adventures of Huckleberry Finn'
1111               }
1112     $total_qty is the sum of all of the quantities in $order_loop
1113     $total_price is the cost of each in $order_loop times the quantity
1114     $total_qtyreceived is the sum of all of the quantityreceived entries in $order_loop
1115
1116 =back
1117
1118 =cut
1119
1120 sub GetHistory {
1121     my ( $title, $author, $name, $from_placed_on, $to_placed_on ) = @_;
1122     my @order_loop;
1123     my $total_qty         = 0;
1124     my $total_qtyreceived = 0;
1125     my $total_price       = 0;
1126
1127 # don't run the query if there are no parameters (list would be too long for sure !)
1128     if ( $title || $author || $name || $from_placed_on || $to_placed_on ) {
1129         my $dbh   = C4::Context->dbh;
1130         my $query ="
1131             SELECT
1132                 biblio.title,
1133                 biblio.author,
1134                 aqorders.basketno,
1135                 name,aqbasket.creationdate,
1136                 aqorders.datereceived,
1137                 aqorders.quantity,
1138                 aqorders.quantityreceived,
1139                 aqorders.ecost,
1140                 aqorders.ordernumber,
1141                 aqorders.booksellerinvoicenumber as invoicenumber,
1142                 aqbooksellers.id as id,
1143                 aqorders.biblionumber
1144             FROM aqorders 
1145             LEFT JOIN aqbasket ON aqorders.basketno=aqbasket.basketno 
1146             LEFT JOIN aqbooksellers ON aqbasket.booksellerid=aqbooksellers.id
1147             LEFT JOIN biblio ON biblio.biblionumber=aqorders.biblionumber";
1148
1149         $query .= " LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber"
1150           if ( C4::Context->preference("IndependantBranches") );
1151
1152         $query .= " WHERE (datecancellationprinted is NULL or datecancellationprinted='0000-00-00') ";
1153         
1154         my @query_params  = ();
1155         
1156         if ( defined $title ) {
1157             $query .= " AND biblio.title LIKE ? ";
1158             push @query_params, "%$title%";
1159         }
1160
1161         if ( defined $author ) {
1162             $query .= " AND biblio.author LIKE ? ";
1163             push @query_params, "%$author%";
1164         }
1165
1166         if ( defined $name ) {
1167             $query .= " AND name LIKE ? ";
1168             push @query_params, "%$name%";
1169         }            
1170
1171         if ( defined $from_placed_on ) {
1172             $query .= " AND creationdate >= ? ";
1173             push @query_params, $from_placed_on;
1174         }
1175
1176         if ( defined $to_placed_on ) {
1177             $query .= " AND creationdate <= ? ";
1178             push @query_params, $to_placed_on;
1179         }
1180
1181         if ( C4::Context->preference("IndependantBranches") ) {
1182             my $userenv = C4::Context->userenv;
1183             if ( ($userenv) && ( $userenv->{flags} != 1 ) ) {
1184                 $query .= " AND (borrowers.branchcode = ? OR borrowers.branchcode ='' ) ";
1185                 push @query_params, $userenv->{branch};
1186             }
1187         }
1188         $query .= " ORDER BY booksellerid";
1189         my $sth = $dbh->prepare($query);
1190         $sth->execute( @query_params );
1191         my $cnt = 1;
1192         while ( my $line = $sth->fetchrow_hashref ) {
1193             $line->{count} = $cnt++;
1194             $line->{toggle} = 1 if $cnt % 2;
1195             push @order_loop, $line;
1196             $line->{creationdate} = format_date( $line->{creationdate} );
1197             $line->{datereceived} = format_date( $line->{datereceived} );
1198             $total_qty         += $line->{'quantity'};
1199             $total_qtyreceived += $line->{'quantityreceived'};
1200             $total_price       += $line->{'quantity'} * $line->{'ecost'};
1201         }
1202     }
1203     return \@order_loop, $total_qty, $total_price, $total_qtyreceived;
1204 }
1205
1206 =head2 GetRecentAcqui
1207
1208    $results = GetRecentAcqui($days);
1209
1210    C<$results> is a ref to a table which containts hashref
1211
1212 =cut
1213
1214 sub GetRecentAcqui {
1215     my $limit  = shift;
1216     my $dbh    = C4::Context->dbh;
1217     my $query = "
1218         SELECT *
1219         FROM   biblio
1220         ORDER BY timestamp DESC
1221         LIMIT  0,".$limit;
1222
1223     my $sth = $dbh->prepare($query);
1224     $sth->execute;
1225     my @results;
1226     while(my $data = $sth->fetchrow_hashref){
1227         push @results,$data;
1228     }
1229     return \@results;
1230 }
1231
1232 1;
1233 __END__
1234
1235 =back
1236
1237 =head1 AUTHOR
1238
1239 Koha Developement team <info@koha.org>
1240
1241 =cut