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