Bug 18807: t/db_dependent/www/batch.t fails
[koha.git] / acqui / basket.pl
blob55aca4cf0d010fc9affbe499785c43a7502dfedc
1 #!/usr/bin/perl
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>.
23 use Modern::Perl;
24 use C4::Auth;
25 use C4::Koha;
26 use C4::Output;
27 use CGI qw ( -utf8 );
28 use C4::Acquisition;
29 use C4::Budgets;
30 use C4::Contract;
31 use C4::Debug;
32 use C4::Biblio;
33 use C4::Members qw/GetMember/; #needed for permissions checking for changing basketgroup of a basket
34 use C4::Items;
35 use C4::Suggestions;
36 use Koha::Biblios;
37 use Koha::Acquisition::Booksellers;
38 use Koha::Libraries;
39 use C4::Letters qw/SendAlerts/;
40 use Date::Calc qw/Add_Delta_Days/;
41 use Koha::Database;
42 use Koha::EDI qw( create_edi_order get_edifact_ean );
44 =head1 NAME
46 basket.pl
48 =head1 DESCRIPTION
50 This script display all informations about basket for the supplier given
51 on input arg. Moreover, it allows us to add a new order for this supplier from
52 an existing record, a suggestion or a new record.
54 =head1 CGI PARAMETERS
56 =over 4
58 =item $basketno
60 The basket number.
62 =item booksellerid
64 the supplier this script have to display the basket.
66 =item order
68 =back
70 =cut
72 our $query = new CGI;
73 our $basketno = $query->param('basketno');
74 our $ean = $query->param('ean');
75 our $booksellerid = $query->param('booksellerid');
76 my $duplinbatch = $query->param('duplinbatch');
78 our ( $template, $loggedinuser, $cookie, $userflags ) = get_template_and_user(
80 template_name => "acqui/basket.tt",
81 query => $query,
82 type => "intranet",
83 authnotrequired => 0,
84 flagsrequired => { acquisition => 'order_manage' },
85 debug => 1,
89 our $basket = GetBasket($basketno);
90 $booksellerid = $basket->{booksellerid} unless $booksellerid;
91 my $bookseller = Koha::Acquisition::Booksellers->find( $booksellerid );
92 my $schema = Koha::Database->new()->schema();
93 my $rs = $schema->resultset('VendorEdiAccount')->search(
94 { vendor_id => $booksellerid, } );
95 $template->param( ediaccount => ($rs->count > 0));
97 unless (CanUserManageBasket($loggedinuser, $basket, $userflags)) {
98 $template->param(
99 cannot_manage_basket => 1,
100 basketno => $basketno,
101 basketname => $basket->{basketname},
102 booksellerid => $booksellerid,
103 name => $bookseller->name,
105 output_html_with_http_headers $query, $cookie, $template->output;
106 exit;
109 # FIXME : what about the "discount" percentage?
110 # FIXME : the query->param('booksellerid') below is probably useless. The bookseller is always known from the basket
111 # if no booksellerid in parameter, get it from basket
112 # warn "=>".$basket->{booksellerid};
113 my $op = $query->param('op') // 'list';
115 our $confirm_pref= C4::Context->preference("BasketConfirmations") || '1';
116 $template->param( skip_confirm_reopen => 1) if $confirm_pref eq '2';
118 my @messages;
120 if ( $op eq 'delete_confirm' ) {
121 my $basketno = $query->param('basketno');
122 my $delbiblio = $query->param('delbiblio');
123 my @orders = GetOrders($basketno);
124 #Delete all orders included in that basket, and all items received.
125 foreach my $myorder (@orders){
126 DelOrder($myorder->{biblionumber},$myorder->{ordernumber});
128 # if $delbiblio = 1, delete the records if possible
129 if ((defined $delbiblio)and ($delbiblio ==1)){
130 my @cannotdelbiblios ;
131 foreach my $myorder (@orders){
132 my $biblionumber = $myorder->{'biblionumber'};
133 my $biblio = Koha::Biblios->find( $biblionumber );
134 my $countbiblio = CountBiblioInOrders($biblionumber);
135 my $ordernumber = $myorder->{'ordernumber'};
136 my $subscriptions = scalar GetSubscriptionsId ($biblionumber);
137 my $itemcount = $biblio->items->count;
138 my $error;
139 if ($countbiblio == 0 && $itemcount == 0 && $subscriptions == 0) {
140 $error = DelBiblio($myorder->{biblionumber}) }
141 else {
142 push @cannotdelbiblios, {biblionumber=> ($myorder->{biblionumber}),
143 title=> $myorder->{'title'},
144 author=> $myorder->{'author'},
145 countbiblio=> $countbiblio,
146 itemcount=>$itemcount,
147 subscriptions=>$subscriptions};
149 if ($error) {
150 push @cannotdelbiblios, {biblionumber=> ($myorder->{biblionumber}),
151 title=> $myorder->{'title'},
152 author=> $myorder->{'author'},
153 othererror=> $error};
156 $template->param( cannotdelbiblios => \@cannotdelbiblios );
158 # delete the basket
159 DelBasket($basketno,);
160 $template->param(
161 delete_confirmed => 1,
162 name => $bookseller->name,
163 booksellerid => $booksellerid,
165 } elsif ( !$bookseller ) {
166 $template->param( NO_BOOKSELLER => 1 );
167 } elsif ($op eq 'export') {
168 print $query->header(
169 -type => 'text/csv',
170 -attachment => 'basket' . $basket->{'basketno'} . '.csv',
172 print GetBasketAsCSV($query->param('basketno'), $query);
173 exit;
174 } elsif ($op eq 'email') {
175 my $err = eval {
176 SendAlerts( 'orderacquisition', $query->param('basketno'), 'ACQORDER' );
178 if ( $@ ) {
179 push @messages, { type => 'error', code => $@ };
180 } elsif ( ref $err and exists $err->{error} ) {
181 push @messages, { type => 'error', code => $err->{error} };
182 } else {
183 push @messages, { type => 'message', code => 'email_sent' };
186 $op = 'list';
187 } elsif ($op eq 'close') {
188 my $confirm = $query->param('confirm') || $confirm_pref eq '2';
189 if ($confirm) {
190 my $basketno = $query->param('basketno');
191 my $booksellerid = $query->param('booksellerid');
192 $basketno =~ /^\d+$/ and CloseBasket($basketno);
193 # if requested, create basket group, close it and attach the basket
194 if ($query->param('createbasketgroup')) {
195 my $branchcode;
196 if(C4::Context->userenv and C4::Context->userenv->{'branch'}
197 and C4::Context->userenv->{'branch'} ne "NO_LIBRARY_SET") {
198 $branchcode = C4::Context->userenv->{'branch'};
200 my $basketgroupid = NewBasketgroup( { name => $basket->{basketname},
201 booksellerid => $booksellerid,
202 deliveryplace => $branchcode,
203 billingplace => $branchcode,
204 closed => 1,
206 ModBasket( { basketno => $basketno,
207 basketgroupid => $basketgroupid } );
208 print $query->redirect('/cgi-bin/koha/acqui/basketgroup.pl?booksellerid='.$booksellerid.'&closed=1');
209 } else {
210 print $query->redirect('/cgi-bin/koha/acqui/booksellers.pl?booksellerid=' . $booksellerid);
212 exit;
213 } else {
214 $template->param(
215 confirm_close => "1",
216 booksellerid => $booksellerid,
217 basketno => $basket->{'basketno'},
218 basketname => $basket->{'basketname'},
219 basketgroupname => $basket->{'basketname'},
222 } elsif ($op eq 'reopen') {
223 ReopenBasket($query->param('basketno'));
224 print $query->redirect('/cgi-bin/koha/acqui/basket.pl?basketno='.$basket->{'basketno'})
226 elsif ( $op eq 'ediorder' ) {
227 edi_close_and_order()
228 } elsif ( $op eq 'mod_users' ) {
229 my $basketusers_ids = $query->param('users_ids');
230 my @basketusers = split( /:/, $basketusers_ids );
231 ModBasketUsers($basketno, @basketusers);
232 print $query->redirect("/cgi-bin/koha/acqui/basket.pl?basketno=$basketno");
233 exit;
234 } elsif ( $op eq 'mod_branch' ) {
235 my $branch = $query->param('branch');
236 $branch = undef if(defined $branch and $branch eq '');
237 ModBasket({
238 basketno => $basket->{basketno},
239 branch => $branch
241 print $query->redirect("/cgi-bin/koha/acqui/basket.pl?basketno=$basketno");
242 exit;
245 if ( $op eq 'list' ) {
246 my @branches_loop;
247 # get librarian branch...
248 if ( C4::Context->preference("IndependentBranches") ) {
249 my $userenv = C4::Context->userenv;
250 unless ( C4::Context->IsSuperLibrarian() ) {
251 my $validtest = ( $basket->{creationdate} eq '' )
252 || ( $userenv->{branch} eq $basket->{branch} )
253 || ( $userenv->{branch} eq '' )
254 || ( $basket->{branch} eq '' );
255 unless ($validtest) {
256 print $query->redirect("../mainpage.pl");
257 exit 0;
261 if (!defined $basket->{branch} or $basket->{branch} eq $userenv->{branch}) {
262 push @branches_loop, {
263 branchcode => $userenv->{branch},
264 branchname => $userenv->{branchname},
265 selected => 1,
268 } else {
269 # get branches
270 my $branches = Koha::Libraries->search( {}, { order_by => ['branchname'] } )->unblessed;
271 foreach my $branch (@$branches) {
272 my $selected = 0;
273 if (defined $basket->{branch}) {
274 $selected = 1 if $branch->{branchcode} eq $basket->{branch};
275 } else {
276 $selected = 1 if $branch->{branchcode} eq C4::Context->userenv->{branch};
278 push @branches_loop, {
279 branchcode => $branch->{branchcode},
280 branchname => $branch->{branchname},
281 selected => $selected
286 #if the basket is closed,and the user has the permission to edit basketgroups, display a list of basketgroups
287 my ($basketgroup, $basketgroups);
288 my $staffuser = GetMember(borrowernumber => $loggedinuser);
289 if ($basket->{closedate} && haspermission($staffuser->{userid}, { acquisition => 'group_manage'} )) {
290 $basketgroups = GetBasketgroups($basket->{booksellerid});
291 for my $bg ( @{$basketgroups} ) {
292 if ($basket->{basketgroupid} && $basket->{basketgroupid} == $bg->{id}){
293 $bg->{default} = 1;
294 $basketgroup = $bg;
299 # if the basket is closed, calculate estimated delivery date
300 my $estimateddeliverydate;
301 if( $basket->{closedate} ) {
302 my ($year, $month, $day) = ($basket->{closedate} =~ /(\d+)-(\d+)-(\d+)/);
303 ($year, $month, $day) = Add_Delta_Days($year, $month, $day, $bookseller->deliverytime);
304 $estimateddeliverydate = sprintf( "%04d-%02d-%02d", $year, $month, $day );
307 # if new basket, pre-fill infos
308 $basket->{creationdate} = "" unless ( $basket->{creationdate} );
309 $basket->{authorisedby} = $loggedinuser unless ( $basket->{authorisedby} );
310 $debug
311 and warn sprintf
312 "loggedinuser: $loggedinuser; creationdate: %s; authorisedby: %s",
313 $basket->{creationdate}, $basket->{authorisedby};
315 my @basketusers_ids = GetBasketUsers($basketno);
316 my @basketusers;
317 foreach my $basketuser_id (@basketusers_ids) {
318 my $basketuser = GetMember(borrowernumber => $basketuser_id);
319 push @basketusers, $basketuser if $basketuser;
322 my $active_currency = Koha::Acquisition::Currencies->get_active;
324 my @orders = GetOrders( $basketno );
325 my @books_loop;
327 my @book_foot_loop;
328 my %foot;
329 my $total_quantity = 0;
330 my $total_tax_excluded = 0;
331 my $total_tax_included = 0;
332 my $total_tax_value = 0;
333 for my $order (@orders) {
334 my $line = get_order_infos( $order, $bookseller);
335 if ( $line->{uncertainprice} ) {
336 $template->param( uncertainprices => 1 );
339 $line->{tax_rate} = $line->{tax_rate_on_ordering};
340 $line->{tax_value} = $line->{tax_value_on_ordering};
342 push @books_loop, $line;
344 $foot{$$line{tax_rate}}{tax_rate} = $$line{tax_rate};
345 $foot{$$line{tax_rate}}{tax_value} += $$line{tax_value};
346 $total_tax_value += $$line{tax_value};
347 $foot{$$line{tax_rate}}{quantity} += $$line{quantity};
348 $total_quantity += $$line{quantity};
349 $foot{$$line{tax_rate}}{total_tax_excluded} += $$line{total_tax_excluded};
350 $total_tax_excluded += $$line{total_tax_excluded};
351 $foot{$$line{tax_rate}}{total_tax_included} += $$line{total_tax_included};
352 $total_tax_included += $$line{total_tax_included};
355 push @book_foot_loop, map {$_} values %foot;
357 # Get cancelled orders
358 my @cancelledorders = GetOrders($basketno, { cancelled => 1 });
359 my @cancelledorders_loop;
360 for my $order (@cancelledorders) {
361 my $line = get_order_infos( $order, $bookseller);
362 push @cancelledorders_loop, $line;
365 my $contract = GetContract({
366 contractnumber => $basket->{contractnumber}
369 if ($basket->{basketgroupid}){
370 $basketgroup = GetBasketgroup($basket->{basketgroupid});
372 my $borrower= GetMember('borrowernumber' => $loggedinuser);
373 my $budgets = GetBudgetHierarchy;
374 my $has_budgets = 0;
375 foreach my $r (@{$budgets}) {
376 if (!defined $r->{budget_amount} || $r->{budget_amount} == 0) {
377 next;
379 next unless (CanUserUseBudget($loggedinuser, $r, $userflags));
381 $has_budgets = 1;
382 last;
385 $template->param(
386 basketno => $basketno,
387 basket => $basket,
388 basketname => $basket->{'basketname'},
389 basketbranchcode => $basket->{branch},
390 basketnote => $basket->{note},
391 basketbooksellernote => $basket->{booksellernote},
392 basketcontractno => $basket->{contractnumber},
393 basketcontractname => $contract->{contractname},
394 branches_loop => \@branches_loop,
395 creationdate => $basket->{creationdate},
396 authorisedby => $basket->{authorisedby},
397 authorisedbyname => $basket->{authorisedbyname},
398 users_ids => join(':', @basketusers_ids),
399 users => \@basketusers,
400 closedate => $basket->{closedate},
401 estimateddeliverydate=> $estimateddeliverydate,
402 is_standing => $basket->{is_standing},
403 deliveryplace => $basket->{deliveryplace},
404 billingplace => $basket->{billingplace},
405 active => $bookseller->active,
406 booksellerid => $bookseller->id,
407 name => $bookseller->name,
408 books_loop => \@books_loop,
409 book_foot_loop => \@book_foot_loop,
410 cancelledorders_loop => \@cancelledorders_loop,
411 total_quantity => $total_quantity,
412 total_tax_excluded => $total_tax_excluded,
413 total_tax_included => $total_tax_included,
414 total_tax_value => $total_tax_value,
415 currency => $active_currency->currency,
416 listincgst => $bookseller->listincgst,
417 basketgroups => $basketgroups,
418 basketgroup => $basketgroup,
419 grouped => $basket->{basketgroupid},
420 # The double negatives and booleans here mean:
421 # "A basket cannot be closed if there are no orders in it or it's a standing order basket."
423 # (The template has another implicit restriction that the order cannot be closed if there
424 # are any orders with uncertain prices.)
425 unclosable => @orders ? $basket->{is_standing} : 1,
426 has_budgets => $has_budgets,
427 duplinbatch => $duplinbatch,
431 $template->param( messages => \@messages );
432 output_html_with_http_headers $query, $cookie, $template->output;
434 sub get_order_infos {
435 my $order = shift;
436 my $bookseller = shift;
437 my $qty = $order->{'quantity'} || 0;
438 if ( !defined $order->{quantityreceived} ) {
439 $order->{quantityreceived} = 0;
441 my $budget = GetBudget($order->{budget_id});
442 my $basket = GetBasket($order->{basketno});
444 my %line = %{ $order };
445 # Don't show unreceived standing orders as received
446 $line{order_received} = ( $qty == $order->{'quantityreceived'} && ( $basket->{is_standing} ? $qty : 1 ) );
447 $line{basketno} = $basketno;
448 $line{budget_name} = $budget->{budget_name};
450 $line{total_tax_included} = $line{ecost_tax_included} * $line{quantity};
451 $line{total_tax_excluded} = $line{ecost_tax_excluded} * $line{quantity};
452 $line{tax_value} = $line{tax_value_on_ordering};
453 $line{tax_rate} = $line{tax_rate_on_ordering};
455 if ( $line{uncertainprice} ) {
456 $line{rrp_tax_excluded} .= ' (Uncertain)';
458 if ( $line{'title'} ) {
459 my $volume = $order->{'volume'};
460 my $seriestitle = $order->{'seriestitle'};
461 $line{'title'} .= " / $seriestitle" if $seriestitle;
462 $line{'title'} .= " / $volume" if $volume;
465 my $biblionumber = $order->{'biblionumber'};
466 if ( $biblionumber ) { # The biblio still exists
467 my $biblio = Koha::Biblios->find( $biblionumber );
468 my $countbiblio = CountBiblioInOrders($biblionumber);
469 my $ordernumber = $order->{'ordernumber'};
470 my @subscriptions = GetSubscriptionsId ($biblionumber);
471 my $itemcount = $biblio->items->count;
472 my $holds_count = $biblio->holds->count;
473 my @items = GetItemnumbersFromOrder( $ordernumber );
474 my $itemholds = $biblio->holds->search({ itemnumber => { -in => \@items } })->count;
476 # 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
477 $line{can_del_bib} = 1 if $countbiblio <= 1 && $itemcount == scalar @items && !(@subscriptions) && !($holds_count);
478 $line{items} = ($itemcount) - (scalar @items);
479 $line{left_item} = 1 if $line{items} >= 1;
480 $line{left_biblio} = 1 if $countbiblio > 1;
481 $line{biblios} = $countbiblio - 1;
482 $line{left_subscription} = 1 if scalar @subscriptions >= 1;
483 $line{subscriptions} = scalar @subscriptions;
484 ($holds_count >= 1) ? $line{left_holds} = 1 : $line{left_holds} = 0;
485 $line{left_holds_on_order} = 1 if $line{left_holds}==1 && ($line{items} == 0 || $itemholds );
486 $line{holds} = $holds_count;
487 $line{holds_on_order} = $itemholds?$itemholds:$holds_count if $line{left_holds_on_order};
491 my $suggestion = GetSuggestionInfoFromBiblionumber($line{biblionumber});
492 $line{suggestionid} = $$suggestion{suggestionid};
493 $line{surnamesuggestedby} = $$suggestion{surnamesuggestedby};
494 $line{firstnamesuggestedby} = $$suggestion{firstnamesuggestedby};
496 foreach my $key (qw(transferred_from transferred_to)) {
497 if ($line{$key}) {
498 my $order = GetOrder($line{$key});
499 my $bookseller = Koha::Acquisition::Booksellers->find( $basket->{booksellerid} );
500 $line{$key} = {
501 order => $order,
502 basket => $basket,
503 bookseller => $bookseller,
504 timestamp => $line{$key . '_timestamp'},
509 return \%line;
512 sub edi_close_and_order {
513 my $confirm = $query->param('confirm') || $confirm_pref eq '2';
514 if ($confirm) {
515 my $edi_params = {
516 basketno => $basketno,
517 ean => $ean,
519 if ( $basket->{branch} ) {
520 $edi_params->{branchcode} = $basket->{branch};
522 if ( create_edi_order($edi_params) ) {
523 #$template->param( edifile => 1 );
525 CloseBasket($basketno);
527 # if requested, create basket group, close it and attach the basket
528 if ( $query->param('createbasketgroup') ) {
529 my $branchcode;
530 if ( C4::Context->userenv
531 and C4::Context->userenv->{'branch'}
532 and C4::Context->userenv->{'branch'} ne "NO_LIBRARY_SET" )
534 $branchcode = C4::Context->userenv->{'branch'};
536 my $basketgroupid = NewBasketgroup(
538 name => $basket->{basketname},
539 booksellerid => $booksellerid,
540 deliveryplace => $branchcode,
541 billingplace => $branchcode,
542 closed => 1,
545 ModBasket(
547 basketno => $basketno,
548 basketgroupid => $basketgroupid
551 print $query->redirect(
552 "/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=$booksellerid&closed=1"
555 else {
556 print $query->redirect(
557 "/cgi-bin/koha/acqui/booksellers.pl?booksellerid=$booksellerid"
560 exit;
562 else {
563 $template->param(
564 edi_confirm => 1,
565 booksellerid => $booksellerid,
566 basketno => $basket->{basketno},
567 basketname => $basket->{basketname},
568 basketgroupname => $basket->{basketname},
570 if ($ean) {
571 $template->param( ean => $ean );
575 return;