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
::Booksellers
;
34 use Koha
::Number
::Price
;
44 use vars
qw(@ISA @EXPORT);
50 &GetBasket &NewBasket &CloseBasket &ReopenBasket &DelBasket &ModBasket
51 &GetBasketAsCSV &GetBasketGroupAsCSV
52 &GetBasketsByBookseller &GetBasketsByBasketgroup
53 &GetBasketsInfosByBookseller
55 &GetBasketUsers &ModBasketUsers
60 &ModBasketgroup &NewBasketgroup &DelBasketgroup &GetBasketgroup &CloseBasketgroup
61 &GetBasketgroups &ReOpenBasketgroup
63 &DelOrder &ModOrder &GetOrder &GetOrders &GetOrdersByBiblionumber
64 &GetLateOrders &GetOrderFromItemnumber
65 &SearchOrders &GetHistory &GetRecentAcqui
66 &ModReceiveOrder &CancelReceipt
68 &GetLastOrderNotReceivedFromSubscriptionid &GetLastOrderReceivedFromSubscriptionid
83 &GetItemnumbersFromOrder
86 &GetBiblioCountByBasketno
92 &FillWithDefaultValues
100 sub GetOrderFromItemnumber
{
101 my ($itemnumber) = @_;
102 my $dbh = C4
::Context
->dbh;
105 SELECT
* from aqorders LEFT JOIN aqorders_items
106 ON
( aqorders
.ordernumber
= aqorders_items
.ordernumber
)
107 WHERE itemnumber
= ?
|;
109 my $sth = $dbh->prepare($query);
113 $sth->execute($itemnumber);
115 my $order = $sth->fetchrow_hashref;
120 # Returns the itemnumber(s) associated with the ordernumber given in parameter
121 sub GetItemnumbersFromOrder
{
122 my ($ordernumber) = @_;
123 my $dbh = C4
::Context
->dbh;
124 my $query = "SELECT itemnumber FROM aqorders_items WHERE ordernumber=?";
125 my $sth = $dbh->prepare($query);
126 $sth->execute($ordernumber);
129 while (my $order = $sth->fetchrow_hashref) {
130 push @tab, $order->{'itemnumber'};
144 C4::Acquisition - Koha functions for dealing with orders and acquisitions
152 The functions in this module deal with acquisitions, managing book
153 orders, basket and parcels.
157 =head2 FUNCTIONS ABOUT BASKETS
161 $aqbasket = &GetBasket($basketnumber);
163 get all basket informations in aqbasket for a given basket
165 B<returns:> informations for a given basket returned as a hashref.
171 my $dbh = C4
::Context
->dbh;
174 concat( b.firstname,' ',b.surname) AS authorisedbyname
176 LEFT JOIN borrowers b ON aqbasket.authorisedby=b.borrowernumber
179 my $sth=$dbh->prepare($query);
180 $sth->execute($basketno);
181 my $basket = $sth->fetchrow_hashref;
185 #------------------------------------------------------------#
189 $basket = &NewBasket( $booksellerid, $authorizedby, $basketname,
190 $basketnote, $basketbooksellernote, $basketcontractnumber, $deliveryplace, $billingplace, $is_standing );
192 Create a new basket in aqbasket table
196 =item C<$booksellerid> is a foreign key in the aqbasket table
198 =item C<$authorizedby> is the username of who created the basket
202 The other parameters are optional, see ModBasketHeader for more info on them.
207 my ( $booksellerid, $authorisedby, $basketname, $basketnote,
208 $basketbooksellernote, $basketcontractnumber, $deliveryplace,
209 $billingplace, $is_standing ) = @_;
210 my $dbh = C4
::Context
->dbh;
212 'INSERT INTO aqbasket (creationdate,booksellerid,authorisedby) '
213 . 'VALUES (now(),?,?)';
214 $dbh->do( $query, {}, $booksellerid, $authorisedby );
216 my $basket = $dbh->{mysql_insertid
};
217 $basketname ||= q{}; # default to empty strings
219 $basketbooksellernote ||= q{};
220 ModBasketHeader
( $basket, $basketname, $basketnote, $basketbooksellernote,
221 $basketcontractnumber, $booksellerid, $deliveryplace, $billingplace, $is_standing );
225 #------------------------------------------------------------#
229 &CloseBasket($basketno);
231 close a basket (becomes unmodifiable, except for receives)
237 my $dbh = C4
::Context
->dbh;
238 $dbh->do('UPDATE aqbasket SET closedate=now() WHERE basketno=?', {}, $basketno );
241 q{UPDATE aqorders SET orderstatus = 'ordered' WHERE basketno = ? AND orderstatus NOT IN ( 'complete', 'cancelled')},
249 &ReopenBasket($basketno);
257 my $dbh = C4
::Context
->dbh;
258 $dbh->do( q{UPDATE aqbasket SET closedate=NULL WHERE basketno=?}, {}, $basketno );
262 SET orderstatus = 'new'
264 AND orderstatus NOT IN ( 'complete', 'cancelled' )
269 #------------------------------------------------------------#
271 =head3 GetBasketAsCSV
273 &GetBasketAsCSV($basketno);
275 Export a basket as CSV
277 $cgi parameter is needed for column name translation
282 my ($basketno, $cgi) = @_;
283 my $basket = GetBasket
($basketno);
284 my @orders = GetOrders
($basketno);
285 my $contract = GetContract
({
286 contractnumber
=> $basket->{'contractnumber'}
289 my $template = C4
::Templates
::gettemplate
("acqui/csv/basket.tt", "intranet", $cgi);
292 foreach my $order (@orders) {
293 my $bd = GetBiblioData
( $order->{'biblionumber'} );
295 contractname
=> $contract->{'contractname'},
296 ordernumber
=> $order->{'ordernumber'},
297 entrydate
=> $order->{'entrydate'},
298 isbn
=> $order->{'isbn'},
299 author
=> $bd->{'author'},
300 title
=> $bd->{'title'},
301 publicationyear
=> $bd->{'publicationyear'},
302 publishercode
=> $bd->{'publishercode'},
303 collectiontitle
=> $bd->{'collectiontitle'},
304 notes
=> $order->{'order_vendornote'},
305 quantity
=> $order->{'quantity'},
306 rrp
=> $order->{'rrp'},
308 for my $place ( qw( deliveryplace billingplace ) ) {
309 if ( my $library = Koha
::Libraries
->find( $row->{deliveryplace
} ) ) {
310 $row->{$place} = $library->branchname
314 contractname author title publishercode collectiontitle notes
315 deliveryplace billingplace
317 # Double the quotes to not be interpreted as a field end
318 $row->{$_} =~ s/"/""/g if $row->{$_};
324 if(defined $a->{publishercode
} and defined $b->{publishercode
}) {
325 $a->{publishercode
} cmp $b->{publishercode
};
329 $template->param(rows
=> \
@rows);
331 return $template->output;
335 =head3 GetBasketGroupAsCSV
337 &GetBasketGroupAsCSV($basketgroupid);
339 Export a basket group as CSV
341 $cgi parameter is needed for column name translation
345 sub GetBasketGroupAsCSV
{
346 my ($basketgroupid, $cgi) = @_;
347 my $baskets = GetBasketsByBasketgroup
($basketgroupid);
349 my $template = C4
::Templates
::gettemplate
('acqui/csv/basketgroup.tt', 'intranet', $cgi);
352 for my $basket (@
$baskets) {
353 my @orders = GetOrders
( $basket->{basketno
} );
354 my $contract = GetContract
({
355 contractnumber
=> $basket->{contractnumber
}
357 my $bookseller = Koha
::Acquisition
::Booksellers
->find( $basket->{booksellerid
} );
358 my $basketgroup = GetBasketgroup
( $$basket{basketgroupid
} );
360 foreach my $order (@orders) {
361 my $bd = GetBiblioData
( $order->{'biblionumber'} );
363 clientnumber
=> $bookseller->accountnumber,
364 basketname
=> $basket->{basketname
},
365 ordernumber
=> $order->{ordernumber
},
366 author
=> $bd->{author
},
367 title
=> $bd->{title
},
368 publishercode
=> $bd->{publishercode
},
369 publicationyear
=> $bd->{publicationyear
},
370 collectiontitle
=> $bd->{collectiontitle
},
371 isbn
=> $order->{isbn
},
372 quantity
=> $order->{quantity
},
373 rrp_tax_included
=> $order->{rrp_tax_included
},
374 rrp_tax_excluded
=> $order->{rrp_tax_excluded
},
375 discount
=> $bookseller->discount,
376 ecost_tax_included
=> $order->{ecost_tax_included
},
377 ecost_tax_excluded
=> $order->{ecost_tax_excluded
},
378 notes
=> $order->{order_vendornote
},
379 entrydate
=> $order->{entrydate
},
380 booksellername
=> $bookseller->name,
381 bookselleraddress
=> $bookseller->address1,
382 booksellerpostal
=> $bookseller->postal,
383 contractnumber
=> $contract->{contractnumber
},
384 contractname
=> $contract->{contractname
},
387 basketgroupdeliveryplace
=> $basketgroup->{deliveryplace
},
388 basketgroupbillingplace
=> $basketgroup->{billingplace
},
389 basketdeliveryplace
=> $basket->{deliveryplace
},
390 basketbillingplace
=> $basket->{billingplace
},
392 for my $place (qw( basketgroupdeliveryplace basketgroupbillingplace basketdeliveryplace basketbillingplace )) {
393 if ( my $library = Koha
::Libraries
->find( $temp->{$place} ) ) {
394 $row->{$place} = $library->branchname;
398 basketname author title publishercode collectiontitle notes
399 booksellername bookselleraddress booksellerpostal contractname
400 basketgroupdeliveryplace basketgroupbillingplace
401 basketdeliveryplace basketbillingplace
403 # Double the quotes to not be interpreted as a field end
404 $row->{$_} =~ s/"/""/g if $row->{$_};
409 $template->param(rows
=> \
@rows);
411 return $template->output;
415 =head3 CloseBasketgroup
417 &CloseBasketgroup($basketgroupno);
423 sub CloseBasketgroup
{
424 my ($basketgroupno) = @_;
425 my $dbh = C4
::Context
->dbh;
426 my $sth = $dbh->prepare("
427 UPDATE aqbasketgroups
431 $sth->execute($basketgroupno);
434 #------------------------------------------------------------#
436 =head3 ReOpenBaskergroup($basketgroupno)
438 &ReOpenBaskergroup($basketgroupno);
444 sub ReOpenBasketgroup
{
445 my ($basketgroupno) = @_;
446 my $dbh = C4
::Context
->dbh;
447 my $sth = $dbh->prepare("
448 UPDATE aqbasketgroups
452 $sth->execute($basketgroupno);
455 #------------------------------------------------------------#
460 &DelBasket($basketno);
462 Deletes the basket that has basketno field $basketno in the aqbasket table.
466 =item C<$basketno> is the primary key of the basket in the aqbasket table.
473 my ( $basketno ) = @_;
474 my $query = "DELETE FROM aqbasket WHERE basketno=?";
475 my $dbh = C4
::Context
->dbh;
476 my $sth = $dbh->prepare($query);
477 $sth->execute($basketno);
481 #------------------------------------------------------------#
485 &ModBasket($basketinfo);
487 Modifies a basket, using a hashref $basketinfo for the relevant information, only $basketinfo->{'basketno'} is required.
491 =item C<$basketno> is the primary key of the basket in the aqbasket table.
498 my $basketinfo = shift;
499 my $query = "UPDATE aqbasket SET ";
501 foreach my $key (keys %$basketinfo){
502 if ($key ne 'basketno'){
503 $query .= "$key=?, ";
504 push(@params, $basketinfo->{$key} || undef );
507 # get rid of the "," at the end of $query
508 if (substr($query, length($query)-2) eq ', '){
513 $query .= "WHERE basketno=?";
514 push(@params, $basketinfo->{'basketno'});
515 my $dbh = C4
::Context
->dbh;
516 my $sth = $dbh->prepare($query);
517 $sth->execute(@params);
522 #------------------------------------------------------------#
524 =head3 ModBasketHeader
526 &ModBasketHeader($basketno, $basketname, $note, $booksellernote, $contractnumber, $booksellerid);
528 Modifies a basket's header.
532 =item C<$basketno> is the "basketno" field in the "aqbasket" table;
534 =item C<$basketname> is the "basketname" field in the "aqbasket" table;
536 =item C<$note> is the "note" field in the "aqbasket" table;
538 =item C<$booksellernote> is the "booksellernote" field in the "aqbasket" table;
540 =item C<$contractnumber> is the "contractnumber" (foreign) key in the "aqbasket" table.
542 =item C<$booksellerid> is the id (foreign) key in the "aqbooksellers" table for the vendor.
544 =item C<$deliveryplace> is the "deliveryplace" field in the aqbasket table.
546 =item C<$billingplace> is the "billingplace" field in the aqbasket table.
548 =item C<$is_standing> is the "is_standing" field in the aqbasket table.
554 sub ModBasketHeader
{
555 my ($basketno, $basketname, $note, $booksellernote, $contractnumber, $booksellerid, $deliveryplace, $billingplace, $is_standing) = @_;
558 SET basketname
=?
, note
=?
, booksellernote
=?
, booksellerid
=?
, deliveryplace
=?
, billingplace
=?
, is_standing
=?
562 my $dbh = C4
::Context
->dbh;
563 my $sth = $dbh->prepare($query);
564 $sth->execute($basketname, $note, $booksellernote, $booksellerid, $deliveryplace, $billingplace, $is_standing, $basketno);
566 if ( $contractnumber ) {
567 my $query2 ="UPDATE aqbasket SET contractnumber=? WHERE basketno=?";
568 my $sth2 = $dbh->prepare($query2);
569 $sth2->execute($contractnumber,$basketno);
574 #------------------------------------------------------------#
576 =head3 GetBasketsByBookseller
578 @results = &GetBasketsByBookseller($booksellerid, $extra);
580 Returns a list of hashes of all the baskets that belong to bookseller 'booksellerid'.
584 =item C<$booksellerid> is the 'id' field of the bookseller in the aqbooksellers table
586 =item C<$extra> is the extra sql parameters, can be
588 $extra->{groupby}: group baskets by column
589 ex. $extra->{groupby} = aqbasket.basketgroupid
590 $extra->{orderby}: order baskets by column
591 $extra->{limit}: limit number of results (can be helpful for pagination)
597 sub GetBasketsByBookseller
{
598 my ($booksellerid, $extra) = @_;
599 my $query = "SELECT * FROM aqbasket WHERE booksellerid=?";
601 if ($extra->{groupby
}) {
602 $query .= " GROUP by $extra->{groupby}";
604 if ($extra->{orderby
}){
605 $query .= " ORDER by $extra->{orderby}";
607 if ($extra->{limit
}){
608 $query .= " LIMIT $extra->{limit}";
611 my $dbh = C4
::Context
->dbh;
612 my $sth = $dbh->prepare($query);
613 $sth->execute($booksellerid);
614 return $sth->fetchall_arrayref({});
617 =head3 GetBasketsInfosByBookseller
619 my $baskets = GetBasketsInfosByBookseller($supplierid, $allbaskets);
621 The optional second parameter allbaskets is a boolean allowing you to
622 select all baskets from the supplier; by default only active baskets (open or
623 closed but still something to receive) are returned.
625 Returns in a arrayref of hashref all about booksellers baskets, plus:
626 total_biblios: Number of distinct biblios in basket
627 total_items: Number of items in basket
628 expected_items: Number of non-received items in basket
632 sub GetBasketsInfosByBookseller
{
633 my ($supplierid, $allbaskets) = @_;
635 return unless $supplierid;
637 my $dbh = C4
::Context
->dbh;
640 SUM(aqorders.quantity) AS total_items,
642 IF ( aqorders.orderstatus = 'cancelled', aqorders.quantity, 0 )
643 ) AS total_items_cancelled,
644 COUNT(DISTINCT aqorders.biblionumber) AS total_biblios,
646 IF(aqorders.datereceived IS NULL
647 AND aqorders.datecancellationprinted IS NULL
652 LEFT JOIN aqorders ON aqorders.basketno = aqbasket.basketno
653 WHERE booksellerid = ?};
655 unless ( $allbaskets ) {
656 $query.=" AND (closedate IS NULL OR (aqorders.quantity > aqorders.quantityreceived AND datecancellationprinted IS NULL))";
658 $query.=" GROUP BY aqbasket.basketno";
660 my $sth = $dbh->prepare($query);
661 $sth->execute($supplierid);
662 my $baskets = $sth->fetchall_arrayref({});
664 # Retrieve the number of biblios cancelled
665 my $cancelled_biblios = $dbh->selectall_hashref( q
|
666 SELECT COUNT
(DISTINCT
(biblionumber
)) AS total_biblios_cancelled
, aqbasket
.basketno
668 LEFT JOIN aqorders ON aqorders
.basketno
= aqbasket
.basketno
669 WHERE booksellerid
= ?
670 AND aqorders
.orderstatus
= 'cancelled'
671 GROUP BY aqbasket
.basketno
672 |, 'basketno', {}, $supplierid );
674 $_->{total_biblios_cancelled
} = $cancelled_biblios->{$_->{basketno
}}{total_biblios_cancelled
} || 0
680 =head3 GetBasketUsers
682 $basketusers_ids = &GetBasketUsers($basketno);
684 Returns a list of all borrowernumbers that are in basket users list
689 my $basketno = shift;
691 return unless $basketno;
694 SELECT borrowernumber
698 my $dbh = C4
::Context
->dbh;
699 my $sth = $dbh->prepare($query);
700 $sth->execute($basketno);
701 my $results = $sth->fetchall_arrayref( {} );
704 foreach (@
$results) {
705 push @borrowernumbers, $_->{'borrowernumber'};
708 return @borrowernumbers;
711 =head3 ModBasketUsers
713 my @basketusers_ids = (1, 2, 3);
714 &ModBasketUsers($basketno, @basketusers_ids);
716 Delete all users from basket users list, and add users in C<@basketusers_ids>
722 my ($basketno, @basketusers_ids) = @_;
724 return unless $basketno;
726 my $dbh = C4
::Context
->dbh;
728 DELETE FROM aqbasketusers
731 my $sth = $dbh->prepare($query);
732 $sth->execute($basketno);
735 INSERT INTO aqbasketusers
(basketno
, borrowernumber
)
738 $sth = $dbh->prepare($query);
739 foreach my $basketuser_id (@basketusers_ids) {
740 $sth->execute($basketno, $basketuser_id);
745 =head3 CanUserManageBasket
747 my $bool = CanUserManageBasket($borrower, $basket[, $userflags]);
748 my $bool = CanUserManageBasket($borrowernumber, $basketno[, $userflags]);
750 Check if a borrower can manage a basket, according to system preference
751 AcqViewBaskets, user permissions and basket properties (creator, users list,
754 First parameter can be either a borrowernumber or a hashref as returned by
755 C4::Members::GetMember.
757 Second parameter can be either a basketno or a hashref as returned by
758 C4::Acquisition::GetBasket.
760 The third parameter is optional. If given, it should be a hashref as returned
761 by C4::Auth::getuserflags. If not, getuserflags is called.
763 If user is authorised to manage basket, returns 1.
768 sub CanUserManageBasket
{
769 my ($borrower, $basket, $userflags) = @_;
771 if (!ref $borrower) {
772 $borrower = C4
::Members
::GetMember
(borrowernumber
=> $borrower);
775 $basket = GetBasket
($basket);
778 return 0 unless ($basket and $borrower);
780 my $borrowernumber = $borrower->{borrowernumber
};
781 my $basketno = $basket->{basketno
};
783 my $AcqViewBaskets = C4
::Context
->preference('AcqViewBaskets');
785 if (!defined $userflags) {
786 my $dbh = C4
::Context
->dbh;
787 my $sth = $dbh->prepare("SELECT flags FROM borrowers WHERE borrowernumber = ?");
788 $sth->execute($borrowernumber);
789 my ($flags) = $sth->fetchrow_array;
792 $userflags = C4
::Auth
::getuserflags
($flags, $borrower->{userid
}, $dbh);
795 unless ($userflags->{superlibrarian
}
796 || (ref $userflags->{acquisition
} && $userflags->{acquisition
}->{order_manage_all
})
797 || (!ref $userflags->{acquisition
} && $userflags->{acquisition
}))
799 if (not exists $userflags->{acquisition
}) {
803 if ( (ref $userflags->{acquisition
} && !$userflags->{acquisition
}->{order_manage
})
804 || (!ref $userflags->{acquisition
} && !$userflags->{acquisition
}) ) {
808 if ($AcqViewBaskets eq 'user'
809 && $basket->{authorisedby
} != $borrowernumber
810 && ! grep { $borrowernumber eq $_ } GetBasketUsers
($basketno)) {
814 if ($AcqViewBaskets eq 'branch' && defined $basket->{branch
}
815 && $basket->{branch
} ne $borrower->{branchcode
}) {
823 #------------------------------------------------------------#
825 =head3 GetBasketsByBasketgroup
827 $baskets = &GetBasketsByBasketgroup($basketgroupid);
829 Returns a reference to all baskets that belong to basketgroup $basketgroupid.
833 sub GetBasketsByBasketgroup
{
834 my $basketgroupid = shift;
836 SELECT
*, aqbasket
.booksellerid as booksellerid
838 LEFT JOIN aqcontract USING
(contractnumber
) WHERE basketgroupid
=?
840 my $dbh = C4
::Context
->dbh;
841 my $sth = $dbh->prepare($query);
842 $sth->execute($basketgroupid);
843 return $sth->fetchall_arrayref({});
846 #------------------------------------------------------------#
848 =head3 NewBasketgroup
850 $basketgroupid = NewBasketgroup(\%hashref);
852 Adds a basketgroup to the aqbasketgroups table, and add the initial baskets to it.
854 $hashref->{'booksellerid'} is the 'id' field of the bookseller in the aqbooksellers table,
856 $hashref->{'name'} is the 'name' field of the basketgroup in the aqbasketgroups table,
858 $hashref->{'basketlist'} is a list reference of the 'id's of the baskets that belong to this group,
860 $hashref->{'billingplace'} is the 'billingplace' field of the basketgroup in the aqbasketgroups table,
862 $hashref->{'deliveryplace'} is the 'deliveryplace' field of the basketgroup in the aqbasketgroups table,
864 $hashref->{'freedeliveryplace'} is the 'freedeliveryplace' field of the basketgroup in the aqbasketgroups table,
866 $hashref->{'deliverycomment'} is the 'deliverycomment' field of the basketgroup in the aqbasketgroups table,
868 $hashref->{'closed'} is the 'closed' field of the aqbasketgroups table, it is false if 0, true otherwise.
873 my $basketgroupinfo = shift;
874 die "booksellerid is required to create a basketgroup" unless $basketgroupinfo->{'booksellerid'};
875 my $query = "INSERT INTO aqbasketgroups (";
877 foreach my $field (qw(name billingplace deliveryplace freedeliveryplace deliverycomment closed)) {
878 if ( defined $basketgroupinfo->{$field} ) {
879 $query .= "$field, ";
880 push(@params, $basketgroupinfo->{$field});
883 $query .= "booksellerid) VALUES (";
888 push(@params, $basketgroupinfo->{'booksellerid'});
889 my $dbh = C4
::Context
->dbh;
890 my $sth = $dbh->prepare($query);
891 $sth->execute(@params);
892 my $basketgroupid = $dbh->{'mysql_insertid'};
893 if( $basketgroupinfo->{'basketlist'} ) {
894 foreach my $basketno (@
{$basketgroupinfo->{'basketlist'}}) {
895 my $query2 = "UPDATE aqbasket SET basketgroupid=? WHERE basketno=?";
896 my $sth2 = $dbh->prepare($query2);
897 $sth2->execute($basketgroupid, $basketno);
900 return $basketgroupid;
903 #------------------------------------------------------------#
905 =head3 ModBasketgroup
907 ModBasketgroup(\%hashref);
909 Modifies a basketgroup in the aqbasketgroups table, and add the baskets to it.
911 $hashref->{'id'} is the 'id' field of the basketgroup in the aqbasketgroup table, this parameter is mandatory,
913 $hashref->{'name'} is the 'name' field of the basketgroup in the aqbasketgroups table,
915 $hashref->{'basketlist'} is a list reference of the 'id's of the baskets that belong to this group,
917 $hashref->{'billingplace'} is the 'billingplace' field of the basketgroup in the aqbasketgroups table,
919 $hashref->{'deliveryplace'} is the 'deliveryplace' field of the basketgroup in the aqbasketgroups table,
921 $hashref->{'freedeliveryplace'} is the 'freedeliveryplace' field of the basketgroup in the aqbasketgroups table,
923 $hashref->{'deliverycomment'} is the 'deliverycomment' field of the basketgroup in the aqbasketgroups table,
925 $hashref->{'closed'} is the 'closed' field of the aqbasketgroups table, it is false if 0, true otherwise.
930 my $basketgroupinfo = shift;
931 die "basketgroup id is required to edit a basketgroup" unless $basketgroupinfo->{'id'};
932 my $dbh = C4
::Context
->dbh;
933 my $query = "UPDATE aqbasketgroups SET ";
935 foreach my $field (qw(name billingplace deliveryplace freedeliveryplace deliverycomment closed)) {
936 if ( defined $basketgroupinfo->{$field} ) {
937 $query .= "$field=?, ";
938 push(@params, $basketgroupinfo->{$field});
943 $query .= " WHERE id=?";
944 push(@params, $basketgroupinfo->{'id'});
945 my $sth = $dbh->prepare($query);
946 $sth->execute(@params);
948 $sth = $dbh->prepare('UPDATE aqbasket SET basketgroupid = NULL WHERE basketgroupid = ?');
949 $sth->execute($basketgroupinfo->{'id'});
951 if($basketgroupinfo->{'basketlist'} && @
{$basketgroupinfo->{'basketlist'}}){
952 $sth = $dbh->prepare("UPDATE aqbasket SET basketgroupid=? WHERE basketno=?");
953 foreach my $basketno (@
{$basketgroupinfo->{'basketlist'}}) {
954 $sth->execute($basketgroupinfo->{'id'}, $basketno);
960 #------------------------------------------------------------#
962 =head3 DelBasketgroup
964 DelBasketgroup($basketgroupid);
966 Deletes a basketgroup in the aqbasketgroups table, and removes the reference to it from the baskets,
970 =item C<$basketgroupid> is the 'id' field of the basket in the aqbasketgroup table
977 my $basketgroupid = shift;
978 die "basketgroup id is required to edit a basketgroup" unless $basketgroupid;
979 my $query = "DELETE FROM aqbasketgroups WHERE id=?";
980 my $dbh = C4
::Context
->dbh;
981 my $sth = $dbh->prepare($query);
982 $sth->execute($basketgroupid);
986 #------------------------------------------------------------#
989 =head2 FUNCTIONS ABOUT ORDERS
991 =head3 GetBasketgroup
993 $basketgroup = &GetBasketgroup($basketgroupid);
995 Returns a reference to the hash containing all information about the basketgroup.
1000 my $basketgroupid = shift;
1001 die "basketgroup id is required to edit a basketgroup" unless $basketgroupid;
1002 my $dbh = C4
::Context
->dbh;
1003 my $result_set = $dbh->selectall_arrayref(
1004 'SELECT * FROM aqbasketgroups WHERE id=?',
1008 return $result_set->[0]; # id is unique
1011 #------------------------------------------------------------#
1013 =head3 GetBasketgroups
1015 $basketgroups = &GetBasketgroups($booksellerid);
1017 Returns a reference to the array of all the basketgroups of bookseller $booksellerid.
1021 sub GetBasketgroups
{
1022 my $booksellerid = shift;
1023 die 'bookseller id is required to edit a basketgroup' unless $booksellerid;
1024 my $query = 'SELECT * FROM aqbasketgroups WHERE booksellerid=? ORDER BY id DESC';
1025 my $dbh = C4
::Context
->dbh;
1026 my $sth = $dbh->prepare($query);
1027 $sth->execute($booksellerid);
1028 return $sth->fetchall_arrayref({});
1031 #------------------------------------------------------------#
1033 =head2 FUNCTIONS ABOUT ORDERS
1037 @orders = &GetOrders( $basketno, { orderby => 'biblio.title', cancelled => 0|1 } );
1039 Looks up the pending (non-cancelled) orders with the given basket
1042 If cancelled is set, only cancelled orders will be returned.
1047 my ( $basketno, $params ) = @_;
1049 return () unless $basketno;
1051 my $orderby = $params->{orderby
};
1052 my $cancelled = $params->{cancelled
} || 0;
1054 my $dbh = C4
::Context
->dbh;
1056 SELECT biblio
.*,biblioitems
.*,
1060 $query .= $cancelled
1062 aqorders_transfers
.ordernumber_to AS transferred_to
,
1063 aqorders_transfers
.timestamp AS transferred_to_timestamp
1066 aqorders_transfers
.ordernumber_from AS transferred_from
,
1067 aqorders_transfers
.timestamp AS transferred_from_timestamp
1071 LEFT JOIN aqbudgets ON aqbudgets
.budget_id
= aqorders
.budget_id
1072 LEFT JOIN biblio ON biblio
.biblionumber
= aqorders
.biblionumber
1073 LEFT JOIN biblioitems ON biblioitems
.biblionumber
=biblio
.biblionumber
1075 $query .= $cancelled
1077 LEFT JOIN aqorders_transfers ON aqorders_transfers
.ordernumber_from
= aqorders
.ordernumber
1080 LEFT JOIN aqorders_transfers ON aqorders_transfers
.ordernumber_to
= aqorders
.ordernumber
1088 $orderby ||= q
|biblioitems
.publishercode
, biblio
.title
|;
1090 AND
(datecancellationprinted IS NOT NULL
1091 AND datecancellationprinted
<> '0000-00-00')
1096 q
|aqorders
.datecancellationprinted desc
, aqorders
.timestamp desc
|;
1098 AND
(datecancellationprinted IS NULL OR datecancellationprinted
='0000-00-00')
1102 $query .= " ORDER BY $orderby";
1104 $dbh->selectall_arrayref( $query, { Slice
=> {} }, $basketno );
1109 #------------------------------------------------------------#
1111 =head3 GetOrdersByBiblionumber
1113 @orders = &GetOrdersByBiblionumber($biblionumber);
1115 Looks up the orders with linked to a specific $biblionumber, including
1116 cancelled orders and received orders.
1119 C<@orders> is an array of references-to-hash, whose keys are the
1120 fields from the aqorders, biblio, and biblioitems tables in the Koha database.
1124 sub GetOrdersByBiblionumber
{
1125 my $biblionumber = shift;
1126 return unless $biblionumber;
1127 my $dbh = C4
::Context
->dbh;
1129 SELECT biblio.*,biblioitems.*,
1133 LEFT JOIN aqbudgets ON aqbudgets.budget_id = aqorders.budget_id
1134 LEFT JOIN biblio ON biblio.biblionumber = aqorders.biblionumber
1135 LEFT JOIN biblioitems ON biblioitems.biblionumber =biblio.biblionumber
1136 WHERE aqorders.biblionumber=?
1139 $dbh->selectall_arrayref( $query, { Slice
=> {} }, $biblionumber );
1140 return @
{$result_set};
1144 #------------------------------------------------------------#
1148 $order = &GetOrder($ordernumber);
1150 Looks up an order by order number.
1152 Returns a reference-to-hash describing the order. The keys of
1153 C<$order> are fields from the biblio, biblioitems, aqorders tables of the Koha database.
1158 my ($ordernumber) = @_;
1159 return unless $ordernumber;
1161 my $dbh = C4
::Context
->dbh;
1162 my $query = qq{SELECT
1166 aqbasket
.basketname
,
1167 borrowers
.branchcode
,
1168 biblioitems
.publicationyear
,
1169 biblio
.copyrightdate
,
1170 biblioitems
.editionstatement
,
1174 biblioitems
.publishercode
,
1175 aqorders
.rrp AS unitpricesupplier
,
1176 aqorders
.ecost AS unitpricelib
,
1177 aqorders
.claims_count AS claims_count
,
1178 aqorders
.claimed_date AS claimed_date
,
1179 aqbudgets
.budget_name AS budget
,
1180 aqbooksellers
.name AS supplier
,
1181 aqbooksellers
.id AS supplierid
,
1182 biblioitems
.publishercode AS publisher
,
1183 ADDDATE
(aqbasket
.closedate
, INTERVAL aqbooksellers
.deliverytime DAY
) AS estimateddeliverydate
,
1184 DATE
(aqbasket
.closedate
) AS orderdate
,
1185 aqorders
.quantity
- COALESCE
(aqorders
.quantityreceived
,0) AS quantity_to_receive
,
1186 (aqorders
.quantity
- COALESCE
(aqorders
.quantityreceived
,0)) * aqorders
.rrp AS subtotal
,
1187 DATEDIFF
(CURDATE
( ),closedate
) AS latesince
1188 FROM aqorders LEFT JOIN biblio ON biblio
.biblionumber
= aqorders
.biblionumber
1189 LEFT JOIN biblioitems ON biblioitems
.biblionumber
= biblio
.biblionumber
1190 LEFT JOIN aqbudgets ON aqorders
.budget_id
= aqbudgets
.budget_id
,
1191 aqbasket LEFT JOIN borrowers ON aqbasket
.authorisedby
= borrowers
.borrowernumber
1192 LEFT JOIN aqbooksellers ON aqbasket
.booksellerid
= aqbooksellers
.id
1193 WHERE aqorders
.basketno
= aqbasket
.basketno
1196 $dbh->selectall_arrayref( $query, { Slice
=> {} }, $ordernumber );
1198 # result_set assumed to contain 1 match
1199 return $result_set->[0];
1202 =head3 GetLastOrderNotReceivedFromSubscriptionid
1204 $order = &GetLastOrderNotReceivedFromSubscriptionid($subscriptionid);
1206 Returns a reference-to-hash describing the last order not received for a subscription.
1210 sub GetLastOrderNotReceivedFromSubscriptionid
{
1211 my ( $subscriptionid ) = @_;
1212 my $dbh = C4
::Context
->dbh;
1214 SELECT
* FROM aqorders
1215 LEFT JOIN subscription
1216 ON
( aqorders
.subscriptionid
= subscription
.subscriptionid
)
1217 WHERE aqorders
.subscriptionid
= ?
1218 AND aqorders
.datereceived IS NULL
1222 $dbh->selectall_arrayref( $query, { Slice
=> {} }, $subscriptionid );
1224 # result_set assumed to contain 1 match
1225 return $result_set->[0];
1228 =head3 GetLastOrderReceivedFromSubscriptionid
1230 $order = &GetLastOrderReceivedFromSubscriptionid($subscriptionid);
1232 Returns a reference-to-hash describing the last order received for a subscription.
1236 sub GetLastOrderReceivedFromSubscriptionid
{
1237 my ( $subscriptionid ) = @_;
1238 my $dbh = C4
::Context
->dbh;
1240 SELECT
* FROM aqorders
1241 LEFT JOIN subscription
1242 ON
( aqorders
.subscriptionid
= subscription
.subscriptionid
)
1243 WHERE aqorders
.subscriptionid
= ?
1244 AND aqorders
.datereceived
=
1246 SELECT MAX
( aqorders
.datereceived
)
1248 LEFT JOIN subscription
1249 ON
( aqorders
.subscriptionid
= subscription
.subscriptionid
)
1250 WHERE aqorders
.subscriptionid
= ?
1251 AND aqorders
.datereceived IS NOT NULL
1253 ORDER BY ordernumber DESC
1257 $dbh->selectall_arrayref( $query, { Slice
=> {} }, $subscriptionid, $subscriptionid );
1259 # result_set assumed to contain 1 match
1260 return $result_set->[0];
1264 #------------------------------------------------------------#
1268 &ModOrder(\%hashref);
1270 Modifies an existing order. Updates the order with order number
1271 $hashref->{'ordernumber'} and biblionumber $hashref->{'biblionumber'}. All
1272 other keys of the hash update the fields with the same name in the aqorders
1273 table of the Koha database.
1278 my $orderinfo = shift;
1280 die "Ordernumber is required" if $orderinfo->{'ordernumber'} eq '';
1282 my $dbh = C4
::Context
->dbh;
1285 # update uncertainprice to an integer, just in case (under FF, checked boxes have the value "ON" by default)
1286 $orderinfo->{uncertainprice
}=1 if $orderinfo->{uncertainprice
};
1288 # delete($orderinfo->{'branchcode'});
1289 # the hash contains a lot of entries not in aqorders, so get the columns ...
1290 my $sth = $dbh->prepare("SELECT * FROM aqorders LIMIT 1;");
1292 my $colnames = $sth->{NAME
};
1293 #FIXME Be careful. If aqorders would have columns with diacritics,
1294 #you should need to decode what you get back from NAME.
1295 #See report 10110 and guided_reports.pl
1296 my $query = "UPDATE aqorders SET ";
1298 foreach my $orderinfokey (grep(!/ordernumber/, keys %$orderinfo)){
1299 # ... and skip hash entries that are not in the aqorders table
1300 # FIXME : probably not the best way to do it (would be better to have a correct hash)
1301 next unless grep(/^$orderinfokey$/, @
$colnames);
1302 $query .= "$orderinfokey=?, ";
1303 push(@params, $orderinfo->{$orderinfokey});
1306 $query .= "timestamp=NOW() WHERE ordernumber=?";
1307 push(@params, $orderinfo->{'ordernumber'} );
1308 $sth = $dbh->prepare($query);
1309 $sth->execute(@params);
1313 #------------------------------------------------------------#
1317 ModItemOrder($itemnumber, $ordernumber);
1319 Modifies the ordernumber of an item in aqorders_items.
1324 my ($itemnumber, $ordernumber) = @_;
1326 return unless ($itemnumber and $ordernumber);
1328 my $dbh = C4
::Context
->dbh;
1330 UPDATE aqorders_items
1332 WHERE itemnumber
= ?
1334 my $sth = $dbh->prepare($query);
1335 return $sth->execute($ordernumber, $itemnumber);
1338 #------------------------------------------------------------#
1340 =head3 ModReceiveOrder
1342 my ( $date_received, $new_ordernumber ) = ModReceiveOrder(
1344 biblionumber => $biblionumber,
1346 quantityreceived => $quantityreceived,
1348 invoice => $invoice,
1349 budget_id => $budget_id,
1350 received_itemnumbers => \@received_itemnumbers,
1351 order_internalnote => $order_internalnote,
1355 Updates an order, to reflect the fact that it was received, at least
1358 If a partial order is received, splits the order into two.
1360 Updates the order with biblionumber C<$biblionumber> and ordernumber
1361 C<$order->{ordernumber}>.
1366 sub ModReceiveOrder
{
1368 my $biblionumber = $params->{biblionumber
};
1369 my $order = { %{ $params->{order
} } }; # Copy the order, we don't want to modify it
1370 my $invoice = $params->{invoice
};
1371 my $quantrec = $params->{quantityreceived
};
1372 my $user = $params->{user
};
1373 my $budget_id = $params->{budget_id
};
1374 my $received_items = $params->{received_items
};
1376 my $dbh = C4
::Context
->dbh;
1377 my $datereceived = ( $invoice and $invoice->{datereceived
} ) ?
$invoice->{datereceived
} : dt_from_string
;
1378 my $suggestionid = GetSuggestionFromBiblionumber
( $biblionumber );
1379 if ($suggestionid) {
1380 ModSuggestion
( {suggestionid
=>$suggestionid,
1381 STATUS
=>'AVAILABLE',
1382 biblionumber
=> $biblionumber}
1386 my $result_set = $dbh->selectrow_arrayref(
1387 q{SELECT aqbasket.is_standing
1389 WHERE basketno=?},{ Slice
=> {} }, $order->{basketno
});
1390 my $is_standing = $result_set->[0]; # we assume we have a unique basket
1392 my $new_ordernumber = $order->{ordernumber
};
1393 if ( $is_standing || $order->{quantity
} > $quantrec ) {
1394 # Split order line in two parts: the first is the original order line
1395 # without received items (the quantity is decreased),
1396 # the second part is a new order line with quantity=quantityrec
1397 # (entirely received)
1401 orderstatus
= 'partial'|;
1402 $query .= q
|, order_internalnote
= ?
| if defined $order->{order_internalnote
};
1403 $query .= q
| WHERE ordernumber
= ?
|;
1404 my $sth = $dbh->prepare($query);
1407 ( $is_standing ?
1 : ($order->{quantity
} - $quantrec) ),
1408 ( defined $order->{order_internalnote
} ?
$order->{order_internalnote
} : () ),
1409 $order->{ordernumber
}
1412 # Recalculate tax_value
1416 tax_value_on_ordering
= quantity
* ecost_tax_excluded
* tax_rate_on_ordering
,
1417 tax_value_on_receiving
= quantity
* unitprice_tax_excluded
* tax_rate_on_receiving
1418 WHERE ordernumber
= ?
1419 |, undef, $order->{ordernumber
});
1421 delete $order->{ordernumber
};
1422 $order->{budget_id
} = ( $budget_id || $order->{budget_id
} );
1423 $order->{quantity
} = $quantrec;
1424 $order->{quantityreceived
} = $quantrec;
1425 $order->{ecost_tax_excluded
} //= 0;
1426 $order->{tax_rate_on_ordering
} //= 0;
1427 $order->{unitprice_tax_excluded
} //= 0;
1428 $order->{tax_rate_on_receiving
} //= 0;
1429 $order->{tax_value_on_ordering
} = $order->{quantity
} * $order->{ecost_tax_excluded
} * $order->{tax_rate_on_ordering
};
1430 $order->{tax_value_on_receiving
} = $order->{quantity
} * $order->{unitprice_tax_excluded
} * $order->{tax_rate_on_receiving
};
1431 $order->{datereceived
} = $datereceived;
1432 $order->{invoiceid
} = $invoice->{invoiceid
};
1433 $order->{orderstatus
} = 'complete';
1434 $new_ordernumber = Koha
::Acquisition
::Order
->new($order)->insert->{ordernumber
};
1436 if ($received_items) {
1437 foreach my $itemnumber (@
$received_items) {
1438 ModItemOrder
($itemnumber, $new_ordernumber);
1444 SET quantityreceived
= ?
,
1448 orderstatus
= 'complete'
1452 , unitprice
= ?
, unitprice_tax_included
= ?
, unitprice_tax_excluded
= ?
1453 | if defined $order->{unitprice
};
1456 ,tax_value_on_receiving
= ?
1457 | if defined $order->{tax_value_on_receiving
};
1460 ,tax_rate_on_receiving
= ?
1461 | if defined $order->{tax_rate_on_receiving
};
1464 , order_internalnote
= ?
1465 | if defined $order->{order_internalnote
};
1467 $query .= q
| where biblionumber
=?
and ordernumber
=?
|;
1469 my $sth = $dbh->prepare( $query );
1470 my @params = ( $quantrec, $datereceived, $invoice->{invoiceid
}, ( $budget_id ?
$budget_id : $order->{budget_id
} ) );
1472 if ( defined $order->{unitprice
} ) {
1473 push @params, $order->{unitprice
}, $order->{unitprice_tax_included
}, $order->{unitprice_tax_excluded
};
1476 if ( defined $order->{tax_value_on_receiving
} ) {
1477 push @params, $order->{tax_value_on_receiving
};
1480 if ( defined $order->{tax_rate_on_receiving
} ) {
1481 push @params, $order->{tax_rate_on_receiving
};
1484 if ( defined $order->{order_internalnote
} ) {
1485 push @params, $order->{order_internalnote
};
1488 push @params, ( $biblionumber, $order->{ordernumber
} );
1490 $sth->execute( @params );
1492 # All items have been received, sent a notification to users
1493 NotifyOrderUsers
( $order->{ordernumber
} );
1496 return ($datereceived, $new_ordernumber);
1499 =head3 CancelReceipt
1501 my $parent_ordernumber = CancelReceipt($ordernumber);
1503 Cancel an order line receipt and update the parent order line, as if no
1505 If items are created at receipt (AcqCreateItem = receiving) then delete
1511 my $ordernumber = shift;
1513 return unless $ordernumber;
1515 my $dbh = C4
::Context
->dbh;
1517 SELECT datereceived
, parent_ordernumber
, quantity
1519 WHERE ordernumber
= ?
1521 my $sth = $dbh->prepare($query);
1522 $sth->execute($ordernumber);
1523 my $order = $sth->fetchrow_hashref;
1525 warn "CancelReceipt: order $ordernumber does not exist";
1528 unless($order->{'datereceived'}) {
1529 warn "CancelReceipt: order $ordernumber is not received";
1533 my $parent_ordernumber = $order->{'parent_ordernumber'};
1535 my @itemnumbers = GetItemnumbersFromOrder
( $ordernumber );
1537 if($parent_ordernumber == $ordernumber || not $parent_ordernumber) {
1538 # The order line has no parent, just mark it as not received
1541 SET quantityreceived
= ?
,
1544 orderstatus
= 'ordered'
1545 WHERE ordernumber
= ?
1547 $sth = $dbh->prepare($query);
1548 $sth->execute(0, undef, undef, $ordernumber);
1549 _cancel_items_receipt
( $ordernumber );
1551 # The order line has a parent, increase parent quantity and delete
1554 SELECT quantity
, datereceived
1556 WHERE ordernumber
= ?
1558 $sth = $dbh->prepare($query);
1559 $sth->execute($parent_ordernumber);
1560 my $parent_order = $sth->fetchrow_hashref;
1561 unless($parent_order) {
1562 warn "Parent order $parent_ordernumber does not exist.";
1565 if($parent_order->{'datereceived'}) {
1566 warn "CancelReceipt: parent order is received.".
1567 " Can't cancel receipt.";
1573 orderstatus
= 'ordered'
1574 WHERE ordernumber
= ?
1576 $sth = $dbh->prepare($query);
1577 my $rv = $sth->execute(
1578 $order->{'quantity'} + $parent_order->{'quantity'},
1582 warn "Cannot update parent order line, so do not cancel".
1587 # Recalculate tax_value
1591 tax_value_on_ordering
= quantity
* ecost_tax_excluded
* tax_rate_on_ordering
,
1592 tax_value_on_receiving
= quantity
* unitprice_tax_excluded
* tax_rate_on_receiving
1593 WHERE ordernumber
= ?
1594 |, undef, $parent_ordernumber);
1596 _cancel_items_receipt
( $ordernumber, $parent_ordernumber );
1599 DELETE FROM aqorders
1600 WHERE ordernumber
= ?
1602 $sth = $dbh->prepare($query);
1603 $sth->execute($ordernumber);
1607 if(C4
::Context
->preference('AcqCreateItem') eq 'ordering') {
1608 my @affects = split q{\|}, C4
::Context
->preference("AcqItemSetSubfieldsWhenReceiptIsCancelled");
1610 for my $in ( @itemnumbers ) {
1611 my $biblionumber = C4
::Biblio
::GetBiblionumberFromItemnumber
( $in );
1612 my $frameworkcode = GetFrameworkCode
($biblionumber);
1613 my ( $itemfield ) = GetMarcFromKohaField
( 'items.itemnumber', $frameworkcode );
1614 my $item = C4
::Items
::GetMarcItem
( $biblionumber, $in );
1615 for my $affect ( @affects ) {
1616 my ( $sf, $v ) = split q{=}, $affect, 2;
1617 foreach ( $item->field($itemfield) ) {
1618 $_->update( $sf => $v );
1621 C4
::Items
::ModItemFromMarc
( $item, $biblionumber, $in );
1626 return $parent_ordernumber;
1629 sub _cancel_items_receipt
{
1630 my ( $ordernumber, $parent_ordernumber ) = @_;
1631 $parent_ordernumber ||= $ordernumber;
1633 my @itemnumbers = GetItemnumbersFromOrder
($ordernumber);
1634 if(C4
::Context
->preference('AcqCreateItem') eq 'receiving') {
1635 # Remove items that were created at receipt
1637 DELETE FROM items
, aqorders_items
1638 USING items
, aqorders_items
1639 WHERE items
.itemnumber
= ? AND aqorders_items
.itemnumber
= ?
1641 my $dbh = C4
::Context
->dbh;
1642 my $sth = $dbh->prepare($query);
1643 foreach my $itemnumber (@itemnumbers) {
1644 $sth->execute($itemnumber, $itemnumber);
1648 foreach my $itemnumber (@itemnumbers) {
1649 ModItemOrder
($itemnumber, $parent_ordernumber);
1654 #------------------------------------------------------------#
1658 @results = &SearchOrders({
1659 ordernumber => $ordernumber,
1662 booksellerid => $booksellerid,
1663 basketno => $basketno,
1664 basketname => $basketname,
1665 basketgroupname => $basketgroupname,
1669 biblionumber => $biblionumber,
1670 budget_id => $budget_id
1673 Searches for orders filtered by criteria.
1675 C<$ordernumber> Finds matching orders or transferred orders by ordernumber.
1676 C<$search> Finds orders matching %$search% in title, author, or isbn.
1677 C<$owner> Finds order for the logged in user.
1678 C<$pending> Finds pending orders. Ignores completed and cancelled orders.
1679 C<$ordered> Finds orders to receive only (status 'ordered' or 'partial').
1682 C<@results> is an array of references-to-hash with the keys are fields
1683 from aqorders, biblio, biblioitems and aqbasket tables.
1688 my ( $params ) = @_;
1689 my $ordernumber = $params->{ordernumber
};
1690 my $search = $params->{search
};
1691 my $ean = $params->{ean
};
1692 my $booksellerid = $params->{booksellerid
};
1693 my $basketno = $params->{basketno
};
1694 my $basketname = $params->{basketname
};
1695 my $basketgroupname = $params->{basketgroupname
};
1696 my $owner = $params->{owner
};
1697 my $pending = $params->{pending
};
1698 my $ordered = $params->{ordered
};
1699 my $biblionumber = $params->{biblionumber
};
1700 my $budget_id = $params->{budget_id
};
1702 my $dbh = C4
::Context
->dbh;
1705 SELECT aqbasket.basketno,
1707 borrowers.firstname,
1710 biblioitems.biblioitemnumber,
1711 biblioitems.publishercode,
1712 biblioitems.publicationyear,
1713 aqbasket.authorisedby,
1714 aqbasket.booksellerid,
1716 aqbasket.creationdate,
1717 aqbasket.basketname,
1718 aqbasketgroups.id as basketgroupid,
1719 aqbasketgroups.name as basketgroupname,
1722 LEFT JOIN aqbasket ON aqorders.basketno = aqbasket.basketno
1723 LEFT JOIN aqbasketgroups ON aqbasket.basketgroupid = aqbasketgroups.id
1724 LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber
1725 LEFT JOIN biblio ON aqorders.biblionumber=biblio.biblionumber
1726 LEFT JOIN biblioitems ON biblioitems.biblionumber=biblio.biblionumber
1729 # If we search on ordernumber, we retrieve the transferred order if a transfer has been done.
1731 LEFT JOIN aqorders_transfers ON aqorders_transfers.ordernumber_to = aqorders.ordernumber
1735 WHERE (datecancellationprinted is NULL)
1738 if ( $pending or $ordered ) {
1741 ( aqbasket.is_standing AND aqorders.orderstatus IN ( "new", "ordered", "partial" ) )
1743 ( quantity > quantityreceived OR quantityreceived is NULL )
1747 $query .= q{ AND aqorders.orderstatus IN ( "ordered", "partial" )};
1755 my $userenv = C4
::Context
->userenv;
1756 if ( C4
::Context
->preference("IndependentBranches") ) {
1757 unless ( C4
::Context
->IsSuperLibrarian() ) {
1760 borrowers.branchcode = ?
1761 OR borrowers.branchcode = ''
1764 push @args, $userenv->{branch
};
1768 if ( $ordernumber ) {
1769 $query .= ' AND ( aqorders.ordernumber = ? OR aqorders_transfers.ordernumber_from = ? ) ';
1770 push @args, ( $ordernumber, $ordernumber );
1772 if ( $biblionumber ) {
1773 $query .= 'AND aqorders.biblionumber = ?';
1774 push @args, $biblionumber;
1777 $query .= ' AND (biblio.title LIKE ? OR biblio.author LIKE ? OR biblioitems.isbn LIKE ?)';
1778 push @args, ("%$search%","%$search%","%$search%");
1781 $query .= ' AND biblioitems.ean = ?';
1784 if ( $booksellerid ) {
1785 $query .= 'AND aqbasket.booksellerid = ?';
1786 push @args, $booksellerid;
1789 $query .= 'AND aqbasket.basketno = ?';
1790 push @args, $basketno;
1793 $query .= 'AND aqbasket.basketname LIKE ?';
1794 push @args, "%$basketname%";
1796 if( $basketgroupname ) {
1797 $query .= ' AND aqbasketgroups.name LIKE ?';
1798 push @args, "%$basketgroupname%";
1802 $query .= ' AND aqbasket.authorisedby=? ';
1803 push @args, $userenv->{'number'};
1807 $query .= ' AND aqorders.budget_id = ?';
1808 push @args, $budget_id;
1811 $query .= ' ORDER BY aqbasket.basketno';
1813 my $sth = $dbh->prepare($query);
1814 $sth->execute(@args);
1815 return $sth->fetchall_arrayref({});
1818 #------------------------------------------------------------#
1822 &DelOrder($biblionumber, $ordernumber);
1824 Cancel the order with the given order and biblio numbers. It does not
1825 delete any entries in the aqorders table, it merely marks them as
1831 my ( $bibnum, $ordernumber, $delete_biblio, $reason ) = @_;
1834 my $dbh = C4
::Context
->dbh;
1837 SET datecancellationprinted=now(), orderstatus='cancelled'
1840 $query .= ", cancellationreason = ? ";
1843 WHERE biblionumber=? AND ordernumber=?
1845 my $sth = $dbh->prepare($query);
1847 $sth->execute($reason, $bibnum, $ordernumber);
1849 $sth->execute( $bibnum, $ordernumber );
1853 my @itemnumbers = GetItemnumbersFromOrder
( $ordernumber );
1854 foreach my $itemnumber (@itemnumbers){
1855 my $delcheck = C4
::Items
::DelItemCheck
( $bibnum, $itemnumber );
1857 if($delcheck != 1) {
1858 $error->{'delitem'} = 1;
1862 if($delete_biblio) {
1863 # We get the number of remaining items
1864 my $biblio = Koha
::Biblios
->find( $bibnum );
1865 my $itemcount = $biblio->items->count;
1867 # If there are no items left,
1868 if ( $itemcount == 0 ) {
1869 # We delete the record
1870 my $delcheck = DelBiblio
($bibnum);
1873 $error->{'delbiblio'} = 1;
1881 =head3 TransferOrder
1883 my $newordernumber = TransferOrder($ordernumber, $basketno);
1885 Transfer an order line to a basket.
1886 Mark $ordernumber as cancelled with an internal note 'Cancelled and transferred
1887 to BOOKSELLER on DATE' and create new order with internal note
1888 'Transferred from BOOKSELLER on DATE'.
1889 Move all attached items to the new order.
1890 Received orders cannot be transferred.
1891 Return the ordernumber of created order.
1896 my ($ordernumber, $basketno) = @_;
1898 return unless ($ordernumber and $basketno);
1900 my $order = GetOrder
( $ordernumber );
1901 return if $order->{datereceived
};
1902 my $basket = GetBasket
($basketno);
1903 return unless $basket;
1905 my $dbh = C4
::Context
->dbh;
1906 my ($query, $sth, $rv);
1910 SET datecancellationprinted = CAST(NOW() AS date), orderstatus = ?
1911 WHERE ordernumber = ?
1913 $sth = $dbh->prepare($query);
1914 $rv = $sth->execute('cancelled', $ordernumber);
1916 delete $order->{'ordernumber'};
1917 delete $order->{parent_ordernumber
};
1918 $order->{'basketno'} = $basketno;
1920 my $newordernumber = Koha
::Acquisition
::Order
->new($order)->insert->{ordernumber
};
1923 UPDATE aqorders_items
1925 WHERE ordernumber = ?
1927 $sth = $dbh->prepare($query);
1928 $sth->execute($newordernumber, $ordernumber);
1931 INSERT INTO aqorders_transfers (ordernumber_from, ordernumber_to)
1934 $sth = $dbh->prepare($query);
1935 $sth->execute($ordernumber, $newordernumber);
1937 return $newordernumber;
1940 =head2 FUNCTIONS ABOUT PARCELS
1944 $results = &GetParcels($bookseller, $order, $code, $datefrom, $dateto);
1946 get a lists of parcels.
1953 is the bookseller this function has to get parcels.
1956 To know on what criteria the results list has to be ordered.
1959 is the booksellerinvoicenumber.
1961 =item $datefrom & $dateto
1962 to know on what date this function has to filter its search.
1967 a pointer on a hash list containing parcel informations as such :
1973 =item Last operation
1975 =item Number of biblio
1977 =item Number of items
1984 my ($bookseller,$order, $code, $datefrom, $dateto) = @_;
1985 my $dbh = C4
::Context
->dbh;
1986 my @query_params = ();
1988 SELECT aqinvoices.invoicenumber,
1989 datereceived,purchaseordernumber,
1990 count(DISTINCT biblionumber) AS biblio,
1991 sum(quantity) AS itemsexpected,
1992 sum(quantityreceived) AS itemsreceived
1993 FROM aqorders LEFT JOIN aqbasket ON aqbasket.basketno = aqorders.basketno
1994 LEFT JOIN aqinvoices ON aqorders.invoiceid = aqinvoices.invoiceid
1995 WHERE aqbasket.booksellerid = ? and datereceived IS NOT NULL
1997 push @query_params, $bookseller;
1999 if ( defined $code ) {
2000 $strsth .= ' and aqinvoices.invoicenumber like ? ';
2001 # add a % to the end of the code to allow stemming.
2002 push @query_params, "$code%";
2005 if ( defined $datefrom ) {
2006 $strsth .= ' and datereceived >= ? ';
2007 push @query_params, $datefrom;
2010 if ( defined $dateto ) {
2011 $strsth .= 'and datereceived <= ? ';
2012 push @query_params, $dateto;
2015 $strsth .= "group by aqinvoices.invoicenumber,datereceived ";
2017 # can't use a placeholder to place this column name.
2018 # but, we could probably be checking to make sure it is a column that will be fetched.
2019 $strsth .= "order by $order " if ($order);
2021 my $sth = $dbh->prepare($strsth);
2023 $sth->execute( @query_params );
2024 my $results = $sth->fetchall_arrayref({});
2028 #------------------------------------------------------------#
2030 =head3 GetLateOrders
2032 @results = &GetLateOrders;
2034 Searches for bookseller with late orders.
2037 the table of supplier with late issues. This table is full of hashref.
2043 my $supplierid = shift;
2045 my $estimateddeliverydatefrom = shift;
2046 my $estimateddeliverydateto = shift;
2048 my $dbh = C4
::Context
->dbh;
2050 #BEWARE, order of parenthesis and LEFT JOIN is important for speed
2051 my $dbdriver = C4
::Context
->config("db_scheme") || "mysql";
2053 my @query_params = ();
2055 SELECT aqbasket.basketno,
2056 aqorders.ordernumber,
2057 DATE(aqbasket.closedate) AS orderdate,
2058 aqbasket.basketname AS basketname,
2059 aqbasket.basketgroupid AS basketgroupid,
2060 aqbasketgroups.name AS basketgroupname,
2061 aqorders.rrp AS unitpricesupplier,
2062 aqorders.ecost AS unitpricelib,
2063 aqorders.claims_count AS claims_count,
2064 aqorders.claimed_date AS claimed_date,
2065 aqbudgets.budget_name AS budget,
2066 borrowers.branchcode AS branch,
2067 aqbooksellers.name AS supplier,
2068 aqbooksellers.id AS supplierid,
2069 biblio.author, biblio.title,
2070 biblioitems.publishercode AS publisher,
2071 biblioitems.publicationyear,
2072 ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) AS estimateddeliverydate,
2076 aqorders LEFT JOIN biblio ON biblio.biblionumber = aqorders.biblionumber
2077 LEFT JOIN biblioitems ON biblioitems.biblionumber = biblio.biblionumber
2078 LEFT JOIN aqbudgets ON aqorders.budget_id = aqbudgets.budget_id,
2079 aqbasket LEFT JOIN borrowers ON aqbasket.authorisedby = borrowers.borrowernumber
2080 LEFT JOIN aqbooksellers ON aqbasket.booksellerid = aqbooksellers.id
2081 LEFT JOIN aqbasketgroups ON aqbasket.basketgroupid = aqbasketgroups.id
2082 WHERE aqorders.basketno = aqbasket.basketno
2083 AND ( datereceived = ''
2084 OR datereceived IS NULL
2085 OR aqorders.quantityreceived < aqorders.quantity
2087 AND aqbasket.closedate IS NOT NULL
2088 AND (aqorders.datecancellationprinted IS NULL OR aqorders.datecancellationprinted='0000-00-00')
2091 if ($dbdriver eq "mysql") {
2093 aqorders.quantity - COALESCE(aqorders.quantityreceived,0) AS quantity,
2094 (aqorders.quantity - COALESCE(aqorders.quantityreceived,0)) * aqorders.rrp AS subtotal,
2095 DATEDIFF(CAST(now() AS date),closedate) AS latesince
2097 if ( defined $delay ) {
2098 $from .= " AND (closedate <= DATE_SUB(CAST(now() AS date),INTERVAL ? DAY)) " ;
2099 push @query_params, $delay;
2101 $having = "HAVING quantity <> 0";
2103 # FIXME: account for IFNULL as above
2105 aqorders.quantity AS quantity,
2106 aqorders.quantity * aqorders.rrp AS subtotal,
2107 (CAST(now() AS date) - closedate) AS latesince
2109 if ( defined $delay ) {
2110 $from .= " AND (closedate <= (CAST(now() AS date) -(INTERVAL ? DAY)) ";
2111 push @query_params, $delay;
2114 if (defined $supplierid) {
2115 $from .= ' AND aqbasket.booksellerid = ? ';
2116 push @query_params, $supplierid;
2118 if (defined $branch) {
2119 $from .= ' AND borrowers.branchcode LIKE ? ';
2120 push @query_params, $branch;
2123 if ( defined $estimateddeliverydatefrom or defined $estimateddeliverydateto ) {
2124 $from .= ' AND aqbooksellers.deliverytime IS NOT NULL ';
2126 if ( defined $estimateddeliverydatefrom ) {
2127 $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) >= ?';
2128 push @query_params, $estimateddeliverydatefrom;
2130 if ( defined $estimateddeliverydateto ) {
2131 $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) <= ?';
2132 push @query_params, $estimateddeliverydateto;
2134 if ( defined $estimateddeliverydatefrom and not defined $estimateddeliverydateto ) {
2135 $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) <= CAST(now() AS date)';
2137 if (C4
::Context
->preference("IndependentBranches")
2138 && !C4
::Context
->IsSuperLibrarian() ) {
2139 $from .= ' AND borrowers.branchcode LIKE ? ';
2140 push @query_params, C4
::Context
->userenv->{branch
};
2142 $from .= " AND orderstatus <> 'cancelled' ";
2143 my $query = "$select $from $having\nORDER BY latesince, basketno, borrowers.branchcode, supplier";
2144 $debug and print STDERR
"GetLateOrders query: $query\nGetLateOrders args: " . join(" ",@query_params);
2145 my $sth = $dbh->prepare($query);
2146 $sth->execute(@query_params);
2148 while (my $data = $sth->fetchrow_hashref) {
2149 push @results, $data;
2154 #------------------------------------------------------------#
2158 \@order_loop = GetHistory( %params );
2160 Retreives some acquisition history information
2170 basket - search both basket name and number
2171 booksellerinvoicenumber
2174 orderstatus (note that orderstatus '' will retrieve orders
2175 of any status except cancelled)
2177 get_canceled_order (if set to a true value, cancelled orders will
2181 $order_loop is a list of hashrefs that each look like this:
2183 'author' => 'Twain, Mark',
2185 'biblionumber' => '215',
2187 'creationdate' => 'MM/DD/YYYY',
2188 'datereceived' => undef,
2191 'invoicenumber' => undef,
2193 'ordernumber' => '1',
2195 'quantityreceived' => undef,
2196 'title' => 'The Adventures of Huckleberry Finn'
2202 # don't run the query if there are no parameters (list would be too long for sure !)
2203 croak
"No search params" unless @_;
2205 my $title = $params{title
};
2206 my $author = $params{author
};
2207 my $isbn = $params{isbn
};
2208 my $ean = $params{ean
};
2209 my $name = $params{name
};
2210 my $from_placed_on = $params{from_placed_on
};
2211 my $to_placed_on = $params{to_placed_on
};
2212 my $basket = $params{basket
};
2213 my $booksellerinvoicenumber = $params{booksellerinvoicenumber
};
2214 my $basketgroupname = $params{basketgroupname
};
2215 my $budget = $params{budget
};
2216 my $orderstatus = $params{orderstatus
};
2217 my $biblionumber = $params{biblionumber
};
2218 my $get_canceled_order = $params{get_canceled_order
} || 0;
2219 my $ordernumber = $params{ordernumber
};
2220 my $search_children_too = $params{search_children_too
} || 0;
2221 my $created_by = $params{created_by
} || [];
2225 my $total_qtyreceived = 0;
2226 my $total_price = 0;
2228 my $dbh = C4
::Context
->dbh;
2231 COALESCE(biblio.title, deletedbiblio.title) AS title,
2232 COALESCE(biblio.author, deletedbiblio.author) AS author,
2233 COALESCE(biblioitems.isbn, deletedbiblioitems.isbn) AS isbn,
2234 COALESCE(biblioitems.ean, deletedbiblioitems.ean) AS ean,
2236 aqbasket.basketname,
2237 aqbasket.basketgroupid,
2238 aqbasket.authorisedby,
2239 concat( borrowers.firstname,' ',borrowers.surname) AS authorisedbyname,
2240 aqbasketgroups.name as groupname,
2242 aqbasket.creationdate,
2243 aqorders.datereceived,
2245 aqorders.quantityreceived,
2247 aqorders.ordernumber,
2249 aqinvoices.invoicenumber,
2250 aqbooksellers.id as id,
2251 aqorders.biblionumber,
2252 aqorders.orderstatus,
2253 aqorders.parent_ordernumber,
2254 aqbudgets.budget_name
2256 $query .= ", aqbudgets.budget_id AS budget" if defined $budget;
2259 LEFT JOIN aqbasket ON aqorders.basketno=aqbasket.basketno
2260 LEFT JOIN aqbasketgroups ON aqbasket.basketgroupid=aqbasketgroups.id
2261 LEFT JOIN aqbooksellers ON aqbasket.booksellerid=aqbooksellers.id
2262 LEFT JOIN biblioitems ON biblioitems.biblionumber=aqorders.biblionumber
2263 LEFT JOIN biblio ON biblio.biblionumber=aqorders.biblionumber
2264 LEFT JOIN aqbudgets ON aqorders.budget_id=aqbudgets.budget_id
2265 LEFT JOIN aqinvoices ON aqorders.invoiceid = aqinvoices.invoiceid
2266 LEFT JOIN deletedbiblio ON deletedbiblio.biblionumber=aqorders.biblionumber
2267 LEFT JOIN deletedbiblioitems ON deletedbiblioitems.biblionumber=aqorders.biblionumber
2268 LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber
2271 $query .= " WHERE 1 ";
2273 unless ($get_canceled_order or (defined $orderstatus and $orderstatus eq 'cancelled')) {
2274 $query .= " AND (datecancellationprinted is NULL or datecancellationprinted='0000-00-00') ";
2277 my @query_params = ();
2279 if ( $biblionumber ) {
2280 $query .= " AND biblio.biblionumber = ?";
2281 push @query_params, $biblionumber;
2285 $query .= " AND biblio.title LIKE ? ";
2286 $title =~ s/\s+/%/g;
2287 push @query_params, "%$title%";
2291 $query .= " AND biblio.author LIKE ? ";
2292 push @query_params, "%$author%";
2296 $query .= " AND biblioitems.isbn LIKE ? ";
2297 push @query_params, "%$isbn%";
2300 $query .= " AND biblioitems.ean = ? ";
2301 push @query_params, "$ean";
2304 $query .= " AND aqbooksellers.name LIKE ? ";
2305 push @query_params, "%$name%";
2309 $query .= " AND aqbudgets.budget_id = ? ";
2310 push @query_params, "$budget";
2313 if ( $from_placed_on ) {
2314 $query .= " AND creationdate >= ? ";
2315 push @query_params, $from_placed_on;
2318 if ( $to_placed_on ) {
2319 $query .= " AND creationdate <= ? ";
2320 push @query_params, $to_placed_on;
2323 if ( defined $orderstatus and $orderstatus ne '') {
2324 $query .= " AND aqorders.orderstatus = ? ";
2325 push @query_params, "$orderstatus";
2329 if ($basket =~ m/^\d+$/) {
2330 $query .= " AND aqorders.basketno = ? ";
2331 push @query_params, $basket;
2333 $query .= " AND aqbasket.basketname LIKE ? ";
2334 push @query_params, "%$basket%";
2338 if ($booksellerinvoicenumber) {
2339 $query .= " AND aqinvoices.invoicenumber LIKE ? ";
2340 push @query_params, "%$booksellerinvoicenumber%";
2343 if ($basketgroupname) {
2344 $query .= " AND aqbasketgroups.name LIKE ? ";
2345 push @query_params, "%$basketgroupname%";
2349 $query .= " AND (aqorders.ordernumber = ? ";
2350 push @query_params, $ordernumber;
2351 if ($search_children_too) {
2352 $query .= " OR aqorders.parent_ordernumber = ? ";
2353 push @query_params, $ordernumber;
2358 if ( @
$created_by ) {
2359 $query .= ' AND aqbasket.authorisedby IN ( ' . join( ',', ('?') x @
$created_by ) . ')';
2360 push @query_params, @
$created_by;
2364 if ( C4
::Context
->preference("IndependentBranches") ) {
2365 unless ( C4
::Context
->IsSuperLibrarian() ) {
2366 $query .= " AND (borrowers.branchcode = ? OR borrowers.branchcode ='' ) ";
2367 push @query_params, C4
::Context
->userenv->{branch
};
2370 $query .= " ORDER BY id";
2372 return $dbh->selectall_arrayref( $query, { Slice
=> {} }, @query_params );
2375 =head2 GetRecentAcqui
2377 $results = GetRecentAcqui($days);
2379 C<$results> is a ref to a table which containts hashref
2383 sub GetRecentAcqui
{
2385 my $dbh = C4
::Context
->dbh;
2389 ORDER BY timestamp DESC
2392 my $sth = $dbh->prepare($query);
2394 my $results = $sth->fetchall_arrayref({});
2398 #------------------------------------------------------------#
2402 &AddClaim($ordernumber);
2404 Add a claim for an order
2409 my ($ordernumber) = @_;
2410 my $dbh = C4
::Context
->dbh;
2413 claims_count = claims_count + 1,
2414 claimed_date = CURDATE()
2415 WHERE ordernumber = ?
2417 my $sth = $dbh->prepare($query);
2418 $sth->execute($ordernumber);
2423 my @invoices = GetInvoices(
2424 invoicenumber => $invoicenumber,
2425 supplierid => $supplierid,
2426 suppliername => $suppliername,
2427 shipmentdatefrom => $shipmentdatefrom, # ISO format
2428 shipmentdateto => $shipmentdateto, # ISO format
2429 billingdatefrom => $billingdatefrom, # ISO format
2430 billingdateto => $billingdateto, # ISO format
2431 isbneanissn => $isbn_or_ean_or_issn,
2434 publisher => $publisher,
2435 publicationyear => $publicationyear,
2436 branchcode => $branchcode,
2437 order_by => $order_by
2440 Return a list of invoices that match all given criteria.
2442 $order_by is "column_name (asc|desc)", where column_name is any of
2443 'invoicenumber', 'booksellerid', 'shipmentdate', 'billingdate', 'closedate',
2444 'shipmentcost', 'shipmentcost_budgetid'.
2446 asc is the default if omitted
2453 my @columns = qw(invoicenumber booksellerid shipmentdate billingdate
2454 closedate shipmentcost shipmentcost_budgetid);
2456 my $dbh = C4
::Context
->dbh;
2458 SELECT aqinvoices
.*, aqbooksellers
.name AS suppliername
,
2461 aqorders
.datereceived IS NOT NULL
,
2462 aqorders
.biblionumber
,
2465 ) AS receivedbiblios
,
2468 aqorders
.subscriptionid IS NOT NULL
,
2469 aqorders
.subscriptionid
,
2472 ) AS is_linked_to_subscriptions
,
2473 SUM
(aqorders
.quantityreceived
) AS receiveditems
2475 LEFT JOIN aqbooksellers ON aqbooksellers
.id
= aqinvoices
.booksellerid
2476 LEFT JOIN aqorders ON aqorders
.invoiceid
= aqinvoices
.invoiceid
2477 LEFT JOIN aqbasket ON aqbasket
.basketno
=aqorders
.basketno
2478 LEFT JOIN borrowers ON aqbasket
.authorisedby
=borrowers
.borrowernumber
2479 LEFT JOIN biblio ON aqorders
.biblionumber
= biblio
.biblionumber
2480 LEFT JOIN biblioitems ON biblio
.biblionumber
= biblioitems
.biblionumber
2481 LEFT JOIN subscription ON biblio
.biblionumber
= subscription
.biblionumber
2486 if($args{supplierid
}) {
2487 push @bind_strs, " aqinvoices.booksellerid = ? ";
2488 push @bind_args, $args{supplierid
};
2490 if($args{invoicenumber
}) {
2491 push @bind_strs, " aqinvoices.invoicenumber LIKE ? ";
2492 push @bind_args, "%$args{invoicenumber}%";
2494 if($args{suppliername
}) {
2495 push @bind_strs, " aqbooksellers.name LIKE ? ";
2496 push @bind_args, "%$args{suppliername}%";
2498 if($args{shipmentdatefrom
}) {
2499 push @bind_strs, " aqinvoices.shipmentdate >= ? ";
2500 push @bind_args, $args{shipmentdatefrom
};
2502 if($args{shipmentdateto
}) {
2503 push @bind_strs, " aqinvoices.shipmentdate <= ? ";
2504 push @bind_args, $args{shipmentdateto
};
2506 if($args{billingdatefrom
}) {
2507 push @bind_strs, " aqinvoices.billingdate >= ? ";
2508 push @bind_args, $args{billingdatefrom
};
2510 if($args{billingdateto
}) {
2511 push @bind_strs, " aqinvoices.billingdate <= ? ";
2512 push @bind_args, $args{billingdateto
};
2514 if($args{isbneanissn
}) {
2515 push @bind_strs, " (biblioitems.isbn LIKE CONCAT('%', ?, '%') OR biblioitems.ean LIKE CONCAT('%', ?, '%') OR biblioitems.issn LIKE CONCAT('%', ?, '%') ) ";
2516 push @bind_args, $args{isbneanissn
}, $args{isbneanissn
}, $args{isbneanissn
};
2519 push @bind_strs, " biblio.title LIKE CONCAT('%', ?, '%') ";
2520 push @bind_args, $args{title
};
2523 push @bind_strs, " biblio.author LIKE CONCAT('%', ?, '%') ";
2524 push @bind_args, $args{author
};
2526 if($args{publisher
}) {
2527 push @bind_strs, " biblioitems.publishercode LIKE CONCAT('%', ?, '%') ";
2528 push @bind_args, $args{publisher
};
2530 if($args{publicationyear
}) {
2531 push @bind_strs, " ((biblioitems.publicationyear LIKE CONCAT('%', ?, '%')) OR (biblio.copyrightdate LIKE CONCAT('%', ?, '%'))) ";
2532 push @bind_args, $args{publicationyear
}, $args{publicationyear
};
2534 if($args{branchcode
}) {
2535 push @bind_strs, " borrowers.branchcode = ? ";
2536 push @bind_args, $args{branchcode
};
2538 if($args{message_id
}) {
2539 push @bind_strs, " aqinvoices.message_id = ? ";
2540 push @bind_args, $args{message_id
};
2543 $query .= " WHERE " . join(" AND ", @bind_strs) if @bind_strs;
2544 $query .= " GROUP BY aqinvoices.invoiceid ";
2546 if($args{order_by
}) {
2547 my ($column, $direction) = split / /, $args{order_by
};
2548 if(grep /^$column$/, @columns) {
2549 $direction ||= 'ASC';
2550 $query .= " ORDER BY $column $direction";
2554 my $sth = $dbh->prepare($query);
2555 $sth->execute(@bind_args);
2557 my $results = $sth->fetchall_arrayref({});
2563 my $invoice = GetInvoice($invoiceid);
2565 Get informations about invoice with given $invoiceid
2567 Return a hash filled with aqinvoices.* fields
2572 my ($invoiceid) = @_;
2575 return unless $invoiceid;
2577 my $dbh = C4
::Context
->dbh;
2583 my $sth = $dbh->prepare($query);
2584 $sth->execute($invoiceid);
2586 $invoice = $sth->fetchrow_hashref;
2590 =head3 GetInvoiceDetails
2592 my $invoice = GetInvoiceDetails($invoiceid)
2594 Return informations about an invoice + the list of related order lines
2596 Orders informations are in $invoice->{orders} (array ref)
2600 sub GetInvoiceDetails
{
2601 my ($invoiceid) = @_;
2603 if ( !defined $invoiceid ) {
2604 carp
'GetInvoiceDetails called without an invoiceid';
2608 my $dbh = C4
::Context
->dbh;
2610 SELECT aqinvoices.*, aqbooksellers.name AS suppliername
2612 LEFT JOIN aqbooksellers ON aqinvoices.booksellerid = aqbooksellers.id
2615 my $sth = $dbh->prepare($query);
2616 $sth->execute($invoiceid);
2618 my $invoice = $sth->fetchrow_hashref;
2623 biblio.copyrightdate,
2625 biblioitems.publishercode,
2626 biblioitems.publicationyear,
2627 aqbasket.basketname,
2628 aqbasketgroups.id AS basketgroupid,
2629 aqbasketgroups.name AS basketgroupname
2631 LEFT JOIN aqbasket ON aqorders.basketno = aqbasket.basketno
2632 LEFT JOIN aqbasketgroups ON aqbasket.basketgroupid = aqbasketgroups.id
2633 LEFT JOIN biblio ON aqorders.biblionumber = biblio.biblionumber
2634 LEFT JOIN biblioitems ON aqorders.biblionumber = biblioitems.biblionumber
2637 $sth = $dbh->prepare($query);
2638 $sth->execute($invoiceid);
2639 $invoice->{orders
} = $sth->fetchall_arrayref({});
2640 $invoice->{orders
} ||= []; # force an empty arrayref if fetchall_arrayref fails
2647 my $invoiceid = AddInvoice(
2648 invoicenumber => $invoicenumber,
2649 booksellerid => $booksellerid,
2650 shipmentdate => $shipmentdate,
2651 billingdate => $billingdate,
2652 closedate => $closedate,
2653 shipmentcost => $shipmentcost,
2654 shipmentcost_budgetid => $shipmentcost_budgetid
2657 Create a new invoice and return its id or undef if it fails.
2664 return unless(%invoice and $invoice{invoicenumber
});
2666 my @columns = qw(invoicenumber booksellerid shipmentdate billingdate
2667 closedate shipmentcost shipmentcost_budgetid message_id);
2671 foreach my $key (keys %invoice) {
2672 if(0 < grep(/^$key$/, @columns)) {
2673 push @set_strs, "$key = ?";
2674 push @set_args, ($invoice{$key} || undef);
2680 my $dbh = C4
::Context
->dbh;
2681 my $query = "INSERT INTO aqinvoices SET ";
2682 $query .= join (",", @set_strs);
2683 my $sth = $dbh->prepare($query);
2684 $rv = $sth->execute(@set_args);
2686 $rv = $dbh->last_insert_id(undef, undef, 'aqinvoices', undef);
2695 invoiceid => $invoiceid, # Mandatory
2696 invoicenumber => $invoicenumber,
2697 booksellerid => $booksellerid,
2698 shipmentdate => $shipmentdate,
2699 billingdate => $billingdate,
2700 closedate => $closedate,
2701 shipmentcost => $shipmentcost,
2702 shipmentcost_budgetid => $shipmentcost_budgetid
2705 Modify an invoice, invoiceid is mandatory.
2707 Return undef if it fails.
2714 return unless(%invoice and $invoice{invoiceid
});
2716 my @columns = qw(invoicenumber booksellerid shipmentdate billingdate
2717 closedate shipmentcost shipmentcost_budgetid);
2721 foreach my $key (keys %invoice) {
2722 if(0 < grep(/^$key$/, @columns)) {
2723 push @set_strs, "$key = ?";
2724 push @set_args, ($invoice{$key} || undef);
2728 my $dbh = C4
::Context
->dbh;
2729 my $query = "UPDATE aqinvoices SET ";
2730 $query .= join(",", @set_strs);
2731 $query .= " WHERE invoiceid = ?";
2733 my $sth = $dbh->prepare($query);
2734 $sth->execute(@set_args, $invoice{invoiceid
});
2739 CloseInvoice($invoiceid);
2743 Equivalent to ModInvoice(invoiceid => $invoiceid, closedate => undef);
2748 my ($invoiceid) = @_;
2750 return unless $invoiceid;
2752 my $dbh = C4
::Context
->dbh;
2755 SET closedate
= CAST
(NOW
() AS DATE
)
2758 my $sth = $dbh->prepare($query);
2759 $sth->execute($invoiceid);
2762 =head3 ReopenInvoice
2764 ReopenInvoice($invoiceid);
2768 Equivalent to ModInvoice(invoiceid => $invoiceid, closedate => output_pref({ dt=>dt_from_string, dateonly=>1, otputpref=>'iso' }))
2773 my ($invoiceid) = @_;
2775 return unless $invoiceid;
2777 my $dbh = C4
::Context
->dbh;
2780 SET closedate
= NULL
2783 my $sth = $dbh->prepare($query);
2784 $sth->execute($invoiceid);
2789 DelInvoice($invoiceid);
2791 Delete an invoice if there are no items attached to it.
2796 my ($invoiceid) = @_;
2798 return unless $invoiceid;
2800 my $dbh = C4
::Context
->dbh;
2806 my $sth = $dbh->prepare($query);
2807 $sth->execute($invoiceid);
2808 my $res = $sth->fetchrow_arrayref;
2809 if ( $res && $res->[0] == 0 ) {
2811 DELETE FROM aqinvoices
2814 my $sth = $dbh->prepare($query);
2815 return ( $sth->execute($invoiceid) > 0 );
2820 =head3 MergeInvoices
2822 MergeInvoices($invoiceid, \@sourceids);
2824 Merge the invoices identified by the IDs in \@sourceids into
2825 the invoice identified by $invoiceid.
2830 my ($invoiceid, $sourceids) = @_;
2832 return unless $invoiceid;
2833 foreach my $sourceid (@
$sourceids) {
2834 next if $sourceid == $invoiceid;
2835 my $source = GetInvoiceDetails
($sourceid);
2836 foreach my $order (@
{$source->{'orders'}}) {
2837 $order->{'invoiceid'} = $invoiceid;
2840 DelInvoice
($source->{'invoiceid'});
2845 =head3 GetBiblioCountByBasketno
2847 $biblio_count = &GetBiblioCountByBasketno($basketno);
2849 Looks up the biblio's count that has basketno value $basketno
2855 sub GetBiblioCountByBasketno
{
2856 my ($basketno) = @_;
2857 my $dbh = C4
::Context
->dbh;
2859 SELECT COUNT( DISTINCT( biblionumber ) )
2862 AND (datecancellationprinted IS NULL OR datecancellationprinted='0000-00-00')
2865 my $sth = $dbh->prepare($query);
2866 $sth->execute($basketno);
2867 return $sth->fetchrow;
2870 # Note this subroutine should be moved to Koha::Acquisition::Order
2871 # Will do when a DBIC decision will be taken.
2872 sub populate_order_with_prices
{
2875 my $order = $params->{order
};
2876 my $booksellerid = $params->{booksellerid
};
2877 return unless $booksellerid;
2879 my $bookseller = Koha
::Acquisition
::Booksellers
->find( $booksellerid );
2881 my $receiving = $params->{receiving
};
2882 my $ordering = $params->{ordering
};
2883 my $discount = $order->{discount
};
2884 $discount /= 100 if $discount > 1;
2887 $order->{tax_rate_on_ordering
} //= $order->{tax_rate
};
2888 if ( $bookseller->listincgst ) {
2889 # The user entered the rrp tax included
2890 $order->{rrp_tax_included
} = $order->{rrp
};
2892 # rrp tax excluded = rrp tax included / ( 1 + tax rate )
2893 $order->{rrp_tax_excluded
} = $order->{rrp_tax_included
} / ( 1 + $order->{tax_rate_on_ordering
} );
2895 # ecost tax excluded = rrp tax excluded * ( 1 - discount )
2896 $order->{ecost_tax_excluded
} = $order->{rrp_tax_excluded
} * ( 1 - $discount );
2898 # ecost tax included = rrp tax included ( 1 - discount )
2899 $order->{ecost_tax_included
} = $order->{rrp_tax_included
} * ( 1 - $discount );
2902 # The user entered the rrp tax excluded
2903 $order->{rrp_tax_excluded
} = $order->{rrp
};
2905 # rrp tax included = rrp tax excluded * ( 1 - tax rate )
2906 $order->{rrp_tax_included
} = $order->{rrp_tax_excluded
} * ( 1 + $order->{tax_rate_on_ordering
} );
2908 # ecost tax excluded = rrp tax excluded * ( 1 - discount )
2909 $order->{ecost_tax_excluded
} = $order->{rrp_tax_excluded
} * ( 1 - $discount );
2911 # ecost tax included = rrp tax excluded * ( 1 + tax rate ) * ( 1 - discount )
2912 $order->{ecost_tax_included
} =
2913 $order->{rrp_tax_excluded
} *
2914 ( 1 + $order->{tax_rate_on_ordering
} ) *
2918 # tax value = quantity * ecost tax excluded * tax rate
2919 $order->{tax_value_on_ordering
} =
2920 $order->{quantity
} * $order->{ecost_tax_excluded
} * $order->{tax_rate_on_ordering
};
2924 $order->{tax_rate_on_receiving
} //= $order->{tax_rate
};
2925 if ( $bookseller->invoiceincgst ) {
2926 # Trick for unitprice. If the unit price rounded value is the same as the ecost rounded value
2927 # we need to keep the exact ecost value
2928 if ( Koha
::Number
::Price
->new( $order->{unitprice
} )->round == Koha
::Number
::Price
->new( $order->{ecost_tax_included
} )->round ) {
2929 $order->{unitprice
} = $order->{ecost_tax_included
};
2932 # The user entered the unit price tax included
2933 $order->{unitprice_tax_included
} = $order->{unitprice
};
2935 # unit price tax excluded = unit price tax included / ( 1 + tax rate )
2936 $order->{unitprice_tax_excluded
} = $order->{unitprice_tax_included
} / ( 1 + $order->{tax_rate_on_receiving
} );
2939 # Trick for unitprice. If the unit price rounded value is the same as the ecost rounded value
2940 # we need to keep the exact ecost value
2941 if ( Koha
::Number
::Price
->new( $order->{unitprice
} )->round == Koha
::Number
::Price
->new( $order->{ecost_tax_excluded
} )->round ) {
2942 $order->{unitprice
} = $order->{ecost_tax_excluded
};
2945 # The user entered the unit price tax excluded
2946 $order->{unitprice_tax_excluded
} = $order->{unitprice
};
2949 # unit price tax included = unit price tax included * ( 1 + tax rate )
2950 $order->{unitprice_tax_included
} = $order->{unitprice_tax_excluded
} * ( 1 + $order->{tax_rate_on_receiving
} );
2953 # tax value = quantity * unit price tax excluded * tax rate
2954 $order->{tax_value_on_receiving
} = $order->{quantity
} * $order->{unitprice_tax_excluded
} * $order->{tax_rate_on_receiving
};
2960 =head3 GetOrderUsers
2962 $order_users_ids = &GetOrderUsers($ordernumber);
2964 Returns a list of all borrowernumbers that are in order users list
2969 my ($ordernumber) = @_;
2971 return unless $ordernumber;
2974 SELECT borrowernumber
2976 WHERE ordernumber
= ?
2978 my $dbh = C4
::Context
->dbh;
2979 my $sth = $dbh->prepare($query);
2980 $sth->execute($ordernumber);
2981 my $results = $sth->fetchall_arrayref( {} );
2983 my @borrowernumbers;
2984 foreach (@
$results) {
2985 push @borrowernumbers, $_->{'borrowernumber'};
2988 return @borrowernumbers;
2991 =head3 ModOrderUsers
2993 my @order_users_ids = (1, 2, 3);
2994 &ModOrderUsers($ordernumber, @basketusers_ids);
2996 Delete all users from order users list, and add users in C<@order_users_ids>
3002 my ( $ordernumber, @order_users_ids ) = @_;
3004 return unless $ordernumber;
3006 my $dbh = C4
::Context
->dbh;
3008 DELETE FROM aqorder_users
3009 WHERE ordernumber
= ?
3011 my $sth = $dbh->prepare($query);
3012 $sth->execute($ordernumber);
3015 INSERT INTO aqorder_users
(ordernumber
, borrowernumber
)
3018 $sth = $dbh->prepare($query);
3019 foreach my $order_user_id (@order_users_ids) {
3020 $sth->execute( $ordernumber, $order_user_id );
3024 sub NotifyOrderUsers
{
3025 my ($ordernumber) = @_;
3027 my @borrowernumbers = GetOrderUsers
($ordernumber);
3028 return unless @borrowernumbers;
3030 my $order = GetOrder
( $ordernumber );
3031 for my $borrowernumber (@borrowernumbers) {
3032 my $borrower = C4
::Members
::GetMember
( borrowernumber
=> $borrowernumber );
3033 my $library = Koha
::Libraries
->find( $borrower->{branchcode
} )->unblessed;
3034 my $biblio = C4
::Biblio
::GetBiblio
( $order->{biblionumber
} );
3035 my $letter = C4
::Letters
::GetPreparedLetter
(
3036 module
=> 'acquisition',
3037 letter_code
=> 'ACQ_NOTIF_ON_RECEIV',
3038 branchcode
=> $library->{branchcode
},
3039 lang
=> $borrower->{lang
},
3041 'branches' => $library,
3042 'borrowers' => $borrower,
3043 'biblio' => $biblio,
3044 'aqorders' => $order,
3048 C4
::Letters
::EnqueueLetter
(
3051 borrowernumber
=> $borrowernumber,
3052 LibraryName
=> C4
::Context
->preference("LibraryName"),
3053 message_transport_type
=> 'email',
3055 ) or warn "can't enqueue letter $letter";
3060 =head3 FillWithDefaultValues
3062 FillWithDefaultValues( $marc_record );
3064 This will update the record with default value defined in the ACQ framework.
3065 For all existing fields, if a default value exists and there are no subfield, it will be created.
3066 If the field does not exist, it will be created too.
3070 sub FillWithDefaultValues
{
3072 my $tagslib = C4
::Biblio
::GetMarcStructure
( 1, 'ACQ', { unsafe
=> 1 } );
3075 C4
::Biblio
::GetMarcFromKohaField
( 'items.itemnumber', '' );
3076 for my $tag ( sort keys %$tagslib ) {
3078 next if $tag == $itemfield;
3079 for my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
3080 next if IsMarcStructureInternal
($tagslib->{$tag}{$subfield});
3081 my $defaultvalue = $tagslib->{$tag}{$subfield}{defaultvalue
};
3082 if ( defined $defaultvalue and $defaultvalue ne '' ) {
3083 my @fields = $record->field($tag);
3085 for my $field (@fields) {
3086 unless ( defined $field->subfield($subfield) ) {
3087 $field->add_subfields(
3088 $subfield => $defaultvalue );
3093 $record->insert_fields_ordered(
3095 $tag, '', '', $subfield => $defaultvalue
3110 Koha Development Team <http://koha-community.org/>