Bug 13320: Move price calculation from tt to pl
[koha.git] / acqui / basket.pl
blob921c67e79c0f32092e07725f825722163a60bbca
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 under the
11 # terms of the GNU General Public License as published by the Free Software
12 # Foundation; either version 2 of the License, or (at your option) any later
13 # version.
15 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
16 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
17 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License along
20 # with Koha; if not, write to the Free Software Foundation, Inc.,
21 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 use strict;
24 use warnings;
25 use C4::Auth;
26 use C4::Koha;
27 use C4::Output;
28 use CGI qw ( -utf8 );
29 use C4::Acquisition;
30 use C4::Budgets;
31 use C4::Branch;
32 use C4::Contract;
33 use C4::Debug;
34 use C4::Biblio;
35 use C4::Members qw/GetMember/; #needed for permissions checking for changing basketgroup of a basket
36 use C4::Items;
37 use C4::Suggestions;
38 use Date::Calc qw/Add_Delta_Days/;
40 =head1 NAME
42 basket.pl
44 =head1 DESCRIPTION
46 This script display all informations about basket for the supplier given
47 on input arg. Moreover, it allows us to add a new order for this supplier from
48 an existing record, a suggestion or a new record.
50 =head1 CGI PARAMETERS
52 =over 4
54 =item $basketno
56 The basket number.
58 =item booksellerid
60 the supplier this script have to display the basket.
62 =item order
64 =back
66 =cut
68 my $query = new CGI;
69 our $basketno = $query->param('basketno');
70 my $booksellerid = $query->param('booksellerid');
72 my ( $template, $loggedinuser, $cookie, $userflags ) = get_template_and_user(
74 template_name => "acqui/basket.tt",
75 query => $query,
76 type => "intranet",
77 authnotrequired => 0,
78 flagsrequired => { acquisition => 'order_manage' },
79 debug => 1,
83 my $basket = GetBasket($basketno);
84 $booksellerid = $basket->{booksellerid} unless $booksellerid;
85 my $bookseller = Koha::Acquisition::Bookseller->fetch({ id => $booksellerid });
87 unless (CanUserManageBasket($loggedinuser, $basket, $userflags)) {
88 $template->param(
89 cannot_manage_basket => 1,
90 basketno => $basketno,
91 basketname => $basket->{basketname},
92 booksellerid => $booksellerid,
93 name => $bookseller->{name}
95 output_html_with_http_headers $query, $cookie, $template->output;
96 exit;
99 # FIXME : what about the "discount" percentage?
100 # FIXME : the query->param('booksellerid') below is probably useless. The bookseller is always known from the basket
101 # if no booksellerid in parameter, get it from basket
102 # warn "=>".$basket->{booksellerid};
103 my $op = $query->param('op');
104 if (!defined $op) {
105 $op = q{};
108 my $confirm_pref= C4::Context->preference("BasketConfirmations") || '1';
109 $template->param( skip_confirm_reopen => 1) if $confirm_pref eq '2';
111 if ( $op eq 'delete_confirm' ) {
112 my $basketno = $query->param('basketno');
113 my $delbiblio = $query->param('delbiblio');
114 my @orders = GetOrders($basketno);
115 #Delete all orders included in that basket, and all items received.
116 foreach my $myorder (@orders){
117 DelOrder($myorder->{biblionumber},$myorder->{ordernumber});
119 # if $delbiblio = 1, delete the records if possible
120 if ((defined $delbiblio)and ($delbiblio ==1)){
121 my @cannotdelbiblios ;
122 foreach my $myorder (@orders){
123 my $biblionumber = $myorder->{'biblionumber'};
124 my $countbiblio = CountBiblioInOrders($biblionumber);
125 my $ordernumber = $myorder->{'ordernumber'};
126 my $subscriptions = scalar GetSubscriptionsId ($biblionumber);
127 my $itemcount = GetItemsCount($biblionumber);
128 my $error;
129 if ($countbiblio == 0 && $itemcount == 0 && $subscriptions == 0) {
130 $error = DelBiblio($myorder->{biblionumber}) }
131 else {
132 push @cannotdelbiblios, {biblionumber=> ($myorder->{biblionumber}),
133 title=> $myorder->{'title'},
134 author=> $myorder->{'author'},
135 countbiblio=> $countbiblio,
136 itemcount=>$itemcount,
137 subscriptions=>$subscriptions};
139 if ($error) {
140 push @cannotdelbiblios, {biblionumber=> ($myorder->{biblionumber}),
141 title=> $myorder->{'title'},
142 author=> $myorder->{'author'},
143 othererror=> $error};
146 $template->param( cannotdelbiblios => \@cannotdelbiblios );
148 # delete the basket
149 DelBasket($basketno,);
150 $template->param( delete_confirmed => 1 );
151 } elsif ( !$bookseller ) {
152 $template->param( NO_BOOKSELLER => 1 );
153 } elsif ( $op eq 'del_basket') {
154 $template->param( delete_confirm => 1 );
155 if ( C4::Context->preference("IndependentBranches") ) {
156 my $userenv = C4::Context->userenv;
157 unless ( C4::Context->IsSuperLibrarian() ) {
158 my $validtest = ( $basket->{creationdate} eq '' )
159 || ( $userenv->{branch} eq $basket->{branch} )
160 || ( $userenv->{branch} eq '' )
161 || ( $basket->{branch} eq '' );
162 unless ($validtest) {
163 print $query->redirect("../mainpage.pl");
164 exit 1;
168 $basket->{creationdate} = "" unless ( $basket->{creationdate} );
169 $basket->{authorisedby} = $loggedinuser unless ( $basket->{authorisedby} );
170 my $contract = GetContract({
171 contractnumber => $basket->{contractnumber}
173 $template->param(
174 basketno => $basketno,
175 basketname => $basket->{'basketname'},
176 basketnote => $basket->{note},
177 basketbooksellernote => $basket->{booksellernote},
178 basketcontractno => $basket->{contractnumber},
179 basketcontractname => $contract->{contractname},
180 creationdate => $basket->{creationdate},
181 authorisedby => $basket->{authorisedby},
182 authorisedbyname => $basket->{authorisedbyname},
183 closedate => $basket->{closedate},
184 deliveryplace => $basket->{deliveryplace},
185 billingplace => $basket->{billingplace},
186 active => $bookseller->{'active'},
187 booksellerid => $bookseller->{'id'},
188 name => $bookseller->{'name'},
189 address1 => $bookseller->{'address1'},
190 address2 => $bookseller->{'address2'},
191 address3 => $bookseller->{'address3'},
192 address4 => $bookseller->{'address4'},
194 } elsif ($op eq 'export') {
195 print $query->header(
196 -type => 'text/csv',
197 -attachment => 'basket' . $basket->{'basketno'} . '.csv',
199 print GetBasketAsCSV($query->param('basketno'), $query);
200 exit;
201 } elsif ($op eq 'close') {
202 my $confirm = $query->param('confirm') || $confirm_pref eq '2';
203 if ($confirm) {
204 my $basketno = $query->param('basketno');
205 my $booksellerid = $query->param('booksellerid');
206 $basketno =~ /^\d+$/ and CloseBasket($basketno);
207 # if requested, create basket group, close it and attach the basket
208 if ($query->param('createbasketgroup')) {
209 my $branchcode;
210 if(C4::Context->userenv and C4::Context->userenv->{'branch'}
211 and C4::Context->userenv->{'branch'} ne "NO_LIBRARY_SET") {
212 $branchcode = C4::Context->userenv->{'branch'};
214 my $basketgroupid = NewBasketgroup( { name => $basket->{basketname},
215 booksellerid => $booksellerid,
216 deliveryplace => $branchcode,
217 billingplace => $branchcode,
218 closed => 1,
220 ModBasket( { basketno => $basketno,
221 basketgroupid => $basketgroupid } );
222 print $query->redirect('/cgi-bin/koha/acqui/basketgroup.pl?booksellerid='.$booksellerid.'&closed=1');
223 } else {
224 print $query->redirect('/cgi-bin/koha/acqui/booksellers.pl?booksellerid=' . $booksellerid);
226 exit;
227 } else {
228 $template->param(
229 confirm_close => "1",
230 booksellerid => $booksellerid,
231 basketno => $basket->{'basketno'},
232 basketname => $basket->{'basketname'},
233 basketgroupname => $basket->{'basketname'},
236 } elsif ($op eq 'reopen') {
237 ReopenBasket($query->param('basketno'));
238 print $query->redirect('/cgi-bin/koha/acqui/basket.pl?basketno='.$basket->{'basketno'})
239 } elsif ( $op eq 'mod_users' ) {
240 my $basketusers_ids = $query->param('basketusers_ids');
241 my @basketusers = split( /:/, $basketusers_ids );
242 ModBasketUsers($basketno, @basketusers);
243 print $query->redirect("/cgi-bin/koha/acqui/basket.pl?basketno=$basketno");
244 exit;
245 } elsif ( $op eq 'mod_branch' ) {
246 my $branch = $query->param('branch');
247 $branch = undef if(defined $branch and $branch eq '');
248 ModBasket({
249 basketno => $basket->{basketno},
250 branch => $branch
252 print $query->redirect("/cgi-bin/koha/acqui/basket.pl?basketno=$basketno");
253 exit;
254 } else {
255 my @branches_loop;
256 # get librarian branch...
257 if ( C4::Context->preference("IndependentBranches") ) {
258 my $userenv = C4::Context->userenv;
259 unless ( C4::Context->IsSuperLibrarian() ) {
260 my $validtest = ( $basket->{creationdate} eq '' )
261 || ( $userenv->{branch} eq $basket->{branch} )
262 || ( $userenv->{branch} eq '' )
263 || ( $basket->{branch} eq '' );
264 unless ($validtest) {
265 print $query->redirect("../mainpage.pl");
266 exit 1;
269 if (!defined $basket->{branch} or $basket->{branch} eq $userenv->{branch}) {
270 push @branches_loop, {
271 branchcode => $userenv->{branch},
272 branchname => $userenv->{branchname},
273 selected => 1,
276 } else {
277 # get branches
278 my $branches = C4::Branch::GetBranches;
279 my @branchcodes = sort {
280 $branches->{$a}->{branchname} cmp $branches->{$b}->{branchname}
281 } keys %$branches;
282 foreach my $branch (@branchcodes) {
283 my $selected = 0;
284 if (defined $basket->{branch}) {
285 $selected = 1 if $branch eq $basket->{branch};
286 } else {
287 $selected = 1 if $branch eq C4::Context->userenv->{branch};
289 push @branches_loop, {
290 branchcode => $branch,
291 branchname => $branches->{$branch}->{branchname},
292 selected => $selected
297 #if the basket is closed,and the user has the permission to edit basketgroups, display a list of basketgroups
298 my ($basketgroup, $basketgroups);
299 my $staffuser = GetMember(borrowernumber => $loggedinuser);
300 if ($basket->{closedate} && haspermission($staffuser->{userid}, { acquisition => 'group_manage'} )) {
301 $basketgroups = GetBasketgroups($basket->{booksellerid});
302 for my $bg ( @{$basketgroups} ) {
303 if ($basket->{basketgroupid} && $basket->{basketgroupid} == $bg->{id}){
304 $bg->{default} = 1;
305 $basketgroup = $bg;
310 # if the basket is closed, calculate estimated delivery date
311 my $estimateddeliverydate;
312 if( $basket->{closedate} ) {
313 my ($year, $month, $day) = ($basket->{closedate} =~ /(\d+)-(\d+)-(\d+)/);
314 ($year, $month, $day) = Add_Delta_Days($year, $month, $day, $bookseller->{deliverytime});
315 $estimateddeliverydate = "$year-$month-$day";
318 # if new basket, pre-fill infos
319 $basket->{creationdate} = "" unless ( $basket->{creationdate} );
320 $basket->{authorisedby} = $loggedinuser unless ( $basket->{authorisedby} );
321 $debug
322 and warn sprintf
323 "loggedinuser: $loggedinuser; creationdate: %s; authorisedby: %s",
324 $basket->{creationdate}, $basket->{authorisedby};
326 my @basketusers_ids = GetBasketUsers($basketno);
327 my @basketusers;
328 foreach my $basketuser_id (@basketusers_ids) {
329 my $basketuser = GetMember(borrowernumber => $basketuser_id);
330 push @basketusers, $basketuser if $basketuser;
333 #to get active currency
334 my $cur = GetCurrency();
337 my @results = GetOrders( $basketno );
338 my @books_loop;
340 my @book_foot_loop;
341 my %foot;
342 my $total_quantity = 0;
343 my $total_gste = 0;
344 my $total_gsti = 0;
345 my $total_gstvalue = 0;
346 for my $order (@results) {
347 my $line = get_order_infos( $order, $bookseller);
348 if ( $line->{uncertainprice} ) {
349 $template->param( uncertainprices => 1 );
352 push @books_loop, $line;
354 $foot{$$line{gstgsti}}{gstgsti} = $$line{gstgsti};
355 $foot{$$line{gstgsti}}{gstvalue} += $$line{gstvalue};
356 $total_gstvalue += $$line{gstvalue};
357 $foot{$$line{gstgsti}}{quantity} += $$line{quantity};
358 $total_quantity += $$line{quantity};
359 $foot{$$line{gstgsti}}{totalgste} += $$line{totalgste};
360 $total_gste += $$line{totalgste};
361 $foot{$$line{gstgsti}}{totalgsti} += $$line{totalgsti};
362 $total_gsti += $$line{totalgsti};
365 push @book_foot_loop, map {$_} values %foot;
367 # Get cancelled orders
368 @results = GetCancelledOrders($basketno);
369 my @cancelledorders_loop;
370 for my $order (@results) {
371 my $line = get_order_infos( $order, $bookseller);
372 push @cancelledorders_loop, $line;
375 my $contract = GetContract({
376 contractnumber => $basket->{contractnumber}
378 my @orders = GetOrders($basketno);
380 if ($basket->{basketgroupid}){
381 $basketgroup = GetBasketgroup($basket->{basketgroupid});
382 $basketgroup->{deliveryplacename} = C4::Branch::GetBranchName( $basketgroup->{deliveryplace} );
383 $basketgroup->{billingplacename} = C4::Branch::GetBranchName( $basketgroup->{billingplace} );
385 my $borrower= GetMember('borrowernumber' => $loggedinuser);
386 my $budgets = GetBudgetHierarchy;
387 my $has_budgets = 0;
388 foreach my $r (@{$budgets}) {
389 if (!defined $r->{budget_amount} || $r->{budget_amount} == 0) {
390 next;
392 next unless (CanUserUseBudget($loggedinuser, $r, $userflags));
394 $has_budgets = 1;
395 last;
398 $template->param(
399 basketno => $basketno,
400 basketname => $basket->{'basketname'},
401 basketbranchname => C4::Branch::GetBranchName($basket->{branch}),
402 basketnote => $basket->{note},
403 basketbooksellernote => $basket->{booksellernote},
404 basketcontractno => $basket->{contractnumber},
405 basketcontractname => $contract->{contractname},
406 branches_loop => \@branches_loop,
407 creationdate => $basket->{creationdate},
408 authorisedby => $basket->{authorisedby},
409 authorisedbyname => $basket->{authorisedbyname},
410 basketusers_ids => join(':', @basketusers_ids),
411 basketusers => \@basketusers,
412 closedate => $basket->{closedate},
413 estimateddeliverydate=> $estimateddeliverydate,
414 deliveryplace => C4::Branch::GetBranchName( $basket->{deliveryplace} ),
415 billingplace => C4::Branch::GetBranchName( $basket->{billingplace} ),
416 active => $bookseller->{'active'},
417 booksellerid => $bookseller->{'id'},
418 name => $bookseller->{'name'},
419 books_loop => \@books_loop,
420 book_foot_loop => \@book_foot_loop,
421 cancelledorders_loop => \@cancelledorders_loop,
422 total_quantity => $total_quantity,
423 total_gste => sprintf( "%.2f", $total_gste ),
424 total_gsti => sprintf( "%.2f", $total_gsti ),
425 total_gstvalue => sprintf( "%.2f", $total_gstvalue ),
426 currency => $cur->{'currency'},
427 listincgst => $bookseller->{listincgst},
428 basketgroups => $basketgroups,
429 basketgroup => $basketgroup,
430 grouped => $basket->{basketgroupid},
431 unclosable => @orders ? 0 : 1,
432 has_budgets => $has_budgets,
436 sub get_order_infos {
437 my $order = shift;
438 my $bookseller = shift;
439 my $qty = $order->{'quantity'} || 0;
440 if ( !defined $order->{quantityreceived} ) {
441 $order->{quantityreceived} = 0;
443 my $budget = GetBudget( $order->{'budget_id'} );
445 my %line = %{ $order };
446 $line{order_received} = ( $qty == $order->{'quantityreceived'} );
447 $line{basketno} = $basketno;
448 $line{budget_name} = $budget->{budget_name};
449 $line{rrp} = ConvertCurrency( $order->{'currency'}, $line{rrp} ); # FIXME from comm
450 if ( $bookseller->{'listincgst'} ) {
451 $line{rrpgsti} = sprintf( "%.2f", $line{rrp} );
452 $line{gstgsti} = sprintf( "%.2f", $line{gstrate} * 100 );
453 $line{rrpgste} = sprintf( "%.2f", $line{rrp} / ( 1 + ( $line{gstgsti} / 100 ) ) );
454 $line{gstgste} = sprintf( "%.2f", $line{gstgsti} / ( 1 + ( $line{gstgsti} / 100 ) ) );
455 $line{ecostgsti} = sprintf( "%.2f", $line{ecost} );
456 $line{ecostgste} = sprintf( "%.2f", $line{ecost} / ( 1 + ( $line{gstgsti} / 100 ) ) );
457 $line{gstvalue} = sprintf( "%.2f", ( $line{ecostgsti} - $line{ecostgste} ) * $line{quantity});
458 $line{totalgste} = sprintf( "%.2f", $order->{quantity} * $line{ecostgste} );
459 $line{totalgsti} = sprintf( "%.2f", $order->{quantity} * $line{ecostgsti} );
460 } else {
461 $line{rrpgsti} = sprintf( "%.2f", $line{rrp} * ( 1 + ( $line{gstrate} ) ) );
462 $line{rrpgste} = sprintf( "%.2f", $line{rrp} );
463 $line{gstgsti} = sprintf( "%.2f", $line{gstrate} * 100 );
464 $line{gstgste} = sprintf( "%.2f", $line{gstrate} * 100 );
465 $line{ecostgsti} = sprintf( "%.2f", $line{ecost} * ( 1 + ( $line{gstrate} ) ) );
466 $line{ecostgste} = sprintf( "%.2f", $line{ecost} );
467 $line{gstvalue} = sprintf( "%.2f", ( $line{ecostgsti} - $line{ecostgste} ) * $line{quantity});
468 $line{totalgste} = sprintf( "%.2f", $order->{quantity} * $line{ecostgste} );
469 $line{totalgsti} = sprintf( "%.2f", $order->{quantity} * $line{ecostgsti} );
472 if ( $line{uncertainprice} ) {
473 $line{rrpgste} .= ' (Uncertain)';
475 if ( $line{'title'} ) {
476 my $volume = $order->{'volume'};
477 my $seriestitle = $order->{'seriestitle'};
478 $line{'title'} .= " / $seriestitle" if $seriestitle;
479 $line{'title'} .= " / $volume" if $volume;
480 } else {
481 $line{'title'} = "Deleted bibliographic notice, can't find title.";
484 my $biblionumber = $order->{'biblionumber'};
485 my $countbiblio = CountBiblioInOrders($biblionumber);
486 my $ordernumber = $order->{'ordernumber'};
487 my @subscriptions = GetSubscriptionsId ($biblionumber);
488 my $itemcount = GetItemsCount($biblionumber);
489 my $holds = GetHolds ($biblionumber);
490 my @items = GetItemnumbersFromOrder( $ordernumber );
491 my $itemholds;
492 foreach my $item (@items){
493 my $nb = GetItemHolds($biblionumber, $item);
494 if ($nb){
495 $itemholds += $nb;
498 # 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
499 $line{can_del_bib} = 1 if $countbiblio <= 1 && $itemcount == scalar @items && !(@subscriptions) && !($holds);
500 $line{items} = ($itemcount) - (scalar @items);
501 $line{left_item} = 1 if $line{items} >= 1;
502 $line{left_biblio} = 1 if $countbiblio > 1;
503 $line{biblios} = $countbiblio - 1;
504 $line{left_subscription} = 1 if scalar @subscriptions >= 1;
505 $line{subscriptions} = scalar @subscriptions;
506 ($holds >= 1) ? $line{left_holds} = 1 : $line{left_holds} = 0;
507 $line{left_holds_on_order} = 1 if $line{left_holds}==1 && ($line{items} == 0 || $itemholds );
508 $line{holds} = $holds;
509 $line{holds_on_order} = $itemholds?$itemholds:$holds if $line{left_holds_on_order};
512 my $suggestion = GetSuggestionInfoFromBiblionumber($line{biblionumber});
513 $line{suggestionid} = $$suggestion{suggestionid};
514 $line{surnamesuggestedby} = $$suggestion{surnamesuggestedby};
515 $line{firstnamesuggestedby} = $$suggestion{firstnamesuggestedby};
517 foreach my $key (qw(transferred_from transferred_to)) {
518 if ($line{$key}) {
519 my $order = GetOrder($line{$key});
520 my $basket = GetBasket($order->{basketno});
521 my $bookseller = Koha::Acquisition::Bookseller->fetch({ id => $basket->{booksellerid} });
522 $line{$key} = {
523 order => $order,
524 basket => $basket,
525 bookseller => $bookseller,
526 timestamp => $line{$key . '_timestamp'},
531 return \%line;
534 output_html_with_http_headers $query, $cookie, $template->output;