3 #script to show display basket of orders
5 # Copyright 2000 - 2004 Katipo
6 # Copyright 2008 - 2009 BibLibre SARL
8 # This file is part of Koha.
10 # Koha is free software; you can redistribute it and/or modify it
11 # under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 3 of the License, or
13 # (at your option) any later version.
15 # Koha is distributed in the hope that it will be useful, but
16 # WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with Koha; if not, see <http://www.gnu.org/licenses>.
36 use Koha::Acquisition::Booksellers;
38 use C4::Letters qw/SendAlerts/;
39 use Date::Calc qw/Add_Delta_Days/;
41 use Koha::EDI qw( create_edi_order get_edifact_ean );
42 use Koha::CsvProfiles;
51 This script display all informations about basket for the supplier given
52 on input arg. Moreover, it allows us to add a new order for this supplier from
53 an existing record, a suggestion or a new record.
65 the supplier this script have to display the basket.
74 our $basketno = $query->param('basketno');
75 our $ean = $query->param('ean');
76 our $booksellerid = $query->param('booksellerid');
77 my $duplinbatch = $query->param('duplinbatch');
79 our ( $template, $loggedinuser, $cookie, $userflags ) = get_template_and_user(
81 template_name => "acqui/basket.tt",
85 flagsrequired => { acquisition => 'order_manage' },
90 our $basket = GetBasket($basketno);
91 $booksellerid = $basket->{booksellerid} unless $booksellerid;
92 my $bookseller = Koha::Acquisition::Booksellers->find( $booksellerid );
93 my $schema = Koha::Database->new()->schema();
94 my $rs = $schema->resultset('VendorEdiAccount')->search(
95 { vendor_id => $booksellerid, } );
96 $template->param( ediaccount => ($rs->count > 0));
98 unless (CanUserManageBasket($loggedinuser, $basket, $userflags)) {
100 cannot_manage_basket => 1,
101 basketno => $basketno,
102 basketname => $basket->{basketname},
103 booksellerid => $booksellerid,
104 booksellername => $bookseller->name,
106 output_html_with_http_headers $query, $cookie, $template->output;
110 # FIXME : what about the "discount" percentage?
111 # FIXME : the query->param('booksellerid') below is probably useless. The bookseller is always known from the basket
112 # if no booksellerid in parameter, get it from basket
113 # warn "=>".$basket->{booksellerid};
114 my $op = $query->param('op') // 'list';
116 our $confirm_pref= C4::Context->preference("BasketConfirmations") || '1';
117 $template->param( skip_confirm_reopen => 1) if $confirm_pref eq '2';
121 if ( $op eq 'delete_confirm' ) {
122 my $basketno = $query->param('basketno');
123 my $delbiblio = $query->param('delbiblio');
124 my @orders = GetOrders($basketno);
125 #Delete all orders included in that basket, and all items received.
126 foreach my $myorder (@orders){
127 DelOrder($myorder->{biblionumber},$myorder->{ordernumber});
129 # if $delbiblio = 1, delete the records if possible
130 if ((defined $delbiblio)and ($delbiblio ==1)){
131 my @cannotdelbiblios ;
132 foreach my $myorder (@orders){
133 my $biblionumber = $myorder->{'biblionumber'};
134 my $biblio = Koha::Biblios->find( $biblionumber );
135 my $countbiblio = CountBiblioInOrders($biblionumber);
136 my $ordernumber = $myorder->{'ordernumber'};
137 my $cnt_subscriptions = $biblio->subscriptions->count;
138 my $itemcount = $biblio->items->count;
140 if ($countbiblio == 0 && $itemcount == 0 && not $cnt_subscriptions ) {
141 $error = DelBiblio($myorder->{biblionumber}) }
143 push @cannotdelbiblios, {biblionumber=> ($myorder->{biblionumber}),
144 title=> $myorder->{'title'},
145 author=> $myorder->{'author'},
146 countbiblio=> $countbiblio,
147 itemcount=>$itemcount,
148 subscriptions => $cnt_subscriptions};
151 push @cannotdelbiblios, {biblionumber=> ($myorder->{biblionumber}),
152 title=> $myorder->{'title'},
153 author=> $myorder->{'author'},
154 othererror=> $error};
157 $template->param( cannotdelbiblios => \@cannotdelbiblios );
160 DelBasket($basketno,);
162 delete_confirmed => 1,
163 booksellername => $bookseller->name,
164 booksellerid => $booksellerid,
166 } elsif ( !$bookseller ) {
167 $template->param( NO_BOOKSELLER => 1 );
168 } elsif ($op eq 'export') {
169 print $query->header(
171 -attachment => 'basket' . $basket->{'basketno'} . '.csv',
173 my $csv_profile_id = $query->param('csv_profile');
174 if (defined $csv_profile_id) {
175 # using a csv profile
176 print GetBasketAsCSV(scalar $query->param('basketno'), $query, $csv_profile_id);
179 print GetBasketAsCSV(scalar $query->param('basketno'), $query);
182 } elsif ($op eq 'email') {
184 SendAlerts( 'orderacquisition', $query->param('basketno'), 'ACQORDER' );
187 push @messages, { type => 'error', code => $@ };
188 } elsif ( ref $err and exists $err->{error} ) {
189 push @messages, { type => 'error', code => $err->{error} };
191 push @messages, { type => 'message', code => 'email_sent' };
195 } elsif ($op eq 'close') {
196 my $confirm = $query->param('confirm') || $confirm_pref eq '2';
198 my $basketno = $query->param('basketno');
199 my $booksellerid = $query->param('booksellerid');
200 $basketno =~ /^\d+$/ and CloseBasket($basketno);
201 # if requested, create basket group, close it and attach the basket
202 if ($query->param('createbasketgroup')) {
204 if(C4::Context->userenv and C4::Context->userenv->{'branch'}
205 and C4::Context->userenv->{'branch'} ne "NO_LIBRARY_SET") {
206 $branchcode = C4::Context->userenv->{'branch'};
208 my $basketgroupid = NewBasketgroup( { name => $basket->{basketname},
209 booksellerid => $booksellerid,
210 deliveryplace => $branchcode,
211 billingplace => $branchcode,
214 ModBasket( { basketno => $basketno,
215 basketgroupid => $basketgroupid } );
216 print $query->redirect('/cgi-bin/koha/acqui/basketgroup.pl?booksellerid='.$booksellerid.'&closed=1');
218 print $query->redirect('/cgi-bin/koha/acqui/booksellers.pl?booksellerid=' . $booksellerid);
223 confirm_close => "1",
224 booksellerid => $booksellerid,
225 booksellername => $bookseller->name,
226 basketno => $basket->{'basketno'},
227 basketname => $basket->{'basketname'},
228 basketgroupname => $basket->{'basketname'},
231 } elsif ($op eq 'reopen') {
232 ReopenBasket(scalar $query->param('basketno'));
233 print $query->redirect('/cgi-bin/koha/acqui/basket.pl?basketno='.$basket->{'basketno'})
235 elsif ( $op eq 'ediorder' ) {
236 edi_close_and_order()
237 } elsif ( $op eq 'mod_users' ) {
238 my $basketusers_ids = $query->param('users_ids');
239 my @basketusers = split( /:/, $basketusers_ids );
240 ModBasketUsers($basketno, @basketusers);
241 print $query->redirect("/cgi-bin/koha/acqui/basket.pl?basketno=$basketno");
243 } elsif ( $op eq 'mod_branch' ) {
244 my $branch = $query->param('branch');
245 $branch = undef if(defined $branch and $branch eq '');
247 basketno => $basket->{basketno},
250 print $query->redirect("/cgi-bin/koha/acqui/basket.pl?basketno=$basketno");
254 if ( $op eq 'list' ) {
256 # get librarian branch...
257 if ( C4::Context->preference("IndependentBranches") ) {
258 my $userenv = C4::Context->userenv;
259 unless ( C4::Context->IsSuperLibrarian() ) {
260 my $validtest = ( $basket->{creationdate} eq '' )
261 || ( $userenv->{branch} eq $basket->{branch} )
262 || ( $userenv->{branch} eq '' )
263 || ( $basket->{branch} eq '' );
264 unless ($validtest) {
265 print $query->redirect("../mainpage.pl");
270 if (!defined $basket->{branch} or $basket->{branch} eq $userenv->{branch}) {
271 push @branches_loop, {
272 branchcode => $userenv->{branch},
273 branchname => $userenv->{branchname},
279 my $branches = Koha::Libraries->search( {}, { order_by => ['branchname'] } )->unblessed;
280 foreach my $branch (@$branches) {
282 if (defined $basket->{branch}) {
283 $selected = 1 if $branch->{branchcode} eq $basket->{branch};
285 $selected = 1 if $branch->{branchcode} eq C4::Context->userenv->{branch};
287 push @branches_loop, {
288 branchcode => $branch->{branchcode},
289 branchname => $branch->{branchname},
290 selected => $selected
295 #if the basket is closed,and the user has the permission to edit basketgroups, display a list of basketgroups
296 my ($basketgroup, $basketgroups);
297 my $patron = Koha::Patrons->find($loggedinuser);
298 if ($basket->{closedate} && haspermission($patron->userid, { acquisition => 'group_manage'} )) {
299 $basketgroups = GetBasketgroups($basket->{booksellerid});
300 for my $bg ( @{$basketgroups} ) {
301 if ($basket->{basketgroupid} && $basket->{basketgroupid} == $bg->{id}){
308 # if the basket is closed, calculate estimated delivery date
309 my $estimateddeliverydate;
310 if( $basket->{closedate} ) {
311 my ($year, $month, $day) = ($basket->{closedate} =~ /(\d+)-(\d+)-(\d+)/);
312 ($year, $month, $day) = Add_Delta_Days($year, $month, $day, $bookseller->deliverytime);
313 $estimateddeliverydate = sprintf( "%04d-%02d-%02d", $year, $month, $day );
316 # if new basket, pre-fill infos
317 $basket->{creationdate} = "" unless ( $basket->{creationdate} );
318 $basket->{authorisedby} = $loggedinuser unless ( $basket->{authorisedby} );
321 "loggedinuser: $loggedinuser; creationdate: %s; authorisedby: %s",
322 $basket->{creationdate}, $basket->{authorisedby};
324 my @basketusers_ids = GetBasketUsers($basketno);
326 foreach my $basketuser_id (@basketusers_ids) {
327 # FIXME Could be improved with a search -in
328 my $basket_patron = Koha::Patrons->find( $basketuser_id );
329 push @basketusers, $basket_patron if $basket_patron;
332 my $active_currency = Koha::Acquisition::Currencies->get_active;
334 my @orders = GetOrders( $basketno );
339 my $total_quantity = 0;
340 my $total_tax_excluded = 0;
341 my $total_tax_included = 0;
342 my $total_tax_value = 0;
343 for my $order (@orders) {
344 my $line = get_order_infos( $order, $bookseller);
345 if ( $line->{uncertainprice} ) {
346 $template->param( uncertainprices => 1 );
349 $line->{tax_rate} = $line->{tax_rate_on_ordering};
350 $line->{tax_value} = $line->{tax_value_on_ordering};
352 push @books_loop, $line;
354 $foot{$$line{tax_rate}}{tax_rate} = $$line{tax_rate};
355 $foot{$$line{tax_rate}}{tax_value} += $$line{tax_value};
356 $total_tax_value += $$line{tax_value};
357 $foot{$$line{tax_rate}}{quantity} += $$line{quantity};
358 $total_quantity += $$line{quantity};
359 $foot{$$line{tax_rate}}{total_tax_excluded} += $$line{total_tax_excluded};
360 $total_tax_excluded += $$line{total_tax_excluded};
361 $foot{$$line{tax_rate}}{total_tax_included} += $$line{total_tax_included};
362 $total_tax_included += $$line{total_tax_included};
365 push @book_foot_loop, map {$_} values %foot;
367 # Get cancelled orders
368 my @cancelledorders = GetOrders($basketno, { cancelled => 1 });
369 my @cancelledorders_loop;
370 for my $order (@cancelledorders) {
371 my $line = get_order_infos( $order, $bookseller);
372 push @cancelledorders_loop, $line;
375 my $contract = GetContract({
376 contractnumber => $basket->{contractnumber}
379 if ($basket->{basketgroupid}){
380 $basketgroup = GetBasketgroup($basket->{basketgroupid});
382 my $budgets = GetBudgetHierarchy;
384 foreach my $r (@{$budgets}) {
385 if (!defined $r->{budget_amount} || $r->{budget_amount} == 0) {
388 next unless (CanUserUseBudget($loggedinuser, $r, $userflags));
395 basketno => $basketno,
397 basketname => $basket->{'basketname'},
398 basketbranchcode => $basket->{branch},
399 basketnote => $basket->{note},
400 basketbooksellernote => $basket->{booksellernote},
401 basketcontractno => $basket->{contractnumber},
402 basketcontractname => $contract->{contractname},
403 branches_loop => \@branches_loop,
404 creationdate => $basket->{creationdate},
405 authorisedby => $basket->{authorisedby},
406 authorisedbyname => $basket->{authorisedbyname},
407 users_ids => join(':', @basketusers_ids),
408 users => \@basketusers,
409 closedate => $basket->{closedate},
410 estimateddeliverydate=> $estimateddeliverydate,
411 is_standing => $basket->{is_standing},
412 deliveryplace => $basket->{deliveryplace},
413 billingplace => $basket->{billingplace},
414 active => $bookseller->active,
415 booksellerid => $bookseller->id,
416 booksellername => $bookseller->name,
417 books_loop => \@books_loop,
418 book_foot_loop => \@book_foot_loop,
419 cancelledorders_loop => \@cancelledorders_loop,
420 total_quantity => $total_quantity,
421 total_tax_excluded => $total_tax_excluded,
422 total_tax_included => $total_tax_included,
423 total_tax_value => $total_tax_value,
424 currency => $active_currency->currency,
425 listincgst => $bookseller->listincgst,
426 basketgroups => $basketgroups,
427 basketgroup => $basketgroup,
428 grouped => $basket->{basketgroupid},
429 # The double negatives and booleans here mean:
430 # "A basket cannot be closed if there are no orders in it or it's a standing order basket."
432 # (The template has another implicit restriction that the order cannot be closed if there
433 # are any orders with uncertain prices.)
434 unclosable => @orders ? $basket->{is_standing} : 1,
435 has_budgets => $has_budgets,
436 duplinbatch => $duplinbatch,
437 csv_profiles => [ Koha::CsvProfiles->search({ type => 'sql', used_for => 'export_basket' }) ],
441 $template->param( messages => \@messages );
442 output_html_with_http_headers $query, $cookie, $template->output;
444 sub get_order_infos {
446 my $bookseller = shift;
447 my $qty = $order->{'quantity'} || 0;
448 if ( !defined $order->{quantityreceived} ) {
449 $order->{quantityreceived} = 0;
451 my $budget = GetBudget($order->{budget_id});
452 my $basket = GetBasket($order->{basketno});
454 my %line = %{ $order };
455 # Don't show unreceived standing orders as received
456 $line{order_received} = ( $qty == $order->{'quantityreceived'} && ( $basket->{is_standing} ? $qty : 1 ) );
457 $line{basketno} = $basketno;
458 $line{budget_name} = $budget->{budget_name};
460 $line{total_tax_included} = $line{ecost_tax_included} * $line{quantity};
461 $line{total_tax_excluded} = $line{ecost_tax_excluded} * $line{quantity};
462 $line{tax_value} = $line{tax_value_on_ordering};
463 $line{tax_rate} = $line{tax_rate_on_ordering};
465 if ( $line{uncertainprice} ) {
466 $line{rrp_tax_excluded} .= ' (Uncertain)';
468 if ( $line{'title'} ) {
469 my $volume = $order->{'volume'};
470 my $seriestitle = $order->{'seriestitle'};
471 $line{'title'} .= " / $seriestitle" if $seriestitle;
472 $line{'title'} .= " / $volume" if $volume;
475 my $biblionumber = $order->{'biblionumber'};
476 if ( $biblionumber ) { # The biblio still exists
477 my $biblio = Koha::Biblios->find( $biblionumber );
478 my $countbiblio = CountBiblioInOrders($biblionumber);
479 my $ordernumber = $order->{'ordernumber'};
480 my $cnt_subscriptions = $biblio->subscriptions->count;
481 my $itemcount = $biblio->items->count;
482 my $holds_count = $biblio->holds->count;
483 my @items = GetItemnumbersFromOrder( $ordernumber );
484 my $itemholds = $biblio->holds->search({ itemnumber => { -in => \@items } })->count;
486 # if the biblio is not in other orders and if there is no items elsewhere and no subscriptions and no holds we can then show the link "Delete order and Biblio" see bug 5680
487 $line{can_del_bib} = 1 if $countbiblio <= 1 && $itemcount == scalar @items && !($cnt_subscriptions) && !($holds_count);
488 $line{items} = ($itemcount) - (scalar @items);
489 $line{left_item} = 1 if $line{items} >= 1;
490 $line{left_biblio} = 1 if $countbiblio > 1;
491 $line{biblios} = $countbiblio - 1;
492 $line{left_subscription} = 1 if $cnt_subscriptions;
493 $line{subscriptions} = $cnt_subscriptions;
494 ($holds_count >= 1) ? $line{left_holds} = 1 : $line{left_holds} = 0;
495 $line{left_holds_on_order} = 1 if $line{left_holds}==1 && ($line{items} == 0 || $itemholds );
496 $line{holds} = $holds_count;
497 $line{holds_on_order} = $itemholds?$itemholds:$holds_count if $line{left_holds_on_order};
501 my $suggestion = GetSuggestionInfoFromBiblionumber($line{biblionumber});
502 $line{suggestionid} = $$suggestion{suggestionid};
503 $line{surnamesuggestedby} = $$suggestion{surnamesuggestedby};
504 $line{firstnamesuggestedby} = $$suggestion{firstnamesuggestedby};
506 foreach my $key (qw(transferred_from transferred_to)) {
508 my $order = GetOrder($line{$key});
509 my $basket = GetBasket($order->{basketno});
510 my $bookseller = Koha::Acquisition::Booksellers->find( $basket->{booksellerid} );
514 bookseller => $bookseller,
515 timestamp => $line{$key . '_timestamp'},
523 sub edi_close_and_order {
524 my $confirm = $query->param('confirm') || $confirm_pref eq '2';
527 basketno => $basketno,
530 if ( $basket->{branch} ) {
531 $edi_params->{branchcode} = $basket->{branch};
533 if ( create_edi_order($edi_params) ) {
534 #$template->param( edifile => 1 );
536 CloseBasket($basketno);
538 # if requested, create basket group, close it and attach the basket
539 if ( $query->param('createbasketgroup') ) {
541 if ( C4::Context->userenv
542 and C4::Context->userenv->{'branch'}
543 and C4::Context->userenv->{'branch'} ne "NO_LIBRARY_SET" )
545 $branchcode = C4::Context->userenv->{'branch'};
547 my $basketgroupid = NewBasketgroup(
549 name => $basket->{basketname},
550 booksellerid => $booksellerid,
551 deliveryplace => $branchcode,
552 billingplace => $branchcode,
558 basketno => $basketno,
559 basketgroupid => $basketgroupid
562 print $query->redirect(
563 "/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=$booksellerid&closed=1"
567 print $query->redirect(
568 "/cgi-bin/koha/acqui/booksellers.pl?booksellerid=$booksellerid"
576 booksellerid => $booksellerid,
577 basketno => $basket->{basketno},
578 basketname => $basket->{basketname},
579 basketgroupname => $basket->{basketname},
582 $template->param( ean => $ean );