Bug 9302: Use patron-title.inc
[koha.git] / acqui / basket.pl
blob92fae60a0ad151fa7dd4654f5ecefbbbbc3ef895
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::Items;
34 use C4::Suggestions;
35 use Koha::Biblios;
36 use Koha::Acquisition::Booksellers;
37 use Koha::Libraries;
38 use C4::Letters qw/SendAlerts/;
39 use Date::Calc qw/Add_Delta_Days/;
40 use Koha::Database;
41 use Koha::EDI qw( create_edi_order get_edifact_ean );
42 use Koha::CsvProfiles;
43 use Koha::Patrons;
45 =head1 NAME
47 basket.pl
49 =head1 DESCRIPTION
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.
55 =head1 CGI PARAMETERS
57 =over 4
59 =item $basketno
61 The basket number.
63 =item booksellerid
65 the supplier this script have to display the basket.
67 =item order
69 =back
71 =cut
73 our $query = new CGI;
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",
82 query => $query,
83 type => "intranet",
84 authnotrequired => 0,
85 flagsrequired => { acquisition => 'order_manage' },
86 debug => 1,
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)) {
99 $template->param(
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;
107 exit;
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';
119 my @messages;
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;
139 my $error;
140 if ($countbiblio == 0 && $itemcount == 0 && not $cnt_subscriptions ) {
141 $error = DelBiblio($myorder->{biblionumber}) }
142 else {
143 push @cannotdelbiblios, {biblionumber=> ($myorder->{biblionumber}),
144 title=> $myorder->{'title'},
145 author=> $myorder->{'author'},
146 countbiblio=> $countbiblio,
147 itemcount=>$itemcount,
148 subscriptions => $cnt_subscriptions};
150 if ($error) {
151 push @cannotdelbiblios, {biblionumber=> ($myorder->{biblionumber}),
152 title=> $myorder->{'title'},
153 author=> $myorder->{'author'},
154 othererror=> $error};
157 $template->param( cannotdelbiblios => \@cannotdelbiblios );
159 # delete the basket
160 DelBasket($basketno,);
161 $template->param(
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(
170 -type => 'text/csv',
171 -attachment => 'basket' . $basket->{'basketno'} . '.csv',
173 my $csv_profile_id = $query->param('csv_profile');
174 print GetBasketAsCSV( scalar $query->param('basketno'), $query, $csv_profile_id ); # if no csv_profile_id passed, using default rows
175 exit;
176 } elsif ($op eq 'email') {
177 my $err = eval {
178 SendAlerts( 'orderacquisition', $query->param('basketno'), 'ACQORDER' );
180 if ( $@ ) {
181 push @messages, { type => 'error', code => $@ };
182 } elsif ( ref $err and exists $err->{error} ) {
183 push @messages, { type => 'error', code => $err->{error} };
184 } else {
185 push @messages, { type => 'message', code => 'email_sent' };
188 $op = 'list';
189 } elsif ($op eq 'close') {
190 my $confirm = $query->param('confirm') || $confirm_pref eq '2';
191 if ($confirm) {
192 my $basketno = $query->param('basketno');
193 my $booksellerid = $query->param('booksellerid');
194 $basketno =~ /^\d+$/ and CloseBasket($basketno);
195 # if requested, create basket group, close it and attach the basket
196 if ($query->param('createbasketgroup')) {
197 my $branchcode;
198 if(C4::Context->userenv and C4::Context->userenv->{'branch'}
199 and C4::Context->userenv->{'branch'} ne "NO_LIBRARY_SET") {
200 $branchcode = C4::Context->userenv->{'branch'};
202 my $basketgroupid = NewBasketgroup( { name => $basket->{basketname},
203 booksellerid => $booksellerid,
204 deliveryplace => $branchcode,
205 billingplace => $branchcode,
206 closed => 1,
208 ModBasket( { basketno => $basketno,
209 basketgroupid => $basketgroupid } );
210 print $query->redirect('/cgi-bin/koha/acqui/basketgroup.pl?booksellerid='.$booksellerid.'&closed=1');
211 } else {
212 print $query->redirect('/cgi-bin/koha/acqui/booksellers.pl?booksellerid=' . $booksellerid);
214 exit;
215 } else {
216 $template->param(
217 confirm_close => "1",
218 booksellerid => $booksellerid,
219 booksellername => $bookseller->name,
220 basketno => $basket->{'basketno'},
221 basketname => $basket->{'basketname'},
222 basketgroupname => $basket->{'basketname'},
225 } elsif ($op eq 'reopen') {
226 ReopenBasket(scalar $query->param('basketno'));
227 print $query->redirect('/cgi-bin/koha/acqui/basket.pl?basketno='.$basket->{'basketno'})
229 elsif ( $op eq 'ediorder' ) {
230 edi_close_and_order()
231 } elsif ( $op eq 'mod_users' ) {
232 my $basketusers_ids = $query->param('users_ids');
233 my @basketusers = split( /:/, $basketusers_ids );
234 ModBasketUsers($basketno, @basketusers);
235 print $query->redirect("/cgi-bin/koha/acqui/basket.pl?basketno=$basketno");
236 exit;
237 } elsif ( $op eq 'mod_branch' ) {
238 my $branch = $query->param('branch');
239 $branch = undef if(defined $branch and $branch eq '');
240 ModBasket({
241 basketno => $basket->{basketno},
242 branch => $branch
244 print $query->redirect("/cgi-bin/koha/acqui/basket.pl?basketno=$basketno");
245 exit;
248 if ( $op eq 'list' ) {
249 my @branches_loop;
250 # get librarian branch...
251 if ( C4::Context->preference("IndependentBranches") ) {
252 my $userenv = C4::Context->userenv;
253 unless ( C4::Context->IsSuperLibrarian() ) {
254 my $validtest = ( $basket->{creationdate} eq '' )
255 || ( $userenv->{branch} eq $basket->{branch} )
256 || ( $userenv->{branch} eq '' )
257 || ( $basket->{branch} eq '' );
258 unless ($validtest) {
259 print $query->redirect("../mainpage.pl");
260 exit 0;
264 if (!defined $basket->{branch} or $basket->{branch} eq $userenv->{branch}) {
265 push @branches_loop, {
266 branchcode => $userenv->{branch},
267 branchname => $userenv->{branchname},
268 selected => 1,
271 } else {
272 # get branches
273 my $branches = Koha::Libraries->search( {}, { order_by => ['branchname'] } )->unblessed;
274 foreach my $branch (@$branches) {
275 my $selected = 0;
276 if (defined $basket->{branch}) {
277 $selected = 1 if $branch->{branchcode} eq $basket->{branch};
278 } else {
279 $selected = 1 if $branch->{branchcode} eq C4::Context->userenv->{branch};
281 push @branches_loop, {
282 branchcode => $branch->{branchcode},
283 branchname => $branch->{branchname},
284 selected => $selected
289 #if the basket is closed,and the user has the permission to edit basketgroups, display a list of basketgroups
290 my ($basketgroup, $basketgroups);
291 my $patron = Koha::Patrons->find($loggedinuser);
292 if ($basket->{closedate} && haspermission($patron->userid, { acquisition => 'group_manage'} )) {
293 $basketgroups = GetBasketgroups($basket->{booksellerid});
294 for my $bg ( @{$basketgroups} ) {
295 if ($basket->{basketgroupid} && $basket->{basketgroupid} == $bg->{id}){
296 $bg->{default} = 1;
297 $basketgroup = $bg;
302 # if the basket is closed, calculate estimated delivery date
303 my $estimateddeliverydate;
304 if( $basket->{closedate} ) {
305 my ($year, $month, $day) = ($basket->{closedate} =~ /(\d+)-(\d+)-(\d+)/);
306 ($year, $month, $day) = Add_Delta_Days($year, $month, $day, $bookseller->deliverytime);
307 $estimateddeliverydate = sprintf( "%04d-%02d-%02d", $year, $month, $day );
310 # if new basket, pre-fill infos
311 $basket->{creationdate} = "" unless ( $basket->{creationdate} );
312 $basket->{authorisedby} = $loggedinuser unless ( $basket->{authorisedby} );
313 $debug
314 and warn sprintf
315 "loggedinuser: $loggedinuser; creationdate: %s; authorisedby: %s",
316 $basket->{creationdate}, $basket->{authorisedby};
318 my @basketusers_ids = GetBasketUsers($basketno);
319 my @basketusers;
320 foreach my $basketuser_id (@basketusers_ids) {
321 # FIXME Could be improved with a search -in
322 my $basket_patron = Koha::Patrons->find( $basketuser_id );
323 push @basketusers, $basket_patron if $basket_patron;
326 my $active_currency = Koha::Acquisition::Currencies->get_active;
328 my @orders = GetOrders( $basketno );
329 my @books_loop;
331 my @book_foot_loop;
332 my %foot;
333 my $total_quantity = 0;
334 my $total_tax_excluded = 0;
335 my $total_tax_included = 0;
336 my $total_tax_value = 0;
337 for my $order (@orders) {
338 my $line = get_order_infos( $order, $bookseller);
339 if ( $line->{uncertainprice} ) {
340 $template->param( uncertainprices => 1 );
343 $line->{tax_rate} = $line->{tax_rate_on_ordering};
344 $line->{tax_value} = $line->{tax_value_on_ordering};
346 push @books_loop, $line;
348 $foot{$$line{tax_rate}}{tax_rate} = $$line{tax_rate};
349 $foot{$$line{tax_rate}}{tax_value} += $$line{tax_value};
350 $total_tax_value += $$line{tax_value};
351 $foot{$$line{tax_rate}}{quantity} += $$line{quantity};
352 $total_quantity += $$line{quantity};
353 $foot{$$line{tax_rate}}{total_tax_excluded} += $$line{total_tax_excluded};
354 $total_tax_excluded += $$line{total_tax_excluded};
355 $foot{$$line{tax_rate}}{total_tax_included} += $$line{total_tax_included};
356 $total_tax_included += $$line{total_tax_included};
359 push @book_foot_loop, map {$_} values %foot;
361 # Get cancelled orders
362 my @cancelledorders = GetOrders($basketno, { cancelled => 1 });
363 my @cancelledorders_loop;
364 for my $order (@cancelledorders) {
365 my $line = get_order_infos( $order, $bookseller);
366 push @cancelledorders_loop, $line;
369 my $contract = GetContract({
370 contractnumber => $basket->{contractnumber}
373 if ($basket->{basketgroupid}){
374 $basketgroup = GetBasketgroup($basket->{basketgroupid});
376 my $budgets = GetBudgetHierarchy;
377 my $has_budgets = 0;
378 foreach my $r (@{$budgets}) {
379 if (!defined $r->{budget_amount} || $r->{budget_amount} == 0) {
380 next;
382 next unless (CanUserUseBudget($loggedinuser, $r, $userflags));
384 $has_budgets = 1;
385 last;
388 $template->param(
389 basketno => $basketno,
390 basket => $basket,
391 basketname => $basket->{'basketname'},
392 basketbranchcode => $basket->{branch},
393 basketnote => $basket->{note},
394 basketbooksellernote => $basket->{booksellernote},
395 basketcontractno => $basket->{contractnumber},
396 basketcontractname => $contract->{contractname},
397 branches_loop => \@branches_loop,
398 creationdate => $basket->{creationdate},
399 authorisedby => $basket->{authorisedby},
400 authorisedbyname => $basket->{authorisedbyname},
401 users_ids => join(':', @basketusers_ids),
402 users => \@basketusers,
403 closedate => $basket->{closedate},
404 estimateddeliverydate=> $estimateddeliverydate,
405 is_standing => $basket->{is_standing},
406 deliveryplace => $basket->{deliveryplace},
407 billingplace => $basket->{billingplace},
408 active => $bookseller->active,
409 booksellerid => $bookseller->id,
410 booksellername => $bookseller->name,
411 books_loop => \@books_loop,
412 book_foot_loop => \@book_foot_loop,
413 cancelledorders_loop => \@cancelledorders_loop,
414 total_quantity => $total_quantity,
415 total_tax_excluded => $total_tax_excluded,
416 total_tax_included => $total_tax_included,
417 total_tax_value => $total_tax_value,
418 currency => $active_currency->currency,
419 listincgst => $bookseller->listincgst,
420 basketgroups => $basketgroups,
421 basketgroup => $basketgroup,
422 grouped => $basket->{basketgroupid},
423 # The double negatives and booleans here mean:
424 # "A basket cannot be closed if there are no orders in it or it's a standing order basket."
426 # (The template has another implicit restriction that the order cannot be closed if there
427 # are any orders with uncertain prices.)
428 unclosable => @orders ? $basket->{is_standing} : 1,
429 has_budgets => $has_budgets,
430 duplinbatch => $duplinbatch,
431 csv_profiles => [ Koha::CsvProfiles->search({ type => 'sql', used_for => 'export_basket' }) ],
435 $template->param( messages => \@messages );
436 output_html_with_http_headers $query, $cookie, $template->output;
438 sub get_order_infos {
439 my $order = shift;
440 my $bookseller = shift;
441 my $qty = $order->{'quantity'} || 0;
442 if ( !defined $order->{quantityreceived} ) {
443 $order->{quantityreceived} = 0;
445 my $budget = GetBudget($order->{budget_id});
446 my $basket = GetBasket($order->{basketno});
448 my %line = %{ $order };
449 # Don't show unreceived standing orders as received
450 $line{order_received} = ( $qty == $order->{'quantityreceived'} && ( $basket->{is_standing} ? $qty : 1 ) );
451 $line{basketno} = $basketno;
452 $line{budget_name} = $budget->{budget_name};
454 $line{total_tax_included} = $line{ecost_tax_included} * $line{quantity};
455 $line{total_tax_excluded} = $line{ecost_tax_excluded} * $line{quantity};
456 $line{tax_value} = $line{tax_value_on_ordering};
457 $line{tax_rate} = $line{tax_rate_on_ordering};
459 if ( $line{uncertainprice} ) {
460 $line{rrp_tax_excluded} .= ' (Uncertain)';
462 if ( $line{'title'} ) {
463 my $volume = $order->{'volume'};
464 my $seriestitle = $order->{'seriestitle'};
465 $line{'title'} .= " / $seriestitle" if $seriestitle;
466 $line{'title'} .= " / $volume" if $volume;
469 my $biblionumber = $order->{'biblionumber'};
470 if ( $biblionumber ) { # The biblio still exists
471 my $biblio = Koha::Biblios->find( $biblionumber );
472 my $countbiblio = CountBiblioInOrders($biblionumber);
473 my $ordernumber = $order->{'ordernumber'};
474 my $cnt_subscriptions = $biblio->subscriptions->count;
475 my $itemcount = $biblio->items->count;
476 my $holds_count = $biblio->holds->count;
477 my @items = GetItemnumbersFromOrder( $ordernumber );
478 my $itemholds = $biblio->holds->search({ itemnumber => { -in => \@items } })->count;
480 # 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
481 $line{can_del_bib} = 1 if $countbiblio <= 1 && $itemcount == scalar @items && !($cnt_subscriptions) && !($holds_count);
482 $line{items} = ($itemcount) - (scalar @items);
483 $line{left_item} = 1 if $line{items} >= 1;
484 $line{left_biblio} = 1 if $countbiblio > 1;
485 $line{biblios} = $countbiblio - 1;
486 $line{left_subscription} = 1 if $cnt_subscriptions;
487 $line{subscriptions} = $cnt_subscriptions;
488 ($holds_count >= 1) ? $line{left_holds} = 1 : $line{left_holds} = 0;
489 $line{left_holds_on_order} = 1 if $line{left_holds}==1 && ($line{items} == 0 || $itemholds );
490 $line{holds} = $holds_count;
491 $line{holds_on_order} = $itemholds?$itemholds:$holds_count if $line{left_holds_on_order};
495 my $suggestion = GetSuggestionInfoFromBiblionumber($line{biblionumber});
496 $line{suggestionid} = $$suggestion{suggestionid};
497 $line{surnamesuggestedby} = $$suggestion{surnamesuggestedby};
498 $line{firstnamesuggestedby} = $$suggestion{firstnamesuggestedby};
500 foreach my $key (qw(transferred_from transferred_to)) {
501 if ($line{$key}) {
502 my $order = GetOrder($line{$key});
503 my $basket = GetBasket($order->{basketno});
504 my $bookseller = Koha::Acquisition::Booksellers->find( $basket->{booksellerid} );
505 $line{$key} = {
506 order => $order,
507 basket => $basket,
508 bookseller => $bookseller,
509 timestamp => $line{$key . '_timestamp'},
514 return \%line;
517 sub edi_close_and_order {
518 my $confirm = $query->param('confirm') || $confirm_pref eq '2';
519 if ($confirm) {
520 my $edi_params = {
521 basketno => $basketno,
522 ean => $ean,
524 if ( $basket->{branch} ) {
525 $edi_params->{branchcode} = $basket->{branch};
527 if ( create_edi_order($edi_params) ) {
528 #$template->param( edifile => 1 );
530 CloseBasket($basketno);
532 # if requested, create basket group, close it and attach the basket
533 if ( $query->param('createbasketgroup') ) {
534 my $branchcode;
535 if ( C4::Context->userenv
536 and C4::Context->userenv->{'branch'}
537 and C4::Context->userenv->{'branch'} ne "NO_LIBRARY_SET" )
539 $branchcode = C4::Context->userenv->{'branch'};
541 my $basketgroupid = NewBasketgroup(
543 name => $basket->{basketname},
544 booksellerid => $booksellerid,
545 deliveryplace => $branchcode,
546 billingplace => $branchcode,
547 closed => 1,
550 ModBasket(
552 basketno => $basketno,
553 basketgroupid => $basketgroupid
556 print $query->redirect(
557 "/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=$booksellerid&closed=1"
560 else {
561 print $query->redirect(
562 "/cgi-bin/koha/acqui/booksellers.pl?booksellerid=$booksellerid"
565 exit;
567 else {
568 $template->param(
569 edi_confirm => 1,
570 booksellerid => $booksellerid,
571 basketno => $basket->{basketno},
572 basketname => $basket->{basketname},
573 basketgroupname => $basket->{basketname},
575 if ($ean) {
576 $template->param( ean => $ean );
580 return;