Merge remote branch 'kc/new/bug_5327' into kcmaster
[koha.git] / acqui / basketgroup.pl
1 #!/usr/bin/perl
2
3 #script to group (closed) baskets into basket groups for easier order management
4 #written by john.soros@biblibre.com 01/10/2008
5
6 # Copyright 2008 - 2009 BibLibre SARL
7 # Parts Copyright Catalyst 2010
8 #
9 # This file is part of Koha.
10 #
11 # Koha is free software; you can redistribute it and/or modify it under the
12 # terms of the GNU General Public License as published by the Free Software
13 # Foundation; either version 2 of the License, or (at your option) any later
14 # version.
15 #
16 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
17 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
18 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
19 #
20 # You should have received a copy of the GNU General Public License along
21 # with Koha; if not, write to the Free Software Foundation, Inc.,
22 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23
24
25 =head1 NAME
26
27 basketgroup.pl
28
29 =head1 DESCRIPTION
30
31  This script lets the user group (closed) baskets into basket groups for easier order management. Note that the grouped baskets have to be from the same bookseller and
32  have to be closed.
33
34 =head1 CGI PARAMETERS
35
36 =over 4
37
38 =item $booksellerid
39
40 The bookseller who we want to display the baskets (and basketgroups) of.
41
42 =back
43
44 =cut
45
46 use strict;
47 use warnings;
48
49 use C4::Input;
50 use C4::Auth;
51 use C4::Output;
52 use CGI;
53
54 use C4::Bookseller qw/GetBookSellerFromId/;
55 use C4::Acquisition qw/CloseBasketgroup ReOpenBasketgroup GetOrders GetBasketsByBasketgroup GetBasketsByBookseller ModBasketgroup NewBasketgroup DelBasketgroup GetBasketgroups ModBasket GetBasketgroup GetBasket/;
56 use C4::Bookseller qw/GetBookSellerFromId/;
57 use C4::Branch qw/GetBranches/;
58 use C4::Members qw/GetMember/;
59
60 my $input=new CGI;
61
62 my ($template, $loggedinuser, $cookie)
63     = get_template_and_user({template_name => "acqui/basketgroup.tmpl",
64                              query => $input,
65                              type => "intranet",
66                              authnotrequired => 0,
67                              flagsrequired => {acquisition => 'group_manage'},
68                              debug => 1,
69                 });
70
71 sub parseinputbaskets {
72     my $booksellerid = shift;
73     my $baskets = &GetBasketsByBookseller($booksellerid);
74     for(my $i=0; $i < scalar @$baskets; ++$i) {
75         if( @$baskets[$i] && ! @$baskets[$i]->{'closedate'} ) {
76             splice(@$baskets, $i, 1);
77             --$i;
78         }
79     }
80     foreach my $basket (@$baskets){
81 #perl DBI uses value "undef" for the mysql "NULL" value, so i need to check everywhere where $basket->{'basketgroupid'} is used for undef ☹
82         $basket->{'basketgroupid'} = $input->param($basket->{'basketno'}.'-group') || undef;
83     }
84     return $baskets;
85 }
86
87
88
89 sub parseinputbasketgroups {
90     my $booksellerid = shift;
91     my $baskets = shift;
92     my $basketgroups = &GetBasketgroups($booksellerid);
93     my $newbasketgroups;
94     foreach my $basket (@$baskets){
95         my $basketgroup;
96         my $i = 0;
97         my $exists;
98         if(! $basket->{'basketgroupid'} || $basket->{'basketgroupid'} == 0){
99             $exists = "true";
100         } else {
101             foreach my $basketgroup (@$basketgroups){
102                 if($basket->{'basketgroupid'} == $basketgroup->{'id'}){
103                     $exists = "true";
104                     push(@{$basketgroup->{'basketlist'}}, $basket->{'basketno'});
105                     last;
106                 }
107             }
108         }
109         if (! $exists){
110 #if the basketgroup doesn't exist yet
111             $basketgroup = $newbasketgroups->{$basket->{'basketgroupid'}} || undef;
112             $basketgroup->{'booksellerid'} = $booksellerid;
113         } else {
114             while($i < scalar @$basketgroups && @$basketgroups[$i]->{'id'} != $basket->{'basketgroupid'}){
115                 ++$i;
116             }
117             $basketgroup = @$basketgroups[$i];
118         }
119         $basketgroup->{'id'}=$basket->{'basketgroupid'};
120         $basketgroup->{'name'}=$input->param('basketgroup-'.$basketgroup->{'id'}.'-name') || "";
121         $basketgroup->{'closed'}= $input->param('basketgroup-'.$basketgroup->{'id'}.'-closed');
122         push(@{$basketgroup->{'basketlist'}}, $basket->{'basketno'});
123         if (! $exists){
124             $newbasketgroups->{$basket->{'basketgroupid'}} = $basketgroup;
125         } else {
126             if($basketgroup->{'id'}){
127                 @$basketgroups[$i] = $basketgroup;
128             }
129         }
130     }
131     return($basketgroups, $newbasketgroups);
132 }
133
134 sub BasketTotal {
135     my $basketno = shift;
136     my $bookseller = shift;
137     my $total = 0;
138     my @orders = GetOrders($basketno);
139     for my $order (@orders){
140         $total = $total + ( $order->{ecost} * $order->{quantity} );
141         if ($bookseller->{invoiceincgst} && ! $bookseller->{listincgst} && ( $bookseller->{gstrate} // C4::Context->preference("gist") )) {
142             my $gst = $bookseller->{gstrate} // C4::Context->preference("gist");
143             $total = $total * ( $gst / 100 +1);
144         }
145     }
146     $total .= $bookseller->{invoiceprice};
147     return $total;
148 }
149
150 #displays all basketgroups and all closed baskets (in their respective groups)
151 sub displaybasketgroups {
152     my $basketgroups = shift;
153     my $bookseller = shift;
154     my $baskets = shift;
155     if (scalar @$basketgroups != 0) {
156         foreach my $basketgroup (@$basketgroups){
157             my $i = 0;
158             while($i < scalar(@$baskets)){
159                 my $basket = @$baskets[$i];
160                 if($basket->{'basketgroupid'} && $basket->{'basketgroupid'} == $basketgroup->{'id'}){
161                     $basket->{total} = BasketTotal($basket->{basketno}, $bookseller);
162                     push(@{$basketgroup->{'baskets'}}, $basket);
163                     splice(@$baskets, $i, 1);
164                     --$i;
165                 }
166                 ++$i;
167             }
168         }
169         $template->param(basketgroups => $basketgroups);
170     }
171     for(my $i=0; $i < scalar @$baskets; ++$i) {
172         if( ! @$baskets[$i]->{'closedate'} ) {
173             splice(@$baskets, $i, 1);
174             --$i;
175         }else{
176             @$baskets[$i]->{total} = BasketTotal(@$baskets[$i]->{basketno}, $bookseller);
177         }
178     }
179     $template->param(baskets => $baskets);
180     $template->param( booksellername => $bookseller ->{'name'});
181 }
182
183 sub printbasketgrouppdf{
184     my ($basketgroupid) = @_;
185     
186     my $pdfformat = C4::Context->preference("OrderPdfFormat");
187     eval "use $pdfformat";
188     # FIXME consider what would happen if $pdfformat does not
189     # contain the name of a valid Perl module.
190     
191     my $basketgroup = GetBasketgroup($basketgroupid);
192     my $bookseller = GetBookSellerFromId($basketgroup->{'booksellerid'});
193     my $baskets = GetBasketsByBasketgroup($basketgroupid);
194     
195     my %orders;
196     for my $basket (@$baskets) {
197         my @ba_orders;
198         my @ords = &GetOrders($basket->{basketno});
199         for my $ord (@ords) {
200             # ba_order is filled with : 
201             # 0      1        2        3         4            5         6       7      8        9
202             #isbn, itemtype, author, title, publishercode, quantity, listprice ecost discount gstrate
203             my @ba_order;
204             if ( $ord->{biblionumber} && $ord->{quantity}> 0 ) {
205                 eval "use C4::Biblio";
206                 eval "use C4::Koha";
207                 my $bib = GetBiblioData($ord->{biblionumber});
208                 my $itemtypes = GetItemTypes();
209                 if($ord->{isbn}){
210                     push(@ba_order, $ord->{isbn});
211                 } else {
212                     push(@ba_order, undef);
213                 }
214                 if ($ord->{itemtype}){
215                     push(@ba_order, $itemtypes->{$bib->{itemtype}}->{description}) if $bib->{itemtype};
216                 } else {
217                     push(@ba_order, undef);
218                 }
219 #             } else {
220 #                 push(@ba_order, undef, undef);
221                 for my $key (qw/author title publishercode quantity listprice ecost/) {
222                     push(@ba_order, $ord->{$key});                                                  #Order lines
223                 }
224                 push(@ba_order, $bookseller->{discount});
225                 push(@ba_order, $bookseller->{gstrate}*100 // C4::Context->preference("gist") // 0);
226                 push(@ba_orders, \@ba_order);
227                 # Editor Number
228                 my $en;
229                 if (C4::Context->preference("marcflavour") eq 'UNIMARC') {
230                     $en = MARC::Record::new_from_xml($ord->{marcxml},'UTF-8')->subfield('345',"b");
231                 } elsif (C4::Context->preference("marcflavour") eq 'MARC21') {
232                     $en = MARC::Record::new_from_xml($ord->{marcxml},'UTF-8')->subfield('037',"a");
233                 }
234                 if($en){
235                     push(@ba_order, $en);
236                 } else {
237                     push(@ba_order, undef);
238                 }
239             }
240         }
241         $orders{$basket->{basketno}}=\@ba_orders;
242     }
243     print $input->header(
244         -type       => 'application/pdf',
245         -attachment => ( $basketgroup->{name} || $basketgroupid ) . '.pdf'
246     );
247     my $pdf = printpdf($basketgroup, $bookseller, $baskets, \%orders, $bookseller->{gstrate} // C4::Context->preference("gist")) || die "pdf generation failed";
248     print $pdf;
249 }
250
251 my $op = $input->param('op');
252 my $booksellerid = $input->param('booksellerid');
253 $template->param(booksellerid => $booksellerid);
254
255 if ( $op eq "add" ) {
256     if(! $booksellerid){
257         $template->param( ungroupedlist => 1);
258         my @booksellers = GetBookSeller('');
259        for (my $i=0; $i < scalar @booksellers; $i++) {
260             my $baskets = &GetBasketsByBookseller($booksellers[$i]->{id});
261             for (my $j=0; $j < scalar @$baskets; $j++) {
262                 if(! @$baskets[$i]->{closedate} || @$baskets[$i]->{basketgroupid}) {
263                     splice(@$baskets, $j, 1);
264                     $j--;
265                 }
266             }
267             if (scalar @$baskets == 0){
268                 splice(@booksellers, $i, 1);
269                 $i--;
270             }
271         }
272     } else {
273         my $basketgroupid = $input->param('basketgroupid');
274         my $billingplace;
275         my $deliveryplace;
276         if ( $basketgroupid ) {
277             # Get the selected baskets in the basketgroup to display them
278             my $selecteds = GetBasketsByBasketgroup($basketgroupid);
279             foreach (@{$selecteds}){
280                 $_->{total} = BasketTotal($_->{basketno}, $_);
281             }
282             $template->param(basketgroupid => $basketgroupid,
283                              selectedbaskets => $selecteds);
284
285             # Get general informations about the basket group to prefill the form
286             my $basketgroup = GetBasketgroup($basketgroupid);
287             $template->param(
288                 name            => $basketgroup->{name},
289                 deliverycomment => $basketgroup->{deliverycomment},
290             );
291             $billingplace  = $basketgroup->{billingplace};
292             $deliveryplace = $basketgroup->{deliveryplace};
293         }
294
295         # determine default billing and delivery places depending on librarian homebranch and existing basketgroup data
296         my $borrower = GetMember( ( 'borrowernumber' => $loggedinuser ) );
297         $billingplace  = $billingplace  || $borrower->{'branchcode'};
298         $deliveryplace = $deliveryplace || $borrower->{'branchcode'};
299         
300         my $branches = GetBranches;
301         
302         # Build the combobox to select the billing place
303         my @billingplaceloop;
304         for (sort keys %$branches) {
305             my $selected = 1 if $_ eq $billingplace;
306             my %row = (
307                 value      => $_,
308                 selected   => $selected,
309                 branchname => $branches->{$_}->{branchname},
310             );
311             push @billingplaceloop, \%row;
312         }
313         $template->param( billingplaceloop => \@billingplaceloop );
314         
315         # Build the combobox to select the delivery place
316         my @deliveryplaceloop;
317         for (sort keys %$branches) {
318             my $selected = 1 if $_ eq $deliveryplace;
319             my %row = (
320                 value      => $_,
321                 selected   => $selected,
322                 branchname => $branches->{$_}->{branchname},
323             );
324             push @deliveryplaceloop, \%row;
325         }
326         $template->param( deliveryplaceloop => \@deliveryplaceloop );
327
328         $template->param( booksellerid => $booksellerid );
329     }
330     $template->param(grouping => 1);
331     my $basketgroups = &GetBasketgroups($booksellerid);
332     my $bookseller = &GetBookSellerFromId($booksellerid);
333     my $baskets = &GetBasketsByBookseller($booksellerid);
334
335     displaybasketgroups($basketgroups, $bookseller, $baskets);
336 } elsif ($op eq 'mod_basket') {
337 #we want to modify an individual basket's group
338   my $basketno=$input->param('basketno');
339   my $basketgroupid=$input->param('basketgroupid');
340   ModBasket( { basketno => $basketno,
341                          basketgroupid => $basketgroupid } );
342   print $input->redirect("basket.pl?basketno=" . $basketno);
343 } elsif ($op eq 'validate') {
344     if(! $booksellerid){
345         $template->param( booksellererror => 1);
346     } else {
347         $template->param( booksellerid => $booksellerid );
348     }
349     my $baskets = parseinputbaskets($booksellerid);
350     my ($basketgroups, $newbasketgroups) = parseinputbasketgroups($booksellerid, $baskets);
351     foreach my $nbgid (keys %$newbasketgroups){
352 #javascript just picks an ID that's higher than anything else, the ID might not be correct..chenge it and change all the basket's basketgroupid as well
353         my $bgid = NewBasketgroup($newbasketgroups->{$nbgid});
354         ${$newbasketgroups->{$nbgid}}->{'id'} = $bgid;
355         ${$newbasketgroups->{$nbgid}}->{'oldid'} = $nbgid;
356     }
357     foreach my $basket (@$baskets){
358 #if the basket was added to a new basketgroup, first change the groupid to the groupid of the basket in mysql, because it contains the id from javascript otherwise.
359         if ( $basket->{'basketgroupid'} && $newbasketgroups->{$basket->{'basketgroupid'}} ){
360             $basket->{'basketgroupid'} = ${$newbasketgroups->{$basket->{'basketgroupid'}}}->{'id'};
361         }
362         ModBasket($basket);
363     }
364     foreach my $basketgroup (@$basketgroups){
365         if(! $basketgroup->{'id'}){
366             foreach my $basket (@{$basketgroup->{'baskets'}}){
367                 if($input->param('basket'.$basket->{'basketno'}.'changed')){
368                     ModBasket($basket);
369                 }
370             }
371         } elsif ($input->param('basketgroup-'.$basketgroup->{'id'}.'-changed')){
372             ModBasketgroup($basketgroup);
373         }
374     }
375     $basketgroups = &GetBasketgroups($booksellerid);
376     my $bookseller = &GetBookSellerFromId($booksellerid);
377     $baskets = &GetBasketsByBookseller($booksellerid);
378
379     displaybasketgroups($basketgroups, $bookseller, $baskets);
380 } elsif ( $op eq 'closeandprint') {
381     my $basketgroupid = $input->param('basketgroupid');
382     
383     CloseBasketgroup($basketgroupid);
384     
385     printbasketgrouppdf($basketgroupid);
386     exit;
387 }elsif ($op eq 'print'){
388     my $basketgroupid = $input->param('basketgroupid');
389     
390     printbasketgrouppdf($basketgroupid);
391     exit;
392 }elsif( $op eq "delete"){
393     my $basketgroupid = $input->param('basketgroupid');
394     DelBasketgroup($basketgroupid);
395     print $input->redirect('/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=' . $booksellerid);
396     
397 }elsif ( $op eq 'reopen'){
398     my $basketgroupid   = $input->param('basketgroupid');
399     my $booksellerid    = $input->param('booksellerid');
400     
401     ReOpenBasketgroup($basketgroupid);
402         
403     print $input->redirect('/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=' . $booksellerid . '#closed');
404     
405 } elsif ( $op eq 'attachbasket') {
406     
407     # Getting parameters
408     my $basketgroup = {};
409     my @baskets         = $input->param('basket');
410     my $basketgroupid   = $input->param('basketgroupid');
411     my $basketgroupname = $input->param('basketgroupname');
412     my $booksellerid    = $input->param('booksellerid');
413     my $billingplace    = $input->param('billingplace');
414     my $deliveryplace   = $input->param('deliveryplace');
415     my $deliverycomment = $input->param('deliverycomment');
416     my $close           = $input->param('close') ? 1 : 0;
417     # If we got a basketgroupname, we create a basketgroup
418     if ($basketgroupid) {
419         $basketgroup = {
420               name            => $basketgroupname,
421               id              => $basketgroupid,
422               basketlist      => \@baskets,
423               billingplace    => $billingplace,
424               deliveryplace   => $deliveryplace,
425               deliverycomment => $deliverycomment,
426               closed          => $close,
427         };
428         ModBasketgroup($basketgroup);
429         if($close){
430             
431         }
432     }else{
433         $basketgroup = {
434             name            => $basketgroupname,
435             booksellerid    => $booksellerid,
436             basketlist      => \@baskets,
437             deliveryplace   => $deliveryplace,
438             deliverycomment => $deliverycomment,
439             closed          => $close,
440         };
441         $basketgroupid = NewBasketgroup($basketgroup);
442     }
443    
444     my $url = '/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=' . $booksellerid;
445     $url .= "&closed=1" if ($input->param("closed")); 
446     print $input->redirect($url);
447     
448 }else{
449     my $basketgroups = &GetBasketgroups($booksellerid);
450     my $bookseller = &GetBookSellerFromId($booksellerid);
451     my $baskets = &GetBasketsByBookseller($booksellerid);
452
453     displaybasketgroups($basketgroups, $bookseller, $baskets);
454 }
455 $template->param(closed => $input->param("closed"));
456 #prolly won't use all these, maybe just use print, the rest can be done inside validate
457 output_html_with_http_headers $input, $cookie, $template->output;