1 package C4
::Acquisition
;
3 # Copyright 2000-2002 Katipo Communications
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
29 use C4
::Templates
qw(gettemplate);
30 use Koha
::DateUtils
qw( dt_from_string output_pref );
31 use Koha
::Acquisition
::Order
;
32 use Koha
::Acquisition
::Bookseller
;
33 use Koha
::Number
::Price
;
43 use vars
qw(@ISA @EXPORT);
49 &GetBasket &NewBasket &CloseBasket &ReopenBasket &DelBasket &ModBasket
50 &GetBasketAsCSV &GetBasketGroupAsCSV
51 &GetBasketsByBookseller &GetBasketsByBasketgroup
52 &GetBasketsInfosByBookseller
54 &GetBasketUsers &ModBasketUsers
59 &ModBasketgroup &NewBasketgroup &DelBasketgroup &GetBasketgroup &CloseBasketgroup
60 &GetBasketgroups &ReOpenBasketgroup
62 &DelOrder &ModOrder &GetOrder &GetOrders &GetOrdersByBiblionumber
63 &GetLateOrders &GetOrderFromItemnumber
64 &SearchOrders &GetHistory &GetRecentAcqui
65 &ModReceiveOrder &CancelReceipt
67 &GetLastOrderNotReceivedFromSubscriptionid &GetLastOrderReceivedFromSubscriptionid
82 &GetItemnumbersFromOrder
85 &GetBiblioCountByBasketno
91 &FillWithDefaultValues
99 sub GetOrderFromItemnumber
{
100 my ($itemnumber) = @_;
101 my $dbh = C4
::Context
->dbh;
104 SELECT
* from aqorders LEFT JOIN aqorders_items
105 ON
( aqorders
.ordernumber
= aqorders_items
.ordernumber
)
106 WHERE itemnumber
= ?
|;
108 my $sth = $dbh->prepare($query);
112 $sth->execute($itemnumber);
114 my $order = $sth->fetchrow_hashref;
119 # Returns the itemnumber(s) associated with the ordernumber given in parameter
120 sub GetItemnumbersFromOrder
{
121 my ($ordernumber) = @_;
122 my $dbh = C4
::Context
->dbh;
123 my $query = "SELECT itemnumber FROM aqorders_items WHERE ordernumber=?";
124 my $sth = $dbh->prepare($query);
125 $sth->execute($ordernumber);
128 while (my $order = $sth->fetchrow_hashref) {
129 push @tab, $order->{'itemnumber'};
143 C4::Acquisition - Koha functions for dealing with orders and acquisitions
151 The functions in this module deal with acquisitions, managing book
152 orders, basket and parcels.
156 =head2 FUNCTIONS ABOUT BASKETS
160 $aqbasket = &GetBasket($basketnumber);
162 get all basket informations in aqbasket for a given basket
164 B<returns:> informations for a given basket returned as a hashref.
170 my $dbh = C4
::Context
->dbh;
173 concat( b.firstname,' ',b.surname) AS authorisedbyname
175 LEFT JOIN borrowers b ON aqbasket.authorisedby=b.borrowernumber
178 my $sth=$dbh->prepare($query);
179 $sth->execute($basketno);
180 my $basket = $sth->fetchrow_hashref;
184 #------------------------------------------------------------#
188 $basket = &NewBasket( $booksellerid, $authorizedby, $basketname,
189 $basketnote, $basketbooksellernote, $basketcontractnumber, $deliveryplace, $billingplace, $is_standing );
191 Create a new basket in aqbasket table
195 =item C<$booksellerid> is a foreign key in the aqbasket table
197 =item C<$authorizedby> is the username of who created the basket
201 The other parameters are optional, see ModBasketHeader for more info on them.
206 my ( $booksellerid, $authorisedby, $basketname, $basketnote,
207 $basketbooksellernote, $basketcontractnumber, $deliveryplace,
208 $billingplace, $is_standing ) = @_;
209 my $dbh = C4
::Context
->dbh;
211 'INSERT INTO aqbasket (creationdate,booksellerid,authorisedby) '
212 . 'VALUES (now(),?,?)';
213 $dbh->do( $query, {}, $booksellerid, $authorisedby );
215 my $basket = $dbh->{mysql_insertid
};
216 $basketname ||= q{}; # default to empty strings
218 $basketbooksellernote ||= q{};
219 ModBasketHeader
( $basket, $basketname, $basketnote, $basketbooksellernote,
220 $basketcontractnumber, $booksellerid, $deliveryplace, $billingplace, $is_standing );
224 #------------------------------------------------------------#
228 &CloseBasket($basketno);
230 close a basket (becomes unmodifiable, except for receives)
236 my $dbh = C4
::Context
->dbh;
237 $dbh->do('UPDATE aqbasket SET closedate=now() WHERE basketno=?', {}, $basketno );
239 $dbh->do( q{UPDATE aqorders SET orderstatus = 'ordered' WHERE basketno = ? AND orderstatus != 'complete'},
246 &ReopenBasket($basketno);
254 my $dbh = C4
::Context
->dbh;
255 $dbh->do( q{UPDATE aqbasket SET closedate=NULL WHERE basketno=?}, {}, $basketno );
259 SET orderstatus = 'new'
261 AND orderstatus != 'complete'
266 #------------------------------------------------------------#
268 =head3 GetBasketAsCSV
270 &GetBasketAsCSV($basketno);
272 Export a basket as CSV
274 $cgi parameter is needed for column name translation
279 my ($basketno, $cgi) = @_;
280 my $basket = GetBasket
($basketno);
281 my @orders = GetOrders
($basketno);
282 my $contract = GetContract
({
283 contractnumber
=> $basket->{'contractnumber'}
286 my $template = C4
::Templates
::gettemplate
("acqui/csv/basket.tt", "intranet", $cgi);
289 foreach my $order (@orders) {
290 my $bd = GetBiblioData
( $order->{'biblionumber'} );
292 contractname
=> $contract->{'contractname'},
293 ordernumber
=> $order->{'ordernumber'},
294 entrydate
=> $order->{'entrydate'},
295 isbn
=> $order->{'isbn'},
296 author
=> $bd->{'author'},
297 title
=> $bd->{'title'},
298 publicationyear
=> $bd->{'publicationyear'},
299 publishercode
=> $bd->{'publishercode'},
300 collectiontitle
=> $bd->{'collectiontitle'},
301 notes
=> $order->{'order_vendornote'},
302 quantity
=> $order->{'quantity'},
303 rrp
=> $order->{'rrp'},
305 for my $place ( qw( deliveryplace billingplace ) ) {
306 if ( my $library = Koha
::Libraries
->find( $row->{deliveryplace
} ) ) {
307 $row->{$place} = $library->branchname
311 contractname author title publishercode collectiontitle notes
312 deliveryplace billingplace
314 # Double the quotes to not be interpreted as a field end
315 $row->{$_} =~ s/"/""/g if $row->{$_};
321 if(defined $a->{publishercode
} and defined $b->{publishercode
}) {
322 $a->{publishercode
} cmp $b->{publishercode
};
326 $template->param(rows
=> \
@rows);
328 return $template->output;
332 =head3 GetBasketGroupAsCSV
334 &GetBasketGroupAsCSV($basketgroupid);
336 Export a basket group as CSV
338 $cgi parameter is needed for column name translation
342 sub GetBasketGroupAsCSV
{
343 my ($basketgroupid, $cgi) = @_;
344 my $baskets = GetBasketsByBasketgroup
($basketgroupid);
346 my $template = C4
::Templates
::gettemplate
('acqui/csv/basketgroup.tt', 'intranet', $cgi);
349 for my $basket (@
$baskets) {
350 my @orders = GetOrders
( $basket->{basketno
} );
351 my $contract = GetContract
({
352 contractnumber
=> $basket->{contractnumber
}
354 my $bookseller = Koha
::Acquisition
::Bookseller
->fetch({ id
=> $basket->{booksellerid
} });
355 my $basketgroup = GetBasketgroup
( $$basket{basketgroupid
} );
357 foreach my $order (@orders) {
358 my $bd = GetBiblioData
( $order->{'biblionumber'} );
360 clientnumber
=> $bookseller->{accountnumber
},
361 basketname
=> $basket->{basketname
},
362 ordernumber
=> $order->{ordernumber
},
363 author
=> $bd->{author
},
364 title
=> $bd->{title
},
365 publishercode
=> $bd->{publishercode
},
366 publicationyear
=> $bd->{publicationyear
},
367 collectiontitle
=> $bd->{collectiontitle
},
368 isbn
=> $order->{isbn
},
369 quantity
=> $order->{quantity
},
370 rrp_tax_included
=> $order->{rrp_tax_included
},
371 rrp_tax_excluded
=> $order->{rrp_tax_excluded
},
372 discount
=> $bookseller->{discount
},
373 ecost_tax_included
=> $order->{ecost_tax_included
},
374 ecost_tax_excluded
=> $order->{ecost_tax_excluded
},
375 notes
=> $order->{order_vendornote
},
376 entrydate
=> $order->{entrydate
},
377 booksellername
=> $bookseller->{name
},
378 bookselleraddress
=> $bookseller->{address1
},
379 booksellerpostal
=> $bookseller->{postal
},
380 contractnumber
=> $contract->{contractnumber
},
381 contractname
=> $contract->{contractname
},
384 basketgroupdeliveryplace
=> $basketgroup->{deliveryplace
},
385 basketgroupbillingplace
=> $basketgroup->{billingplace
},
386 basketdeliveryplace
=> $basket->{deliveryplace
},
387 basketbillingplace
=> $basket->{billingplace
},
389 for my $place (qw( basketgroupdeliveryplace basketgroupbillingplace basketdeliveryplace basketbillingplace )) {
390 if ( my $library = Koha
::Libraries
->find( $temp->{$place} ) ) {
391 $row->{$place} = $library->branchname;
395 basketname author title publishercode collectiontitle notes
396 booksellername bookselleraddress booksellerpostal contractname
397 basketgroupdeliveryplace basketgroupbillingplace
398 basketdeliveryplace basketbillingplace
400 # Double the quotes to not be interpreted as a field end
401 $row->{$_} =~ s/"/""/g if $row->{$_};
406 $template->param(rows
=> \
@rows);
408 return $template->output;
412 =head3 CloseBasketgroup
414 &CloseBasketgroup($basketgroupno);
420 sub CloseBasketgroup
{
421 my ($basketgroupno) = @_;
422 my $dbh = C4
::Context
->dbh;
423 my $sth = $dbh->prepare("
424 UPDATE aqbasketgroups
428 $sth->execute($basketgroupno);
431 #------------------------------------------------------------#
433 =head3 ReOpenBaskergroup($basketgroupno)
435 &ReOpenBaskergroup($basketgroupno);
441 sub ReOpenBasketgroup
{
442 my ($basketgroupno) = @_;
443 my $dbh = C4
::Context
->dbh;
444 my $sth = $dbh->prepare("
445 UPDATE aqbasketgroups
449 $sth->execute($basketgroupno);
452 #------------------------------------------------------------#
457 &DelBasket($basketno);
459 Deletes the basket that has basketno field $basketno in the aqbasket table.
463 =item C<$basketno> is the primary key of the basket in the aqbasket table.
470 my ( $basketno ) = @_;
471 my $query = "DELETE FROM aqbasket WHERE basketno=?";
472 my $dbh = C4
::Context
->dbh;
473 my $sth = $dbh->prepare($query);
474 $sth->execute($basketno);
478 #------------------------------------------------------------#
482 &ModBasket($basketinfo);
484 Modifies a basket, using a hashref $basketinfo for the relevant information, only $basketinfo->{'basketno'} is required.
488 =item C<$basketno> is the primary key of the basket in the aqbasket table.
495 my $basketinfo = shift;
496 my $query = "UPDATE aqbasket SET ";
498 foreach my $key (keys %$basketinfo){
499 if ($key ne 'basketno'){
500 $query .= "$key=?, ";
501 push(@params, $basketinfo->{$key} || undef );
504 # get rid of the "," at the end of $query
505 if (substr($query, length($query)-2) eq ', '){
510 $query .= "WHERE basketno=?";
511 push(@params, $basketinfo->{'basketno'});
512 my $dbh = C4
::Context
->dbh;
513 my $sth = $dbh->prepare($query);
514 $sth->execute(@params);
519 #------------------------------------------------------------#
521 =head3 ModBasketHeader
523 &ModBasketHeader($basketno, $basketname, $note, $booksellernote, $contractnumber, $booksellerid);
525 Modifies a basket's header.
529 =item C<$basketno> is the "basketno" field in the "aqbasket" table;
531 =item C<$basketname> is the "basketname" field in the "aqbasket" table;
533 =item C<$note> is the "note" field in the "aqbasket" table;
535 =item C<$booksellernote> is the "booksellernote" field in the "aqbasket" table;
537 =item C<$contractnumber> is the "contractnumber" (foreign) key in the "aqbasket" table.
539 =item C<$booksellerid> is the id (foreign) key in the "aqbooksellers" table for the vendor.
541 =item C<$deliveryplace> is the "deliveryplace" field in the aqbasket table.
543 =item C<$billingplace> is the "billingplace" field in the aqbasket table.
545 =item C<$is_standing> is the "is_standing" field in the aqbasket table.
551 sub ModBasketHeader
{
552 my ($basketno, $basketname, $note, $booksellernote, $contractnumber, $booksellerid, $deliveryplace, $billingplace, $is_standing) = @_;
555 SET basketname
=?
, note
=?
, booksellernote
=?
, booksellerid
=?
, deliveryplace
=?
, billingplace
=?
, is_standing
=?
559 my $dbh = C4
::Context
->dbh;
560 my $sth = $dbh->prepare($query);
561 $sth->execute($basketname, $note, $booksellernote, $booksellerid, $deliveryplace, $billingplace, $is_standing, $basketno);
563 if ( $contractnumber ) {
564 my $query2 ="UPDATE aqbasket SET contractnumber=? WHERE basketno=?";
565 my $sth2 = $dbh->prepare($query2);
566 $sth2->execute($contractnumber,$basketno);
571 #------------------------------------------------------------#
573 =head3 GetBasketsByBookseller
575 @results = &GetBasketsByBookseller($booksellerid, $extra);
577 Returns a list of hashes of all the baskets that belong to bookseller 'booksellerid'.
581 =item C<$booksellerid> is the 'id' field of the bookseller in the aqbooksellers table
583 =item C<$extra> is the extra sql parameters, can be
585 $extra->{groupby}: group baskets by column
586 ex. $extra->{groupby} = aqbasket.basketgroupid
587 $extra->{orderby}: order baskets by column
588 $extra->{limit}: limit number of results (can be helpful for pagination)
594 sub GetBasketsByBookseller
{
595 my ($booksellerid, $extra) = @_;
596 my $query = "SELECT * FROM aqbasket WHERE booksellerid=?";
598 if ($extra->{groupby
}) {
599 $query .= " GROUP by $extra->{groupby}";
601 if ($extra->{orderby
}){
602 $query .= " ORDER by $extra->{orderby}";
604 if ($extra->{limit
}){
605 $query .= " LIMIT $extra->{limit}";
608 my $dbh = C4
::Context
->dbh;
609 my $sth = $dbh->prepare($query);
610 $sth->execute($booksellerid);
611 return $sth->fetchall_arrayref({});
614 =head3 GetBasketsInfosByBookseller
616 my $baskets = GetBasketsInfosByBookseller($supplierid, $allbaskets);
618 The optional second parameter allbaskets is a boolean allowing you to
619 select all baskets from the supplier; by default only active baskets (open or
620 closed but still something to receive) are returned.
622 Returns in a arrayref of hashref all about booksellers baskets, plus:
623 total_biblios: Number of distinct biblios in basket
624 total_items: Number of items in basket
625 expected_items: Number of non-received items in basket
629 sub GetBasketsInfosByBookseller
{
630 my ($supplierid, $allbaskets) = @_;
632 return unless $supplierid;
634 my $dbh = C4
::Context
->dbh;
637 SUM(aqorders.quantity) AS total_items,
639 IF ( aqorders.orderstatus = 'cancelled', aqorders.quantity, 0 )
640 ) AS total_items_cancelled,
641 COUNT(DISTINCT aqorders.biblionumber) AS total_biblios,
643 IF(aqorders.datereceived IS NULL
644 AND aqorders.datecancellationprinted IS NULL
649 LEFT JOIN aqorders ON aqorders.basketno = aqbasket.basketno
650 WHERE booksellerid = ?};
652 unless ( $allbaskets ) {
653 $query.=" AND (closedate IS NULL OR (aqorders.quantity > aqorders.quantityreceived AND datecancellationprinted IS NULL))";
655 $query.=" GROUP BY aqbasket.basketno";
657 my $sth = $dbh->prepare($query);
658 $sth->execute($supplierid);
659 my $baskets = $sth->fetchall_arrayref({});
661 # Retrieve the number of biblios cancelled
662 my $cancelled_biblios = $dbh->selectall_hashref( q
|
663 SELECT COUNT
(DISTINCT
(biblionumber
)) AS total_biblios_cancelled
, aqbasket
.basketno
665 LEFT JOIN aqorders ON aqorders
.basketno
= aqbasket
.basketno
666 WHERE booksellerid
= ?
667 AND aqorders
.orderstatus
= 'cancelled'
668 GROUP BY aqbasket
.basketno
669 |, 'basketno', {}, $supplierid );
671 $_->{total_biblios_cancelled
} = $cancelled_biblios->{$_->{basketno
}}{total_biblios_cancelled
} || 0
677 =head3 GetBasketUsers
679 $basketusers_ids = &GetBasketUsers($basketno);
681 Returns a list of all borrowernumbers that are in basket users list
686 my $basketno = shift;
688 return unless $basketno;
691 SELECT borrowernumber
695 my $dbh = C4
::Context
->dbh;
696 my $sth = $dbh->prepare($query);
697 $sth->execute($basketno);
698 my $results = $sth->fetchall_arrayref( {} );
701 foreach (@
$results) {
702 push @borrowernumbers, $_->{'borrowernumber'};
705 return @borrowernumbers;
708 =head3 ModBasketUsers
710 my @basketusers_ids = (1, 2, 3);
711 &ModBasketUsers($basketno, @basketusers_ids);
713 Delete all users from basket users list, and add users in C<@basketusers_ids>
719 my ($basketno, @basketusers_ids) = @_;
721 return unless $basketno;
723 my $dbh = C4
::Context
->dbh;
725 DELETE FROM aqbasketusers
728 my $sth = $dbh->prepare($query);
729 $sth->execute($basketno);
732 INSERT INTO aqbasketusers
(basketno
, borrowernumber
)
735 $sth = $dbh->prepare($query);
736 foreach my $basketuser_id (@basketusers_ids) {
737 $sth->execute($basketno, $basketuser_id);
742 =head3 CanUserManageBasket
744 my $bool = CanUserManageBasket($borrower, $basket[, $userflags]);
745 my $bool = CanUserManageBasket($borrowernumber, $basketno[, $userflags]);
747 Check if a borrower can manage a basket, according to system preference
748 AcqViewBaskets, user permissions and basket properties (creator, users list,
751 First parameter can be either a borrowernumber or a hashref as returned by
752 C4::Members::GetMember.
754 Second parameter can be either a basketno or a hashref as returned by
755 C4::Acquisition::GetBasket.
757 The third parameter is optional. If given, it should be a hashref as returned
758 by C4::Auth::getuserflags. If not, getuserflags is called.
760 If user is authorised to manage basket, returns 1.
765 sub CanUserManageBasket
{
766 my ($borrower, $basket, $userflags) = @_;
768 if (!ref $borrower) {
769 $borrower = C4
::Members
::GetMember
(borrowernumber
=> $borrower);
772 $basket = GetBasket
($basket);
775 return 0 unless ($basket and $borrower);
777 my $borrowernumber = $borrower->{borrowernumber
};
778 my $basketno = $basket->{basketno
};
780 my $AcqViewBaskets = C4
::Context
->preference('AcqViewBaskets');
782 if (!defined $userflags) {
783 my $dbh = C4
::Context
->dbh;
784 my $sth = $dbh->prepare("SELECT flags FROM borrowers WHERE borrowernumber = ?");
785 $sth->execute($borrowernumber);
786 my ($flags) = $sth->fetchrow_array;
789 $userflags = C4
::Auth
::getuserflags
($flags, $borrower->{userid
}, $dbh);
792 unless ($userflags->{superlibrarian
}
793 || (ref $userflags->{acquisition
} && $userflags->{acquisition
}->{order_manage_all
})
794 || (!ref $userflags->{acquisition
} && $userflags->{acquisition
}))
796 if (not exists $userflags->{acquisition
}) {
800 if ( (ref $userflags->{acquisition
} && !$userflags->{acquisition
}->{order_manage
})
801 || (!ref $userflags->{acquisition
} && !$userflags->{acquisition
}) ) {
805 if ($AcqViewBaskets eq 'user'
806 && $basket->{authorisedby
} != $borrowernumber
807 && grep($borrowernumber, GetBasketUsers
($basketno)) == 0) {
811 if ($AcqViewBaskets eq 'branch' && defined $basket->{branch
}
812 && $basket->{branch
} ne $borrower->{branchcode
}) {
820 #------------------------------------------------------------#
822 =head3 GetBasketsByBasketgroup
824 $baskets = &GetBasketsByBasketgroup($basketgroupid);
826 Returns a reference to all baskets that belong to basketgroup $basketgroupid.
830 sub GetBasketsByBasketgroup
{
831 my $basketgroupid = shift;
833 SELECT
*, aqbasket
.booksellerid as booksellerid
835 LEFT JOIN aqcontract USING
(contractnumber
) WHERE basketgroupid
=?
837 my $dbh = C4
::Context
->dbh;
838 my $sth = $dbh->prepare($query);
839 $sth->execute($basketgroupid);
840 return $sth->fetchall_arrayref({});
843 #------------------------------------------------------------#
845 =head3 NewBasketgroup
847 $basketgroupid = NewBasketgroup(\%hashref);
849 Adds a basketgroup to the aqbasketgroups table, and add the initial baskets to it.
851 $hashref->{'booksellerid'} is the 'id' field of the bookseller in the aqbooksellers table,
853 $hashref->{'name'} is the 'name' field of the basketgroup in the aqbasketgroups table,
855 $hashref->{'basketlist'} is a list reference of the 'id's of the baskets that belong to this group,
857 $hashref->{'billingplace'} is the 'billingplace' field of the basketgroup in the aqbasketgroups table,
859 $hashref->{'deliveryplace'} is the 'deliveryplace' field of the basketgroup in the aqbasketgroups table,
861 $hashref->{'freedeliveryplace'} is the 'freedeliveryplace' field of the basketgroup in the aqbasketgroups table,
863 $hashref->{'deliverycomment'} is the 'deliverycomment' field of the basketgroup in the aqbasketgroups table,
865 $hashref->{'closed'} is the 'closed' field of the aqbasketgroups table, it is false if 0, true otherwise.
870 my $basketgroupinfo = shift;
871 die "booksellerid is required to create a basketgroup" unless $basketgroupinfo->{'booksellerid'};
872 my $query = "INSERT INTO aqbasketgroups (";
874 foreach my $field (qw(name billingplace deliveryplace freedeliveryplace deliverycomment closed)) {
875 if ( defined $basketgroupinfo->{$field} ) {
876 $query .= "$field, ";
877 push(@params, $basketgroupinfo->{$field});
880 $query .= "booksellerid) VALUES (";
885 push(@params, $basketgroupinfo->{'booksellerid'});
886 my $dbh = C4
::Context
->dbh;
887 my $sth = $dbh->prepare($query);
888 $sth->execute(@params);
889 my $basketgroupid = $dbh->{'mysql_insertid'};
890 if( $basketgroupinfo->{'basketlist'} ) {
891 foreach my $basketno (@
{$basketgroupinfo->{'basketlist'}}) {
892 my $query2 = "UPDATE aqbasket SET basketgroupid=? WHERE basketno=?";
893 my $sth2 = $dbh->prepare($query2);
894 $sth2->execute($basketgroupid, $basketno);
897 return $basketgroupid;
900 #------------------------------------------------------------#
902 =head3 ModBasketgroup
904 ModBasketgroup(\%hashref);
906 Modifies a basketgroup in the aqbasketgroups table, and add the baskets to it.
908 $hashref->{'id'} is the 'id' field of the basketgroup in the aqbasketgroup table, this parameter is mandatory,
910 $hashref->{'name'} is the 'name' field of the basketgroup in the aqbasketgroups table,
912 $hashref->{'basketlist'} is a list reference of the 'id's of the baskets that belong to this group,
914 $hashref->{'billingplace'} is the 'billingplace' field of the basketgroup in the aqbasketgroups table,
916 $hashref->{'deliveryplace'} is the 'deliveryplace' field of the basketgroup in the aqbasketgroups table,
918 $hashref->{'freedeliveryplace'} is the 'freedeliveryplace' field of the basketgroup in the aqbasketgroups table,
920 $hashref->{'deliverycomment'} is the 'deliverycomment' field of the basketgroup in the aqbasketgroups table,
922 $hashref->{'closed'} is the 'closed' field of the aqbasketgroups table, it is false if 0, true otherwise.
927 my $basketgroupinfo = shift;
928 die "basketgroup id is required to edit a basketgroup" unless $basketgroupinfo->{'id'};
929 my $dbh = C4
::Context
->dbh;
930 my $query = "UPDATE aqbasketgroups SET ";
932 foreach my $field (qw(name billingplace deliveryplace freedeliveryplace deliverycomment closed)) {
933 if ( defined $basketgroupinfo->{$field} ) {
934 $query .= "$field=?, ";
935 push(@params, $basketgroupinfo->{$field});
940 $query .= " WHERE id=?";
941 push(@params, $basketgroupinfo->{'id'});
942 my $sth = $dbh->prepare($query);
943 $sth->execute(@params);
945 $sth = $dbh->prepare('UPDATE aqbasket SET basketgroupid = NULL WHERE basketgroupid = ?');
946 $sth->execute($basketgroupinfo->{'id'});
948 if($basketgroupinfo->{'basketlist'} && @
{$basketgroupinfo->{'basketlist'}}){
949 $sth = $dbh->prepare("UPDATE aqbasket SET basketgroupid=? WHERE basketno=?");
950 foreach my $basketno (@
{$basketgroupinfo->{'basketlist'}}) {
951 $sth->execute($basketgroupinfo->{'id'}, $basketno);
957 #------------------------------------------------------------#
959 =head3 DelBasketgroup
961 DelBasketgroup($basketgroupid);
963 Deletes a basketgroup in the aqbasketgroups table, and removes the reference to it from the baskets,
967 =item C<$basketgroupid> is the 'id' field of the basket in the aqbasketgroup table
974 my $basketgroupid = shift;
975 die "basketgroup id is required to edit a basketgroup" unless $basketgroupid;
976 my $query = "DELETE FROM aqbasketgroups WHERE id=?";
977 my $dbh = C4
::Context
->dbh;
978 my $sth = $dbh->prepare($query);
979 $sth->execute($basketgroupid);
983 #------------------------------------------------------------#
986 =head2 FUNCTIONS ABOUT ORDERS
988 =head3 GetBasketgroup
990 $basketgroup = &GetBasketgroup($basketgroupid);
992 Returns a reference to the hash containing all information about the basketgroup.
997 my $basketgroupid = shift;
998 die "basketgroup id is required to edit a basketgroup" unless $basketgroupid;
999 my $dbh = C4
::Context
->dbh;
1000 my $result_set = $dbh->selectall_arrayref(
1001 'SELECT * FROM aqbasketgroups WHERE id=?',
1005 return $result_set->[0]; # id is unique
1008 #------------------------------------------------------------#
1010 =head3 GetBasketgroups
1012 $basketgroups = &GetBasketgroups($booksellerid);
1014 Returns a reference to the array of all the basketgroups of bookseller $booksellerid.
1018 sub GetBasketgroups
{
1019 my $booksellerid = shift;
1020 die 'bookseller id is required to edit a basketgroup' unless $booksellerid;
1021 my $query = 'SELECT * FROM aqbasketgroups WHERE booksellerid=? ORDER BY id DESC';
1022 my $dbh = C4
::Context
->dbh;
1023 my $sth = $dbh->prepare($query);
1024 $sth->execute($booksellerid);
1025 return $sth->fetchall_arrayref({});
1028 #------------------------------------------------------------#
1030 =head2 FUNCTIONS ABOUT ORDERS
1034 @orders = &GetOrders( $basketno, { orderby => 'biblio.title', cancelled => 0|1 } );
1036 Looks up the pending (non-cancelled) orders with the given basket
1039 If cancelled is set, only cancelled orders will be returned.
1044 my ( $basketno, $params ) = @_;
1046 return () unless $basketno;
1048 my $orderby = $params->{orderby
};
1049 my $cancelled = $params->{cancelled
} || 0;
1051 my $dbh = C4
::Context
->dbh;
1053 SELECT biblio
.*,biblioitems
.*,
1057 $query .= $cancelled
1059 aqorders_transfers
.ordernumber_to AS transferred_to
,
1060 aqorders_transfers
.timestamp AS transferred_to_timestamp
1063 aqorders_transfers
.ordernumber_from AS transferred_from
,
1064 aqorders_transfers
.timestamp AS transferred_from_timestamp
1068 LEFT JOIN aqbudgets ON aqbudgets
.budget_id
= aqorders
.budget_id
1069 LEFT JOIN biblio ON biblio
.biblionumber
= aqorders
.biblionumber
1070 LEFT JOIN biblioitems ON biblioitems
.biblionumber
=biblio
.biblionumber
1072 $query .= $cancelled
1074 LEFT JOIN aqorders_transfers ON aqorders_transfers
.ordernumber_from
= aqorders
.ordernumber
1077 LEFT JOIN aqorders_transfers ON aqorders_transfers
.ordernumber_to
= aqorders
.ordernumber
1085 $orderby ||= q
|biblioitems
.publishercode
, biblio
.title
|;
1087 AND
(datecancellationprinted IS NOT NULL
1088 AND datecancellationprinted
<> '0000-00-00')
1093 q
|aqorders
.datecancellationprinted desc
, aqorders
.timestamp desc
|;
1095 AND
(datecancellationprinted IS NULL OR datecancellationprinted
='0000-00-00')
1099 $query .= " ORDER BY $orderby";
1101 $dbh->selectall_arrayref( $query, { Slice
=> {} }, $basketno );
1106 #------------------------------------------------------------#
1108 =head3 GetOrdersByBiblionumber
1110 @orders = &GetOrdersByBiblionumber($biblionumber);
1112 Looks up the orders with linked to a specific $biblionumber, including
1113 cancelled orders and received orders.
1116 C<@orders> is an array of references-to-hash, whose keys are the
1117 fields from the aqorders, biblio, and biblioitems tables in the Koha database.
1121 sub GetOrdersByBiblionumber
{
1122 my $biblionumber = shift;
1123 return unless $biblionumber;
1124 my $dbh = C4
::Context
->dbh;
1126 SELECT biblio.*,biblioitems.*,
1130 LEFT JOIN aqbudgets ON aqbudgets.budget_id = aqorders.budget_id
1131 LEFT JOIN biblio ON biblio.biblionumber = aqorders.biblionumber
1132 LEFT JOIN biblioitems ON biblioitems.biblionumber =biblio.biblionumber
1133 WHERE aqorders.biblionumber=?
1136 $dbh->selectall_arrayref( $query, { Slice
=> {} }, $biblionumber );
1137 return @
{$result_set};
1141 #------------------------------------------------------------#
1145 $order = &GetOrder($ordernumber);
1147 Looks up an order by order number.
1149 Returns a reference-to-hash describing the order. The keys of
1150 C<$order> are fields from the biblio, biblioitems, aqorders tables of the Koha database.
1155 my ($ordernumber) = @_;
1156 return unless $ordernumber;
1158 my $dbh = C4
::Context
->dbh;
1159 my $query = qq{SELECT
1163 aqbasket
.basketname
,
1164 borrowers
.branchcode
,
1165 biblioitems
.publicationyear
,
1166 biblio
.copyrightdate
,
1167 biblioitems
.editionstatement
,
1171 biblioitems
.publishercode
,
1172 aqorders
.rrp AS unitpricesupplier
,
1173 aqorders
.ecost AS unitpricelib
,
1174 aqorders
.claims_count AS claims_count
,
1175 aqorders
.claimed_date AS claimed_date
,
1176 aqbudgets
.budget_name AS budget
,
1177 aqbooksellers
.name AS supplier
,
1178 aqbooksellers
.id AS supplierid
,
1179 biblioitems
.publishercode AS publisher
,
1180 ADDDATE
(aqbasket
.closedate
, INTERVAL aqbooksellers
.deliverytime DAY
) AS estimateddeliverydate
,
1181 DATE
(aqbasket
.closedate
) AS orderdate
,
1182 aqorders
.quantity
- COALESCE
(aqorders
.quantityreceived
,0) AS quantity_to_receive
,
1183 (aqorders
.quantity
- COALESCE
(aqorders
.quantityreceived
,0)) * aqorders
.rrp AS subtotal
,
1184 DATEDIFF
(CURDATE
( ),closedate
) AS latesince
1185 FROM aqorders LEFT JOIN biblio ON biblio
.biblionumber
= aqorders
.biblionumber
1186 LEFT JOIN biblioitems ON biblioitems
.biblionumber
= biblio
.biblionumber
1187 LEFT JOIN aqbudgets ON aqorders
.budget_id
= aqbudgets
.budget_id
,
1188 aqbasket LEFT JOIN borrowers ON aqbasket
.authorisedby
= borrowers
.borrowernumber
1189 LEFT JOIN aqbooksellers ON aqbasket
.booksellerid
= aqbooksellers
.id
1190 WHERE aqorders
.basketno
= aqbasket
.basketno
1193 $dbh->selectall_arrayref( $query, { Slice
=> {} }, $ordernumber );
1195 # result_set assumed to contain 1 match
1196 return $result_set->[0];
1199 =head3 GetLastOrderNotReceivedFromSubscriptionid
1201 $order = &GetLastOrderNotReceivedFromSubscriptionid($subscriptionid);
1203 Returns a reference-to-hash describing the last order not received for a subscription.
1207 sub GetLastOrderNotReceivedFromSubscriptionid
{
1208 my ( $subscriptionid ) = @_;
1209 my $dbh = C4
::Context
->dbh;
1211 SELECT
* FROM aqorders
1212 LEFT JOIN subscription
1213 ON
( aqorders
.subscriptionid
= subscription
.subscriptionid
)
1214 WHERE aqorders
.subscriptionid
= ?
1215 AND aqorders
.datereceived IS NULL
1219 $dbh->selectall_arrayref( $query, { Slice
=> {} }, $subscriptionid );
1221 # result_set assumed to contain 1 match
1222 return $result_set->[0];
1225 =head3 GetLastOrderReceivedFromSubscriptionid
1227 $order = &GetLastOrderReceivedFromSubscriptionid($subscriptionid);
1229 Returns a reference-to-hash describing the last order received for a subscription.
1233 sub GetLastOrderReceivedFromSubscriptionid
{
1234 my ( $subscriptionid ) = @_;
1235 my $dbh = C4
::Context
->dbh;
1237 SELECT
* FROM aqorders
1238 LEFT JOIN subscription
1239 ON
( aqorders
.subscriptionid
= subscription
.subscriptionid
)
1240 WHERE aqorders
.subscriptionid
= ?
1241 AND aqorders
.datereceived
=
1243 SELECT MAX
( aqorders
.datereceived
)
1245 LEFT JOIN subscription
1246 ON
( aqorders
.subscriptionid
= subscription
.subscriptionid
)
1247 WHERE aqorders
.subscriptionid
= ?
1248 AND aqorders
.datereceived IS NOT NULL
1250 ORDER BY ordernumber DESC
1254 $dbh->selectall_arrayref( $query, { Slice
=> {} }, $subscriptionid, $subscriptionid );
1256 # result_set assumed to contain 1 match
1257 return $result_set->[0];
1261 #------------------------------------------------------------#
1265 &ModOrder(\%hashref);
1267 Modifies an existing order. Updates the order with order number
1268 $hashref->{'ordernumber'} and biblionumber $hashref->{'biblionumber'}. All
1269 other keys of the hash update the fields with the same name in the aqorders
1270 table of the Koha database.
1275 my $orderinfo = shift;
1277 die "Ordernumber is required" if $orderinfo->{'ordernumber'} eq '';
1279 my $dbh = C4
::Context
->dbh;
1282 # update uncertainprice to an integer, just in case (under FF, checked boxes have the value "ON" by default)
1283 $orderinfo->{uncertainprice
}=1 if $orderinfo->{uncertainprice
};
1285 # delete($orderinfo->{'branchcode'});
1286 # the hash contains a lot of entries not in aqorders, so get the columns ...
1287 my $sth = $dbh->prepare("SELECT * FROM aqorders LIMIT 1;");
1289 my $colnames = $sth->{NAME
};
1290 #FIXME Be careful. If aqorders would have columns with diacritics,
1291 #you should need to decode what you get back from NAME.
1292 #See report 10110 and guided_reports.pl
1293 my $query = "UPDATE aqorders SET ";
1295 foreach my $orderinfokey (grep(!/ordernumber/, keys %$orderinfo)){
1296 # ... and skip hash entries that are not in the aqorders table
1297 # FIXME : probably not the best way to do it (would be better to have a correct hash)
1298 next unless grep(/^$orderinfokey$/, @
$colnames);
1299 $query .= "$orderinfokey=?, ";
1300 push(@params, $orderinfo->{$orderinfokey});
1303 $query .= "timestamp=NOW() WHERE ordernumber=?";
1304 push(@params, $orderinfo->{'ordernumber'} );
1305 $sth = $dbh->prepare($query);
1306 $sth->execute(@params);
1310 #------------------------------------------------------------#
1314 ModItemOrder($itemnumber, $ordernumber);
1316 Modifies the ordernumber of an item in aqorders_items.
1321 my ($itemnumber, $ordernumber) = @_;
1323 return unless ($itemnumber and $ordernumber);
1325 my $dbh = C4
::Context
->dbh;
1327 UPDATE aqorders_items
1329 WHERE itemnumber
= ?
1331 my $sth = $dbh->prepare($query);
1332 return $sth->execute($ordernumber, $itemnumber);
1335 #------------------------------------------------------------#
1337 =head3 ModReceiveOrder
1339 my ( $date_received, $new_ordernumber ) = ModReceiveOrder(
1341 biblionumber => $biblionumber,
1343 quantityreceived => $quantityreceived,
1345 invoice => $invoice,
1346 budget_id => $budget_id,
1347 received_itemnumbers => \@received_itemnumbers,
1348 order_internalnote => $order_internalnote,
1352 Updates an order, to reflect the fact that it was received, at least
1355 If a partial order is received, splits the order into two.
1357 Updates the order with biblionumber C<$biblionumber> and ordernumber
1358 C<$order->{ordernumber}>.
1363 sub ModReceiveOrder
{
1365 my $biblionumber = $params->{biblionumber
};
1366 my $order = { %{ $params->{order
} } }; # Copy the order, we don't want to modify it
1367 my $invoice = $params->{invoice
};
1368 my $quantrec = $params->{quantityreceived
};
1369 my $user = $params->{user
};
1370 my $budget_id = $params->{budget_id
};
1371 my $received_items = $params->{received_items
};
1373 my $dbh = C4
::Context
->dbh;
1374 my $datereceived = ( $invoice and $invoice->{datereceived
} ) ?
$invoice->{datereceived
} : dt_from_string
;
1375 my $suggestionid = GetSuggestionFromBiblionumber
( $biblionumber );
1376 if ($suggestionid) {
1377 ModSuggestion
( {suggestionid
=>$suggestionid,
1378 STATUS
=>'AVAILABLE',
1379 biblionumber
=> $biblionumber}
1383 my $result_set = $dbh->selectrow_arrayref(
1384 q{SELECT aqbasket.is_standing
1386 WHERE basketno=?},{ Slice
=> {} }, $order->{basketno
});
1387 my $is_standing = $result_set->[0]; # we assume we have a unique basket
1389 my $new_ordernumber = $order->{ordernumber
};
1390 if ( $is_standing || $order->{quantity
} > $quantrec ) {
1391 # Split order line in two parts: the first is the original order line
1392 # without received items (the quantity is decreased),
1393 # the second part is a new order line with quantity=quantityrec
1394 # (entirely received)
1398 orderstatus
= 'partial'|;
1399 $query .= q
|, order_internalnote
= ?
| if defined $order->{order_internalnote
};
1400 $query .= q
| WHERE ordernumber
= ?
|;
1401 my $sth = $dbh->prepare($query);
1404 ( $is_standing ?
1 : ($order->{quantity
} - $quantrec) ),
1405 ( defined $order->{order_internalnote
} ?
$order->{order_internalnote
} : () ),
1406 $order->{ordernumber
}
1409 # Recalculate tax_value
1413 tax_value_on_ordering
= quantity
* ecost_tax_excluded
* tax_rate_on_ordering
,
1414 tax_value_on_receiving
= quantity
* unitprice_tax_excluded
* tax_rate_on_receiving
1415 WHERE ordernumber
= ?
1416 |, undef, $order->{ordernumber
});
1418 delete $order->{ordernumber
};
1419 $order->{budget_id
} = ( $budget_id || $order->{budget_id
} );
1420 $order->{quantity
} = $quantrec;
1421 $order->{quantityreceived
} = $quantrec;
1422 $order->{ecost_tax_excluded
} //= 0;
1423 $order->{tax_rate_on_ordering
} //= 0;
1424 $order->{unitprice_tax_excluded
} //= 0;
1425 $order->{tax_rate_on_receiving
} //= 0;
1426 $order->{tax_value_on_ordering
} = $order->{quantity
} * $order->{ecost_tax_excluded
} * $order->{tax_rate_on_ordering
};
1427 $order->{tax_value_on_receiving
} = $order->{quantity
} * $order->{unitprice_tax_excluded
} * $order->{tax_rate_on_receiving
};
1428 $order->{datereceived
} = $datereceived;
1429 $order->{invoiceid
} = $invoice->{invoiceid
};
1430 $order->{orderstatus
} = 'complete';
1431 $new_ordernumber = Koha
::Acquisition
::Order
->new($order)->insert->{ordernumber
};
1433 if ($received_items) {
1434 foreach my $itemnumber (@
$received_items) {
1435 ModItemOrder
($itemnumber, $new_ordernumber);
1441 SET quantityreceived
= ?
,
1445 orderstatus
= 'complete'
1449 , unitprice
= ?
, unitprice_tax_included
= ?
, unitprice_tax_excluded
= ?
1450 | if defined $order->{unitprice
};
1453 ,tax_value_on_receiving
= ?
1454 | if defined $order->{tax_value_on_receiving
};
1457 ,tax_rate_on_receiving
= ?
1458 | if defined $order->{tax_rate_on_receiving
};
1461 , order_internalnote
= ?
1462 | if defined $order->{order_internalnote
};
1464 $query .= q
| where biblionumber
=?
and ordernumber
=?
|;
1466 my $sth = $dbh->prepare( $query );
1467 my @params = ( $quantrec, $datereceived, $invoice->{invoiceid
}, ( $budget_id ?
$budget_id : $order->{budget_id
} ) );
1469 if ( defined $order->{unitprice
} ) {
1470 push @params, $order->{unitprice
}, $order->{unitprice_tax_included
}, $order->{unitprice_tax_excluded
};
1473 if ( defined $order->{tax_value_on_receiving
} ) {
1474 push @params, $order->{tax_value_on_receiving
};
1477 if ( defined $order->{tax_rate_on_receiving
} ) {
1478 push @params, $order->{tax_rate_on_receiving
};
1481 if ( defined $order->{order_internalnote
} ) {
1482 push @params, $order->{order_internalnote
};
1485 push @params, ( $biblionumber, $order->{ordernumber
} );
1487 $sth->execute( @params );
1489 # All items have been received, sent a notification to users
1490 NotifyOrderUsers
( $order->{ordernumber
} );
1493 return ($datereceived, $new_ordernumber);
1496 =head3 CancelReceipt
1498 my $parent_ordernumber = CancelReceipt($ordernumber);
1500 Cancel an order line receipt and update the parent order line, as if no
1502 If items are created at receipt (AcqCreateItem = receiving) then delete
1508 my $ordernumber = shift;
1510 return unless $ordernumber;
1512 my $dbh = C4
::Context
->dbh;
1514 SELECT datereceived
, parent_ordernumber
, quantity
1516 WHERE ordernumber
= ?
1518 my $sth = $dbh->prepare($query);
1519 $sth->execute($ordernumber);
1520 my $order = $sth->fetchrow_hashref;
1522 warn "CancelReceipt: order $ordernumber does not exist";
1525 unless($order->{'datereceived'}) {
1526 warn "CancelReceipt: order $ordernumber is not received";
1530 my $parent_ordernumber = $order->{'parent_ordernumber'};
1532 my @itemnumbers = GetItemnumbersFromOrder
( $ordernumber );
1534 if($parent_ordernumber == $ordernumber || not $parent_ordernumber) {
1535 # The order line has no parent, just mark it as not received
1538 SET quantityreceived
= ?
,
1541 orderstatus
= 'ordered'
1542 WHERE ordernumber
= ?
1544 $sth = $dbh->prepare($query);
1545 $sth->execute(0, undef, undef, $ordernumber);
1546 _cancel_items_receipt
( $ordernumber );
1548 # The order line has a parent, increase parent quantity and delete
1551 SELECT quantity
, datereceived
1553 WHERE ordernumber
= ?
1555 $sth = $dbh->prepare($query);
1556 $sth->execute($parent_ordernumber);
1557 my $parent_order = $sth->fetchrow_hashref;
1558 unless($parent_order) {
1559 warn "Parent order $parent_ordernumber does not exist.";
1562 if($parent_order->{'datereceived'}) {
1563 warn "CancelReceipt: parent order is received.".
1564 " Can't cancel receipt.";
1570 orderstatus
= 'ordered'
1571 WHERE ordernumber
= ?
1573 $sth = $dbh->prepare($query);
1574 my $rv = $sth->execute(
1575 $order->{'quantity'} + $parent_order->{'quantity'},
1579 warn "Cannot update parent order line, so do not cancel".
1584 # Recalculate tax_value
1588 tax_value_on_ordering
= quantity
* ecost_tax_excluded
* tax_rate_on_ordering
,
1589 tax_value_on_receiving
= quantity
* unitprice_tax_excluded
* tax_rate_on_receiving
1590 WHERE ordernumber
= ?
1591 |, undef, $parent_ordernumber);
1593 _cancel_items_receipt
( $ordernumber, $parent_ordernumber );
1596 DELETE FROM aqorders
1597 WHERE ordernumber
= ?
1599 $sth = $dbh->prepare($query);
1600 $sth->execute($ordernumber);
1604 if(C4
::Context
->preference('AcqCreateItem') eq 'ordering') {
1605 my @affects = split q{\|}, C4
::Context
->preference("AcqItemSetSubfieldsWhenReceiptIsCancelled");
1607 for my $in ( @itemnumbers ) {
1608 my $biblionumber = C4
::Biblio
::GetBiblionumberFromItemnumber
( $in );
1609 my $frameworkcode = GetFrameworkCode
($biblionumber);
1610 my ( $itemfield ) = GetMarcFromKohaField
( 'items.itemnumber', $frameworkcode );
1611 my $item = C4
::Items
::GetMarcItem
( $biblionumber, $in );
1612 for my $affect ( @affects ) {
1613 my ( $sf, $v ) = split q{=}, $affect, 2;
1614 foreach ( $item->field($itemfield) ) {
1615 $_->update( $sf => $v );
1618 C4
::Items
::ModItemFromMarc
( $item, $biblionumber, $in );
1623 return $parent_ordernumber;
1626 sub _cancel_items_receipt
{
1627 my ( $ordernumber, $parent_ordernumber ) = @_;
1628 $parent_ordernumber ||= $ordernumber;
1630 my @itemnumbers = GetItemnumbersFromOrder
($ordernumber);
1631 if(C4
::Context
->preference('AcqCreateItem') eq 'receiving') {
1632 # Remove items that were created at receipt
1634 DELETE FROM items
, aqorders_items
1635 USING items
, aqorders_items
1636 WHERE items
.itemnumber
= ? AND aqorders_items
.itemnumber
= ?
1638 my $dbh = C4
::Context
->dbh;
1639 my $sth = $dbh->prepare($query);
1640 foreach my $itemnumber (@itemnumbers) {
1641 $sth->execute($itemnumber, $itemnumber);
1645 foreach my $itemnumber (@itemnumbers) {
1646 ModItemOrder
($itemnumber, $parent_ordernumber);
1651 #------------------------------------------------------------#
1655 @results = &SearchOrders({
1656 ordernumber => $ordernumber,
1658 biblionumber => $biblionumber,
1660 booksellerid => $booksellerid,
1661 basketno => $basketno,
1667 Searches for orders.
1669 C<$owner> Finds order for the logged in user.
1670 C<$pending> Finds pending orders. Ignores completed and cancelled orders.
1671 C<$ordered> Finds orders to receive only (status 'ordered' or 'partial').
1674 C<@results> is an array of references-to-hash with the keys are fields
1675 from aqorders, biblio, biblioitems and aqbasket tables.
1680 my ( $params ) = @_;
1681 my $ordernumber = $params->{ordernumber
};
1682 my $search = $params->{search
};
1683 my $ean = $params->{ean
};
1684 my $booksellerid = $params->{booksellerid
};
1685 my $basketno = $params->{basketno
};
1686 my $basketname = $params->{basketname
};
1687 my $basketgroupname = $params->{basketgroupname
};
1688 my $owner = $params->{owner
};
1689 my $pending = $params->{pending
};
1690 my $ordered = $params->{ordered
};
1691 my $biblionumber = $params->{biblionumber
};
1692 my $budget_id = $params->{budget_id
};
1694 my $dbh = C4
::Context
->dbh;
1697 SELECT aqbasket.basketno,
1699 borrowers.firstname,
1702 biblioitems.biblioitemnumber,
1703 aqbasket.authorisedby,
1704 aqbasket.booksellerid,
1706 aqbasket.creationdate,
1707 aqbasket.basketname,
1708 aqbasketgroups.id as basketgroupid,
1709 aqbasketgroups.name as basketgroupname,
1712 LEFT JOIN aqbasket ON aqorders.basketno = aqbasket.basketno
1713 LEFT JOIN aqbasketgroups ON aqbasket.basketgroupid = aqbasketgroups.id
1714 LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber
1715 LEFT JOIN biblio ON aqorders.biblionumber=biblio.biblionumber
1716 LEFT JOIN biblioitems ON biblioitems.biblionumber=biblio.biblionumber
1719 # If we search on ordernumber, we retrieve the transferred order if a transfer has been done.
1721 LEFT JOIN aqorders_transfers ON aqorders_transfers.ordernumber_to = aqorders.ordernumber
1725 WHERE (datecancellationprinted is NULL)
1728 if ( $pending or $ordered ) {
1731 ( aqbasket.is_standing AND aqorders.orderstatus IN ( "new", "ordered", "partial" ) )
1733 ( quantity > quantityreceived OR quantityreceived is NULL )
1737 $query .= q{ AND aqorders.orderstatus IN ( "ordered", "partial" )};
1745 my $userenv = C4
::Context
->userenv;
1746 if ( C4
::Context
->preference("IndependentBranches") ) {
1747 unless ( C4
::Context
->IsSuperLibrarian() ) {
1750 borrowers.branchcode = ?
1751 OR borrowers.branchcode = ''
1754 push @args, $userenv->{branch
};
1758 if ( $ordernumber ) {
1759 $query .= ' AND ( aqorders.ordernumber = ? OR aqorders_transfers.ordernumber_from = ? ) ';
1760 push @args, ( $ordernumber, $ordernumber );
1762 if ( $biblionumber ) {
1763 $query .= 'AND aqorders.biblionumber = ?';
1764 push @args, $biblionumber;
1767 $query .= ' AND (biblio.title LIKE ? OR biblio.author LIKE ? OR biblioitems.isbn LIKE ?)';
1768 push @args, ("%$search%","%$search%","%$search%");
1771 $query .= ' AND biblioitems.ean = ?';
1774 if ( $booksellerid ) {
1775 $query .= 'AND aqbasket.booksellerid = ?';
1776 push @args, $booksellerid;
1779 $query .= 'AND aqbasket.basketno = ?';
1780 push @args, $basketno;
1783 $query .= 'AND aqbasket.basketname LIKE ?';
1784 push @args, "%$basketname%";
1786 if( $basketgroupname ) {
1787 $query .= ' AND aqbasketgroups.name LIKE ?';
1788 push @args, "%$basketgroupname%";
1792 $query .= ' AND aqbasket.authorisedby=? ';
1793 push @args, $userenv->{'number'};
1797 $query .= ' AND aqorders.budget_id = ?';
1798 push @args, $budget_id;
1801 $query .= ' ORDER BY aqbasket.basketno';
1803 my $sth = $dbh->prepare($query);
1804 $sth->execute(@args);
1805 return $sth->fetchall_arrayref({});
1808 #------------------------------------------------------------#
1812 &DelOrder($biblionumber, $ordernumber);
1814 Cancel the order with the given order and biblio numbers. It does not
1815 delete any entries in the aqorders table, it merely marks them as
1821 my ( $bibnum, $ordernumber, $delete_biblio, $reason ) = @_;
1824 my $dbh = C4
::Context
->dbh;
1827 SET datecancellationprinted=now(), orderstatus='cancelled'
1830 $query .= ", cancellationreason = ? ";
1833 WHERE biblionumber=? AND ordernumber=?
1835 my $sth = $dbh->prepare($query);
1837 $sth->execute($reason, $bibnum, $ordernumber);
1839 $sth->execute( $bibnum, $ordernumber );
1843 my @itemnumbers = GetItemnumbersFromOrder
( $ordernumber );
1844 foreach my $itemnumber (@itemnumbers){
1845 my $delcheck = C4
::Items
::DelItemCheck
( $bibnum, $itemnumber );
1847 if($delcheck != 1) {
1848 $error->{'delitem'} = 1;
1852 if($delete_biblio) {
1853 # We get the number of remaining items
1854 my $itemcount = C4
::Items
::GetItemsCount
($bibnum);
1856 # If there are no items left,
1857 if ( $itemcount == 0 ) {
1858 # We delete the record
1859 my $delcheck = DelBiblio
($bibnum);
1862 $error->{'delbiblio'} = 1;
1870 =head3 TransferOrder
1872 my $newordernumber = TransferOrder($ordernumber, $basketno);
1874 Transfer an order line to a basket.
1875 Mark $ordernumber as cancelled with an internal note 'Cancelled and transferred
1876 to BOOKSELLER on DATE' and create new order with internal note
1877 'Transferred from BOOKSELLER on DATE'.
1878 Move all attached items to the new order.
1879 Received orders cannot be transferred.
1880 Return the ordernumber of created order.
1885 my ($ordernumber, $basketno) = @_;
1887 return unless ($ordernumber and $basketno);
1889 my $order = GetOrder
( $ordernumber );
1890 return if $order->{datereceived
};
1891 my $basket = GetBasket
($basketno);
1892 return unless $basket;
1894 my $dbh = C4
::Context
->dbh;
1895 my ($query, $sth, $rv);
1899 SET datecancellationprinted = CAST(NOW() AS date), orderstatus = ?
1900 WHERE ordernumber = ?
1902 $sth = $dbh->prepare($query);
1903 $rv = $sth->execute('cancelled', $ordernumber);
1905 delete $order->{'ordernumber'};
1906 delete $order->{parent_ordernumber
};
1907 $order->{'basketno'} = $basketno;
1909 my $newordernumber = Koha
::Acquisition
::Order
->new($order)->insert->{ordernumber
};
1912 UPDATE aqorders_items
1914 WHERE ordernumber = ?
1916 $sth = $dbh->prepare($query);
1917 $sth->execute($newordernumber, $ordernumber);
1920 INSERT INTO aqorders_transfers (ordernumber_from, ordernumber_to)
1923 $sth = $dbh->prepare($query);
1924 $sth->execute($ordernumber, $newordernumber);
1926 return $newordernumber;
1929 =head2 FUNCTIONS ABOUT PARCELS
1933 $results = &GetParcels($bookseller, $order, $code, $datefrom, $dateto);
1935 get a lists of parcels.
1942 is the bookseller this function has to get parcels.
1945 To know on what criteria the results list has to be ordered.
1948 is the booksellerinvoicenumber.
1950 =item $datefrom & $dateto
1951 to know on what date this function has to filter its search.
1956 a pointer on a hash list containing parcel informations as such :
1962 =item Last operation
1964 =item Number of biblio
1966 =item Number of items
1973 my ($bookseller,$order, $code, $datefrom, $dateto) = @_;
1974 my $dbh = C4
::Context
->dbh;
1975 my @query_params = ();
1977 SELECT aqinvoices.invoicenumber,
1978 datereceived,purchaseordernumber,
1979 count(DISTINCT biblionumber) AS biblio,
1980 sum(quantity) AS itemsexpected,
1981 sum(quantityreceived) AS itemsreceived
1982 FROM aqorders LEFT JOIN aqbasket ON aqbasket.basketno = aqorders.basketno
1983 LEFT JOIN aqinvoices ON aqorders.invoiceid = aqinvoices.invoiceid
1984 WHERE aqbasket.booksellerid = ? and datereceived IS NOT NULL
1986 push @query_params, $bookseller;
1988 if ( defined $code ) {
1989 $strsth .= ' and aqinvoices.invoicenumber like ? ';
1990 # add a % to the end of the code to allow stemming.
1991 push @query_params, "$code%";
1994 if ( defined $datefrom ) {
1995 $strsth .= ' and datereceived >= ? ';
1996 push @query_params, $datefrom;
1999 if ( defined $dateto ) {
2000 $strsth .= 'and datereceived <= ? ';
2001 push @query_params, $dateto;
2004 $strsth .= "group by aqinvoices.invoicenumber,datereceived ";
2006 # can't use a placeholder to place this column name.
2007 # but, we could probably be checking to make sure it is a column that will be fetched.
2008 $strsth .= "order by $order " if ($order);
2010 my $sth = $dbh->prepare($strsth);
2012 $sth->execute( @query_params );
2013 my $results = $sth->fetchall_arrayref({});
2017 #------------------------------------------------------------#
2019 =head3 GetLateOrders
2021 @results = &GetLateOrders;
2023 Searches for bookseller with late orders.
2026 the table of supplier with late issues. This table is full of hashref.
2032 my $supplierid = shift;
2034 my $estimateddeliverydatefrom = shift;
2035 my $estimateddeliverydateto = shift;
2037 my $dbh = C4
::Context
->dbh;
2039 #BEWARE, order of parenthesis and LEFT JOIN is important for speed
2040 my $dbdriver = C4
::Context
->config("db_scheme") || "mysql";
2042 my @query_params = ();
2044 SELECT aqbasket.basketno,
2045 aqorders.ordernumber,
2046 DATE(aqbasket.closedate) AS orderdate,
2047 aqbasket.basketname AS basketname,
2048 aqbasket.basketgroupid AS basketgroupid,
2049 aqbasketgroups.name AS basketgroupname,
2050 aqorders.rrp AS unitpricesupplier,
2051 aqorders.ecost AS unitpricelib,
2052 aqorders.claims_count AS claims_count,
2053 aqorders.claimed_date AS claimed_date,
2054 aqbudgets.budget_name AS budget,
2055 borrowers.branchcode AS branch,
2056 aqbooksellers.name AS supplier,
2057 aqbooksellers.id AS supplierid,
2058 biblio.author, biblio.title,
2059 biblioitems.publishercode AS publisher,
2060 biblioitems.publicationyear,
2061 ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) AS estimateddeliverydate,
2065 aqorders LEFT JOIN biblio ON biblio.biblionumber = aqorders.biblionumber
2066 LEFT JOIN biblioitems ON biblioitems.biblionumber = biblio.biblionumber
2067 LEFT JOIN aqbudgets ON aqorders.budget_id = aqbudgets.budget_id,
2068 aqbasket LEFT JOIN borrowers ON aqbasket.authorisedby = borrowers.borrowernumber
2069 LEFT JOIN aqbooksellers ON aqbasket.booksellerid = aqbooksellers.id
2070 LEFT JOIN aqbasketgroups ON aqbasket.basketgroupid = aqbasketgroups.id
2071 WHERE aqorders.basketno = aqbasket.basketno
2072 AND ( datereceived = ''
2073 OR datereceived IS NULL
2074 OR aqorders.quantityreceived < aqorders.quantity
2076 AND aqbasket.closedate IS NOT NULL
2077 AND (aqorders.datecancellationprinted IS NULL OR aqorders.datecancellationprinted='0000-00-00')
2080 if ($dbdriver eq "mysql") {
2082 aqorders.quantity - COALESCE(aqorders.quantityreceived,0) AS quantity,
2083 (aqorders.quantity - COALESCE(aqorders.quantityreceived,0)) * aqorders.rrp AS subtotal,
2084 DATEDIFF(CAST(now() AS date),closedate) AS latesince
2086 if ( defined $delay ) {
2087 $from .= " AND (closedate <= DATE_SUB(CAST(now() AS date),INTERVAL ? DAY)) " ;
2088 push @query_params, $delay;
2091 HAVING quantity <> 0
2092 AND unitpricesupplier <> 0
2093 AND unitpricelib <> 0
2096 # FIXME: account for IFNULL as above
2098 aqorders.quantity AS quantity,
2099 aqorders.quantity * aqorders.rrp AS subtotal,
2100 (CAST(now() AS date) - closedate) AS latesince
2102 if ( defined $delay ) {
2103 $from .= " AND (closedate <= (CAST(now() AS date) -(INTERVAL ? DAY)) ";
2104 push @query_params, $delay;
2107 if (defined $supplierid) {
2108 $from .= ' AND aqbasket.booksellerid = ? ';
2109 push @query_params, $supplierid;
2111 if (defined $branch) {
2112 $from .= ' AND borrowers.branchcode LIKE ? ';
2113 push @query_params, $branch;
2116 if ( defined $estimateddeliverydatefrom or defined $estimateddeliverydateto ) {
2117 $from .= ' AND aqbooksellers.deliverytime IS NOT NULL ';
2119 if ( defined $estimateddeliverydatefrom ) {
2120 $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) >= ?';
2121 push @query_params, $estimateddeliverydatefrom;
2123 if ( defined $estimateddeliverydateto ) {
2124 $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) <= ?';
2125 push @query_params, $estimateddeliverydateto;
2127 if ( defined $estimateddeliverydatefrom and not defined $estimateddeliverydateto ) {
2128 $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) <= CAST(now() AS date)';
2130 if (C4
::Context
->preference("IndependentBranches")
2131 && !C4
::Context
->IsSuperLibrarian() ) {
2132 $from .= ' AND borrowers.branchcode LIKE ? ';
2133 push @query_params, C4
::Context
->userenv->{branch
};
2135 $from .= " AND orderstatus <> 'cancelled' ";
2136 my $query = "$select $from $having\nORDER BY latesince, basketno, borrowers.branchcode, supplier";
2137 $debug and print STDERR
"GetLateOrders query: $query\nGetLateOrders args: " . join(" ",@query_params);
2138 my $sth = $dbh->prepare($query);
2139 $sth->execute(@query_params);
2141 while (my $data = $sth->fetchrow_hashref) {
2142 push @results, $data;
2147 #------------------------------------------------------------#
2151 \@order_loop = GetHistory( %params );
2153 Retreives some acquisition history information
2163 basket - search both basket name and number
2164 booksellerinvoicenumber
2167 orderstatus (note that orderstatus '' will retrieve orders
2168 of any status except cancelled)
2170 get_canceled_order (if set to a true value, cancelled orders will
2174 $order_loop is a list of hashrefs that each look like this:
2176 'author' => 'Twain, Mark',
2178 'biblionumber' => '215',
2180 'creationdate' => 'MM/DD/YYYY',
2181 'datereceived' => undef,
2184 'invoicenumber' => undef,
2186 'ordernumber' => '1',
2188 'quantityreceived' => undef,
2189 'title' => 'The Adventures of Huckleberry Finn'
2195 # don't run the query if there are no parameters (list would be too long for sure !)
2196 croak
"No search params" unless @_;
2198 my $title = $params{title
};
2199 my $author = $params{author
};
2200 my $isbn = $params{isbn
};
2201 my $ean = $params{ean
};
2202 my $name = $params{name
};
2203 my $from_placed_on = $params{from_placed_on
};
2204 my $to_placed_on = $params{to_placed_on
};
2205 my $basket = $params{basket
};
2206 my $booksellerinvoicenumber = $params{booksellerinvoicenumber
};
2207 my $basketgroupname = $params{basketgroupname
};
2208 my $budget = $params{budget
};
2209 my $orderstatus = $params{orderstatus
};
2210 my $biblionumber = $params{biblionumber
};
2211 my $get_canceled_order = $params{get_canceled_order
} || 0;
2212 my $ordernumber = $params{ordernumber
};
2213 my $search_children_too = $params{search_children_too
} || 0;
2214 my $created_by = $params{created_by
} || [];
2218 my $total_qtyreceived = 0;
2219 my $total_price = 0;
2221 my $dbh = C4
::Context
->dbh;
2224 COALESCE(biblio.title, deletedbiblio.title) AS title,
2225 COALESCE(biblio.author, deletedbiblio.author) AS author,
2226 COALESCE(biblioitems.isbn, deletedbiblioitems.isbn) AS isbn,
2227 COALESCE(biblioitems.ean, deletedbiblioitems.ean) AS ean,
2229 aqbasket.basketname,
2230 aqbasket.basketgroupid,
2231 aqbasket.authorisedby,
2232 concat( borrowers.firstname,' ',borrowers.surname) AS authorisedbyname,
2233 aqbasketgroups.name as groupname,
2235 aqbasket.creationdate,
2236 aqorders.datereceived,
2238 aqorders.quantityreceived,
2240 aqorders.ordernumber,
2242 aqinvoices.invoicenumber,
2243 aqbooksellers.id as id,
2244 aqorders.biblionumber,
2245 aqorders.orderstatus,
2246 aqorders.parent_ordernumber,
2247 aqbudgets.budget_name
2249 $query .= ", aqbudgets.budget_id AS budget" if defined $budget;
2252 LEFT JOIN aqbasket ON aqorders.basketno=aqbasket.basketno
2253 LEFT JOIN aqbasketgroups ON aqbasket.basketgroupid=aqbasketgroups.id
2254 LEFT JOIN aqbooksellers ON aqbasket.booksellerid=aqbooksellers.id
2255 LEFT JOIN biblioitems ON biblioitems.biblionumber=aqorders.biblionumber
2256 LEFT JOIN biblio ON biblio.biblionumber=aqorders.biblionumber
2257 LEFT JOIN aqbudgets ON aqorders.budget_id=aqbudgets.budget_id
2258 LEFT JOIN aqinvoices ON aqorders.invoiceid = aqinvoices.invoiceid
2259 LEFT JOIN deletedbiblio ON deletedbiblio.biblionumber=aqorders.biblionumber
2260 LEFT JOIN deletedbiblioitems ON deletedbiblioitems.biblionumber=aqorders.biblionumber
2261 LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber
2264 $query .= " WHERE 1 ";
2266 unless ($get_canceled_order or (defined $orderstatus and $orderstatus eq 'cancelled')) {
2267 $query .= " AND (datecancellationprinted is NULL or datecancellationprinted='0000-00-00') ";
2270 my @query_params = ();
2272 if ( $biblionumber ) {
2273 $query .= " AND biblio.biblionumber = ?";
2274 push @query_params, $biblionumber;
2278 $query .= " AND biblio.title LIKE ? ";
2279 $title =~ s/\s+/%/g;
2280 push @query_params, "%$title%";
2284 $query .= " AND biblio.author LIKE ? ";
2285 push @query_params, "%$author%";
2289 $query .= " AND biblioitems.isbn LIKE ? ";
2290 push @query_params, "%$isbn%";
2293 $query .= " AND biblioitems.ean = ? ";
2294 push @query_params, "$ean";
2297 $query .= " AND aqbooksellers.name LIKE ? ";
2298 push @query_params, "%$name%";
2302 $query .= " AND aqbudgets.budget_id = ? ";
2303 push @query_params, "$budget";
2306 if ( $from_placed_on ) {
2307 $query .= " AND creationdate >= ? ";
2308 push @query_params, $from_placed_on;
2311 if ( $to_placed_on ) {
2312 $query .= " AND creationdate <= ? ";
2313 push @query_params, $to_placed_on;
2316 if ( defined $orderstatus and $orderstatus ne '') {
2317 $query .= " AND aqorders.orderstatus = ? ";
2318 push @query_params, "$orderstatus";
2322 if ($basket =~ m/^\d+$/) {
2323 $query .= " AND aqorders.basketno = ? ";
2324 push @query_params, $basket;
2326 $query .= " AND aqbasket.basketname LIKE ? ";
2327 push @query_params, "%$basket%";
2331 if ($booksellerinvoicenumber) {
2332 $query .= " AND aqinvoices.invoicenumber LIKE ? ";
2333 push @query_params, "%$booksellerinvoicenumber%";
2336 if ($basketgroupname) {
2337 $query .= " AND aqbasketgroups.name LIKE ? ";
2338 push @query_params, "%$basketgroupname%";
2342 $query .= " AND (aqorders.ordernumber = ? ";
2343 push @query_params, $ordernumber;
2344 if ($search_children_too) {
2345 $query .= " OR aqorders.parent_ordernumber = ? ";
2346 push @query_params, $ordernumber;
2351 if ( @
$created_by ) {
2352 $query .= ' AND aqbasket.authorisedby IN ( ' . join( ',', ('?') x @
$created_by ) . ')';
2353 push @query_params, @
$created_by;
2357 if ( C4
::Context
->preference("IndependentBranches") ) {
2358 unless ( C4
::Context
->IsSuperLibrarian() ) {
2359 $query .= " AND (borrowers.branchcode = ? OR borrowers.branchcode ='' ) ";
2360 push @query_params, C4
::Context
->userenv->{branch
};
2363 $query .= " ORDER BY id";
2365 return $dbh->selectall_arrayref( $query, { Slice
=> {} }, @query_params );
2368 =head2 GetRecentAcqui
2370 $results = GetRecentAcqui($days);
2372 C<$results> is a ref to a table which containts hashref
2376 sub GetRecentAcqui
{
2378 my $dbh = C4
::Context
->dbh;
2382 ORDER BY timestamp DESC
2385 my $sth = $dbh->prepare($query);
2387 my $results = $sth->fetchall_arrayref({});
2391 #------------------------------------------------------------#
2395 &AddClaim($ordernumber);
2397 Add a claim for an order
2402 my ($ordernumber) = @_;
2403 my $dbh = C4
::Context
->dbh;
2406 claims_count = claims_count + 1,
2407 claimed_date = CURDATE()
2408 WHERE ordernumber = ?
2410 my $sth = $dbh->prepare($query);
2411 $sth->execute($ordernumber);
2416 my @invoices = GetInvoices(
2417 invoicenumber => $invoicenumber,
2418 supplierid => $supplierid,
2419 suppliername => $suppliername,
2420 shipmentdatefrom => $shipmentdatefrom, # ISO format
2421 shipmentdateto => $shipmentdateto, # ISO format
2422 billingdatefrom => $billingdatefrom, # ISO format
2423 billingdateto => $billingdateto, # ISO format
2424 isbneanissn => $isbn_or_ean_or_issn,
2427 publisher => $publisher,
2428 publicationyear => $publicationyear,
2429 branchcode => $branchcode,
2430 order_by => $order_by
2433 Return a list of invoices that match all given criteria.
2435 $order_by is "column_name (asc|desc)", where column_name is any of
2436 'invoicenumber', 'booksellerid', 'shipmentdate', 'billingdate', 'closedate',
2437 'shipmentcost', 'shipmentcost_budgetid'.
2439 asc is the default if omitted
2446 my @columns = qw(invoicenumber booksellerid shipmentdate billingdate
2447 closedate shipmentcost shipmentcost_budgetid);
2449 my $dbh = C4
::Context
->dbh;
2451 SELECT aqinvoices
.*, aqbooksellers
.name AS suppliername
,
2454 aqorders
.datereceived IS NOT NULL
,
2455 aqorders
.biblionumber
,
2458 ) AS receivedbiblios
,
2461 aqorders
.subscriptionid IS NOT NULL
,
2462 aqorders
.subscriptionid
,
2465 ) AS is_linked_to_subscriptions
,
2466 SUM
(aqorders
.quantityreceived
) AS receiveditems
2468 LEFT JOIN aqbooksellers ON aqbooksellers
.id
= aqinvoices
.booksellerid
2469 LEFT JOIN aqorders ON aqorders
.invoiceid
= aqinvoices
.invoiceid
2470 LEFT JOIN aqbasket ON aqbasket
.basketno
=aqorders
.basketno
2471 LEFT JOIN borrowers ON aqbasket
.authorisedby
=borrowers
.borrowernumber
2472 LEFT JOIN biblio ON aqorders
.biblionumber
= biblio
.biblionumber
2473 LEFT JOIN biblioitems ON biblio
.biblionumber
= biblioitems
.biblionumber
2474 LEFT JOIN subscription ON biblio
.biblionumber
= subscription
.biblionumber
2479 if($args{supplierid
}) {
2480 push @bind_strs, " aqinvoices.booksellerid = ? ";
2481 push @bind_args, $args{supplierid
};
2483 if($args{invoicenumber
}) {
2484 push @bind_strs, " aqinvoices.invoicenumber LIKE ? ";
2485 push @bind_args, "%$args{invoicenumber}%";
2487 if($args{suppliername
}) {
2488 push @bind_strs, " aqbooksellers.name LIKE ? ";
2489 push @bind_args, "%$args{suppliername}%";
2491 if($args{shipmentdatefrom
}) {
2492 push @bind_strs, " aqinvoices.shipmentdate >= ? ";
2493 push @bind_args, $args{shipmentdatefrom
};
2495 if($args{shipmentdateto
}) {
2496 push @bind_strs, " aqinvoices.shipmentdate <= ? ";
2497 push @bind_args, $args{shipmentdateto
};
2499 if($args{billingdatefrom
}) {
2500 push @bind_strs, " aqinvoices.billingdate >= ? ";
2501 push @bind_args, $args{billingdatefrom
};
2503 if($args{billingdateto
}) {
2504 push @bind_strs, " aqinvoices.billingdate <= ? ";
2505 push @bind_args, $args{billingdateto
};
2507 if($args{isbneanissn
}) {
2508 push @bind_strs, " (biblioitems.isbn LIKE CONCAT('%', ?, '%') OR biblioitems.ean LIKE CONCAT('%', ?, '%') OR biblioitems.issn LIKE CONCAT('%', ?, '%') ) ";
2509 push @bind_args, $args{isbneanissn
}, $args{isbneanissn
}, $args{isbneanissn
};
2512 push @bind_strs, " biblio.title LIKE CONCAT('%', ?, '%') ";
2513 push @bind_args, $args{title
};
2516 push @bind_strs, " biblio.author LIKE CONCAT('%', ?, '%') ";
2517 push @bind_args, $args{author
};
2519 if($args{publisher
}) {
2520 push @bind_strs, " biblioitems.publishercode LIKE CONCAT('%', ?, '%') ";
2521 push @bind_args, $args{publisher
};
2523 if($args{publicationyear
}) {
2524 push @bind_strs, " ((biblioitems.publicationyear LIKE CONCAT('%', ?, '%')) OR (biblio.copyrightdate LIKE CONCAT('%', ?, '%'))) ";
2525 push @bind_args, $args{publicationyear
}, $args{publicationyear
};
2527 if($args{branchcode
}) {
2528 push @bind_strs, " borrowers.branchcode = ? ";
2529 push @bind_args, $args{branchcode
};
2531 if($args{message_id
}) {
2532 push @bind_strs, " aqinvoices.message_id = ? ";
2533 push @bind_args, $args{message_id
};
2536 $query .= " WHERE " . join(" AND ", @bind_strs) if @bind_strs;
2537 $query .= " GROUP BY aqinvoices.invoiceid ";
2539 if($args{order_by
}) {
2540 my ($column, $direction) = split / /, $args{order_by
};
2541 if(grep /^$column$/, @columns) {
2542 $direction ||= 'ASC';
2543 $query .= " ORDER BY $column $direction";
2547 my $sth = $dbh->prepare($query);
2548 $sth->execute(@bind_args);
2550 my $results = $sth->fetchall_arrayref({});
2556 my $invoice = GetInvoice($invoiceid);
2558 Get informations about invoice with given $invoiceid
2560 Return a hash filled with aqinvoices.* fields
2565 my ($invoiceid) = @_;
2568 return unless $invoiceid;
2570 my $dbh = C4
::Context
->dbh;
2576 my $sth = $dbh->prepare($query);
2577 $sth->execute($invoiceid);
2579 $invoice = $sth->fetchrow_hashref;
2583 =head3 GetInvoiceDetails
2585 my $invoice = GetInvoiceDetails($invoiceid)
2587 Return informations about an invoice + the list of related order lines
2589 Orders informations are in $invoice->{orders} (array ref)
2593 sub GetInvoiceDetails
{
2594 my ($invoiceid) = @_;
2596 if ( !defined $invoiceid ) {
2597 carp
'GetInvoiceDetails called without an invoiceid';
2601 my $dbh = C4
::Context
->dbh;
2603 SELECT aqinvoices.*, aqbooksellers.name AS suppliername
2605 LEFT JOIN aqbooksellers ON aqinvoices.booksellerid = aqbooksellers.id
2608 my $sth = $dbh->prepare($query);
2609 $sth->execute($invoiceid);
2611 my $invoice = $sth->fetchrow_hashref;
2616 biblio.copyrightdate,
2617 biblioitems.publishercode,
2618 biblioitems.publicationyear,
2619 aqbasket.basketname,
2620 aqbasketgroups.id AS basketgroupid,
2621 aqbasketgroups.name AS basketgroupname
2623 LEFT JOIN aqbasket ON aqorders.basketno = aqbasket.basketno
2624 LEFT JOIN aqbasketgroups ON aqbasket.basketgroupid = aqbasketgroups.id
2625 LEFT JOIN biblio ON aqorders.biblionumber = biblio.biblionumber
2626 LEFT JOIN biblioitems ON aqorders.biblionumber = biblioitems.biblionumber
2629 $sth = $dbh->prepare($query);
2630 $sth->execute($invoiceid);
2631 $invoice->{orders
} = $sth->fetchall_arrayref({});
2632 $invoice->{orders
} ||= []; # force an empty arrayref if fetchall_arrayref fails
2639 my $invoiceid = AddInvoice(
2640 invoicenumber => $invoicenumber,
2641 booksellerid => $booksellerid,
2642 shipmentdate => $shipmentdate,
2643 billingdate => $billingdate,
2644 closedate => $closedate,
2645 shipmentcost => $shipmentcost,
2646 shipmentcost_budgetid => $shipmentcost_budgetid
2649 Create a new invoice and return its id or undef if it fails.
2656 return unless(%invoice and $invoice{invoicenumber
});
2658 my @columns = qw(invoicenumber booksellerid shipmentdate billingdate
2659 closedate shipmentcost shipmentcost_budgetid message_id);
2663 foreach my $key (keys %invoice) {
2664 if(0 < grep(/^$key$/, @columns)) {
2665 push @set_strs, "$key = ?";
2666 push @set_args, ($invoice{$key} || undef);
2672 my $dbh = C4
::Context
->dbh;
2673 my $query = "INSERT INTO aqinvoices SET ";
2674 $query .= join (",", @set_strs);
2675 my $sth = $dbh->prepare($query);
2676 $rv = $sth->execute(@set_args);
2678 $rv = $dbh->last_insert_id(undef, undef, 'aqinvoices', undef);
2687 invoiceid => $invoiceid, # Mandatory
2688 invoicenumber => $invoicenumber,
2689 booksellerid => $booksellerid,
2690 shipmentdate => $shipmentdate,
2691 billingdate => $billingdate,
2692 closedate => $closedate,
2693 shipmentcost => $shipmentcost,
2694 shipmentcost_budgetid => $shipmentcost_budgetid
2697 Modify an invoice, invoiceid is mandatory.
2699 Return undef if it fails.
2706 return unless(%invoice and $invoice{invoiceid
});
2708 my @columns = qw(invoicenumber booksellerid shipmentdate billingdate
2709 closedate shipmentcost shipmentcost_budgetid);
2713 foreach my $key (keys %invoice) {
2714 if(0 < grep(/^$key$/, @columns)) {
2715 push @set_strs, "$key = ?";
2716 push @set_args, ($invoice{$key} || undef);
2720 my $dbh = C4
::Context
->dbh;
2721 my $query = "UPDATE aqinvoices SET ";
2722 $query .= join(",", @set_strs);
2723 $query .= " WHERE invoiceid = ?";
2725 my $sth = $dbh->prepare($query);
2726 $sth->execute(@set_args, $invoice{invoiceid
});
2731 CloseInvoice($invoiceid);
2735 Equivalent to ModInvoice(invoiceid => $invoiceid, closedate => undef);
2740 my ($invoiceid) = @_;
2742 return unless $invoiceid;
2744 my $dbh = C4
::Context
->dbh;
2747 SET closedate
= CAST
(NOW
() AS DATE
)
2750 my $sth = $dbh->prepare($query);
2751 $sth->execute($invoiceid);
2754 =head3 ReopenInvoice
2756 ReopenInvoice($invoiceid);
2760 Equivalent to ModInvoice(invoiceid => $invoiceid, closedate => output_pref({ dt=>dt_from_string, dateonly=>1, otputpref=>'iso' }))
2765 my ($invoiceid) = @_;
2767 return unless $invoiceid;
2769 my $dbh = C4
::Context
->dbh;
2772 SET closedate
= NULL
2775 my $sth = $dbh->prepare($query);
2776 $sth->execute($invoiceid);
2781 DelInvoice($invoiceid);
2783 Delete an invoice if there are no items attached to it.
2788 my ($invoiceid) = @_;
2790 return unless $invoiceid;
2792 my $dbh = C4
::Context
->dbh;
2798 my $sth = $dbh->prepare($query);
2799 $sth->execute($invoiceid);
2800 my $res = $sth->fetchrow_arrayref;
2801 if ( $res && $res->[0] == 0 ) {
2803 DELETE FROM aqinvoices
2806 my $sth = $dbh->prepare($query);
2807 return ( $sth->execute($invoiceid) > 0 );
2812 =head3 MergeInvoices
2814 MergeInvoices($invoiceid, \@sourceids);
2816 Merge the invoices identified by the IDs in \@sourceids into
2817 the invoice identified by $invoiceid.
2822 my ($invoiceid, $sourceids) = @_;
2824 return unless $invoiceid;
2825 foreach my $sourceid (@
$sourceids) {
2826 next if $sourceid == $invoiceid;
2827 my $source = GetInvoiceDetails
($sourceid);
2828 foreach my $order (@
{$source->{'orders'}}) {
2829 $order->{'invoiceid'} = $invoiceid;
2832 DelInvoice
($source->{'invoiceid'});
2837 =head3 GetBiblioCountByBasketno
2839 $biblio_count = &GetBiblioCountByBasketno($basketno);
2841 Looks up the biblio's count that has basketno value $basketno
2847 sub GetBiblioCountByBasketno
{
2848 my ($basketno) = @_;
2849 my $dbh = C4
::Context
->dbh;
2851 SELECT COUNT( DISTINCT( biblionumber ) )
2854 AND (datecancellationprinted IS NULL OR datecancellationprinted='0000-00-00')
2857 my $sth = $dbh->prepare($query);
2858 $sth->execute($basketno);
2859 return $sth->fetchrow;
2862 # Note this subroutine should be moved to Koha::Acquisition::Order
2863 # Will do when a DBIC decision will be taken.
2864 sub populate_order_with_prices
{
2867 my $order = $params->{order
};
2868 my $booksellerid = $params->{booksellerid
};
2869 return unless $booksellerid;
2871 my $bookseller = Koha
::Acquisition
::Bookseller
->fetch({ id
=> $booksellerid });
2873 my $receiving = $params->{receiving
};
2874 my $ordering = $params->{ordering
};
2875 my $discount = $order->{discount
};
2876 $discount /= 100 if $discount > 1;
2879 $order->{tax_rate_on_ordering
} //= $order->{tax_rate
};
2880 if ( $bookseller->{listincgst
} ) {
2881 # The user entered the rrp tax included
2882 $order->{rrp_tax_included
} = $order->{rrp
};
2884 # rrp tax excluded = rrp tax included / ( 1 + tax rate )
2885 $order->{rrp_tax_excluded
} = $order->{rrp_tax_included
} / ( 1 + $order->{tax_rate_on_ordering
} );
2887 # ecost tax excluded = rrp tax excluded * ( 1 - discount )
2888 $order->{ecost_tax_excluded
} = $order->{rrp_tax_excluded
} * ( 1 - $discount );
2890 # ecost tax included = rrp tax included ( 1 - discount )
2891 $order->{ecost_tax_included
} = $order->{rrp_tax_included
} * ( 1 - $discount );
2894 # The user entered the rrp tax excluded
2895 $order->{rrp_tax_excluded
} = $order->{rrp
};
2897 # rrp tax included = rrp tax excluded * ( 1 - tax rate )
2898 $order->{rrp_tax_included
} = $order->{rrp_tax_excluded
} * ( 1 + $order->{tax_rate_on_ordering
} );
2900 # ecost tax excluded = rrp tax excluded * ( 1 - discount )
2901 $order->{ecost_tax_excluded
} = $order->{rrp_tax_excluded
} * ( 1 - $discount );
2903 # ecost tax included = rrp tax excluded * ( 1 - tax rate ) * ( 1 - discount )
2904 $order->{ecost_tax_included
} =
2905 $order->{rrp_tax_excluded
} *
2906 ( 1 + $order->{tax_rate_on_ordering
} ) *
2910 # tax value = quantity * ecost tax excluded * tax rate
2911 $order->{tax_value_on_ordering
} =
2912 $order->{quantity
} * $order->{ecost_tax_excluded
} * $order->{tax_rate_on_ordering
};
2916 $order->{tax_rate_on_receiving
} //= $order->{tax_rate
};
2917 if ( $bookseller->{invoiceincgst
} ) {
2918 # Trick for unitprice. If the unit price rounded value is the same as the ecost rounded value
2919 # we need to keep the exact ecost value
2920 if ( Koha
::Number
::Price
->new( $order->{unitprice
} )->round == Koha
::Number
::Price
->new( $order->{ecost_tax_included
} )->round ) {
2921 $order->{unitprice
} = $order->{ecost_tax_included
};
2924 # The user entered the unit price tax included
2925 $order->{unitprice_tax_included
} = $order->{unitprice
};
2927 # unit price tax excluded = unit price tax included / ( 1 + tax rate )
2928 $order->{unitprice_tax_excluded
} = $order->{unitprice_tax_included
} / ( 1 + $order->{tax_rate_on_receiving
} );
2931 # Trick for unitprice. If the unit price rounded value is the same as the ecost rounded value
2932 # we need to keep the exact ecost value
2933 if ( Koha
::Number
::Price
->new( $order->{unitprice
} )->round == Koha
::Number
::Price
->new( $order->{ecost_tax_excluded
} )->round ) {
2934 $order->{unitprice
} = $order->{ecost_tax_excluded
};
2937 # The user entered the unit price tax excluded
2938 $order->{unitprice_tax_excluded
} = $order->{unitprice
};
2941 # unit price tax included = unit price tax included * ( 1 + tax rate )
2942 $order->{unitprice_tax_included
} = $order->{unitprice_tax_excluded
} * ( 1 + $order->{tax_rate_on_receiving
} );
2945 # tax value = quantity * unit price tax excluded * tax rate
2946 $order->{tax_value_on_receiving
} = $order->{quantity
} * $order->{unitprice_tax_excluded
} * $order->{tax_rate_on_receiving
};
2952 =head3 GetOrderUsers
2954 $order_users_ids = &GetOrderUsers($ordernumber);
2956 Returns a list of all borrowernumbers that are in order users list
2961 my ($ordernumber) = @_;
2963 return unless $ordernumber;
2966 SELECT borrowernumber
2968 WHERE ordernumber
= ?
2970 my $dbh = C4
::Context
->dbh;
2971 my $sth = $dbh->prepare($query);
2972 $sth->execute($ordernumber);
2973 my $results = $sth->fetchall_arrayref( {} );
2975 my @borrowernumbers;
2976 foreach (@
$results) {
2977 push @borrowernumbers, $_->{'borrowernumber'};
2980 return @borrowernumbers;
2983 =head3 ModOrderUsers
2985 my @order_users_ids = (1, 2, 3);
2986 &ModOrderUsers($ordernumber, @basketusers_ids);
2988 Delete all users from order users list, and add users in C<@order_users_ids>
2994 my ( $ordernumber, @order_users_ids ) = @_;
2996 return unless $ordernumber;
2998 my $dbh = C4
::Context
->dbh;
3000 DELETE FROM aqorder_users
3001 WHERE ordernumber
= ?
3003 my $sth = $dbh->prepare($query);
3004 $sth->execute($ordernumber);
3007 INSERT INTO aqorder_users
(ordernumber
, borrowernumber
)
3010 $sth = $dbh->prepare($query);
3011 foreach my $order_user_id (@order_users_ids) {
3012 $sth->execute( $ordernumber, $order_user_id );
3016 sub NotifyOrderUsers
{
3017 my ($ordernumber) = @_;
3019 my @borrowernumbers = GetOrderUsers
($ordernumber);
3020 return unless @borrowernumbers;
3022 my $order = GetOrder
( $ordernumber );
3023 for my $borrowernumber (@borrowernumbers) {
3024 my $borrower = C4
::Members
::GetMember
( borrowernumber
=> $borrowernumber );
3025 my $library = Koha
::Libraries
->find( $borrower->{branchcode
} )->unblessed;
3026 my $biblio = C4
::Biblio
::GetBiblio
( $order->{biblionumber
} );
3027 my $letter = C4
::Letters
::GetPreparedLetter
(
3028 module
=> 'acquisition',
3029 letter_code
=> 'ACQ_NOTIF_ON_RECEIV',
3030 branchcode
=> $library->{branchcode
},
3032 'branches' => $library,
3033 'borrowers' => $borrower,
3034 'biblio' => $biblio,
3035 'aqorders' => $order,
3039 C4
::Letters
::EnqueueLetter
(
3042 borrowernumber
=> $borrowernumber,
3043 LibraryName
=> C4
::Context
->preference("LibraryName"),
3044 message_transport_type
=> 'email',
3046 ) or warn "can't enqueue letter $letter";
3051 =head3 FillWithDefaultValues
3053 FillWithDefaultValues( $marc_record );
3055 This will update the record with default value defined in the ACQ framework.
3056 For all existing fields, if a default value exists and there are no subfield, it will be created.
3057 If the field does not exist, it will be created too.
3061 sub FillWithDefaultValues
{
3063 my $tagslib = C4
::Biblio
::GetMarcStructure
( 1, 'ACQ', { unsafe
=> 1 } );
3066 C4
::Biblio
::GetMarcFromKohaField
( 'items.itemnumber', '' );
3067 for my $tag ( sort keys %$tagslib ) {
3069 next if $tag == $itemfield;
3070 for my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
3071 next if IsMarcStructureInternal
($tagslib->{$tag}{$subfield});
3072 my $defaultvalue = $tagslib->{$tag}{$subfield}{defaultvalue
};
3073 if ( defined $defaultvalue and $defaultvalue ne '' ) {
3074 my @fields = $record->field($tag);
3076 for my $field (@fields) {
3077 unless ( defined $field->subfield($subfield) ) {
3078 $field->add_subfields(
3079 $subfield => $defaultvalue );
3084 $record->insert_fields_ordered(
3086 $tag, '', '', $subfield => $defaultvalue
3101 Koha Development Team <http://koha-community.org/>