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
;
36 use Koha
::CsvProfiles
;
45 use vars
qw(@ISA @EXPORT);
51 &GetBasket &NewBasket &CloseBasket &ReopenBasket &DelBasket &ModBasket
52 &GetBasketAsCSV &GetBasketGroupAsCSV
53 &GetBasketsByBookseller &GetBasketsByBasketgroup
54 &GetBasketsInfosByBookseller
56 &GetBasketUsers &ModBasketUsers
61 &ModBasketgroup &NewBasketgroup &DelBasketgroup &GetBasketgroup &CloseBasketgroup
62 &GetBasketgroups &ReOpenBasketgroup
64 &DelOrder &ModOrder &GetOrder &GetOrders &GetOrdersByBiblionumber
65 &GetLateOrders &GetOrderFromItemnumber
66 &SearchOrders &GetHistory &GetRecentAcqui
67 &ModReceiveOrder &CancelReceipt
69 &GetLastOrderNotReceivedFromSubscriptionid &GetLastOrderReceivedFromSubscriptionid
84 &GetItemnumbersFromOrder
87 &GetBiblioCountByBasketno
93 &FillWithDefaultValues
101 sub GetOrderFromItemnumber
{
102 my ($itemnumber) = @_;
103 my $dbh = C4
::Context
->dbh;
106 SELECT
* from aqorders LEFT JOIN aqorders_items
107 ON
( aqorders
.ordernumber
= aqorders_items
.ordernumber
)
108 WHERE itemnumber
= ?
|;
110 my $sth = $dbh->prepare($query);
114 $sth->execute($itemnumber);
116 my $order = $sth->fetchrow_hashref;
121 # Returns the itemnumber(s) associated with the ordernumber given in parameter
122 sub GetItemnumbersFromOrder
{
123 my ($ordernumber) = @_;
124 my $dbh = C4
::Context
->dbh;
125 my $query = "SELECT itemnumber FROM aqorders_items WHERE ordernumber=?";
126 my $sth = $dbh->prepare($query);
127 $sth->execute($ordernumber);
130 while (my $order = $sth->fetchrow_hashref) {
131 push @tab, $order->{'itemnumber'};
145 C4::Acquisition - Koha functions for dealing with orders and acquisitions
153 The functions in this module deal with acquisitions, managing book
154 orders, basket and parcels.
158 =head2 FUNCTIONS ABOUT BASKETS
162 $aqbasket = &GetBasket($basketnumber);
164 get all basket informations in aqbasket for a given basket
166 B<returns:> informations for a given basket returned as a hashref.
172 my $dbh = C4
::Context
->dbh;
175 concat( b.firstname,' ',b.surname) AS authorisedbyname
177 LEFT JOIN borrowers b ON aqbasket.authorisedby=b.borrowernumber
180 my $sth=$dbh->prepare($query);
181 $sth->execute($basketno);
182 my $basket = $sth->fetchrow_hashref;
186 #------------------------------------------------------------#
190 $basket = &NewBasket( $booksellerid, $authorizedby, $basketname,
191 $basketnote, $basketbooksellernote, $basketcontractnumber, $deliveryplace, $billingplace, $is_standing );
193 Create a new basket in aqbasket table
197 =item C<$booksellerid> is a foreign key in the aqbasket table
199 =item C<$authorizedby> is the username of who created the basket
203 The other parameters are optional, see ModBasketHeader for more info on them.
208 my ( $booksellerid, $authorisedby, $basketname, $basketnote,
209 $basketbooksellernote, $basketcontractnumber, $deliveryplace,
210 $billingplace, $is_standing ) = @_;
211 my $dbh = C4
::Context
->dbh;
213 'INSERT INTO aqbasket (creationdate,booksellerid,authorisedby) '
214 . 'VALUES (now(),?,?)';
215 $dbh->do( $query, {}, $booksellerid, $authorisedby );
217 my $basket = $dbh->{mysql_insertid
};
218 $basketname ||= q{}; # default to empty strings
220 $basketbooksellernote ||= q{};
221 ModBasketHeader
( $basket, $basketname, $basketnote, $basketbooksellernote,
222 $basketcontractnumber, $booksellerid, $deliveryplace, $billingplace, $is_standing );
226 #------------------------------------------------------------#
230 &CloseBasket($basketno);
232 close a basket (becomes unmodifiable, except for receives)
238 my $dbh = C4
::Context
->dbh;
239 $dbh->do('UPDATE aqbasket SET closedate=now() WHERE basketno=?', {}, $basketno );
241 $dbh->do( q{UPDATE aqorders SET orderstatus = 'ordered' WHERE basketno = ? AND orderstatus != 'complete'},
248 &ReopenBasket($basketno);
256 my $dbh = C4
::Context
->dbh;
257 $dbh->do( q{UPDATE aqbasket SET closedate=NULL WHERE basketno=?}, {}, $basketno );
261 SET orderstatus = 'new'
263 AND orderstatus != 'complete'
268 #------------------------------------------------------------#
270 =head3 GetBasketAsCSV
272 &GetBasketAsCSV($basketno);
274 Export a basket as CSV
276 $cgi parameter is needed for column name translation
281 my ($basketno, $cgi, $csv_profile_id) = @_;
282 my $basket = GetBasket
($basketno);
283 my @orders = GetOrders
($basketno);
284 my $contract = GetContract
({
285 contractnumber
=> $basket->{'contractnumber'}
288 my $template = C4
::Templates
::gettemplate
("acqui/csv/basket.tt", "intranet", $cgi);
290 if ($csv_profile_id) {
291 my $csv_profile = Koha
::CsvProfiles
->find( $csv_profile_id );
292 die "There is no valid csv profile given" unless $csv_profile;
294 my $csv = Text
::CSV_XS
->new({'quote_char'=>'"','escape_char'=>'"','sep_char'=>$csv_profile->csv_separator,'binary'=>1});
295 my $csv_profile_content = $csv_profile->content;
296 my ( @headers, @fields );
297 while ( $csv_profile_content =~ /
300 ([^\
|]*) # fieldname (table.row or row)
304 my $field = ($2 eq '') ?
$1 : $2;
306 $header =~ s/^\s+|\s+$//g; # Trim whitespaces
307 push @headers, $header;
309 $field =~ s/[^\.]*\.{1}//; # Remove the table name if exists.
310 $field =~ s/^\s+|\s+$//g; # Trim whitespaces
311 push @fields, $field;
313 for my $order (@orders) {
315 my $bd = GetBiblioData
( $order->{'biblionumber'} );
316 my @biblioitems = GetBiblioItemByBiblioNumber
( $order->{'biblionumber'});
317 for my $biblioitem (@biblioitems) {
318 if ( $biblioitem->{isbn
}
320 and $biblioitem->{isbn
} eq $order->{isbn
} )
322 $order = { %$order, %$biblioitem };
326 $order = {%$order, %$contract};
328 $order = {%$order, %$basket, %$bd};
329 for my $field (@fields) {
330 push @row, $order->{$field};
334 my $content = join( $csv_profile->csv_separator, @headers ) . "\n";
335 for my $row ( @rows ) {
336 $csv->combine(@
$row);
337 my $string = $csv->string;
338 $content .= $string . "\n";
343 foreach my $order (@orders) {
344 my $bd = GetBiblioData
( $order->{'biblionumber'} );
346 contractname
=> $contract->{'contractname'},
347 ordernumber
=> $order->{'ordernumber'},
348 entrydate
=> $order->{'entrydate'},
349 isbn
=> $order->{'isbn'},
350 author
=> $bd->{'author'},
351 title
=> $bd->{'title'},
352 publicationyear
=> $bd->{'publicationyear'},
353 publishercode
=> $bd->{'publishercode'},
354 collectiontitle
=> $bd->{'collectiontitle'},
355 notes
=> $order->{'order_vendornote'},
356 quantity
=> $order->{'quantity'},
357 rrp
=> $order->{'rrp'},
359 for my $place ( qw( deliveryplace billingplace ) ) {
360 if ( my $library = Koha
::Libraries
->find( $row->{deliveryplace
} ) ) {
361 $row->{$place} = $library->branchname
365 contractname author title publishercode collectiontitle notes
366 deliveryplace billingplace
368 # Double the quotes to not be interpreted as a field end
369 $row->{$_} =~ s/"/""/g if $row->{$_};
375 if(defined $a->{publishercode
} and defined $b->{publishercode
}) {
376 $a->{publishercode
} cmp $b->{publishercode
};
380 $template->param(rows
=> \
@rows);
382 return $template->output;
387 =head3 GetBasketGroupAsCSV
389 &GetBasketGroupAsCSV($basketgroupid);
391 Export a basket group as CSV
393 $cgi parameter is needed for column name translation
397 sub GetBasketGroupAsCSV
{
398 my ($basketgroupid, $cgi) = @_;
399 my $baskets = GetBasketsByBasketgroup
($basketgroupid);
401 my $template = C4
::Templates
::gettemplate
('acqui/csv/basketgroup.tt', 'intranet', $cgi);
404 for my $basket (@
$baskets) {
405 my @orders = GetOrders
( $basket->{basketno
} );
406 my $contract = GetContract
({
407 contractnumber
=> $basket->{contractnumber
}
409 my $bookseller = Koha
::Acquisition
::Booksellers
->find( $basket->{booksellerid
} );
410 my $basketgroup = GetBasketgroup
( $$basket{basketgroupid
} );
412 foreach my $order (@orders) {
413 my $bd = GetBiblioData
( $order->{'biblionumber'} );
415 clientnumber
=> $bookseller->accountnumber,
416 basketname
=> $basket->{basketname
},
417 ordernumber
=> $order->{ordernumber
},
418 author
=> $bd->{author
},
419 title
=> $bd->{title
},
420 publishercode
=> $bd->{publishercode
},
421 publicationyear
=> $bd->{publicationyear
},
422 collectiontitle
=> $bd->{collectiontitle
},
423 isbn
=> $order->{isbn
},
424 quantity
=> $order->{quantity
},
425 rrp_tax_included
=> $order->{rrp_tax_included
},
426 rrp_tax_excluded
=> $order->{rrp_tax_excluded
},
427 discount
=> $bookseller->discount,
428 ecost_tax_included
=> $order->{ecost_tax_included
},
429 ecost_tax_excluded
=> $order->{ecost_tax_excluded
},
430 notes
=> $order->{order_vendornote
},
431 entrydate
=> $order->{entrydate
},
432 booksellername
=> $bookseller->name,
433 bookselleraddress
=> $bookseller->address1,
434 booksellerpostal
=> $bookseller->postal,
435 contractnumber
=> $contract->{contractnumber
},
436 contractname
=> $contract->{contractname
},
439 basketgroupdeliveryplace
=> $basketgroup->{deliveryplace
},
440 basketgroupbillingplace
=> $basketgroup->{billingplace
},
441 basketdeliveryplace
=> $basket->{deliveryplace
},
442 basketbillingplace
=> $basket->{billingplace
},
444 for my $place (qw( basketgroupdeliveryplace basketgroupbillingplace basketdeliveryplace basketbillingplace )) {
445 if ( my $library = Koha
::Libraries
->find( $temp->{$place} ) ) {
446 $row->{$place} = $library->branchname;
450 basketname author title publishercode collectiontitle notes
451 booksellername bookselleraddress booksellerpostal contractname
452 basketgroupdeliveryplace basketgroupbillingplace
453 basketdeliveryplace basketbillingplace
455 # Double the quotes to not be interpreted as a field end
456 $row->{$_} =~ s/"/""/g if $row->{$_};
461 $template->param(rows
=> \
@rows);
463 return $template->output;
467 =head3 CloseBasketgroup
469 &CloseBasketgroup($basketgroupno);
475 sub CloseBasketgroup
{
476 my ($basketgroupno) = @_;
477 my $dbh = C4
::Context
->dbh;
478 my $sth = $dbh->prepare("
479 UPDATE aqbasketgroups
483 $sth->execute($basketgroupno);
486 #------------------------------------------------------------#
488 =head3 ReOpenBaskergroup($basketgroupno)
490 &ReOpenBaskergroup($basketgroupno);
496 sub ReOpenBasketgroup
{
497 my ($basketgroupno) = @_;
498 my $dbh = C4
::Context
->dbh;
499 my $sth = $dbh->prepare("
500 UPDATE aqbasketgroups
504 $sth->execute($basketgroupno);
507 #------------------------------------------------------------#
512 &DelBasket($basketno);
514 Deletes the basket that has basketno field $basketno in the aqbasket table.
518 =item C<$basketno> is the primary key of the basket in the aqbasket table.
525 my ( $basketno ) = @_;
526 my $query = "DELETE FROM aqbasket WHERE basketno=?";
527 my $dbh = C4
::Context
->dbh;
528 my $sth = $dbh->prepare($query);
529 $sth->execute($basketno);
533 #------------------------------------------------------------#
537 &ModBasket($basketinfo);
539 Modifies a basket, using a hashref $basketinfo for the relevant information, only $basketinfo->{'basketno'} is required.
543 =item C<$basketno> is the primary key of the basket in the aqbasket table.
550 my $basketinfo = shift;
551 my $query = "UPDATE aqbasket SET ";
553 foreach my $key (keys %$basketinfo){
554 if ($key ne 'basketno'){
555 $query .= "$key=?, ";
556 push(@params, $basketinfo->{$key} || undef );
559 # get rid of the "," at the end of $query
560 if (substr($query, length($query)-2) eq ', '){
565 $query .= "WHERE basketno=?";
566 push(@params, $basketinfo->{'basketno'});
567 my $dbh = C4
::Context
->dbh;
568 my $sth = $dbh->prepare($query);
569 $sth->execute(@params);
574 #------------------------------------------------------------#
576 =head3 ModBasketHeader
578 &ModBasketHeader($basketno, $basketname, $note, $booksellernote, $contractnumber, $booksellerid);
580 Modifies a basket's header.
584 =item C<$basketno> is the "basketno" field in the "aqbasket" table;
586 =item C<$basketname> is the "basketname" field in the "aqbasket" table;
588 =item C<$note> is the "note" field in the "aqbasket" table;
590 =item C<$booksellernote> is the "booksellernote" field in the "aqbasket" table;
592 =item C<$contractnumber> is the "contractnumber" (foreign) key in the "aqbasket" table.
594 =item C<$booksellerid> is the id (foreign) key in the "aqbooksellers" table for the vendor.
596 =item C<$deliveryplace> is the "deliveryplace" field in the aqbasket table.
598 =item C<$billingplace> is the "billingplace" field in the aqbasket table.
600 =item C<$is_standing> is the "is_standing" field in the aqbasket table.
606 sub ModBasketHeader
{
607 my ($basketno, $basketname, $note, $booksellernote, $contractnumber, $booksellerid, $deliveryplace, $billingplace, $is_standing) = @_;
610 SET basketname
=?
, note
=?
, booksellernote
=?
, booksellerid
=?
, deliveryplace
=?
, billingplace
=?
, is_standing
=?
614 my $dbh = C4
::Context
->dbh;
615 my $sth = $dbh->prepare($query);
616 $sth->execute($basketname, $note, $booksellernote, $booksellerid, $deliveryplace, $billingplace, $is_standing, $basketno);
618 if ( $contractnumber ) {
619 my $query2 ="UPDATE aqbasket SET contractnumber=? WHERE basketno=?";
620 my $sth2 = $dbh->prepare($query2);
621 $sth2->execute($contractnumber,$basketno);
626 #------------------------------------------------------------#
628 =head3 GetBasketsByBookseller
630 @results = &GetBasketsByBookseller($booksellerid, $extra);
632 Returns a list of hashes of all the baskets that belong to bookseller 'booksellerid'.
636 =item C<$booksellerid> is the 'id' field of the bookseller in the aqbooksellers table
638 =item C<$extra> is the extra sql parameters, can be
640 $extra->{groupby}: group baskets by column
641 ex. $extra->{groupby} = aqbasket.basketgroupid
642 $extra->{orderby}: order baskets by column
643 $extra->{limit}: limit number of results (can be helpful for pagination)
649 sub GetBasketsByBookseller
{
650 my ($booksellerid, $extra) = @_;
651 my $query = "SELECT * FROM aqbasket WHERE booksellerid=?";
653 if ($extra->{groupby
}) {
654 $query .= " GROUP by $extra->{groupby}";
656 if ($extra->{orderby
}){
657 $query .= " ORDER by $extra->{orderby}";
659 if ($extra->{limit
}){
660 $query .= " LIMIT $extra->{limit}";
663 my $dbh = C4
::Context
->dbh;
664 my $sth = $dbh->prepare($query);
665 $sth->execute($booksellerid);
666 return $sth->fetchall_arrayref({});
669 =head3 GetBasketsInfosByBookseller
671 my $baskets = GetBasketsInfosByBookseller($supplierid, $allbaskets);
673 The optional second parameter allbaskets is a boolean allowing you to
674 select all baskets from the supplier; by default only active baskets (open or
675 closed but still something to receive) are returned.
677 Returns in a arrayref of hashref all about booksellers baskets, plus:
678 total_biblios: Number of distinct biblios in basket
679 total_items: Number of items in basket
680 expected_items: Number of non-received items in basket
684 sub GetBasketsInfosByBookseller
{
685 my ($supplierid, $allbaskets) = @_;
687 return unless $supplierid;
689 my $dbh = C4
::Context
->dbh;
692 SUM(aqorders.quantity) AS total_items,
694 IF ( aqorders.orderstatus = 'cancelled', aqorders.quantity, 0 )
695 ) AS total_items_cancelled,
696 COUNT(DISTINCT aqorders.biblionumber) AS total_biblios,
698 IF(aqorders.datereceived IS NULL
699 AND aqorders.datecancellationprinted IS NULL
704 LEFT JOIN aqorders ON aqorders.basketno = aqbasket.basketno
705 WHERE booksellerid = ?};
707 unless ( $allbaskets ) {
708 $query.=" AND (closedate IS NULL OR (aqorders.quantity > aqorders.quantityreceived AND datecancellationprinted IS NULL))";
710 $query.=" GROUP BY aqbasket.basketno";
712 my $sth = $dbh->prepare($query);
713 $sth->execute($supplierid);
714 my $baskets = $sth->fetchall_arrayref({});
716 # Retrieve the number of biblios cancelled
717 my $cancelled_biblios = $dbh->selectall_hashref( q
|
718 SELECT COUNT
(DISTINCT
(biblionumber
)) AS total_biblios_cancelled
, aqbasket
.basketno
720 LEFT JOIN aqorders ON aqorders
.basketno
= aqbasket
.basketno
721 WHERE booksellerid
= ?
722 AND aqorders
.orderstatus
= 'cancelled'
723 GROUP BY aqbasket
.basketno
724 |, 'basketno', {}, $supplierid );
726 $_->{total_biblios_cancelled
} = $cancelled_biblios->{$_->{basketno
}}{total_biblios_cancelled
} || 0
732 =head3 GetBasketUsers
734 $basketusers_ids = &GetBasketUsers($basketno);
736 Returns a list of all borrowernumbers that are in basket users list
741 my $basketno = shift;
743 return unless $basketno;
746 SELECT borrowernumber
750 my $dbh = C4
::Context
->dbh;
751 my $sth = $dbh->prepare($query);
752 $sth->execute($basketno);
753 my $results = $sth->fetchall_arrayref( {} );
756 foreach (@
$results) {
757 push @borrowernumbers, $_->{'borrowernumber'};
760 return @borrowernumbers;
763 =head3 ModBasketUsers
765 my @basketusers_ids = (1, 2, 3);
766 &ModBasketUsers($basketno, @basketusers_ids);
768 Delete all users from basket users list, and add users in C<@basketusers_ids>
774 my ($basketno, @basketusers_ids) = @_;
776 return unless $basketno;
778 my $dbh = C4
::Context
->dbh;
780 DELETE FROM aqbasketusers
783 my $sth = $dbh->prepare($query);
784 $sth->execute($basketno);
787 INSERT INTO aqbasketusers
(basketno
, borrowernumber
)
790 $sth = $dbh->prepare($query);
791 foreach my $basketuser_id (@basketusers_ids) {
792 $sth->execute($basketno, $basketuser_id);
797 =head3 CanUserManageBasket
799 my $bool = CanUserManageBasket($borrower, $basket[, $userflags]);
800 my $bool = CanUserManageBasket($borrowernumber, $basketno[, $userflags]);
802 Check if a borrower can manage a basket, according to system preference
803 AcqViewBaskets, user permissions and basket properties (creator, users list,
806 First parameter can be either a borrowernumber or a hashref as returned by
807 C4::Members::GetMember.
809 Second parameter can be either a basketno or a hashref as returned by
810 C4::Acquisition::GetBasket.
812 The third parameter is optional. If given, it should be a hashref as returned
813 by C4::Auth::getuserflags. If not, getuserflags is called.
815 If user is authorised to manage basket, returns 1.
820 sub CanUserManageBasket
{
821 my ($borrower, $basket, $userflags) = @_;
823 if (!ref $borrower) {
824 $borrower = C4
::Members
::GetMember
(borrowernumber
=> $borrower);
827 $basket = GetBasket
($basket);
830 return 0 unless ($basket and $borrower);
832 my $borrowernumber = $borrower->{borrowernumber
};
833 my $basketno = $basket->{basketno
};
835 my $AcqViewBaskets = C4
::Context
->preference('AcqViewBaskets');
837 if (!defined $userflags) {
838 my $dbh = C4
::Context
->dbh;
839 my $sth = $dbh->prepare("SELECT flags FROM borrowers WHERE borrowernumber = ?");
840 $sth->execute($borrowernumber);
841 my ($flags) = $sth->fetchrow_array;
844 $userflags = C4
::Auth
::getuserflags
($flags, $borrower->{userid
}, $dbh);
847 unless ($userflags->{superlibrarian
}
848 || (ref $userflags->{acquisition
} && $userflags->{acquisition
}->{order_manage_all
})
849 || (!ref $userflags->{acquisition
} && $userflags->{acquisition
}))
851 if (not exists $userflags->{acquisition
}) {
855 if ( (ref $userflags->{acquisition
} && !$userflags->{acquisition
}->{order_manage
})
856 || (!ref $userflags->{acquisition
} && !$userflags->{acquisition
}) ) {
860 if ($AcqViewBaskets eq 'user'
861 && $basket->{authorisedby
} != $borrowernumber
862 && grep($borrowernumber, GetBasketUsers
($basketno)) == 0) {
866 if ($AcqViewBaskets eq 'branch' && defined $basket->{branch
}
867 && $basket->{branch
} ne $borrower->{branchcode
}) {
875 #------------------------------------------------------------#
877 =head3 GetBasketsByBasketgroup
879 $baskets = &GetBasketsByBasketgroup($basketgroupid);
881 Returns a reference to all baskets that belong to basketgroup $basketgroupid.
885 sub GetBasketsByBasketgroup
{
886 my $basketgroupid = shift;
888 SELECT
*, aqbasket
.booksellerid as booksellerid
890 LEFT JOIN aqcontract USING
(contractnumber
) WHERE basketgroupid
=?
892 my $dbh = C4
::Context
->dbh;
893 my $sth = $dbh->prepare($query);
894 $sth->execute($basketgroupid);
895 return $sth->fetchall_arrayref({});
898 #------------------------------------------------------------#
900 =head3 NewBasketgroup
902 $basketgroupid = NewBasketgroup(\%hashref);
904 Adds a basketgroup to the aqbasketgroups table, and add the initial baskets to it.
906 $hashref->{'booksellerid'} is the 'id' field of the bookseller in the aqbooksellers table,
908 $hashref->{'name'} is the 'name' field of the basketgroup in the aqbasketgroups table,
910 $hashref->{'basketlist'} is a list reference of the 'id's of the baskets that belong to this group,
912 $hashref->{'billingplace'} is the 'billingplace' field of the basketgroup in the aqbasketgroups table,
914 $hashref->{'deliveryplace'} is the 'deliveryplace' field of the basketgroup in the aqbasketgroups table,
916 $hashref->{'freedeliveryplace'} is the 'freedeliveryplace' field of the basketgroup in the aqbasketgroups table,
918 $hashref->{'deliverycomment'} is the 'deliverycomment' field of the basketgroup in the aqbasketgroups table,
920 $hashref->{'closed'} is the 'closed' field of the aqbasketgroups table, it is false if 0, true otherwise.
925 my $basketgroupinfo = shift;
926 die "booksellerid is required to create a basketgroup" unless $basketgroupinfo->{'booksellerid'};
927 my $query = "INSERT INTO aqbasketgroups (";
929 foreach my $field (qw(name billingplace deliveryplace freedeliveryplace deliverycomment closed)) {
930 if ( defined $basketgroupinfo->{$field} ) {
931 $query .= "$field, ";
932 push(@params, $basketgroupinfo->{$field});
935 $query .= "booksellerid) VALUES (";
940 push(@params, $basketgroupinfo->{'booksellerid'});
941 my $dbh = C4
::Context
->dbh;
942 my $sth = $dbh->prepare($query);
943 $sth->execute(@params);
944 my $basketgroupid = $dbh->{'mysql_insertid'};
945 if( $basketgroupinfo->{'basketlist'} ) {
946 foreach my $basketno (@
{$basketgroupinfo->{'basketlist'}}) {
947 my $query2 = "UPDATE aqbasket SET basketgroupid=? WHERE basketno=?";
948 my $sth2 = $dbh->prepare($query2);
949 $sth2->execute($basketgroupid, $basketno);
952 return $basketgroupid;
955 #------------------------------------------------------------#
957 =head3 ModBasketgroup
959 ModBasketgroup(\%hashref);
961 Modifies a basketgroup in the aqbasketgroups table, and add the baskets to it.
963 $hashref->{'id'} is the 'id' field of the basketgroup in the aqbasketgroup table, this parameter is mandatory,
965 $hashref->{'name'} is the 'name' field of the basketgroup in the aqbasketgroups table,
967 $hashref->{'basketlist'} is a list reference of the 'id's of the baskets that belong to this group,
969 $hashref->{'billingplace'} is the 'billingplace' field of the basketgroup in the aqbasketgroups table,
971 $hashref->{'deliveryplace'} is the 'deliveryplace' field of the basketgroup in the aqbasketgroups table,
973 $hashref->{'freedeliveryplace'} is the 'freedeliveryplace' field of the basketgroup in the aqbasketgroups table,
975 $hashref->{'deliverycomment'} is the 'deliverycomment' field of the basketgroup in the aqbasketgroups table,
977 $hashref->{'closed'} is the 'closed' field of the aqbasketgroups table, it is false if 0, true otherwise.
982 my $basketgroupinfo = shift;
983 die "basketgroup id is required to edit a basketgroup" unless $basketgroupinfo->{'id'};
984 my $dbh = C4
::Context
->dbh;
985 my $query = "UPDATE aqbasketgroups SET ";
987 foreach my $field (qw(name billingplace deliveryplace freedeliveryplace deliverycomment closed)) {
988 if ( defined $basketgroupinfo->{$field} ) {
989 $query .= "$field=?, ";
990 push(@params, $basketgroupinfo->{$field});
995 $query .= " WHERE id=?";
996 push(@params, $basketgroupinfo->{'id'});
997 my $sth = $dbh->prepare($query);
998 $sth->execute(@params);
1000 $sth = $dbh->prepare('UPDATE aqbasket SET basketgroupid = NULL WHERE basketgroupid = ?');
1001 $sth->execute($basketgroupinfo->{'id'});
1003 if($basketgroupinfo->{'basketlist'} && @
{$basketgroupinfo->{'basketlist'}}){
1004 $sth = $dbh->prepare("UPDATE aqbasket SET basketgroupid=? WHERE basketno=?");
1005 foreach my $basketno (@
{$basketgroupinfo->{'basketlist'}}) {
1006 $sth->execute($basketgroupinfo->{'id'}, $basketno);
1012 #------------------------------------------------------------#
1014 =head3 DelBasketgroup
1016 DelBasketgroup($basketgroupid);
1018 Deletes a basketgroup in the aqbasketgroups table, and removes the reference to it from the baskets,
1022 =item C<$basketgroupid> is the 'id' field of the basket in the aqbasketgroup table
1028 sub DelBasketgroup
{
1029 my $basketgroupid = shift;
1030 die "basketgroup id is required to edit a basketgroup" unless $basketgroupid;
1031 my $query = "DELETE FROM aqbasketgroups WHERE id=?";
1032 my $dbh = C4
::Context
->dbh;
1033 my $sth = $dbh->prepare($query);
1034 $sth->execute($basketgroupid);
1038 #------------------------------------------------------------#
1041 =head2 FUNCTIONS ABOUT ORDERS
1043 =head3 GetBasketgroup
1045 $basketgroup = &GetBasketgroup($basketgroupid);
1047 Returns a reference to the hash containing all information about the basketgroup.
1051 sub GetBasketgroup
{
1052 my $basketgroupid = shift;
1053 die "basketgroup id is required to edit a basketgroup" unless $basketgroupid;
1054 my $dbh = C4
::Context
->dbh;
1055 my $result_set = $dbh->selectall_arrayref(
1056 'SELECT * FROM aqbasketgroups WHERE id=?',
1060 return $result_set->[0]; # id is unique
1063 #------------------------------------------------------------#
1065 =head3 GetBasketgroups
1067 $basketgroups = &GetBasketgroups($booksellerid);
1069 Returns a reference to the array of all the basketgroups of bookseller $booksellerid.
1073 sub GetBasketgroups
{
1074 my $booksellerid = shift;
1075 die 'bookseller id is required to edit a basketgroup' unless $booksellerid;
1076 my $query = 'SELECT * FROM aqbasketgroups WHERE booksellerid=? ORDER BY id DESC';
1077 my $dbh = C4
::Context
->dbh;
1078 my $sth = $dbh->prepare($query);
1079 $sth->execute($booksellerid);
1080 return $sth->fetchall_arrayref({});
1083 #------------------------------------------------------------#
1085 =head2 FUNCTIONS ABOUT ORDERS
1089 @orders = &GetOrders( $basketno, { orderby => 'biblio.title', cancelled => 0|1 } );
1091 Looks up the pending (non-cancelled) orders with the given basket
1094 If cancelled is set, only cancelled orders will be returned.
1099 my ( $basketno, $params ) = @_;
1101 return () unless $basketno;
1103 my $orderby = $params->{orderby
};
1104 my $cancelled = $params->{cancelled
} || 0;
1106 my $dbh = C4
::Context
->dbh;
1108 SELECT biblio
.*,biblioitems
.*,
1112 $query .= $cancelled
1114 aqorders_transfers
.ordernumber_to AS transferred_to
,
1115 aqorders_transfers
.timestamp AS transferred_to_timestamp
1118 aqorders_transfers
.ordernumber_from AS transferred_from
,
1119 aqorders_transfers
.timestamp AS transferred_from_timestamp
1123 LEFT JOIN aqbudgets ON aqbudgets
.budget_id
= aqorders
.budget_id
1124 LEFT JOIN biblio ON biblio
.biblionumber
= aqorders
.biblionumber
1125 LEFT JOIN biblioitems ON biblioitems
.biblionumber
=biblio
.biblionumber
1127 $query .= $cancelled
1129 LEFT JOIN aqorders_transfers ON aqorders_transfers
.ordernumber_from
= aqorders
.ordernumber
1132 LEFT JOIN aqorders_transfers ON aqorders_transfers
.ordernumber_to
= aqorders
.ordernumber
1140 $orderby ||= q
|biblioitems
.publishercode
, biblio
.title
|;
1142 AND
(datecancellationprinted IS NOT NULL
1143 AND datecancellationprinted
<> '0000-00-00')
1148 q
|aqorders
.datecancellationprinted desc
, aqorders
.timestamp desc
|;
1150 AND
(datecancellationprinted IS NULL OR datecancellationprinted
='0000-00-00')
1154 $query .= " ORDER BY $orderby";
1156 $dbh->selectall_arrayref( $query, { Slice
=> {} }, $basketno );
1161 #------------------------------------------------------------#
1163 =head3 GetOrdersByBiblionumber
1165 @orders = &GetOrdersByBiblionumber($biblionumber);
1167 Looks up the orders with linked to a specific $biblionumber, including
1168 cancelled orders and received orders.
1171 C<@orders> is an array of references-to-hash, whose keys are the
1172 fields from the aqorders, biblio, and biblioitems tables in the Koha database.
1176 sub GetOrdersByBiblionumber
{
1177 my $biblionumber = shift;
1178 return unless $biblionumber;
1179 my $dbh = C4
::Context
->dbh;
1181 SELECT biblio.*,biblioitems.*,
1185 LEFT JOIN aqbudgets ON aqbudgets.budget_id = aqorders.budget_id
1186 LEFT JOIN biblio ON biblio.biblionumber = aqorders.biblionumber
1187 LEFT JOIN biblioitems ON biblioitems.biblionumber =biblio.biblionumber
1188 WHERE aqorders.biblionumber=?
1191 $dbh->selectall_arrayref( $query, { Slice
=> {} }, $biblionumber );
1192 return @
{$result_set};
1196 #------------------------------------------------------------#
1200 $order = &GetOrder($ordernumber);
1202 Looks up an order by order number.
1204 Returns a reference-to-hash describing the order. The keys of
1205 C<$order> are fields from the biblio, biblioitems, aqorders tables of the Koha database.
1210 my ($ordernumber) = @_;
1211 return unless $ordernumber;
1213 my $dbh = C4
::Context
->dbh;
1214 my $query = qq{SELECT
1218 aqbasket
.basketname
,
1219 borrowers
.branchcode
,
1220 biblioitems
.publicationyear
,
1221 biblio
.copyrightdate
,
1222 biblioitems
.editionstatement
,
1226 biblioitems
.publishercode
,
1227 aqorders
.rrp AS unitpricesupplier
,
1228 aqorders
.ecost AS unitpricelib
,
1229 aqorders
.claims_count AS claims_count
,
1230 aqorders
.claimed_date AS claimed_date
,
1231 aqbudgets
.budget_name AS budget
,
1232 aqbooksellers
.name AS supplier
,
1233 aqbooksellers
.id AS supplierid
,
1234 biblioitems
.publishercode AS publisher
,
1235 ADDDATE
(aqbasket
.closedate
, INTERVAL aqbooksellers
.deliverytime DAY
) AS estimateddeliverydate
,
1236 DATE
(aqbasket
.closedate
) AS orderdate
,
1237 aqorders
.quantity
- COALESCE
(aqorders
.quantityreceived
,0) AS quantity_to_receive
,
1238 (aqorders
.quantity
- COALESCE
(aqorders
.quantityreceived
,0)) * aqorders
.rrp AS subtotal
,
1239 DATEDIFF
(CURDATE
( ),closedate
) AS latesince
1240 FROM aqorders LEFT JOIN biblio ON biblio
.biblionumber
= aqorders
.biblionumber
1241 LEFT JOIN biblioitems ON biblioitems
.biblionumber
= biblio
.biblionumber
1242 LEFT JOIN aqbudgets ON aqorders
.budget_id
= aqbudgets
.budget_id
,
1243 aqbasket LEFT JOIN borrowers ON aqbasket
.authorisedby
= borrowers
.borrowernumber
1244 LEFT JOIN aqbooksellers ON aqbasket
.booksellerid
= aqbooksellers
.id
1245 WHERE aqorders
.basketno
= aqbasket
.basketno
1248 $dbh->selectall_arrayref( $query, { Slice
=> {} }, $ordernumber );
1250 # result_set assumed to contain 1 match
1251 return $result_set->[0];
1254 =head3 GetLastOrderNotReceivedFromSubscriptionid
1256 $order = &GetLastOrderNotReceivedFromSubscriptionid($subscriptionid);
1258 Returns a reference-to-hash describing the last order not received for a subscription.
1262 sub GetLastOrderNotReceivedFromSubscriptionid
{
1263 my ( $subscriptionid ) = @_;
1264 my $dbh = C4
::Context
->dbh;
1266 SELECT
* FROM aqorders
1267 LEFT JOIN subscription
1268 ON
( aqorders
.subscriptionid
= subscription
.subscriptionid
)
1269 WHERE aqorders
.subscriptionid
= ?
1270 AND aqorders
.datereceived IS NULL
1274 $dbh->selectall_arrayref( $query, { Slice
=> {} }, $subscriptionid );
1276 # result_set assumed to contain 1 match
1277 return $result_set->[0];
1280 =head3 GetLastOrderReceivedFromSubscriptionid
1282 $order = &GetLastOrderReceivedFromSubscriptionid($subscriptionid);
1284 Returns a reference-to-hash describing the last order received for a subscription.
1288 sub GetLastOrderReceivedFromSubscriptionid
{
1289 my ( $subscriptionid ) = @_;
1290 my $dbh = C4
::Context
->dbh;
1292 SELECT
* FROM aqorders
1293 LEFT JOIN subscription
1294 ON
( aqorders
.subscriptionid
= subscription
.subscriptionid
)
1295 WHERE aqorders
.subscriptionid
= ?
1296 AND aqorders
.datereceived
=
1298 SELECT MAX
( aqorders
.datereceived
)
1300 LEFT JOIN subscription
1301 ON
( aqorders
.subscriptionid
= subscription
.subscriptionid
)
1302 WHERE aqorders
.subscriptionid
= ?
1303 AND aqorders
.datereceived IS NOT NULL
1305 ORDER BY ordernumber DESC
1309 $dbh->selectall_arrayref( $query, { Slice
=> {} }, $subscriptionid, $subscriptionid );
1311 # result_set assumed to contain 1 match
1312 return $result_set->[0];
1316 #------------------------------------------------------------#
1320 &ModOrder(\%hashref);
1322 Modifies an existing order. Updates the order with order number
1323 $hashref->{'ordernumber'} and biblionumber $hashref->{'biblionumber'}. All
1324 other keys of the hash update the fields with the same name in the aqorders
1325 table of the Koha database.
1330 my $orderinfo = shift;
1332 die "Ordernumber is required" if $orderinfo->{'ordernumber'} eq '';
1334 my $dbh = C4
::Context
->dbh;
1337 # update uncertainprice to an integer, just in case (under FF, checked boxes have the value "ON" by default)
1338 $orderinfo->{uncertainprice
}=1 if $orderinfo->{uncertainprice
};
1340 # delete($orderinfo->{'branchcode'});
1341 # the hash contains a lot of entries not in aqorders, so get the columns ...
1342 my $sth = $dbh->prepare("SELECT * FROM aqorders LIMIT 1;");
1344 my $colnames = $sth->{NAME
};
1345 #FIXME Be careful. If aqorders would have columns with diacritics,
1346 #you should need to decode what you get back from NAME.
1347 #See report 10110 and guided_reports.pl
1348 my $query = "UPDATE aqorders SET ";
1350 foreach my $orderinfokey (grep(!/ordernumber/, keys %$orderinfo)){
1351 # ... and skip hash entries that are not in the aqorders table
1352 # FIXME : probably not the best way to do it (would be better to have a correct hash)
1353 next unless grep(/^$orderinfokey$/, @
$colnames);
1354 $query .= "$orderinfokey=?, ";
1355 push(@params, $orderinfo->{$orderinfokey});
1358 $query .= "timestamp=NOW() WHERE ordernumber=?";
1359 push(@params, $orderinfo->{'ordernumber'} );
1360 $sth = $dbh->prepare($query);
1361 $sth->execute(@params);
1365 #------------------------------------------------------------#
1369 ModItemOrder($itemnumber, $ordernumber);
1371 Modifies the ordernumber of an item in aqorders_items.
1376 my ($itemnumber, $ordernumber) = @_;
1378 return unless ($itemnumber and $ordernumber);
1380 my $dbh = C4
::Context
->dbh;
1382 UPDATE aqorders_items
1384 WHERE itemnumber
= ?
1386 my $sth = $dbh->prepare($query);
1387 return $sth->execute($ordernumber, $itemnumber);
1390 #------------------------------------------------------------#
1392 =head3 ModReceiveOrder
1394 my ( $date_received, $new_ordernumber ) = ModReceiveOrder(
1396 biblionumber => $biblionumber,
1398 quantityreceived => $quantityreceived,
1400 invoice => $invoice,
1401 budget_id => $budget_id,
1402 received_itemnumbers => \@received_itemnumbers,
1403 order_internalnote => $order_internalnote,
1407 Updates an order, to reflect the fact that it was received, at least
1410 If a partial order is received, splits the order into two.
1412 Updates the order with biblionumber C<$biblionumber> and ordernumber
1413 C<$order->{ordernumber}>.
1418 sub ModReceiveOrder
{
1420 my $biblionumber = $params->{biblionumber
};
1421 my $order = { %{ $params->{order
} } }; # Copy the order, we don't want to modify it
1422 my $invoice = $params->{invoice
};
1423 my $quantrec = $params->{quantityreceived
};
1424 my $user = $params->{user
};
1425 my $budget_id = $params->{budget_id
};
1426 my $received_items = $params->{received_items
};
1428 my $dbh = C4
::Context
->dbh;
1429 my $datereceived = ( $invoice and $invoice->{datereceived
} ) ?
$invoice->{datereceived
} : dt_from_string
;
1430 my $suggestionid = GetSuggestionFromBiblionumber
( $biblionumber );
1431 if ($suggestionid) {
1432 ModSuggestion
( {suggestionid
=>$suggestionid,
1433 STATUS
=>'AVAILABLE',
1434 biblionumber
=> $biblionumber}
1438 my $result_set = $dbh->selectrow_arrayref(
1439 q{SELECT aqbasket.is_standing
1441 WHERE basketno=?},{ Slice
=> {} }, $order->{basketno
});
1442 my $is_standing = $result_set->[0]; # we assume we have a unique basket
1444 my $new_ordernumber = $order->{ordernumber
};
1445 if ( $is_standing || $order->{quantity
} > $quantrec ) {
1446 # Split order line in two parts: the first is the original order line
1447 # without received items (the quantity is decreased),
1448 # the second part is a new order line with quantity=quantityrec
1449 # (entirely received)
1453 orderstatus
= 'partial'|;
1454 $query .= q
|, order_internalnote
= ?
| if defined $order->{order_internalnote
};
1455 $query .= q
| WHERE ordernumber
= ?
|;
1456 my $sth = $dbh->prepare($query);
1459 ( $is_standing ?
1 : ($order->{quantity
} - $quantrec) ),
1460 ( defined $order->{order_internalnote
} ?
$order->{order_internalnote
} : () ),
1461 $order->{ordernumber
}
1464 # Recalculate tax_value
1468 tax_value_on_ordering
= quantity
* ecost_tax_excluded
* tax_rate_on_ordering
,
1469 tax_value_on_receiving
= quantity
* unitprice_tax_excluded
* tax_rate_on_receiving
1470 WHERE ordernumber
= ?
1471 |, undef, $order->{ordernumber
});
1473 delete $order->{ordernumber
};
1474 $order->{budget_id
} = ( $budget_id || $order->{budget_id
} );
1475 $order->{quantity
} = $quantrec;
1476 $order->{quantityreceived
} = $quantrec;
1477 $order->{ecost_tax_excluded
} //= 0;
1478 $order->{tax_rate_on_ordering
} //= 0;
1479 $order->{unitprice_tax_excluded
} //= 0;
1480 $order->{tax_rate_on_receiving
} //= 0;
1481 $order->{tax_value_on_ordering
} = $order->{quantity
} * $order->{ecost_tax_excluded
} * $order->{tax_rate_on_ordering
};
1482 $order->{tax_value_on_receiving
} = $order->{quantity
} * $order->{unitprice_tax_excluded
} * $order->{tax_rate_on_receiving
};
1483 $order->{datereceived
} = $datereceived;
1484 $order->{invoiceid
} = $invoice->{invoiceid
};
1485 $order->{orderstatus
} = 'complete';
1486 $new_ordernumber = Koha
::Acquisition
::Order
->new($order)->insert->{ordernumber
};
1488 if ($received_items) {
1489 foreach my $itemnumber (@
$received_items) {
1490 ModItemOrder
($itemnumber, $new_ordernumber);
1496 SET quantityreceived
= ?
,
1500 orderstatus
= 'complete'
1504 , unitprice
= ?
, unitprice_tax_included
= ?
, unitprice_tax_excluded
= ?
1505 | if defined $order->{unitprice
};
1508 ,tax_value_on_receiving
= ?
1509 | if defined $order->{tax_value_on_receiving
};
1512 ,tax_rate_on_receiving
= ?
1513 | if defined $order->{tax_rate_on_receiving
};
1516 , order_internalnote
= ?
1517 | if defined $order->{order_internalnote
};
1519 $query .= q
| where biblionumber
=?
and ordernumber
=?
|;
1521 my $sth = $dbh->prepare( $query );
1522 my @params = ( $quantrec, $datereceived, $invoice->{invoiceid
}, ( $budget_id ?
$budget_id : $order->{budget_id
} ) );
1524 if ( defined $order->{unitprice
} ) {
1525 push @params, $order->{unitprice
}, $order->{unitprice_tax_included
}, $order->{unitprice_tax_excluded
};
1528 if ( defined $order->{tax_value_on_receiving
} ) {
1529 push @params, $order->{tax_value_on_receiving
};
1532 if ( defined $order->{tax_rate_on_receiving
} ) {
1533 push @params, $order->{tax_rate_on_receiving
};
1536 if ( defined $order->{order_internalnote
} ) {
1537 push @params, $order->{order_internalnote
};
1540 push @params, ( $biblionumber, $order->{ordernumber
} );
1542 $sth->execute( @params );
1544 # All items have been received, sent a notification to users
1545 NotifyOrderUsers
( $order->{ordernumber
} );
1548 return ($datereceived, $new_ordernumber);
1551 =head3 CancelReceipt
1553 my $parent_ordernumber = CancelReceipt($ordernumber);
1555 Cancel an order line receipt and update the parent order line, as if no
1557 If items are created at receipt (AcqCreateItem = receiving) then delete
1563 my $ordernumber = shift;
1565 return unless $ordernumber;
1567 my $dbh = C4
::Context
->dbh;
1569 SELECT datereceived
, parent_ordernumber
, quantity
1571 WHERE ordernumber
= ?
1573 my $sth = $dbh->prepare($query);
1574 $sth->execute($ordernumber);
1575 my $order = $sth->fetchrow_hashref;
1577 warn "CancelReceipt: order $ordernumber does not exist";
1580 unless($order->{'datereceived'}) {
1581 warn "CancelReceipt: order $ordernumber is not received";
1585 my $parent_ordernumber = $order->{'parent_ordernumber'};
1587 my @itemnumbers = GetItemnumbersFromOrder
( $ordernumber );
1589 if($parent_ordernumber == $ordernumber || not $parent_ordernumber) {
1590 # The order line has no parent, just mark it as not received
1593 SET quantityreceived
= ?
,
1596 orderstatus
= 'ordered'
1597 WHERE ordernumber
= ?
1599 $sth = $dbh->prepare($query);
1600 $sth->execute(0, undef, undef, $ordernumber);
1601 _cancel_items_receipt
( $ordernumber );
1603 # The order line has a parent, increase parent quantity and delete
1606 SELECT quantity
, datereceived
1608 WHERE ordernumber
= ?
1610 $sth = $dbh->prepare($query);
1611 $sth->execute($parent_ordernumber);
1612 my $parent_order = $sth->fetchrow_hashref;
1613 unless($parent_order) {
1614 warn "Parent order $parent_ordernumber does not exist.";
1617 if($parent_order->{'datereceived'}) {
1618 warn "CancelReceipt: parent order is received.".
1619 " Can't cancel receipt.";
1625 orderstatus
= 'ordered'
1626 WHERE ordernumber
= ?
1628 $sth = $dbh->prepare($query);
1629 my $rv = $sth->execute(
1630 $order->{'quantity'} + $parent_order->{'quantity'},
1634 warn "Cannot update parent order line, so do not cancel".
1639 # Recalculate tax_value
1643 tax_value_on_ordering
= quantity
* ecost_tax_excluded
* tax_rate_on_ordering
,
1644 tax_value_on_receiving
= quantity
* unitprice_tax_excluded
* tax_rate_on_receiving
1645 WHERE ordernumber
= ?
1646 |, undef, $parent_ordernumber);
1648 _cancel_items_receipt
( $ordernumber, $parent_ordernumber );
1651 DELETE FROM aqorders
1652 WHERE ordernumber
= ?
1654 $sth = $dbh->prepare($query);
1655 $sth->execute($ordernumber);
1659 if(C4
::Context
->preference('AcqCreateItem') eq 'ordering') {
1660 my @affects = split q{\|}, C4
::Context
->preference("AcqItemSetSubfieldsWhenReceiptIsCancelled");
1662 for my $in ( @itemnumbers ) {
1663 my $biblionumber = C4
::Biblio
::GetBiblionumberFromItemnumber
( $in );
1664 my $frameworkcode = GetFrameworkCode
($biblionumber);
1665 my ( $itemfield ) = GetMarcFromKohaField
( 'items.itemnumber', $frameworkcode );
1666 my $item = C4
::Items
::GetMarcItem
( $biblionumber, $in );
1667 for my $affect ( @affects ) {
1668 my ( $sf, $v ) = split q{=}, $affect, 2;
1669 foreach ( $item->field($itemfield) ) {
1670 $_->update( $sf => $v );
1673 C4
::Items
::ModItemFromMarc
( $item, $biblionumber, $in );
1678 return $parent_ordernumber;
1681 sub _cancel_items_receipt
{
1682 my ( $ordernumber, $parent_ordernumber ) = @_;
1683 $parent_ordernumber ||= $ordernumber;
1685 my @itemnumbers = GetItemnumbersFromOrder
($ordernumber);
1686 if(C4
::Context
->preference('AcqCreateItem') eq 'receiving') {
1687 # Remove items that were created at receipt
1689 DELETE FROM items
, aqorders_items
1690 USING items
, aqorders_items
1691 WHERE items
.itemnumber
= ? AND aqorders_items
.itemnumber
= ?
1693 my $dbh = C4
::Context
->dbh;
1694 my $sth = $dbh->prepare($query);
1695 foreach my $itemnumber (@itemnumbers) {
1696 $sth->execute($itemnumber, $itemnumber);
1700 foreach my $itemnumber (@itemnumbers) {
1701 ModItemOrder
($itemnumber, $parent_ordernumber);
1706 #------------------------------------------------------------#
1710 @results = &SearchOrders({
1711 ordernumber => $ordernumber,
1714 booksellerid => $booksellerid,
1715 basketno => $basketno,
1716 basketname => $basketname,
1717 basketgroupname => $basketgroupname,
1721 biblionumber => $biblionumber,
1722 budget_id => $budget_id
1725 Searches for orders filtered by criteria.
1727 C<$ordernumber> Finds matching orders or transferred orders by ordernumber.
1728 C<$search> Finds orders matching %$search% in title, author, or isbn.
1729 C<$owner> Finds order for the logged in user.
1730 C<$pending> Finds pending orders. Ignores completed and cancelled orders.
1731 C<$ordered> Finds orders to receive only (status 'ordered' or 'partial').
1734 C<@results> is an array of references-to-hash with the keys are fields
1735 from aqorders, biblio, biblioitems and aqbasket tables.
1740 my ( $params ) = @_;
1741 my $ordernumber = $params->{ordernumber
};
1742 my $search = $params->{search
};
1743 my $ean = $params->{ean
};
1744 my $booksellerid = $params->{booksellerid
};
1745 my $basketno = $params->{basketno
};
1746 my $basketname = $params->{basketname
};
1747 my $basketgroupname = $params->{basketgroupname
};
1748 my $owner = $params->{owner
};
1749 my $pending = $params->{pending
};
1750 my $ordered = $params->{ordered
};
1751 my $biblionumber = $params->{biblionumber
};
1752 my $budget_id = $params->{budget_id
};
1754 my $dbh = C4
::Context
->dbh;
1757 SELECT aqbasket.basketno,
1759 borrowers.firstname,
1762 biblioitems.biblioitemnumber,
1763 biblioitems.publishercode,
1764 biblioitems.publicationyear,
1765 aqbasket.authorisedby,
1766 aqbasket.booksellerid,
1768 aqbasket.creationdate,
1769 aqbasket.basketname,
1770 aqbasketgroups.id as basketgroupid,
1771 aqbasketgroups.name as basketgroupname,
1774 LEFT JOIN aqbasket ON aqorders.basketno = aqbasket.basketno
1775 LEFT JOIN aqbasketgroups ON aqbasket.basketgroupid = aqbasketgroups.id
1776 LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber
1777 LEFT JOIN biblio ON aqorders.biblionumber=biblio.biblionumber
1778 LEFT JOIN biblioitems ON biblioitems.biblionumber=biblio.biblionumber
1781 # If we search on ordernumber, we retrieve the transferred order if a transfer has been done.
1783 LEFT JOIN aqorders_transfers ON aqorders_transfers.ordernumber_to = aqorders.ordernumber
1787 WHERE (datecancellationprinted is NULL)
1790 if ( $pending or $ordered ) {
1793 ( aqbasket.is_standing AND aqorders.orderstatus IN ( "new", "ordered", "partial" ) )
1795 ( quantity > quantityreceived OR quantityreceived is NULL )
1799 $query .= q{ AND aqorders.orderstatus IN ( "ordered", "partial" )};
1807 my $userenv = C4
::Context
->userenv;
1808 if ( C4
::Context
->preference("IndependentBranches") ) {
1809 unless ( C4
::Context
->IsSuperLibrarian() ) {
1812 borrowers.branchcode = ?
1813 OR borrowers.branchcode = ''
1816 push @args, $userenv->{branch
};
1820 if ( $ordernumber ) {
1821 $query .= ' AND ( aqorders.ordernumber = ? OR aqorders_transfers.ordernumber_from = ? ) ';
1822 push @args, ( $ordernumber, $ordernumber );
1824 if ( $biblionumber ) {
1825 $query .= 'AND aqorders.biblionumber = ?';
1826 push @args, $biblionumber;
1829 $query .= ' AND (biblio.title LIKE ? OR biblio.author LIKE ? OR biblioitems.isbn LIKE ?)';
1830 push @args, ("%$search%","%$search%","%$search%");
1833 $query .= ' AND biblioitems.ean = ?';
1836 if ( $booksellerid ) {
1837 $query .= 'AND aqbasket.booksellerid = ?';
1838 push @args, $booksellerid;
1841 $query .= 'AND aqbasket.basketno = ?';
1842 push @args, $basketno;
1845 $query .= 'AND aqbasket.basketname LIKE ?';
1846 push @args, "%$basketname%";
1848 if( $basketgroupname ) {
1849 $query .= ' AND aqbasketgroups.name LIKE ?';
1850 push @args, "%$basketgroupname%";
1854 $query .= ' AND aqbasket.authorisedby=? ';
1855 push @args, $userenv->{'number'};
1859 $query .= ' AND aqorders.budget_id = ?';
1860 push @args, $budget_id;
1863 $query .= ' ORDER BY aqbasket.basketno';
1865 my $sth = $dbh->prepare($query);
1866 $sth->execute(@args);
1867 return $sth->fetchall_arrayref({});
1870 #------------------------------------------------------------#
1874 &DelOrder($biblionumber, $ordernumber);
1876 Cancel the order with the given order and biblio numbers. It does not
1877 delete any entries in the aqorders table, it merely marks them as
1883 my ( $bibnum, $ordernumber, $delete_biblio, $reason ) = @_;
1886 my $dbh = C4
::Context
->dbh;
1889 SET datecancellationprinted=now(), orderstatus='cancelled'
1892 $query .= ", cancellationreason = ? ";
1895 WHERE biblionumber=? AND ordernumber=?
1897 my $sth = $dbh->prepare($query);
1899 $sth->execute($reason, $bibnum, $ordernumber);
1901 $sth->execute( $bibnum, $ordernumber );
1905 my @itemnumbers = GetItemnumbersFromOrder
( $ordernumber );
1906 foreach my $itemnumber (@itemnumbers){
1907 my $delcheck = C4
::Items
::DelItemCheck
( $bibnum, $itemnumber );
1909 if($delcheck != 1) {
1910 $error->{'delitem'} = 1;
1914 if($delete_biblio) {
1915 # We get the number of remaining items
1916 my $biblio = Koha
::Biblios
->find( $bibnum );
1917 my $itemcount = $biblio->items->count;
1919 # If there are no items left,
1920 if ( $itemcount == 0 ) {
1921 # We delete the record
1922 my $delcheck = DelBiblio
($bibnum);
1925 $error->{'delbiblio'} = 1;
1933 =head3 TransferOrder
1935 my $newordernumber = TransferOrder($ordernumber, $basketno);
1937 Transfer an order line to a basket.
1938 Mark $ordernumber as cancelled with an internal note 'Cancelled and transferred
1939 to BOOKSELLER on DATE' and create new order with internal note
1940 'Transferred from BOOKSELLER on DATE'.
1941 Move all attached items to the new order.
1942 Received orders cannot be transferred.
1943 Return the ordernumber of created order.
1948 my ($ordernumber, $basketno) = @_;
1950 return unless ($ordernumber and $basketno);
1952 my $order = GetOrder
( $ordernumber );
1953 return if $order->{datereceived
};
1954 my $basket = GetBasket
($basketno);
1955 return unless $basket;
1957 my $dbh = C4
::Context
->dbh;
1958 my ($query, $sth, $rv);
1962 SET datecancellationprinted = CAST(NOW() AS date), orderstatus = ?
1963 WHERE ordernumber = ?
1965 $sth = $dbh->prepare($query);
1966 $rv = $sth->execute('cancelled', $ordernumber);
1968 delete $order->{'ordernumber'};
1969 delete $order->{parent_ordernumber
};
1970 $order->{'basketno'} = $basketno;
1972 my $newordernumber = Koha
::Acquisition
::Order
->new($order)->insert->{ordernumber
};
1975 UPDATE aqorders_items
1977 WHERE ordernumber = ?
1979 $sth = $dbh->prepare($query);
1980 $sth->execute($newordernumber, $ordernumber);
1983 INSERT INTO aqorders_transfers (ordernumber_from, ordernumber_to)
1986 $sth = $dbh->prepare($query);
1987 $sth->execute($ordernumber, $newordernumber);
1989 return $newordernumber;
1992 =head2 FUNCTIONS ABOUT PARCELS
1996 $results = &GetParcels($bookseller, $order, $code, $datefrom, $dateto);
1998 get a lists of parcels.
2005 is the bookseller this function has to get parcels.
2008 To know on what criteria the results list has to be ordered.
2011 is the booksellerinvoicenumber.
2013 =item $datefrom & $dateto
2014 to know on what date this function has to filter its search.
2019 a pointer on a hash list containing parcel informations as such :
2025 =item Last operation
2027 =item Number of biblio
2029 =item Number of items
2036 my ($bookseller,$order, $code, $datefrom, $dateto) = @_;
2037 my $dbh = C4
::Context
->dbh;
2038 my @query_params = ();
2040 SELECT aqinvoices.invoicenumber,
2041 datereceived,purchaseordernumber,
2042 count(DISTINCT biblionumber) AS biblio,
2043 sum(quantity) AS itemsexpected,
2044 sum(quantityreceived) AS itemsreceived
2045 FROM aqorders LEFT JOIN aqbasket ON aqbasket.basketno = aqorders.basketno
2046 LEFT JOIN aqinvoices ON aqorders.invoiceid = aqinvoices.invoiceid
2047 WHERE aqbasket.booksellerid = ? and datereceived IS NOT NULL
2049 push @query_params, $bookseller;
2051 if ( defined $code ) {
2052 $strsth .= ' and aqinvoices.invoicenumber like ? ';
2053 # add a % to the end of the code to allow stemming.
2054 push @query_params, "$code%";
2057 if ( defined $datefrom ) {
2058 $strsth .= ' and datereceived >= ? ';
2059 push @query_params, $datefrom;
2062 if ( defined $dateto ) {
2063 $strsth .= 'and datereceived <= ? ';
2064 push @query_params, $dateto;
2067 $strsth .= "group by aqinvoices.invoicenumber,datereceived ";
2069 # can't use a placeholder to place this column name.
2070 # but, we could probably be checking to make sure it is a column that will be fetched.
2071 $strsth .= "order by $order " if ($order);
2073 my $sth = $dbh->prepare($strsth);
2075 $sth->execute( @query_params );
2076 my $results = $sth->fetchall_arrayref({});
2080 #------------------------------------------------------------#
2082 =head3 GetLateOrders
2084 @results = &GetLateOrders;
2086 Searches for bookseller with late orders.
2089 the table of supplier with late issues. This table is full of hashref.
2095 my $supplierid = shift;
2097 my $estimateddeliverydatefrom = shift;
2098 my $estimateddeliverydateto = shift;
2100 my $dbh = C4
::Context
->dbh;
2102 #BEWARE, order of parenthesis and LEFT JOIN is important for speed
2103 my $dbdriver = C4
::Context
->config("db_scheme") || "mysql";
2105 my @query_params = ();
2107 SELECT aqbasket.basketno,
2108 aqorders.ordernumber,
2109 DATE(aqbasket.closedate) AS orderdate,
2110 aqbasket.basketname AS basketname,
2111 aqbasket.basketgroupid AS basketgroupid,
2112 aqbasketgroups.name AS basketgroupname,
2113 aqorders.rrp AS unitpricesupplier,
2114 aqorders.ecost AS unitpricelib,
2115 aqorders.claims_count AS claims_count,
2116 aqorders.claimed_date AS claimed_date,
2117 aqbudgets.budget_name AS budget,
2118 borrowers.branchcode AS branch,
2119 aqbooksellers.name AS supplier,
2120 aqbooksellers.id AS supplierid,
2121 biblio.author, biblio.title,
2122 biblioitems.publishercode AS publisher,
2123 biblioitems.publicationyear,
2124 ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) AS estimateddeliverydate,
2128 aqorders LEFT JOIN biblio ON biblio.biblionumber = aqorders.biblionumber
2129 LEFT JOIN biblioitems ON biblioitems.biblionumber = biblio.biblionumber
2130 LEFT JOIN aqbudgets ON aqorders.budget_id = aqbudgets.budget_id,
2131 aqbasket LEFT JOIN borrowers ON aqbasket.authorisedby = borrowers.borrowernumber
2132 LEFT JOIN aqbooksellers ON aqbasket.booksellerid = aqbooksellers.id
2133 LEFT JOIN aqbasketgroups ON aqbasket.basketgroupid = aqbasketgroups.id
2134 WHERE aqorders.basketno = aqbasket.basketno
2135 AND ( datereceived = ''
2136 OR datereceived IS NULL
2137 OR aqorders.quantityreceived < aqorders.quantity
2139 AND aqbasket.closedate IS NOT NULL
2140 AND (aqorders.datecancellationprinted IS NULL OR aqorders.datecancellationprinted='0000-00-00')
2143 if ($dbdriver eq "mysql") {
2145 aqorders.quantity - COALESCE(aqorders.quantityreceived,0) AS quantity,
2146 (aqorders.quantity - COALESCE(aqorders.quantityreceived,0)) * aqorders.rrp AS subtotal,
2147 DATEDIFF(CAST(now() AS date),closedate) AS latesince
2149 if ( defined $delay ) {
2150 $from .= " AND (closedate <= DATE_SUB(CAST(now() AS date),INTERVAL ? DAY)) " ;
2151 push @query_params, $delay;
2153 $having = "HAVING quantity <> 0";
2155 # FIXME: account for IFNULL as above
2157 aqorders.quantity AS quantity,
2158 aqorders.quantity * aqorders.rrp AS subtotal,
2159 (CAST(now() AS date) - closedate) AS latesince
2161 if ( defined $delay ) {
2162 $from .= " AND (closedate <= (CAST(now() AS date) -(INTERVAL ? DAY)) ";
2163 push @query_params, $delay;
2166 if (defined $supplierid) {
2167 $from .= ' AND aqbasket.booksellerid = ? ';
2168 push @query_params, $supplierid;
2170 if (defined $branch) {
2171 $from .= ' AND borrowers.branchcode LIKE ? ';
2172 push @query_params, $branch;
2175 if ( defined $estimateddeliverydatefrom or defined $estimateddeliverydateto ) {
2176 $from .= ' AND aqbooksellers.deliverytime IS NOT NULL ';
2178 if ( defined $estimateddeliverydatefrom ) {
2179 $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) >= ?';
2180 push @query_params, $estimateddeliverydatefrom;
2182 if ( defined $estimateddeliverydateto ) {
2183 $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) <= ?';
2184 push @query_params, $estimateddeliverydateto;
2186 if ( defined $estimateddeliverydatefrom and not defined $estimateddeliverydateto ) {
2187 $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) <= CAST(now() AS date)';
2189 if (C4
::Context
->preference("IndependentBranches")
2190 && !C4
::Context
->IsSuperLibrarian() ) {
2191 $from .= ' AND borrowers.branchcode LIKE ? ';
2192 push @query_params, C4
::Context
->userenv->{branch
};
2194 $from .= " AND orderstatus <> 'cancelled' ";
2195 my $query = "$select $from $having\nORDER BY latesince, basketno, borrowers.branchcode, supplier";
2196 $debug and print STDERR
"GetLateOrders query: $query\nGetLateOrders args: " . join(" ",@query_params);
2197 my $sth = $dbh->prepare($query);
2198 $sth->execute(@query_params);
2200 while (my $data = $sth->fetchrow_hashref) {
2201 push @results, $data;
2206 #------------------------------------------------------------#
2210 \@order_loop = GetHistory( %params );
2212 Retreives some acquisition history information
2222 basket - search both basket name and number
2223 booksellerinvoicenumber
2226 orderstatus (note that orderstatus '' will retrieve orders
2227 of any status except cancelled)
2229 get_canceled_order (if set to a true value, cancelled orders will
2233 $order_loop is a list of hashrefs that each look like this:
2235 'author' => 'Twain, Mark',
2237 'biblionumber' => '215',
2239 'creationdate' => 'MM/DD/YYYY',
2240 'datereceived' => undef,
2243 'invoicenumber' => undef,
2245 'ordernumber' => '1',
2247 'quantityreceived' => undef,
2248 'title' => 'The Adventures of Huckleberry Finn'
2254 # don't run the query if there are no parameters (list would be too long for sure !)
2255 croak
"No search params" unless @_;
2257 my $title = $params{title
};
2258 my $author = $params{author
};
2259 my $isbn = $params{isbn
};
2260 my $ean = $params{ean
};
2261 my $name = $params{name
};
2262 my $from_placed_on = $params{from_placed_on
};
2263 my $to_placed_on = $params{to_placed_on
};
2264 my $basket = $params{basket
};
2265 my $booksellerinvoicenumber = $params{booksellerinvoicenumber
};
2266 my $basketgroupname = $params{basketgroupname
};
2267 my $budget = $params{budget
};
2268 my $orderstatus = $params{orderstatus
};
2269 my $biblionumber = $params{biblionumber
};
2270 my $get_canceled_order = $params{get_canceled_order
} || 0;
2271 my $ordernumber = $params{ordernumber
};
2272 my $search_children_too = $params{search_children_too
} || 0;
2273 my $created_by = $params{created_by
} || [];
2277 my $total_qtyreceived = 0;
2278 my $total_price = 0;
2280 my $dbh = C4
::Context
->dbh;
2283 COALESCE(biblio.title, deletedbiblio.title) AS title,
2284 COALESCE(biblio.author, deletedbiblio.author) AS author,
2285 COALESCE(biblioitems.isbn, deletedbiblioitems.isbn) AS isbn,
2286 COALESCE(biblioitems.ean, deletedbiblioitems.ean) AS ean,
2288 aqbasket.basketname,
2289 aqbasket.basketgroupid,
2290 aqbasket.authorisedby,
2291 concat( borrowers.firstname,' ',borrowers.surname) AS authorisedbyname,
2292 aqbasketgroups.name as groupname,
2294 aqbasket.creationdate,
2295 aqorders.datereceived,
2297 aqorders.quantityreceived,
2299 aqorders.ordernumber,
2301 aqinvoices.invoicenumber,
2302 aqbooksellers.id as id,
2303 aqorders.biblionumber,
2304 aqorders.orderstatus,
2305 aqorders.parent_ordernumber,
2306 aqbudgets.budget_name
2308 $query .= ", aqbudgets.budget_id AS budget" if defined $budget;
2311 LEFT JOIN aqbasket ON aqorders.basketno=aqbasket.basketno
2312 LEFT JOIN aqbasketgroups ON aqbasket.basketgroupid=aqbasketgroups.id
2313 LEFT JOIN aqbooksellers ON aqbasket.booksellerid=aqbooksellers.id
2314 LEFT JOIN biblioitems ON biblioitems.biblionumber=aqorders.biblionumber
2315 LEFT JOIN biblio ON biblio.biblionumber=aqorders.biblionumber
2316 LEFT JOIN aqbudgets ON aqorders.budget_id=aqbudgets.budget_id
2317 LEFT JOIN aqinvoices ON aqorders.invoiceid = aqinvoices.invoiceid
2318 LEFT JOIN deletedbiblio ON deletedbiblio.biblionumber=aqorders.biblionumber
2319 LEFT JOIN deletedbiblioitems ON deletedbiblioitems.biblionumber=aqorders.biblionumber
2320 LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber
2323 $query .= " WHERE 1 ";
2325 unless ($get_canceled_order or (defined $orderstatus and $orderstatus eq 'cancelled')) {
2326 $query .= " AND (datecancellationprinted is NULL or datecancellationprinted='0000-00-00') ";
2329 my @query_params = ();
2331 if ( $biblionumber ) {
2332 $query .= " AND biblio.biblionumber = ?";
2333 push @query_params, $biblionumber;
2337 $query .= " AND biblio.title LIKE ? ";
2338 $title =~ s/\s+/%/g;
2339 push @query_params, "%$title%";
2343 $query .= " AND biblio.author LIKE ? ";
2344 push @query_params, "%$author%";
2348 $query .= " AND biblioitems.isbn LIKE ? ";
2349 push @query_params, "%$isbn%";
2352 $query .= " AND biblioitems.ean = ? ";
2353 push @query_params, "$ean";
2356 $query .= " AND aqbooksellers.name LIKE ? ";
2357 push @query_params, "%$name%";
2361 $query .= " AND aqbudgets.budget_id = ? ";
2362 push @query_params, "$budget";
2365 if ( $from_placed_on ) {
2366 $query .= " AND creationdate >= ? ";
2367 push @query_params, $from_placed_on;
2370 if ( $to_placed_on ) {
2371 $query .= " AND creationdate <= ? ";
2372 push @query_params, $to_placed_on;
2375 if ( defined $orderstatus and $orderstatus ne '') {
2376 $query .= " AND aqorders.orderstatus = ? ";
2377 push @query_params, "$orderstatus";
2381 if ($basket =~ m/^\d+$/) {
2382 $query .= " AND aqorders.basketno = ? ";
2383 push @query_params, $basket;
2385 $query .= " AND aqbasket.basketname LIKE ? ";
2386 push @query_params, "%$basket%";
2390 if ($booksellerinvoicenumber) {
2391 $query .= " AND aqinvoices.invoicenumber LIKE ? ";
2392 push @query_params, "%$booksellerinvoicenumber%";
2395 if ($basketgroupname) {
2396 $query .= " AND aqbasketgroups.name LIKE ? ";
2397 push @query_params, "%$basketgroupname%";
2401 $query .= " AND (aqorders.ordernumber = ? ";
2402 push @query_params, $ordernumber;
2403 if ($search_children_too) {
2404 $query .= " OR aqorders.parent_ordernumber = ? ";
2405 push @query_params, $ordernumber;
2410 if ( @
$created_by ) {
2411 $query .= ' AND aqbasket.authorisedby IN ( ' . join( ',', ('?') x @
$created_by ) . ')';
2412 push @query_params, @
$created_by;
2416 if ( C4
::Context
->preference("IndependentBranches") ) {
2417 unless ( C4
::Context
->IsSuperLibrarian() ) {
2418 $query .= " AND (borrowers.branchcode = ? OR borrowers.branchcode ='' ) ";
2419 push @query_params, C4
::Context
->userenv->{branch
};
2422 $query .= " ORDER BY id";
2424 return $dbh->selectall_arrayref( $query, { Slice
=> {} }, @query_params );
2427 =head2 GetRecentAcqui
2429 $results = GetRecentAcqui($days);
2431 C<$results> is a ref to a table which containts hashref
2435 sub GetRecentAcqui
{
2437 my $dbh = C4
::Context
->dbh;
2441 ORDER BY timestamp DESC
2444 my $sth = $dbh->prepare($query);
2446 my $results = $sth->fetchall_arrayref({});
2450 #------------------------------------------------------------#
2454 &AddClaim($ordernumber);
2456 Add a claim for an order
2461 my ($ordernumber) = @_;
2462 my $dbh = C4
::Context
->dbh;
2465 claims_count = claims_count + 1,
2466 claimed_date = CURDATE()
2467 WHERE ordernumber = ?
2469 my $sth = $dbh->prepare($query);
2470 $sth->execute($ordernumber);
2475 my @invoices = GetInvoices(
2476 invoicenumber => $invoicenumber,
2477 supplierid => $supplierid,
2478 suppliername => $suppliername,
2479 shipmentdatefrom => $shipmentdatefrom, # ISO format
2480 shipmentdateto => $shipmentdateto, # ISO format
2481 billingdatefrom => $billingdatefrom, # ISO format
2482 billingdateto => $billingdateto, # ISO format
2483 isbneanissn => $isbn_or_ean_or_issn,
2486 publisher => $publisher,
2487 publicationyear => $publicationyear,
2488 branchcode => $branchcode,
2489 order_by => $order_by
2492 Return a list of invoices that match all given criteria.
2494 $order_by is "column_name (asc|desc)", where column_name is any of
2495 'invoicenumber', 'booksellerid', 'shipmentdate', 'billingdate', 'closedate',
2496 'shipmentcost', 'shipmentcost_budgetid'.
2498 asc is the default if omitted
2505 my @columns = qw(invoicenumber booksellerid shipmentdate billingdate
2506 closedate shipmentcost shipmentcost_budgetid);
2508 my $dbh = C4
::Context
->dbh;
2510 SELECT aqinvoices
.*, aqbooksellers
.name AS suppliername
,
2513 aqorders
.datereceived IS NOT NULL
,
2514 aqorders
.biblionumber
,
2517 ) AS receivedbiblios
,
2520 aqorders
.subscriptionid IS NOT NULL
,
2521 aqorders
.subscriptionid
,
2524 ) AS is_linked_to_subscriptions
,
2525 SUM
(aqorders
.quantityreceived
) AS receiveditems
2527 LEFT JOIN aqbooksellers ON aqbooksellers
.id
= aqinvoices
.booksellerid
2528 LEFT JOIN aqorders ON aqorders
.invoiceid
= aqinvoices
.invoiceid
2529 LEFT JOIN aqbasket ON aqbasket
.basketno
=aqorders
.basketno
2530 LEFT JOIN borrowers ON aqbasket
.authorisedby
=borrowers
.borrowernumber
2531 LEFT JOIN biblio ON aqorders
.biblionumber
= biblio
.biblionumber
2532 LEFT JOIN biblioitems ON biblio
.biblionumber
= biblioitems
.biblionumber
2533 LEFT JOIN subscription ON biblio
.biblionumber
= subscription
.biblionumber
2538 if($args{supplierid
}) {
2539 push @bind_strs, " aqinvoices.booksellerid = ? ";
2540 push @bind_args, $args{supplierid
};
2542 if($args{invoicenumber
}) {
2543 push @bind_strs, " aqinvoices.invoicenumber LIKE ? ";
2544 push @bind_args, "%$args{invoicenumber}%";
2546 if($args{suppliername
}) {
2547 push @bind_strs, " aqbooksellers.name LIKE ? ";
2548 push @bind_args, "%$args{suppliername}%";
2550 if($args{shipmentdatefrom
}) {
2551 push @bind_strs, " aqinvoices.shipmentdate >= ? ";
2552 push @bind_args, $args{shipmentdatefrom
};
2554 if($args{shipmentdateto
}) {
2555 push @bind_strs, " aqinvoices.shipmentdate <= ? ";
2556 push @bind_args, $args{shipmentdateto
};
2558 if($args{billingdatefrom
}) {
2559 push @bind_strs, " aqinvoices.billingdate >= ? ";
2560 push @bind_args, $args{billingdatefrom
};
2562 if($args{billingdateto
}) {
2563 push @bind_strs, " aqinvoices.billingdate <= ? ";
2564 push @bind_args, $args{billingdateto
};
2566 if($args{isbneanissn
}) {
2567 push @bind_strs, " (biblioitems.isbn LIKE CONCAT('%', ?, '%') OR biblioitems.ean LIKE CONCAT('%', ?, '%') OR biblioitems.issn LIKE CONCAT('%', ?, '%') ) ";
2568 push @bind_args, $args{isbneanissn
}, $args{isbneanissn
}, $args{isbneanissn
};
2571 push @bind_strs, " biblio.title LIKE CONCAT('%', ?, '%') ";
2572 push @bind_args, $args{title
};
2575 push @bind_strs, " biblio.author LIKE CONCAT('%', ?, '%') ";
2576 push @bind_args, $args{author
};
2578 if($args{publisher
}) {
2579 push @bind_strs, " biblioitems.publishercode LIKE CONCAT('%', ?, '%') ";
2580 push @bind_args, $args{publisher
};
2582 if($args{publicationyear
}) {
2583 push @bind_strs, " ((biblioitems.publicationyear LIKE CONCAT('%', ?, '%')) OR (biblio.copyrightdate LIKE CONCAT('%', ?, '%'))) ";
2584 push @bind_args, $args{publicationyear
}, $args{publicationyear
};
2586 if($args{branchcode
}) {
2587 push @bind_strs, " borrowers.branchcode = ? ";
2588 push @bind_args, $args{branchcode
};
2590 if($args{message_id
}) {
2591 push @bind_strs, " aqinvoices.message_id = ? ";
2592 push @bind_args, $args{message_id
};
2595 $query .= " WHERE " . join(" AND ", @bind_strs) if @bind_strs;
2596 $query .= " GROUP BY aqinvoices.invoiceid ";
2598 if($args{order_by
}) {
2599 my ($column, $direction) = split / /, $args{order_by
};
2600 if(grep /^$column$/, @columns) {
2601 $direction ||= 'ASC';
2602 $query .= " ORDER BY $column $direction";
2606 my $sth = $dbh->prepare($query);
2607 $sth->execute(@bind_args);
2609 my $results = $sth->fetchall_arrayref({});
2615 my $invoice = GetInvoice($invoiceid);
2617 Get informations about invoice with given $invoiceid
2619 Return a hash filled with aqinvoices.* fields
2624 my ($invoiceid) = @_;
2627 return unless $invoiceid;
2629 my $dbh = C4
::Context
->dbh;
2635 my $sth = $dbh->prepare($query);
2636 $sth->execute($invoiceid);
2638 $invoice = $sth->fetchrow_hashref;
2642 =head3 GetInvoiceDetails
2644 my $invoice = GetInvoiceDetails($invoiceid)
2646 Return informations about an invoice + the list of related order lines
2648 Orders informations are in $invoice->{orders} (array ref)
2652 sub GetInvoiceDetails
{
2653 my ($invoiceid) = @_;
2655 if ( !defined $invoiceid ) {
2656 carp
'GetInvoiceDetails called without an invoiceid';
2660 my $dbh = C4
::Context
->dbh;
2662 SELECT aqinvoices.*, aqbooksellers.name AS suppliername
2664 LEFT JOIN aqbooksellers ON aqinvoices.booksellerid = aqbooksellers.id
2667 my $sth = $dbh->prepare($query);
2668 $sth->execute($invoiceid);
2670 my $invoice = $sth->fetchrow_hashref;
2675 biblio.copyrightdate,
2677 biblioitems.publishercode,
2678 biblioitems.publicationyear,
2679 aqbasket.basketname,
2680 aqbasketgroups.id AS basketgroupid,
2681 aqbasketgroups.name AS basketgroupname
2683 LEFT JOIN aqbasket ON aqorders.basketno = aqbasket.basketno
2684 LEFT JOIN aqbasketgroups ON aqbasket.basketgroupid = aqbasketgroups.id
2685 LEFT JOIN biblio ON aqorders.biblionumber = biblio.biblionumber
2686 LEFT JOIN biblioitems ON aqorders.biblionumber = biblioitems.biblionumber
2689 $sth = $dbh->prepare($query);
2690 $sth->execute($invoiceid);
2691 $invoice->{orders
} = $sth->fetchall_arrayref({});
2692 $invoice->{orders
} ||= []; # force an empty arrayref if fetchall_arrayref fails
2699 my $invoiceid = AddInvoice(
2700 invoicenumber => $invoicenumber,
2701 booksellerid => $booksellerid,
2702 shipmentdate => $shipmentdate,
2703 billingdate => $billingdate,
2704 closedate => $closedate,
2705 shipmentcost => $shipmentcost,
2706 shipmentcost_budgetid => $shipmentcost_budgetid
2709 Create a new invoice and return its id or undef if it fails.
2716 return unless(%invoice and $invoice{invoicenumber
});
2718 my @columns = qw(invoicenumber booksellerid shipmentdate billingdate
2719 closedate shipmentcost shipmentcost_budgetid message_id);
2723 foreach my $key (keys %invoice) {
2724 if(0 < grep(/^$key$/, @columns)) {
2725 push @set_strs, "$key = ?";
2726 push @set_args, ($invoice{$key} || undef);
2732 my $dbh = C4
::Context
->dbh;
2733 my $query = "INSERT INTO aqinvoices SET ";
2734 $query .= join (",", @set_strs);
2735 my $sth = $dbh->prepare($query);
2736 $rv = $sth->execute(@set_args);
2738 $rv = $dbh->last_insert_id(undef, undef, 'aqinvoices', undef);
2747 invoiceid => $invoiceid, # Mandatory
2748 invoicenumber => $invoicenumber,
2749 booksellerid => $booksellerid,
2750 shipmentdate => $shipmentdate,
2751 billingdate => $billingdate,
2752 closedate => $closedate,
2753 shipmentcost => $shipmentcost,
2754 shipmentcost_budgetid => $shipmentcost_budgetid
2757 Modify an invoice, invoiceid is mandatory.
2759 Return undef if it fails.
2766 return unless(%invoice and $invoice{invoiceid
});
2768 my @columns = qw(invoicenumber booksellerid shipmentdate billingdate
2769 closedate shipmentcost shipmentcost_budgetid);
2773 foreach my $key (keys %invoice) {
2774 if(0 < grep(/^$key$/, @columns)) {
2775 push @set_strs, "$key = ?";
2776 push @set_args, ($invoice{$key} || undef);
2780 my $dbh = C4
::Context
->dbh;
2781 my $query = "UPDATE aqinvoices SET ";
2782 $query .= join(",", @set_strs);
2783 $query .= " WHERE invoiceid = ?";
2785 my $sth = $dbh->prepare($query);
2786 $sth->execute(@set_args, $invoice{invoiceid
});
2791 CloseInvoice($invoiceid);
2795 Equivalent to ModInvoice(invoiceid => $invoiceid, closedate => undef);
2800 my ($invoiceid) = @_;
2802 return unless $invoiceid;
2804 my $dbh = C4
::Context
->dbh;
2807 SET closedate
= CAST
(NOW
() AS DATE
)
2810 my $sth = $dbh->prepare($query);
2811 $sth->execute($invoiceid);
2814 =head3 ReopenInvoice
2816 ReopenInvoice($invoiceid);
2820 Equivalent to ModInvoice(invoiceid => $invoiceid, closedate => output_pref({ dt=>dt_from_string, dateonly=>1, otputpref=>'iso' }))
2825 my ($invoiceid) = @_;
2827 return unless $invoiceid;
2829 my $dbh = C4
::Context
->dbh;
2832 SET closedate
= NULL
2835 my $sth = $dbh->prepare($query);
2836 $sth->execute($invoiceid);
2841 DelInvoice($invoiceid);
2843 Delete an invoice if there are no items attached to it.
2848 my ($invoiceid) = @_;
2850 return unless $invoiceid;
2852 my $dbh = C4
::Context
->dbh;
2858 my $sth = $dbh->prepare($query);
2859 $sth->execute($invoiceid);
2860 my $res = $sth->fetchrow_arrayref;
2861 if ( $res && $res->[0] == 0 ) {
2863 DELETE FROM aqinvoices
2866 my $sth = $dbh->prepare($query);
2867 return ( $sth->execute($invoiceid) > 0 );
2872 =head3 MergeInvoices
2874 MergeInvoices($invoiceid, \@sourceids);
2876 Merge the invoices identified by the IDs in \@sourceids into
2877 the invoice identified by $invoiceid.
2882 my ($invoiceid, $sourceids) = @_;
2884 return unless $invoiceid;
2885 foreach my $sourceid (@
$sourceids) {
2886 next if $sourceid == $invoiceid;
2887 my $source = GetInvoiceDetails
($sourceid);
2888 foreach my $order (@
{$source->{'orders'}}) {
2889 $order->{'invoiceid'} = $invoiceid;
2892 DelInvoice
($source->{'invoiceid'});
2897 =head3 GetBiblioCountByBasketno
2899 $biblio_count = &GetBiblioCountByBasketno($basketno);
2901 Looks up the biblio's count that has basketno value $basketno
2907 sub GetBiblioCountByBasketno
{
2908 my ($basketno) = @_;
2909 my $dbh = C4
::Context
->dbh;
2911 SELECT COUNT( DISTINCT( biblionumber ) )
2914 AND (datecancellationprinted IS NULL OR datecancellationprinted='0000-00-00')
2917 my $sth = $dbh->prepare($query);
2918 $sth->execute($basketno);
2919 return $sth->fetchrow;
2922 # Note this subroutine should be moved to Koha::Acquisition::Order
2923 # Will do when a DBIC decision will be taken.
2924 sub populate_order_with_prices
{
2927 my $order = $params->{order
};
2928 my $booksellerid = $params->{booksellerid
};
2929 return unless $booksellerid;
2931 my $bookseller = Koha
::Acquisition
::Booksellers
->find( $booksellerid );
2933 my $receiving = $params->{receiving
};
2934 my $ordering = $params->{ordering
};
2935 my $discount = $order->{discount
};
2936 $discount /= 100 if $discount > 1;
2939 $order->{tax_rate_on_ordering
} //= $order->{tax_rate
};
2940 if ( $bookseller->listincgst ) {
2941 # The user entered the rrp tax included
2942 $order->{rrp_tax_included
} = $order->{rrp
};
2944 # rrp tax excluded = rrp tax included / ( 1 + tax rate )
2945 $order->{rrp_tax_excluded
} = $order->{rrp_tax_included
} / ( 1 + $order->{tax_rate_on_ordering
} );
2947 # ecost tax excluded = rrp tax excluded * ( 1 - discount )
2948 $order->{ecost_tax_excluded
} = $order->{rrp_tax_excluded
} * ( 1 - $discount );
2950 # ecost tax included = rrp tax included ( 1 - discount )
2951 $order->{ecost_tax_included
} = $order->{rrp_tax_included
} * ( 1 - $discount );
2954 # The user entered the rrp tax excluded
2955 $order->{rrp_tax_excluded
} = $order->{rrp
};
2957 # rrp tax included = rrp tax excluded * ( 1 - tax rate )
2958 $order->{rrp_tax_included
} = $order->{rrp_tax_excluded
} * ( 1 + $order->{tax_rate_on_ordering
} );
2960 # ecost tax excluded = rrp tax excluded * ( 1 - discount )
2961 $order->{ecost_tax_excluded
} = $order->{rrp_tax_excluded
} * ( 1 - $discount );
2963 # ecost tax included = rrp tax excluded * ( 1 - tax rate ) * ( 1 - discount )
2964 $order->{ecost_tax_included
} =
2965 $order->{rrp_tax_excluded
} *
2966 ( 1 + $order->{tax_rate_on_ordering
} ) *
2970 # tax value = quantity * ecost tax excluded * tax rate
2971 $order->{tax_value_on_ordering
} =
2972 $order->{quantity
} * $order->{ecost_tax_excluded
} * $order->{tax_rate_on_ordering
};
2976 $order->{tax_rate_on_receiving
} //= $order->{tax_rate
};
2977 if ( $bookseller->invoiceincgst ) {
2978 # Trick for unitprice. If the unit price rounded value is the same as the ecost rounded value
2979 # we need to keep the exact ecost value
2980 if ( Koha
::Number
::Price
->new( $order->{unitprice
} )->round == Koha
::Number
::Price
->new( $order->{ecost_tax_included
} )->round ) {
2981 $order->{unitprice
} = $order->{ecost_tax_included
};
2984 # The user entered the unit price tax included
2985 $order->{unitprice_tax_included
} = $order->{unitprice
};
2987 # unit price tax excluded = unit price tax included / ( 1 + tax rate )
2988 $order->{unitprice_tax_excluded
} = $order->{unitprice_tax_included
} / ( 1 + $order->{tax_rate_on_receiving
} );
2991 # Trick for unitprice. If the unit price rounded value is the same as the ecost rounded value
2992 # we need to keep the exact ecost value
2993 if ( Koha
::Number
::Price
->new( $order->{unitprice
} )->round == Koha
::Number
::Price
->new( $order->{ecost_tax_excluded
} )->round ) {
2994 $order->{unitprice
} = $order->{ecost_tax_excluded
};
2997 # The user entered the unit price tax excluded
2998 $order->{unitprice_tax_excluded
} = $order->{unitprice
};
3001 # unit price tax included = unit price tax included * ( 1 + tax rate )
3002 $order->{unitprice_tax_included
} = $order->{unitprice_tax_excluded
} * ( 1 + $order->{tax_rate_on_receiving
} );
3005 # tax value = quantity * unit price tax excluded * tax rate
3006 $order->{tax_value_on_receiving
} = $order->{quantity
} * $order->{unitprice_tax_excluded
} * $order->{tax_rate_on_receiving
};
3012 =head3 GetOrderUsers
3014 $order_users_ids = &GetOrderUsers($ordernumber);
3016 Returns a list of all borrowernumbers that are in order users list
3021 my ($ordernumber) = @_;
3023 return unless $ordernumber;
3026 SELECT borrowernumber
3028 WHERE ordernumber
= ?
3030 my $dbh = C4
::Context
->dbh;
3031 my $sth = $dbh->prepare($query);
3032 $sth->execute($ordernumber);
3033 my $results = $sth->fetchall_arrayref( {} );
3035 my @borrowernumbers;
3036 foreach (@
$results) {
3037 push @borrowernumbers, $_->{'borrowernumber'};
3040 return @borrowernumbers;
3043 =head3 ModOrderUsers
3045 my @order_users_ids = (1, 2, 3);
3046 &ModOrderUsers($ordernumber, @basketusers_ids);
3048 Delete all users from order users list, and add users in C<@order_users_ids>
3054 my ( $ordernumber, @order_users_ids ) = @_;
3056 return unless $ordernumber;
3058 my $dbh = C4
::Context
->dbh;
3060 DELETE FROM aqorder_users
3061 WHERE ordernumber
= ?
3063 my $sth = $dbh->prepare($query);
3064 $sth->execute($ordernumber);
3067 INSERT INTO aqorder_users
(ordernumber
, borrowernumber
)
3070 $sth = $dbh->prepare($query);
3071 foreach my $order_user_id (@order_users_ids) {
3072 $sth->execute( $ordernumber, $order_user_id );
3076 sub NotifyOrderUsers
{
3077 my ($ordernumber) = @_;
3079 my @borrowernumbers = GetOrderUsers
($ordernumber);
3080 return unless @borrowernumbers;
3082 my $order = GetOrder
( $ordernumber );
3083 for my $borrowernumber (@borrowernumbers) {
3084 my $borrower = C4
::Members
::GetMember
( borrowernumber
=> $borrowernumber );
3085 my $library = Koha
::Libraries
->find( $borrower->{branchcode
} )->unblessed;
3086 my $biblio = C4
::Biblio
::GetBiblio
( $order->{biblionumber
} );
3087 my $letter = C4
::Letters
::GetPreparedLetter
(
3088 module
=> 'acquisition',
3089 letter_code
=> 'ACQ_NOTIF_ON_RECEIV',
3090 branchcode
=> $library->{branchcode
},
3091 lang
=> $borrower->{lang
},
3093 'branches' => $library,
3094 'borrowers' => $borrower,
3095 'biblio' => $biblio,
3096 'aqorders' => $order,
3100 C4
::Letters
::EnqueueLetter
(
3103 borrowernumber
=> $borrowernumber,
3104 LibraryName
=> C4
::Context
->preference("LibraryName"),
3105 message_transport_type
=> 'email',
3107 ) or warn "can't enqueue letter $letter";
3112 =head3 FillWithDefaultValues
3114 FillWithDefaultValues( $marc_record );
3116 This will update the record with default value defined in the ACQ framework.
3117 For all existing fields, if a default value exists and there are no subfield, it will be created.
3118 If the field does not exist, it will be created too.
3122 sub FillWithDefaultValues
{
3124 my $tagslib = C4
::Biblio
::GetMarcStructure
( 1, 'ACQ', { unsafe
=> 1 } );
3127 C4
::Biblio
::GetMarcFromKohaField
( 'items.itemnumber', '' );
3128 for my $tag ( sort keys %$tagslib ) {
3130 next if $tag == $itemfield;
3131 for my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
3132 next if IsMarcStructureInternal
($tagslib->{$tag}{$subfield});
3133 my $defaultvalue = $tagslib->{$tag}{$subfield}{defaultvalue
};
3134 if ( defined $defaultvalue and $defaultvalue ne '' ) {
3135 my @fields = $record->field($tag);
3137 for my $field (@fields) {
3138 unless ( defined $field->subfield($subfield) ) {
3139 $field->add_subfields(
3140 $subfield => $defaultvalue );
3145 $record->insert_fields_ordered(
3147 $tag, '', '', $subfield => $defaultvalue
3162 Koha Development Team <http://koha-community.org/>