Bug 7295: (follow-up) update DBIx::Class schema classes
[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::Bookseller qw( GetBookSellerFromId);
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.tmpl",
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) = GetBookSellerFromId($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     DelBasket($basketno);
114     $template->param( delete_confirmed => 1 );
115 } elsif ( !$bookseller ) {
116     $template->param( NO_BOOKSELLER => 1 );
117 } elsif ( $op eq 'del_basket') {
118     $template->param( delete_confirm => 1 );
119     if ( C4::Context->preference("IndependentBranches") ) {
120         my $userenv = C4::Context->userenv;
121         unless ( $userenv->{flags} == 1 ) {
122             my $validtest = ( $basket->{creationdate} eq '' )
123               || ( $userenv->{branch} eq $basket->{branch} )
124               || ( $userenv->{branch} eq '' )
125               || ( $basket->{branch}  eq '' );
126             unless ($validtest) {
127                 print $query->redirect("../mainpage.pl");
128                 exit 1;
129             }
130         }
131     }
132     $basket->{creationdate} = ""            unless ( $basket->{creationdate} );
133     $basket->{authorisedby} = $loggedinuser unless ( $basket->{authorisedby} );
134     my $contract = &GetContract($basket->{contractnumber});
135     $template->param(
136         basketno             => $basketno,
137         basketname           => $basket->{'basketname'},
138         basketnote           => $basket->{note},
139         basketbooksellernote => $basket->{booksellernote},
140         basketcontractno     => $basket->{contractnumber},
141         basketcontractname   => $contract->{contractname},
142         creationdate         => $basket->{creationdate},
143         authorisedby         => $basket->{authorisedby},
144         authorisedbyname     => $basket->{authorisedbyname},
145         closedate            => $basket->{closedate},
146         deliveryplace        => $basket->{deliveryplace},
147         billingplace         => $basket->{billingplace},
148         active               => $bookseller->{'active'},
149         booksellerid         => $bookseller->{'id'},
150         name                 => $bookseller->{'name'},
151         address1             => $bookseller->{'address1'},
152         address2             => $bookseller->{'address2'},
153         address3             => $bookseller->{'address3'},
154         address4             => $bookseller->{'address4'},
155       );
156 } elsif ($op eq 'attachbasket' && $template->{'VARS'}->{'CAN_user_acquisition_group_manage'} == 1) {
157       print $query->redirect('/cgi-bin/koha/acqui/basketgroup.pl?basketno=' . $basket->{'basketno'} . '&op=attachbasket&booksellerid=' . $booksellerid);
158     # check if we have to "close" a basket before building page
159 } elsif ($op eq 'export') {
160     print $query->header(
161         -type       => 'text/csv',
162         -attachment => 'basket' . $basket->{'basketno'} . '.csv',
163     );
164     print GetBasketAsCSV($query->param('basketno'), $query);
165     exit;
166 } elsif ($op eq 'close') {
167     my $confirm = $query->param('confirm') || $confirm_pref eq '2';
168     if ($confirm) {
169         my $basketno = $query->param('basketno');
170         my $booksellerid = $query->param('booksellerid');
171         $basketno =~ /^\d+$/ and CloseBasket($basketno);
172         # if requested, create basket group, close it and attach the basket
173         if ($query->param('createbasketgroup')) {
174             my $branchcode;
175             if(C4::Context->userenv and C4::Context->userenv->{'branch'}
176               and C4::Context->userenv->{'branch'} ne "NO_LIBRARY_SET") {
177                 $branchcode = C4::Context->userenv->{'branch'};
178             }
179             my $basketgroupid = NewBasketgroup( { name => $basket->{basketname},
180                             booksellerid => $booksellerid,
181                             deliveryplace => $branchcode,
182                             billingplace => $branchcode,
183                             closed => 1,
184                             });
185             ModBasket( { basketno => $basketno,
186                          basketgroupid => $basketgroupid } );
187             print $query->redirect('/cgi-bin/koha/acqui/basketgroup.pl?booksellerid='.$booksellerid.'&closed=1');
188         } else {
189             print $query->redirect('/cgi-bin/koha/acqui/booksellers.pl?booksellerid=' . $booksellerid);
190         }
191         exit;
192     } else {
193     $template->param(
194         confirm_close   => "1",
195         booksellerid    => $booksellerid,
196         basketno        => $basket->{'basketno'},
197         basketname      => $basket->{'basketname'},
198         basketgroupname => $basket->{'basketname'},
199     );
200     }
201 } elsif ($op eq 'reopen') {
202     ReopenBasket($query->param('basketno'));
203     print $query->redirect('/cgi-bin/koha/acqui/basket.pl?basketno='.$basket->{'basketno'})
204 } elsif ( $op eq 'mod_users' ) {
205     my $basketusers_ids = $query->param('basketusers_ids');
206     my @basketusers = split( /:/, $basketusers_ids );
207     ModBasketUsers($basketno, @basketusers);
208     print $query->redirect("/cgi-bin/koha/acqui/basket.pl?basketno=$basketno");
209     exit;
210 } elsif ( $op eq 'mod_branch' ) {
211     my $branch = $query->param('branch');
212     $branch = undef if(defined $branch and $branch eq '');
213     ModBasket({
214         basketno => $basket->{basketno},
215         branch   => $branch
216     });
217     print $query->redirect("/cgi-bin/koha/acqui/basket.pl?basketno=$basketno");
218     exit;
219 } else {
220     my @branches_loop;
221     # get librarian branch...
222     if ( C4::Context->preference("IndependentBranches") ) {
223         my $userenv = C4::Context->userenv;
224         unless ( $userenv->{flags} == 1 ) {
225             my $validtest = ( $basket->{creationdate} eq '' )
226               || ( $userenv->{branch} eq $basket->{branch} )
227               || ( $userenv->{branch} eq '' )
228               || ( $basket->{branch}  eq '' );
229             unless ($validtest) {
230                 print $query->redirect("../mainpage.pl");
231                 exit 1;
232             }
233         }
234         if (!defined $basket->{branch} or $basket->{branch} eq $userenv->{branch}) {
235             push @branches_loop, {
236                 branchcode => $userenv->{branch},
237                 branchname => $userenv->{branchname},
238                 selected => 1,
239             };
240         }
241     } else {
242         # get branches
243         my $branches = C4::Branch::GetBranches;
244         my @branchcodes = sort {
245             $branches->{$a}->{branchname} cmp $branches->{$b}->{branchname}
246         } keys %$branches;
247         foreach my $branch (@branchcodes) {
248             my $selected = 0;
249             if (defined $basket->{branch}) {
250                 $selected = 1 if $branch eq $basket->{branch};
251             } else {
252                 $selected = 1 if $branch eq C4::Context->userenv->{branch};
253             }
254             push @branches_loop, {
255                 branchcode => $branch,
256                 branchname => $branches->{$branch}->{branchname},
257                 selected => $selected
258             };
259         }
260     }
261
262 #if the basket is closed,and the user has the permission to edit basketgroups, display a list of basketgroups
263     my ($basketgroup, $basketgroups);
264     my $staffuser = GetMember(borrowernumber => $loggedinuser);
265     if ($basket->{closedate} && haspermission($staffuser->{userid}, { acquisition => 'group_manage'} )) {
266         $basketgroups = GetBasketgroups($basket->{booksellerid});
267         for my $bg ( @{$basketgroups} ) {
268             if ($basket->{basketgroupid} && $basket->{basketgroupid} == $bg->{id}){
269                 $bg->{default} = 1;
270                 $basketgroup = $bg;
271             }
272         }
273         my %emptygroup = ( id   =>   undef,
274                            name =>   "No group");
275         if ( ! $basket->{basketgroupid} ) {
276             $emptygroup{default} = 1;
277             $emptygroup{nogroup} = 1;
278         }
279         unshift( @$basketgroups, \%emptygroup );
280     }
281
282     # if the basket is closed, calculate estimated delivery date
283     my $estimateddeliverydate;
284     if( $basket->{closedate} ) {
285         my ($year, $month, $day) = ($basket->{closedate} =~ /(\d+)-(\d+)-(\d+)/);
286         ($year, $month, $day) = Add_Delta_Days($year, $month, $day, $bookseller->{deliverytime});
287         $estimateddeliverydate = "$year-$month-$day";
288     }
289
290     # if new basket, pre-fill infos
291     $basket->{creationdate} = ""            unless ( $basket->{creationdate} );
292     $basket->{authorisedby} = $loggedinuser unless ( $basket->{authorisedby} );
293     $debug
294       and warn sprintf
295       "loggedinuser: $loggedinuser; creationdate: %s; authorisedby: %s",
296       $basket->{creationdate}, $basket->{authorisedby};
297
298     my @basketusers_ids = GetBasketUsers($basketno);
299     my @basketusers;
300     foreach my $basketuser_id (@basketusers_ids) {
301         my $basketuser = GetMember(borrowernumber => $basketuser_id);
302         push @basketusers, $basketuser if $basketuser;
303     }
304
305     #to get active currency
306     my $cur = GetCurrency();
307
308
309     my @results = GetOrders( $basketno );
310     my @books_loop;
311
312     my @book_foot_loop;
313     my %foot;
314     my $total_quantity = 0;
315     my $total_gste = 0;
316     my $total_gsti = 0;
317     my $total_gstvalue = 0;
318     for my $order (@results) {
319         my $line = get_order_infos( $order, $bookseller);
320         if ( $line->{uncertainprice} ) {
321             $template->param( uncertainprices => 1 );
322         }
323
324         push @books_loop, $line;
325
326         $foot{$$line{gstgsti}}{gstgsti} = $$line{gstgsti};
327         $foot{$$line{gstgsti}}{gstvalue} += $$line{gstvalue};
328         $total_gstvalue += $$line{gstvalue};
329         $foot{$$line{gstgsti}}{quantity}  += $$line{quantity};
330         $total_quantity += $$line{quantity};
331         $foot{$$line{gstgsti}}{totalgste} += $$line{totalgste};
332         $total_gste += $$line{totalgste};
333         $foot{$$line{gstgsti}}{totalgsti} += $$line{totalgsti};
334         $total_gsti += $$line{totalgsti};
335     }
336
337     push @book_foot_loop, map {$_} values %foot;
338
339     # Get cancelled orders
340     @results = GetCancelledOrders($basketno);
341     my @cancelledorders_loop;
342     for my $order (@results) {
343         my $line = get_order_infos( $order, $bookseller);
344         push @cancelledorders_loop, $line;
345     }
346
347     my $contract = &GetContract($basket->{contractnumber});
348     my @orders = GetOrders($basketno);
349
350     if ($basket->{basketgroupid}){
351         $basketgroup = GetBasketgroup($basket->{basketgroupid});
352         $basketgroup->{deliveryplacename} = C4::Branch::GetBranchName( $basketgroup->{deliveryplace} );
353         $basketgroup->{billingplacename} = C4::Branch::GetBranchName( $basketgroup->{billingplace} );
354     }
355     my $borrower= GetMember('borrowernumber' => $loggedinuser);
356     my $budgets = GetBudgetHierarchy;
357     my $has_budgets = 0;
358     foreach my $r (@{$budgets}) {
359         if (!defined $r->{budget_amount} || $r->{budget_amount} == 0) {
360             next;
361         }
362         next unless (CanUserUseBudget($loggedinuser, $r, $userflags));
363
364         $has_budgets = 1;
365         last;
366     }
367
368     $template->param(
369         basketno             => $basketno,
370         basketname           => $basket->{'basketname'},
371         basketbranchname     => C4::Branch::GetBranchName($basket->{branch}),
372         basketnote           => $basket->{note},
373         basketbooksellernote => $basket->{booksellernote},
374         basketcontractno     => $basket->{contractnumber},
375         basketcontractname   => $contract->{contractname},
376         branches_loop        => \@branches_loop,
377         creationdate         => $basket->{creationdate},
378         authorisedby         => $basket->{authorisedby},
379         authorisedbyname     => $basket->{authorisedbyname},
380         basketusers_ids      => join(':', @basketusers_ids),
381         basketusers          => \@basketusers,
382         closedate            => $basket->{closedate},
383         estimateddeliverydate=> $estimateddeliverydate,
384         deliveryplace        => C4::Branch::GetBranchName( $basket->{deliveryplace} ),
385         billingplace         => C4::Branch::GetBranchName( $basket->{billingplace} ),
386         active               => $bookseller->{'active'},
387         booksellerid         => $bookseller->{'id'},
388         name                 => $bookseller->{'name'},
389         books_loop           => \@books_loop,
390         book_foot_loop       => \@book_foot_loop,
391         cancelledorders_loop => \@cancelledorders_loop,
392         total_quantity       => $total_quantity,
393         total_gste           => sprintf( "%.2f", $total_gste ),
394         total_gsti           => sprintf( "%.2f", $total_gsti ),
395         total_gstvalue       => sprintf( "%.2f", $total_gstvalue ),
396         currency             => $cur->{'currency'},
397         listincgst           => $bookseller->{listincgst},
398         basketgroups         => $basketgroups,
399         basketgroup          => $basketgroup,
400         grouped              => $basket->{basketgroupid},
401         unclosable           => @orders ? 0 : 1, 
402         has_budgets          => $has_budgets,
403     );
404 }
405
406 sub get_order_infos {
407     my $order = shift;
408     my $bookseller = shift;
409     my $qty = $order->{'quantity'} || 0;
410     if ( !defined $order->{quantityreceived} ) {
411         $order->{quantityreceived} = 0;
412     }
413     my $budget = GetBudget( $order->{'budget_id'} );
414
415     my %line = %{ $order };
416     $line{order_received} = ( $qty == $order->{'quantityreceived'} );
417     $line{basketno}       = $basketno;
418     $line{budget_name}    = $budget->{budget_name};
419     $line{rrp} = ConvertCurrency( $order->{'currency'}, $line{rrp} ); # FIXME from comm
420     if ( $bookseller->{'listincgst'} ) {
421         $line{rrpgsti} = sprintf( "%.2f", $line{rrp} );
422         $line{gstgsti} = sprintf( "%.2f", $line{gstrate} * 100 );
423         $line{rrpgste} = sprintf( "%.2f", $line{rrp} / ( 1 + ( $line{gstgsti} / 100 ) ) );
424         $line{gstgste} = sprintf( "%.2f", $line{gstgsti} / ( 1 + ( $line{gstgsti} / 100 ) ) );
425         $line{ecostgsti} = sprintf( "%.2f", $line{ecost} );
426         $line{ecostgste} = sprintf( "%.2f", $line{ecost} / ( 1 + ( $line{gstgsti} / 100 ) ) );
427         $line{gstvalue} = sprintf( "%.2f", ( $line{ecostgsti} - $line{ecostgste} ) * $line{quantity});
428         $line{totalgste} = sprintf( "%.2f", $order->{quantity} * $line{ecostgste} );
429         $line{totalgsti} = sprintf( "%.2f", $order->{quantity} * $line{ecostgsti} );
430     } else {
431         $line{rrpgsti} = sprintf( "%.2f", $line{rrp} * ( 1 + ( $line{gstrate} ) ) );
432         $line{rrpgste} = sprintf( "%.2f", $line{rrp} );
433         $line{gstgsti} = sprintf( "%.2f", $line{gstrate} * 100 );
434         $line{gstgste} = sprintf( "%.2f", $line{gstrate} * 100 );
435         $line{ecostgsti} = sprintf( "%.2f", $line{ecost} * ( 1 + ( $line{gstrate} ) ) );
436         $line{ecostgste} = sprintf( "%.2f", $line{ecost} );
437         $line{gstvalue} = sprintf( "%.2f", ( $line{ecostgsti} - $line{ecostgste} ) * $line{quantity});
438         $line{totalgste} = sprintf( "%.2f", $order->{quantity} * $line{ecostgste} );
439         $line{totalgsti} = sprintf( "%.2f", $order->{quantity} * $line{ecostgsti} );
440     }
441
442     if ( $line{uncertainprice} ) {
443         $line{rrpgste} .= ' (Uncertain)';
444     }
445     if ( $line{'title'} ) {
446         my $volume      = $order->{'volume'};
447         my $seriestitle = $order->{'seriestitle'};
448         $line{'title'} .= " / $seriestitle" if $seriestitle;
449         $line{'title'} .= " / $volume"      if $volume;
450     } else {
451         $line{'title'} = "Deleted bibliographic notice, can't find title.";
452     }
453
454     my $biblionumber = $order->{'biblionumber'};
455     my $countbiblio = CountBiblioInOrders($biblionumber);
456     my $ordernumber = $order->{'ordernumber'};
457     my @subscriptions = GetSubscriptionsId ($biblionumber);
458     my $itemcount = GetItemsCount($biblionumber);
459     my $holds  = GetHolds ($biblionumber);
460     my @items = GetItemnumbersFromOrder( $ordernumber );
461     my $itemholds;
462     foreach my $item (@items){
463         my $nb = GetItemHolds($biblionumber, $item);
464         if ($nb){
465             $itemholds += $nb;
466         }
467     }
468     # 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
469     $line{can_del_bib}          = 1 if $countbiblio <= 1 && $itemcount == scalar @items && !(@subscriptions) && !($holds);
470     $line{items}                = ($itemcount) - (scalar @items);
471     $line{left_item}            = 1 if $line{items} >= 1;
472     $line{left_biblio}          = 1 if $countbiblio > 1;
473     $line{biblios}              = $countbiblio - 1;
474     $line{left_subscription}    = 1 if scalar @subscriptions >= 1;
475     $line{subscriptions}        = scalar @subscriptions;
476     ($holds >= 1) ? $line{left_holds} = 1 : $line{left_holds} = 0;
477     $line{left_holds_on_order}  = 1 if $line{left_holds}==1 && ($line{items} == 0 || $itemholds );
478     $line{holds}                = $holds;
479     $line{holds_on_order}       = $itemholds?$itemholds:$holds if $line{left_holds_on_order};
480
481
482     my $suggestion   = GetSuggestionInfoFromBiblionumber($line{biblionumber});
483     $line{suggestionid}         = $$suggestion{suggestionid};
484     $line{surnamesuggestedby}   = $$suggestion{surnamesuggestedby};
485     $line{firstnamesuggestedby} = $$suggestion{firstnamesuggestedby};
486
487     foreach my $key (qw(transferred_from transferred_to)) {
488         if ($line{$key}) {
489             my $order = GetOrder($line{$key});
490             my $basket = GetBasket($order->{basketno});
491             my $bookseller = GetBookSellerFromId($basket->{booksellerid});
492             $line{$key} = {
493                 order => $order,
494                 basket => $basket,
495                 bookseller => $bookseller,
496                 timestamp => $line{$key . '_timestamp'},
497             };
498         }
499     }
500
501     return \%line;
502 }
503
504 output_html_with_http_headers $query, $cookie, $template->output;