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