Merge remote-tracking branch 'origin/new/bug_7613'
[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 use Carp;
49
50 use C4::Input;
51 use C4::Auth;
52 use C4::Output;
53 use CGI;
54
55 use C4::Bookseller qw/GetBookSellerFromId/;
56 use C4::Acquisition qw/CloseBasketgroup ReOpenBasketgroup GetOrders GetBasketsByBasketgroup GetBasketsByBookseller ModBasketgroup NewBasketgroup DelBasketgroup GetBasketgroups ModBasket GetBasketgroup GetBasket GetBasketGroupAsCSV/;
57 use C4::Bookseller qw/GetBookSellerFromId/;
58 use C4::Branch qw/GetBranches/;
59 use C4::Members qw/GetMember/;
60
61 our $input=new CGI;
62
63 our ($template, $loggedinuser, $cookie)
64     = get_template_and_user({template_name => "acqui/basketgroup.tmpl",
65                              query => $input,
66                              type => "intranet",
67                              authnotrequired => 0,
68                              flagsrequired => {acquisition => 'group_manage'},
69                              debug => 1,
70                 });
71
72 sub parseinputbaskets {
73     my $booksellerid = shift;
74     my $baskets = &GetBasketsByBookseller($booksellerid);
75     for(my $i=0; $i < scalar @$baskets; ++$i) {
76         if( @$baskets[$i] && ! @$baskets[$i]->{'closedate'} ) {
77             splice(@$baskets, $i, 1);
78             --$i;
79         }
80     }
81     foreach my $basket (@$baskets){
82 #perl DBI uses value "undef" for the mysql "NULL" value, so i need to check everywhere where $basket->{'basketgroupid'} is used for undef ☹
83         $basket->{'basketgroupid'} = $input->param($basket->{'basketno'}.'-group') || undef;
84     }
85     return $baskets;
86 }
87
88
89
90 sub parseinputbasketgroups {
91     my $booksellerid = shift;
92     my $baskets = shift;
93     my $basketgroups = &GetBasketgroups($booksellerid);
94     my $newbasketgroups;
95     foreach my $basket (@$baskets){
96         my $basketgroup;
97         my $i = 0;
98         my $exists;
99         if(! $basket->{'basketgroupid'} || $basket->{'basketgroupid'} == 0){
100             $exists = "true";
101         } else {
102             foreach my $basketgroup (@$basketgroups){
103                 if($basket->{'basketgroupid'} == $basketgroup->{'id'}){
104                     $exists = "true";
105                     push(@{$basketgroup->{'basketlist'}}, $basket->{'basketno'});
106                     last;
107                 }
108             }
109         }
110         if (! $exists){
111 #if the basketgroup doesn't exist yet
112             $basketgroup = $newbasketgroups->{$basket->{'basketgroupid'}} || undef;
113             $basketgroup->{'booksellerid'} = $booksellerid;
114         } else {
115             while($i < scalar @$basketgroups && @$basketgroups[$i]->{'id'} != $basket->{'basketgroupid'}){
116                 ++$i;
117             }
118             $basketgroup = @$basketgroups[$i];
119         }
120         $basketgroup->{'id'}=$basket->{'basketgroupid'};
121         $basketgroup->{'name'}=$input->param('basketgroup-'.$basketgroup->{'id'}.'-name') || "";
122         $basketgroup->{'closed'}= $input->param('basketgroup-'.$basketgroup->{'id'}.'-closed');
123         push(@{$basketgroup->{'basketlist'}}, $basket->{'basketno'});
124         if (! $exists){
125             $newbasketgroups->{$basket->{'basketgroupid'}} = $basketgroup;
126         } else {
127             if($basketgroup->{'id'}){
128                 @$basketgroups[$i] = $basketgroup;
129             }
130         }
131     }
132     return($basketgroups, $newbasketgroups);
133 }
134
135 sub BasketTotal {
136     my $basketno = shift;
137     my $bookseller = shift;
138     my $total = 0;
139     my @orders = GetOrders($basketno);
140     for my $order (@orders){
141         $total = $total + ( $order->{ecost} * $order->{quantity} );
142         if ($bookseller->{invoiceincgst} && ! $bookseller->{listincgst} && ( $bookseller->{gstrate} // C4::Context->preference("gist") )) {
143             my $gst = $bookseller->{gstrate} // C4::Context->preference("gist");
144             $total = $total * ( $gst / 100 +1);
145         }
146     }
147     $total .= $bookseller->{invoiceprice};
148     return $total;
149 }
150
151 #displays all basketgroups and all closed baskets (in their respective groups)
152 sub displaybasketgroups {
153     my $basketgroups = shift;
154     my $bookseller = shift;
155     my $baskets = shift;
156     if (scalar @$basketgroups != 0) {
157         foreach my $basketgroup (@$basketgroups){
158             my $i = 0;
159             while($i < scalar(@$baskets)){
160                 my $basket = @$baskets[$i];
161                 if($basket->{'basketgroupid'} && $basket->{'basketgroupid'} == $basketgroup->{'id'}){
162                     $basket->{total} = BasketTotal($basket->{basketno}, $bookseller);
163                     push(@{$basketgroup->{'baskets'}}, $basket);
164                     splice(@$baskets, $i, 1);
165                     --$i;
166                 }
167                 ++$i;
168             }
169         }
170         $template->param(basketgroups => $basketgroups);
171     }
172     for(my $i=0; $i < scalar @$baskets; ++$i) {
173         if( ! @$baskets[$i]->{'closedate'} ) {
174             splice(@$baskets, $i, 1);
175             --$i;
176         }else{
177             @$baskets[$i]->{total} = BasketTotal(@$baskets[$i]->{basketno}, $bookseller);
178         }
179     }
180     $template->param(baskets => $baskets);
181     $template->param( booksellername => $bookseller ->{'name'});
182 }
183
184 sub printbasketgrouppdf{
185     my ($basketgroupid) = @_;
186     
187     my $pdfformat = C4::Context->preference("OrderPdfFormat");
188     if ($pdfformat eq 'pdfformat::layout3pages' || $pdfformat eq 'pdfformat::layout2pages'){
189         eval {
190         eval "require $pdfformat";
191             import $pdfformat;
192         };
193         if ($@){
194         }
195     }
196     else {
197         print $input->header;  
198         print $input->start_html;  # FIXME Should do a nicer page
199         print "<h1>Invalid PDF Format set</h1>";
200         print "Please go to the systempreferences and set a valid pdfformat";
201         exit;
202     }
203     
204     my $basketgroup = GetBasketgroup($basketgroupid);
205     my $bookseller = GetBookSellerFromId($basketgroup->{'booksellerid'});
206     my $baskets = GetBasketsByBasketgroup($basketgroupid);
207     
208     my %orders;
209     for my $basket (@$baskets) {
210         my @ba_orders;
211         my @ords = &GetOrders($basket->{basketno});
212         for my $ord (@ords) {
213             # ba_order is filled with : 
214             # 0      1        2        3         4            5         6       7      8        9
215             #isbn, itemtype, author, title, publishercode, quantity, listprice ecost discount gstrate
216             my @ba_order;
217             if ( $ord->{biblionumber} && $ord->{quantity}> 0 ) {
218                 eval {
219                     require C4::Biblio;
220                     import C4::Biblio;
221                 };
222                 if ($@){
223                     croak $@;
224                 }
225                 eval {
226                     require C4::Koha;
227                     import C4::Koha;
228                 };
229                 if ($@){
230                     croak $@;
231                 }
232                 my $bib = GetBiblioData($ord->{biblionumber});
233                 my $itemtypes = GetItemTypes();
234                 if($ord->{isbn}){
235                     push(@ba_order, $ord->{isbn});
236                 } else {
237                     push(@ba_order, undef);
238                 }
239                 if ($ord->{itemtype} and $bib->{itemtype}){
240                     push(@ba_order, $itemtypes->{$bib->{itemtype}}->{description});
241                 } else {
242                     push(@ba_order, undef);
243                 }
244 #             } else {
245 #                 push(@ba_order, undef, undef);
246                 for my $key (qw/author title publishercode quantity listprice ecost/) {
247                     push(@ba_order, $ord->{$key});                                                  #Order lines
248                 }
249                 push(@ba_order, $bookseller->{discount});
250                 push(@ba_order, $bookseller->{gstrate}*100 // C4::Context->preference("gist") // 0);
251                 push(@ba_orders, \@ba_order);
252                 # Editor Number
253                 my $en;
254                 my $marcrecord=eval{MARC::Record::new_from_xml( $ord->{marcxml},'UTF-8' )};
255                 if ($marcrecord){
256                     if ( C4::Context->preference("marcflavour") eq 'UNIMARC' ) {
257                         $en = $marcrecord->subfield( '345', "b" );
258                     } elsif ( C4::Context->preference("marcflavour") eq 'MARC21' ) {
259                         $en = $marcrecord->subfield( '037', "a" );
260                     }
261                 }
262                 if($en){
263                     push(@ba_order, $en);
264                 } else {
265                     push(@ba_order, undef);
266                 }
267             }
268         }
269         $orders{$basket->{basketno}}=\@ba_orders;
270     }
271     print $input->header(
272         -type       => 'application/pdf',
273         -attachment => ( $basketgroup->{name} || $basketgroupid ) . '.pdf'
274     );
275     my $pdf = printpdf($basketgroup, $bookseller, $baskets, \%orders, $bookseller->{gstrate} // C4::Context->preference("gist")) || die "pdf generation failed";
276     print $pdf;
277
278 }
279
280 my $op = $input->param('op') || 'display';
281 my $booksellerid = $input->param('booksellerid');
282 $template->param(booksellerid => $booksellerid);
283
284 if ( $op eq "add" ) {
285     if(! $booksellerid){
286         $template->param( ungroupedlist => 1);
287         my @booksellers = GetBookSeller('');
288        for (my $i=0; $i < scalar @booksellers; $i++) {
289             my $baskets = &GetBasketsByBookseller($booksellers[$i]->{id});
290             for (my $j=0; $j < scalar @$baskets; $j++) {
291                 if(! @$baskets[$i]->{closedate} || @$baskets[$i]->{basketgroupid}) {
292                     splice(@$baskets, $j, 1);
293                     $j--;
294                 }
295             }
296             if (scalar @$baskets == 0){
297                 splice(@booksellers, $i, 1);
298                 $i--;
299             }
300         }
301     } else {
302         my $basketgroupid = $input->param('basketgroupid');
303         my $billingplace;
304         my $deliveryplace;
305         my $freedeliveryplace;
306         if ( $basketgroupid ) {
307             # Get the selected baskets in the basketgroup to display them
308             my $selecteds = GetBasketsByBasketgroup($basketgroupid);
309             foreach (@{$selecteds}){
310                 $_->{total} = BasketTotal($_->{basketno}, $_);
311             }
312             $template->param(basketgroupid => $basketgroupid,
313                              selectedbaskets => $selecteds);
314
315             # Get general informations about the basket group to prefill the form
316             my $basketgroup = GetBasketgroup($basketgroupid);
317             $template->param(
318                 name            => $basketgroup->{name},
319                 deliverycomment => $basketgroup->{deliverycomment},
320                 freedeliveryplace => $basketgroup->{freedeliveryplace},
321             );
322             $billingplace  = $basketgroup->{billingplace};
323             $deliveryplace = $basketgroup->{deliveryplace};
324             $freedeliveryplace = $basketgroup->{freedeliveryplace};
325         }
326
327         # determine default billing and delivery places depending on librarian homebranch and existing basketgroup data
328         my $borrower = GetMember( ( 'borrowernumber' => $loggedinuser ) );
329         $billingplace  = $billingplace  || $borrower->{'branchcode'};
330         $deliveryplace = $deliveryplace || $borrower->{'branchcode'};
331         
332         my $branches = GetBranches;
333         
334         # Build the combobox to select the billing place
335         my @billingplaceloop;
336         for (sort keys %$branches) {
337             push @billingplaceloop, {
338                 value      => $_,
339                 selected   => $_ eq $billingplace,
340                 branchname => $branches->{$_}->{branchname},
341             };
342         }
343         $template->param( billingplaceloop => \@billingplaceloop );
344         
345         # Build the combobox to select the delivery place
346         my @deliveryplaceloop;
347         for (sort keys %$branches) {
348             push @deliveryplaceloop, {
349                 value      => $_,
350                 selected   => $_ eq $deliveryplace,
351                 branchname => $branches->{$_}->{branchname},
352             };
353         }
354         $template->param( deliveryplaceloop => \@deliveryplaceloop );
355
356         $template->param( booksellerid => $booksellerid );
357     }
358     $template->param(grouping => 1);
359     my $basketgroups = &GetBasketgroups($booksellerid);
360     my $bookseller = &GetBookSellerFromId($booksellerid);
361     my $baskets = &GetBasketsByBookseller($booksellerid);
362
363     displaybasketgroups($basketgroups, $bookseller, $baskets);
364 } elsif ($op eq 'mod_basket') {
365 #we want to modify an individual basket's group
366   my $basketno=$input->param('basketno');
367   my $basketgroupid=$input->param('basketgroupid');
368   ModBasket( { basketno => $basketno,
369                          basketgroupid => $basketgroupid } );
370   print $input->redirect("basket.pl?basketno=" . $basketno);
371 } elsif ($op eq 'validate') {
372     if(! $booksellerid){
373         $template->param( booksellererror => 1);
374     } else {
375         $template->param( booksellerid => $booksellerid );
376     }
377     my $baskets = parseinputbaskets($booksellerid);
378     my ($basketgroups, $newbasketgroups) = parseinputbasketgroups($booksellerid, $baskets);
379     foreach my $nbgid (keys %$newbasketgroups){
380 #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
381         my $bgid = NewBasketgroup($newbasketgroups->{$nbgid});
382         ${$newbasketgroups->{$nbgid}}->{'id'} = $bgid;
383         ${$newbasketgroups->{$nbgid}}->{'oldid'} = $nbgid;
384     }
385     foreach my $basket (@$baskets){
386 #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.
387         if ( $basket->{'basketgroupid'} && $newbasketgroups->{$basket->{'basketgroupid'}} ){
388             $basket->{'basketgroupid'} = ${$newbasketgroups->{$basket->{'basketgroupid'}}}->{'id'};
389         }
390         ModBasket($basket);
391     }
392     foreach my $basketgroup (@$basketgroups){
393         if(! $basketgroup->{'id'}){
394             foreach my $basket (@{$basketgroup->{'baskets'}}){
395                 if($input->param('basket'.$basket->{'basketno'}.'changed')){
396                     ModBasket($basket);
397                 }
398             }
399         } elsif ($input->param('basketgroup-'.$basketgroup->{'id'}.'-changed')){
400             ModBasketgroup($basketgroup);
401         }
402     }
403     $basketgroups = &GetBasketgroups($booksellerid);
404     my $bookseller = &GetBookSellerFromId($booksellerid);
405     $baskets = &GetBasketsByBookseller($booksellerid);
406
407     displaybasketgroups($basketgroups, $bookseller, $baskets);
408 } elsif ( $op eq 'closeandprint') {
409     my $basketgroupid = $input->param('basketgroupid');
410     
411     CloseBasketgroup($basketgroupid);
412     
413     printbasketgrouppdf($basketgroupid);
414     exit;
415 }elsif ($op eq 'print'){
416     my $basketgroupid = $input->param('basketgroupid');
417     
418     printbasketgrouppdf($basketgroupid);
419     exit;
420 }elsif ( $op eq "export" ) {
421     my $basketgroupid = $input->param('basketgroupid');
422     print $input->header(
423         -type       => 'text/csv',
424         -attachment => 'basketgroup' . $basketgroupid . '.csv',
425     );
426     print GetBasketGroupAsCSV( $basketgroupid, $input );
427     exit;
428 }elsif( $op eq "delete"){
429     my $basketgroupid = $input->param('basketgroupid');
430     DelBasketgroup($basketgroupid);
431     print $input->redirect('/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=' . $booksellerid);
432     
433 }elsif ( $op eq 'reopen'){
434     my $basketgroupid   = $input->param('basketgroupid');
435     my $booksellerid    = $input->param('booksellerid');
436     
437     ReOpenBasketgroup($basketgroupid);
438         
439     print $input->redirect('/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=' . $booksellerid . '#closed');
440     
441 } elsif ( $op eq 'attachbasket') {
442     
443     # Getting parameters
444     my $basketgroup       = {};
445     my @baskets           = $input->param('basket');
446     my $basketgroupid     = $input->param('basketgroupid');
447     my $basketgroupname   = $input->param('basketgroupname');
448     my $booksellerid      = $input->param('booksellerid');
449     my $billingplace      = $input->param('billingplace');
450     my $deliveryplace     = $input->param('deliveryplace');
451     my $freedeliveryplace = $input->param('freedeliveryplace');
452     my $deliverycomment   = $input->param('deliverycomment');
453     my $close             = $input->param('close') ? 1 : 0;
454     # If we got a basketgroupname, we create a basketgroup
455     if ($basketgroupid) {
456         $basketgroup = {
457               name              => $basketgroupname,
458               id                => $basketgroupid,
459               basketlist        => \@baskets,
460               billingplace      => $billingplace,
461               deliveryplace     => $deliveryplace,
462               freedeliveryplace => $freedeliveryplace,
463               deliverycomment   => $deliverycomment,
464               closed            => $close,
465         };
466         ModBasketgroup($basketgroup);
467         if($close){
468             
469         }
470     }else{
471         $basketgroup = {
472             name              => $basketgroupname,
473             booksellerid      => $booksellerid,
474             basketlist        => \@baskets,
475             deliveryplace     => $deliveryplace,
476             freedeliveryplace => $freedeliveryplace,
477             deliverycomment   => $deliverycomment,
478             closed            => $close,
479         };
480         $basketgroupid = NewBasketgroup($basketgroup);
481     }
482    
483     my $url = '/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=' . $booksellerid;
484     $url .= "&closed=1" if ($input->param("closed")); 
485     print $input->redirect($url);
486     
487 }else{
488     my $basketgroups = &GetBasketgroups($booksellerid);
489     my $bookseller = &GetBookSellerFromId($booksellerid);
490     my $baskets = &GetBasketsByBookseller($booksellerid);
491
492     displaybasketgroups($basketgroups, $bookseller, $baskets);
493 }
494 $template->param(closed => $input->param("closed"));
495 #prolly won't use all these, maybe just use print, the rest can be done inside validate
496 output_html_with_http_headers $input, $cookie, $template->output;