Merge remote-tracking branch 'origin/new/bug_8130'
[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::Bookseller qw( GetBookSellerFromId);
32 use C4::Debug;
33 use C4::Biblio;
34 use C4::Members qw/GetMember/;  #needed for permissions checking for changing basketgroup of a basket
35 use C4::Items;
36 use C4::Suggestions;
37 use Date::Calc qw/Add_Delta_Days/;
38
39 =head1 NAME
40
41 basket.pl
42
43 =head1 DESCRIPTION
44
45  This script display all informations about basket for the supplier given
46  on input arg.  Moreover, it allows us to add a new order for this supplier from
47  an existing record, a suggestion or a new record.
48
49 =head1 CGI PARAMETERS
50
51 =over 4
52
53 =item $basketno
54
55 The basket number.
56
57 =item booksellerid
58
59 the supplier this script have to display the basket.
60
61 =item order
62
63 =back
64
65 =cut
66
67 my $query        = new CGI;
68 my $basketno     = $query->param('basketno');
69 my $booksellerid = $query->param('booksellerid');
70
71 my ( $template, $loggedinuser, $cookie, $userflags ) = get_template_and_user(
72     {
73         template_name   => "acqui/basket.tmpl",
74         query           => $query,
75         type            => "intranet",
76         authnotrequired => 0,
77         flagsrequired   => { acquisition => 'order_manage' },
78         debug           => 1,
79     }
80 );
81
82 my $basket = GetBasket($basketno);
83
84 # FIXME : what about the "discount" percentage?
85 # FIXME : the query->param('booksellerid') below is probably useless. The bookseller is always known from the basket
86 # if no booksellerid in parameter, get it from basket
87 # warn "=>".$basket->{booksellerid};
88 $booksellerid = $basket->{booksellerid} unless $booksellerid;
89 my ($bookseller) = GetBookSellerFromId($booksellerid);
90 my $op = $query->param('op');
91 if (!defined $op) {
92     $op = q{};
93 }
94
95 my $confirm_pref= C4::Context->preference("BasketConfirmations") || '1';
96 $template->param( skip_confirm_reopen => 1) if $confirm_pref eq '2';
97
98 if ( $op eq 'delete_confirm' ) {
99     my $basketno = $query->param('basketno');
100     DelBasket($basketno);
101     $template->param( delete_confirmed => 1 );
102 } elsif ( !$bookseller ) {
103     $template->param( NO_BOOKSELLER => 1 );
104 } elsif ( $op eq 'del_basket') {
105     $template->param( delete_confirm => 1 );
106     if ( C4::Context->preference("IndependantBranches") ) {
107         my $userenv = C4::Context->userenv;
108         unless ( $userenv->{flags} == 1 ) {
109             my $validtest = ( $basket->{creationdate} eq '' )
110               || ( $userenv->{branch} eq $basket->{branch} )
111               || ( $userenv->{branch} eq '' )
112               || ( $basket->{branch}  eq '' );
113             unless ($validtest) {
114                 print $query->redirect("../mainpage.pl");
115                 exit 1;
116             }
117         }
118     }
119     $basket->{creationdate} = ""            unless ( $basket->{creationdate} );
120     $basket->{authorisedby} = $loggedinuser unless ( $basket->{authorisedby} );
121     my $contract = &GetContract($basket->{contractnumber});
122     $template->param(
123         basketno             => $basketno,
124         basketname           => $basket->{'basketname'},
125         basketnote           => $basket->{note},
126         basketbooksellernote => $basket->{booksellernote},
127         basketcontractno     => $basket->{contractnumber},
128         basketcontractname   => $contract->{contractname},
129         creationdate         => $basket->{creationdate},
130         authorisedby         => $basket->{authorisedby},
131         authorisedbyname     => $basket->{authorisedbyname},
132         closedate            => $basket->{closedate},
133         active               => $bookseller->{'active'},
134         booksellerid         => $bookseller->{'id'},
135         name                 => $bookseller->{'name'},
136         address1             => $bookseller->{'address1'},
137         address2             => $bookseller->{'address2'},
138         address3             => $bookseller->{'address3'},
139         address4             => $bookseller->{'address4'},
140       );
141 } elsif ($op eq 'attachbasket' && $template->{'VARS'}->{'CAN_user_acquisition_group_manage'} == 1) {
142       print $query->redirect('/cgi-bin/koha/acqui/basketgroup.pl?basketno=' . $basket->{'basketno'} . '&op=attachbasket&booksellerid=' . $booksellerid);
143     # check if we have to "close" a basket before building page
144 } elsif ($op eq 'export') {
145     print $query->header(
146         -type       => 'text/csv',
147         -attachment => 'basket' . $basket->{'basketno'} . '.csv',
148     );
149     print GetBasketAsCSV($query->param('basketno'));
150     exit;
151 } elsif ($op eq 'close') {
152     my $confirm = $query->param('confirm') || $confirm_pref eq '2';
153     if ($confirm) {
154         my $basketno = $query->param('basketno');
155         my $booksellerid = $query->param('booksellerid');
156         $basketno =~ /^\d+$/ and CloseBasket($basketno);
157         # if requested, create basket group, close it and attach the basket
158         if ($query->param('createbasketgroup')) {
159             my $basketgroupid = NewBasketgroup( { name => $basket->{basketname},
160                             booksellerid => $booksellerid,
161                             closed => 1,
162                             });
163             ModBasket( { basketno => $basketno,
164                          basketgroupid => $basketgroupid } );
165             print $query->redirect('/cgi-bin/koha/acqui/basketgroup.pl?booksellerid='.$booksellerid.'&closed=1');
166         } else {
167             print $query->redirect('/cgi-bin/koha/acqui/booksellers.pl?booksellerid=' . $booksellerid);
168         }
169         exit;
170     } else {
171     $template->param(confirm_close => "1",
172             booksellerid    => $booksellerid,
173             basketno        => $basket->{'basketno'},
174                 basketname      => $basket->{'basketname'},
175             basketgroupname => $basket->{'basketname'});
176         
177     }
178 } elsif ($op eq 'reopen') {
179     my $basket;
180     $basket->{basketno} = $query->param('basketno');
181     $basket->{closedate} = undef;
182     ModBasket($basket);
183     print $query->redirect('/cgi-bin/koha/acqui/basket.pl?basketno='.$basket->{'basketno'})
184 } else {
185     # get librarian branch...
186     if ( C4::Context->preference("IndependantBranches") ) {
187         my $userenv = C4::Context->userenv;
188         unless ( $userenv->{flags} == 1 ) {
189             my $validtest = ( $basket->{creationdate} eq '' )
190               || ( $userenv->{branch} eq $basket->{branch} )
191               || ( $userenv->{branch} eq '' )
192               || ( $basket->{branch}  eq '' );
193             unless ($validtest) {
194                 print $query->redirect("../mainpage.pl");
195                 exit 1;
196             }
197         }
198     }
199 #if the basket is closed,and the user has the permission to edit basketgroups, display a list of basketgroups
200     my $basketgroups;
201     my $member = GetMember(borrowernumber => $loggedinuser);
202     if ($basket->{closedate} && haspermission({ acquisition => 'group_manage'} )) {
203         $basketgroups = GetBasketgroups($basket->{booksellerid});
204         for my $bg ( @{$basketgroups} ) {
205             if ($basket->{basketgroupid} && $basket->{basketgroupid} == $bg->{id}){
206                 $bg->{default} = 1;
207             }
208         }
209         my %emptygroup = ( id   =>   undef,
210                            name =>   "No group");
211         if ( ! $basket->{basketgroupid} ) {
212             $emptygroup{default} = 1;
213             $emptygroup{nogroup} = 1;
214         }
215         unshift( @$basketgroups, \%emptygroup );
216     }
217
218     # if the basket is closed, calculate estimated delivery date
219     my $estimateddeliverydate;
220     if( $basket->{closedate} ) {
221         my ($year, $month, $day) = ($basket->{closedate} =~ /(\d+)-(\d+)-(\d+)/);
222         ($year, $month, $day) = Add_Delta_Days($year, $month, $day, $bookseller->{deliverytime});
223         $estimateddeliverydate = "$year-$month-$day";
224     }
225
226     # if new basket, pre-fill infos
227     $basket->{creationdate} = ""            unless ( $basket->{creationdate} );
228     $basket->{authorisedby} = $loggedinuser unless ( $basket->{authorisedby} );
229     $debug
230       and warn sprintf
231       "loggedinuser: $loggedinuser; creationdate: %s; authorisedby: %s",
232       $basket->{creationdate}, $basket->{authorisedby};
233
234         #to get active currency
235         my $cur = GetCurrency();
236
237
238     my @results = GetOrders( $basketno );
239     
240         my $gist = $bookseller->{gstrate} // C4::Context->preference("gist") // 0;
241         $gist = 0 if $gist == 0.0000;
242         my $discount = $bookseller->{'discount'} / 100;
243     my $total_rrp = 0;      # RRP Total, its value will be assigned to $total_rrp_gsti or $total_rrp_gste depending of $bookseller->{'listincgst'}
244     my $total_rrp_gsti = 0; # RRP Total, GST included
245     my $total_rrp_gste = 0; # RRP Total, GST excluded
246     my $gist_rrp = 0;
247     my $total_rrp_est = 0;
248
249     my $qty_total;
250     my @books_loop;
251     my $suggestion;
252
253     for my $order ( @results ) {
254         my $rrp = $order->{'listprice'} || 0;
255                 my $qty = $order->{'quantity'} || 0;
256         if (!defined $order->{quantityreceived}) {
257             $order->{quantityreceived} = 0;
258         }
259         for ( qw(rrp ecost quantityreceived)) {
260             if (!defined $order->{$_}) {
261                 $order->{$_} = 0;
262             }
263         }
264
265         my $budget = GetBudget(  $order->{'budget_id'} );
266         $rrp = ConvertCurrency( $order->{'currency'}, $rrp );
267
268         $total_rrp += $qty * $order->{'rrp'};
269         my $line_total = $qty * $order->{'ecost'};
270         $total_rrp_est += $qty * $order->{'ecost'};
271                 # FIXME: what about the "actual cost" field?
272         $qty_total += $qty;
273         my %line = %{ $order };
274         my $biblionumber = $order->{'biblionumber'};
275         my $countbiblio = CountBiblioInOrders($biblionumber);
276         my $ordernumber = $order->{'ordernumber'};
277         my @subscriptions = GetSubscriptionsId ($biblionumber);
278         my $itemcount = GetItemsCount($biblionumber);
279         my $holds  = GetHolds ($biblionumber);
280         my @items = GetItemnumbersFromOrder( $ordernumber );
281         my $itemholds;
282         foreach my $item (@items){
283             my $nb = GetItemHolds($biblionumber, $item);
284             if ($nb){
285                 $itemholds += $nb;
286             }
287         }
288         # 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
289         $line{can_del_bib}          = 1 if $countbiblio <= 1 && $itemcount == scalar @items && !(@subscriptions) && !($holds);
290         $line{items}                = ($itemcount) - (scalar @items);
291         $line{left_item}            = 1 if $line{items} >= 1;
292         $line{left_biblio}          = 1 if $countbiblio > 1;
293         $line{biblios}              = $countbiblio - 1;
294         $line{left_subscription}    = 1 if scalar @subscriptions >= 1;
295         $line{subscriptions}        = scalar @subscriptions;
296         ($holds >= 1) ? $line{left_holds} = 1 : $line{left_holds} = 0;
297         $line{left_holds_on_order}  = 1 if $line{left_holds}==1 && ($line{items} == 0 || $itemholds );
298         $line{holds}                = $holds;
299         $line{holds_on_order}       = $itemholds?$itemholds:$holds if $line{left_holds_on_order};
300         $line{order_received}       = ( $qty == $order->{'quantityreceived'} );
301         $line{basketno}             = $basketno;
302         $line{budget_name}          = $budget->{budget_name};
303         $line{rrp}                  = sprintf( "%.2f", $line{'rrp'} );
304         $line{ecost}                = sprintf( "%.2f", $line{'ecost'} );
305         $line{line_total}           = sprintf( "%.2f", $line_total );
306         if ($line{uncertainprice}) {
307             $template->param( uncertainprices => 1 );
308             $line{rrp} .= ' (Uncertain)';
309         }
310         if ($line{'title'}){
311             my $volume = $order->{'volume'};
312             my $seriestitle = $order->{'seriestitle'};
313             $line{'title'} .= " / $seriestitle" if $seriestitle;
314             $line{'title'} .= " / $volume" if $volume;
315         } else {
316             $line{'title'} = "Deleted bibliographic notice, can't find title.";
317         }
318
319         $suggestion = GetSuggestionInfoFromBiblionumber($line{biblionumber});
320         $line{suggestionid}         = $suggestion->{suggestionid};
321         $line{surnamesuggestedby}   = $suggestion->{surnamesuggestedby};
322         $line{firstnamesuggestedby} = $suggestion->{firstnamesuggestedby};
323
324         push @books_loop, \%line;
325     }
326
327 my $total_est_gste;
328     my $total_est_gsti;
329     my $gist_est;
330     if ($gist){                                                    # if we have GST
331        if ( $bookseller->{'listincgst'} ) {                        # if prices already includes GST
332            $total_rrp_gsti = $total_rrp;                           # we know $total_rrp_gsti
333            $total_rrp_gste = $total_rrp_gsti / ( $gist + 1 );      # and can reverse compute other values
334            $gist_rrp       = $total_rrp_gsti - $total_rrp_gste;    #
335            $total_est_gste = $total_rrp_gste - ( $total_rrp_gste * $discount );
336            $total_est_gsti = $total_rrp_est;
337         } else {                                                    # if prices does not include GST
338            $total_rrp_gste = $total_rrp;                           # then we use the common way to compute other values
339            $gist_rrp       = $total_rrp_gste * $gist;              #
340            $total_rrp_gsti = $total_rrp_gste + $gist_rrp;          #
341            $total_est_gste = $total_rrp_est;
342            $total_est_gsti = $total_rrp_gsti - ( $total_rrp_gsti * $discount );
343        }
344        $gist_est = $gist_rrp - ( $gist_rrp * $discount );
345     } else {
346     $total_rrp_gsti = $total_rrp;
347     $total_est_gsti = $total_rrp_est;
348 }
349
350     my $contract = &GetContract($basket->{contractnumber});
351     my @orders = GetOrders($basketno);
352
353     my $borrower= GetMember('borrowernumber' => $loggedinuser);
354     my $budgets = GetBudgetHierarchy;
355     my $has_budgets = 0;
356     foreach my $r (@{$budgets}) {
357         if (!defined $r->{budget_amount} || $r->{budget_amount} == 0) {
358             next;
359         }
360         next unless (CanUserUseBudget($loggedinuser, $r, $userflags));
361
362         $has_budgets = 1;
363         last;
364     }
365
366     my @cancelledorders = GetCancelledOrders($basketno);
367     foreach (@cancelledorders) {
368         $_->{'line_total'} = sprintf("%.2f", $_->{'ecost'} * $_->{'quantity'});
369     }
370
371     $template->param(
372         basketno             => $basketno,
373         basketname           => $basket->{'basketname'},
374         basketnote           => $basket->{note},
375         basketbooksellernote => $basket->{booksellernote},
376         basketcontractno     => $basket->{contractnumber},
377         basketcontractname   => $contract->{contractname},
378         creationdate         => $basket->{creationdate},
379         authorisedby         => $basket->{authorisedby},
380         authorisedbyname     => $basket->{authorisedbyname},
381         closedate            => $basket->{closedate},
382         estimateddeliverydate=> $estimateddeliverydate,
383         active               => $bookseller->{'active'},
384         booksellerid         => $bookseller->{'id'},
385         name                 => $bookseller->{'name'},
386         books_loop           => \@books_loop,
387         cancelledorders_loop => \@cancelledorders,
388         gist_rate            => sprintf( "%.2f", $gist * 100 ) . '%',
389         total_rrp_gste       => sprintf( "%.2f", $total_rrp_gste ),
390         total_est_gste       => sprintf( "%.2f", $total_est_gste ),
391         gist_est             => sprintf( "%.2f", $gist_est ),
392         gist_rrp             => sprintf( "%.2f", $gist_rrp ),        
393         total_rrp_gsti       => sprintf( "%.2f", $total_rrp_gsti ),
394         total_est_gsti       => sprintf( "%.2f", $total_est_gsti ),
395 #        currency             => $bookseller->{'listprice'},
396         currency                => $cur->{'currency'},
397         qty_total            => $qty_total,
398         GST                  => $gist,
399         basketgroups         => $basketgroups,
400         grouped              => $basket->{basketgroupid},
401         unclosable           => @orders ? 0 : 1, 
402         has_budgets          => $has_budgets,
403     );
404 }
405
406 output_html_with_http_headers $query, $cookie, $template->output;