Bug 10313 Fix link to invoice from orders
[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
17 # with Koha; if not, write to the Free Software Foundation, Inc.,
18 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
21 use strict;
22 use warnings;
23 use Carp;
24 use C4::Context;
25 use C4::Debug;
26 use C4::Dates qw(format_date format_date_in_iso);
27 use MARC::Record;
28 use C4::Suggestions;
29 use C4::Biblio;
30 use C4::Debug;
31 use C4::SQLHelper qw(InsertInTable);
32 use C4::Bookseller qw(GetBookSellerFromId);
33 use C4::Templates qw(gettemplate);
34
35 use Time::localtime;
36 use HTML::Entities;
37
38 use vars qw($VERSION @ISA @EXPORT);
39
40 BEGIN {
41     # set the version for version checking
42     $VERSION = 3.07.00.049;
43     require Exporter;
44     @ISA    = qw(Exporter);
45     @EXPORT = qw(
46         &GetBasket &NewBasket &CloseBasket &DelBasket &ModBasket
47         &GetBasketAsCSV &GetBasketGroupAsCSV
48         &GetBasketsByBookseller &GetBasketsByBasketgroup
49         &GetBasketsInfosByBookseller
50
51         &ModBasketHeader
52
53         &ModBasketgroup &NewBasketgroup &DelBasketgroup &GetBasketgroup &CloseBasketgroup
54         &GetBasketgroups &ReOpenBasketgroup
55
56         &NewOrder &DelOrder &ModOrder &GetPendingOrders &GetOrder &GetOrders &GetOrdersByBiblionumber
57         &GetOrderNumber &GetLateOrders &GetOrderFromItemnumber
58         &SearchOrder &GetHistory &GetRecentAcqui
59         &ModReceiveOrder &CancelReceipt &ModOrderBiblioitemNumber
60         &GetCancelledOrders
61         &GetLastOrderNotReceivedFromSubscriptionid &GetLastOrderReceivedFromSubscriptionid
62         &NewOrderItem &ModOrderItem &ModItemOrder
63
64         &GetParcels &GetParcel
65         &GetContracts &GetContract
66
67         &GetInvoices
68         &GetInvoice
69         &GetInvoiceDetails
70         &AddInvoice
71         &ModInvoice
72         &CloseInvoice
73         &ReopenInvoice
74
75         &GetItemnumbersFromOrder
76
77         &AddClaim
78     );
79 }
80
81
82
83
84
85 sub GetOrderFromItemnumber {
86     my ($itemnumber) = @_;
87     my $dbh          = C4::Context->dbh;
88     my $query        = qq|
89
90     SELECT  * from aqorders    LEFT JOIN aqorders_items
91     ON (     aqorders.ordernumber = aqorders_items.ordernumber   )
92     WHERE itemnumber = ?  |;
93
94     my $sth = $dbh->prepare($query);
95
96 #    $sth->trace(3);
97
98     $sth->execute($itemnumber);
99
100     my $order = $sth->fetchrow_hashref;
101     return ( $order  );
102
103 }
104
105 # Returns the itemnumber(s) associated with the ordernumber given in parameter
106 sub GetItemnumbersFromOrder {
107     my ($ordernumber) = @_;
108     my $dbh          = C4::Context->dbh;
109     my $query        = "SELECT itemnumber FROM aqorders_items WHERE ordernumber=?";
110     my $sth = $dbh->prepare($query);
111     $sth->execute($ordernumber);
112     my @tab;
113
114     while (my $order = $sth->fetchrow_hashref) {
115     push @tab, $order->{'itemnumber'};
116     }
117
118     return @tab;
119
120 }
121
122
123
124
125
126
127 =head1 NAME
128
129 C4::Acquisition - Koha functions for dealing with orders and acquisitions
130
131 =head1 SYNOPSIS
132
133 use C4::Acquisition;
134
135 =head1 DESCRIPTION
136
137 The functions in this module deal with acquisitions, managing book
138 orders, basket and parcels.
139
140 =head1 FUNCTIONS
141
142 =head2 FUNCTIONS ABOUT BASKETS
143
144 =head3 GetBasket
145
146   $aqbasket = &GetBasket($basketnumber);
147
148 get all basket informations in aqbasket for a given basket
149
150 B<returns:> informations for a given basket returned as a hashref.
151
152 =cut
153
154 sub GetBasket {
155     my ($basketno) = @_;
156     my $dbh        = C4::Context->dbh;
157     my $query = "
158         SELECT  aqbasket.*,
159                 concat( b.firstname,' ',b.surname) AS authorisedbyname,
160                 b.branchcode AS branch
161         FROM    aqbasket
162         LEFT JOIN borrowers b ON aqbasket.authorisedby=b.borrowernumber
163         WHERE basketno=?
164     ";
165     my $sth=$dbh->prepare($query);
166     $sth->execute($basketno);
167     my $basket = $sth->fetchrow_hashref;
168     return ( $basket );
169 }
170
171 #------------------------------------------------------------#
172
173 =head3 NewBasket
174
175   $basket = &NewBasket( $booksellerid, $authorizedby, $basketname, 
176       $basketnote, $basketbooksellernote, $basketcontractnumber, $deliveryplace, $billingplace );
177
178 Create a new basket in aqbasket table
179
180 =over
181
182 =item C<$booksellerid> is a foreign key in the aqbasket table
183
184 =item C<$authorizedby> is the username of who created the basket
185
186 =back
187
188 The other parameters are optional, see ModBasketHeader for more info on them.
189
190 =cut
191
192 sub NewBasket {
193     my ( $booksellerid, $authorisedby, $basketname, $basketnote,
194         $basketbooksellernote, $basketcontractnumber, $deliveryplace,
195         $billingplace ) = @_;
196     my $dbh = C4::Context->dbh;
197     my $query =
198         'INSERT INTO aqbasket (creationdate,booksellerid,authorisedby) '
199       . 'VALUES  (now(),?,?)';
200     $dbh->do( $query, {}, $booksellerid, $authorisedby );
201
202     my $basket = $dbh->{mysql_insertid};
203     $basketname           ||= q{}; # default to empty strings
204     $basketnote           ||= q{};
205     $basketbooksellernote ||= q{};
206     ModBasketHeader( $basket, $basketname, $basketnote, $basketbooksellernote,
207         $basketcontractnumber, $booksellerid, $deliveryplace, $billingplace );
208     return $basket;
209 }
210
211 #------------------------------------------------------------#
212
213 =head3 CloseBasket
214
215   &CloseBasket($basketno);
216
217 close a basket (becomes unmodifiable,except for recieves)
218
219 =cut
220
221 sub CloseBasket {
222     my ($basketno) = @_;
223     my $dbh        = C4::Context->dbh;
224     my $query = "
225         UPDATE aqbasket
226         SET    closedate=now()
227         WHERE  basketno=?
228     ";
229     my $sth = $dbh->prepare($query);
230     $sth->execute($basketno);
231 }
232
233 #------------------------------------------------------------#
234
235 =head3 GetBasketAsCSV
236
237   &GetBasketAsCSV($basketno);
238
239 Export a basket as CSV
240
241 $cgi parameter is needed for column name translation
242
243 =cut
244
245 sub GetBasketAsCSV {
246     my ($basketno, $cgi) = @_;
247     my $basket = GetBasket($basketno);
248     my @orders = GetOrders($basketno);
249     my $contract = GetContract($basket->{'contractnumber'});
250
251     my $template = C4::Templates::gettemplate("acqui/csv/basket.tmpl", "intranet", $cgi);
252
253     my @rows;
254     foreach my $order (@orders) {
255         my $bd = GetBiblioData( $order->{'biblionumber'} );
256         my $row = {
257             contractname => $contract->{'contractname'},
258             ordernumber => $order->{'ordernumber'},
259             entrydate => $order->{'entrydate'},
260             isbn => $order->{'isbn'},
261             author => $bd->{'author'},
262             title => $bd->{'title'},
263             publicationyear => $bd->{'publicationyear'},
264             publishercode => $bd->{'publishercode'},
265             collectiontitle => $bd->{'collectiontitle'},
266             notes => $order->{'notes'},
267             quantity => $order->{'quantity'},
268             rrp => $order->{'rrp'},
269             deliveryplace => C4::Branch::GetBranchName( $basket->{'deliveryplace'} ),
270             billingplace => C4::Branch::GetBranchName( $basket->{'billingplace'} ),
271         };
272         foreach(qw(
273             contractname author title publishercode collectiontitle notes
274             deliveryplace billingplace
275         ) ) {
276             # Double the quotes to not be interpreted as a field end
277             $row->{$_} =~ s/"/""/g if $row->{$_};
278         }
279         push @rows, $row;
280     }
281
282     @rows = sort {
283         if(defined $a->{publishercode} and defined $b->{publishercode}) {
284             $a->{publishercode} cmp $b->{publishercode};
285         }
286     } @rows;
287
288     $template->param(rows => \@rows);
289
290     return $template->output;
291 }
292
293
294 =head3 GetBasketGroupAsCSV
295
296 =over 4
297
298 &GetBasketGroupAsCSV($basketgroupid);
299
300 Export a basket group as CSV
301
302 $cgi parameter is needed for column name translation
303
304 =back
305
306 =cut
307
308 sub GetBasketGroupAsCSV {
309     my ($basketgroupid, $cgi) = @_;
310     my $baskets = GetBasketsByBasketgroup($basketgroupid);
311
312     my $template = C4::Templates::gettemplate('acqui/csv/basketgroup.tmpl', 'intranet', $cgi);
313
314     my @rows;
315     for my $basket (@$baskets) {
316         my @orders     = GetOrders( $$basket{basketno} );
317         my $contract   = GetContract( $$basket{contractnumber} );
318         my $bookseller = GetBookSellerFromId( $$basket{booksellerid} );
319         my $basketgroup = GetBasketgroup( $$basket{basketgroupid} );
320
321         foreach my $order (@orders) {
322             my $bd = GetBiblioData( $order->{'biblionumber'} );
323             my $row = {
324                 clientnumber => $bookseller->{accountnumber},
325                 basketname => $basket->{basketname},
326                 ordernumber => $order->{ordernumber},
327                 author => $bd->{author},
328                 title => $bd->{title},
329                 publishercode => $bd->{publishercode},
330                 publicationyear => $bd->{publicationyear},
331                 collectiontitle => $bd->{collectiontitle},
332                 isbn => $order->{isbn},
333                 quantity => $order->{quantity},
334                 rrp => $order->{rrp},
335                 discount => $bookseller->{discount},
336                 ecost => $order->{ecost},
337                 notes => $order->{notes},
338                 entrydate => $order->{entrydate},
339                 booksellername => $bookseller->{name},
340                 bookselleraddress => $bookseller->{address1},
341                 booksellerpostal => $bookseller->{postal},
342                 contractnumber => $contract->{contractnumber},
343                 contractname => $contract->{contractname},
344                 basketgroupdeliveryplace => C4::Branch::GetBranchName( $basketgroup->{deliveryplace} ),
345                 basketgroupbillingplace => C4::Branch::GetBranchName( $basketgroup->{billingplace} ),
346                 basketdeliveryplace => C4::Branch::GetBranchName( $basket->{deliveryplace} ),
347                 basketbillingplace => C4::Branch::GetBranchName( $basket->{billingplace} ),
348             };
349             foreach(qw(
350                 basketname author title publishercode collectiontitle notes
351                 booksellername bookselleraddress booksellerpostal contractname
352                 basketgroupdeliveryplace basketgroupbillingplace
353                 basketdeliveryplace basketbillingplace
354             ) ) {
355                 # Double the quotes to not be interpreted as a field end
356                 $row->{$_} =~ s/"/""/g if $row->{$_};
357             }
358             push @rows, $row;
359          }
360      }
361     $template->param(rows => \@rows);
362
363     return $template->output;
364
365 }
366
367 =head3 CloseBasketgroup
368
369   &CloseBasketgroup($basketgroupno);
370
371 close a basketgroup
372
373 =cut
374
375 sub CloseBasketgroup {
376     my ($basketgroupno) = @_;
377     my $dbh        = C4::Context->dbh;
378     my $sth = $dbh->prepare("
379         UPDATE aqbasketgroups
380         SET    closed=1
381         WHERE  id=?
382     ");
383     $sth->execute($basketgroupno);
384 }
385
386 #------------------------------------------------------------#
387
388 =head3 ReOpenBaskergroup($basketgroupno)
389
390   &ReOpenBaskergroup($basketgroupno);
391
392 reopen a basketgroup
393
394 =cut
395
396 sub ReOpenBasketgroup {
397     my ($basketgroupno) = @_;
398     my $dbh        = C4::Context->dbh;
399     my $sth = $dbh->prepare("
400         UPDATE aqbasketgroups
401         SET    closed=0
402         WHERE  id=?
403     ");
404     $sth->execute($basketgroupno);
405 }
406
407 #------------------------------------------------------------#
408
409
410 =head3 DelBasket
411
412   &DelBasket($basketno);
413
414 Deletes the basket that has basketno field $basketno in the aqbasket table.
415
416 =over
417
418 =item C<$basketno> is the primary key of the basket in the aqbasket table.
419
420 =back
421
422 =cut
423
424 sub DelBasket {
425     my ( $basketno ) = @_;
426     my $query = "DELETE FROM aqbasket WHERE basketno=?";
427     my $dbh = C4::Context->dbh;
428     my $sth = $dbh->prepare($query);
429     $sth->execute($basketno);
430     $sth->finish;
431 }
432
433 #------------------------------------------------------------#
434
435 =head3 ModBasket
436
437   &ModBasket($basketinfo);
438
439 Modifies a basket, using a hashref $basketinfo for the relevant information, only $basketinfo->{'basketno'} is required.
440
441 =over
442
443 =item C<$basketno> is the primary key of the basket in the aqbasket table.
444
445 =back
446
447 =cut
448
449 sub ModBasket {
450     my $basketinfo = shift;
451     my $query = "UPDATE aqbasket SET ";
452     my @params;
453     foreach my $key (keys %$basketinfo){
454         if ($key ne 'basketno'){
455             $query .= "$key=?, ";
456             push(@params, $basketinfo->{$key} || undef );
457         }
458     }
459 # get rid of the "," at the end of $query
460     if (substr($query, length($query)-2) eq ', '){
461         chop($query);
462         chop($query);
463         $query .= ' ';
464     }
465     $query .= "WHERE basketno=?";
466     push(@params, $basketinfo->{'basketno'});
467     my $dbh = C4::Context->dbh;
468     my $sth = $dbh->prepare($query);
469     $sth->execute(@params);
470     $sth->finish;
471 }
472
473 #------------------------------------------------------------#
474
475 =head3 ModBasketHeader
476
477   &ModBasketHeader($basketno, $basketname, $note, $booksellernote, $contractnumber, $booksellerid);
478
479 Modifies a basket's header.
480
481 =over
482
483 =item C<$basketno> is the "basketno" field in the "aqbasket" table;
484
485 =item C<$basketname> is the "basketname" field in the "aqbasket" table;
486
487 =item C<$note> is the "note" field in the "aqbasket" table;
488
489 =item C<$booksellernote> is the "booksellernote" field in the "aqbasket" table;
490
491 =item C<$contractnumber> is the "contractnumber" (foreign) key in the "aqbasket" table.
492
493 =item C<$booksellerid> is the id (foreign) key in the "aqbooksellers" table for the vendor.
494
495 =item C<$deliveryplace> is the "deliveryplace" field in the aqbasket table.
496
497 =item C<$billingplace> is the "billingplace" field in the aqbasket table.
498
499 =back
500
501 =cut
502
503 sub ModBasketHeader {
504     my ($basketno, $basketname, $note, $booksellernote, $contractnumber, $booksellerid, $deliveryplace, $billingplace) = @_;
505     my $query = qq{
506         UPDATE aqbasket
507         SET basketname=?, note=?, booksellernote=?, booksellerid=?, deliveryplace=?, billingplace=?
508         WHERE basketno=?
509     };
510
511     my $dbh = C4::Context->dbh;
512     my $sth = $dbh->prepare($query);
513     $sth->execute($basketname, $note, $booksellernote, $booksellerid, $deliveryplace, $billingplace, $basketno);
514
515     if ( $contractnumber ) {
516         my $query2 ="UPDATE aqbasket SET contractnumber=? WHERE basketno=?";
517         my $sth2 = $dbh->prepare($query2);
518         $sth2->execute($contractnumber,$basketno);
519         $sth2->finish;
520     }
521     $sth->finish;
522 }
523
524 #------------------------------------------------------------#
525
526 =head3 GetBasketsByBookseller
527
528   @results = &GetBasketsByBookseller($booksellerid, $extra);
529
530 Returns a list of hashes of all the baskets that belong to bookseller 'booksellerid'.
531
532 =over
533
534 =item C<$booksellerid> is the 'id' field of the bookseller in the aqbooksellers table
535
536 =item C<$extra> is the extra sql parameters, can be
537
538  $extra->{groupby}: group baskets by column
539     ex. $extra->{groupby} = aqbasket.basketgroupid
540  $extra->{orderby}: order baskets by column
541  $extra->{limit}: limit number of results (can be helpful for pagination)
542
543 =back
544
545 =cut
546
547 sub GetBasketsByBookseller {
548     my ($booksellerid, $extra) = @_;
549     my $query = "SELECT * FROM aqbasket WHERE booksellerid=?";
550     if ($extra){
551         if ($extra->{groupby}) {
552             $query .= " GROUP by $extra->{groupby}";
553         }
554         if ($extra->{orderby}){
555             $query .= " ORDER by $extra->{orderby}";
556         }
557         if ($extra->{limit}){
558             $query .= " LIMIT $extra->{limit}";
559         }
560     }
561     my $dbh = C4::Context->dbh;
562     my $sth = $dbh->prepare($query);
563     $sth->execute($booksellerid);
564     my $results = $sth->fetchall_arrayref({});
565     $sth->finish;
566     return $results
567 }
568
569 =head3 GetBasketsInfosByBookseller
570
571     my $baskets = GetBasketsInfosByBookseller($supplierid);
572
573 Returns in a arrayref of hashref all about booksellers baskets, plus:
574     total_biblios: Number of distinct biblios in basket
575     total_items: Number of items in basket
576     expected_items: Number of non-received items in basket
577
578 =cut
579
580 sub GetBasketsInfosByBookseller {
581     my ($supplierid, $allbaskets) = @_;
582
583     return unless $supplierid;
584
585     my $dbh = C4::Context->dbh;
586     my $query = qq{
587         SELECT aqbasket.*,
588           SUM(aqorders.quantity) AS total_items,
589           COUNT(DISTINCT aqorders.biblionumber) AS total_biblios,
590           SUM(
591             IF(aqorders.datereceived IS NULL
592               AND aqorders.datecancellationprinted IS NULL
593             , aqorders.quantity
594             , 0)
595           ) AS expected_items
596         FROM aqbasket
597           LEFT JOIN aqorders ON aqorders.basketno = aqbasket.basketno
598         WHERE booksellerid = ?};
599     if(!$allbaskets) {
600         $query.=" AND (closedate IS NULL OR (aqorders.quantity > aqorders.quantityreceived AND datecancellationprinted IS NULL))";
601     }
602     $query.=" GROUP BY aqbasket.basketno";
603
604     my $sth = $dbh->prepare($query);
605     $sth->execute($supplierid);
606     return $sth->fetchall_arrayref({});
607 }
608
609
610 #------------------------------------------------------------#
611
612 =head3 GetBasketsByBasketgroup
613
614   $baskets = &GetBasketsByBasketgroup($basketgroupid);
615
616 Returns a reference to all baskets that belong to basketgroup $basketgroupid.
617
618 =cut
619
620 sub GetBasketsByBasketgroup {
621     my $basketgroupid = shift;
622     my $query = qq{
623         SELECT *, aqbasket.booksellerid as booksellerid
624         FROM aqbasket
625         LEFT JOIN aqcontract USING(contractnumber) WHERE basketgroupid=?
626     };
627     my $dbh = C4::Context->dbh;
628     my $sth = $dbh->prepare($query);
629     $sth->execute($basketgroupid);
630     my $results = $sth->fetchall_arrayref({});
631     $sth->finish;
632     return $results
633 }
634
635 #------------------------------------------------------------#
636
637 =head3 NewBasketgroup
638
639   $basketgroupid = NewBasketgroup(\%hashref);
640
641 Adds a basketgroup to the aqbasketgroups table, and add the initial baskets to it.
642
643 $hashref->{'booksellerid'} is the 'id' field of the bookseller in the aqbooksellers table,
644
645 $hashref->{'name'} is the 'name' field of the basketgroup in the aqbasketgroups table,
646
647 $hashref->{'basketlist'} is a list reference of the 'id's of the baskets that belong to this group,
648
649 $hashref->{'billingplace'} is the 'billingplace' field of the basketgroup in the aqbasketgroups table,
650
651 $hashref->{'deliveryplace'} is the 'deliveryplace' field of the basketgroup in the aqbasketgroups table,
652
653 $hashref->{'freedeliveryplace'} is the 'freedeliveryplace' field of the basketgroup in the aqbasketgroups table,
654
655 $hashref->{'deliverycomment'} is the 'deliverycomment' field of the basketgroup in the aqbasketgroups table,
656
657 $hashref->{'closed'} is the 'closed' field of the aqbasketgroups table, it is false if 0, true otherwise.
658
659 =cut
660
661 sub NewBasketgroup {
662     my $basketgroupinfo = shift;
663     die "booksellerid is required to create a basketgroup" unless $basketgroupinfo->{'booksellerid'};
664     my $query = "INSERT INTO aqbasketgroups (";
665     my @params;
666     foreach my $field (qw(name billingplace deliveryplace freedeliveryplace deliverycomment closed)) {
667         if ( defined $basketgroupinfo->{$field} ) {
668             $query .= "$field, ";
669             push(@params, $basketgroupinfo->{$field});
670         }
671     }
672     $query .= "booksellerid) VALUES (";
673     foreach (@params) {
674         $query .= "?, ";
675     }
676     $query .= "?)";
677     push(@params, $basketgroupinfo->{'booksellerid'});
678     my $dbh = C4::Context->dbh;
679     my $sth = $dbh->prepare($query);
680     $sth->execute(@params);
681     my $basketgroupid = $dbh->{'mysql_insertid'};
682     if( $basketgroupinfo->{'basketlist'} ) {
683         foreach my $basketno (@{$basketgroupinfo->{'basketlist'}}) {
684             my $query2 = "UPDATE aqbasket SET basketgroupid=? WHERE basketno=?";
685             my $sth2 = $dbh->prepare($query2);
686             $sth2->execute($basketgroupid, $basketno);
687         }
688     }
689     return $basketgroupid;
690 }
691
692 #------------------------------------------------------------#
693
694 =head3 ModBasketgroup
695
696   ModBasketgroup(\%hashref);
697
698 Modifies a basketgroup in the aqbasketgroups table, and add the baskets to it.
699
700 $hashref->{'id'} is the 'id' field of the basketgroup in the aqbasketgroup table, this parameter is mandatory,
701
702 $hashref->{'name'} is the 'name' field of the basketgroup in the aqbasketgroups table,
703
704 $hashref->{'basketlist'} is a list reference of the 'id's of the baskets that belong to this group,
705
706 $hashref->{'billingplace'} is the 'billingplace' field of the basketgroup in the aqbasketgroups table,
707
708 $hashref->{'deliveryplace'} is the 'deliveryplace' field of the basketgroup in the aqbasketgroups table,
709
710 $hashref->{'freedeliveryplace'} is the 'freedeliveryplace' field of the basketgroup in the aqbasketgroups table,
711
712 $hashref->{'deliverycomment'} is the 'deliverycomment' field of the basketgroup in the aqbasketgroups table,
713
714 $hashref->{'closed'} is the 'closed' field of the aqbasketgroups table, it is false if 0, true otherwise.
715
716 =cut
717
718 sub ModBasketgroup {
719     my $basketgroupinfo = shift;
720     die "basketgroup id is required to edit a basketgroup" unless $basketgroupinfo->{'id'};
721     my $dbh = C4::Context->dbh;
722     my $query = "UPDATE aqbasketgroups SET ";
723     my @params;
724     foreach my $field (qw(name billingplace deliveryplace freedeliveryplace deliverycomment closed)) {
725         if ( defined $basketgroupinfo->{$field} ) {
726             $query .= "$field=?, ";
727             push(@params, $basketgroupinfo->{$field});
728         }
729     }
730     chop($query);
731     chop($query);
732     $query .= " WHERE id=?";
733     push(@params, $basketgroupinfo->{'id'});
734     my $sth = $dbh->prepare($query);
735     $sth->execute(@params);
736
737     $sth = $dbh->prepare('UPDATE aqbasket SET basketgroupid = NULL WHERE basketgroupid = ?');
738     $sth->execute($basketgroupinfo->{'id'});
739
740     if($basketgroupinfo->{'basketlist'} && @{$basketgroupinfo->{'basketlist'}}){
741         $sth = $dbh->prepare("UPDATE aqbasket SET basketgroupid=? WHERE basketno=?");
742         foreach my $basketno (@{$basketgroupinfo->{'basketlist'}}) {
743             $sth->execute($basketgroupinfo->{'id'}, $basketno);
744             $sth->finish;
745         }
746     }
747     $sth->finish;
748 }
749
750 #------------------------------------------------------------#
751
752 =head3 DelBasketgroup
753
754   DelBasketgroup($basketgroupid);
755
756 Deletes a basketgroup in the aqbasketgroups table, and removes the reference to it from the baskets,
757
758 =over
759
760 =item C<$basketgroupid> is the 'id' field of the basket in the aqbasketgroup table
761
762 =back
763
764 =cut
765
766 sub DelBasketgroup {
767     my $basketgroupid = shift;
768     die "basketgroup id is required to edit a basketgroup" unless $basketgroupid;
769     my $query = "DELETE FROM aqbasketgroups WHERE id=?";
770     my $dbh = C4::Context->dbh;
771     my $sth = $dbh->prepare($query);
772     $sth->execute($basketgroupid);
773     $sth->finish;
774 }
775
776 #------------------------------------------------------------#
777
778
779 =head2 FUNCTIONS ABOUT ORDERS
780
781 =head3 GetBasketgroup
782
783   $basketgroup = &GetBasketgroup($basketgroupid);
784
785 Returns a reference to the hash containing all infermation about the basketgroup.
786
787 =cut
788
789 sub GetBasketgroup {
790     my $basketgroupid = shift;
791     die "basketgroup id is required to edit a basketgroup" unless $basketgroupid;
792     my $query = "SELECT * FROM aqbasketgroups WHERE id=?";
793     my $dbh = C4::Context->dbh;
794     my $sth = $dbh->prepare($query);
795     $sth->execute($basketgroupid);
796     my $result = $sth->fetchrow_hashref;
797     $sth->finish;
798     return $result
799 }
800
801 #------------------------------------------------------------#
802
803 =head3 GetBasketgroups
804
805   $basketgroups = &GetBasketgroups($booksellerid);
806
807 Returns a reference to the array of all the basketgroups of bookseller $booksellerid.
808
809 =cut
810
811 sub GetBasketgroups {
812     my $booksellerid = shift;
813     die 'bookseller id is required to edit a basketgroup' unless $booksellerid;
814     my $query = 'SELECT * FROM aqbasketgroups WHERE booksellerid=? ORDER BY id DESC';
815     my $dbh = C4::Context->dbh;
816     my $sth = $dbh->prepare($query);
817     $sth->execute($booksellerid);
818     return $sth->fetchall_arrayref({});
819 }
820
821 #------------------------------------------------------------#
822
823 =head2 FUNCTIONS ABOUT ORDERS
824
825 =cut
826
827 #------------------------------------------------------------#
828
829 =head3 GetPendingOrders
830
831 $orders = &GetPendingOrders($supplierid,$grouped,$owner,$basketno,$ordernumber,$search,$ean);
832
833 Finds pending orders from the bookseller with the given ID. Ignores
834 completed and cancelled orders.
835
836 C<$booksellerid> contains the bookseller identifier
837 C<$owner> contains 0 or 1. 0 means any owner. 1 means only the list of orders entered by the user itself.
838 C<$grouped> is a boolean that, if set to 1 will group all order lines of the same basket
839 in a single result line
840 C<$orders> is a reference-to-array; each element is a reference-to-hash.
841
842 Used also by the filter in parcel.pl
843 I have added:
844
845 C<$ordernumber>
846 C<$search>
847 C<$ean>
848
849 These give the value of the corresponding field in the aqorders table
850 of the Koha database.
851
852 Results are ordered from most to least recent.
853
854 =cut
855
856 sub GetPendingOrders {
857     my ($supplierid,$grouped,$owner,$basketno,$ordernumber,$search,$ean) = @_;
858     my $dbh = C4::Context->dbh;
859     my $strsth = "
860         SELECT ".($grouped?"count(*),":"")."aqbasket.basketno,
861                surname,firstname,biblio.*,biblioitems.isbn,
862                aqbasket.closedate, aqbasket.creationdate, aqbasket.basketname,
863                aqorders.*
864         FROM aqorders
865         LEFT JOIN aqbasket ON aqbasket.basketno=aqorders.basketno
866         LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber
867         LEFT JOIN biblio ON biblio.biblionumber=aqorders.biblionumber
868         LEFT JOIN biblioitems ON biblioitems.biblionumber=biblio.biblionumber
869         WHERE (quantity > quantityreceived OR quantityreceived is NULL)
870         AND datecancellationprinted IS NULL";
871     my @query_params;
872     my $userenv = C4::Context->userenv;
873     if ( C4::Context->preference("IndependentBranches") ) {
874         if ( ($userenv) && ( $userenv->{flags} != 1 ) ) {
875             $strsth .= " AND (borrowers.branchcode = ?
876                         or borrowers.branchcode  = '')";
877             push @query_params, $userenv->{branch};
878         }
879     }
880     if ($supplierid) {
881         $strsth .= " AND aqbasket.booksellerid = ?";
882         push @query_params, $supplierid;
883     }
884     if($ordernumber){
885         $strsth .= " AND (aqorders.ordernumber=?)";
886         push @query_params, $ordernumber;
887     }
888     if($search){
889         $strsth .= " AND (biblio.title like ? OR biblio.author LIKE ? OR biblioitems.isbn like ?)";
890         push @query_params, ("%$search%","%$search%","%$search%");
891     }
892     if ($ean) {
893         $strsth .= " AND biblioitems.ean = ?";
894         push @query_params, $ean;
895     }
896     if ($basketno) {
897         $strsth .= " AND aqbasket.basketno=? ";
898         push @query_params, $basketno;
899     }
900     if ($owner) {
901         $strsth .= " AND aqbasket.authorisedby=? ";
902         push @query_params, $userenv->{'number'};
903     }
904     $strsth .= " group by aqbasket.basketno" if $grouped;
905     $strsth .= " order by aqbasket.basketno";
906     my $sth = $dbh->prepare($strsth);
907     $sth->execute( @query_params );
908     my $results = $sth->fetchall_arrayref({});
909     $sth->finish;
910     return $results;
911 }
912
913 #------------------------------------------------------------#
914
915 =head3 GetOrders
916
917   @orders = &GetOrders($basketnumber, $orderby);
918
919 Looks up the pending (non-cancelled) orders with the given basket
920 number. If C<$booksellerID> is non-empty, only orders from that seller
921 are returned.
922
923 return :
924 C<&basket> returns a two-element array. C<@orders> is an array of
925 references-to-hash, whose keys are the fields from the aqorders,
926 biblio, and biblioitems tables in the Koha database.
927
928 =cut
929
930 sub GetOrders {
931     my ( $basketno, $orderby ) = @_;
932     my $dbh   = C4::Context->dbh;
933     my $query  ="
934         SELECT biblio.*,biblioitems.*,
935                 aqorders.*,
936                 aqbudgets.*,
937                 biblio.title
938         FROM    aqorders
939             LEFT JOIN aqbudgets        ON aqbudgets.budget_id = aqorders.budget_id
940             LEFT JOIN biblio           ON biblio.biblionumber = aqorders.biblionumber
941             LEFT JOIN biblioitems      ON biblioitems.biblionumber =biblio.biblionumber
942         WHERE   basketno=?
943             AND (datecancellationprinted IS NULL OR datecancellationprinted='0000-00-00')
944     ";
945
946     $orderby = "biblioitems.publishercode,biblio.title" unless $orderby;
947     $query .= " ORDER BY $orderby";
948     my $sth = $dbh->prepare($query);
949     $sth->execute($basketno);
950     my $results = $sth->fetchall_arrayref({});
951     $sth->finish;
952     return @$results;
953 }
954
955 #------------------------------------------------------------#
956 =head3 GetOrdersByBiblionumber
957
958   @orders = &GetOrdersByBiblionumber($biblionumber);
959
960 Looks up the orders with linked to a specific $biblionumber, including
961 cancelled orders and received orders.
962
963 return :
964 C<@orders> is an array of references-to-hash, whose keys are the
965 fields from the aqorders, biblio, and biblioitems tables in the Koha database.
966
967 =cut
968
969 sub GetOrdersByBiblionumber {
970     my $biblionumber = shift;
971     return unless $biblionumber;
972     my $dbh   = C4::Context->dbh;
973     my $query  ="
974         SELECT biblio.*,biblioitems.*,
975                 aqorders.*,
976                 aqbudgets.*
977         FROM    aqorders
978             LEFT JOIN aqbudgets        ON aqbudgets.budget_id = aqorders.budget_id
979             LEFT JOIN biblio           ON biblio.biblionumber = aqorders.biblionumber
980             LEFT JOIN biblioitems      ON biblioitems.biblionumber =biblio.biblionumber
981         WHERE   aqorders.biblionumber=?
982     ";
983     my $sth = $dbh->prepare($query);
984     $sth->execute($biblionumber);
985     my $results = $sth->fetchall_arrayref({});
986     $sth->finish;
987     return @$results;
988 }
989
990 #------------------------------------------------------------#
991
992 =head3 GetOrderNumber
993
994   $ordernumber = &GetOrderNumber($biblioitemnumber, $biblionumber);
995
996 Looks up the ordernumber with the given biblionumber and biblioitemnumber.
997
998 Returns the number of this order.
999
1000 =over
1001
1002 =item C<$ordernumber> is the order number.
1003
1004 =back
1005
1006 =cut
1007
1008 sub GetOrderNumber {
1009     my ( $biblionumber,$biblioitemnumber ) = @_;
1010     my $dbh = C4::Context->dbh;
1011     my $query = "
1012         SELECT ordernumber
1013         FROM   aqorders
1014         WHERE  biblionumber=?
1015         AND    biblioitemnumber=?
1016     ";
1017     my $sth = $dbh->prepare($query);
1018     $sth->execute( $biblionumber, $biblioitemnumber );
1019
1020     return $sth->fetchrow;
1021 }
1022
1023 #------------------------------------------------------------#
1024
1025 =head3 GetOrder
1026
1027   $order = &GetOrder($ordernumber);
1028
1029 Looks up an order by order number.
1030
1031 Returns a reference-to-hash describing the order. The keys of
1032 C<$order> are fields from the biblio, biblioitems, aqorders tables of the Koha database.
1033
1034 =cut
1035
1036 sub GetOrder {
1037     my ($ordernumber) = @_;
1038     my $dbh      = C4::Context->dbh;
1039     my $query = "
1040         SELECT biblioitems.*, biblio.*, aqorders.*
1041         FROM   aqorders
1042         LEFT JOIN biblio on           biblio.biblionumber=aqorders.biblionumber
1043         LEFT JOIN biblioitems on       biblioitems.biblionumber=aqorders.biblionumber
1044         WHERE aqorders.ordernumber=?
1045
1046     ";
1047     my $sth= $dbh->prepare($query);
1048     $sth->execute($ordernumber);
1049     my $data = $sth->fetchrow_hashref;
1050     $sth->finish;
1051     return $data;
1052 }
1053
1054 =head3 GetLastOrderNotReceivedFromSubscriptionid
1055
1056   $order = &GetLastOrderNotReceivedFromSubscriptionid($subscriptionid);
1057
1058 Returns a reference-to-hash describing the last order not received for a subscription.
1059
1060 =cut
1061
1062 sub GetLastOrderNotReceivedFromSubscriptionid {
1063     my ( $subscriptionid ) = @_;
1064     my $dbh                = C4::Context->dbh;
1065     my $query              = qq|
1066         SELECT * FROM aqorders
1067         LEFT JOIN subscription
1068             ON ( aqorders.subscriptionid = subscription.subscriptionid )
1069         WHERE aqorders.subscriptionid = ?
1070             AND aqorders.datereceived IS NULL
1071         LIMIT 1
1072     |;
1073     my $sth = $dbh->prepare( $query );
1074     $sth->execute( $subscriptionid );
1075     my $order = $sth->fetchrow_hashref;
1076     return $order;
1077 }
1078
1079 =head3 GetLastOrderReceivedFromSubscriptionid
1080
1081   $order = &GetLastOrderReceivedFromSubscriptionid($subscriptionid);
1082
1083 Returns a reference-to-hash describing the last order received for a subscription.
1084
1085 =cut
1086
1087 sub GetLastOrderReceivedFromSubscriptionid {
1088     my ( $subscriptionid ) = @_;
1089     my $dbh                = C4::Context->dbh;
1090     my $query              = qq|
1091         SELECT * FROM aqorders
1092         LEFT JOIN subscription
1093             ON ( aqorders.subscriptionid = subscription.subscriptionid )
1094         WHERE aqorders.subscriptionid = ?
1095             AND aqorders.datereceived =
1096                 (
1097                     SELECT MAX( aqorders.datereceived )
1098                     FROM aqorders
1099                     LEFT JOIN subscription
1100                         ON ( aqorders.subscriptionid = subscription.subscriptionid )
1101                         WHERE aqorders.subscriptionid = ?
1102                             AND aqorders.datereceived IS NOT NULL
1103                 )
1104         ORDER BY ordernumber DESC
1105         LIMIT 1
1106     |;
1107     my $sth = $dbh->prepare( $query );
1108     $sth->execute( $subscriptionid, $subscriptionid );
1109     my $order = $sth->fetchrow_hashref;
1110     return $order;
1111
1112 }
1113
1114
1115 #------------------------------------------------------------#
1116
1117 =head3 NewOrder
1118
1119   &NewOrder(\%hashref);
1120
1121 Adds a new order to the database. Any argument that isn't described
1122 below is the new value of the field with the same name in the aqorders
1123 table of the Koha database.
1124
1125 =over
1126
1127 =item $hashref->{'basketno'} is the basketno foreign key in aqorders, it is mandatory
1128
1129 =item $hashref->{'ordernumber'} is a "minimum order number."
1130
1131 =item $hashref->{'budgetdate'} is effectively ignored.
1132 If it's undef (anything false) or the string 'now', the current day is used.
1133 Else, the upcoming July 1st is used.
1134
1135 =item $hashref->{'subscription'} may be either "yes", or anything else for "no".
1136
1137 =item $hashref->{'uncertainprice'} may be 0 for "the price is known" or 1 for "the price is uncertain"
1138
1139 =item defaults entrydate to Now
1140
1141 The following keys are used: "biblionumber", "title", "basketno", "quantity", "notes", "biblioitemnumber", "rrp", "ecost", "gstrate", "unitprice", "subscription", "sort1", "sort2", "booksellerinvoicenumber", "listprice", "budgetdate", "purchaseordernumber", "branchcode", "booksellerinvoicenumber", "budget_id".
1142
1143 =back
1144
1145 =cut
1146
1147 sub NewOrder {
1148     my $orderinfo = shift;
1149 #### ------------------------------
1150     my $dbh = C4::Context->dbh;
1151     my @params;
1152
1153
1154     # if these parameters are missing, we can't continue
1155     for my $key (qw/basketno quantity biblionumber budget_id/) {
1156         croak "Mandatory parameter $key missing" unless $orderinfo->{$key};
1157     }
1158
1159     if ( defined $orderinfo->{subscription} && $orderinfo->{'subscription'} eq 'yes' ) {
1160         $orderinfo->{'subscription'} = 1;
1161     } else {
1162         $orderinfo->{'subscription'} = 0;
1163     }
1164     $orderinfo->{'entrydate'} ||= C4::Dates->new()->output("iso");
1165     if (!$orderinfo->{quantityreceived}) {
1166         $orderinfo->{quantityreceived} = 0;
1167     }
1168
1169     my $ordernumber=InsertInTable("aqorders",$orderinfo);
1170     if (not $orderinfo->{parent_ordernumber}) {
1171         my $sth = $dbh->prepare("
1172             UPDATE aqorders
1173             SET parent_ordernumber = ordernumber
1174             WHERE ordernumber = ?
1175         ");
1176         $sth->execute($ordernumber);
1177     }
1178     return ( $orderinfo->{'basketno'}, $ordernumber );
1179 }
1180
1181
1182
1183 #------------------------------------------------------------#
1184
1185 =head3 NewOrderItem
1186
1187   &NewOrderItem();
1188
1189 =cut
1190
1191 sub NewOrderItem {
1192     my ($itemnumber, $ordernumber)  = @_;
1193     my $dbh = C4::Context->dbh;
1194     my $query = qq|
1195             INSERT INTO aqorders_items
1196                 (itemnumber, ordernumber)
1197             VALUES (?,?)    |;
1198
1199     my $sth = $dbh->prepare($query);
1200     $sth->execute( $itemnumber, $ordernumber);
1201 }
1202
1203 #------------------------------------------------------------#
1204
1205 =head3 ModOrder
1206
1207   &ModOrder(\%hashref);
1208
1209 Modifies an existing order. Updates the order with order number
1210 $hashref->{'ordernumber'} and biblionumber $hashref->{'biblionumber'}. All 
1211 other keys of the hash update the fields with the same name in the aqorders 
1212 table of the Koha database.
1213
1214 =cut
1215
1216 sub ModOrder {
1217     my $orderinfo = shift;
1218
1219     die "Ordernumber is required"     if $orderinfo->{'ordernumber'} eq  '' ;
1220     die "Biblionumber is required"  if  $orderinfo->{'biblionumber'} eq '';
1221
1222     my $dbh = C4::Context->dbh;
1223     my @params;
1224
1225     # update uncertainprice to an integer, just in case (under FF, checked boxes have the value "ON" by default)
1226     $orderinfo->{uncertainprice}=1 if $orderinfo->{uncertainprice};
1227
1228 #    delete($orderinfo->{'branchcode'});
1229     # the hash contains a lot of entries not in aqorders, so get the columns ...
1230     my $sth = $dbh->prepare("SELECT * FROM aqorders LIMIT 1;");
1231     $sth->execute;
1232     my $colnames = $sth->{NAME};
1233         #FIXME Be careful. If aqorders would have columns with diacritics,
1234         #you should need to decode what you get back from NAME.
1235         #See report 10110 and guided_reports.pl
1236     my $query = "UPDATE aqorders SET ";
1237
1238     foreach my $orderinfokey (grep(!/ordernumber/, keys %$orderinfo)){
1239         # ... and skip hash entries that are not in the aqorders table
1240         # FIXME : probably not the best way to do it (would be better to have a correct hash)
1241         next unless grep(/^$orderinfokey$/, @$colnames);
1242             $query .= "$orderinfokey=?, ";
1243             push(@params, $orderinfo->{$orderinfokey});
1244     }
1245
1246     $query .= "timestamp=NOW()  WHERE  ordernumber=?";
1247 #   push(@params, $specorderinfo{'ordernumber'});
1248     push(@params, $orderinfo->{'ordernumber'} );
1249     $sth = $dbh->prepare($query);
1250     $sth->execute(@params);
1251     $sth->finish;
1252 }
1253
1254 #------------------------------------------------------------#
1255
1256 =head3 ModOrderItem
1257
1258   &ModOrderItem(\%hashref);
1259
1260 Modifies the itemnumber in the aqorders_items table. The input hash needs three entities:
1261
1262 =over
1263
1264 =item - itemnumber: the old itemnumber
1265 =item - ordernumber: the order this item is attached to
1266 =item - newitemnumber: the new itemnumber we want to attach the line to
1267
1268 =back
1269
1270 =cut
1271
1272 sub ModOrderItem {
1273     my $orderiteminfo = shift;
1274     if (! $orderiteminfo->{'ordernumber'} || ! $orderiteminfo->{'itemnumber'} || ! $orderiteminfo->{'newitemnumber'}){
1275         die "Ordernumber, itemnumber and newitemnumber is required";
1276     }
1277
1278     my $dbh = C4::Context->dbh;
1279
1280     my $query = "UPDATE aqorders_items set itemnumber=? where itemnumber=? and ordernumber=?";
1281     my @params = ($orderiteminfo->{'newitemnumber'}, $orderiteminfo->{'itemnumber'}, $orderiteminfo->{'ordernumber'});
1282     my $sth = $dbh->prepare($query);
1283     $sth->execute(@params);
1284     return 0;
1285 }
1286
1287 =head3 ModItemOrder
1288
1289     ModItemOrder($itemnumber, $ordernumber);
1290
1291 Modifies the ordernumber of an item in aqorders_items.
1292
1293 =cut
1294
1295 sub ModItemOrder {
1296     my ($itemnumber, $ordernumber) = @_;
1297
1298     return unless ($itemnumber and $ordernumber);
1299
1300     my $dbh = C4::Context->dbh;
1301     my $query = qq{
1302         UPDATE aqorders_items
1303         SET ordernumber = ?
1304         WHERE itemnumber = ?
1305     };
1306     my $sth = $dbh->prepare($query);
1307     return $sth->execute($ordernumber, $itemnumber);
1308 }
1309
1310 #------------------------------------------------------------#
1311
1312
1313 =head3 ModOrderBibliotemNumber
1314
1315   &ModOrderBiblioitemNumber($biblioitemnumber,$ordernumber, $biblionumber);
1316
1317 Modifies the biblioitemnumber for an existing order.
1318 Updates the order with order number C<$ordernum> and biblionumber C<$biblionumber>.
1319
1320 =cut
1321
1322 #FIXME: is this used at all?
1323 sub ModOrderBiblioitemNumber {
1324     my ($biblioitemnumber,$ordernumber, $biblionumber) = @_;
1325     my $dbh = C4::Context->dbh;
1326     my $query = "
1327     UPDATE aqorders
1328     SET    biblioitemnumber = ?
1329     WHERE  ordernumber = ?
1330     AND biblionumber =  ?";
1331     my $sth = $dbh->prepare($query);
1332     $sth->execute( $biblioitemnumber, $ordernumber, $biblionumber );
1333 }
1334
1335 =head3 GetCancelledOrders
1336
1337   my @orders = GetCancelledOrders($basketno, $orderby);
1338
1339 Returns cancelled orders for a basket
1340
1341 =cut
1342
1343 sub GetCancelledOrders {
1344     my ( $basketno, $orderby ) = @_;
1345
1346     return () unless $basketno;
1347
1348     my $dbh   = C4::Context->dbh;
1349     my $query = "
1350         SELECT biblio.*, biblioitems.*, aqorders.*, aqbudgets.*
1351         FROM aqorders
1352           LEFT JOIN aqbudgets   ON aqbudgets.budget_id = aqorders.budget_id
1353           LEFT JOIN biblio      ON biblio.biblionumber = aqorders.biblionumber
1354           LEFT JOIN biblioitems ON biblioitems.biblionumber = biblio.biblionumber
1355         WHERE basketno = ?
1356           AND (datecancellationprinted IS NOT NULL
1357                AND datecancellationprinted <> '0000-00-00')
1358     ";
1359
1360     $orderby = "aqorders.datecancellationprinted desc, aqorders.timestamp desc"
1361         unless $orderby;
1362     $query .= " ORDER BY $orderby";
1363     my $sth = $dbh->prepare($query);
1364     $sth->execute($basketno);
1365     my $results = $sth->fetchall_arrayref( {} );
1366
1367     return @$results;
1368 }
1369
1370
1371 #------------------------------------------------------------#
1372
1373 =head3 ModReceiveOrder
1374
1375   &ModReceiveOrder($biblionumber, $ordernumber, $quantityreceived, $user,
1376     $unitprice, $invoiceid, $biblioitemnumber,
1377     $bookfund, $rrp, \@received_itemnumbers);
1378
1379 Updates an order, to reflect the fact that it was received, at least
1380 in part. All arguments not mentioned below update the fields with the
1381 same name in the aqorders table of the Koha database.
1382
1383 If a partial order is received, splits the order into two.
1384
1385 Updates the order with bibilionumber C<$biblionumber> and ordernumber
1386 C<$ordernumber>.
1387
1388 =cut
1389
1390
1391 sub ModReceiveOrder {
1392     my (
1393         $biblionumber,    $ordernumber,  $quantrec, $user, $cost, $ecost,
1394         $invoiceid, $rrp, $budget_id, $datereceived, $received_items
1395     )
1396     = @_;
1397
1398     my $dbh = C4::Context->dbh;
1399     $datereceived = C4::Dates->output('iso') unless $datereceived;
1400     my $suggestionid = GetSuggestionFromBiblionumber( $biblionumber );
1401     if ($suggestionid) {
1402         ModSuggestion( {suggestionid=>$suggestionid,
1403                         STATUS=>'AVAILABLE',
1404                         biblionumber=> $biblionumber}
1405                         );
1406     }
1407
1408     my $sth=$dbh->prepare("
1409         SELECT * FROM   aqorders
1410         WHERE           biblionumber=? AND aqorders.ordernumber=?");
1411
1412     $sth->execute($biblionumber,$ordernumber);
1413     my $order = $sth->fetchrow_hashref();
1414     $sth->finish();
1415
1416     my $new_ordernumber = $ordernumber;
1417     if ( $order->{quantity} > $quantrec ) {
1418         # Split order line in two parts: the first is the original order line
1419         # without received items (the quantity is decreased),
1420         # the second part is a new order line with quantity=quantityrec
1421         # (entirely received)
1422         $sth=$dbh->prepare("
1423             UPDATE aqorders
1424             SET quantity = ?
1425             WHERE ordernumber = ?
1426         ");
1427
1428         $sth->execute($order->{quantity} - $quantrec, $ordernumber);
1429
1430         $sth->finish;
1431
1432         delete $order->{'ordernumber'};
1433         $order->{'quantity'} = $quantrec;
1434         $order->{'quantityreceived'} = $quantrec;
1435         $order->{'datereceived'} = $datereceived;
1436         $order->{'invoiceid'} = $invoiceid;
1437         $order->{'unitprice'} = $cost;
1438         $order->{'rrp'} = $rrp;
1439         $order->{ecost} = $ecost;
1440         $order->{'orderstatus'} = 3;    # totally received
1441         $new_ordernumber = NewOrder($order);
1442
1443         if ($received_items) {
1444             foreach my $itemnumber (@$received_items) {
1445                 ModItemOrder($itemnumber, $new_ordernumber);
1446             }
1447         }
1448     } else {
1449         $sth=$dbh->prepare("update aqorders
1450                             set quantityreceived=?,datereceived=?,invoiceid=?,
1451                                 unitprice=?,rrp=?,ecost=?
1452                             where biblionumber=? and ordernumber=?");
1453         $sth->execute($quantrec,$datereceived,$invoiceid,$cost,$rrp,$ecost,$biblionumber,$ordernumber);
1454         $sth->finish;
1455     }
1456     return ($datereceived, $new_ordernumber);
1457 }
1458
1459 =head3 CancelReceipt
1460
1461     my $parent_ordernumber = CancelReceipt($ordernumber);
1462
1463     Cancel an order line receipt and update the parent order line, as if no
1464     receipt was made.
1465     If items are created at receipt (AcqCreateItem = receiving) then delete
1466     these items.
1467
1468 =cut
1469
1470 sub CancelReceipt {
1471     my $ordernumber = shift;
1472
1473     return unless $ordernumber;
1474
1475     my $dbh = C4::Context->dbh;
1476     my $query = qq{
1477         SELECT datereceived, parent_ordernumber, quantity
1478         FROM aqorders
1479         WHERE ordernumber = ?
1480     };
1481     my $sth = $dbh->prepare($query);
1482     $sth->execute($ordernumber);
1483     my $order = $sth->fetchrow_hashref;
1484     unless($order) {
1485         warn "CancelReceipt: order $ordernumber does not exist";
1486         return;
1487     }
1488     unless($order->{'datereceived'}) {
1489         warn "CancelReceipt: order $ordernumber is not received";
1490         return;
1491     }
1492
1493     my $parent_ordernumber = $order->{'parent_ordernumber'};
1494
1495     if($parent_ordernumber == $ordernumber || not $parent_ordernumber) {
1496         # The order line has no parent, just mark it as not received
1497         $query = qq{
1498             UPDATE aqorders
1499             SET quantityreceived = ?,
1500                 datereceived = ?,
1501                 invoiceid = ?
1502             WHERE ordernumber = ?
1503         };
1504         $sth = $dbh->prepare($query);
1505         $sth->execute(0, undef, undef, $ordernumber);
1506     } else {
1507         # The order line has a parent, increase parent quantity and delete
1508         # the order line.
1509         $query = qq{
1510             SELECT quantity, datereceived
1511             FROM aqorders
1512             WHERE ordernumber = ?
1513         };
1514         $sth = $dbh->prepare($query);
1515         $sth->execute($parent_ordernumber);
1516         my $parent_order = $sth->fetchrow_hashref;
1517         unless($parent_order) {
1518             warn "Parent order $parent_ordernumber does not exist.";
1519             return;
1520         }
1521         if($parent_order->{'datereceived'}) {
1522             warn "CancelReceipt: parent order is received.".
1523                 " Can't cancel receipt.";
1524             return;
1525         }
1526         $query = qq{
1527             UPDATE aqorders
1528             SET quantity = ?
1529             WHERE ordernumber = ?
1530         };
1531         $sth = $dbh->prepare($query);
1532         my $rv = $sth->execute(
1533             $order->{'quantity'} + $parent_order->{'quantity'},
1534             $parent_ordernumber
1535         );
1536         unless($rv) {
1537             warn "Cannot update parent order line, so do not cancel".
1538                 " receipt";
1539             return;
1540         }
1541         if(C4::Context->preference('AcqCreateItem') eq 'receiving') {
1542             # Remove items that were created at receipt
1543             $query = qq{
1544                 DELETE FROM items, aqorders_items
1545                 USING items, aqorders_items
1546                 WHERE items.itemnumber = ? AND aqorders_items.itemnumber = ?
1547             };
1548             $sth = $dbh->prepare($query);
1549             my @itemnumbers = GetItemnumbersFromOrder($ordernumber);
1550             foreach my $itemnumber (@itemnumbers) {
1551                 $sth->execute($itemnumber, $itemnumber);
1552             }
1553         } else {
1554             # Update items
1555             my @itemnumbers = GetItemnumbersFromOrder($ordernumber);
1556             foreach my $itemnumber (@itemnumbers) {
1557                 ModItemOrder($itemnumber, $parent_ordernumber);
1558             }
1559         }
1560         # Delete order line
1561         $query = qq{
1562             DELETE FROM aqorders
1563             WHERE ordernumber = ?
1564         };
1565         $sth = $dbh->prepare($query);
1566         $sth->execute($ordernumber);
1567
1568     }
1569
1570     return $parent_ordernumber;
1571 }
1572
1573 #------------------------------------------------------------#
1574
1575 =head3 SearchOrder
1576
1577 @results = &SearchOrder($search, $biblionumber, $complete);
1578
1579 Searches for orders.
1580
1581 C<$search> may take one of several forms: if it is an ISBN,
1582 C<&ordersearch> returns orders with that ISBN. If C<$search> is an
1583 order number, C<&ordersearch> returns orders with that order number
1584 and biblionumber C<$biblionumber>. Otherwise, C<$search> is considered
1585 to be a space-separated list of search terms; in this case, all of the
1586 terms must appear in the title (matching the beginning of title
1587 words).
1588
1589 If C<$complete> is C<yes>, the results will include only completed
1590 orders. In any case, C<&ordersearch> ignores cancelled orders.
1591
1592 C<&ordersearch> returns an array.
1593 C<@results> is an array of references-to-hash with the following keys:
1594
1595 =over 4
1596
1597 =item C<author>
1598
1599 =item C<seriestitle>
1600
1601 =item C<branchcode>
1602
1603 =item C<budget_id>
1604
1605 =back
1606
1607 =cut
1608
1609 sub SearchOrder {
1610 #### -------- SearchOrder-------------------------------
1611     my ( $ordernumber, $search, $ean, $supplierid, $basket ) = @_;
1612
1613     my $dbh = C4::Context->dbh;
1614     my @args = ();
1615     my $query =
1616             "SELECT *
1617             FROM aqorders
1618             LEFT JOIN biblio ON aqorders.biblionumber=biblio.biblionumber
1619             LEFT JOIN biblioitems ON biblioitems.biblionumber=biblio.biblionumber
1620             LEFT JOIN aqbasket ON aqorders.basketno = aqbasket.basketno
1621                 WHERE  (datecancellationprinted is NULL)";
1622
1623     if($ordernumber){
1624         $query .= " AND (aqorders.ordernumber=?)";
1625         push @args, $ordernumber;
1626     }
1627     if($search){
1628         $query .= " AND (biblio.title like ? OR biblio.author LIKE ? OR biblioitems.isbn like ?)";
1629         push @args, ("%$search%","%$search%","%$search%");
1630     }
1631     if ($ean) {
1632         $query .= " AND biblioitems.ean = ?";
1633         push @args, $ean;
1634     }
1635     if ($supplierid) {
1636         $query .= "AND aqbasket.booksellerid = ?";
1637         push @args, $supplierid;
1638     }
1639     if($basket){
1640         $query .= "AND aqorders.basketno = ?";
1641         push @args, $basket;
1642     }
1643
1644     my $sth = $dbh->prepare($query);
1645     $sth->execute(@args);
1646     my $results = $sth->fetchall_arrayref({});
1647     $sth->finish;
1648     return $results;
1649 }
1650
1651 #------------------------------------------------------------#
1652
1653 =head3 DelOrder
1654
1655   &DelOrder($biblionumber, $ordernumber);
1656
1657 Cancel the order with the given order and biblio numbers. It does not
1658 delete any entries in the aqorders table, it merely marks them as
1659 cancelled.
1660
1661 =cut
1662
1663 sub DelOrder {
1664     my ( $bibnum, $ordernumber ) = @_;
1665     my $dbh = C4::Context->dbh;
1666     my $query = "
1667         UPDATE aqorders
1668         SET    datecancellationprinted=now()
1669         WHERE  biblionumber=? AND ordernumber=?
1670     ";
1671     my $sth = $dbh->prepare($query);
1672     $sth->execute( $bibnum, $ordernumber );
1673     $sth->finish;
1674     my @itemnumbers = GetItemnumbersFromOrder( $ordernumber );
1675     foreach my $itemnumber (@itemnumbers){
1676         C4::Items::DelItem( $dbh, $bibnum, $itemnumber );
1677     }
1678     
1679 }
1680
1681 =head2 FUNCTIONS ABOUT PARCELS
1682
1683 =cut
1684
1685 #------------------------------------------------------------#
1686
1687 =head3 GetParcel
1688
1689   @results = &GetParcel($booksellerid, $code, $date);
1690
1691 Looks up all of the received items from the supplier with the given
1692 bookseller ID at the given date, for the given code (bookseller Invoice number). Ignores cancelled and completed orders.
1693
1694 C<@results> is an array of references-to-hash. The keys of each element are fields from
1695 the aqorders, biblio, and biblioitems tables of the Koha database.
1696
1697 C<@results> is sorted alphabetically by book title.
1698
1699 =cut
1700
1701 sub GetParcel {
1702     #gets all orders from a certain supplier, orders them alphabetically
1703     my ( $supplierid, $code, $datereceived ) = @_;
1704     my $dbh     = C4::Context->dbh;
1705     my @results = ();
1706     $code .= '%'
1707     if $code;  # add % if we search on a given code (otherwise, let him empty)
1708     my $strsth ="
1709         SELECT  authorisedby,
1710                 creationdate,
1711                 aqbasket.basketno,
1712                 closedate,surname,
1713                 firstname,
1714                 aqorders.biblionumber,
1715                 aqorders.ordernumber,
1716                 aqorders.parent_ordernumber,
1717                 aqorders.quantity,
1718                 aqorders.quantityreceived,
1719                 aqorders.unitprice,
1720                 aqorders.listprice,
1721                 aqorders.rrp,
1722                 aqorders.ecost,
1723                 aqorders.gstrate,
1724                 biblio.title
1725         FROM aqorders
1726         LEFT JOIN aqbasket ON aqbasket.basketno=aqorders.basketno
1727         LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber
1728         LEFT JOIN biblio ON aqorders.biblionumber=biblio.biblionumber
1729         LEFT JOIN aqinvoices ON aqorders.invoiceid = aqinvoices.invoiceid
1730         WHERE
1731             aqbasket.booksellerid = ?
1732             AND aqinvoices.invoicenumber LIKE ?
1733             AND aqorders.datereceived = ? ";
1734
1735     my @query_params = ( $supplierid, $code, $datereceived );
1736     if ( C4::Context->preference("IndependentBranches") ) {
1737         my $userenv = C4::Context->userenv;
1738         if ( ($userenv) && ( $userenv->{flags} != 1 ) ) {
1739             $strsth .= " and (borrowers.branchcode = ?
1740                         or borrowers.branchcode  = '')";
1741             push @query_params, $userenv->{branch};
1742         }
1743     }
1744     $strsth .= " ORDER BY aqbasket.basketno";
1745     # ## parcelinformation : $strsth
1746     my $sth = $dbh->prepare($strsth);
1747     $sth->execute( @query_params );
1748     while ( my $data = $sth->fetchrow_hashref ) {
1749         push( @results, $data );
1750     }
1751     # ## countparcelbiblio: scalar(@results)
1752     $sth->finish;
1753
1754     return @results;
1755 }
1756
1757 #------------------------------------------------------------#
1758
1759 =head3 GetParcels
1760
1761   $results = &GetParcels($bookseller, $order, $code, $datefrom, $dateto);
1762
1763 get a lists of parcels.
1764
1765 * Input arg :
1766
1767 =over
1768
1769 =item $bookseller
1770 is the bookseller this function has to get parcels.
1771
1772 =item $order
1773 To know on what criteria the results list has to be ordered.
1774
1775 =item $code
1776 is the booksellerinvoicenumber.
1777
1778 =item $datefrom & $dateto
1779 to know on what date this function has to filter its search.
1780
1781 =back
1782
1783 * return:
1784 a pointer on a hash list containing parcel informations as such :
1785
1786 =over
1787
1788 =item Creation date
1789
1790 =item Last operation
1791
1792 =item Number of biblio
1793
1794 =item Number of items
1795
1796 =back
1797
1798 =cut
1799
1800 sub GetParcels {
1801     my ($bookseller,$order, $code, $datefrom, $dateto) = @_;
1802     my $dbh    = C4::Context->dbh;
1803     my @query_params = ();
1804     my $strsth ="
1805         SELECT  aqinvoices.invoicenumber,
1806                 datereceived,purchaseordernumber,
1807                 count(DISTINCT biblionumber) AS biblio,
1808                 sum(quantity) AS itemsexpected,
1809                 sum(quantityreceived) AS itemsreceived
1810         FROM   aqorders LEFT JOIN aqbasket ON aqbasket.basketno = aqorders.basketno
1811         LEFT JOIN aqinvoices ON aqorders.invoiceid = aqinvoices.invoiceid
1812         WHERE aqbasket.booksellerid = ? and datereceived IS NOT NULL
1813     ";
1814     push @query_params, $bookseller;
1815
1816     if ( defined $code ) {
1817         $strsth .= ' and aqinvoices.invoicenumber like ? ';
1818         # add a % to the end of the code to allow stemming.
1819         push @query_params, "$code%";
1820     }
1821
1822     if ( defined $datefrom ) {
1823         $strsth .= ' and datereceived >= ? ';
1824         push @query_params, $datefrom;
1825     }
1826
1827     if ( defined $dateto ) {
1828         $strsth .=  'and datereceived <= ? ';
1829         push @query_params, $dateto;
1830     }
1831
1832     $strsth .= "group by aqinvoices.invoicenumber,datereceived ";
1833
1834     # can't use a placeholder to place this column name.
1835     # but, we could probably be checking to make sure it is a column that will be fetched.
1836     $strsth .= "order by $order " if ($order);
1837
1838     my $sth = $dbh->prepare($strsth);
1839
1840     $sth->execute( @query_params );
1841     my $results = $sth->fetchall_arrayref({});
1842     $sth->finish;
1843     return @$results;
1844 }
1845
1846 #------------------------------------------------------------#
1847
1848 =head3 GetLateOrders
1849
1850   @results = &GetLateOrders;
1851
1852 Searches for bookseller with late orders.
1853
1854 return:
1855 the table of supplier with late issues. This table is full of hashref.
1856
1857 =cut
1858
1859 sub GetLateOrders {
1860     my $delay      = shift;
1861     my $supplierid = shift;
1862     my $branch     = shift;
1863     my $estimateddeliverydatefrom = shift;
1864     my $estimateddeliverydateto = shift;
1865
1866     my $dbh = C4::Context->dbh;
1867
1868     #BEWARE, order of parenthesis and LEFT JOIN is important for speed
1869     my $dbdriver = C4::Context->config("db_scheme") || "mysql";
1870
1871     my @query_params = ();
1872     my $select = "
1873     SELECT aqbasket.basketno,
1874         aqorders.ordernumber,
1875         DATE(aqbasket.closedate)  AS orderdate,
1876         aqorders.rrp              AS unitpricesupplier,
1877         aqorders.ecost            AS unitpricelib,
1878         aqorders.claims_count     AS claims_count,
1879         aqorders.claimed_date     AS claimed_date,
1880         aqbudgets.budget_name     AS budget,
1881         borrowers.branchcode      AS branch,
1882         aqbooksellers.name        AS supplier,
1883         aqbooksellers.id          AS supplierid,
1884         biblio.author, biblio.title,
1885         biblioitems.publishercode AS publisher,
1886         biblioitems.publicationyear,
1887         ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) AS estimateddeliverydate,
1888     ";
1889     my $from = "
1890     FROM
1891         aqorders LEFT JOIN biblio     ON biblio.biblionumber         = aqorders.biblionumber
1892         LEFT JOIN biblioitems         ON biblioitems.biblionumber    = biblio.biblionumber
1893         LEFT JOIN aqbudgets           ON aqorders.budget_id          = aqbudgets.budget_id,
1894         aqbasket LEFT JOIN borrowers  ON aqbasket.authorisedby       = borrowers.borrowernumber
1895         LEFT JOIN aqbooksellers       ON aqbasket.booksellerid       = aqbooksellers.id
1896         WHERE aqorders.basketno = aqbasket.basketno
1897         AND ( datereceived = ''
1898             OR datereceived IS NULL
1899             OR aqorders.quantityreceived < aqorders.quantity
1900         )
1901         AND aqbasket.closedate IS NOT NULL
1902         AND (aqorders.datecancellationprinted IS NULL OR aqorders.datecancellationprinted='0000-00-00')
1903     ";
1904     my $having = "";
1905     if ($dbdriver eq "mysql") {
1906         $select .= "
1907         aqorders.quantity - COALESCE(aqorders.quantityreceived,0)                 AS quantity,
1908         (aqorders.quantity - COALESCE(aqorders.quantityreceived,0)) * aqorders.rrp AS subtotal,
1909         DATEDIFF(CAST(now() AS date),closedate) AS latesince
1910         ";
1911         if ( defined $delay ) {
1912             $from .= " AND (closedate <= DATE_SUB(CAST(now() AS date),INTERVAL ? DAY)) " ;
1913             push @query_params, $delay;
1914         }
1915         $having = "
1916         HAVING quantity          <> 0
1917             AND unitpricesupplier <> 0
1918             AND unitpricelib      <> 0
1919         ";
1920     } else {
1921         # FIXME: account for IFNULL as above
1922         $select .= "
1923                 aqorders.quantity                AS quantity,
1924                 aqorders.quantity * aqorders.rrp AS subtotal,
1925                 (CAST(now() AS date) - closedate)            AS latesince
1926         ";
1927         if ( defined $delay ) {
1928             $from .= " AND (closedate <= (CAST(now() AS date) -(INTERVAL ? DAY)) ";
1929             push @query_params, $delay;
1930         }
1931     }
1932     if (defined $supplierid) {
1933         $from .= ' AND aqbasket.booksellerid = ? ';
1934         push @query_params, $supplierid;
1935     }
1936     if (defined $branch) {
1937         $from .= ' AND borrowers.branchcode LIKE ? ';
1938         push @query_params, $branch;
1939     }
1940
1941     if ( defined $estimateddeliverydatefrom or defined $estimateddeliverydateto ) {
1942         $from .= ' AND aqbooksellers.deliverytime IS NOT NULL ';
1943     }
1944     if ( defined $estimateddeliverydatefrom ) {
1945         $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) >= ?';
1946         push @query_params, $estimateddeliverydatefrom;
1947     }
1948     if ( defined $estimateddeliverydateto ) {
1949         $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) <= ?';
1950         push @query_params, $estimateddeliverydateto;
1951     }
1952     if ( defined $estimateddeliverydatefrom and not defined $estimateddeliverydateto ) {
1953         $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) <= CAST(now() AS date)';
1954     }
1955     if (C4::Context->preference("IndependentBranches")
1956             && C4::Context->userenv
1957             && C4::Context->userenv->{flags} != 1 ) {
1958         $from .= ' AND borrowers.branchcode LIKE ? ';
1959         push @query_params, C4::Context->userenv->{branch};
1960     }
1961     my $query = "$select $from $having\nORDER BY latesince, basketno, borrowers.branchcode, supplier";
1962     $debug and print STDERR "GetLateOrders query: $query\nGetLateOrders args: " . join(" ",@query_params);
1963     my $sth = $dbh->prepare($query);
1964     $sth->execute(@query_params);
1965     my @results;
1966     while (my $data = $sth->fetchrow_hashref) {
1967         $data->{orderdate} = format_date($data->{orderdate});
1968         $data->{claimed_date} = format_date($data->{claimed_date});
1969         push @results, $data;
1970     }
1971     return @results;
1972 }
1973
1974 #------------------------------------------------------------#
1975
1976 =head3 GetHistory
1977
1978   (\@order_loop, $total_qty, $total_price, $total_qtyreceived) = GetHistory( %params );
1979
1980 Retreives some acquisition history information
1981
1982 params:  
1983   title
1984   author
1985   name
1986   from_placed_on
1987   to_placed_on
1988   basket                  - search both basket name and number
1989   booksellerinvoicenumber 
1990
1991 returns:
1992     $order_loop is a list of hashrefs that each look like this:
1993             {
1994                 'author'           => 'Twain, Mark',
1995                 'basketno'         => '1',
1996                 'biblionumber'     => '215',
1997                 'count'            => 1,
1998                 'creationdate'     => 'MM/DD/YYYY',
1999                 'datereceived'     => undef,
2000                 'ecost'            => '1.00',
2001                 'id'               => '1',
2002                 'invoicenumber'    => undef,
2003                 'name'             => '',
2004                 'ordernumber'      => '1',
2005                 'quantity'         => 1,
2006                 'quantityreceived' => undef,
2007                 'title'            => 'The Adventures of Huckleberry Finn'
2008             }
2009     $total_qty is the sum of all of the quantities in $order_loop
2010     $total_price is the cost of each in $order_loop times the quantity
2011     $total_qtyreceived is the sum of all of the quantityreceived entries in $order_loop
2012
2013 =cut
2014
2015 sub GetHistory {
2016 # don't run the query if there are no parameters (list would be too long for sure !)
2017     croak "No search params" unless @_;
2018     my %params = @_;
2019     my $title = $params{title};
2020     my $author = $params{author};
2021     my $isbn   = $params{isbn};
2022     my $ean    = $params{ean};
2023     my $name = $params{name};
2024     my $from_placed_on = $params{from_placed_on};
2025     my $to_placed_on = $params{to_placed_on};
2026     my $basket = $params{basket};
2027     my $booksellerinvoicenumber = $params{booksellerinvoicenumber};
2028     my $basketgroupname = $params{basketgroupname};
2029     my @order_loop;
2030     my $total_qty         = 0;
2031     my $total_qtyreceived = 0;
2032     my $total_price       = 0;
2033
2034     my $dbh   = C4::Context->dbh;
2035     my $query ="
2036         SELECT
2037             biblio.title,
2038             biblio.author,
2039             biblioitems.isbn,
2040         biblioitems.ean,
2041             aqorders.basketno,
2042             aqbasket.basketname,
2043             aqbasket.basketgroupid,
2044             aqbasketgroups.name as groupname,
2045             aqbooksellers.name,
2046             aqbasket.creationdate,
2047             aqorders.datereceived,
2048             aqorders.quantity,
2049             aqorders.quantityreceived,
2050             aqorders.ecost,
2051             aqorders.ordernumber,
2052             aqorders.invoiceid,
2053             aqinvoices.invoicenumber,
2054             aqbooksellers.id as id,
2055             aqorders.biblionumber
2056         FROM aqorders
2057         LEFT JOIN aqbasket ON aqorders.basketno=aqbasket.basketno
2058         LEFT JOIN aqbasketgroups ON aqbasket.basketgroupid=aqbasketgroups.id
2059         LEFT JOIN aqbooksellers ON aqbasket.booksellerid=aqbooksellers.id
2060         LEFT JOIN biblioitems ON biblioitems.biblionumber=aqorders.biblionumber
2061         LEFT JOIN biblio ON biblio.biblionumber=aqorders.biblionumber
2062     LEFT JOIN aqinvoices ON aqorders.invoiceid = aqinvoices.invoiceid";
2063
2064     $query .= " LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber"
2065     if ( C4::Context->preference("IndependentBranches") );
2066
2067     $query .= " WHERE (datecancellationprinted is NULL or datecancellationprinted='0000-00-00') ";
2068
2069     my @query_params  = ();
2070
2071     if ( $title ) {
2072         $query .= " AND biblio.title LIKE ? ";
2073         $title =~ s/\s+/%/g;
2074         push @query_params, "%$title%";
2075     }
2076
2077     if ( $author ) {
2078         $query .= " AND biblio.author LIKE ? ";
2079         push @query_params, "%$author%";
2080     }
2081
2082     if ( $isbn ) {
2083         $query .= " AND biblioitems.isbn LIKE ? ";
2084         push @query_params, "%$isbn%";
2085     }
2086     if ( defined $ean and $ean ) {
2087         $query .= " AND biblioitems.ean = ? ";
2088         push @query_params, "$ean";
2089     }
2090     if ( $name ) {
2091         $query .= " AND aqbooksellers.name LIKE ? ";
2092         push @query_params, "%$name%";
2093     }
2094
2095     if ( $from_placed_on ) {
2096         $query .= " AND creationdate >= ? ";
2097         push @query_params, $from_placed_on;
2098     }
2099
2100     if ( $to_placed_on ) {
2101         $query .= " AND creationdate <= ? ";
2102         push @query_params, $to_placed_on;
2103     }
2104
2105     if ($basket) {
2106         if ($basket =~ m/^\d+$/) {
2107             $query .= " AND aqorders.basketno = ? ";
2108             push @query_params, $basket;
2109         } else {
2110             $query .= " AND aqbasket.basketname LIKE ? ";
2111             push @query_params, "%$basket%";
2112         }
2113     }
2114
2115     if ($booksellerinvoicenumber) {
2116         $query .= " AND aqinvoices.invoicenumber LIKE ? ";
2117         push @query_params, "%$booksellerinvoicenumber%";
2118     }
2119
2120     if ($basketgroupname) {
2121         $query .= " AND aqbasketgroups.name LIKE ? ";
2122         push @query_params, "%$basketgroupname%";
2123     }
2124
2125     if ( C4::Context->preference("IndependentBranches") ) {
2126         my $userenv = C4::Context->userenv;
2127         if ( $userenv && ($userenv->{flags} || 0) != 1 ) {
2128             $query .= " AND (borrowers.branchcode = ? OR borrowers.branchcode ='' ) ";
2129             push @query_params, $userenv->{branch};
2130         }
2131     }
2132     $query .= " ORDER BY id";
2133     my $sth = $dbh->prepare($query);
2134     $sth->execute( @query_params );
2135     my $cnt = 1;
2136     while ( my $line = $sth->fetchrow_hashref ) {
2137         $line->{count} = $cnt++;
2138         $line->{toggle} = 1 if $cnt % 2;
2139         push @order_loop, $line;
2140         $total_qty         += $line->{'quantity'};
2141         $total_qtyreceived += $line->{'quantityreceived'};
2142         $total_price       += $line->{'quantity'} * $line->{'ecost'};
2143     }
2144     return \@order_loop, $total_qty, $total_price, $total_qtyreceived;
2145 }
2146
2147 =head2 GetRecentAcqui
2148
2149   $results = GetRecentAcqui($days);
2150
2151 C<$results> is a ref to a table which containts hashref
2152
2153 =cut
2154
2155 sub GetRecentAcqui {
2156     my $limit  = shift;
2157     my $dbh    = C4::Context->dbh;
2158     my $query = "
2159         SELECT *
2160         FROM   biblio
2161         ORDER BY timestamp DESC
2162         LIMIT  0,".$limit;
2163
2164     my $sth = $dbh->prepare($query);
2165     $sth->execute;
2166     my $results = $sth->fetchall_arrayref({});
2167     return $results;
2168 }
2169
2170 =head3 GetContracts
2171
2172   $contractlist = &GetContracts($booksellerid, $activeonly);
2173
2174 Looks up the contracts that belong to a bookseller
2175
2176 Returns a list of contracts
2177
2178 =over
2179
2180 =item C<$booksellerid> is the "id" field in the "aqbooksellers" table.
2181
2182 =item C<$activeonly> if exists get only contracts that are still active.
2183
2184 =back
2185
2186 =cut
2187
2188 sub GetContracts {
2189     my ( $booksellerid, $activeonly ) = @_;
2190     my $dbh = C4::Context->dbh;
2191     my $query;
2192     if (! $activeonly) {
2193         $query = "
2194             SELECT *
2195             FROM   aqcontract
2196             WHERE  booksellerid=?
2197         ";
2198     } else {
2199         $query = "SELECT *
2200             FROM aqcontract
2201             WHERE booksellerid=?
2202                 AND contractenddate >= CURDATE( )";
2203     }
2204     my $sth = $dbh->prepare($query);
2205     $sth->execute( $booksellerid );
2206     my @results;
2207     while (my $data = $sth->fetchrow_hashref ) {
2208         push(@results, $data);
2209     }
2210     $sth->finish;
2211     return @results;
2212 }
2213
2214 #------------------------------------------------------------#
2215
2216 =head3 GetContract
2217
2218   $contract = &GetContract($contractID);
2219
2220 Looks up the contract that has PRIMKEY (contractnumber) value $contractID
2221
2222 Returns a contract
2223
2224 =cut
2225
2226 sub GetContract {
2227     my ( $contractno ) = @_;
2228     my $dbh = C4::Context->dbh;
2229     my $query = "
2230         SELECT *
2231         FROM   aqcontract
2232         WHERE  contractnumber=?
2233         ";
2234
2235     my $sth = $dbh->prepare($query);
2236     $sth->execute( $contractno );
2237     my $result = $sth->fetchrow_hashref;
2238     return $result;
2239 }
2240
2241 =head3 AddClaim
2242
2243 =over 4
2244
2245 &AddClaim($ordernumber);
2246
2247 Add a claim for an order
2248
2249 =back
2250
2251 =cut
2252 sub AddClaim {
2253     my ($ordernumber) = @_;
2254     my $dbh          = C4::Context->dbh;
2255     my $query        = "
2256         UPDATE aqorders SET
2257             claims_count = claims_count + 1,
2258             claimed_date = CURDATE()
2259         WHERE ordernumber = ?
2260         ";
2261     my $sth = $dbh->prepare($query);
2262     $sth->execute($ordernumber);
2263 }
2264
2265 =head3 GetInvoices
2266
2267     my @invoices = GetInvoices(
2268         invoicenumber => $invoicenumber,
2269         suppliername => $suppliername,
2270         shipmentdatefrom => $shipmentdatefrom, # ISO format
2271         shipmentdateto => $shipmentdateto, # ISO format
2272         billingdatefrom => $billingdatefrom, # ISO format
2273         billingdateto => $billingdateto, # ISO format
2274         isbneanissn => $isbn_or_ean_or_issn,
2275         title => $title,
2276         author => $author,
2277         publisher => $publisher,
2278         publicationyear => $publicationyear,
2279         branchcode => $branchcode,
2280         order_by => $order_by
2281     );
2282
2283 Return a list of invoices that match all given criteria.
2284
2285 $order_by is "column_name (asc|desc)", where column_name is any of
2286 'invoicenumber', 'booksellerid', 'shipmentdate', 'billingdate', 'closedate',
2287 'shipmentcost', 'shipmentcost_budgetid'.
2288
2289 asc is the default if omitted
2290
2291 =cut
2292
2293 sub GetInvoices {
2294     my %args = @_;
2295
2296     my @columns = qw(invoicenumber booksellerid shipmentdate billingdate
2297         closedate shipmentcost shipmentcost_budgetid);
2298
2299     my $dbh = C4::Context->dbh;
2300     my $query = qq{
2301         SELECT aqinvoices.*, aqbooksellers.name AS suppliername,
2302           COUNT(
2303             DISTINCT IF(
2304               aqorders.datereceived IS NOT NULL,
2305               aqorders.biblionumber,
2306               NULL
2307             )
2308           ) AS receivedbiblios,
2309           SUM(aqorders.quantityreceived) AS receiveditems
2310         FROM aqinvoices
2311           LEFT JOIN aqbooksellers ON aqbooksellers.id = aqinvoices.booksellerid
2312           LEFT JOIN aqorders ON aqorders.invoiceid = aqinvoices.invoiceid
2313           LEFT JOIN biblio ON aqorders.biblionumber = biblio.biblionumber
2314           LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
2315           LEFT JOIN subscription ON biblio.biblionumber = subscription.biblionumber
2316     };
2317
2318     my @bind_args;
2319     my @bind_strs;
2320     if($args{supplierid}) {
2321         push @bind_strs, " aqinvoices.booksellerid = ? ";
2322         push @bind_args, $args{supplierid};
2323     }
2324     if($args{invoicenumber}) {
2325         push @bind_strs, " aqinvoices.invoicenumber LIKE ? ";
2326         push @bind_args, "%$args{invoicenumber}%";
2327     }
2328     if($args{suppliername}) {
2329         push @bind_strs, " aqbooksellers.name LIKE ? ";
2330         push @bind_args, "%$args{suppliername}%";
2331     }
2332     if($args{shipmentdatefrom}) {
2333         push @bind_strs, " aqinvoices.shipementdate >= ? ";
2334         push @bind_args, $args{shipmentdatefrom};
2335     }
2336     if($args{shipmentdateto}) {
2337         push @bind_strs, " aqinvoices.shipementdate <= ? ";
2338         push @bind_args, $args{shipmentdateto};
2339     }
2340     if($args{billingdatefrom}) {
2341         push @bind_strs, " aqinvoices.billingdate >= ? ";
2342         push @bind_args, $args{billingdatefrom};
2343     }
2344     if($args{billingdateto}) {
2345         push @bind_strs, " aqinvoices.billingdate <= ? ";
2346         push @bind_args, $args{billingdateto};
2347     }
2348     if($args{isbneanissn}) {
2349         push @bind_strs, " (biblioitems.isbn LIKE ? OR biblioitems.ean LIKE ? OR biblioitems.issn LIKE ? ) ";
2350         push @bind_args, $args{isbneanissn}, $args{isbneanissn}, $args{isbneanissn};
2351     }
2352     if($args{title}) {
2353         push @bind_strs, " biblio.title LIKE ? ";
2354         push @bind_args, $args{title};
2355     }
2356     if($args{author}) {
2357         push @bind_strs, " biblio.author LIKE ? ";
2358         push @bind_args, $args{author};
2359     }
2360     if($args{publisher}) {
2361         push @bind_strs, " biblioitems.publishercode LIKE ? ";
2362         push @bind_args, $args{publisher};
2363     }
2364     if($args{publicationyear}) {
2365         push @bind_strs, " biblioitems.publicationyear = ? ";
2366         push @bind_args, $args{publicationyear};
2367     }
2368     if($args{branchcode}) {
2369         push @bind_strs, " aqorders.branchcode = ? ";
2370         push @bind_args, $args{branchcode};
2371     }
2372
2373     $query .= " WHERE " . join(" AND ", @bind_strs) if @bind_strs;
2374     $query .= " GROUP BY aqinvoices.invoiceid ";
2375
2376     if($args{order_by}) {
2377         my ($column, $direction) = split / /, $args{order_by};
2378         if(grep /^$column$/, @columns) {
2379             $direction ||= 'ASC';
2380             $query .= " ORDER BY $column $direction";
2381         }
2382     }
2383
2384     my $sth = $dbh->prepare($query);
2385     $sth->execute(@bind_args);
2386
2387     my $results = $sth->fetchall_arrayref({});
2388     return @$results;
2389 }
2390
2391 =head3 GetInvoice
2392
2393     my $invoice = GetInvoice($invoiceid);
2394
2395 Get informations about invoice with given $invoiceid
2396
2397 Return a hash filled with aqinvoices.* fields
2398
2399 =cut
2400
2401 sub GetInvoice {
2402     my ($invoiceid) = @_;
2403     my $invoice;
2404
2405     return unless $invoiceid;
2406
2407     my $dbh = C4::Context->dbh;
2408     my $query = qq{
2409         SELECT *
2410         FROM aqinvoices
2411         WHERE invoiceid = ?
2412     };
2413     my $sth = $dbh->prepare($query);
2414     $sth->execute($invoiceid);
2415
2416     $invoice = $sth->fetchrow_hashref;
2417     return $invoice;
2418 }
2419
2420 =head3 GetInvoiceDetails
2421
2422     my $invoice = GetInvoiceDetails($invoiceid)
2423
2424 Return informations about an invoice + the list of related order lines
2425
2426 Orders informations are in $invoice->{orders} (array ref)
2427
2428 =cut
2429
2430 sub GetInvoiceDetails {
2431     my ($invoiceid) = @_;
2432
2433     if ( !defined $invoiceid ) {
2434         carp 'GetInvoiceDetails called without an invoiceid';
2435         return;
2436     }
2437
2438     my $dbh = C4::Context->dbh;
2439     my $query = qq{
2440         SELECT aqinvoices.*, aqbooksellers.name AS suppliername
2441         FROM aqinvoices
2442           LEFT JOIN aqbooksellers ON aqinvoices.booksellerid = aqbooksellers.id
2443         WHERE invoiceid = ?
2444     };
2445     my $sth = $dbh->prepare($query);
2446     $sth->execute($invoiceid);
2447
2448     my $invoice = $sth->fetchrow_hashref;
2449
2450     $query = qq{
2451         SELECT aqorders.*, biblio.*
2452         FROM aqorders
2453           LEFT JOIN biblio ON aqorders.biblionumber = biblio.biblionumber
2454         WHERE invoiceid = ?
2455     };
2456     $sth = $dbh->prepare($query);
2457     $sth->execute($invoiceid);
2458     $invoice->{orders} = $sth->fetchall_arrayref({});
2459     $invoice->{orders} ||= []; # force an empty arrayref if fetchall_arrayref fails
2460
2461     return $invoice;
2462 }
2463
2464 =head3 AddInvoice
2465
2466     my $invoiceid = AddInvoice(
2467         invoicenumber => $invoicenumber,
2468         booksellerid => $booksellerid,
2469         shipmentdate => $shipmentdate,
2470         billingdate => $billingdate,
2471         closedate => $closedate,
2472         shipmentcost => $shipmentcost,
2473         shipmentcost_budgetid => $shipmentcost_budgetid
2474     );
2475
2476 Create a new invoice and return its id or undef if it fails.
2477
2478 =cut
2479
2480 sub AddInvoice {
2481     my %invoice = @_;
2482
2483     return unless(%invoice and $invoice{invoicenumber});
2484
2485     my @columns = qw(invoicenumber booksellerid shipmentdate billingdate
2486         closedate shipmentcost shipmentcost_budgetid);
2487
2488     my @set_strs;
2489     my @set_args;
2490     foreach my $key (keys %invoice) {
2491         if(0 < grep(/^$key$/, @columns)) {
2492             push @set_strs, "$key = ?";
2493             push @set_args, ($invoice{$key} || undef);
2494         }
2495     }
2496
2497     my $rv;
2498     if(@set_args > 0) {
2499         my $dbh = C4::Context->dbh;
2500         my $query = "INSERT INTO aqinvoices SET ";
2501         $query .= join (",", @set_strs);
2502         my $sth = $dbh->prepare($query);
2503         $rv = $sth->execute(@set_args);
2504         if($rv) {
2505             $rv = $dbh->last_insert_id(undef, undef, 'aqinvoices', undef);
2506         }
2507     }
2508     return $rv;
2509 }
2510
2511 =head3 ModInvoice
2512
2513     ModInvoice(
2514         invoiceid => $invoiceid,    # Mandatory
2515         invoicenumber => $invoicenumber,
2516         booksellerid => $booksellerid,
2517         shipmentdate => $shipmentdate,
2518         billingdate => $billingdate,
2519         closedate => $closedate,
2520         shipmentcost => $shipmentcost,
2521         shipmentcost_budgetid => $shipmentcost_budgetid
2522     );
2523
2524 Modify an invoice, invoiceid is mandatory.
2525
2526 Return undef if it fails.
2527
2528 =cut
2529
2530 sub ModInvoice {
2531     my %invoice = @_;
2532
2533     return unless(%invoice and $invoice{invoiceid});
2534
2535     my @columns = qw(invoicenumber booksellerid shipmentdate billingdate
2536         closedate shipmentcost shipmentcost_budgetid);
2537
2538     my @set_strs;
2539     my @set_args;
2540     foreach my $key (keys %invoice) {
2541         if(0 < grep(/^$key$/, @columns)) {
2542             push @set_strs, "$key = ?";
2543             push @set_args, ($invoice{$key} || undef);
2544         }
2545     }
2546
2547     my $dbh = C4::Context->dbh;
2548     my $query = "UPDATE aqinvoices SET ";
2549     $query .= join(",", @set_strs);
2550     $query .= " WHERE invoiceid = ?";
2551
2552     my $sth = $dbh->prepare($query);
2553     $sth->execute(@set_args, $invoice{invoiceid});
2554 }
2555
2556 =head3 CloseInvoice
2557
2558     CloseInvoice($invoiceid);
2559
2560 Close an invoice.
2561
2562 Equivalent to ModInvoice(invoiceid => $invoiceid, closedate => undef);
2563
2564 =cut
2565
2566 sub CloseInvoice {
2567     my ($invoiceid) = @_;
2568
2569     return unless $invoiceid;
2570
2571     my $dbh = C4::Context->dbh;
2572     my $query = qq{
2573         UPDATE aqinvoices
2574         SET closedate = CAST(NOW() AS DATE)
2575         WHERE invoiceid = ?
2576     };
2577     my $sth = $dbh->prepare($query);
2578     $sth->execute($invoiceid);
2579 }
2580
2581 =head3 ReopenInvoice
2582
2583     ReopenInvoice($invoiceid);
2584
2585 Reopen an invoice
2586
2587 Equivalent to ModInvoice(invoiceid => $invoiceid, closedate => C4::Dates->new()->output('iso'))
2588
2589 =cut
2590
2591 sub ReopenInvoice {
2592     my ($invoiceid) = @_;
2593
2594     return unless $invoiceid;
2595
2596     my $dbh = C4::Context->dbh;
2597     my $query = qq{
2598         UPDATE aqinvoices
2599         SET closedate = NULL
2600         WHERE invoiceid = ?
2601     };
2602     my $sth = $dbh->prepare($query);
2603     $sth->execute($invoiceid);
2604 }
2605
2606 1;
2607 __END__
2608
2609 =head1 AUTHOR
2610
2611 Koha Development Team <http://koha-community.org/>
2612
2613 =cut