Bug 13321: Fix table display in invoice page
[koha.git] / acqui / basket.pl
bloba7a01fd655da26f54bc9a92f7f1b7836df41de79
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::Libraries;
37 use C4::Letters qw/SendAlerts/;
38 use Date::Calc qw/Add_Delta_Days/;
39 use Koha::Database;
40 use Koha::EDI qw( create_edi_order get_edifact_ean );
42 =head1 NAME
44 basket.pl
46 =head1 DESCRIPTION
48 This script display all informations about basket for the supplier given
49 on input arg. Moreover, it allows us to add a new order for this supplier from
50 an existing record, a suggestion or a new record.
52 =head1 CGI PARAMETERS
54 =over 4
56 =item $basketno
58 The basket number.
60 =item booksellerid
62 the supplier this script have to display the basket.
64 =item order
66 =back
68 =cut
70 my $query = new CGI;
71 our $basketno = $query->param('basketno');
72 my $ean = $query->param('ean');
73 my $booksellerid = $query->param('booksellerid');
74 my $duplinbatch = $query->param('duplinbatch');
76 my ( $template, $loggedinuser, $cookie, $userflags ) = get_template_and_user(
78 template_name => "acqui/basket.tt",
79 query => $query,
80 type => "intranet",
81 authnotrequired => 0,
82 flagsrequired => { acquisition => 'order_manage' },
83 debug => 1,
87 my $basket = GetBasket($basketno);
88 $booksellerid = $basket->{booksellerid} unless $booksellerid;
89 my $bookseller = Koha::Acquisition::Bookseller->fetch({ id => $booksellerid });
90 my $schema = Koha::Database->new()->schema();
91 my $rs = $schema->resultset('VendorEdiAccount')->search(
92 { vendor_id => $booksellerid, } );
93 $template->param( ediaccount => ($rs->count > 0));
95 unless (CanUserManageBasket($loggedinuser, $basket, $userflags)) {
96 $template->param(
97 cannot_manage_basket => 1,
98 basketno => $basketno,
99 basketname => $basket->{basketname},
100 booksellerid => $booksellerid,
101 name => $bookseller->{name}
103 output_html_with_http_headers $query, $cookie, $template->output;
104 exit;
107 # FIXME : what about the "discount" percentage?
108 # FIXME : the query->param('booksellerid') below is probably useless. The bookseller is always known from the basket
109 # if no booksellerid in parameter, get it from basket
110 # warn "=>".$basket->{booksellerid};
111 my $op = $query->param('op') // 'list';
113 my $confirm_pref= C4::Context->preference("BasketConfirmations") || '1';
114 $template->param( skip_confirm_reopen => 1) if $confirm_pref eq '2';
116 my @messages;
118 if ( $op eq 'delete_confirm' ) {
119 my $basketno = $query->param('basketno');
120 my $delbiblio = $query->param('delbiblio');
121 my @orders = GetOrders($basketno);
122 #Delete all orders included in that basket, and all items received.
123 foreach my $myorder (@orders){
124 DelOrder($myorder->{biblionumber},$myorder->{ordernumber});
126 # if $delbiblio = 1, delete the records if possible
127 if ((defined $delbiblio)and ($delbiblio ==1)){
128 my @cannotdelbiblios ;
129 foreach my $myorder (@orders){
130 my $biblionumber = $myorder->{'biblionumber'};
131 my $countbiblio = CountBiblioInOrders($biblionumber);
132 my $ordernumber = $myorder->{'ordernumber'};
133 my $subscriptions = scalar GetSubscriptionsId ($biblionumber);
134 my $itemcount = GetItemsCount($biblionumber);
135 my $error;
136 if ($countbiblio == 0 && $itemcount == 0 && $subscriptions == 0) {
137 $error = DelBiblio($myorder->{biblionumber}) }
138 else {
139 push @cannotdelbiblios, {biblionumber=> ($myorder->{biblionumber}),
140 title=> $myorder->{'title'},
141 author=> $myorder->{'author'},
142 countbiblio=> $countbiblio,
143 itemcount=>$itemcount,
144 subscriptions=>$subscriptions};
146 if ($error) {
147 push @cannotdelbiblios, {biblionumber=> ($myorder->{biblionumber}),
148 title=> $myorder->{'title'},
149 author=> $myorder->{'author'},
150 othererror=> $error};
153 $template->param( cannotdelbiblios => \@cannotdelbiblios );
155 # delete the basket
156 DelBasket($basketno,);
157 $template->param( delete_confirmed => 1 );
158 } elsif ( !$bookseller ) {
159 $template->param( NO_BOOKSELLER => 1 );
160 } elsif ($op eq 'export') {
161 print $query->header(
162 -type => 'text/csv',
163 -attachment => 'basket' . $basket->{'basketno'} . '.csv',
165 print GetBasketAsCSV($query->param('basketno'), $query);
166 exit;
167 } elsif ($op eq 'email') {
168 my $err = eval {
169 SendAlerts( 'orderacquisition', $query->param('basketno'), 'ACQORDER' );
171 if ( $@ ) {
172 push @messages, { type => 'error', code => $@ };
173 } elsif ( ref $err and exists $err->{error} ) {
174 push @messages, { type => 'error', code => $err->{error} };
175 } else {
176 push @messages, { type => 'message', code => 'email_sent' };
179 $op = 'list';
180 } elsif ($op eq 'close') {
181 my $confirm = $query->param('confirm') || $confirm_pref eq '2';
182 if ($confirm) {
183 my $basketno = $query->param('basketno');
184 my $booksellerid = $query->param('booksellerid');
185 $basketno =~ /^\d+$/ and CloseBasket($basketno);
186 # if requested, create basket group, close it and attach the basket
187 if ($query->param('createbasketgroup')) {
188 my $branchcode;
189 if(C4::Context->userenv and C4::Context->userenv->{'branch'}
190 and C4::Context->userenv->{'branch'} ne "NO_LIBRARY_SET") {
191 $branchcode = C4::Context->userenv->{'branch'};
193 my $basketgroupid = NewBasketgroup( { name => $basket->{basketname},
194 booksellerid => $booksellerid,
195 deliveryplace => $branchcode,
196 billingplace => $branchcode,
197 closed => 1,
199 ModBasket( { basketno => $basketno,
200 basketgroupid => $basketgroupid } );
201 print $query->redirect('/cgi-bin/koha/acqui/basketgroup.pl?booksellerid='.$booksellerid.'&closed=1');
202 } else {
203 print $query->redirect('/cgi-bin/koha/acqui/booksellers.pl?booksellerid=' . $booksellerid);
205 exit;
206 } else {
207 $template->param(
208 confirm_close => "1",
209 booksellerid => $booksellerid,
210 basketno => $basket->{'basketno'},
211 basketname => $basket->{'basketname'},
212 basketgroupname => $basket->{'basketname'},
215 } elsif ($op eq 'reopen') {
216 ReopenBasket($query->param('basketno'));
217 print $query->redirect('/cgi-bin/koha/acqui/basket.pl?basketno='.$basket->{'basketno'})
219 elsif ( $op eq 'ediorder' ) {
220 edi_close_and_order()
221 } elsif ( $op eq 'mod_users' ) {
222 my $basketusers_ids = $query->param('users_ids');
223 my @basketusers = split( /:/, $basketusers_ids );
224 ModBasketUsers($basketno, @basketusers);
225 print $query->redirect("/cgi-bin/koha/acqui/basket.pl?basketno=$basketno");
226 exit;
227 } elsif ( $op eq 'mod_branch' ) {
228 my $branch = $query->param('branch');
229 $branch = undef if(defined $branch and $branch eq '');
230 ModBasket({
231 basketno => $basket->{basketno},
232 branch => $branch
234 print $query->redirect("/cgi-bin/koha/acqui/basket.pl?basketno=$basketno");
235 exit;
238 if ( $op eq 'list' ) {
239 my @branches_loop;
240 # get librarian branch...
241 if ( C4::Context->preference("IndependentBranches") ) {
242 my $userenv = C4::Context->userenv;
243 unless ( C4::Context->IsSuperLibrarian() ) {
244 my $validtest = ( $basket->{creationdate} eq '' )
245 || ( $userenv->{branch} eq $basket->{branch} )
246 || ( $userenv->{branch} eq '' )
247 || ( $basket->{branch} eq '' );
248 unless ($validtest) {
249 print $query->redirect("../mainpage.pl");
250 exit 0;
254 if (!defined $basket->{branch} or $basket->{branch} eq $userenv->{branch}) {
255 push @branches_loop, {
256 branchcode => $userenv->{branch},
257 branchname => $userenv->{branchname},
258 selected => 1,
261 } else {
262 # get branches
263 my $branches = Koha::Libraries->search( {}, { order_by => ['branchname'] } )->unblessed;
264 foreach my $branch (@$branches) {
265 my $selected = 0;
266 if (defined $basket->{branch}) {
267 $selected = 1 if $branch->{branchcode} eq $basket->{branch};
268 } else {
269 $selected = 1 if $branch->{branchcode} eq C4::Context->userenv->{branch};
271 push @branches_loop, {
272 branchcode => $branch->{branchcode},
273 branchname => $branch->{branchname},
274 selected => $selected
279 #if the basket is closed,and the user has the permission to edit basketgroups, display a list of basketgroups
280 my ($basketgroup, $basketgroups);
281 my $staffuser = GetMember(borrowernumber => $loggedinuser);
282 if ($basket->{closedate} && haspermission($staffuser->{userid}, { acquisition => 'group_manage'} )) {
283 $basketgroups = GetBasketgroups($basket->{booksellerid});
284 for my $bg ( @{$basketgroups} ) {
285 if ($basket->{basketgroupid} && $basket->{basketgroupid} == $bg->{id}){
286 $bg->{default} = 1;
287 $basketgroup = $bg;
292 # if the basket is closed, calculate estimated delivery date
293 my $estimateddeliverydate;
294 if( $basket->{closedate} ) {
295 my ($year, $month, $day) = ($basket->{closedate} =~ /(\d+)-(\d+)-(\d+)/);
296 ($year, $month, $day) = Add_Delta_Days($year, $month, $day, $bookseller->{deliverytime});
297 $estimateddeliverydate = sprintf( "%04d-%02d-%02d", $year, $month, $day );
300 # if new basket, pre-fill infos
301 $basket->{creationdate} = "" unless ( $basket->{creationdate} );
302 $basket->{authorisedby} = $loggedinuser unless ( $basket->{authorisedby} );
303 $debug
304 and warn sprintf
305 "loggedinuser: $loggedinuser; creationdate: %s; authorisedby: %s",
306 $basket->{creationdate}, $basket->{authorisedby};
308 my @basketusers_ids = GetBasketUsers($basketno);
309 my @basketusers;
310 foreach my $basketuser_id (@basketusers_ids) {
311 my $basketuser = GetMember(borrowernumber => $basketuser_id);
312 push @basketusers, $basketuser if $basketuser;
315 my $active_currency = Koha::Acquisition::Currencies->get_active;
317 my @orders = GetOrders( $basketno );
318 my @books_loop;
320 my @book_foot_loop;
321 my %foot;
322 my $total_quantity = 0;
323 my $total_tax_excluded = 0;
324 my $total_tax_included = 0;
325 my $total_tax_value = 0;
326 for my $order (@orders) {
327 my $line = get_order_infos( $order, $bookseller);
328 if ( $line->{uncertainprice} ) {
329 $template->param( uncertainprices => 1 );
332 push @books_loop, $line;
334 $foot{$$line{tax_rate}}{tax_rate} = $$line{tax_rate};
335 $foot{$$line{tax_rate}}{tax_value} += $$line{tax_value};
336 $total_tax_value += $$line{tax_value};
337 $foot{$$line{tax_rate}}{quantity} += $$line{quantity};
338 $total_quantity += $$line{quantity};
339 $foot{$$line{tax_rate}}{total_tax_excluded} += $$line{total_tax_excluded};
340 $total_tax_excluded += $$line{total_tax_excluded};
341 $foot{$$line{tax_rate}}{total_tax_included} += $$line{total_tax_included};
342 $total_tax_included += $$line{total_tax_included};
345 push @book_foot_loop, map {$_} values %foot;
347 # Get cancelled orders
348 my @cancelledorders = GetOrders($basketno, { cancelled => 1 });
349 my @cancelledorders_loop;
350 for my $order (@cancelledorders) {
351 my $line = get_order_infos( $order, $bookseller);
352 push @cancelledorders_loop, $line;
355 my $contract = GetContract({
356 contractnumber => $basket->{contractnumber}
359 if ($basket->{basketgroupid}){
360 $basketgroup = GetBasketgroup($basket->{basketgroupid});
362 my $borrower= GetMember('borrowernumber' => $loggedinuser);
363 my $budgets = GetBudgetHierarchy;
364 my $has_budgets = 0;
365 foreach my $r (@{$budgets}) {
366 if (!defined $r->{budget_amount} || $r->{budget_amount} == 0) {
367 next;
369 next unless (CanUserUseBudget($loggedinuser, $r, $userflags));
371 $has_budgets = 1;
372 last;
375 $template->param(
376 basketno => $basketno,
377 basket => $basket,
378 basketname => $basket->{'basketname'},
379 basketbranchcode => $basket->{branch},
380 basketnote => $basket->{note},
381 basketbooksellernote => $basket->{booksellernote},
382 basketcontractno => $basket->{contractnumber},
383 basketcontractname => $contract->{contractname},
384 branches_loop => \@branches_loop,
385 creationdate => $basket->{creationdate},
386 authorisedby => $basket->{authorisedby},
387 authorisedbyname => $basket->{authorisedbyname},
388 users_ids => join(':', @basketusers_ids),
389 users => \@basketusers,
390 closedate => $basket->{closedate},
391 estimateddeliverydate=> $estimateddeliverydate,
392 is_standing => $basket->{is_standing},
393 deliveryplace => $basket->{deliveryplace},
394 billingplace => $basket->{billingplace},
395 active => $bookseller->{'active'},
396 booksellerid => $bookseller->{'id'},
397 name => $bookseller->{'name'},
398 books_loop => \@books_loop,
399 book_foot_loop => \@book_foot_loop,
400 cancelledorders_loop => \@cancelledorders_loop,
401 total_quantity => $total_quantity,
402 total_tax_excluded => $total_tax_excluded,
403 total_tax_included => $total_tax_included,
404 total_tax_value => $total_tax_value,
405 currency => $active_currency->currency,
406 listincgst => $bookseller->{listincgst},
407 basketgroups => $basketgroups,
408 basketgroup => $basketgroup,
409 grouped => $basket->{basketgroupid},
410 # The double negatives and booleans here mean:
411 # "A basket cannot be closed if there are no orders in it or it's a standing order basket."
413 # (The template has another implicit restriction that the order cannot be closed if there
414 # are any orders with uncertain prices.)
415 unclosable => @orders ? $basket->{is_standing} : 1,
416 has_budgets => $has_budgets,
417 duplinbatch => $duplinbatch,
421 $template->param( messages => \@messages );
422 output_html_with_http_headers $query, $cookie, $template->output;
424 sub get_order_infos {
425 my $order = shift;
426 my $bookseller = shift;
427 my $qty = $order->{'quantity'} || 0;
428 if ( !defined $order->{quantityreceived} ) {
429 $order->{quantityreceived} = 0;
431 my $budget = GetBudget($order->{budget_id});
432 my $basket = GetBasket($order->{basketno});
434 my %line = %{ $order };
435 # Don't show unreceived standing orders as received
436 $line{order_received} = ( $qty == $order->{'quantityreceived'} && ( $basket->{is_standing} ? $qty : 1 ) );
437 $line{basketno} = $basketno;
438 $line{budget_name} = $budget->{budget_name};
440 $line{total_tax_included} = $line{ecost_tax_included} * $line{quantity};
441 $line{total_tax_excluded} = $line{ecost_tax_excluded} * $line{quantity};
443 if ( $line{uncertainprice} ) {
444 $line{rrp_tax_excluded} .= ' (Uncertain)';
446 if ( $line{'title'} ) {
447 my $volume = $order->{'volume'};
448 my $seriestitle = $order->{'seriestitle'};
449 $line{'title'} .= " / $seriestitle" if $seriestitle;
450 $line{'title'} .= " / $volume" if $volume;
453 my $biblionumber = $order->{'biblionumber'};
454 my $countbiblio = CountBiblioInOrders($biblionumber);
455 my $ordernumber = $order->{'ordernumber'};
456 my @subscriptions = GetSubscriptionsId ($biblionumber);
457 my $itemcount = GetItemsCount($biblionumber);
458 my $holds = GetHolds ($biblionumber);
459 my @items = GetItemnumbersFromOrder( $ordernumber );
460 my $itemholds;
461 foreach my $item (@items){
462 my $nb = GetItemHolds($biblionumber, $item);
463 if ($nb){
464 $itemholds += $nb;
467 # 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
468 $line{can_del_bib} = 1 if $countbiblio <= 1 && $itemcount == scalar @items && !(@subscriptions) && !($holds);
469 $line{items} = ($itemcount) - (scalar @items);
470 $line{left_item} = 1 if $line{items} >= 1;
471 $line{left_biblio} = 1 if $countbiblio > 1;
472 $line{biblios} = $countbiblio - 1;
473 $line{left_subscription} = 1 if scalar @subscriptions >= 1;
474 $line{subscriptions} = scalar @subscriptions;
475 ($holds >= 1) ? $line{left_holds} = 1 : $line{left_holds} = 0;
476 $line{left_holds_on_order} = 1 if $line{left_holds}==1 && ($line{items} == 0 || $itemholds );
477 $line{holds} = $holds;
478 $line{holds_on_order} = $itemholds?$itemholds:$holds if $line{left_holds_on_order};
481 my $suggestion = GetSuggestionInfoFromBiblionumber($line{biblionumber});
482 $line{suggestionid} = $$suggestion{suggestionid};
483 $line{surnamesuggestedby} = $$suggestion{surnamesuggestedby};
484 $line{firstnamesuggestedby} = $$suggestion{firstnamesuggestedby};
486 foreach my $key (qw(transferred_from transferred_to)) {
487 if ($line{$key}) {
488 my $order = GetOrder($line{$key});
489 my $bookseller = Koha::Acquisition::Bookseller->fetch({ id => $basket->{booksellerid} });
490 $line{$key} = {
491 order => $order,
492 basket => $basket,
493 bookseller => $bookseller,
494 timestamp => $line{$key . '_timestamp'},
499 return \%line;
502 sub edi_close_and_order {
503 my $confirm = $query->param('confirm') || $confirm_pref eq '2';
504 if ($confirm) {
505 my $edi_params = {
506 basketno => $basketno,
507 ean => $ean,
509 if ( $basket->{branch} ) {
510 $edi_params->{branchcode} = $basket->{branch};
512 if ( create_edi_order($edi_params) ) {
513 #$template->param( edifile => 1 );
515 CloseBasket($basketno);
517 # if requested, create basket group, close it and attach the basket
518 if ( $query->param('createbasketgroup') ) {
519 my $branchcode;
520 if ( C4::Context->userenv
521 and C4::Context->userenv->{'branch'}
522 and C4::Context->userenv->{'branch'} ne "NO_LIBRARY_SET" )
524 $branchcode = C4::Context->userenv->{'branch'};
526 my $basketgroupid = NewBasketgroup(
528 name => $basket->{basketname},
529 booksellerid => $booksellerid,
530 deliveryplace => $branchcode,
531 billingplace => $branchcode,
532 closed => 1,
535 ModBasket(
537 basketno => $basketno,
538 basketgroupid => $basketgroupid
541 print $query->redirect(
542 "/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=$booksellerid&closed=1"
545 else {
546 print $query->redirect(
547 "/cgi-bin/koha/acqui/booksellers.pl?booksellerid=$booksellerid"
550 exit;
552 else {
553 $template->param(
554 edi_confirm => 1,
555 booksellerid => $booksellerid,
556 basketno => $basket->{basketno},
557 basketname => $basket->{basketname},
558 basketgroupname => $basket->{basketname},
560 if ($ean) {
561 $template->param( ean => $ean );
565 return;