]> git.koha-community.org Git - koha.git/blob - acqui/basket.pl
Bug 24663: Remove authnotrequired if set to 0
[koha.git] / acqui / basket.pl
1 #!/usr/bin/perl
2
3 #script to show display basket of orders
4
5 # Copyright 2000 - 2004 Katipo
6 # Copyright 2008 - 2009 BibLibre SARL
7 #
8 # This file is part of Koha.
9 #
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.
14 #
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.
19 #
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>.
22
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::Baskets;
37 use Koha::Acquisition::Booksellers;
38 use Koha::Acquisition::Orders;
39 use Koha::Libraries;
40 use C4::Letters qw/SendAlerts/;
41 use Date::Calc qw/Add_Delta_Days/;
42 use Koha::Database;
43 use Koha::EDI qw( create_edi_order get_edifact_ean );
44 use Koha::CsvProfiles;
45 use Koha::Patrons;
46
47 use Koha::AdditionalFields;
48
49 =head1 NAME
50
51 basket.pl
52
53 =head1 DESCRIPTION
54
55  This script display all informations about basket for the supplier given
56  on input arg.  Moreover, it allows us to add a new order for this supplier from
57  an existing record, a suggestion or a new record.
58
59 =head1 CGI PARAMETERS
60
61 =over 4
62
63 =item $basketno
64
65 The basket number.
66
67 =item booksellerid
68
69 the supplier this script have to display the basket.
70
71 =item order
72
73 =back
74
75 =cut
76
77 our $query        = new CGI;
78 our $basketno     = $query->param('basketno');
79 our $ean          = $query->param('ean');
80 our $booksellerid = $query->param('booksellerid');
81 my $duplinbatch =  $query->param('duplinbatch');
82
83 our ( $template, $loggedinuser, $cookie, $userflags ) = get_template_and_user(
84     {
85         template_name   => "acqui/basket.tt",
86         query           => $query,
87         type            => "intranet",
88         flagsrequired   => { acquisition => 'order_manage' },
89         debug           => 1,
90     }
91 );
92
93 our $basket = GetBasket($basketno);
94 $booksellerid = $basket->{booksellerid} unless $booksellerid;
95 my $bookseller = Koha::Acquisition::Booksellers->find( $booksellerid );
96 my $schema = Koha::Database->new()->schema();
97 my $rs = $schema->resultset('VendorEdiAccount')->search(
98     { vendor_id => $booksellerid, } );
99 $template->param( ediaccount => ($rs->count > 0));
100
101 unless (CanUserManageBasket($loggedinuser, $basket, $userflags)) {
102     $template->param(
103         cannot_manage_basket => 1,
104         basketno => $basketno,
105         basketname => $basket->{basketname},
106         booksellerid => $booksellerid,
107         booksellername => $bookseller->name,
108     );
109     output_html_with_http_headers $query, $cookie, $template->output;
110     exit;
111 }
112
113 # FIXME : what about the "discount" percentage?
114 # FIXME : the query->param('booksellerid') below is probably useless. The bookseller is always known from the basket
115 # if no booksellerid in parameter, get it from basket
116 # warn "=>".$basket->{booksellerid};
117 my $op = $query->param('op') // 'list';
118
119 our $confirm_pref= C4::Context->preference("BasketConfirmations") || '1';
120 $template->param( skip_confirm_reopen => 1) if $confirm_pref eq '2';
121
122 my @messages;
123
124 if ( $op eq 'delete_confirm' ) {
125     my $basketno = $query->param('basketno');
126     my $delbiblio = $query->param('delbiblio');
127     my @orders = GetOrders($basketno);
128 #Delete all orders included in that basket, and all items received.
129     foreach my $myorder (@orders){
130         DelOrder($myorder->{biblionumber},$myorder->{ordernumber});
131     }
132 # if $delbiblio = 1, delete the records if possible
133     if ((defined $delbiblio)and ($delbiblio ==1)){
134         my @cannotdelbiblios ;
135         foreach my $myorder (@orders){
136             my $biblionumber = $myorder->{'biblionumber'};
137             my $biblio = Koha::Biblios->find( $biblionumber );
138             my $countbiblio = $biblio->active_orders->count;
139             my $ordernumber = $myorder->{'ordernumber'};
140             my $cnt_subscriptions = $biblio->subscriptions->count;
141             my $itemcount = $biblio->items->count;
142             my $error;
143             if ($countbiblio == 0 && $itemcount == 0 && not $cnt_subscriptions ) {
144                 $error = DelBiblio($myorder->{biblionumber}) }
145             else {
146                 push @cannotdelbiblios, {biblionumber=> ($myorder->{biblionumber}),
147                                          title=> $myorder->{'title'},
148                                          author=> $myorder->{'author'},
149                                          countbiblio=> $countbiblio,
150                                          itemcount=>$itemcount,
151                                          subscriptions => $cnt_subscriptions};
152             }
153             if ($error) {
154                 push @cannotdelbiblios, {biblionumber=> ($myorder->{biblionumber}),
155                                          title=> $myorder->{'title'},
156                                          author=> $myorder->{'author'},
157                                          othererror=> $error};
158             }
159         }
160         $template->param( cannotdelbiblios => \@cannotdelbiblios );
161     }
162  # delete the basket
163     DelBasket($basketno,);
164     $template->param(
165         delete_confirmed => 1,
166         booksellername => $bookseller->name,
167         booksellerid => $booksellerid,
168     );
169 } elsif ( !$bookseller ) {
170     $template->param( NO_BOOKSELLER => 1 );
171 } elsif ($op eq 'export') {
172     print $query->header(
173         -type       => 'text/csv',
174         -attachment => 'basket' . $basket->{'basketno'} . '.csv',
175     );
176     my $csv_profile_id = $query->param('csv_profile');
177     print GetBasketAsCSV( scalar $query->param('basketno'), $query, $csv_profile_id ); # if no csv_profile_id passed, using default rows
178     exit;
179 } elsif ($op eq 'email') {
180     my $err = eval {
181         SendAlerts( 'orderacquisition', $query->param('basketno'), 'ACQORDER' );
182     };
183     if ( $@ ) {
184         push @messages, { type => 'error', code => $@ };
185     } elsif ( ref $err and exists $err->{error} ) {
186         push @messages, { type => 'error', code => $err->{error} };
187     } else {
188         push @messages, { type => 'message', code => 'email_sent' };
189     }
190
191     $op = 'list';
192 } elsif ($op eq 'close') {
193     my $confirm = $query->param('confirm') || $confirm_pref eq '2';
194     if ($confirm) {
195         my $basketno = $query->param('basketno');
196         my $booksellerid = $query->param('booksellerid');
197         $basketno =~ /^\d+$/ and CloseBasket($basketno);
198         # if requested, create basket group, close it and attach the basket
199         if ($query->param('createbasketgroup')) {
200             my $branchcode;
201             if(C4::Context->userenv and C4::Context->userenv->{'branch'}) {
202                 $branchcode = C4::Context->userenv->{'branch'};
203             }
204             my $basketgroupid = NewBasketgroup( { name => $basket->{basketname},
205                             booksellerid => $booksellerid,
206                             deliveryplace => $branchcode,
207                             billingplace => $branchcode,
208                             closed => 1,
209                             });
210             ModBasket( { basketno => $basketno,
211                          basketgroupid => $basketgroupid } );
212             print $query->redirect('/cgi-bin/koha/acqui/basketgroup.pl?booksellerid='.$booksellerid.'&closed=1');
213         } else {
214             print $query->redirect('/cgi-bin/koha/acqui/booksellers.pl?booksellerid=' . $booksellerid);
215         }
216         exit;
217     } else {
218     $template->param(
219         confirm_close   => "1",
220         booksellerid    => $booksellerid,
221         booksellername  => $bookseller->name,
222         basketno        => $basket->{'basketno'},
223         basketname      => $basket->{'basketname'},
224         basketgroupname => $basket->{'basketname'},
225     );
226     }
227 } elsif ($op eq 'reopen') {
228     ReopenBasket(scalar $query->param('basketno'));
229     print $query->redirect('/cgi-bin/koha/acqui/basket.pl?basketno='.$basket->{'basketno'})
230 }
231 elsif ( $op eq 'ediorder' ) {
232     edi_close_and_order()
233 } elsif ( $op eq 'mod_users' ) {
234     my $basketusers_ids = $query->param('users_ids');
235     my @basketusers = split( /:/, $basketusers_ids );
236     ModBasketUsers($basketno, @basketusers);
237     print $query->redirect("/cgi-bin/koha/acqui/basket.pl?basketno=$basketno");
238     exit;
239 } elsif ( $op eq 'mod_branch' ) {
240     my $branch = $query->param('branch');
241     $branch = undef if(defined $branch and $branch eq '');
242     ModBasket({
243         basketno => $basket->{basketno},
244         branch   => $branch
245     });
246     print $query->redirect("/cgi-bin/koha/acqui/basket.pl?basketno=$basketno");
247     exit;
248 }
249
250 if ( $op eq 'list' ) {
251     my @branches_loop;
252     # get librarian branch...
253     if ( C4::Context->preference("IndependentBranches") ) {
254         my $userenv = C4::Context->userenv;
255         unless ( C4::Context->IsSuperLibrarian() ) {
256             my $validtest = ( $basket->{creationdate} eq '' )
257               || ( $userenv->{branch} eq $basket->{branch} )
258               || ( $userenv->{branch} eq '' )
259               || ( $basket->{branch}  eq '' );
260             unless ($validtest) {
261                 print $query->redirect("../mainpage.pl");
262                 exit 0;
263             }
264         }
265
266         if (!defined $basket->{branch} or $basket->{branch} eq $userenv->{branch}) {
267             push @branches_loop, {
268                 branchcode => $userenv->{branch},
269                 branchname => $userenv->{branchname},
270                 selected => 1,
271             };
272         }
273     } else {
274         # get branches
275         my $branches = Koha::Libraries->search( {}, { order_by => ['branchname'] } )->unblessed;
276         foreach my $branch (@$branches) {
277             my $selected = 0;
278             if (defined $basket->{branch}) {
279                 $selected = 1 if $branch->{branchcode} eq $basket->{branch};
280             } else {
281                 $selected = 1 if $branch->{branchcode} eq C4::Context->userenv->{branch};
282             }
283             push @branches_loop, {
284                 branchcode => $branch->{branchcode},
285                 branchname => $branch->{branchname},
286                 selected => $selected
287             };
288         }
289     }
290
291 #if the basket is closed,and the user has the permission to edit basketgroups, display a list of basketgroups
292     my ($basketgroup, $basketgroups);
293     my $patron = Koha::Patrons->find($loggedinuser);
294     if ($basket->{closedate} && haspermission($patron->userid, { acquisition => 'group_manage'} )) {
295         $basketgroups = GetBasketgroups($basket->{booksellerid});
296         for my $bg ( @{$basketgroups} ) {
297             if ($basket->{basketgroupid} && $basket->{basketgroupid} == $bg->{id}){
298                 $bg->{default} = 1;
299                 $basketgroup = $bg;
300             }
301         }
302     }
303
304     # if the basket is closed, calculate estimated delivery date
305     my $estimateddeliverydate;
306     if( $basket->{closedate} ) {
307         my ($year, $month, $day) = ($basket->{closedate} =~ /(\d+)-(\d+)-(\d+)/);
308         ($year, $month, $day) = Add_Delta_Days($year, $month, $day, $bookseller->deliverytime);
309         $estimateddeliverydate = sprintf( "%04d-%02d-%02d", $year, $month, $day );
310     }
311
312     # if new basket, pre-fill infos
313     $basket->{creationdate} = ""            unless ( $basket->{creationdate} );
314     $basket->{authorisedby} = $loggedinuser unless ( $basket->{authorisedby} );
315     $debug
316       and warn sprintf
317       "loggedinuser: $loggedinuser; creationdate: %s; authorisedby: %s",
318       $basket->{creationdate}, $basket->{authorisedby};
319
320     my @basketusers_ids = GetBasketUsers($basketno);
321     my @basketusers;
322     foreach my $basketuser_id (@basketusers_ids) {
323         # FIXME Could be improved with a search -in
324         my $basket_patron = Koha::Patrons->find( $basketuser_id );
325         push @basketusers, $basket_patron if $basket_patron;
326     }
327
328     my $active_currency = Koha::Acquisition::Currencies->get_active;
329
330     my @orders = GetOrders( $basketno );
331     my @books_loop;
332
333     my @book_foot_loop;
334     my %foot;
335     my $total_quantity = 0;
336     my $total_tax_excluded = 0;
337     my $total_tax_included = 0;
338     my $total_tax_value = 0;
339     for my $order (@orders) {
340         my $line = get_order_infos( $order, $bookseller);
341         if ( $line->{uncertainprice} ) {
342             $template->param( uncertainprices => 1 );
343         }
344
345         $line->{tax_rate} = $line->{tax_rate_on_ordering} // 0;
346         $line->{tax_value} = $line->{tax_value_on_ordering} // 0;
347
348         push @books_loop, $line;
349
350         $foot{$$line{tax_rate}}{tax_rate} = $$line{tax_rate};
351         $foot{$$line{tax_rate}}{tax_value} += get_rounded_price($$line{tax_value});
352         $total_tax_value += $$line{tax_value};
353         $foot{$$line{tax_rate}}{quantity}  += get_rounded_price($$line{quantity});
354         $total_quantity += $$line{quantity};
355         $foot{$$line{tax_rate}}{total_tax_excluded} += $$line{total_tax_excluded};
356         $total_tax_excluded += $$line{total_tax_excluded};
357         $foot{$$line{tax_rate}}{total_tax_included} += $$line{total_tax_included};
358         $total_tax_included += $$line{total_tax_included};
359     }
360
361     push @book_foot_loop, map {$_} values %foot;
362
363     # Get cancelled orders
364     my @cancelledorders = GetOrders($basketno, { cancelled => 1 });
365     my @cancelledorders_loop;
366     for my $order (@cancelledorders) {
367         my $line = get_order_infos( $order, $bookseller);
368         push @cancelledorders_loop, $line;
369     }
370
371     my $contract = GetContract({
372         contractnumber => $basket->{contractnumber}
373     });
374
375     if ($basket->{basketgroupid}){
376         $basketgroup = GetBasketgroup($basket->{basketgroupid});
377     }
378     my $budgets = GetBudgetHierarchy;
379     my $has_budgets = 0;
380     foreach my $r (@{$budgets}) {
381         next unless (CanUserUseBudget($loggedinuser, $r, $userflags));
382
383         $has_budgets = 1;
384         last;
385     }
386
387     $template->param(
388         basketno             => $basketno,
389         basket               => $basket,
390         basketname           => $basket->{'basketname'},
391         basketbranchcode     => $basket->{branch},
392         basketnote           => $basket->{note},
393         basketbooksellernote => $basket->{booksellernote},
394         basketcontractno     => $basket->{contractnumber},
395         basketcontractname   => $contract->{contractname},
396         branches_loop        => \@branches_loop,
397         creationdate         => $basket->{creationdate},
398         authorisedby         => $basket->{authorisedby},
399         authorisedbyname     => $basket->{authorisedbyname},
400         users_ids            => join(':', @basketusers_ids),
401         users                => \@basketusers,
402         closedate            => $basket->{closedate},
403         estimateddeliverydate=> $estimateddeliverydate,
404         is_standing          => $basket->{is_standing},
405         deliveryplace        => $basket->{deliveryplace},
406         billingplace         => $basket->{billingplace},
407         active               => $bookseller->active,
408         booksellerid         => $bookseller->id,
409         booksellername       => $bookseller->name,
410         books_loop           => \@books_loop,
411         book_foot_loop       => \@book_foot_loop,
412         cancelledorders_loop => \@cancelledorders_loop,
413         total_quantity       => $total_quantity,
414         total_tax_excluded   => $total_tax_excluded,
415         total_tax_included   => $total_tax_included,
416         total_tax_value      => $total_tax_value,
417         currency             => $active_currency->currency,
418         listincgst           => $bookseller->listincgst,
419         basketgroups         => $basketgroups,
420         basketgroup          => $basketgroup,
421         grouped              => $basket->{basketgroupid},
422         # The double negatives and booleans here mean:
423         # "A basket cannot be closed if there are no orders in it or it's a standing order basket."
424         #
425         # (The template has another implicit restriction that the order cannot be closed if there
426         # are any orders with uncertain prices.)
427         unclosable           => @orders ? $basket->{is_standing} : 1,
428         has_budgets          => $has_budgets,
429         duplinbatch          => $duplinbatch,
430         csv_profiles         => [ Koha::CsvProfiles->search({ type => 'sql', used_for => 'export_basket' }) ],
431         available_additional_fields => [ Koha::AdditionalFields->search( { tablename => 'aqbasket' } ) ],
432         additional_field_values => { map {
433             $_->field->name => $_->value
434         } Koha::Acquisition::Baskets->find($basketno)->additional_field_values->as_list },
435     );
436 }
437
438 $template->param( messages => \@messages );
439 output_html_with_http_headers $query, $cookie, $template->output;
440
441 sub get_order_infos {
442     my $order = shift;
443     my $bookseller = shift;
444     my $qty = $order->{'quantity'} || 0;
445     if ( !defined $order->{quantityreceived} ) {
446         $order->{quantityreceived} = 0;
447     }
448     my $budget = GetBudget($order->{budget_id});
449     my $basket = GetBasket($order->{basketno});
450
451     my %line = %{ $order };
452     # Don't show unreceived standing orders as received
453     $line{order_received} = ( $qty == $order->{'quantityreceived'} && ( $basket->{is_standing} ? $qty : 1 ) );
454     $line{basketno}       = $basketno;
455     $line{budget_name}    = $budget->{budget_name};
456
457     # If we have an actual cost that should be the total, otherwise use the ecost
458     my $cost_tax_included = $line{unitprice_tax_included} || $line{ecost_tax_included};
459     my $cost_tax_excluded = $line{unitprice_tax_excluded} || $line{ecost_tax_excluded};
460     $line{total_tax_included} = get_rounded_price($cost_tax_included) * $line{quantity};
461     $line{total_tax_excluded} = get_rounded_price($cost_tax_excluded) * $line{quantity};
462     $line{tax_value} = $line{tax_value_on_ordering};
463     $line{tax_rate} = $line{tax_rate_on_ordering};
464
465     if ( $line{'title'} ) {
466         my $volume      = $order->{'volume'};
467         my $seriestitle = $order->{'seriestitle'};
468         $line{'title'} .= " / $seriestitle" if $seriestitle;
469         $line{'title'} .= " / $volume"      if $volume;
470     }
471
472     my $biblionumber = $order->{'biblionumber'};
473     if ( $biblionumber ) { # The biblio still exists
474         my $biblio = Koha::Biblios->find( $biblionumber );
475         my $countbiblio = $biblio->active_orders->count;
476
477         my $ordernumber = $order->{'ordernumber'};
478         my $cnt_subscriptions = $biblio->subscriptions->count;
479         my $itemcount   = $biblio->items->count;
480         my $holds_count = $biblio->holds->count;
481         my $order = Koha::Acquisition::Orders->find($ordernumber); # FIXME We should certainly do that at the beginning of this sub
482         my $items = $order->items;
483         my $itemholds  = $biblio->holds->search({ itemnumber => { -in => [ $items->get_column('itemnumber') ] } })->count;
484
485         # 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
486         $line{can_del_bib}          = 1 if $countbiblio <= 1 && $itemcount == $items->count && !($cnt_subscriptions) && !($holds_count);
487         $line{items}                = $itemcount - $items->count;
488         $line{left_item}            = 1 if $line{items} >= 1;
489         $line{left_biblio}          = 1 if $countbiblio > 1;
490         $line{biblios}              = $countbiblio - 1;
491         $line{left_subscription}    = 1 if $cnt_subscriptions;
492         $line{subscriptions}        = $cnt_subscriptions;
493         ($holds_count >= 1) ? $line{left_holds} = 1 : $line{left_holds} = 0;
494         $line{left_holds_on_order}  = 1 if $line{left_holds}==1 && ($line{items} == 0 || $itemholds );
495         $line{holds}                = $holds_count;
496         $line{holds_on_order}       = $itemholds?$itemholds:$holds_count if $line{left_holds_on_order};
497         $line{order_object}         = $order;
498     }
499
500
501     my $suggestion   = GetSuggestionInfoFromBiblionumber($line{biblionumber});
502     $line{suggestionid}         = $$suggestion{suggestionid};
503     $line{surnamesuggestedby}   = $$suggestion{surnamesuggestedby};
504     $line{firstnamesuggestedby} = $$suggestion{firstnamesuggestedby};
505
506     foreach my $key (qw(transferred_from transferred_to)) {
507         if ($line{$key}) {
508             my $order = GetOrder($line{$key});
509             my $basket = GetBasket($order->{basketno});
510             my $bookseller = Koha::Acquisition::Booksellers->find( $basket->{booksellerid} );
511             $line{$key} = {
512                 order => $order,
513                 basket => $basket,
514                 bookseller => $bookseller,
515                 timestamp => $line{$key . '_timestamp'},
516             };
517         }
518     }
519
520     return \%line;
521 }
522
523 sub edi_close_and_order {
524     my $confirm = $query->param('confirm') || $confirm_pref eq '2';
525     if ($confirm) {
526             my $edi_params = {
527                 basketno => $basketno,
528                 ean    => $ean,
529             };
530             if ( $basket->{branch} ) {
531                 $edi_params->{branchcode} = $basket->{branch};
532             }
533             if ( create_edi_order($edi_params) ) {
534                 #$template->param( edifile => 1 );
535             }
536         CloseBasket($basketno);
537
538         # if requested, create basket group, close it and attach the basket
539         if ( $query->param('createbasketgroup') ) {
540             my $branchcode;
541             if (    C4::Context->userenv
542                 and C4::Context->userenv->{'branch'} )
543             {
544                 $branchcode = C4::Context->userenv->{'branch'};
545             }
546             my $basketgroupid = NewBasketgroup(
547                 {
548                     name          => $basket->{basketname},
549                     booksellerid  => $booksellerid,
550                     deliveryplace => $branchcode,
551                     billingplace  => $branchcode,
552                     closed        => 1,
553                 }
554             );
555             ModBasket(
556                 {
557                     basketno      => $basketno,
558                     basketgroupid => $basketgroupid
559                 }
560             );
561             print $query->redirect(
562 "/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=$booksellerid&closed=1"
563             );
564         }
565         else {
566             print $query->redirect(
567                 "/cgi-bin/koha/acqui/booksellers.pl?booksellerid=$booksellerid"
568             );
569         }
570         exit;
571     }
572     else {
573         $template->param(
574             edi_confirm     => 1,
575             booksellerid    => $booksellerid,
576             basketno        => $basket->{basketno},
577             basketname      => $basket->{basketname},
578             basketgroupname => $basket->{basketname},
579         );
580         if ($ean) {
581             $template->param( ean => $ean );
582         }
583
584     }
585     return;
586 }