Merge branch 'new/bug_4330' 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} and $bib->{itemtype}){
215                     push(@ba_order, $itemtypes->{$bib->{itemtype}}->{description});
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         my $freedeliveryplace;
277         if ( $basketgroupid ) {
278             # Get the selected baskets in the basketgroup to display them
279             my $selecteds = GetBasketsByBasketgroup($basketgroupid);
280             foreach (@{$selecteds}){
281                 $_->{total} = BasketTotal($_->{basketno}, $_);
282             }
283             $template->param(basketgroupid => $basketgroupid,
284                              selectedbaskets => $selecteds);
285
286             # Get general informations about the basket group to prefill the form
287             my $basketgroup = GetBasketgroup($basketgroupid);
288             $template->param(
289                 name            => $basketgroup->{name},
290                 deliverycomment => $basketgroup->{deliverycomment},
291                 freedeliveryplace => $basketgroup->{freedeliveryplace},
292             );
293             $billingplace  = $basketgroup->{billingplace};
294             $deliveryplace = $basketgroup->{deliveryplace};
295             $freedeliveryplace = $basketgroup->{freedeliveryplace};
296         }
297
298         # determine default billing and delivery places depending on librarian homebranch and existing basketgroup data
299         my $borrower = GetMember( ( 'borrowernumber' => $loggedinuser ) );
300         $billingplace  = $billingplace  || $borrower->{'branchcode'};
301         $deliveryplace = $deliveryplace || $borrower->{'branchcode'};
302         
303         my $branches = GetBranches;
304         
305         # Build the combobox to select the billing place
306         my @billingplaceloop;
307         for (sort keys %$branches) {
308             push @billingplaceloop, {
309                 value      => $_,
310                 selected   => $_ eq $billingplace,
311                 branchname => $branches->{$_}->{branchname},
312             };
313         }
314         $template->param( billingplaceloop => \@billingplaceloop );
315         
316         # Build the combobox to select the delivery place
317         my @deliveryplaceloop;
318         for (sort keys %$branches) {
319             push @deliveryplaceloop, {
320                 value      => $_,
321                 selected   => $_ eq $deliveryplace,
322                 branchname => $branches->{$_}->{branchname},
323             };
324         }
325         $template->param( deliveryplaceloop => \@deliveryplaceloop );
326
327         $template->param( booksellerid => $booksellerid );
328     }
329     $template->param(grouping => 1);
330     my $basketgroups = &GetBasketgroups($booksellerid);
331     my $bookseller = &GetBookSellerFromId($booksellerid);
332     my $baskets = &GetBasketsByBookseller($booksellerid);
333
334     displaybasketgroups($basketgroups, $bookseller, $baskets);
335 } elsif ($op eq 'mod_basket') {
336 #we want to modify an individual basket's group
337   my $basketno=$input->param('basketno');
338   my $basketgroupid=$input->param('basketgroupid');
339   ModBasket( { basketno => $basketno,
340                          basketgroupid => $basketgroupid } );
341   print $input->redirect("basket.pl?basketno=" . $basketno);
342 } elsif ($op eq 'validate') {
343     if(! $booksellerid){
344         $template->param( booksellererror => 1);
345     } else {
346         $template->param( booksellerid => $booksellerid );
347     }
348     my $baskets = parseinputbaskets($booksellerid);
349     my ($basketgroups, $newbasketgroups) = parseinputbasketgroups($booksellerid, $baskets);
350     foreach my $nbgid (keys %$newbasketgroups){
351 #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
352         my $bgid = NewBasketgroup($newbasketgroups->{$nbgid});
353         ${$newbasketgroups->{$nbgid}}->{'id'} = $bgid;
354         ${$newbasketgroups->{$nbgid}}->{'oldid'} = $nbgid;
355     }
356     foreach my $basket (@$baskets){
357 #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.
358         if ( $basket->{'basketgroupid'} && $newbasketgroups->{$basket->{'basketgroupid'}} ){
359             $basket->{'basketgroupid'} = ${$newbasketgroups->{$basket->{'basketgroupid'}}}->{'id'};
360         }
361         ModBasket($basket);
362     }
363     foreach my $basketgroup (@$basketgroups){
364         if(! $basketgroup->{'id'}){
365             foreach my $basket (@{$basketgroup->{'baskets'}}){
366                 if($input->param('basket'.$basket->{'basketno'}.'changed')){
367                     ModBasket($basket);
368                 }
369             }
370         } elsif ($input->param('basketgroup-'.$basketgroup->{'id'}.'-changed')){
371             ModBasketgroup($basketgroup);
372         }
373     }
374     $basketgroups = &GetBasketgroups($booksellerid);
375     my $bookseller = &GetBookSellerFromId($booksellerid);
376     $baskets = &GetBasketsByBookseller($booksellerid);
377
378     displaybasketgroups($basketgroups, $bookseller, $baskets);
379 } elsif ( $op eq 'closeandprint') {
380     my $basketgroupid = $input->param('basketgroupid');
381     
382     CloseBasketgroup($basketgroupid);
383     
384     printbasketgrouppdf($basketgroupid);
385     exit;
386 }elsif ($op eq 'print'){
387     my $basketgroupid = $input->param('basketgroupid');
388     
389     printbasketgrouppdf($basketgroupid);
390     exit;
391 }elsif( $op eq "delete"){
392     my $basketgroupid = $input->param('basketgroupid');
393     DelBasketgroup($basketgroupid);
394     print $input->redirect('/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=' . $booksellerid);
395     
396 }elsif ( $op eq 'reopen'){
397     my $basketgroupid   = $input->param('basketgroupid');
398     my $booksellerid    = $input->param('booksellerid');
399     
400     ReOpenBasketgroup($basketgroupid);
401         
402     print $input->redirect('/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=' . $booksellerid . '#closed');
403     
404 } elsif ( $op eq 'attachbasket') {
405     
406     # Getting parameters
407     my $basketgroup       = {};
408     my @baskets           = $input->param('basket');
409     my $basketgroupid     = $input->param('basketgroupid');
410     my $basketgroupname   = $input->param('basketgroupname');
411     my $booksellerid      = $input->param('booksellerid');
412     my $billingplace      = $input->param('billingplace');
413     my $deliveryplace     = $input->param('deliveryplace');
414     my $freedeliveryplace = $input->param('freedeliveryplace');
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               freedeliveryplace => $freedeliveryplace,
426               deliverycomment   => $deliverycomment,
427               closed            => $close,
428         };
429         ModBasketgroup($basketgroup);
430         if($close){
431             
432         }
433     }else{
434         $basketgroup = {
435             name              => $basketgroupname,
436             booksellerid      => $booksellerid,
437             basketlist        => \@baskets,
438             deliveryplace     => $deliveryplace,
439             freedeliveryplace => $freedeliveryplace,
440             deliverycomment   => $deliverycomment,
441             closed            => $close,
442         };
443         $basketgroupid = NewBasketgroup($basketgroup);
444     }
445    
446     my $url = '/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=' . $booksellerid;
447     $url .= "&closed=1" if ($input->param("closed")); 
448     print $input->redirect($url);
449     
450 }else{
451     my $basketgroups = &GetBasketgroups($booksellerid);
452     my $bookseller = &GetBookSellerFromId($booksellerid);
453     my $baskets = &GetBasketsByBookseller($booksellerid);
454
455     displaybasketgroups($basketgroups, $bookseller, $baskets);
456 }
457 $template->param(closed => $input->param("closed"));
458 #prolly won't use all these, maybe just use print, the rest can be done inside validate
459 output_html_with_http_headers $input, $cookie, $template->output;