BZ6066 let's the librarian choose the itemtype when ordering
[wip/koha-chris_n.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         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             my $selected = 1 if $_ eq $billingplace;
309             my %row = (
310                 value      => $_,
311                 selected   => $selected,
312                 branchname => $branches->{$_}->{branchname},
313             );
314             push @billingplaceloop, \%row;
315         }
316         $template->param( billingplaceloop => \@billingplaceloop );
317         
318         # Build the combobox to select the delivery place
319         my @deliveryplaceloop;
320         for (sort keys %$branches) {
321             my $selected = 1 if $_ eq $deliveryplace;
322             my %row = (
323                 value      => $_,
324                 selected   => $selected,
325                 branchname => $branches->{$_}->{branchname},
326             );
327             push @deliveryplaceloop, \%row;
328         }
329         $template->param( deliveryplaceloop => \@deliveryplaceloop );
330
331         $template->param( booksellerid => $booksellerid );
332     }
333     $template->param(grouping => 1);
334     my $basketgroups = &GetBasketgroups($booksellerid);
335     my $bookseller = &GetBookSellerFromId($booksellerid);
336     my $baskets = &GetBasketsByBookseller($booksellerid);
337
338     displaybasketgroups($basketgroups, $bookseller, $baskets);
339 } elsif ($op eq 'mod_basket') {
340 #we want to modify an individual basket's group
341   my $basketno=$input->param('basketno');
342   my $basketgroupid=$input->param('basketgroupid');
343   ModBasket( { basketno => $basketno,
344                          basketgroupid => $basketgroupid } );
345   print $input->redirect("basket.pl?basketno=" . $basketno);
346 } elsif ($op eq 'validate') {
347     if(! $booksellerid){
348         $template->param( booksellererror => 1);
349     } else {
350         $template->param( booksellerid => $booksellerid );
351     }
352     my $baskets = parseinputbaskets($booksellerid);
353     my ($basketgroups, $newbasketgroups) = parseinputbasketgroups($booksellerid, $baskets);
354     foreach my $nbgid (keys %$newbasketgroups){
355 #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
356         my $bgid = NewBasketgroup($newbasketgroups->{$nbgid});
357         ${$newbasketgroups->{$nbgid}}->{'id'} = $bgid;
358         ${$newbasketgroups->{$nbgid}}->{'oldid'} = $nbgid;
359     }
360     foreach my $basket (@$baskets){
361 #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.
362         if ( $basket->{'basketgroupid'} && $newbasketgroups->{$basket->{'basketgroupid'}} ){
363             $basket->{'basketgroupid'} = ${$newbasketgroups->{$basket->{'basketgroupid'}}}->{'id'};
364         }
365         ModBasket($basket);
366     }
367     foreach my $basketgroup (@$basketgroups){
368         if(! $basketgroup->{'id'}){
369             foreach my $basket (@{$basketgroup->{'baskets'}}){
370                 if($input->param('basket'.$basket->{'basketno'}.'changed')){
371                     ModBasket($basket);
372                 }
373             }
374         } elsif ($input->param('basketgroup-'.$basketgroup->{'id'}.'-changed')){
375             ModBasketgroup($basketgroup);
376         }
377     }
378     $basketgroups = &GetBasketgroups($booksellerid);
379     my $bookseller = &GetBookSellerFromId($booksellerid);
380     $baskets = &GetBasketsByBookseller($booksellerid);
381
382     displaybasketgroups($basketgroups, $bookseller, $baskets);
383 } elsif ( $op eq 'closeandprint') {
384     my $basketgroupid = $input->param('basketgroupid');
385     
386     CloseBasketgroup($basketgroupid);
387     
388     printbasketgrouppdf($basketgroupid);
389     exit;
390 }elsif ($op eq 'print'){
391     my $basketgroupid = $input->param('basketgroupid');
392     
393     printbasketgrouppdf($basketgroupid);
394     exit;
395 }elsif( $op eq "delete"){
396     my $basketgroupid = $input->param('basketgroupid');
397     DelBasketgroup($basketgroupid);
398     print $input->redirect('/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=' . $booksellerid);
399     
400 }elsif ( $op eq 'reopen'){
401     my $basketgroupid   = $input->param('basketgroupid');
402     my $booksellerid    = $input->param('booksellerid');
403     
404     ReOpenBasketgroup($basketgroupid);
405         
406     print $input->redirect('/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=' . $booksellerid . '#closed');
407     
408 } elsif ( $op eq 'attachbasket') {
409     
410     # Getting parameters
411     my $basketgroup       = {};
412     my @baskets           = $input->param('basket');
413     my $basketgroupid     = $input->param('basketgroupid');
414     my $basketgroupname   = $input->param('basketgroupname');
415     my $booksellerid      = $input->param('booksellerid');
416     my $billingplace      = $input->param('billingplace');
417     my $deliveryplace     = $input->param('deliveryplace');
418     my $freedeliveryplace = $input->param('freedeliveryplace');
419     my $deliverycomment   = $input->param('deliverycomment');
420     my $close             = $input->param('close') ? 1 : 0;
421     # If we got a basketgroupname, we create a basketgroup
422     if ($basketgroupid) {
423         $basketgroup = {
424               name              => $basketgroupname,
425               id                => $basketgroupid,
426               basketlist        => \@baskets,
427               billingplace      => $billingplace,
428               deliveryplace     => $deliveryplace,
429               freedeliveryplace => $freedeliveryplace,
430               deliverycomment   => $deliverycomment,
431               closed            => $close,
432         };
433         ModBasketgroup($basketgroup);
434         if($close){
435             
436         }
437     }else{
438         $basketgroup = {
439             name              => $basketgroupname,
440             booksellerid      => $booksellerid,
441             basketlist        => \@baskets,
442             deliveryplace     => $deliveryplace,
443             freedeliveryplace => $freedeliveryplace,
444             deliverycomment   => $deliverycomment,
445             closed            => $close,
446         };
447         $basketgroupid = NewBasketgroup($basketgroup);
448     }
449    
450     my $url = '/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=' . $booksellerid;
451     $url .= "&closed=1" if ($input->param("closed")); 
452     print $input->redirect($url);
453     
454 }else{
455     my $basketgroups = &GetBasketgroups($booksellerid);
456     my $bookseller = &GetBookSellerFromId($booksellerid);
457     my $baskets = &GetBasketsByBookseller($booksellerid);
458
459     displaybasketgroups($basketgroups, $bookseller, $baskets);
460 }
461 $template->param(closed => $input->param("closed"));
462 #prolly won't use all these, maybe just use print, the rest can be done inside validate
463 output_html_with_http_headers $input, $cookie, $template->output;