DBRev 16.12.00.000 - the road goes ever on
[koha.git] / acqui / basket.pl
blobca2d2d2068e4244a0bc9fa10b4b6fb4ac8742345
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 $line->{tax_rate} = $line->{tax_rate_on_ordering};
333 $line->{tax_value} = $line->{tax_value_on_ordering};
335 push @books_loop, $line;
337 $foot{$$line{tax_rate}}{tax_rate} = $$line{tax_rate};
338 $foot{$$line{tax_rate}}{tax_value} += $$line{tax_value};
339 $total_tax_value += $$line{tax_value};
340 $foot{$$line{tax_rate}}{quantity} += $$line{quantity};
341 $total_quantity += $$line{quantity};
342 $foot{$$line{tax_rate}}{total_tax_excluded} += $$line{total_tax_excluded};
343 $total_tax_excluded += $$line{total_tax_excluded};
344 $foot{$$line{tax_rate}}{total_tax_included} += $$line{total_tax_included};
345 $total_tax_included += $$line{total_tax_included};
348 push @book_foot_loop, map {$_} values %foot;
350 # Get cancelled orders
351 my @cancelledorders = GetOrders($basketno, { cancelled => 1 });
352 my @cancelledorders_loop;
353 for my $order (@cancelledorders) {
354 my $line = get_order_infos( $order, $bookseller);
355 push @cancelledorders_loop, $line;
358 my $contract = GetContract({
359 contractnumber => $basket->{contractnumber}
362 if ($basket->{basketgroupid}){
363 $basketgroup = GetBasketgroup($basket->{basketgroupid});
365 my $borrower= GetMember('borrowernumber' => $loggedinuser);
366 my $budgets = GetBudgetHierarchy;
367 my $has_budgets = 0;
368 foreach my $r (@{$budgets}) {
369 if (!defined $r->{budget_amount} || $r->{budget_amount} == 0) {
370 next;
372 next unless (CanUserUseBudget($loggedinuser, $r, $userflags));
374 $has_budgets = 1;
375 last;
378 $template->param(
379 basketno => $basketno,
380 basket => $basket,
381 basketname => $basket->{'basketname'},
382 basketbranchcode => $basket->{branch},
383 basketnote => $basket->{note},
384 basketbooksellernote => $basket->{booksellernote},
385 basketcontractno => $basket->{contractnumber},
386 basketcontractname => $contract->{contractname},
387 branches_loop => \@branches_loop,
388 creationdate => $basket->{creationdate},
389 authorisedby => $basket->{authorisedby},
390 authorisedbyname => $basket->{authorisedbyname},
391 users_ids => join(':', @basketusers_ids),
392 users => \@basketusers,
393 closedate => $basket->{closedate},
394 estimateddeliverydate=> $estimateddeliverydate,
395 is_standing => $basket->{is_standing},
396 deliveryplace => $basket->{deliveryplace},
397 billingplace => $basket->{billingplace},
398 active => $bookseller->{'active'},
399 booksellerid => $bookseller->{'id'},
400 name => $bookseller->{'name'},
401 books_loop => \@books_loop,
402 book_foot_loop => \@book_foot_loop,
403 cancelledorders_loop => \@cancelledorders_loop,
404 total_quantity => $total_quantity,
405 total_tax_excluded => $total_tax_excluded,
406 total_tax_included => $total_tax_included,
407 total_tax_value => $total_tax_value,
408 currency => $active_currency->currency,
409 listincgst => $bookseller->{listincgst},
410 basketgroups => $basketgroups,
411 basketgroup => $basketgroup,
412 grouped => $basket->{basketgroupid},
413 # The double negatives and booleans here mean:
414 # "A basket cannot be closed if there are no orders in it or it's a standing order basket."
416 # (The template has another implicit restriction that the order cannot be closed if there
417 # are any orders with uncertain prices.)
418 unclosable => @orders ? $basket->{is_standing} : 1,
419 has_budgets => $has_budgets,
420 duplinbatch => $duplinbatch,
424 $template->param( messages => \@messages );
425 output_html_with_http_headers $query, $cookie, $template->output;
427 sub get_order_infos {
428 my $order = shift;
429 my $bookseller = shift;
430 my $qty = $order->{'quantity'} || 0;
431 if ( !defined $order->{quantityreceived} ) {
432 $order->{quantityreceived} = 0;
434 my $budget = GetBudget($order->{budget_id});
435 my $basket = GetBasket($order->{basketno});
437 my %line = %{ $order };
438 # Don't show unreceived standing orders as received
439 $line{order_received} = ( $qty == $order->{'quantityreceived'} && ( $basket->{is_standing} ? $qty : 1 ) );
440 $line{basketno} = $basketno;
441 $line{budget_name} = $budget->{budget_name};
443 $line{total_tax_included} = $line{ecost_tax_included} * $line{quantity};
444 $line{total_tax_excluded} = $line{ecost_tax_excluded} * $line{quantity};
445 $line{tax_value} = $line{tax_value_on_ordering};
446 $line{tax_rate} = $line{tax_rate_on_ordering};
448 if ( $line{uncertainprice} ) {
449 $line{rrp_tax_excluded} .= ' (Uncertain)';
451 if ( $line{'title'} ) {
452 my $volume = $order->{'volume'};
453 my $seriestitle = $order->{'seriestitle'};
454 $line{'title'} .= " / $seriestitle" if $seriestitle;
455 $line{'title'} .= " / $volume" if $volume;
458 my $biblionumber = $order->{'biblionumber'};
459 my $countbiblio = CountBiblioInOrders($biblionumber);
460 my $ordernumber = $order->{'ordernumber'};
461 my @subscriptions = GetSubscriptionsId ($biblionumber);
462 my $itemcount = GetItemsCount($biblionumber);
463 my $holds = GetHolds ($biblionumber);
464 my @items = GetItemnumbersFromOrder( $ordernumber );
465 my $itemholds;
466 foreach my $item (@items){
467 my $nb = GetItemHolds($biblionumber, $item);
468 if ($nb){
469 $itemholds += $nb;
472 # 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
473 $line{can_del_bib} = 1 if $countbiblio <= 1 && $itemcount == scalar @items && !(@subscriptions) && !($holds);
474 $line{items} = ($itemcount) - (scalar @items);
475 $line{left_item} = 1 if $line{items} >= 1;
476 $line{left_biblio} = 1 if $countbiblio > 1;
477 $line{biblios} = $countbiblio - 1;
478 $line{left_subscription} = 1 if scalar @subscriptions >= 1;
479 $line{subscriptions} = scalar @subscriptions;
480 ($holds >= 1) ? $line{left_holds} = 1 : $line{left_holds} = 0;
481 $line{left_holds_on_order} = 1 if $line{left_holds}==1 && ($line{items} == 0 || $itemholds );
482 $line{holds} = $holds;
483 $line{holds_on_order} = $itemholds?$itemholds:$holds if $line{left_holds_on_order};
486 my $suggestion = GetSuggestionInfoFromBiblionumber($line{biblionumber});
487 $line{suggestionid} = $$suggestion{suggestionid};
488 $line{surnamesuggestedby} = $$suggestion{surnamesuggestedby};
489 $line{firstnamesuggestedby} = $$suggestion{firstnamesuggestedby};
491 foreach my $key (qw(transferred_from transferred_to)) {
492 if ($line{$key}) {
493 my $order = GetOrder($line{$key});
494 my $bookseller = Koha::Acquisition::Bookseller->fetch({ id => $basket->{booksellerid} });
495 $line{$key} = {
496 order => $order,
497 basket => $basket,
498 bookseller => $bookseller,
499 timestamp => $line{$key . '_timestamp'},
504 return \%line;
507 sub edi_close_and_order {
508 my $confirm = $query->param('confirm') || $confirm_pref eq '2';
509 if ($confirm) {
510 my $edi_params = {
511 basketno => $basketno,
512 ean => $ean,
514 if ( $basket->{branch} ) {
515 $edi_params->{branchcode} = $basket->{branch};
517 if ( create_edi_order($edi_params) ) {
518 #$template->param( edifile => 1 );
520 CloseBasket($basketno);
522 # if requested, create basket group, close it and attach the basket
523 if ( $query->param('createbasketgroup') ) {
524 my $branchcode;
525 if ( C4::Context->userenv
526 and C4::Context->userenv->{'branch'}
527 and C4::Context->userenv->{'branch'} ne "NO_LIBRARY_SET" )
529 $branchcode = C4::Context->userenv->{'branch'};
531 my $basketgroupid = NewBasketgroup(
533 name => $basket->{basketname},
534 booksellerid => $booksellerid,
535 deliveryplace => $branchcode,
536 billingplace => $branchcode,
537 closed => 1,
540 ModBasket(
542 basketno => $basketno,
543 basketgroupid => $basketgroupid
546 print $query->redirect(
547 "/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=$booksellerid&closed=1"
550 else {
551 print $query->redirect(
552 "/cgi-bin/koha/acqui/booksellers.pl?booksellerid=$booksellerid"
555 exit;
557 else {
558 $template->param(
559 edi_confirm => 1,
560 booksellerid => $booksellerid,
561 basketno => $basket->{basketno},
562 basketname => $basket->{basketname},
563 basketgroupname => $basket->{basketname},
565 if ($ean) {
566 $template->param( ean => $ean );
570 return;