Bug 10694: (follow-up) fix various issues
[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 to be printed or exported.
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::Budgets qw/ConvertCurrency/;
57 use C4::Acquisition qw/CloseBasketgroup ReOpenBasketgroup GetOrders GetBasketsByBasketgroup GetBasketsByBookseller ModBasketgroup NewBasketgroup DelBasketgroup GetBasketgroups ModBasket GetBasketgroup GetBasket GetBasketGroupAsCSV/;
58 use C4::Bookseller qw/GetBookSellerFromId/;
59 use C4::Branch qw/GetBranches/;
60 use C4::Members qw/GetMember/;
61
62 our $input=new CGI;
63
64 our ($template, $loggedinuser, $cookie)
65     = get_template_and_user({template_name => "acqui/basketgroup.tmpl",
66                              query => $input,
67                              type => "intranet",
68                              authnotrequired => 0,
69                              flagsrequired => {acquisition => 'group_manage'},
70                              debug => 1,
71                 });
72
73 sub BasketTotal {
74     my $basketno = shift;
75     my $bookseller = shift;
76     my $total = 0;
77     my @orders = GetOrders($basketno);
78     for my $order (@orders){
79         $total = $total + ( $order->{ecost} * $order->{quantity} );
80         if ($bookseller->{invoiceincgst} && ! $bookseller->{listincgst} && ( $bookseller->{gstrate} // C4::Context->preference("gist") )) {
81             my $gst = $bookseller->{gstrate} // C4::Context->preference("gist");
82             $total = $total * ( $gst / 100 +1);
83         }
84     }
85     $total .= " " . ($bookseller->{invoiceprice} // 0);
86     return $total;
87 }
88
89 #displays all basketgroups and all closed baskets (in their respective groups)
90 sub displaybasketgroups {
91     my $basketgroups = shift;
92     my $bookseller = shift;
93     my $baskets = shift;
94     if (scalar @$basketgroups != 0) {
95         foreach my $basketgroup (@$basketgroups){
96             my $i = 0;
97             my $basketsqty = 0;
98             while($i < scalar(@$baskets)){
99                 my $basket = @$baskets[$i];
100                 if($basket->{'basketgroupid'} && $basket->{'basketgroupid'} == $basketgroup->{'id'}){
101                     $basket->{total} = BasketTotal($basket->{basketno}, $bookseller);
102                     push(@{$basketgroup->{'baskets'}}, $basket);
103                     splice(@$baskets, $i, 1);
104                     ++$basketsqty;
105                     --$i;
106                 }
107                 ++$i;
108             }
109             $basketgroup -> {'basketsqty'} = $basketsqty;
110         }
111         $template->param(basketgroups => $basketgroups);
112     }
113     for(my $i=0; $i < scalar @$baskets; ++$i) {
114         if( ! @$baskets[$i]->{'closedate'} ) {
115             splice(@$baskets, $i, 1);
116             --$i;
117         }else{
118             @$baskets[$i]->{total} = BasketTotal(@$baskets[$i]->{basketno}, $bookseller);
119         }
120     }
121     $template->param(baskets => $baskets);
122     $template->param( booksellername => $bookseller ->{'name'});
123 }
124
125 sub printbasketgrouppdf{
126     my ($basketgroupid) = @_;
127     
128     my $pdfformat = C4::Context->preference("OrderPdfFormat");
129     if ($pdfformat eq 'pdfformat::layout3pages' || $pdfformat eq 'pdfformat::layout2pages' || $pdfformat eq 'pdfformat::layout3pagesfr'
130         || $pdfformat eq 'pdfformat::layout2pagesde'){
131         eval {
132         eval "require $pdfformat";
133             import $pdfformat;
134         };
135         if ($@){
136         }
137     }
138     else {
139         print $input->header;  
140         print $input->start_html;  # FIXME Should do a nicer page
141         print "<h1>Invalid PDF Format set</h1>";
142         print "Please go to the systempreferences and set a valid pdfformat";
143         exit;
144     }
145     
146     my $basketgroup = GetBasketgroup($basketgroupid);
147     my $bookseller = GetBookSellerFromId($basketgroup->{'booksellerid'});
148     my $baskets = GetBasketsByBasketgroup($basketgroupid);
149     
150     my %orders;
151     for my $basket (@$baskets) {
152         my @ba_orders;
153         my @ords = &GetOrders($basket->{basketno});
154         for my $ord (@ords) {
155
156             next unless ( $ord->{biblionumber} or $ord->{quantity}> 0 );
157             eval {
158                 require C4::Biblio;
159                 import C4::Biblio;
160             };
161             if ($@){
162                 croak $@;
163             }
164             eval {
165                 require C4::Koha;
166                 import C4::Koha;
167             };
168             if ($@){
169                 croak $@;
170             }
171
172             $ord->{rrp} = ConvertCurrency( $ord->{'currency'}, $ord->{rrp} );
173             if ( $bookseller->{'listincgst'} ) {
174                 $ord->{rrpgsti} = sprintf( "%.2f", $ord->{rrp} );
175                 $ord->{gstgsti} = sprintf( "%.2f", $ord->{gstrate} * 100 );
176                 $ord->{rrpgste} = sprintf( "%.2f", $ord->{rrp} / ( 1 + ( $ord->{gstgsti} / 100 ) ) );
177                 $ord->{gstgste} = sprintf( "%.2f", $ord->{gstgsti} / ( 1 + ( $ord->{gstgsti} / 100 ) ) );
178                 $ord->{ecostgsti} = sprintf( "%.2f", $ord->{ecost} );
179                 $ord->{ecostgste} = sprintf( "%.2f", $ord->{ecost} / ( 1 + ( $ord->{gstgsti} / 100 ) ) );
180                 $ord->{gstvalue} = sprintf( "%.2f", ( $ord->{ecostgsti} - $ord->{ecostgste} ) * $ord->{quantity});
181                 $ord->{totalgste} = sprintf( "%.2f", $ord->{quantity} * $ord->{ecostgste} );
182                 $ord->{totalgsti} = sprintf( "%.2f", $ord->{quantity} * $ord->{ecostgsti} );
183             } else {
184                 $ord->{rrpgsti} = sprintf( "%.2f", $ord->{rrp} * ( 1 + ( $ord->{gstrate} ) ) );
185                 $ord->{rrpgste} = sprintf( "%.2f", $ord->{rrp} );
186                 $ord->{gstgsti} = sprintf( "%.2f", $ord->{gstrate} * 100 );
187                 $ord->{gstgste} = sprintf( "%.2f", $ord->{gstrate} * 100 );
188                 $ord->{ecostgsti} = sprintf( "%.2f", $ord->{ecost} * ( 1 + ( $ord->{gstrate} ) ) );
189                 $ord->{ecostgste} = sprintf( "%.2f", $ord->{ecost} );
190                 $ord->{gstvalue} = sprintf( "%.2f", ( $ord->{ecostgsti} - $ord->{ecostgste} ) * $ord->{quantity});
191                 $ord->{totalgste} = sprintf( "%.2f", $ord->{quantity} * $ord->{ecostgste} );
192                 $ord->{totalgsti} = sprintf( "%.2f", $ord->{quantity} * $ord->{ecostgsti} );
193             }
194             my $bib = GetBiblioData($ord->{biblionumber});
195             my $itemtypes = GetItemTypes();
196
197             #FIXME DELETE ME
198             # 0      1        2        3         4            5         6       7      8        9
199             #isbn, itemtype, author, title, publishercode, quantity, listprice ecost discount gstrate
200
201             # Editor Number
202             my $en;
203             my $edition;
204             my $marcrecord=eval{MARC::Record::new_from_xml( $ord->{marcxml},'UTF-8' )};
205             if ($marcrecord){
206                 if ( C4::Context->preference("marcflavour") eq 'UNIMARC' ) {
207                     $en = $marcrecord->subfield( '345', "b" );
208                     $edition = $marcrecord->subfield( '205', 'a' );
209                 } elsif ( C4::Context->preference("marcflavour") eq 'MARC21' ) {
210                     $en = $marcrecord->subfield( '037', "a" );
211                     $edition = $marcrecord->subfield( '250', 'a' );
212                 }
213             }
214
215             my $ba_order = {
216                 isbn => ($ord->{isbn} ? $ord->{isbn} : undef),
217                 itemtype => ( $ord->{itemtype} and $bib->{itemtype} ? $itemtypes->{$bib->{itemtype}}->{description} : undef ),
218                 en => ( $en ? $en : undef ),
219                 edition => ( $edition ? $edition : undef ),
220             };
221             for my $key ( qw/ gstrate author title itemtype publishercode copyrightdate publicationyear discount quantity rrpgsti rrpgste gstgsti gstgste ecostgsti ecostgste gstvalue totalgste totalgsti / ) {
222                 $ba_order->{$key} = $ord->{$key};
223             }
224
225             push(@ba_orders, $ba_order);
226         }
227         $orders{$basket->{basketno}} = \@ba_orders;
228     }
229     print $input->header(
230         -type       => 'application/pdf',
231         -attachment => ( $basketgroup->{name} || $basketgroupid ) . '.pdf'
232     );
233     my $pdf = printpdf($basketgroup, $bookseller, $baskets, \%orders, $bookseller->{gstrate} // C4::Context->preference("gist")) || die "pdf generation failed";
234     print $pdf;
235
236 }
237
238 my $op = $input->param('op') || 'display';
239 # possible values of $op :
240 # - add : adds a new basketgroup, or edit an open basketgroup, or display a closed basketgroup
241 # - mod_basket : modify an individual basket of the basketgroup
242 # - closeandprint : close and print an closed basketgroup in pdf. called by clicking on "Close and print" button in closed basketgroups list
243 # - print : print a closed basketgroup. called by clicking on "Print" button in closed basketgroups list
244 # - export : export in CSV a closed basketgroup. called by clicking on "Export" button in closed basketgroups list
245 # - delete : delete an open basketgroup. called by clicking on "Delete" button in open basketgroups list
246 # - reopen : reopen a closed basketgroup. called by clicking on "Reopen" button in closed basketgroup list
247 # - attachbasket : save a modified basketgroup, or creates a new basketgroup when a basket is closed. called from basket page
248 # - display : display the list of all basketgroups for a vendor
249 my $booksellerid = $input->param('booksellerid');
250 $template->param(booksellerid => $booksellerid);
251
252 if ( $op eq "add" ) {
253 #
254 # if no param('basketgroupid') is not defined, adds a new basketgroup
255 # else, edit (if it is open) or display (if it is close) the basketgroup basketgroupid
256 # the template will know if basketgroup must be displayed or edited, depending on the value of closed key
257 #
258     my $bookseller = &GetBookSellerFromId($booksellerid);
259     my $basketgroupid = $input->param('basketgroupid');
260     my $billingplace;
261     my $deliveryplace;
262     my $freedeliveryplace;
263     if ( $basketgroupid ) {
264         # Get the selected baskets in the basketgroup to display them
265         my $selecteds = GetBasketsByBasketgroup($basketgroupid);
266         foreach my $basket(@{$selecteds}){
267             $basket->{total} = BasketTotal($basket->{basketno}, $bookseller);
268         }
269         $template->param(basketgroupid => $basketgroupid,
270                          selectedbaskets => $selecteds);
271
272         # Get general informations about the basket group to prefill the form
273         my $basketgroup = GetBasketgroup($basketgroupid);
274         $template->param(
275             name            => $basketgroup->{name},
276             deliverycomment => $basketgroup->{deliverycomment},
277             freedeliveryplace => $basketgroup->{freedeliveryplace},
278         );
279         $billingplace  = $basketgroup->{billingplace};
280         $deliveryplace = $basketgroup->{deliveryplace};
281         $freedeliveryplace = $basketgroup->{freedeliveryplace};
282         $template->param( closedbg => ($basketgroup ->{'closed'}) ? 1 : 0);
283     } else {
284         $template->param( closedbg => 0);
285     }
286     # determine default billing and delivery places depending on librarian homebranch and existing basketgroup data
287     my $borrower = GetMember( ( 'borrowernumber' => $loggedinuser ) );
288     $billingplace  = $billingplace  || $borrower->{'branchcode'};
289     $deliveryplace = $deliveryplace || $borrower->{'branchcode'};
290
291     my $branches = C4::Branch::GetBranchesLoop( $billingplace );
292     $template->param( billingplaceloop => $branches );
293     $branches = C4::Branch::GetBranchesLoop( $deliveryplace );
294     $template->param( deliveryplaceloop => $branches );
295     $template->param( booksellerid => $booksellerid );
296
297     # the template will display a unique basketgroup
298     $template->param(grouping => 1);
299     my $basketgroups = &GetBasketgroups($booksellerid);
300     my $baskets = &GetBasketsByBookseller($booksellerid);
301     displaybasketgroups($basketgroups, $bookseller, $baskets);
302 } elsif ($op eq 'mod_basket') {
303 #
304 # edit an individual basket contained in this basketgroup
305 #
306   my $basketno=$input->param('basketno');
307   my $basketgroupid=$input->param('basketgroupid');
308   ModBasket( { basketno => $basketno,
309                          basketgroupid => $basketgroupid } );
310   print $input->redirect("basket.pl?basketno=" . $basketno);
311 } elsif ( $op eq 'closeandprint') {
312 #
313 # close an open basketgroup and generates a pdf
314 #
315     my $basketgroupid = $input->param('basketgroupid');
316     CloseBasketgroup($basketgroupid);
317     printbasketgrouppdf($basketgroupid);
318     exit;
319 }elsif ($op eq 'print'){
320 #
321 # print a closed basketgroup
322 #
323     my $basketgroupid = $input->param('basketgroupid');
324     printbasketgrouppdf($basketgroupid);
325     exit;
326 }elsif ( $op eq "export" ) {
327 #
328 # export a closed basketgroup in csv
329 #
330     my $basketgroupid = $input->param('basketgroupid');
331     print $input->header(
332         -type       => 'text/csv',
333         -attachment => 'basketgroup' . $basketgroupid . '.csv',
334     );
335     print GetBasketGroupAsCSV( $basketgroupid, $input );
336     exit;
337 }elsif( $op eq "delete"){
338 #
339 # delete an closed basketgroup
340 #
341     my $basketgroupid = $input->param('basketgroupid');
342     DelBasketgroup($basketgroupid);
343     print $input->redirect('/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=' . $booksellerid.'&amp;listclosed=1');
344 }elsif ( $op eq 'reopen'){
345 #
346 # reopen a closed basketgroup
347 #
348     my $basketgroupid   = $input->param('basketgroupid');
349     my $booksellerid    = $input->param('booksellerid');
350     ReOpenBasketgroup($basketgroupid);
351     my $redirectpath = ((defined $input->param('mode'))&& ($input->param('mode') eq 'singlebg')) ?'/cgi-bin/koha/acqui/basketgroup.pl?op=add&amp;basketgroupid='.$basketgroupid.'&amp;booksellerid='.$booksellerid : '/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=' .$booksellerid.'&amp;listclosed=1';
352     print $input->redirect($redirectpath);
353 } elsif ( $op eq 'attachbasket') {
354 #
355 # save a modified basketgroup, or creates a new basketgroup when a basket is closed. called from basket page
356 #
357     # Getting parameters
358     my $basketgroup       = {};
359     my @baskets           = $input->param('basket');
360     my $basketgroupid     = $input->param('basketgroupid');
361     my $basketgroupname   = $input->param('basketgroupname');
362     my $booksellerid      = $input->param('booksellerid');
363     my $billingplace      = $input->param('billingplace');
364     my $deliveryplace     = $input->param('deliveryplace');
365     my $freedeliveryplace = $input->param('freedeliveryplace');
366     my $deliverycomment   = $input->param('deliverycomment');
367     my $closedbg          = $input->param('closedbg') ? 1 : 0;
368     if ($basketgroupid) {
369     # If we have a basketgroupid we edit the basketgroup
370         $basketgroup = {
371               name              => $basketgroupname,
372               id                => $basketgroupid,
373               basketlist        => \@baskets,
374               billingplace      => $billingplace,
375               deliveryplace     => $deliveryplace,
376               freedeliveryplace => $freedeliveryplace,
377               deliverycomment   => $deliverycomment,
378               closed            => $closedbg,
379         };
380         ModBasketgroup($basketgroup);
381         if($closedbg){
382 # FIXME
383         }
384     }else{
385     # we create a new basketgroup (whith a closed basket)
386         $basketgroup = {
387             name              => $basketgroupname,
388             booksellerid      => $booksellerid,
389             basketlist        => \@baskets,
390             billingplace      => $billingplace,
391             deliveryplace     => $deliveryplace,
392             freedeliveryplace => $freedeliveryplace,
393             deliverycomment   => $deliverycomment,
394             closed            => $closedbg,
395         };
396         $basketgroupid = NewBasketgroup($basketgroup);
397     }
398     my $redirectpath = ((defined $input->param('mode')) && ($input->param('mode') eq 'singlebg')) ?'/cgi-bin/koha/acqui/basketgroup.pl?op=add&amp;basketgroupid='.$basketgroupid.'&amp;booksellerid='.$booksellerid : '/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=' . $booksellerid;
399     $redirectpath .=  "&amp;listclosed=1" if $closedbg ;
400     print $input->redirect($redirectpath );
401     
402 }else{
403 # no param : display the list of all basketgroups for a given vendor
404     my $basketgroups = &GetBasketgroups($booksellerid);
405     my $bookseller = &GetBookSellerFromId($booksellerid);
406     my $baskets = &GetBasketsByBookseller($booksellerid);
407
408     displaybasketgroups($basketgroups, $bookseller, $baskets);
409 }
410 $template->param(listclosed => ((defined $input->param('listclosed')) && ($input->param('listclosed') eq '1'))? 1:0 );
411 #prolly won't use all these, maybe just use print, the rest can be done inside validate
412 output_html_with_http_headers $input, $cookie, $template->output;