Bug 12896: Move the bookseller-related code into Koha::Acquisition::Bookseller
[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 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.
14 #
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.
18 #
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.
22
23 use strict;
24 use warnings;
25 use C4::Auth;
26 use C4::Koha;
27 use C4::Output;
28 use CGI;
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/;
39
40 =head1 NAME
41
42 basket.pl
43
44 =head1 DESCRIPTION
45
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.
49
50 =head1 CGI PARAMETERS
51
52 =over 4
53
54 =item $basketno
55
56 The basket number.
57
58 =item booksellerid
59
60 the supplier this script have to display the basket.
61
62 =item order
63
64 =back
65
66 =cut
67
68 my $query        = new CGI;
69 our $basketno     = $query->param('basketno');
70 my $booksellerid = $query->param('booksellerid');
71
72 my ( $template, $loggedinuser, $cookie, $userflags ) = get_template_and_user(
73     {
74         template_name   => "acqui/basket.tt",
75         query           => $query,
76         type            => "intranet",
77         authnotrequired => 0,
78         flagsrequired   => { acquisition => 'order_manage' },
79         debug           => 1,
80     }
81 );
82
83 my $basket = GetBasket($basketno);
84 $booksellerid = $basket->{booksellerid} unless $booksellerid;
85 my $bookseller = Koha::Acquisition::Bookseller->fetch({ id => $booksellerid });
86
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}
94     );
95     output_html_with_http_headers $query, $cookie, $template->output;
96     exit;
97 }
98
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{};
106 }
107
108 my $confirm_pref= C4::Context->preference("BasketConfirmations") || '1';
109 $template->param( skip_confirm_reopen => 1) if $confirm_pref eq '2';
110
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});
118     }
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};
138             }
139             if ($error) {
140                 push @cannotdelbiblios, {biblionumber=> ($myorder->{biblionumber}),
141                                          title=> $myorder->{'title'},
142                                          author=> $myorder->{'author'},
143                                          othererror=> $error};
144             }
145         }
146         $template->param( cannotdelbiblios => \@cannotdelbiblios );
147     }
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;
165             }
166         }
167     }
168     $basket->{creationdate} = ""            unless ( $basket->{creationdate} );
169     $basket->{authorisedby} = $loggedinuser unless ( $basket->{authorisedby} );
170     my $contract = GetContract({
171         contractnumber => $basket->{contractnumber}
172     });
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'},
193       );
194 } elsif ($op eq 'export') {
195     print $query->header(
196         -type       => 'text/csv',
197         -attachment => 'basket' . $basket->{'basketno'} . '.csv',
198     );
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'};
213             }
214             my $basketgroupid = NewBasketgroup( { name => $basket->{basketname},
215                             booksellerid => $booksellerid,
216                             deliveryplace => $branchcode,
217                             billingplace => $branchcode,
218                             closed => 1,
219                             });
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);
225         }
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'},
234     );
235     }
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
251     });
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;
267             }
268         }
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,
274             };
275         }
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};
288             }
289             push @branches_loop, {
290                 branchcode => $branch,
291                 branchname => $branches->{$branch}->{branchname},
292                 selected => $selected
293             };
294         }
295     }
296
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;
306             }
307         }
308     }
309
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";
316     }
317
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};
325
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;
331     }
332
333     #to get active currency
334     my $cur = GetCurrency();
335
336
337     my @results = GetOrders( $basketno );
338     my @books_loop;
339
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 );
350         }
351
352         push @books_loop, $line;
353
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};
363     }
364
365     push @book_foot_loop, map {$_} values %foot;
366
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;
373     }
374
375     my $contract = GetContract({
376         contractnumber => $basket->{contractnumber}
377     });
378     my @orders = GetOrders($basketno);
379
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} );
384     }
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;
391         }
392         next unless (CanUserUseBudget($loggedinuser, $r, $userflags));
393
394         $has_budgets = 1;
395         last;
396     }
397
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,
433     );
434 }
435
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;
442     }
443     my $budget = GetBudget( $order->{'budget_id'} );
444
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} );
470     }
471
472     if ( $line{uncertainprice} ) {
473         $line{rrpgste} .= ' (Uncertain)';
474     }
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.";
482     }
483
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;
496         }
497     }
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};
510
511
512     my $suggestion   = GetSuggestionInfoFromBiblionumber($line{biblionumber});
513     $line{suggestionid}         = $$suggestion{suggestionid};
514     $line{surnamesuggestedby}   = $$suggestion{surnamesuggestedby};
515     $line{firstnamesuggestedby} = $$suggestion{firstnamesuggestedby};
516
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'},
527             };
528         }
529     }
530
531     return \%line;
532 }
533
534 output_html_with_http_headers $query, $cookie, $template->output;