3 #script to show display basket of orders
4 #written by chris@katipo.co.nz 24/2/2000
6 # Copyright 2000-2002 Katipo Communications
8 # This file is part of Koha.
10 # Koha is free software; you can redistribute it and/or modify it
11 # under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 3 of the License, or
13 # (at your option) any later version.
15 # Koha is distributed in the hope that it will be useful, but
16 # WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with Koha; if not, see <http://www.gnu.org/licenses>.
30 this script allows to create a new record to order it. This record shouldn't exist
38 the bookseller the librarian has to buy a new book.
41 the title of this new record.
44 the author of this new record.
46 =item publication year
47 the publication year of this new record.
50 the number of this order.
55 the basket number for this new order.
58 if this order comes from a suggestion.
61 the item's id in the breeding reservoir
71 use C4::Auth qw( get_template_and_user );
72 use C4::Budgets qw( GetBudget GetBudgetHierarchy CanUserUseBudget );
74 use C4::Acquisition qw( GetOrder GetBasket FillWithDefaultValues GetOrderUsers );
75 use C4::Contract qw( GetContract );
76 use C4::Suggestions qw( GetSuggestion GetSuggestionInfo );
83 IsMarcStructureInternal
85 use C4::Output qw( output_and_exit output_html_with_http_headers );
87 use C4::Search qw( FindDuplicate );
89 #needed for z3950 import:
90 use C4::ImportBatch qw( SetImportRecordStatus SetMatchedBiblionumber GetImportRecordMarc );
92 use Koha::Acquisition::Booksellers;
93 use Koha::Acquisition::Currencies qw( get_active );
95 use Koha::BiblioFrameworks;
96 use Koha::DateUtils qw( dt_from_string );
97 use Koha::MarcSubfieldStructures;
100 use Koha::RecordProcessor;
101 use Koha::Subscriptions;
103 our $input = CGI->new;
104 my $booksellerid = $input->param('booksellerid'); # FIXME: else ERROR!
105 my $budget_id = $input->param('budget_id') || 0;
106 my $title = $input->param('title');
107 my $author = $input->param('author');
108 my $publicationyear = $input->param('publicationyear');
109 my $ordernumber = $input->param('ordernumber') || '';
110 our $biblionumber = $input->param('biblionumber');
111 our $basketno = $input->param('basketno');
112 my $suggestionid = $input->param('suggestionid');
113 my $uncertainprice = $input->param('uncertainprice');
114 my $import_batch_id = $input->param('import_batch_id'); # if this is filled, we come from a staged file, and we will return here after saving the order !
115 my $from_subscriptionid = $input->param('from_subscriptionid');
119 our ( $template, $loggedinuser, $cookie, $userflags ) = get_template_and_user(
121 template_name => "acqui/neworderempty.tt",
124 flagsrequired => { acquisition => 'order_manage' },
128 our $marcflavour = C4::Context->preference('marcflavour');
131 my $order = GetOrder($ordernumber);
132 $basketno = $order->{'basketno'};
135 our $basket = GetBasket($basketno);
136 my $basketobj = Koha::Acquisition::Baskets->find( $basketno );
137 $booksellerid = $basket->{booksellerid} unless $booksellerid;
138 my $bookseller = Koha::Acquisition::Booksellers->find( $booksellerid );
140 output_and_exit( $input, $cookie, $template, 'unknown_basket') unless $basketobj;
141 output_and_exit( $input, $cookie, $template, 'unknown_vendor') unless $bookseller;
144 ordernumber => $ordernumber,
145 basketno => $basketno,
147 booksellerid => $basket->{'booksellerid'},
148 name => $bookseller->name,
150 output_and_exit( $input, $cookie, $template, 'order_cannot_be_edited' )
151 if $ordernumber and $basketobj->closedate;
153 my $contract = GetContract({
154 contractnumber => $basket->{contractnumber}
157 #simple parameters reading (all in one :-)
158 our $params = $input->Vars;
159 my $listprice=0; # the price, that can be in MARC record if we have one
160 if ( $ordernumber eq '' and defined $params->{'breedingid'}){
161 #we want to import from the breeding reservoir (from a z3950 search)
162 my ($marcrecord, $encoding) = MARCfindbreeding($params->{'breedingid'});
163 die("Could not find the selected record in the reservoir, bailing") unless $marcrecord;
165 # Remove all the items (952) from the imported record
166 foreach my $item ($marcrecord->field('952')) {
167 $marcrecord->delete_field($item);
172 ($biblionumber,$duplicatetitle) = FindDuplicate($marcrecord);
173 if($biblionumber && !$input->param('use_external_source')) {
174 #if duplicate record found and user did not decide yet, first warn user
175 #and let them choose between using a new record or an existing record
176 Load_Duplicate($duplicatetitle);
179 #from this point: add a new record
180 C4::Acquisition::FillWithDefaultValues($marcrecord, {only_mandatory => 1});
182 $params->{'frameworkcode'} or $params->{'frameworkcode'} = "";
183 ( $biblionumber, $bibitemnum ) = AddBiblio( $marcrecord, $params->{'frameworkcode'} );
184 # get the price if there is one.
185 $listprice = GetMarcPrice($marcrecord, $marcflavour);
186 SetImportRecordStatus($params->{'breedingid'}, 'imported');
188 SetMatchedBiblionumber( $params->{breedingid}, $biblionumber );
193 my ( @order_user_ids, @order_users, @catalog_details );
194 our $tagslib = GetMarcStructure(1, 'ACQ', { unsafe => 1 } );
195 my ( $itemnumber_tag, $itemnumber_subtag ) = GetMarcFromKohaField( 'items.itemnumber' );
196 if ( not $ordernumber ) { # create order
199 if ( $biblionumber ) {
200 $data = GetBiblioData($biblionumber);
202 # get suggestion fields if applicable. If it's a subscription renewal, then the biblio already exists
203 # otherwise, retrieve suggestion information.
204 elsif ($suggestionid) {
205 $data = GetSuggestion($suggestionid);
206 $budget_id ||= $data->{'budgetid'} // 0;
209 if ( not $biblionumber and Koha::BiblioFrameworks->find('ACQ') ) {
210 foreach my $tag ( sort keys %{$tagslib} ) {
212 next if $tag eq $itemnumber_tag; # skip items fields
213 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
214 my $mss = $tagslib->{$tag}{$subfield};
215 next if IsMarcStructureInternal($mss);
216 next if $mss->{tab} == -1;
217 my $value = $mss->{defaultvalue};
219 if ($suggestionid and $mss->{kohafield}) {
220 # Reading suggestion info if ordering from a suggestion
221 if ( $mss->{kohafield} eq 'biblio.title' ) {
222 $value = $data->{title};
224 elsif ( $mss->{kohafield} eq 'biblio.author' ) {
225 $value = $data->{author};
227 elsif ( $mss->{kohafield} eq 'biblioitems.publishercode' ) {
228 $value = $data->{publishercode};
230 elsif ( $mss->{kohafield} eq 'biblioitems.editionstatement' ) {
231 $value = $data->{editionstatement};
233 elsif ( $mss->{kohafield} eq 'biblioitems.publicationyear' ) {
234 $value = $data->{publicationyear};
236 elsif ( $mss->{kohafield} eq 'biblioitems.isbn' ) {
237 $value = $data->{isbn};
239 elsif ( $mss->{kohafield} eq 'biblio.seriestitle' ) {
240 $value = $data->{seriestitle};
246 # get today date & replace <<YYYY>>, <<YY>>, <<MM>>, <<DD>> if provided in the default value
247 my $today_dt = dt_from_string;
248 my $year = $today_dt->strftime('%Y');
249 my $shortyear = $today_dt->strftime('%y');
250 my $month = $today_dt->strftime('%m');
251 my $day = $today_dt->strftime('%d');
252 $value =~ s/<<YYYY>>/$year/g;
253 $value =~ s/<<YY>>/$shortyear/g;
254 $value =~ s/<<MM>>/$month/g;
255 $value =~ s/<<DD>>/$day/g;
257 # And <<USER>> with surname (?)
259 ( C4::Context->userenv
260 ? C4::Context->userenv->{'surname'}
261 : "superlibrarian" );
262 $value =~ s/<<USER>>/$username/g;
264 push @catalog_details, {
266 subfield => $subfield,
267 %$mss, # Do we need plugins support (?)
275 $data = GetOrder($ordernumber);
276 $budget_id = $data->{'budget_id'};
279 subscriptionid => $data->{subscriptionid},
282 $basket = GetBasket( $data->{'basketno'} );
283 $basketno = $basket->{'basketno'};
285 @order_user_ids = GetOrderUsers($ordernumber);
286 foreach my $order_user_id (@order_user_ids) {
287 # FIXME Could be improved with search -in
288 my $order_patron = Koha::Patrons->find( $order_user_id );
289 push @order_users, $order_patron if $order_patron;
292 $biblionumber = $data->{biblionumber};
295 # - no ordernumber but a biblionumber: from a subscription, from an existing record
296 # - no ordernumber, no biblionumber: from a suggestion, from a new order
297 if ( not $ordernumber or $biblionumber ) {
298 if ( C4::Context->preference('UseACQFrameworkForBiblioRecords') ) {
299 my $biblio = Koha::Biblios->find($biblionumber);
300 my $record = $biblio ? $biblio->metadata->record : undef;
301 foreach my $tag ( sort keys %{$tagslib} ) {
303 next if $tag eq $itemnumber_tag; # skip items fields
304 my @fields = $biblionumber ? $record->field($tag) : ();
305 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
306 my $mss = $tagslib->{$tag}{$subfield};
307 next if IsMarcStructureInternal($mss);
308 next if $mss->{tab} == -1;
309 # We only need to display the values
310 my $value = join '; ', map { $tag < 10 ? $_->data : $_->subfield( $subfield ) } @fields;
312 push @catalog_details, {
314 subfield => $subfield,
324 $template->param( catalog_details => \@catalog_details, );
327 $suggestion = GetSuggestionInfo($suggestionid) if $suggestionid;
329 my $active_currency = Koha::Acquisition::Currencies->get_active;
331 # build bookfund list
332 my $patron = Koha::Patrons->find( $loggedinuser )->unblessed;
334 my $budget = GetBudget($budget_id);
336 my $budget_loop = [];
337 my $budgets = GetBudgetHierarchy;
338 foreach my $r (@{$budgets}) {
339 next unless (CanUserUseBudget($patron, $r, $userflags));
340 push @{$budget_loop}, {
341 b_id => $r->{budget_id},
342 b_txt => $r->{budget_name},
343 b_sort1_authcat => $r->{'sort1_authcat'},
344 b_sort2_authcat => $r->{'sort2_authcat'},
345 b_active => $r->{budget_period_active},
346 b_sel => ( $r->{budget_id} == $budget_id ) ? 1 : 0,
347 b_level => $r->{budget_level},
352 $template->param( sort1 => $data->{'sort1'} );
353 $template->param( sort2 => $data->{'sort2'} );
355 if ($basketobj->effective_create_items eq 'ordering' && !$ordernumber) {
356 # Check if ACQ framework exists
357 my $marc = GetMarcStructure(1, 'ACQ', { unsafe => 1 } );
359 $template->param('NoACQframework' => 1);
362 AcqCreateItemOrdering => 1,
363 UniqueItemFields => C4::Context->preference('UniqueItemFields'),
367 # Get the item types list, but only if item_level_itype is YES. Otherwise, it will be in the item, no need to display it in the biblio
369 @itemtypes = Koha::ItemTypes->search->as_list unless C4::Context->preference('item-level_itypes');
371 if ( defined $from_subscriptionid ) {
372 # Get the last received order for this subscription
373 my $lastOrderReceived = Koha::Acquisition::Orders->search(
375 subscriptionid => $from_subscriptionid,
376 datereceived => { '!=' => undef }
380 [ { -desc => 'datereceived' }, { -desc => 'ordernumber' } ]
383 if ( $lastOrderReceived->count ) {
384 $lastOrderReceived = $lastOrderReceived->next->unblessed; # FIXME We should send the object to the template
385 $budget_id = $lastOrderReceived->{budgetid};
386 $data->{listprice} = $lastOrderReceived->{listprice};
387 $data->{uncertainprice} = $lastOrderReceived->{uncertainprice};
388 $data->{tax_rate} = $lastOrderReceived->{tax_rate_on_ordering};
389 $data->{discount} = $lastOrderReceived->{discount};
390 $data->{rrp} = $lastOrderReceived->{rrp};
391 $data->{replacementprice} = $lastOrderReceived->{replacementprice};
392 $data->{ecost} = $lastOrderReceived->{ecost};
393 $data->{quantity} = $lastOrderReceived->{quantity};
394 $data->{unitprice} = $lastOrderReceived->{unitprice};
395 $data->{order_internalnote} = $lastOrderReceived->{order_internalnote};
396 $data->{order_vendornote} = $lastOrderReceived->{order_vendornote};
397 $data->{sort1} = $lastOrderReceived->{sort1};
398 $data->{sort2} = $lastOrderReceived->{sort2};
400 $basket = GetBasket( $input->param('basketno') );
403 my $subscription = Koha::Subscriptions->find($from_subscriptionid);
405 subscriptionid => $from_subscriptionid,
406 subscription => $subscription,
410 # Find the items.barcode subfield for barcode validations
411 my (undef, $barcode_subfield) = GetMarcFromKohaField( 'items.barcode' );
414 # get option values for TaxRates syspref
415 my @gst_values = map {
417 }, split( '\|', C4::Context->preference("TaxRates") );
419 my $quantity = $input->param('rr_quantity_to_order') ?
420 $input->param('rr_quantity_to_order') :
426 existing => $biblionumber,
427 # basket informations
428 basketname => $basket->{'basketname'},
429 basketnote => $basket->{'note'},
430 booksellerid => $basket->{'booksellerid'},
431 basketbooksellernote => $basket->{booksellernote},
432 basketcontractno => $basket->{contractnumber},
433 basketcontractname => $contract->{contractname},
434 creationdate => $basket->{creationdate},
435 authorisedby => $basket->{'authorisedby'},
436 authorisedbyname => $basket->{'authorisedbyname'},
437 closedate => $basket->{'closedate'},
439 suggestionid => $suggestion->{suggestionid},
440 surnamesuggestedby => $suggestion->{surnamesuggestedby},
441 firstnamesuggestedby => $suggestion->{firstnamesuggestedby},
442 biblionumber => $biblionumber,
443 uncertainprice => $data->{'uncertainprice'},
444 discount_2dp => sprintf( "%.2f", $bookseller->discount ) , # for display
445 discount => $bookseller->discount,
446 orderdiscount_2dp => sprintf( "%.2f", $data->{'discount'} || 0 ),
447 orderdiscount => $data->{'discount'},
448 order_internalnote => $data->{'order_internalnote'},
449 order_vendornote => $data->{'order_vendornote'},
450 listincgst => $bookseller->listincgst,
451 invoiceincgst => $bookseller->invoiceincgst,
452 cur_active_sym => $active_currency->symbol,
453 cur_active => $active_currency->currency,
454 currencies => Koha::Acquisition::Currencies->search,
455 currency => $data->{currency},
456 vendor_currency => $bookseller->listprice,
457 orderexists => ( $new eq 'yes' ) ? 0 : 1,
458 title => $data->{'title'},
459 author => $data->{'author'},
460 publicationyear => $data->{'publicationyear'} ? $data->{'publicationyear'} : $data->{'copyrightdate'},
461 editionstatement => $data->{'editionstatement'},
462 budget_loop => $budget_loop,
463 isbn => $data->{'isbn'},
464 ean => $data->{'ean'},
465 seriestitle => $data->{'seriestitle'},
466 itemtypeloop => \@itemtypes,
467 quantity => $quantity,
468 quantityrec => $quantity,
469 rrp => $data->{'rrp'},
470 replacementprice => $data->{'replacementprice'},
471 gst_values => \@gst_values,
472 tax_rate => $data->{tax_rate_on_ordering} ? $data->{tax_rate_on_ordering}+0.0 : $bookseller->tax_rate ? $bookseller->tax_rate+0.0 : 0,
473 listprice => sprintf( "%.2f", $data->{listprice} || $data->{price} || $listprice),
474 total => sprintf( "%.2f", ($data->{ecost} || 0) * ($data->{'quantity'} || 0) ),
475 ecost => sprintf( "%.2f", $data->{ecost} || 0),
476 unitprice => sprintf( "%.2f", $data->{unitprice} || 0),
477 publishercode => $data->{'publishercode'},
478 barcode_subfield => $barcode_subfield,
479 import_batch_id => $import_batch_id,
480 acqcreate => $basketobj->effective_create_items eq "ordering" ? 1 : "",
481 users_ids => join(':', @order_user_ids),
482 users => \@order_users,
483 (uc(C4::Context->preference("marcflavour"))) => 1,
484 estimated_delivery_date => $data->{estimated_delivery_date},
487 output_html_with_http_headers $input, $cookie, $template->output;
490 =head2 MARCfindbreeding
492 $record = MARCfindbreeding($breedingid);
494 Look up the import record repository for the record with
495 record with id $breedingid. If found, returns the decoded
496 MARC::Record; otherwise, -1 is returned (FIXME).
497 Returns as second parameter the character encoding.
501 sub MARCfindbreeding {
503 my ($marc, $encoding) = GetImportRecordMarc($id);
504 # remove the - in isbn, koha store isbn without any -
506 my $record = MARC::Record->new_from_usmarc($marc);
507 my ($isbnfield,$isbnsubfield) = GetMarcFromKohaField( 'biblioitems.isbn' );
508 if ( $record->field($isbnfield) ) {
509 foreach my $field ( $record->field($isbnfield) ) {
510 foreach my $subfield ( $field->subfield($isbnsubfield) ) {
511 my $newisbn = $field->subfield($isbnsubfield);
513 $field->update( $isbnsubfield => $newisbn );
517 # fix the unimarc 100 coded field (with unicode information)
518 if ($marcflavour eq 'UNIMARC' && $record->subfield(100,'a')) {
519 my $f100a=$record->subfield(100,'a');
520 my $f100 = $record->field(100);
521 my $f100temp = $f100->as_string;
522 $record->delete_field($f100);
523 if ( length($f100temp) > 28 ) {
524 substr( $f100temp, 26, 2, "50" );
525 $f100->update( 'a' => $f100temp );
526 my $f100 = MARC::Field->new( '100', '', '', 'a' => $f100temp );
527 $record->insert_fields_ordered($f100);
531 if ( !defined(ref($record)) ) {
535 # normalize author : probably UNIMARC specific...
536 if ( C4::Context->preference("z3950NormalizeAuthor")
537 and C4::Context->preference("z3950AuthorAuthFields") )
539 my ( $tag, $subfield ) = GetMarcFromKohaField( "biblio.author" );
542 C4::Context->preference("z3950AuthorAuthFields");
543 my @auth_fields = split /,/, $auth_fields;
546 if ( $record->field($tag) ) {
547 foreach my $tmpfield ( $record->field($tag)->subfields ) {
549 my $subfieldcode = shift @$tmpfield;
550 my $subfieldvalue = shift @$tmpfield;
552 $field->add_subfields(
553 "$subfieldcode" => $subfieldvalue )
554 if ( $subfieldcode ne $subfield );
558 MARC::Field->new( $tag, "", "",
559 $subfieldcode => $subfieldvalue )
560 if ( $subfieldcode ne $subfield );
564 $record->delete_field( $record->field($tag) );
565 foreach my $fieldtag (@auth_fields) {
566 next unless ( $record->field($fieldtag) );
567 my $lastname = $record->field($fieldtag)->subfield('a');
568 my $firstname = $record->field($fieldtag)->subfield('b');
569 my $title = $record->field($fieldtag)->subfield('c');
570 my $number = $record->field($fieldtag)->subfield('d');
572 $field->add_subfields(
573 "$subfield" => ucfirst($title) . " "
574 . ucfirst($firstname) . " "
578 $field->add_subfields(
579 "$subfield" => ucfirst($firstname) . ", "
580 . ucfirst($lastname) );
583 $record->insert_fields_ordered($field);
585 return $record, $encoding;
592 my ($duplicatetitle)= @_;
593 ($template, $loggedinuser, $cookie) = get_template_and_user(
595 template_name => "acqui/neworderempty_duplicate.tt",
598 flagsrequired => { acquisition => 'order_manage' },
603 biblionumber => $biblionumber,
604 basketno => $basketno,
605 booksellerid => $basket->{'booksellerid'},
606 breedingid => $params->{'breedingid'},
607 duplicatetitle => $duplicatetitle,
608 (uc(C4::Context->preference("marcflavour"))) => 1
611 output_html_with_http_headers $input, $cookie, $template->output;