3 #script to group (closed) baskets into basket groups for easier order management
4 #written by john.soros@biblibre.com 01/10/2008
6 # Copyright 2008 - 2009 BibLibre SARL
7 # Parts Copyright Catalyst 2010
9 # This file is part of Koha.
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
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.
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.
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
40 The bookseller who we want to display the baskets (and basketgroups) of.
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 GetBranchName/;
60 use C4::Members qw/GetMember/;
64 our ($template, $loggedinuser, $cookie)
65 = get_template_and_user({template_name => "acqui/basketgroup.tmpl",
69 flagsrequired => {acquisition => 'group_manage'},
73 sub parseinputbaskets {
74 my $booksellerid = shift;
75 my $baskets = &GetBasketsByBookseller($booksellerid);
76 for(my $i=0; $i < scalar @$baskets; ++$i) {
77 if( @$baskets[$i] && ! @$baskets[$i]->{'closedate'} ) {
78 splice(@$baskets, $i, 1);
82 foreach my $basket (@$baskets){
83 #perl DBI uses value "undef" for the mysql "NULL" value, so i need to check everywhere where $basket->{'basketgroupid'} is used for undef ☹
84 $basket->{'basketgroupid'} = $input->param($basket->{'basketno'}.'-group') || undef;
91 sub parseinputbasketgroups {
92 my $booksellerid = shift;
94 my $basketgroups = &GetBasketgroups($booksellerid);
96 foreach my $basket (@$baskets){
100 if(! $basket->{'basketgroupid'} || $basket->{'basketgroupid'} == 0){
103 foreach my $basketgroup (@$basketgroups){
104 if($basket->{'basketgroupid'} == $basketgroup->{'id'}){
106 push(@{$basketgroup->{'basketlist'}}, $basket->{'basketno'});
112 #if the basketgroup doesn't exist yet
113 $basketgroup = $newbasketgroups->{$basket->{'basketgroupid'}} || undef;
114 $basketgroup->{'booksellerid'} = $booksellerid;
116 while($i < scalar @$basketgroups && @$basketgroups[$i]->{'id'} != $basket->{'basketgroupid'}){
119 $basketgroup = @$basketgroups[$i];
121 $basketgroup->{'id'}=$basket->{'basketgroupid'};
122 $basketgroup->{'name'}=$input->param('basketgroup-'.$basketgroup->{'id'}.'-name') || "";
123 $basketgroup->{'closed'}= $input->param('basketgroup-'.$basketgroup->{'id'}.'-closed');
124 push(@{$basketgroup->{'basketlist'}}, $basket->{'basketno'});
126 $newbasketgroups->{$basket->{'basketgroupid'}} = $basketgroup;
128 if($basketgroup->{'id'}){
129 @$basketgroups[$i] = $basketgroup;
133 return($basketgroups, $newbasketgroups);
137 my $basketno = shift;
138 my $bookseller = shift;
140 my @orders = GetOrders($basketno);
141 for my $order (@orders){
142 $total = $total + ( $order->{ecost} * $order->{quantity} );
143 if ($bookseller->{invoiceincgst} && ! $bookseller->{listincgst} && ( $bookseller->{gstrate} // C4::Context->preference("gist") )) {
144 my $gst = $bookseller->{gstrate} // C4::Context->preference("gist");
145 $total = $total * ( $gst / 100 +1);
148 $total .= $bookseller->{invoiceprice};
152 #displays all basketgroups and all closed baskets (in their respective groups)
153 sub displaybasketgroups {
154 my $basketgroups = shift;
155 my $bookseller = shift;
157 if (scalar @$basketgroups != 0) {
158 foreach my $basketgroup (@$basketgroups){
159 $basketgroup -> {'billingplacename'} = GetBranchName($basketgroup -> {'billingplace'});
160 $basketgroup -> {'deliveryplacename'} = GetBranchName($basketgroup -> {'deliveryplace'});
163 while($i < scalar(@$baskets)){
164 my $basket = @$baskets[$i];
165 if($basket->{'basketgroupid'} && $basket->{'basketgroupid'} == $basketgroup->{'id'}){
166 $basket->{total} = BasketTotal($basket->{basketno}, $bookseller);
167 push(@{$basketgroup->{'baskets'}}, $basket);
168 splice(@$baskets, $i, 1);
174 $basketgroup -> {'basketsqty'} = $basketsqty;
176 $template->param(basketgroups => $basketgroups);
178 for(my $i=0; $i < scalar @$baskets; ++$i) {
179 if( ! @$baskets[$i]->{'closedate'} ) {
180 splice(@$baskets, $i, 1);
183 @$baskets[$i]->{total} = BasketTotal(@$baskets[$i]->{basketno}, $bookseller);
186 $template->param(baskets => $baskets);
187 $template->param( booksellername => $bookseller ->{'name'});
190 sub printbasketgrouppdf{
191 my ($basketgroupid) = @_;
193 my $pdfformat = C4::Context->preference("OrderPdfFormat");
194 if ($pdfformat eq 'pdfformat::layout3pages' || $pdfformat eq 'pdfformat::layout2pages'){
196 eval "require $pdfformat";
203 print $input->header;
204 print $input->start_html; # FIXME Should do a nicer page
205 print "<h1>Invalid PDF Format set</h1>";
206 print "Please go to the systempreferences and set a valid pdfformat";
210 my $basketgroup = GetBasketgroup($basketgroupid);
211 my $bookseller = GetBookSellerFromId($basketgroup->{'booksellerid'});
212 my $baskets = GetBasketsByBasketgroup($basketgroupid);
215 for my $basket (@$baskets) {
217 my @ords = &GetOrders($basket->{basketno});
218 for my $ord (@ords) {
220 next unless ( $ord->{biblionumber} or $ord->{quantity}> 0 );
236 $ord->{rrp} = ConvertCurrency( $ord->{'currency'}, $ord->{rrp} );
237 if ( $bookseller->{'listincgst'} ) {
238 $ord->{rrpgsti} = sprintf( "%.2f", $ord->{rrp} );
239 $ord->{gstgsti} = sprintf( "%.2f", $ord->{gstrate} * 100 );
240 $ord->{rrpgste} = sprintf( "%.2f", $ord->{rrp} / ( 1 + ( $ord->{gstgsti} / 100 ) ) );
241 $ord->{gstgste} = sprintf( "%.2f", $ord->{gstgsti} / ( 1 + ( $ord->{gstgsti} / 100 ) ) );
242 $ord->{ecostgsti} = sprintf( "%.2f", $ord->{ecost} );
243 $ord->{ecostgste} = sprintf( "%.2f", $ord->{ecost} / ( 1 + ( $ord->{gstgsti} / 100 ) ) );
244 $ord->{gstvalue} = sprintf( "%.2f", ( $ord->{ecostgsti} - $ord->{ecostgste} ) * $ord->{quantity});
245 $ord->{totalgste} = sprintf( "%.2f", $ord->{quantity} * $ord->{ecostgste} );
246 $ord->{totalgsti} = sprintf( "%.2f", $ord->{quantity} * $ord->{ecostgsti} );
248 $ord->{rrpgsti} = sprintf( "%.2f", $ord->{rrp} * ( 1 + ( $ord->{gstrate} ) ) );
249 $ord->{rrpgste} = sprintf( "%.2f", $ord->{rrp} );
250 $ord->{gstgsti} = sprintf( "%.2f", $ord->{gstrate} * 100 );
251 $ord->{gstgste} = sprintf( "%.2f", $ord->{gstrate} * 100 );
252 $ord->{ecostgsti} = sprintf( "%.2f", $ord->{ecost} * ( 1 + ( $ord->{gstrate} ) ) );
253 $ord->{ecostgste} = sprintf( "%.2f", $ord->{ecost} );
254 $ord->{gstvalue} = sprintf( "%.2f", ( $ord->{ecostgsti} - $ord->{ecostgste} ) * $ord->{quantity});
255 $ord->{totalgste} = sprintf( "%.2f", $ord->{quantity} * $ord->{ecostgste} );
256 $ord->{totalgsti} = sprintf( "%.2f", $ord->{quantity} * $ord->{ecostgsti} );
258 my $bib = GetBiblioData($ord->{biblionumber});
259 my $itemtypes = GetItemTypes();
262 # 0 1 2 3 4 5 6 7 8 9
263 #isbn, itemtype, author, title, publishercode, quantity, listprice ecost discount gstrate
267 my $marcrecord=eval{MARC::Record::new_from_xml( $ord->{marcxml},'UTF-8' )};
269 if ( C4::Context->preference("marcflavour") eq 'UNIMARC' ) {
270 $en = $marcrecord->subfield( '345', "b" );
271 } elsif ( C4::Context->preference("marcflavour") eq 'MARC21' ) {
272 $en = $marcrecord->subfield( '037', "a" );
277 isbn => ($ord->{isbn} ? $ord->{isbn} : undef),
278 itemtype => ( $ord->{itemtype} and $bib->{itemtype} ? $itemtypes->{$bib->{itemtype}}->{description} : undef ),
279 en => ( $en ? $en : undef ),
281 for my $key ( qw/ gstrate author title itemtype publishercode discount quantity rrpgsti rrpgste gstgsti gstgste ecostgsti ecostgste gstvalue totalgste totalgsti / ) {
282 $ba_order->{$key} = $ord->{$key};
285 push(@ba_orders, $ba_order);
287 $orders{$basket->{basketno}} = \@ba_orders;
289 print $input->header(
290 -type => 'application/pdf',
291 -attachment => ( $basketgroup->{name} || $basketgroupid ) . '.pdf'
293 my $pdf = printpdf($basketgroup, $bookseller, $baskets, \%orders, $bookseller->{gstrate} // C4::Context->preference("gist")) || die "pdf generation failed";
298 my $op = $input->param('op') || 'display';
299 my $booksellerid = $input->param('booksellerid');
300 $template->param(booksellerid => $booksellerid);
302 if ( $op eq "add" ) {
304 $template->param( ungroupedlist => 1);
305 my @booksellers = GetBookSeller('');
306 for (my $i=0; $i < scalar @booksellers; $i++) {
307 my $baskets = &GetBasketsByBookseller($booksellers[$i]->{id});
308 for (my $j=0; $j < scalar @$baskets; $j++) {
309 if(! @$baskets[$i]->{closedate} || @$baskets[$i]->{basketgroupid}) {
310 splice(@$baskets, $j, 1);
314 if (scalar @$baskets == 0){
315 splice(@booksellers, $i, 1);
320 my $basketgroupid = $input->param('basketgroupid');
323 my $freedeliveryplace;
324 if ( $basketgroupid ) {
325 # Get the selected baskets in the basketgroup to display them
326 my $selecteds = GetBasketsByBasketgroup($basketgroupid);
327 foreach (@{$selecteds}){
328 $_->{total} = BasketTotal($_->{basketno}, $_);
330 $template->param(basketgroupid => $basketgroupid,
331 selectedbaskets => $selecteds);
333 # Get general informations about the basket group to prefill the form
334 my $basketgroup = GetBasketgroup($basketgroupid);
336 name => $basketgroup->{name},
337 deliverycomment => $basketgroup->{deliverycomment},
338 freedeliveryplace => $basketgroup->{freedeliveryplace},
340 $billingplace = $basketgroup->{billingplace};
341 $deliveryplace = $basketgroup->{deliveryplace};
342 $freedeliveryplace = $basketgroup->{freedeliveryplace};
345 # determine default billing and delivery places depending on librarian homebranch and existing basketgroup data
346 my $borrower = GetMember( ( 'borrowernumber' => $loggedinuser ) );
347 $billingplace = $billingplace || $borrower->{'branchcode'};
348 $deliveryplace = $deliveryplace || $borrower->{'branchcode'};
350 my $branches = C4::Branch::GetBranchesLoop( $billingplace );
351 $template->param( billingplaceloop => $branches );
352 $branches = C4::Branch::GetBranchesLoop( $deliveryplace );
353 $template->param( deliveryplaceloop => $branches );
355 $template->param( booksellerid => $booksellerid );
357 $template->param(grouping => 1);
358 my $basketgroups = &GetBasketgroups($booksellerid);
359 my $bookseller = &GetBookSellerFromId($booksellerid);
360 my $baskets = &GetBasketsByBookseller($booksellerid);
362 displaybasketgroups($basketgroups, $bookseller, $baskets);
363 } elsif ($op eq 'mod_basket') {
364 #we want to modify an individual basket's group
365 my $basketno=$input->param('basketno');
366 my $basketgroupid=$input->param('basketgroupid');
367 ModBasket( { basketno => $basketno,
368 basketgroupid => $basketgroupid } );
369 print $input->redirect("basket.pl?basketno=" . $basketno);
370 } elsif ($op eq 'validate') {
372 $template->param( booksellererror => 1);
374 $template->param( booksellerid => $booksellerid );
376 my $baskets = parseinputbaskets($booksellerid);
377 my ($basketgroups, $newbasketgroups) = parseinputbasketgroups($booksellerid, $baskets);
378 foreach my $nbgid (keys %$newbasketgroups){
379 #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
380 my $bgid = NewBasketgroup($newbasketgroups->{$nbgid});
381 ${$newbasketgroups->{$nbgid}}->{'id'} = $bgid;
382 ${$newbasketgroups->{$nbgid}}->{'oldid'} = $nbgid;
384 foreach my $basket (@$baskets){
385 #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.
386 if ( $basket->{'basketgroupid'} && $newbasketgroups->{$basket->{'basketgroupid'}} ){
387 $basket->{'basketgroupid'} = ${$newbasketgroups->{$basket->{'basketgroupid'}}}->{'id'};
391 foreach my $basketgroup (@$basketgroups){
392 if(! $basketgroup->{'id'}){
393 foreach my $basket (@{$basketgroup->{'baskets'}}){
394 if($input->param('basket'.$basket->{'basketno'}.'changed')){
398 } elsif ($input->param('basketgroup-'.$basketgroup->{'id'}.'-changed')){
399 ModBasketgroup($basketgroup);
402 $basketgroups = &GetBasketgroups($booksellerid);
403 my $bookseller = &GetBookSellerFromId($booksellerid);
404 $baskets = &GetBasketsByBookseller($booksellerid);
406 displaybasketgroups($basketgroups, $bookseller, $baskets);
407 } elsif ( $op eq 'closeandprint') {
408 my $basketgroupid = $input->param('basketgroupid');
410 CloseBasketgroup($basketgroupid);
412 printbasketgrouppdf($basketgroupid);
414 }elsif ($op eq 'print'){
415 my $basketgroupid = $input->param('basketgroupid');
417 printbasketgrouppdf($basketgroupid);
419 }elsif ( $op eq "export" ) {
420 my $basketgroupid = $input->param('basketgroupid');
421 print $input->header(
423 -attachment => 'basketgroup' . $basketgroupid . '.csv',
425 print GetBasketGroupAsCSV( $basketgroupid, $input );
427 }elsif( $op eq "delete"){
428 my $basketgroupid = $input->param('basketgroupid');
429 DelBasketgroup($basketgroupid);
430 print $input->redirect('/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=' . $booksellerid);
432 }elsif ( $op eq 'reopen'){
433 my $basketgroupid = $input->param('basketgroupid');
434 my $booksellerid = $input->param('booksellerid');
436 ReOpenBasketgroup($basketgroupid);
438 print $input->redirect('/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=' . $booksellerid . '#closed');
440 } elsif ( $op eq 'attachbasket') {
443 my $basketgroup = {};
444 my @baskets = $input->param('basket');
445 my $basketgroupid = $input->param('basketgroupid');
446 my $basketgroupname = $input->param('basketgroupname');
447 my $booksellerid = $input->param('booksellerid');
448 my $billingplace = $input->param('billingplace');
449 my $deliveryplace = $input->param('deliveryplace');
450 my $freedeliveryplace = $input->param('freedeliveryplace');
451 my $deliverycomment = $input->param('deliverycomment');
452 my $close = $input->param('close') ? 1 : 0;
453 # If we got a basketgroupname, we create a basketgroup
454 if ($basketgroupid) {
456 name => $basketgroupname,
457 id => $basketgroupid,
458 basketlist => \@baskets,
459 billingplace => $billingplace,
460 deliveryplace => $deliveryplace,
461 freedeliveryplace => $freedeliveryplace,
462 deliverycomment => $deliverycomment,
465 ModBasketgroup($basketgroup);
471 name => $basketgroupname,
472 booksellerid => $booksellerid,
473 basketlist => \@baskets,
474 billingplace => $billingplace,
475 deliveryplace => $deliveryplace,
476 freedeliveryplace => $freedeliveryplace,
477 deliverycomment => $deliverycomment,
480 $basketgroupid = NewBasketgroup($basketgroup);
483 my $url = '/cgi-bin/koha/acqui/basketgroup.pl?booksellerid=' . $booksellerid;
484 $url .= "&closed=1" if ($input->param("closed"));
485 print $input->redirect($url);
488 my $basketgroups = &GetBasketgroups($booksellerid);
489 my $bookseller = &GetBookSellerFromId($booksellerid);
490 my $baskets = &GetBasketsByBookseller($booksellerid);
492 displaybasketgroups($basketgroups, $bookseller, $baskets);
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;