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
;
35 use Koha
::Number
::Price
;
37 use Koha
::CsvProfiles
;
47 use vars
qw(@ISA @EXPORT);
53 &GetBasket &NewBasket &CloseBasket &ReopenBasket &DelBasket &ModBasket
54 &GetBasketAsCSV &GetBasketGroupAsCSV
55 &GetBasketsByBookseller &GetBasketsByBasketgroup
56 &GetBasketsInfosByBookseller
58 &GetBasketUsers &ModBasketUsers
63 &ModBasketgroup &NewBasketgroup &DelBasketgroup &GetBasketgroup &CloseBasketgroup
64 &GetBasketgroups &ReOpenBasketgroup
66 &DelOrder &ModOrder &GetOrder &GetOrders &GetOrdersByBiblionumber
67 &GetLateOrders &GetOrderFromItemnumber
68 &SearchOrders &GetHistory &GetRecentAcqui
69 &ModReceiveOrder &CancelReceipt
71 &GetLastOrderNotReceivedFromSubscriptionid &GetLastOrderReceivedFromSubscriptionid
86 &GetItemnumbersFromOrder
89 &GetBiblioCountByBasketno
95 &FillWithDefaultValues
103 sub GetOrderFromItemnumber
{
104 my ($itemnumber) = @_;
105 my $dbh = C4
::Context
->dbh;
108 SELECT
* from aqorders LEFT JOIN aqorders_items
109 ON
( aqorders
.ordernumber
= aqorders_items
.ordernumber
)
110 WHERE itemnumber
= ?
|;
112 my $sth = $dbh->prepare($query);
116 $sth->execute($itemnumber);
118 my $order = $sth->fetchrow_hashref;
123 # Returns the itemnumber(s) associated with the ordernumber given in parameter
124 sub GetItemnumbersFromOrder
{
125 my ($ordernumber) = @_;
126 my $dbh = C4
::Context
->dbh;
127 my $query = "SELECT itemnumber FROM aqorders_items WHERE ordernumber=?";
128 my $sth = $dbh->prepare($query);
129 $sth->execute($ordernumber);
132 while (my $order = $sth->fetchrow_hashref) {
133 push @tab, $order->{'itemnumber'};
147 C4::Acquisition - Koha functions for dealing with orders and acquisitions
155 The functions in this module deal with acquisitions, managing book
156 orders, basket and parcels.
160 =head2 FUNCTIONS ABOUT BASKETS
164 $aqbasket = &GetBasket($basketnumber);
166 get all basket informations in aqbasket for a given basket
168 B<returns:> informations for a given basket returned as a hashref.
174 my $dbh = C4
::Context
->dbh;
177 concat( b.firstname,' ',b.surname) AS authorisedbyname
179 LEFT JOIN borrowers b ON aqbasket.authorisedby=b.borrowernumber
182 my $sth=$dbh->prepare($query);
183 $sth->execute($basketno);
184 my $basket = $sth->fetchrow_hashref;
188 #------------------------------------------------------------#
192 $basket = &NewBasket( $booksellerid, $authorizedby, $basketname,
193 $basketnote, $basketbooksellernote, $basketcontractnumber, $deliveryplace, $billingplace, $is_standing );
195 Create a new basket in aqbasket table
199 =item C<$booksellerid> is a foreign key in the aqbasket table
201 =item C<$authorizedby> is the username of who created the basket
205 The other parameters are optional, see ModBasketHeader for more info on them.
210 my ( $booksellerid, $authorisedby, $basketname, $basketnote,
211 $basketbooksellernote, $basketcontractnumber, $deliveryplace,
212 $billingplace, $is_standing ) = @_;
213 my $dbh = C4
::Context
->dbh;
215 'INSERT INTO aqbasket (creationdate,booksellerid,authorisedby) '
216 . 'VALUES (now(),?,?)';
217 $dbh->do( $query, {}, $booksellerid, $authorisedby );
219 my $basket = $dbh->{mysql_insertid
};
220 $basketname ||= q{}; # default to empty strings
222 $basketbooksellernote ||= q{};
223 ModBasketHeader
( $basket, $basketname, $basketnote, $basketbooksellernote,
224 $basketcontractnumber, $booksellerid, $deliveryplace, $billingplace, $is_standing );
228 #------------------------------------------------------------#
232 &CloseBasket($basketno);
234 close a basket (becomes unmodifiable, except for receives)
240 my $dbh = C4
::Context
->dbh;
241 $dbh->do('UPDATE aqbasket SET closedate=now() WHERE basketno=?', {}, $basketno );
243 $dbh->do( q{UPDATE aqorders SET orderstatus = 'ordered' WHERE basketno = ? AND orderstatus != 'complete'},
250 &ReopenBasket($basketno);
258 my $dbh = C4
::Context
->dbh;
259 $dbh->do( q{UPDATE aqbasket SET closedate=NULL WHERE basketno=?}, {}, $basketno );
263 SET orderstatus = 'new'
265 AND orderstatus != 'complete'
270 #------------------------------------------------------------#
272 =head3 GetBasketAsCSV
274 &GetBasketAsCSV($basketno);
276 Export a basket as CSV
278 $cgi parameter is needed for column name translation
283 my ($basketno, $cgi, $csv_profile_id) = @_;
284 my $basket = GetBasket
($basketno);
285 my @orders = GetOrders
($basketno);
286 my $contract = GetContract
({
287 contractnumber
=> $basket->{'contractnumber'}
290 my $template = C4
::Templates
::gettemplate
("acqui/csv/basket.tt", "intranet", $cgi);
292 if ($csv_profile_id) {
293 my $csv_profile = Koha
::CsvProfiles
->find( $csv_profile_id );
294 die "There is no valid csv profile given" unless $csv_profile;
296 my $csv = Text
::CSV_XS
->new({'quote_char'=>'"','escape_char'=>'"','sep_char'=>$csv_profile->csv_separator,'binary'=>1});
297 my $csv_profile_content = $csv_profile->content;
298 my ( @headers, @fields );
299 while ( $csv_profile_content =~ /
302 ([^\
|]*) # fieldname (table.row or row)
306 my $field = ($2 eq '') ?
$1 : $2;
308 $header =~ s/^\s+|\s+$//g; # Trim whitespaces
309 push @headers, $header;
311 $field =~ s/[^\.]*\.{1}//; # Remove the table name if exists.
312 $field =~ s/^\s+|\s+$//g; # Trim whitespaces
313 push @fields, $field;
315 for my $order (@orders) {
317 my $bd = GetBiblioData
( $order->{'biblionumber'} );
318 my @biblioitems = GetBiblioItemByBiblioNumber
( $order->{'biblionumber'});
319 for my $biblioitem (@biblioitems) {
320 if ( $biblioitem->{isbn
}
322 and $biblioitem->{isbn
} eq $order->{isbn
} )
324 $order = { %$order, %$biblioitem };
328 $order = {%$order, %$contract};
330 $order = {%$order, %$basket, %$bd};
331 for my $field (@fields) {
332 push @row, $order->{$field};
336 my $content = join( $csv_profile->csv_separator, @headers ) . "\n";
337 for my $row ( @rows ) {
338 $csv->combine(@
$row);
339 my $string = $csv->string;
340 $content .= $string . "\n";
345 foreach my $order (@orders) {
346 my $bd = GetBiblioData
( $order->{'biblionumber'} );
348 contractname
=> $contract->{'contractname'},
349 ordernumber
=> $order->{'ordernumber'},
350 entrydate
=> $order->{'entrydate'},
351 isbn
=> $order->{'isbn'},
352 author
=> $bd->{'author'},
353 title
=> $bd->{'title'},
354 publicationyear
=> $bd->{'publicationyear'},
355 publishercode
=> $bd->{'publishercode'},
356 collectiontitle
=> $bd->{'collectiontitle'},
357 notes
=> $order->{'order_vendornote'},
358 quantity
=> $order->{'quantity'},
359 rrp
=> $order->{'rrp'},
361 for my $place ( qw( deliveryplace billingplace ) ) {
362 if ( my $library = Koha
::Libraries
->find( $row->{deliveryplace
} ) ) {
363 $row->{$place} = $library->branchname
367 contractname author title publishercode collectiontitle notes
368 deliveryplace billingplace
370 # Double the quotes to not be interpreted as a field end
371 $row->{$_} =~ s/"/""/g if $row->{$_};
377 if(defined $a->{publishercode
} and defined $b->{publishercode
}) {
378 $a->{publishercode
} cmp $b->{publishercode
};
382 $template->param(rows
=> \
@rows);
384 return $template->output;
389 =head3 GetBasketGroupAsCSV
391 &GetBasketGroupAsCSV($basketgroupid);
393 Export a basket group as CSV
395 $cgi parameter is needed for column name translation
399 sub GetBasketGroupAsCSV
{
400 my ($basketgroupid, $cgi) = @_;
401 my $baskets = GetBasketsByBasketgroup
($basketgroupid);
403 my $template = C4
::Templates
::gettemplate
('acqui/csv/basketgroup.tt', 'intranet', $cgi);
406 for my $basket (@
$baskets) {
407 my @orders = GetOrders
( $basket->{basketno
} );
408 my $contract = GetContract
({
409 contractnumber
=> $basket->{contractnumber
}
411 my $bookseller = Koha
::Acquisition
::Booksellers
->find( $basket->{booksellerid
} );
412 my $basketgroup = GetBasketgroup
( $$basket{basketgroupid
} );
414 foreach my $order (@orders) {
415 my $bd = GetBiblioData
( $order->{'biblionumber'} );
417 clientnumber
=> $bookseller->accountnumber,
418 basketname
=> $basket->{basketname
},
419 ordernumber
=> $order->{ordernumber
},
420 author
=> $bd->{author
},
421 title
=> $bd->{title
},
422 publishercode
=> $bd->{publishercode
},
423 publicationyear
=> $bd->{publicationyear
},
424 collectiontitle
=> $bd->{collectiontitle
},
425 isbn
=> $order->{isbn
},
426 quantity
=> $order->{quantity
},
427 rrp_tax_included
=> $order->{rrp_tax_included
},
428 rrp_tax_excluded
=> $order->{rrp_tax_excluded
},
429 discount
=> $bookseller->discount,
430 ecost_tax_included
=> $order->{ecost_tax_included
},
431 ecost_tax_excluded
=> $order->{ecost_tax_excluded
},
432 notes
=> $order->{order_vendornote
},
433 entrydate
=> $order->{entrydate
},
434 booksellername
=> $bookseller->name,
435 bookselleraddress
=> $bookseller->address1,
436 booksellerpostal
=> $bookseller->postal,
437 contractnumber
=> $contract->{contractnumber
},
438 contractname
=> $contract->{contractname
},
441 basketgroupdeliveryplace
=> $basketgroup->{deliveryplace
},
442 basketgroupbillingplace
=> $basketgroup->{billingplace
},
443 basketdeliveryplace
=> $basket->{deliveryplace
},
444 basketbillingplace
=> $basket->{billingplace
},
446 for my $place (qw( basketgroupdeliveryplace basketgroupbillingplace basketdeliveryplace basketbillingplace )) {
447 if ( my $library = Koha
::Libraries
->find( $temp->{$place} ) ) {
448 $row->{$place} = $library->branchname;
452 basketname author title publishercode collectiontitle notes
453 booksellername bookselleraddress booksellerpostal contractname
454 basketgroupdeliveryplace basketgroupbillingplace
455 basketdeliveryplace basketbillingplace
457 # Double the quotes to not be interpreted as a field end
458 $row->{$_} =~ s/"/""/g if $row->{$_};
463 $template->param(rows
=> \
@rows);
465 return $template->output;
469 =head3 CloseBasketgroup
471 &CloseBasketgroup($basketgroupno);
477 sub CloseBasketgroup
{
478 my ($basketgroupno) = @_;
479 my $dbh = C4
::Context
->dbh;
480 my $sth = $dbh->prepare("
481 UPDATE aqbasketgroups
485 $sth->execute($basketgroupno);
488 #------------------------------------------------------------#
490 =head3 ReOpenBaskergroup($basketgroupno)
492 &ReOpenBaskergroup($basketgroupno);
498 sub ReOpenBasketgroup
{
499 my ($basketgroupno) = @_;
500 my $dbh = C4
::Context
->dbh;
501 my $sth = $dbh->prepare("
502 UPDATE aqbasketgroups
506 $sth->execute($basketgroupno);
509 #------------------------------------------------------------#
514 &DelBasket($basketno);
516 Deletes the basket that has basketno field $basketno in the aqbasket table.
520 =item C<$basketno> is the primary key of the basket in the aqbasket table.
527 my ( $basketno ) = @_;
528 my $query = "DELETE FROM aqbasket WHERE basketno=?";
529 my $dbh = C4
::Context
->dbh;
530 my $sth = $dbh->prepare($query);
531 $sth->execute($basketno);
535 #------------------------------------------------------------#
539 &ModBasket($basketinfo);
541 Modifies a basket, using a hashref $basketinfo for the relevant information, only $basketinfo->{'basketno'} is required.
545 =item C<$basketno> is the primary key of the basket in the aqbasket table.
552 my $basketinfo = shift;
553 my $query = "UPDATE aqbasket SET ";
555 foreach my $key (keys %$basketinfo){
556 if ($key ne 'basketno'){
557 $query .= "$key=?, ";
558 push(@params, $basketinfo->{$key} || undef );
561 # get rid of the "," at the end of $query
562 if (substr($query, length($query)-2) eq ', '){
567 $query .= "WHERE basketno=?";
568 push(@params, $basketinfo->{'basketno'});
569 my $dbh = C4
::Context
->dbh;
570 my $sth = $dbh->prepare($query);
571 $sth->execute(@params);
576 #------------------------------------------------------------#
578 =head3 ModBasketHeader
580 &ModBasketHeader($basketno, $basketname, $note, $booksellernote, $contractnumber, $booksellerid);
582 Modifies a basket's header.
586 =item C<$basketno> is the "basketno" field in the "aqbasket" table;
588 =item C<$basketname> is the "basketname" field in the "aqbasket" table;
590 =item C<$note> is the "note" field in the "aqbasket" table;
592 =item C<$booksellernote> is the "booksellernote" field in the "aqbasket" table;
594 =item C<$contractnumber> is the "contractnumber" (foreign) key in the "aqbasket" table.
596 =item C<$booksellerid> is the id (foreign) key in the "aqbooksellers" table for the vendor.
598 =item C<$deliveryplace> is the "deliveryplace" field in the aqbasket table.
600 =item C<$billingplace> is the "billingplace" field in the aqbasket table.
602 =item C<$is_standing> is the "is_standing" field in the aqbasket table.
608 sub ModBasketHeader
{
609 my ($basketno, $basketname, $note, $booksellernote, $contractnumber, $booksellerid, $deliveryplace, $billingplace, $is_standing) = @_;
612 SET basketname
=?
, note
=?
, booksellernote
=?
, booksellerid
=?
, deliveryplace
=?
, billingplace
=?
, is_standing
=?
616 my $dbh = C4
::Context
->dbh;
617 my $sth = $dbh->prepare($query);
618 $sth->execute($basketname, $note, $booksellernote, $booksellerid, $deliveryplace, $billingplace, $is_standing, $basketno);
620 if ( $contractnumber ) {
621 my $query2 ="UPDATE aqbasket SET contractnumber=? WHERE basketno=?";
622 my $sth2 = $dbh->prepare($query2);
623 $sth2->execute($contractnumber,$basketno);
628 #------------------------------------------------------------#
630 =head3 GetBasketsByBookseller
632 @results = &GetBasketsByBookseller($booksellerid, $extra);
634 Returns a list of hashes of all the baskets that belong to bookseller 'booksellerid'.
638 =item C<$booksellerid> is the 'id' field of the bookseller in the aqbooksellers table
640 =item C<$extra> is the extra sql parameters, can be
642 $extra->{groupby}: group baskets by column
643 ex. $extra->{groupby} = aqbasket.basketgroupid
644 $extra->{orderby}: order baskets by column
645 $extra->{limit}: limit number of results (can be helpful for pagination)
651 sub GetBasketsByBookseller
{
652 my ($booksellerid, $extra) = @_;
653 my $query = "SELECT * FROM aqbasket WHERE booksellerid=?";
655 if ($extra->{groupby
}) {
656 $query .= " GROUP by $extra->{groupby}";
658 if ($extra->{orderby
}){
659 $query .= " ORDER by $extra->{orderby}";
661 if ($extra->{limit
}){
662 $query .= " LIMIT $extra->{limit}";
665 my $dbh = C4
::Context
->dbh;
666 my $sth = $dbh->prepare($query);
667 $sth->execute($booksellerid);
668 return $sth->fetchall_arrayref({});
671 =head3 GetBasketsInfosByBookseller
673 my $baskets = GetBasketsInfosByBookseller($supplierid, $allbaskets);
675 The optional second parameter allbaskets is a boolean allowing you to
676 select all baskets from the supplier; by default only active baskets (open or
677 closed but still something to receive) are returned.
679 Returns in a arrayref of hashref all about booksellers baskets, plus:
680 total_biblios: Number of distinct biblios in basket
681 total_items: Number of items in basket
682 expected_items: Number of non-received items in basket
686 sub GetBasketsInfosByBookseller
{
687 my ($supplierid, $allbaskets) = @_;
689 return unless $supplierid;
691 my $dbh = C4
::Context
->dbh;
694 SUM(aqorders.quantity) AS total_items,
696 IF ( aqorders.orderstatus = 'cancelled', aqorders.quantity, 0 )
697 ) AS total_items_cancelled,
698 COUNT(DISTINCT aqorders.biblionumber) AS total_biblios,
700 IF(aqorders.datereceived IS NULL
701 AND aqorders.datecancellationprinted IS NULL
706 LEFT JOIN aqorders ON aqorders.basketno = aqbasket.basketno
707 WHERE booksellerid = ?};
709 unless ( $allbaskets ) {
710 $query.=" AND (closedate IS NULL OR (aqorders.quantity > aqorders.quantityreceived AND datecancellationprinted IS NULL))";
712 $query.=" GROUP BY aqbasket.basketno";
714 my $sth = $dbh->prepare($query);
715 $sth->execute($supplierid);
716 my $baskets = $sth->fetchall_arrayref({});
718 # Retrieve the number of biblios cancelled
719 my $cancelled_biblios = $dbh->selectall_hashref( q
|
720 SELECT COUNT
(DISTINCT
(biblionumber
)) AS total_biblios_cancelled
, aqbasket
.basketno
722 LEFT JOIN aqorders ON aqorders
.basketno
= aqbasket
.basketno
723 WHERE booksellerid
= ?
724 AND aqorders
.orderstatus
= 'cancelled'
725 GROUP BY aqbasket
.basketno
726 |, 'basketno', {}, $supplierid );
728 $_->{total_biblios_cancelled
} = $cancelled_biblios->{$_->{basketno
}}{total_biblios_cancelled
} || 0
734 =head3 GetBasketUsers
736 $basketusers_ids = &GetBasketUsers($basketno);
738 Returns a list of all borrowernumbers that are in basket users list
743 my $basketno = shift;
745 return unless $basketno;
748 SELECT borrowernumber
752 my $dbh = C4
::Context
->dbh;
753 my $sth = $dbh->prepare($query);
754 $sth->execute($basketno);
755 my $results = $sth->fetchall_arrayref( {} );
758 foreach (@
$results) {
759 push @borrowernumbers, $_->{'borrowernumber'};
762 return @borrowernumbers;
765 =head3 ModBasketUsers
767 my @basketusers_ids = (1, 2, 3);
768 &ModBasketUsers($basketno, @basketusers_ids);
770 Delete all users from basket users list, and add users in C<@basketusers_ids>
776 my ($basketno, @basketusers_ids) = @_;
778 return unless $basketno;
780 my $dbh = C4
::Context
->dbh;
782 DELETE FROM aqbasketusers
785 my $sth = $dbh->prepare($query);
786 $sth->execute($basketno);
789 INSERT INTO aqbasketusers
(basketno
, borrowernumber
)
792 $sth = $dbh->prepare($query);
793 foreach my $basketuser_id (@basketusers_ids) {
794 $sth->execute($basketno, $basketuser_id);
799 =head3 CanUserManageBasket
801 my $bool = CanUserManageBasket($borrower, $basket[, $userflags]);
802 my $bool = CanUserManageBasket($borrowernumber, $basketno[, $userflags]);
804 Check if a borrower can manage a basket, according to system preference
805 AcqViewBaskets, user permissions and basket properties (creator, users list,
808 First parameter can be either a borrowernumber or a hashref as returned by
809 Koha::Patron->unblessed
811 Second parameter can be either a basketno or a hashref as returned by
812 C4::Acquisition::GetBasket.
814 The third parameter is optional. If given, it should be a hashref as returned
815 by C4::Auth::getuserflags. If not, getuserflags is called.
817 If user is authorised to manage basket, returns 1.
822 sub CanUserManageBasket
{
823 my ($borrower, $basket, $userflags) = @_;
825 if (!ref $borrower) {
826 # FIXME This needs to be replaced
827 # We should not accept both scalar and array
828 # Tests need to be updated
829 $borrower = Koha
::Patrons
->find( $borrower )->unblessed;
832 $basket = GetBasket
($basket);
835 return 0 unless ($basket and $borrower);
837 my $borrowernumber = $borrower->{borrowernumber
};
838 my $basketno = $basket->{basketno
};
840 my $AcqViewBaskets = C4
::Context
->preference('AcqViewBaskets');
842 if (!defined $userflags) {
843 my $dbh = C4
::Context
->dbh;
844 my $sth = $dbh->prepare("SELECT flags FROM borrowers WHERE borrowernumber = ?");
845 $sth->execute($borrowernumber);
846 my ($flags) = $sth->fetchrow_array;
849 $userflags = C4
::Auth
::getuserflags
($flags, $borrower->{userid
}, $dbh);
852 unless ($userflags->{superlibrarian
}
853 || (ref $userflags->{acquisition
} && $userflags->{acquisition
}->{order_manage_all
})
854 || (!ref $userflags->{acquisition
} && $userflags->{acquisition
}))
856 if (not exists $userflags->{acquisition
}) {
860 if ( (ref $userflags->{acquisition
} && !$userflags->{acquisition
}->{order_manage
})
861 || (!ref $userflags->{acquisition
} && !$userflags->{acquisition
}) ) {
865 if ($AcqViewBaskets eq 'user'
866 && $basket->{authorisedby
} != $borrowernumber
867 && ! grep { $borrowernumber eq $_ } GetBasketUsers
($basketno)) {
871 if ($AcqViewBaskets eq 'branch' && defined $basket->{branch
}
872 && $basket->{branch
} ne $borrower->{branchcode
}) {
880 #------------------------------------------------------------#
882 =head3 GetBasketsByBasketgroup
884 $baskets = &GetBasketsByBasketgroup($basketgroupid);
886 Returns a reference to all baskets that belong to basketgroup $basketgroupid.
890 sub GetBasketsByBasketgroup
{
891 my $basketgroupid = shift;
893 SELECT
*, aqbasket
.booksellerid as booksellerid
895 LEFT JOIN aqcontract USING
(contractnumber
) WHERE basketgroupid
=?
897 my $dbh = C4
::Context
->dbh;
898 my $sth = $dbh->prepare($query);
899 $sth->execute($basketgroupid);
900 return $sth->fetchall_arrayref({});
903 #------------------------------------------------------------#
905 =head3 NewBasketgroup
907 $basketgroupid = NewBasketgroup(\%hashref);
909 Adds a basketgroup to the aqbasketgroups table, and add the initial baskets to it.
911 $hashref->{'booksellerid'} is the 'id' field of the bookseller in the aqbooksellers table,
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 "booksellerid is required to create a basketgroup" unless $basketgroupinfo->{'booksellerid'};
932 my $query = "INSERT INTO aqbasketgroups (";
934 foreach my $field (qw(name billingplace deliveryplace freedeliveryplace deliverycomment closed)) {
935 if ( defined $basketgroupinfo->{$field} ) {
936 $query .= "$field, ";
937 push(@params, $basketgroupinfo->{$field});
940 $query .= "booksellerid) VALUES (";
945 push(@params, $basketgroupinfo->{'booksellerid'});
946 my $dbh = C4
::Context
->dbh;
947 my $sth = $dbh->prepare($query);
948 $sth->execute(@params);
949 my $basketgroupid = $dbh->{'mysql_insertid'};
950 if( $basketgroupinfo->{'basketlist'} ) {
951 foreach my $basketno (@
{$basketgroupinfo->{'basketlist'}}) {
952 my $query2 = "UPDATE aqbasket SET basketgroupid=? WHERE basketno=?";
953 my $sth2 = $dbh->prepare($query2);
954 $sth2->execute($basketgroupid, $basketno);
957 return $basketgroupid;
960 #------------------------------------------------------------#
962 =head3 ModBasketgroup
964 ModBasketgroup(\%hashref);
966 Modifies a basketgroup in the aqbasketgroups table, and add the baskets to it.
968 $hashref->{'id'} is the 'id' field of the basketgroup in the aqbasketgroup table, this parameter is mandatory,
970 $hashref->{'name'} is the 'name' field of the basketgroup in the aqbasketgroups table,
972 $hashref->{'basketlist'} is a list reference of the 'id's of the baskets that belong to this group,
974 $hashref->{'billingplace'} is the 'billingplace' field of the basketgroup in the aqbasketgroups table,
976 $hashref->{'deliveryplace'} is the 'deliveryplace' field of the basketgroup in the aqbasketgroups table,
978 $hashref->{'freedeliveryplace'} is the 'freedeliveryplace' field of the basketgroup in the aqbasketgroups table,
980 $hashref->{'deliverycomment'} is the 'deliverycomment' field of the basketgroup in the aqbasketgroups table,
982 $hashref->{'closed'} is the 'closed' field of the aqbasketgroups table, it is false if 0, true otherwise.
987 my $basketgroupinfo = shift;
988 die "basketgroup id is required to edit a basketgroup" unless $basketgroupinfo->{'id'};
989 my $dbh = C4
::Context
->dbh;
990 my $query = "UPDATE aqbasketgroups SET ";
992 foreach my $field (qw(name billingplace deliveryplace freedeliveryplace deliverycomment closed)) {
993 if ( defined $basketgroupinfo->{$field} ) {
994 $query .= "$field=?, ";
995 push(@params, $basketgroupinfo->{$field});
1000 $query .= " WHERE id=?";
1001 push(@params, $basketgroupinfo->{'id'});
1002 my $sth = $dbh->prepare($query);
1003 $sth->execute(@params);
1005 $sth = $dbh->prepare('UPDATE aqbasket SET basketgroupid = NULL WHERE basketgroupid = ?');
1006 $sth->execute($basketgroupinfo->{'id'});
1008 if($basketgroupinfo->{'basketlist'} && @
{$basketgroupinfo->{'basketlist'}}){
1009 $sth = $dbh->prepare("UPDATE aqbasket SET basketgroupid=? WHERE basketno=?");
1010 foreach my $basketno (@
{$basketgroupinfo->{'basketlist'}}) {
1011 $sth->execute($basketgroupinfo->{'id'}, $basketno);
1017 #------------------------------------------------------------#
1019 =head3 DelBasketgroup
1021 DelBasketgroup($basketgroupid);
1023 Deletes a basketgroup in the aqbasketgroups table, and removes the reference to it from the baskets,
1027 =item C<$basketgroupid> is the 'id' field of the basket in the aqbasketgroup table
1033 sub DelBasketgroup
{
1034 my $basketgroupid = shift;
1035 die "basketgroup id is required to edit a basketgroup" unless $basketgroupid;
1036 my $query = "DELETE FROM aqbasketgroups WHERE id=?";
1037 my $dbh = C4
::Context
->dbh;
1038 my $sth = $dbh->prepare($query);
1039 $sth->execute($basketgroupid);
1043 #------------------------------------------------------------#
1046 =head2 FUNCTIONS ABOUT ORDERS
1048 =head3 GetBasketgroup
1050 $basketgroup = &GetBasketgroup($basketgroupid);
1052 Returns a reference to the hash containing all information about the basketgroup.
1056 sub GetBasketgroup
{
1057 my $basketgroupid = shift;
1058 die "basketgroup id is required to edit a basketgroup" unless $basketgroupid;
1059 my $dbh = C4
::Context
->dbh;
1060 my $result_set = $dbh->selectall_arrayref(
1061 'SELECT * FROM aqbasketgroups WHERE id=?',
1065 return $result_set->[0]; # id is unique
1068 #------------------------------------------------------------#
1070 =head3 GetBasketgroups
1072 $basketgroups = &GetBasketgroups($booksellerid);
1074 Returns a reference to the array of all the basketgroups of bookseller $booksellerid.
1078 sub GetBasketgroups
{
1079 my $booksellerid = shift;
1080 die 'bookseller id is required to edit a basketgroup' unless $booksellerid;
1081 my $query = 'SELECT * FROM aqbasketgroups WHERE booksellerid=? ORDER BY id DESC';
1082 my $dbh = C4
::Context
->dbh;
1083 my $sth = $dbh->prepare($query);
1084 $sth->execute($booksellerid);
1085 return $sth->fetchall_arrayref({});
1088 #------------------------------------------------------------#
1090 =head2 FUNCTIONS ABOUT ORDERS
1094 @orders = &GetOrders( $basketno, { orderby => 'biblio.title', cancelled => 0|1 } );
1096 Looks up the pending (non-cancelled) orders with the given basket
1099 If cancelled is set, only cancelled orders will be returned.
1104 my ( $basketno, $params ) = @_;
1106 return () unless $basketno;
1108 my $orderby = $params->{orderby
};
1109 my $cancelled = $params->{cancelled
} || 0;
1111 my $dbh = C4
::Context
->dbh;
1113 SELECT biblio
.*,biblioitems
.*,
1117 $query .= $cancelled
1119 aqorders_transfers
.ordernumber_to AS transferred_to
,
1120 aqorders_transfers
.timestamp AS transferred_to_timestamp
1123 aqorders_transfers
.ordernumber_from AS transferred_from
,
1124 aqorders_transfers
.timestamp AS transferred_from_timestamp
1128 LEFT JOIN aqbudgets ON aqbudgets
.budget_id
= aqorders
.budget_id
1129 LEFT JOIN biblio ON biblio
.biblionumber
= aqorders
.biblionumber
1130 LEFT JOIN biblioitems ON biblioitems
.biblionumber
=biblio
.biblionumber
1132 $query .= $cancelled
1134 LEFT JOIN aqorders_transfers ON aqorders_transfers
.ordernumber_from
= aqorders
.ordernumber
1137 LEFT JOIN aqorders_transfers ON aqorders_transfers
.ordernumber_to
= aqorders
.ordernumber
1145 $orderby ||= q
|biblioitems
.publishercode
, biblio
.title
|;
1147 AND
(datecancellationprinted IS NOT NULL
1148 AND datecancellationprinted
<> '0000-00-00')
1153 q
|aqorders
.datecancellationprinted desc
, aqorders
.timestamp desc
|;
1155 AND
(datecancellationprinted IS NULL OR datecancellationprinted
='0000-00-00')
1159 $query .= " ORDER BY $orderby";
1161 $dbh->selectall_arrayref( $query, { Slice
=> {} }, $basketno );
1166 #------------------------------------------------------------#
1168 =head3 GetOrdersByBiblionumber
1170 @orders = &GetOrdersByBiblionumber($biblionumber);
1172 Looks up the orders with linked to a specific $biblionumber, including
1173 cancelled orders and received orders.
1176 C<@orders> is an array of references-to-hash, whose keys are the
1177 fields from the aqorders, biblio, and biblioitems tables in the Koha database.
1181 sub GetOrdersByBiblionumber
{
1182 my $biblionumber = shift;
1183 return unless $biblionumber;
1184 my $dbh = C4
::Context
->dbh;
1186 SELECT biblio.*,biblioitems.*,
1190 LEFT JOIN aqbudgets ON aqbudgets.budget_id = aqorders.budget_id
1191 LEFT JOIN biblio ON biblio.biblionumber = aqorders.biblionumber
1192 LEFT JOIN biblioitems ON biblioitems.biblionumber =biblio.biblionumber
1193 WHERE aqorders.biblionumber=?
1196 $dbh->selectall_arrayref( $query, { Slice
=> {} }, $biblionumber );
1197 return @
{$result_set};
1201 #------------------------------------------------------------#
1205 $order = &GetOrder($ordernumber);
1207 Looks up an order by order number.
1209 Returns a reference-to-hash describing the order. The keys of
1210 C<$order> are fields from the biblio, biblioitems, aqorders tables of the Koha database.
1215 my ($ordernumber) = @_;
1216 return unless $ordernumber;
1218 my $dbh = C4
::Context
->dbh;
1219 my $query = qq{SELECT
1223 aqbasket
.basketname
,
1224 borrowers
.branchcode
,
1225 biblioitems
.publicationyear
,
1226 biblio
.copyrightdate
,
1227 biblioitems
.editionstatement
,
1231 biblioitems
.publishercode
,
1232 aqorders
.rrp AS unitpricesupplier
,
1233 aqorders
.ecost AS unitpricelib
,
1234 aqorders
.claims_count AS claims_count
,
1235 aqorders
.claimed_date AS claimed_date
,
1236 aqbudgets
.budget_name AS budget
,
1237 aqbooksellers
.name AS supplier
,
1238 aqbooksellers
.id AS supplierid
,
1239 biblioitems
.publishercode AS publisher
,
1240 ADDDATE
(aqbasket
.closedate
, INTERVAL aqbooksellers
.deliverytime DAY
) AS estimateddeliverydate
,
1241 DATE
(aqbasket
.closedate
) AS orderdate
,
1242 aqorders
.quantity
- COALESCE
(aqorders
.quantityreceived
,0) AS quantity_to_receive
,
1243 (aqorders
.quantity
- COALESCE
(aqorders
.quantityreceived
,0)) * aqorders
.rrp AS subtotal
,
1244 DATEDIFF
(CURDATE
( ),closedate
) AS latesince
1245 FROM aqorders LEFT JOIN biblio ON biblio
.biblionumber
= aqorders
.biblionumber
1246 LEFT JOIN biblioitems ON biblioitems
.biblionumber
= biblio
.biblionumber
1247 LEFT JOIN aqbudgets ON aqorders
.budget_id
= aqbudgets
.budget_id
,
1248 aqbasket LEFT JOIN borrowers ON aqbasket
.authorisedby
= borrowers
.borrowernumber
1249 LEFT JOIN aqbooksellers ON aqbasket
.booksellerid
= aqbooksellers
.id
1250 WHERE aqorders
.basketno
= aqbasket
.basketno
1253 $dbh->selectall_arrayref( $query, { Slice
=> {} }, $ordernumber );
1255 # result_set assumed to contain 1 match
1256 return $result_set->[0];
1259 =head3 GetLastOrderNotReceivedFromSubscriptionid
1261 $order = &GetLastOrderNotReceivedFromSubscriptionid($subscriptionid);
1263 Returns a reference-to-hash describing the last order not received for a subscription.
1267 sub GetLastOrderNotReceivedFromSubscriptionid
{
1268 my ( $subscriptionid ) = @_;
1269 my $dbh = C4
::Context
->dbh;
1271 SELECT
* FROM aqorders
1272 LEFT JOIN subscription
1273 ON
( aqorders
.subscriptionid
= subscription
.subscriptionid
)
1274 WHERE aqorders
.subscriptionid
= ?
1275 AND aqorders
.datereceived IS NULL
1279 $dbh->selectall_arrayref( $query, { Slice
=> {} }, $subscriptionid );
1281 # result_set assumed to contain 1 match
1282 return $result_set->[0];
1285 =head3 GetLastOrderReceivedFromSubscriptionid
1287 $order = &GetLastOrderReceivedFromSubscriptionid($subscriptionid);
1289 Returns a reference-to-hash describing the last order received for a subscription.
1293 sub GetLastOrderReceivedFromSubscriptionid
{
1294 my ( $subscriptionid ) = @_;
1295 my $dbh = C4
::Context
->dbh;
1297 SELECT
* FROM aqorders
1298 LEFT JOIN subscription
1299 ON
( aqorders
.subscriptionid
= subscription
.subscriptionid
)
1300 WHERE aqorders
.subscriptionid
= ?
1301 AND aqorders
.datereceived
=
1303 SELECT MAX
( aqorders
.datereceived
)
1305 LEFT JOIN subscription
1306 ON
( aqorders
.subscriptionid
= subscription
.subscriptionid
)
1307 WHERE aqorders
.subscriptionid
= ?
1308 AND aqorders
.datereceived IS NOT NULL
1310 ORDER BY ordernumber DESC
1314 $dbh->selectall_arrayref( $query, { Slice
=> {} }, $subscriptionid, $subscriptionid );
1316 # result_set assumed to contain 1 match
1317 return $result_set->[0];
1321 #------------------------------------------------------------#
1325 &ModOrder(\%hashref);
1327 Modifies an existing order. Updates the order with order number
1328 $hashref->{'ordernumber'} and biblionumber $hashref->{'biblionumber'}. All
1329 other keys of the hash update the fields with the same name in the aqorders
1330 table of the Koha database.
1335 my $orderinfo = shift;
1337 die "Ordernumber is required" if $orderinfo->{'ordernumber'} eq '';
1339 my $dbh = C4
::Context
->dbh;
1342 # update uncertainprice to an integer, just in case (under FF, checked boxes have the value "ON" by default)
1343 $orderinfo->{uncertainprice
}=1 if $orderinfo->{uncertainprice
};
1345 # delete($orderinfo->{'branchcode'});
1346 # the hash contains a lot of entries not in aqorders, so get the columns ...
1347 my $sth = $dbh->prepare("SELECT * FROM aqorders LIMIT 1;");
1349 my $colnames = $sth->{NAME
};
1350 #FIXME Be careful. If aqorders would have columns with diacritics,
1351 #you should need to decode what you get back from NAME.
1352 #See report 10110 and guided_reports.pl
1353 my $query = "UPDATE aqorders SET ";
1355 foreach my $orderinfokey (grep(!/ordernumber/, keys %$orderinfo)){
1356 # ... and skip hash entries that are not in the aqorders table
1357 # FIXME : probably not the best way to do it (would be better to have a correct hash)
1358 next unless grep(/^$orderinfokey$/, @
$colnames);
1359 $query .= "$orderinfokey=?, ";
1360 push(@params, $orderinfo->{$orderinfokey});
1363 $query .= "timestamp=NOW() WHERE ordernumber=?";
1364 push(@params, $orderinfo->{'ordernumber'} );
1365 $sth = $dbh->prepare($query);
1366 $sth->execute(@params);
1370 #------------------------------------------------------------#
1374 ModItemOrder($itemnumber, $ordernumber);
1376 Modifies the ordernumber of an item in aqorders_items.
1381 my ($itemnumber, $ordernumber) = @_;
1383 return unless ($itemnumber and $ordernumber);
1385 my $dbh = C4
::Context
->dbh;
1387 UPDATE aqorders_items
1389 WHERE itemnumber
= ?
1391 my $sth = $dbh->prepare($query);
1392 return $sth->execute($ordernumber, $itemnumber);
1395 #------------------------------------------------------------#
1397 =head3 ModReceiveOrder
1399 my ( $date_received, $new_ordernumber ) = ModReceiveOrder(
1401 biblionumber => $biblionumber,
1403 quantityreceived => $quantityreceived,
1405 invoice => $invoice,
1406 budget_id => $budget_id,
1407 received_itemnumbers => \@received_itemnumbers,
1408 order_internalnote => $order_internalnote,
1412 Updates an order, to reflect the fact that it was received, at least
1415 If a partial order is received, splits the order into two.
1417 Updates the order with biblionumber C<$biblionumber> and ordernumber
1418 C<$order->{ordernumber}>.
1423 sub ModReceiveOrder
{
1425 my $biblionumber = $params->{biblionumber
};
1426 my $order = { %{ $params->{order
} } }; # Copy the order, we don't want to modify it
1427 my $invoice = $params->{invoice
};
1428 my $quantrec = $params->{quantityreceived
};
1429 my $user = $params->{user
};
1430 my $budget_id = $params->{budget_id
};
1431 my $received_items = $params->{received_items
};
1433 my $dbh = C4
::Context
->dbh;
1434 my $datereceived = ( $invoice and $invoice->{datereceived
} ) ?
$invoice->{datereceived
} : dt_from_string
;
1435 my $suggestionid = GetSuggestionFromBiblionumber
( $biblionumber );
1436 if ($suggestionid) {
1437 ModSuggestion
( {suggestionid
=>$suggestionid,
1438 STATUS
=>'AVAILABLE',
1439 biblionumber
=> $biblionumber}
1443 my $result_set = $dbh->selectrow_arrayref(
1444 q{SELECT aqbasket.is_standing
1446 WHERE basketno=?},{ Slice
=> {} }, $order->{basketno
});
1447 my $is_standing = $result_set->[0]; # we assume we have a unique basket
1449 my $new_ordernumber = $order->{ordernumber
};
1450 if ( $is_standing || $order->{quantity
} > $quantrec ) {
1451 # Split order line in two parts: the first is the original order line
1452 # without received items (the quantity is decreased),
1453 # the second part is a new order line with quantity=quantityrec
1454 # (entirely received)
1458 orderstatus
= 'partial'|;
1459 $query .= q
|, order_internalnote
= ?
| if defined $order->{order_internalnote
};
1460 $query .= q
| WHERE ordernumber
= ?
|;
1461 my $sth = $dbh->prepare($query);
1464 ( $is_standing ?
1 : ($order->{quantity
} - $quantrec) ),
1465 ( defined $order->{order_internalnote
} ?
$order->{order_internalnote
} : () ),
1466 $order->{ordernumber
}
1469 # Recalculate tax_value
1473 tax_value_on_ordering
= quantity
* ecost_tax_excluded
* tax_rate_on_ordering
,
1474 tax_value_on_receiving
= quantity
* unitprice_tax_excluded
* tax_rate_on_receiving
1475 WHERE ordernumber
= ?
1476 |, undef, $order->{ordernumber
});
1478 delete $order->{ordernumber
};
1479 $order->{budget_id
} = ( $budget_id || $order->{budget_id
} );
1480 $order->{quantity
} = $quantrec;
1481 $order->{quantityreceived
} = $quantrec;
1482 $order->{ecost_tax_excluded
} //= 0;
1483 $order->{tax_rate_on_ordering
} //= 0;
1484 $order->{unitprice_tax_excluded
} //= 0;
1485 $order->{tax_rate_on_receiving
} //= 0;
1486 $order->{tax_value_on_ordering
} = $order->{quantity
} * $order->{ecost_tax_excluded
} * $order->{tax_rate_on_ordering
};
1487 $order->{tax_value_on_receiving
} = $order->{quantity
} * $order->{unitprice_tax_excluded
} * $order->{tax_rate_on_receiving
};
1488 $order->{datereceived
} = $datereceived;
1489 $order->{invoiceid
} = $invoice->{invoiceid
};
1490 $order->{orderstatus
} = 'complete';
1491 $new_ordernumber = Koha
::Acquisition
::Order
->new($order)->insert->{ordernumber
};
1493 if ($received_items) {
1494 foreach my $itemnumber (@
$received_items) {
1495 ModItemOrder
($itemnumber, $new_ordernumber);
1501 SET quantityreceived
= ?
,
1505 orderstatus
= 'complete'
1509 , unitprice
= ?
, unitprice_tax_included
= ?
, unitprice_tax_excluded
= ?
1510 | if defined $order->{unitprice
};
1513 ,tax_value_on_receiving
= ?
1514 | if defined $order->{tax_value_on_receiving
};
1517 ,tax_rate_on_receiving
= ?
1518 | if defined $order->{tax_rate_on_receiving
};
1521 , order_internalnote
= ?
1522 | if defined $order->{order_internalnote
};
1524 $query .= q
| where biblionumber
=?
and ordernumber
=?
|;
1526 my $sth = $dbh->prepare( $query );
1527 my @params = ( $quantrec, $datereceived, $invoice->{invoiceid
}, ( $budget_id ?
$budget_id : $order->{budget_id
} ) );
1529 if ( defined $order->{unitprice
} ) {
1530 push @params, $order->{unitprice
}, $order->{unitprice_tax_included
}, $order->{unitprice_tax_excluded
};
1533 if ( defined $order->{tax_value_on_receiving
} ) {
1534 push @params, $order->{tax_value_on_receiving
};
1537 if ( defined $order->{tax_rate_on_receiving
} ) {
1538 push @params, $order->{tax_rate_on_receiving
};
1541 if ( defined $order->{order_internalnote
} ) {
1542 push @params, $order->{order_internalnote
};
1545 push @params, ( $biblionumber, $order->{ordernumber
} );
1547 $sth->execute( @params );
1549 # All items have been received, sent a notification to users
1550 NotifyOrderUsers
( $order->{ordernumber
} );
1553 return ($datereceived, $new_ordernumber);
1556 =head3 CancelReceipt
1558 my $parent_ordernumber = CancelReceipt($ordernumber);
1560 Cancel an order line receipt and update the parent order line, as if no
1562 If items are created at receipt (AcqCreateItem = receiving) then delete
1568 my $ordernumber = shift;
1570 return unless $ordernumber;
1572 my $dbh = C4
::Context
->dbh;
1574 SELECT datereceived
, parent_ordernumber
, quantity
1576 WHERE ordernumber
= ?
1578 my $sth = $dbh->prepare($query);
1579 $sth->execute($ordernumber);
1580 my $order = $sth->fetchrow_hashref;
1582 warn "CancelReceipt: order $ordernumber does not exist";
1585 unless($order->{'datereceived'}) {
1586 warn "CancelReceipt: order $ordernumber is not received";
1590 my $parent_ordernumber = $order->{'parent_ordernumber'};
1592 my @itemnumbers = GetItemnumbersFromOrder
( $ordernumber );
1594 if($parent_ordernumber == $ordernumber || not $parent_ordernumber) {
1595 # The order line has no parent, just mark it as not received
1598 SET quantityreceived
= ?
,
1601 orderstatus
= 'ordered'
1602 WHERE ordernumber
= ?
1604 $sth = $dbh->prepare($query);
1605 $sth->execute(0, undef, undef, $ordernumber);
1606 _cancel_items_receipt
( $ordernumber );
1608 # The order line has a parent, increase parent quantity and delete
1611 SELECT quantity
, datereceived
1613 WHERE ordernumber
= ?
1615 $sth = $dbh->prepare($query);
1616 $sth->execute($parent_ordernumber);
1617 my $parent_order = $sth->fetchrow_hashref;
1618 unless($parent_order) {
1619 warn "Parent order $parent_ordernumber does not exist.";
1622 if($parent_order->{'datereceived'}) {
1623 warn "CancelReceipt: parent order is received.".
1624 " Can't cancel receipt.";
1630 orderstatus
= 'ordered'
1631 WHERE ordernumber
= ?
1633 $sth = $dbh->prepare($query);
1634 my $rv = $sth->execute(
1635 $order->{'quantity'} + $parent_order->{'quantity'},
1639 warn "Cannot update parent order line, so do not cancel".
1644 # Recalculate tax_value
1648 tax_value_on_ordering
= quantity
* ecost_tax_excluded
* tax_rate_on_ordering
,
1649 tax_value_on_receiving
= quantity
* unitprice_tax_excluded
* tax_rate_on_receiving
1650 WHERE ordernumber
= ?
1651 |, undef, $parent_ordernumber);
1653 _cancel_items_receipt
( $ordernumber, $parent_ordernumber );
1656 DELETE FROM aqorders
1657 WHERE ordernumber
= ?
1659 $sth = $dbh->prepare($query);
1660 $sth->execute($ordernumber);
1664 if(C4
::Context
->preference('AcqCreateItem') eq 'ordering') {
1665 my @affects = split q{\|}, C4
::Context
->preference("AcqItemSetSubfieldsWhenReceiptIsCancelled");
1667 for my $in ( @itemnumbers ) {
1668 my $item = Koha
::Items
->find( $in );
1669 my $biblio = $item->biblio;
1670 my ( $itemfield ) = GetMarcFromKohaField
( 'items.itemnumber', $biblio->frameworkcode );
1671 my $item_marc = C4
::Items
::GetMarcItem
( $biblio->biblionumber, $in );
1672 for my $affect ( @affects ) {
1673 my ( $sf, $v ) = split q{=}, $affect, 2;
1674 foreach ( $item_marc->field($itemfield) ) {
1675 $_->update( $sf => $v );
1678 C4
::Items
::ModItemFromMarc
( $item_marc, $biblio->biblionumber, $in );
1683 return $parent_ordernumber;
1686 sub _cancel_items_receipt
{
1687 my ( $ordernumber, $parent_ordernumber ) = @_;
1688 $parent_ordernumber ||= $ordernumber;
1690 my @itemnumbers = GetItemnumbersFromOrder
($ordernumber);
1691 if(C4
::Context
->preference('AcqCreateItem') eq 'receiving') {
1692 # Remove items that were created at receipt
1694 DELETE FROM items
, aqorders_items
1695 USING items
, aqorders_items
1696 WHERE items
.itemnumber
= ? AND aqorders_items
.itemnumber
= ?
1698 my $dbh = C4
::Context
->dbh;
1699 my $sth = $dbh->prepare($query);
1700 foreach my $itemnumber (@itemnumbers) {
1701 $sth->execute($itemnumber, $itemnumber);
1705 foreach my $itemnumber (@itemnumbers) {
1706 ModItemOrder
($itemnumber, $parent_ordernumber);
1711 #------------------------------------------------------------#
1715 @results = &SearchOrders({
1716 ordernumber => $ordernumber,
1719 booksellerid => $booksellerid,
1720 basketno => $basketno,
1721 basketname => $basketname,
1722 basketgroupname => $basketgroupname,
1726 biblionumber => $biblionumber,
1727 budget_id => $budget_id
1730 Searches for orders filtered by criteria.
1732 C<$ordernumber> Finds matching orders or transferred orders by ordernumber.
1733 C<$search> Finds orders matching %$search% in title, author, or isbn.
1734 C<$owner> Finds order for the logged in user.
1735 C<$pending> Finds pending orders. Ignores completed and cancelled orders.
1736 C<$ordered> Finds orders to receive only (status 'ordered' or 'partial').
1739 C<@results> is an array of references-to-hash with the keys are fields
1740 from aqorders, biblio, biblioitems and aqbasket tables.
1745 my ( $params ) = @_;
1746 my $ordernumber = $params->{ordernumber
};
1747 my $search = $params->{search
};
1748 my $ean = $params->{ean
};
1749 my $booksellerid = $params->{booksellerid
};
1750 my $basketno = $params->{basketno
};
1751 my $basketname = $params->{basketname
};
1752 my $basketgroupname = $params->{basketgroupname
};
1753 my $owner = $params->{owner
};
1754 my $pending = $params->{pending
};
1755 my $ordered = $params->{ordered
};
1756 my $biblionumber = $params->{biblionumber
};
1757 my $budget_id = $params->{budget_id
};
1759 my $dbh = C4
::Context
->dbh;
1762 SELECT aqbasket.basketno,
1764 borrowers.firstname,
1767 biblioitems.biblioitemnumber,
1768 biblioitems.publishercode,
1769 biblioitems.publicationyear,
1770 aqbasket.authorisedby,
1771 aqbasket.booksellerid,
1773 aqbasket.creationdate,
1774 aqbasket.basketname,
1775 aqbasketgroups.id as basketgroupid,
1776 aqbasketgroups.name as basketgroupname,
1779 LEFT JOIN aqbasket ON aqorders.basketno = aqbasket.basketno
1780 LEFT JOIN aqbasketgroups ON aqbasket.basketgroupid = aqbasketgroups.id
1781 LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber
1782 LEFT JOIN biblio ON aqorders.biblionumber=biblio.biblionumber
1783 LEFT JOIN biblioitems ON biblioitems.biblionumber=biblio.biblionumber
1786 # If we search on ordernumber, we retrieve the transferred order if a transfer has been done.
1788 LEFT JOIN aqorders_transfers ON aqorders_transfers.ordernumber_to = aqorders.ordernumber
1792 WHERE (datecancellationprinted is NULL)
1795 if ( $pending or $ordered ) {
1798 ( aqbasket.is_standing AND aqorders.orderstatus IN ( "new", "ordered", "partial" ) )
1800 ( quantity > quantityreceived OR quantityreceived is NULL )
1804 $query .= q{ AND aqorders.orderstatus IN ( "ordered", "partial" )};
1812 my $userenv = C4
::Context
->userenv;
1813 if ( C4
::Context
->preference("IndependentBranches") ) {
1814 unless ( C4
::Context
->IsSuperLibrarian() ) {
1817 borrowers.branchcode = ?
1818 OR borrowers.branchcode = ''
1821 push @args, $userenv->{branch
};
1825 if ( $ordernumber ) {
1826 $query .= ' AND ( aqorders.ordernumber = ? OR aqorders_transfers.ordernumber_from = ? ) ';
1827 push @args, ( $ordernumber, $ordernumber );
1829 if ( $biblionumber ) {
1830 $query .= 'AND aqorders.biblionumber = ?';
1831 push @args, $biblionumber;
1834 $query .= ' AND (biblio.title LIKE ? OR biblio.author LIKE ? OR biblioitems.isbn LIKE ?)';
1835 push @args, ("%$search%","%$search%","%$search%");
1838 $query .= ' AND biblioitems.ean = ?';
1841 if ( $booksellerid ) {
1842 $query .= 'AND aqbasket.booksellerid = ?';
1843 push @args, $booksellerid;
1846 $query .= 'AND aqbasket.basketno = ?';
1847 push @args, $basketno;
1850 $query .= 'AND aqbasket.basketname LIKE ?';
1851 push @args, "%$basketname%";
1853 if( $basketgroupname ) {
1854 $query .= ' AND aqbasketgroups.name LIKE ?';
1855 push @args, "%$basketgroupname%";
1859 $query .= ' AND aqbasket.authorisedby=? ';
1860 push @args, $userenv->{'number'};
1864 $query .= ' AND aqorders.budget_id = ?';
1865 push @args, $budget_id;
1868 $query .= ' ORDER BY aqbasket.basketno';
1870 my $sth = $dbh->prepare($query);
1871 $sth->execute(@args);
1872 return $sth->fetchall_arrayref({});
1875 #------------------------------------------------------------#
1879 &DelOrder($biblionumber, $ordernumber);
1881 Cancel the order with the given order and biblio numbers. It does not
1882 delete any entries in the aqorders table, it merely marks them as
1888 my ( $bibnum, $ordernumber, $delete_biblio, $reason ) = @_;
1891 my $dbh = C4
::Context
->dbh;
1894 SET datecancellationprinted=now(), orderstatus='cancelled'
1897 $query .= ", cancellationreason = ? ";
1900 WHERE biblionumber=? AND ordernumber=?
1902 my $sth = $dbh->prepare($query);
1904 $sth->execute($reason, $bibnum, $ordernumber);
1906 $sth->execute( $bibnum, $ordernumber );
1910 my @itemnumbers = GetItemnumbersFromOrder
( $ordernumber );
1911 foreach my $itemnumber (@itemnumbers){
1912 my $delcheck = C4
::Items
::DelItemCheck
( $bibnum, $itemnumber );
1914 if($delcheck != 1) {
1915 $error->{'delitem'} = 1;
1919 if($delete_biblio) {
1920 # We get the number of remaining items
1921 my $biblio = Koha
::Biblios
->find( $bibnum );
1922 my $itemcount = $biblio->items->count;
1924 # If there are no items left,
1925 if ( $itemcount == 0 ) {
1926 # We delete the record
1927 my $delcheck = DelBiblio
($bibnum);
1930 $error->{'delbiblio'} = 1;
1938 =head3 TransferOrder
1940 my $newordernumber = TransferOrder($ordernumber, $basketno);
1942 Transfer an order line to a basket.
1943 Mark $ordernumber as cancelled with an internal note 'Cancelled and transferred
1944 to BOOKSELLER on DATE' and create new order with internal note
1945 'Transferred from BOOKSELLER on DATE'.
1946 Move all attached items to the new order.
1947 Received orders cannot be transferred.
1948 Return the ordernumber of created order.
1953 my ($ordernumber, $basketno) = @_;
1955 return unless ($ordernumber and $basketno);
1957 my $order = GetOrder
( $ordernumber );
1958 return if $order->{datereceived
};
1959 my $basket = GetBasket
($basketno);
1960 return unless $basket;
1962 my $dbh = C4
::Context
->dbh;
1963 my ($query, $sth, $rv);
1967 SET datecancellationprinted = CAST(NOW() AS date), orderstatus = ?
1968 WHERE ordernumber = ?
1970 $sth = $dbh->prepare($query);
1971 $rv = $sth->execute('cancelled', $ordernumber);
1973 delete $order->{'ordernumber'};
1974 delete $order->{parent_ordernumber
};
1975 $order->{'basketno'} = $basketno;
1977 my $newordernumber = Koha
::Acquisition
::Order
->new($order)->insert->{ordernumber
};
1980 UPDATE aqorders_items
1982 WHERE ordernumber = ?
1984 $sth = $dbh->prepare($query);
1985 $sth->execute($newordernumber, $ordernumber);
1988 INSERT INTO aqorders_transfers (ordernumber_from, ordernumber_to)
1991 $sth = $dbh->prepare($query);
1992 $sth->execute($ordernumber, $newordernumber);
1994 return $newordernumber;
1997 =head2 FUNCTIONS ABOUT PARCELS
2001 $results = &GetParcels($bookseller, $order, $code, $datefrom, $dateto);
2003 get a lists of parcels.
2010 is the bookseller this function has to get parcels.
2013 To know on what criteria the results list has to be ordered.
2016 is the booksellerinvoicenumber.
2018 =item $datefrom & $dateto
2019 to know on what date this function has to filter its search.
2024 a pointer on a hash list containing parcel informations as such :
2030 =item Last operation
2032 =item Number of biblio
2034 =item Number of items
2041 my ($bookseller,$order, $code, $datefrom, $dateto) = @_;
2042 my $dbh = C4
::Context
->dbh;
2043 my @query_params = ();
2045 SELECT aqinvoices.invoicenumber,
2046 datereceived,purchaseordernumber,
2047 count(DISTINCT biblionumber) AS biblio,
2048 sum(quantity) AS itemsexpected,
2049 sum(quantityreceived) AS itemsreceived
2050 FROM aqorders LEFT JOIN aqbasket ON aqbasket.basketno = aqorders.basketno
2051 LEFT JOIN aqinvoices ON aqorders.invoiceid = aqinvoices.invoiceid
2052 WHERE aqbasket.booksellerid = ? and datereceived IS NOT NULL
2054 push @query_params, $bookseller;
2056 if ( defined $code ) {
2057 $strsth .= ' and aqinvoices.invoicenumber like ? ';
2058 # add a % to the end of the code to allow stemming.
2059 push @query_params, "$code%";
2062 if ( defined $datefrom ) {
2063 $strsth .= ' and datereceived >= ? ';
2064 push @query_params, $datefrom;
2067 if ( defined $dateto ) {
2068 $strsth .= 'and datereceived <= ? ';
2069 push @query_params, $dateto;
2072 $strsth .= "group by aqinvoices.invoicenumber,datereceived ";
2074 # can't use a placeholder to place this column name.
2075 # but, we could probably be checking to make sure it is a column that will be fetched.
2076 $strsth .= "order by $order " if ($order);
2078 my $sth = $dbh->prepare($strsth);
2080 $sth->execute( @query_params );
2081 my $results = $sth->fetchall_arrayref({});
2085 #------------------------------------------------------------#
2087 =head3 GetLateOrders
2089 @results = &GetLateOrders;
2091 Searches for bookseller with late orders.
2094 the table of supplier with late issues. This table is full of hashref.
2100 my $supplierid = shift;
2102 my $estimateddeliverydatefrom = shift;
2103 my $estimateddeliverydateto = shift;
2105 my $dbh = C4
::Context
->dbh;
2107 #BEWARE, order of parenthesis and LEFT JOIN is important for speed
2108 my $dbdriver = C4
::Context
->config("db_scheme") || "mysql";
2110 my @query_params = ();
2112 SELECT aqbasket.basketno,
2113 aqorders.ordernumber,
2114 DATE(aqbasket.closedate) AS orderdate,
2115 aqbasket.basketname AS basketname,
2116 aqbasket.basketgroupid AS basketgroupid,
2117 aqbasketgroups.name AS basketgroupname,
2118 aqorders.rrp AS unitpricesupplier,
2119 aqorders.ecost AS unitpricelib,
2120 aqorders.claims_count AS claims_count,
2121 aqorders.claimed_date AS claimed_date,
2122 aqbudgets.budget_name AS budget,
2123 borrowers.branchcode AS branch,
2124 aqbooksellers.name AS supplier,
2125 aqbooksellers.id AS supplierid,
2126 biblio.author, biblio.title,
2127 biblioitems.publishercode AS publisher,
2128 biblioitems.publicationyear,
2129 ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) AS estimateddeliverydate,
2133 aqorders LEFT JOIN biblio ON biblio.biblionumber = aqorders.biblionumber
2134 LEFT JOIN biblioitems ON biblioitems.biblionumber = biblio.biblionumber
2135 LEFT JOIN aqbudgets ON aqorders.budget_id = aqbudgets.budget_id,
2136 aqbasket LEFT JOIN borrowers ON aqbasket.authorisedby = borrowers.borrowernumber
2137 LEFT JOIN aqbooksellers ON aqbasket.booksellerid = aqbooksellers.id
2138 LEFT JOIN aqbasketgroups ON aqbasket.basketgroupid = aqbasketgroups.id
2139 WHERE aqorders.basketno = aqbasket.basketno
2140 AND ( datereceived = ''
2141 OR datereceived IS NULL
2142 OR aqorders.quantityreceived < aqorders.quantity
2144 AND aqbasket.closedate IS NOT NULL
2145 AND (aqorders.datecancellationprinted IS NULL OR aqorders.datecancellationprinted='0000-00-00')
2148 if ($dbdriver eq "mysql") {
2150 aqorders.quantity - COALESCE(aqorders.quantityreceived,0) AS quantity,
2151 (aqorders.quantity - COALESCE(aqorders.quantityreceived,0)) * aqorders.rrp AS subtotal,
2152 DATEDIFF(CAST(now() AS date),closedate) AS latesince
2154 if ( defined $delay ) {
2155 $from .= " AND (closedate <= DATE_SUB(CAST(now() AS date),INTERVAL ? DAY)) " ;
2156 push @query_params, $delay;
2158 $having = "HAVING quantity <> 0";
2160 # FIXME: account for IFNULL as above
2162 aqorders.quantity AS quantity,
2163 aqorders.quantity * aqorders.rrp AS subtotal,
2164 (CAST(now() AS date) - closedate) AS latesince
2166 if ( defined $delay ) {
2167 $from .= " AND (closedate <= (CAST(now() AS date) -(INTERVAL ? DAY)) ";
2168 push @query_params, $delay;
2171 if (defined $supplierid) {
2172 $from .= ' AND aqbasket.booksellerid = ? ';
2173 push @query_params, $supplierid;
2175 if (defined $branch) {
2176 $from .= ' AND borrowers.branchcode LIKE ? ';
2177 push @query_params, $branch;
2180 if ( defined $estimateddeliverydatefrom or defined $estimateddeliverydateto ) {
2181 $from .= ' AND aqbooksellers.deliverytime IS NOT NULL ';
2183 if ( defined $estimateddeliverydatefrom ) {
2184 $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) >= ?';
2185 push @query_params, $estimateddeliverydatefrom;
2187 if ( defined $estimateddeliverydateto ) {
2188 $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) <= ?';
2189 push @query_params, $estimateddeliverydateto;
2191 if ( defined $estimateddeliverydatefrom and not defined $estimateddeliverydateto ) {
2192 $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) <= CAST(now() AS date)';
2194 if (C4
::Context
->preference("IndependentBranches")
2195 && !C4
::Context
->IsSuperLibrarian() ) {
2196 $from .= ' AND borrowers.branchcode LIKE ? ';
2197 push @query_params, C4
::Context
->userenv->{branch
};
2199 $from .= " AND orderstatus <> 'cancelled' ";
2200 my $query = "$select $from $having\nORDER BY latesince, basketno, borrowers.branchcode, supplier";
2201 $debug and print STDERR
"GetLateOrders query: $query\nGetLateOrders args: " . join(" ",@query_params);
2202 my $sth = $dbh->prepare($query);
2203 $sth->execute(@query_params);
2205 while (my $data = $sth->fetchrow_hashref) {
2206 push @results, $data;
2211 #------------------------------------------------------------#
2215 \@order_loop = GetHistory( %params );
2217 Retreives some acquisition history information
2227 basket - search both basket name and number
2228 booksellerinvoicenumber
2231 orderstatus (note that orderstatus '' will retrieve orders
2232 of any status except cancelled)
2234 get_canceled_order (if set to a true value, cancelled orders will
2238 $order_loop is a list of hashrefs that each look like this:
2240 'author' => 'Twain, Mark',
2242 'biblionumber' => '215',
2244 'creationdate' => 'MM/DD/YYYY',
2245 'datereceived' => undef,
2248 'invoicenumber' => undef,
2250 'ordernumber' => '1',
2252 'quantityreceived' => undef,
2253 'title' => 'The Adventures of Huckleberry Finn'
2259 # don't run the query if there are no parameters (list would be too long for sure !)
2260 croak
"No search params" unless @_;
2262 my $title = $params{title
};
2263 my $author = $params{author
};
2264 my $isbn = $params{isbn
};
2265 my $ean = $params{ean
};
2266 my $name = $params{name
};
2267 my $from_placed_on = $params{from_placed_on
};
2268 my $to_placed_on = $params{to_placed_on
};
2269 my $basket = $params{basket
};
2270 my $booksellerinvoicenumber = $params{booksellerinvoicenumber
};
2271 my $basketgroupname = $params{basketgroupname
};
2272 my $budget = $params{budget
};
2273 my $orderstatus = $params{orderstatus
};
2274 my $biblionumber = $params{biblionumber
};
2275 my $get_canceled_order = $params{get_canceled_order
} || 0;
2276 my $ordernumber = $params{ordernumber
};
2277 my $search_children_too = $params{search_children_too
} || 0;
2278 my $created_by = $params{created_by
} || [];
2282 my $total_qtyreceived = 0;
2283 my $total_price = 0;
2285 my $dbh = C4
::Context
->dbh;
2288 COALESCE(biblio.title, deletedbiblio.title) AS title,
2289 COALESCE(biblio.author, deletedbiblio.author) AS author,
2290 COALESCE(biblioitems.isbn, deletedbiblioitems.isbn) AS isbn,
2291 COALESCE(biblioitems.ean, deletedbiblioitems.ean) AS ean,
2293 aqbasket.basketname,
2294 aqbasket.basketgroupid,
2295 aqbasket.authorisedby,
2296 concat( borrowers.firstname,' ',borrowers.surname) AS authorisedbyname,
2297 aqbasketgroups.name as groupname,
2299 aqbasket.creationdate,
2300 aqorders.datereceived,
2302 aqorders.quantityreceived,
2304 aqorders.ordernumber,
2306 aqinvoices.invoicenumber,
2307 aqbooksellers.id as id,
2308 aqorders.biblionumber,
2309 aqorders.orderstatus,
2310 aqorders.parent_ordernumber,
2311 aqbudgets.budget_name
2313 $query .= ", aqbudgets.budget_id AS budget" if defined $budget;
2316 LEFT JOIN aqbasket ON aqorders.basketno=aqbasket.basketno
2317 LEFT JOIN aqbasketgroups ON aqbasket.basketgroupid=aqbasketgroups.id
2318 LEFT JOIN aqbooksellers ON aqbasket.booksellerid=aqbooksellers.id
2319 LEFT JOIN biblioitems ON biblioitems.biblionumber=aqorders.biblionumber
2320 LEFT JOIN biblio ON biblio.biblionumber=aqorders.biblionumber
2321 LEFT JOIN aqbudgets ON aqorders.budget_id=aqbudgets.budget_id
2322 LEFT JOIN aqinvoices ON aqorders.invoiceid = aqinvoices.invoiceid
2323 LEFT JOIN deletedbiblio ON deletedbiblio.biblionumber=aqorders.biblionumber
2324 LEFT JOIN deletedbiblioitems ON deletedbiblioitems.biblionumber=aqorders.biblionumber
2325 LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber
2328 $query .= " WHERE 1 ";
2330 unless ($get_canceled_order or (defined $orderstatus and $orderstatus eq 'cancelled')) {
2331 $query .= " AND (datecancellationprinted is NULL or datecancellationprinted='0000-00-00') ";
2334 my @query_params = ();
2336 if ( $biblionumber ) {
2337 $query .= " AND biblio.biblionumber = ?";
2338 push @query_params, $biblionumber;
2342 $query .= " AND biblio.title LIKE ? ";
2343 $title =~ s/\s+/%/g;
2344 push @query_params, "%$title%";
2348 $query .= " AND biblio.author LIKE ? ";
2349 push @query_params, "%$author%";
2353 $query .= " AND biblioitems.isbn LIKE ? ";
2354 push @query_params, "%$isbn%";
2357 $query .= " AND biblioitems.ean = ? ";
2358 push @query_params, "$ean";
2361 $query .= " AND aqbooksellers.name LIKE ? ";
2362 push @query_params, "%$name%";
2366 $query .= " AND aqbudgets.budget_id = ? ";
2367 push @query_params, "$budget";
2370 if ( $from_placed_on ) {
2371 $query .= " AND creationdate >= ? ";
2372 push @query_params, $from_placed_on;
2375 if ( $to_placed_on ) {
2376 $query .= " AND creationdate <= ? ";
2377 push @query_params, $to_placed_on;
2380 if ( defined $orderstatus and $orderstatus ne '') {
2381 $query .= " AND aqorders.orderstatus = ? ";
2382 push @query_params, "$orderstatus";
2386 if ($basket =~ m/^\d+$/) {
2387 $query .= " AND aqorders.basketno = ? ";
2388 push @query_params, $basket;
2390 $query .= " AND aqbasket.basketname LIKE ? ";
2391 push @query_params, "%$basket%";
2395 if ($booksellerinvoicenumber) {
2396 $query .= " AND aqinvoices.invoicenumber LIKE ? ";
2397 push @query_params, "%$booksellerinvoicenumber%";
2400 if ($basketgroupname) {
2401 $query .= " AND aqbasketgroups.name LIKE ? ";
2402 push @query_params, "%$basketgroupname%";
2406 $query .= " AND (aqorders.ordernumber = ? ";
2407 push @query_params, $ordernumber;
2408 if ($search_children_too) {
2409 $query .= " OR aqorders.parent_ordernumber = ? ";
2410 push @query_params, $ordernumber;
2415 if ( @
$created_by ) {
2416 $query .= ' AND aqbasket.authorisedby IN ( ' . join( ',', ('?') x @
$created_by ) . ')';
2417 push @query_params, @
$created_by;
2421 if ( C4
::Context
->preference("IndependentBranches") ) {
2422 unless ( C4
::Context
->IsSuperLibrarian() ) {
2423 $query .= " AND (borrowers.branchcode = ? OR borrowers.branchcode ='' ) ";
2424 push @query_params, C4
::Context
->userenv->{branch
};
2427 $query .= " ORDER BY id";
2429 return $dbh->selectall_arrayref( $query, { Slice
=> {} }, @query_params );
2432 =head2 GetRecentAcqui
2434 $results = GetRecentAcqui($days);
2436 C<$results> is a ref to a table which containts hashref
2440 sub GetRecentAcqui
{
2442 my $dbh = C4
::Context
->dbh;
2446 ORDER BY timestamp DESC
2449 my $sth = $dbh->prepare($query);
2451 my $results = $sth->fetchall_arrayref({});
2455 #------------------------------------------------------------#
2459 &AddClaim($ordernumber);
2461 Add a claim for an order
2466 my ($ordernumber) = @_;
2467 my $dbh = C4
::Context
->dbh;
2470 claims_count = claims_count + 1,
2471 claimed_date = CURDATE()
2472 WHERE ordernumber = ?
2474 my $sth = $dbh->prepare($query);
2475 $sth->execute($ordernumber);
2480 my @invoices = GetInvoices(
2481 invoicenumber => $invoicenumber,
2482 supplierid => $supplierid,
2483 suppliername => $suppliername,
2484 shipmentdatefrom => $shipmentdatefrom, # ISO format
2485 shipmentdateto => $shipmentdateto, # ISO format
2486 billingdatefrom => $billingdatefrom, # ISO format
2487 billingdateto => $billingdateto, # ISO format
2488 isbneanissn => $isbn_or_ean_or_issn,
2491 publisher => $publisher,
2492 publicationyear => $publicationyear,
2493 branchcode => $branchcode,
2494 order_by => $order_by
2497 Return a list of invoices that match all given criteria.
2499 $order_by is "column_name (asc|desc)", where column_name is any of
2500 'invoicenumber', 'booksellerid', 'shipmentdate', 'billingdate', 'closedate',
2501 'shipmentcost', 'shipmentcost_budgetid'.
2503 asc is the default if omitted
2510 my @columns = qw(invoicenumber booksellerid shipmentdate billingdate
2511 closedate shipmentcost shipmentcost_budgetid);
2513 my $dbh = C4
::Context
->dbh;
2515 SELECT aqinvoices
.*, aqbooksellers
.name AS suppliername
,
2518 aqorders
.datereceived IS NOT NULL
,
2519 aqorders
.biblionumber
,
2522 ) AS receivedbiblios
,
2525 aqorders
.subscriptionid IS NOT NULL
,
2526 aqorders
.subscriptionid
,
2529 ) AS is_linked_to_subscriptions
,
2530 SUM
(aqorders
.quantityreceived
) AS receiveditems
2532 LEFT JOIN aqbooksellers ON aqbooksellers
.id
= aqinvoices
.booksellerid
2533 LEFT JOIN aqorders ON aqorders
.invoiceid
= aqinvoices
.invoiceid
2534 LEFT JOIN aqbasket ON aqbasket
.basketno
=aqorders
.basketno
2535 LEFT JOIN borrowers ON aqbasket
.authorisedby
=borrowers
.borrowernumber
2536 LEFT JOIN biblio ON aqorders
.biblionumber
= biblio
.biblionumber
2537 LEFT JOIN biblioitems ON biblio
.biblionumber
= biblioitems
.biblionumber
2538 LEFT JOIN subscription ON biblio
.biblionumber
= subscription
.biblionumber
2543 if($args{supplierid
}) {
2544 push @bind_strs, " aqinvoices.booksellerid = ? ";
2545 push @bind_args, $args{supplierid
};
2547 if($args{invoicenumber
}) {
2548 push @bind_strs, " aqinvoices.invoicenumber LIKE ? ";
2549 push @bind_args, "%$args{invoicenumber}%";
2551 if($args{suppliername
}) {
2552 push @bind_strs, " aqbooksellers.name LIKE ? ";
2553 push @bind_args, "%$args{suppliername}%";
2555 if($args{shipmentdatefrom
}) {
2556 push @bind_strs, " aqinvoices.shipmentdate >= ? ";
2557 push @bind_args, $args{shipmentdatefrom
};
2559 if($args{shipmentdateto
}) {
2560 push @bind_strs, " aqinvoices.shipmentdate <= ? ";
2561 push @bind_args, $args{shipmentdateto
};
2563 if($args{billingdatefrom
}) {
2564 push @bind_strs, " aqinvoices.billingdate >= ? ";
2565 push @bind_args, $args{billingdatefrom
};
2567 if($args{billingdateto
}) {
2568 push @bind_strs, " aqinvoices.billingdate <= ? ";
2569 push @bind_args, $args{billingdateto
};
2571 if($args{isbneanissn
}) {
2572 push @bind_strs, " (biblioitems.isbn LIKE CONCAT('%', ?, '%') OR biblioitems.ean LIKE CONCAT('%', ?, '%') OR biblioitems.issn LIKE CONCAT('%', ?, '%') ) ";
2573 push @bind_args, $args{isbneanissn
}, $args{isbneanissn
}, $args{isbneanissn
};
2576 push @bind_strs, " biblio.title LIKE CONCAT('%', ?, '%') ";
2577 push @bind_args, $args{title
};
2580 push @bind_strs, " biblio.author LIKE CONCAT('%', ?, '%') ";
2581 push @bind_args, $args{author
};
2583 if($args{publisher
}) {
2584 push @bind_strs, " biblioitems.publishercode LIKE CONCAT('%', ?, '%') ";
2585 push @bind_args, $args{publisher
};
2587 if($args{publicationyear
}) {
2588 push @bind_strs, " ((biblioitems.publicationyear LIKE CONCAT('%', ?, '%')) OR (biblio.copyrightdate LIKE CONCAT('%', ?, '%'))) ";
2589 push @bind_args, $args{publicationyear
}, $args{publicationyear
};
2591 if($args{branchcode
}) {
2592 push @bind_strs, " borrowers.branchcode = ? ";
2593 push @bind_args, $args{branchcode
};
2595 if($args{message_id
}) {
2596 push @bind_strs, " aqinvoices.message_id = ? ";
2597 push @bind_args, $args{message_id
};
2600 $query .= " WHERE " . join(" AND ", @bind_strs) if @bind_strs;
2601 $query .= " GROUP BY aqinvoices.invoiceid ";
2603 if($args{order_by
}) {
2604 my ($column, $direction) = split / /, $args{order_by
};
2605 if(grep /^$column$/, @columns) {
2606 $direction ||= 'ASC';
2607 $query .= " ORDER BY $column $direction";
2611 my $sth = $dbh->prepare($query);
2612 $sth->execute(@bind_args);
2614 my $results = $sth->fetchall_arrayref({});
2620 my $invoice = GetInvoice($invoiceid);
2622 Get informations about invoice with given $invoiceid
2624 Return a hash filled with aqinvoices.* fields
2629 my ($invoiceid) = @_;
2632 return unless $invoiceid;
2634 my $dbh = C4
::Context
->dbh;
2640 my $sth = $dbh->prepare($query);
2641 $sth->execute($invoiceid);
2643 $invoice = $sth->fetchrow_hashref;
2647 =head3 GetInvoiceDetails
2649 my $invoice = GetInvoiceDetails($invoiceid)
2651 Return informations about an invoice + the list of related order lines
2653 Orders informations are in $invoice->{orders} (array ref)
2657 sub GetInvoiceDetails
{
2658 my ($invoiceid) = @_;
2660 if ( !defined $invoiceid ) {
2661 carp
'GetInvoiceDetails called without an invoiceid';
2665 my $dbh = C4
::Context
->dbh;
2667 SELECT aqinvoices.*, aqbooksellers.name AS suppliername
2669 LEFT JOIN aqbooksellers ON aqinvoices.booksellerid = aqbooksellers.id
2672 my $sth = $dbh->prepare($query);
2673 $sth->execute($invoiceid);
2675 my $invoice = $sth->fetchrow_hashref;
2680 biblio.copyrightdate,
2682 biblioitems.publishercode,
2683 biblioitems.publicationyear,
2684 aqbasket.basketname,
2685 aqbasketgroups.id AS basketgroupid,
2686 aqbasketgroups.name AS basketgroupname
2688 LEFT JOIN aqbasket ON aqorders.basketno = aqbasket.basketno
2689 LEFT JOIN aqbasketgroups ON aqbasket.basketgroupid = aqbasketgroups.id
2690 LEFT JOIN biblio ON aqorders.biblionumber = biblio.biblionumber
2691 LEFT JOIN biblioitems ON aqorders.biblionumber = biblioitems.biblionumber
2694 $sth = $dbh->prepare($query);
2695 $sth->execute($invoiceid);
2696 $invoice->{orders
} = $sth->fetchall_arrayref({});
2697 $invoice->{orders
} ||= []; # force an empty arrayref if fetchall_arrayref fails
2704 my $invoiceid = AddInvoice(
2705 invoicenumber => $invoicenumber,
2706 booksellerid => $booksellerid,
2707 shipmentdate => $shipmentdate,
2708 billingdate => $billingdate,
2709 closedate => $closedate,
2710 shipmentcost => $shipmentcost,
2711 shipmentcost_budgetid => $shipmentcost_budgetid
2714 Create a new invoice and return its id or undef if it fails.
2721 return unless(%invoice and $invoice{invoicenumber
});
2723 my @columns = qw(invoicenumber booksellerid shipmentdate billingdate
2724 closedate shipmentcost shipmentcost_budgetid message_id);
2728 foreach my $key (keys %invoice) {
2729 if(0 < grep(/^$key$/, @columns)) {
2730 push @set_strs, "$key = ?";
2731 push @set_args, ($invoice{$key} || undef);
2737 my $dbh = C4
::Context
->dbh;
2738 my $query = "INSERT INTO aqinvoices SET ";
2739 $query .= join (",", @set_strs);
2740 my $sth = $dbh->prepare($query);
2741 $rv = $sth->execute(@set_args);
2743 $rv = $dbh->last_insert_id(undef, undef, 'aqinvoices', undef);
2752 invoiceid => $invoiceid, # Mandatory
2753 invoicenumber => $invoicenumber,
2754 booksellerid => $booksellerid,
2755 shipmentdate => $shipmentdate,
2756 billingdate => $billingdate,
2757 closedate => $closedate,
2758 shipmentcost => $shipmentcost,
2759 shipmentcost_budgetid => $shipmentcost_budgetid
2762 Modify an invoice, invoiceid is mandatory.
2764 Return undef if it fails.
2771 return unless(%invoice and $invoice{invoiceid
});
2773 my @columns = qw(invoicenumber booksellerid shipmentdate billingdate
2774 closedate shipmentcost shipmentcost_budgetid);
2778 foreach my $key (keys %invoice) {
2779 if(0 < grep(/^$key$/, @columns)) {
2780 push @set_strs, "$key = ?";
2781 push @set_args, ($invoice{$key} || undef);
2785 my $dbh = C4
::Context
->dbh;
2786 my $query = "UPDATE aqinvoices SET ";
2787 $query .= join(",", @set_strs);
2788 $query .= " WHERE invoiceid = ?";
2790 my $sth = $dbh->prepare($query);
2791 $sth->execute(@set_args, $invoice{invoiceid
});
2796 CloseInvoice($invoiceid);
2800 Equivalent to ModInvoice(invoiceid => $invoiceid, closedate => undef);
2805 my ($invoiceid) = @_;
2807 return unless $invoiceid;
2809 my $dbh = C4
::Context
->dbh;
2812 SET closedate
= CAST
(NOW
() AS DATE
)
2815 my $sth = $dbh->prepare($query);
2816 $sth->execute($invoiceid);
2819 =head3 ReopenInvoice
2821 ReopenInvoice($invoiceid);
2825 Equivalent to ModInvoice(invoiceid => $invoiceid, closedate => output_pref({ dt=>dt_from_string, dateonly=>1, otputpref=>'iso' }))
2830 my ($invoiceid) = @_;
2832 return unless $invoiceid;
2834 my $dbh = C4
::Context
->dbh;
2837 SET closedate
= NULL
2840 my $sth = $dbh->prepare($query);
2841 $sth->execute($invoiceid);
2846 DelInvoice($invoiceid);
2848 Delete an invoice if there are no items attached to it.
2853 my ($invoiceid) = @_;
2855 return unless $invoiceid;
2857 my $dbh = C4
::Context
->dbh;
2863 my $sth = $dbh->prepare($query);
2864 $sth->execute($invoiceid);
2865 my $res = $sth->fetchrow_arrayref;
2866 if ( $res && $res->[0] == 0 ) {
2868 DELETE FROM aqinvoices
2871 my $sth = $dbh->prepare($query);
2872 return ( $sth->execute($invoiceid) > 0 );
2877 =head3 MergeInvoices
2879 MergeInvoices($invoiceid, \@sourceids);
2881 Merge the invoices identified by the IDs in \@sourceids into
2882 the invoice identified by $invoiceid.
2887 my ($invoiceid, $sourceids) = @_;
2889 return unless $invoiceid;
2890 foreach my $sourceid (@
$sourceids) {
2891 next if $sourceid == $invoiceid;
2892 my $source = GetInvoiceDetails
($sourceid);
2893 foreach my $order (@
{$source->{'orders'}}) {
2894 $order->{'invoiceid'} = $invoiceid;
2897 DelInvoice
($source->{'invoiceid'});
2902 =head3 GetBiblioCountByBasketno
2904 $biblio_count = &GetBiblioCountByBasketno($basketno);
2906 Looks up the biblio's count that has basketno value $basketno
2912 sub GetBiblioCountByBasketno
{
2913 my ($basketno) = @_;
2914 my $dbh = C4
::Context
->dbh;
2916 SELECT COUNT( DISTINCT( biblionumber ) )
2919 AND (datecancellationprinted IS NULL OR datecancellationprinted='0000-00-00')
2922 my $sth = $dbh->prepare($query);
2923 $sth->execute($basketno);
2924 return $sth->fetchrow;
2927 # Note this subroutine should be moved to Koha::Acquisition::Order
2928 # Will do when a DBIC decision will be taken.
2929 sub populate_order_with_prices
{
2932 my $order = $params->{order
};
2933 my $booksellerid = $params->{booksellerid
};
2934 return unless $booksellerid;
2936 my $bookseller = Koha
::Acquisition
::Booksellers
->find( $booksellerid );
2938 my $receiving = $params->{receiving
};
2939 my $ordering = $params->{ordering
};
2940 my $discount = $order->{discount
};
2941 $discount /= 100 if $discount > 1;
2944 $order->{tax_rate_on_ordering
} //= $order->{tax_rate
};
2945 if ( $bookseller->listincgst ) {
2946 # The user entered the rrp tax included
2947 $order->{rrp_tax_included
} = $order->{rrp
};
2949 # rrp tax excluded = rrp tax included / ( 1 + tax rate )
2950 $order->{rrp_tax_excluded
} = $order->{rrp_tax_included
} / ( 1 + $order->{tax_rate_on_ordering
} );
2952 # ecost tax excluded = rrp tax excluded * ( 1 - discount )
2953 $order->{ecost_tax_excluded
} = $order->{rrp_tax_excluded
} * ( 1 - $discount );
2955 # ecost tax included = rrp tax included ( 1 - discount )
2956 $order->{ecost_tax_included
} = $order->{rrp_tax_included
} * ( 1 - $discount );
2959 # The user entered the rrp tax excluded
2960 $order->{rrp_tax_excluded
} = $order->{rrp
};
2962 # rrp tax included = rrp tax excluded * ( 1 - tax rate )
2963 $order->{rrp_tax_included
} = $order->{rrp_tax_excluded
} * ( 1 + $order->{tax_rate_on_ordering
} );
2965 # ecost tax excluded = rrp tax excluded * ( 1 - discount )
2966 $order->{ecost_tax_excluded
} = $order->{rrp_tax_excluded
} * ( 1 - $discount );
2968 # ecost tax included = rrp tax excluded * ( 1 - tax rate ) * ( 1 - discount )
2969 $order->{ecost_tax_included
} =
2970 $order->{rrp_tax_excluded
} *
2971 ( 1 + $order->{tax_rate_on_ordering
} ) *
2975 # tax value = quantity * ecost tax excluded * tax rate
2976 $order->{tax_value_on_ordering
} =
2977 $order->{quantity
} * $order->{ecost_tax_excluded
} * $order->{tax_rate_on_ordering
};
2981 $order->{tax_rate_on_receiving
} //= $order->{tax_rate
};
2982 if ( $bookseller->invoiceincgst ) {
2983 # Trick for unitprice. If the unit price rounded value is the same as the ecost rounded value
2984 # we need to keep the exact ecost value
2985 if ( Koha
::Number
::Price
->new( $order->{unitprice
} )->round == Koha
::Number
::Price
->new( $order->{ecost_tax_included
} )->round ) {
2986 $order->{unitprice
} = $order->{ecost_tax_included
};
2989 # The user entered the unit price tax included
2990 $order->{unitprice_tax_included
} = $order->{unitprice
};
2992 # unit price tax excluded = unit price tax included / ( 1 + tax rate )
2993 $order->{unitprice_tax_excluded
} = $order->{unitprice_tax_included
} / ( 1 + $order->{tax_rate_on_receiving
} );
2996 # Trick for unitprice. If the unit price rounded value is the same as the ecost rounded value
2997 # we need to keep the exact ecost value
2998 if ( Koha
::Number
::Price
->new( $order->{unitprice
} )->round == Koha
::Number
::Price
->new( $order->{ecost_tax_excluded
} )->round ) {
2999 $order->{unitprice
} = $order->{ecost_tax_excluded
};
3002 # The user entered the unit price tax excluded
3003 $order->{unitprice_tax_excluded
} = $order->{unitprice
};
3006 # unit price tax included = unit price tax included * ( 1 + tax rate )
3007 $order->{unitprice_tax_included
} = $order->{unitprice_tax_excluded
} * ( 1 + $order->{tax_rate_on_receiving
} );
3010 # tax value = quantity * unit price tax excluded * tax rate
3011 $order->{tax_value_on_receiving
} = $order->{quantity
} * $order->{unitprice_tax_excluded
} * $order->{tax_rate_on_receiving
};
3017 =head3 GetOrderUsers
3019 $order_users_ids = &GetOrderUsers($ordernumber);
3021 Returns a list of all borrowernumbers that are in order users list
3026 my ($ordernumber) = @_;
3028 return unless $ordernumber;
3031 SELECT borrowernumber
3033 WHERE ordernumber
= ?
3035 my $dbh = C4
::Context
->dbh;
3036 my $sth = $dbh->prepare($query);
3037 $sth->execute($ordernumber);
3038 my $results = $sth->fetchall_arrayref( {} );
3040 my @borrowernumbers;
3041 foreach (@
$results) {
3042 push @borrowernumbers, $_->{'borrowernumber'};
3045 return @borrowernumbers;
3048 =head3 ModOrderUsers
3050 my @order_users_ids = (1, 2, 3);
3051 &ModOrderUsers($ordernumber, @basketusers_ids);
3053 Delete all users from order users list, and add users in C<@order_users_ids>
3059 my ( $ordernumber, @order_users_ids ) = @_;
3061 return unless $ordernumber;
3063 my $dbh = C4
::Context
->dbh;
3065 DELETE FROM aqorder_users
3066 WHERE ordernumber
= ?
3068 my $sth = $dbh->prepare($query);
3069 $sth->execute($ordernumber);
3072 INSERT INTO aqorder_users
(ordernumber
, borrowernumber
)
3075 $sth = $dbh->prepare($query);
3076 foreach my $order_user_id (@order_users_ids) {
3077 $sth->execute( $ordernumber, $order_user_id );
3081 sub NotifyOrderUsers
{
3082 my ($ordernumber) = @_;
3084 my @borrowernumbers = GetOrderUsers
($ordernumber);
3085 return unless @borrowernumbers;
3087 my $order = GetOrder
( $ordernumber );
3088 for my $borrowernumber (@borrowernumbers) {
3089 my $patron = Koha
::Patrons
->find( $borrowernumber );
3090 my $library = $patron->library->unblessed;
3091 my $biblio = Koha
::Biblios
->find( $order->{biblionumber
} )->unblessed;
3092 my $letter = C4
::Letters
::GetPreparedLetter
(
3093 module
=> 'acquisition',
3094 letter_code
=> 'ACQ_NOTIF_ON_RECEIV',
3095 branchcode
=> $library->{branchcode
},
3096 lang
=> $patron->lang,
3098 'branches' => $library,
3099 'borrowers' => $patron->unblessed,
3100 'biblio' => $biblio,
3101 'aqorders' => $order,
3105 C4
::Letters
::EnqueueLetter
(
3108 borrowernumber
=> $borrowernumber,
3109 LibraryName
=> C4
::Context
->preference("LibraryName"),
3110 message_transport_type
=> 'email',
3112 ) or warn "can't enqueue letter $letter";
3117 =head3 FillWithDefaultValues
3119 FillWithDefaultValues( $marc_record );
3121 This will update the record with default value defined in the ACQ framework.
3122 For all existing fields, if a default value exists and there are no subfield, it will be created.
3123 If the field does not exist, it will be created too.
3127 sub FillWithDefaultValues
{
3129 my $tagslib = C4
::Biblio
::GetMarcStructure
( 1, 'ACQ', { unsafe
=> 1 } );
3132 C4
::Biblio
::GetMarcFromKohaField
( 'items.itemnumber', '' );
3133 for my $tag ( sort keys %$tagslib ) {
3135 next if $tag == $itemfield;
3136 for my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
3137 next if IsMarcStructureInternal
($tagslib->{$tag}{$subfield});
3138 my $defaultvalue = $tagslib->{$tag}{$subfield}{defaultvalue
};
3139 if ( defined $defaultvalue and $defaultvalue ne '' ) {
3140 my @fields = $record->field($tag);
3142 for my $field (@fields) {
3143 unless ( defined $field->subfield($subfield) ) {
3144 $field->add_subfields(
3145 $subfield => $defaultvalue );
3150 $record->insert_fields_ordered(
3152 $tag, '', '', $subfield => $defaultvalue
3167 Koha Development Team <http://koha-community.org/>