Bug 17785: Fix OAI-PMH's XSLT-generated URLs under Plack
[koha.git] / acqui / basket.pl
blobadcc43e1158ee7cba21177e0e368e5d17807d0f8
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::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 );
43 =head1 NAME
45 basket.pl
47 =head1 DESCRIPTION
49 This script display all informations about basket for the supplier given
50 on input arg. Moreover, it allows us to add a new order for this supplier from
51 an existing record, a suggestion or a new record.
53 =head1 CGI PARAMETERS
55 =over 4
57 =item $basketno
59 The basket number.
61 =item booksellerid
63 the supplier this script have to display the basket.
65 =item order
67 =back
69 =cut
71 my $query = new CGI;
72 our $basketno = $query->param('basketno');
73 my $ean = $query->param('ean');
74 my $booksellerid = $query->param('booksellerid');
75 my $duplinbatch = $query->param('duplinbatch');
77 my ( $template, $loggedinuser, $cookie, $userflags ) = get_template_and_user(
79 template_name => "acqui/basket.tt",
80 query => $query,
81 type => "intranet",
82 authnotrequired => 0,
83 flagsrequired => { acquisition => 'order_manage' },
84 debug => 1,
88 my $basket = GetBasket($basketno);
89 $booksellerid = $basket->{booksellerid} unless $booksellerid;
90 my $bookseller = Koha::Acquisition::Bookseller->fetch({ id => $booksellerid });
91 my $schema = Koha::Database->new()->schema();
92 my $rs = $schema->resultset('VendorEdiAccount')->search(
93 { vendor_id => $booksellerid, } );
94 $template->param( ediaccount => ($rs->count > 0));
96 unless (CanUserManageBasket($loggedinuser, $basket, $userflags)) {
97 $template->param(
98 cannot_manage_basket => 1,
99 basketno => $basketno,
100 basketname => $basket->{basketname},
101 booksellerid => $booksellerid,
102 name => $bookseller->{name}
104 output_html_with_http_headers $query, $cookie, $template->output;
105 exit;
108 # FIXME : what about the "discount" percentage?
109 # FIXME : the query->param('booksellerid') below is probably useless. The bookseller is always known from the basket
110 # if no booksellerid in parameter, get it from basket
111 # warn "=>".$basket->{booksellerid};
112 my $op = $query->param('op') // 'list';
114 my $confirm_pref= C4::Context->preference("BasketConfirmations") || '1';
115 $template->param( skip_confirm_reopen => 1) if $confirm_pref eq '2';
117 my @messages;
119 if ( $op eq 'delete_confirm' ) {
120 my $basketno = $query->param('basketno');
121 my $delbiblio = $query->param('delbiblio');
122 my @orders = GetOrders($basketno);
123 #Delete all orders included in that basket, and all items received.
124 foreach my $myorder (@orders){
125 DelOrder($myorder->{biblionumber},$myorder->{ordernumber});
127 # if $delbiblio = 1, delete the records if possible
128 if ((defined $delbiblio)and ($delbiblio ==1)){
129 my @cannotdelbiblios ;
130 foreach my $myorder (@orders){
131 my $biblionumber = $myorder->{'biblionumber'};
132 my $countbiblio = CountBiblioInOrders($biblionumber);
133 my $ordernumber = $myorder->{'ordernumber'};
134 my $subscriptions = scalar GetSubscriptionsId ($biblionumber);
135 my $itemcount = GetItemsCount($biblionumber);
136 my $error;
137 if ($countbiblio == 0 && $itemcount == 0 && $subscriptions == 0) {
138 $error = DelBiblio($myorder->{biblionumber}) }
139 else {
140 push @cannotdelbiblios, {biblionumber=> ($myorder->{biblionumber}),
141 title=> $myorder->{'title'},
142 author=> $myorder->{'author'},
143 countbiblio=> $countbiblio,
144 itemcount=>$itemcount,
145 subscriptions=>$subscriptions};
147 if ($error) {
148 push @cannotdelbiblios, {biblionumber=> ($myorder->{biblionumber}),
149 title=> $myorder->{'title'},
150 author=> $myorder->{'author'},
151 othererror=> $error};
154 $template->param( cannotdelbiblios => \@cannotdelbiblios );
156 # delete the basket
157 DelBasket($basketno,);
158 $template->param( delete_confirmed => 1 );
159 } elsif ( !$bookseller ) {
160 $template->param( NO_BOOKSELLER => 1 );
161 } elsif ($op eq 'export') {
162 print $query->header(
163 -type => 'text/csv',
164 -attachment => 'basket' . $basket->{'basketno'} . '.csv',
166 print GetBasketAsCSV($query->param('basketno'), $query);
167 exit;
168 } elsif ($op eq 'email') {
169 my $err = eval {
170 SendAlerts( 'orderacquisition', $query->param('basketno'), 'ACQORDER' );
172 if ( $@ ) {
173 push @messages, { type => 'error', code => $@ };
174 } elsif ( ref $err and exists $err->{error} ) {
175 push @messages, { type => 'error', code => $err->{error} };
176 } else {
177 push @messages, { type => 'message', code => 'email_sent' };
180 $op = 'list';
181 } elsif ($op eq 'close') {
182 my $confirm = $query->param('confirm') || $confirm_pref eq '2';
183 if ($confirm) {
184 my $basketno = $query->param('basketno');
185 my $booksellerid = $query->param('booksellerid');
186 $basketno =~ /^\d+$/ and CloseBasket($basketno);
187 # if requested, create basket group, close it and attach the basket
188 if ($query->param('createbasketgroup')) {
189 my $branchcode;
190 if(C4::Context->userenv and C4::Context->userenv->{'branch'}
191 and C4::Context->userenv->{'branch'} ne "NO_LIBRARY_SET") {
192 $branchcode = C4::Context->userenv->{'branch'};
194 my $basketgroupid = NewBasketgroup( { name => $basket->{basketname},
195 booksellerid => $booksellerid,
196 deliveryplace => $branchcode,
197 billingplace => $branchcode,
198 closed => 1,
200 ModBasket( { basketno => $basketno,
201 basketgroupid => $basketgroupid } );
202 print $query->redirect('/cgi-bin/koha/acqui/basketgroup.pl?booksellerid='.$booksellerid.'&closed=1');
203 } else {
204 print $query->redirect('/cgi-bin/koha/acqui/booksellers.pl?booksellerid=' . $booksellerid);
206 exit;
207 } else {
208 $template->param(
209 confirm_close => "1",
210 booksellerid => $booksellerid,
211 basketno => $basket->{'basketno'},
212 basketname => $basket->{'basketname'},
213 basketgroupname => $basket->{'basketname'},
216 } elsif ($op eq 'reopen') {
217 ReopenBasket($query->param('basketno'));
218 print $query->redirect('/cgi-bin/koha/acqui/basket.pl?basketno='.$basket->{'basketno'})
220 elsif ( $op eq 'ediorder' ) {
221 edi_close_and_order()
222 } elsif ( $op eq 'mod_users' ) {
223 my $basketusers_ids = $query->param('users_ids');
224 my @basketusers = split( /:/, $basketusers_ids );
225 ModBasketUsers($basketno, @basketusers);
226 print $query->redirect("/cgi-bin/koha/acqui/basket.pl?basketno=$basketno");
227 exit;
228 } elsif ( $op eq 'mod_branch' ) {
229 my $branch = $query->param('branch');
230 $branch = undef if(defined $branch and $branch eq '');
231 ModBasket({
232 basketno => $basket->{basketno},
233 branch => $branch
235 print $query->redirect("/cgi-bin/koha/acqui/basket.pl?basketno=$basketno");
236 exit;
239 if ( $op eq 'list' ) {
240 my @branches_loop;
241 # get librarian branch...
242 if ( C4::Context->preference("IndependentBranches") ) {
243 my $userenv = C4::Context->userenv;
244 unless ( C4::Context->IsSuperLibrarian() ) {
245 my $validtest = ( $basket->{creationdate} eq '' )
246 || ( $userenv->{branch} eq $basket->{branch} )
247 || ( $userenv->{branch} eq '' )
248 || ( $basket->{branch} eq '' );
249 unless ($validtest) {
250 print $query->redirect("../mainpage.pl");
251 exit 0;
255 if (!defined $basket->{branch} or $basket->{branch} eq $userenv->{branch}) {
256 push @branches_loop, {
257 branchcode => $userenv->{branch},
258 branchname => $userenv->{branchname},
259 selected => 1,
262 } else {
263 # get branches
264 my $branches = Koha::Libraries->search( {}, { order_by => ['branchname'] } )->unblessed;
265 foreach my $branch (@$branches) {
266 my $selected = 0;
267 if (defined $basket->{branch}) {
268 $selected = 1 if $branch->{branchcode} eq $basket->{branch};
269 } else {
270 $selected = 1 if $branch->{branchcode} eq C4::Context->userenv->{branch};
272 push @branches_loop, {
273 branchcode => $branch->{branchcode},
274 branchname => $branch->{branchname},
275 selected => $selected
280 #if the basket is closed,and the user has the permission to edit basketgroups, display a list of basketgroups
281 my ($basketgroup, $basketgroups);
282 my $staffuser = GetMember(borrowernumber => $loggedinuser);
283 if ($basket->{closedate} && haspermission($staffuser->{userid}, { acquisition => 'group_manage'} )) {
284 $basketgroups = GetBasketgroups($basket->{booksellerid});
285 for my $bg ( @{$basketgroups} ) {
286 if ($basket->{basketgroupid} && $basket->{basketgroupid} == $bg->{id}){
287 $bg->{default} = 1;
288 $basketgroup = $bg;
293 # if the basket is closed, calculate estimated delivery date
294 my $estimateddeliverydate;
295 if( $basket->{closedate} ) {
296 my ($year, $month, $day) = ($basket->{closedate} =~ /(\d+)-(\d+)-(\d+)/);
297 ($year, $month, $day) = Add_Delta_Days($year, $month, $day, $bookseller->{deliverytime});
298 $estimateddeliverydate = sprintf( "%04d-%02d-%02d", $year, $month, $day );
301 # if new basket, pre-fill infos
302 $basket->{creationdate} = "" unless ( $basket->{creationdate} );
303 $basket->{authorisedby} = $loggedinuser unless ( $basket->{authorisedby} );
304 $debug
305 and warn sprintf
306 "loggedinuser: $loggedinuser; creationdate: %s; authorisedby: %s",
307 $basket->{creationdate}, $basket->{authorisedby};
309 my @basketusers_ids = GetBasketUsers($basketno);
310 my @basketusers;
311 foreach my $basketuser_id (@basketusers_ids) {
312 my $basketuser = GetMember(borrowernumber => $basketuser_id);
313 push @basketusers, $basketuser if $basketuser;
316 my $active_currency = Koha::Acquisition::Currencies->get_active;
318 my @orders = GetOrders( $basketno );
319 my @books_loop;
321 my @book_foot_loop;
322 my %foot;
323 my $total_quantity = 0;
324 my $total_tax_excluded = 0;
325 my $total_tax_included = 0;
326 my $total_tax_value = 0;
327 for my $order (@orders) {
328 my $line = get_order_infos( $order, $bookseller);
329 if ( $line->{uncertainprice} ) {
330 $template->param( uncertainprices => 1 );
333 $line->{tax_rate} = $line->{tax_rate_on_ordering};
334 $line->{tax_value} = $line->{tax_value_on_ordering};
336 push @books_loop, $line;
338 $foot{$$line{tax_rate}}{tax_rate} = $$line{tax_rate};
339 $foot{$$line{tax_rate}}{tax_value} += $$line{tax_value};
340 $total_tax_value += $$line{tax_value};
341 $foot{$$line{tax_rate}}{quantity} += $$line{quantity};
342 $total_quantity += $$line{quantity};
343 $foot{$$line{tax_rate}}{total_tax_excluded} += $$line{total_tax_excluded};
344 $total_tax_excluded += $$line{total_tax_excluded};
345 $foot{$$line{tax_rate}}{total_tax_included} += $$line{total_tax_included};
346 $total_tax_included += $$line{total_tax_included};
349 push @book_foot_loop, map {$_} values %foot;
351 # Get cancelled orders
352 my @cancelledorders = GetOrders($basketno, { cancelled => 1 });
353 my @cancelledorders_loop;
354 for my $order (@cancelledorders) {
355 my $line = get_order_infos( $order, $bookseller);
356 push @cancelledorders_loop, $line;
359 my $contract = GetContract({
360 contractnumber => $basket->{contractnumber}
363 if ($basket->{basketgroupid}){
364 $basketgroup = GetBasketgroup($basket->{basketgroupid});
366 my $borrower= GetMember('borrowernumber' => $loggedinuser);
367 my $budgets = GetBudgetHierarchy;
368 my $has_budgets = 0;
369 foreach my $r (@{$budgets}) {
370 if (!defined $r->{budget_amount} || $r->{budget_amount} == 0) {
371 next;
373 next unless (CanUserUseBudget($loggedinuser, $r, $userflags));
375 $has_budgets = 1;
376 last;
379 $template->param(
380 basketno => $basketno,
381 basket => $basket,
382 basketname => $basket->{'basketname'},
383 basketbranchcode => $basket->{branch},
384 basketnote => $basket->{note},
385 basketbooksellernote => $basket->{booksellernote},
386 basketcontractno => $basket->{contractnumber},
387 basketcontractname => $contract->{contractname},
388 branches_loop => \@branches_loop,
389 creationdate => $basket->{creationdate},
390 authorisedby => $basket->{authorisedby},
391 authorisedbyname => $basket->{authorisedbyname},
392 users_ids => join(':', @basketusers_ids),
393 users => \@basketusers,
394 closedate => $basket->{closedate},
395 estimateddeliverydate=> $estimateddeliverydate,
396 is_standing => $basket->{is_standing},
397 deliveryplace => $basket->{deliveryplace},
398 billingplace => $basket->{billingplace},
399 active => $bookseller->{'active'},
400 booksellerid => $bookseller->{'id'},
401 name => $bookseller->{'name'},
402 books_loop => \@books_loop,
403 book_foot_loop => \@book_foot_loop,
404 cancelledorders_loop => \@cancelledorders_loop,
405 total_quantity => $total_quantity,
406 total_tax_excluded => $total_tax_excluded,
407 total_tax_included => $total_tax_included,
408 total_tax_value => $total_tax_value,
409 currency => $active_currency->currency,
410 listincgst => $bookseller->{listincgst},
411 basketgroups => $basketgroups,
412 basketgroup => $basketgroup,
413 grouped => $basket->{basketgroupid},
414 # The double negatives and booleans here mean:
415 # "A basket cannot be closed if there are no orders in it or it's a standing order basket."
417 # (The template has another implicit restriction that the order cannot be closed if there
418 # are any orders with uncertain prices.)
419 unclosable => @orders ? $basket->{is_standing} : 1,
420 has_budgets => $has_budgets,
421 duplinbatch => $duplinbatch,
425 $template->param( messages => \@messages );
426 output_html_with_http_headers $query, $cookie, $template->output;
428 sub get_order_infos {
429 my $order = shift;
430 my $bookseller = shift;
431 my $qty = $order->{'quantity'} || 0;
432 if ( !defined $order->{quantityreceived} ) {
433 $order->{quantityreceived} = 0;
435 my $budget = GetBudget($order->{budget_id});
436 my $basket = GetBasket($order->{basketno});
438 my %line = %{ $order };
439 # Don't show unreceived standing orders as received
440 $line{order_received} = ( $qty == $order->{'quantityreceived'} && ( $basket->{is_standing} ? $qty : 1 ) );
441 $line{basketno} = $basketno;
442 $line{budget_name} = $budget->{budget_name};
444 $line{total_tax_included} = $line{ecost_tax_included} * $line{quantity};
445 $line{total_tax_excluded} = $line{ecost_tax_excluded} * $line{quantity};
446 $line{tax_value} = $line{tax_value_on_ordering};
447 $line{tax_rate} = $line{tax_rate_on_ordering};
449 if ( $line{uncertainprice} ) {
450 $line{rrp_tax_excluded} .= ' (Uncertain)';
452 if ( $line{'title'} ) {
453 my $volume = $order->{'volume'};
454 my $seriestitle = $order->{'seriestitle'};
455 $line{'title'} .= " / $seriestitle" if $seriestitle;
456 $line{'title'} .= " / $volume" if $volume;
459 my $biblionumber = $order->{'biblionumber'};
460 my $biblio = Koha::Biblios->find( $biblionumber );
461 my $countbiblio = CountBiblioInOrders($biblionumber);
462 my $ordernumber = $order->{'ordernumber'};
463 my @subscriptions = GetSubscriptionsId ($biblionumber);
464 my $itemcount = GetItemsCount($biblionumber);
465 my $holds_count = $biblio->holds->count;
466 my @items = GetItemnumbersFromOrder( $ordernumber );
467 my $itemholds;
468 foreach my $item (@items){
469 my $nb = GetItemHolds($biblionumber, $item);
470 if ($nb){
471 $itemholds += $nb;
474 # 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
475 $line{can_del_bib} = 1 if $countbiblio <= 1 && $itemcount == scalar @items && !(@subscriptions) && !($holds_count);
476 $line{items} = ($itemcount) - (scalar @items);
477 $line{left_item} = 1 if $line{items} >= 1;
478 $line{left_biblio} = 1 if $countbiblio > 1;
479 $line{biblios} = $countbiblio - 1;
480 $line{left_subscription} = 1 if scalar @subscriptions >= 1;
481 $line{subscriptions} = scalar @subscriptions;
482 ($holds_count >= 1) ? $line{left_holds} = 1 : $line{left_holds} = 0;
483 $line{left_holds_on_order} = 1 if $line{left_holds}==1 && ($line{items} == 0 || $itemholds );
484 $line{holds} = $holds_count;
485 $line{holds_on_order} = $itemholds?$itemholds:$holds_count if $line{left_holds_on_order};
488 my $suggestion = GetSuggestionInfoFromBiblionumber($line{biblionumber});
489 $line{suggestionid} = $$suggestion{suggestionid};
490 $line{surnamesuggestedby} = $$suggestion{surnamesuggestedby};
491 $line{firstnamesuggestedby} = $$suggestion{firstnamesuggestedby};
493 foreach my $key (qw(transferred_from transferred_to)) {
494 if ($line{$key}) {
495 my $order = GetOrder($line{$key});
496 my $bookseller = Koha::Acquisition::Bookseller->fetch({ id => $basket->{booksellerid} });
497 $line{$key} = {
498 order => $order,
499 basket => $basket,
500 bookseller => $bookseller,
501 timestamp => $line{$key . '_timestamp'},
506 return \%line;
509 sub edi_close_and_order {
510 my $confirm = $query->param('confirm') || $confirm_pref eq '2';
511 if ($confirm) {
512 my $edi_params = {
513 basketno => $basketno,
514 ean => $ean,
516 if ( $basket->{branch} ) {
517 $edi_params->{branchcode} = $basket->{branch};
519 if ( create_edi_order($edi_params) ) {
520 #$template->param( edifile => 1 );
522 CloseBasket($basketno);
524 # if requested, create basket group, close it and attach the basket
525 if ( $query->param('createbasketgroup') ) {
526 my $branchcode;
527 if ( C4::Context->userenv
528 and C4::Context->userenv->{'branch'}
529 and C4::Context->userenv->{'branch'} ne "NO_LIBRARY_SET" )
531 $branchcode = C4::Context->userenv->{'branch'};
533 my $basketgroupid = NewBasketgroup(
535 name => $basket->{basketname},
536 booksellerid => $booksellerid,
537 deliveryplace => $branchcode,
538 billingplace => $branchcode,
539 closed => 1,
542 ModBasket(
544 basketno => $basketno,
545 basketgroupid => $basketgroupid
548 print $query->redirect(
549 "/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=$booksellerid&closed=1"
552 else {
553 print $query->redirect(
554 "/cgi-bin/koha/acqui/booksellers.pl?booksellerid=$booksellerid"
557 exit;
559 else {
560 $template->param(
561 edi_confirm => 1,
562 booksellerid => $booksellerid,
563 basketno => $basket->{basketno},
564 basketname => $basket->{basketname},
565 basketgroupname => $basket->{basketname},
567 if ($ean) {
568 $template->param( ean => $ean );
572 return;