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;
102 use Koha::UI::Form::Builder::Biblio;
103 use Koha::AdditionalFields;
105 our $input = CGI->new;
106 my $booksellerid = $input->param('booksellerid'); # FIXME: else ERROR!
107 my $budget_id = $input->param('budget_id') || 0;
108 my $title = $input->param('title');
109 my $author = $input->param('author');
110 my $publicationyear = $input->param('publicationyear');
111 my $ordernumber = $input->param('ordernumber') || '';
112 our $biblionumber = $input->param('biblionumber');
113 our $basketno = $input->param('basketno');
114 my $suggestionid = $input->param('suggestionid');
115 my $uncertainprice = $input->param('uncertainprice');
116 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 !
117 my $from_subscriptionid = $input->param('from_subscriptionid');
118 my $frameworkcode = $input->param('frameworkcode') // q{};
119 our $breedingid = $input->param('breedingid');
122 my $op = $input->param('op') || q{};
124 our ( $template, $loggedinuser, $cookie, $userflags ) = get_template_and_user(
126 template_name => "acqui/neworderempty.tt",
129 flagsrequired => { acquisition => 'order_manage' },
133 our $marcflavour = C4::Context->preference('marcflavour');
136 my $order = GetOrder($ordernumber);
137 $basketno = $order->{'basketno'};
140 our $basket = GetBasket($basketno);
141 my $basketobj = Koha::Acquisition::Baskets->find($basketno);
142 $booksellerid = $basket->{booksellerid} unless $booksellerid;
143 my $bookseller = Koha::Acquisition::Booksellers->find($booksellerid);
144 $data = GetOrder($ordernumber) if $ordernumber;
146 output_and_exit( $input, $cookie, $template, 'unknown_basket') unless $basketobj;
147 output_and_exit( $input, $cookie, $template, 'unknown_vendor') unless $bookseller;
150 ordernumber => $ordernumber,
151 basketno => $basketno,
153 booksellerid => $basket->{'booksellerid'},
154 name => $bookseller->name,
156 output_and_exit( $input, $cookie, $template, 'order_cannot_be_edited' )
157 if $ordernumber and ( $basketobj->closedate || $data->{orderstatus} eq "complete" );
159 my $contract = GetContract({
160 contractnumber => $basket->{contractnumber}
163 my $listprice=0; # the price, that can be in MARC record if we have one
164 if ( $ordernumber eq '' and defined $breedingid ){
165 #we want to import from the breeding reservoir (from a z3950 search)
166 my ($marcrecord, $encoding) = MARCfindbreeding($breedingid);
167 die("Could not find the selected record in the reservoir, bailing") unless $marcrecord;
169 # Remove all the items (952) from the imported record
170 foreach my $item ($marcrecord->field('952')) {
171 $marcrecord->delete_field($item);
176 ($biblionumber,$duplicatetitle) = FindDuplicate($marcrecord);
177 if($biblionumber && $op ne 'cud-use_external_source') {
178 #if duplicate record found and user did not decide yet, first warn user
179 #and let them choose between using a new record or an existing record
180 Load_Duplicate($duplicatetitle);
183 #from this point: add a new record
184 C4::Acquisition::FillWithDefaultValues($marcrecord, {only_mandatory => 1});
186 ( $biblionumber, $bibitemnum ) = AddBiblio( $marcrecord, $frameworkcode );
187 # get the price if there is one.
188 $listprice = GetMarcPrice($marcrecord, $marcflavour);
189 SetImportRecordStatus( $breedingid, 'imported' );
191 SetMatchedBiblionumber( $breedingid, $biblionumber );
196 my ( @order_user_ids, @order_users, @catalog_details );
197 our $tagslib = GetMarcStructure(1, 'ACQ', { unsafe => 1 } );
198 my ( $itemnumber_tag, $itemnumber_subtag ) = GetMarcFromKohaField( 'items.itemnumber' );
199 if ( not $ordernumber ) { # create order
202 if ( $biblionumber ) {
203 $data = GetBiblioData($biblionumber);
205 # get suggestion fields if applicable. If it's a subscription renewal, then the biblio already exists
206 # otherwise, retrieve suggestion information.
207 elsif ($suggestionid) {
208 $data = GetSuggestion($suggestionid);
209 $data->{quantitysugg} = $data->{quantity};
210 undef $data->{quantity};
211 $budget_id ||= $data->{'budgetid'} // 0;
214 if ( not $biblionumber and Koha::BiblioFrameworks->find('ACQ') ) {
215 my $biblio_form_builder = Koha::UI::Form::Builder::Biblio->new();
216 foreach my $tag ( sort keys %{$tagslib} ) {
218 next if $tag eq $itemnumber_tag; # skip items fields
219 my $index_tag = int(rand(1000000));
220 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
221 my $mss = $tagslib->{$tag}{$subfield};
222 next if IsMarcStructureInternal($mss);
223 next if $mss->{tab} == -1;
224 my $value = $mss->{defaultvalue};
226 if ($suggestionid and $mss->{kohafield}) {
227 # Reading suggestion info if ordering from a suggestion
228 if ( $mss->{kohafield} eq 'biblio.title' ) {
229 $value = $data->{title};
231 elsif ( $mss->{kohafield} eq 'biblio.author' ) {
232 $value = $data->{author};
234 elsif ( $mss->{kohafield} eq 'biblioitems.publishercode' ) {
235 $value = $data->{publishercode};
237 elsif ( $mss->{kohafield} eq 'biblioitems.editionstatement' ) {
238 $value = $data->{editionstatement};
240 elsif ( $mss->{kohafield} eq 'biblioitems.publicationyear' ) {
241 $value = $data->{publicationyear};
243 elsif ( $mss->{kohafield} eq 'biblioitems.isbn' ) {
244 $value = $data->{isbn};
246 elsif ( $mss->{kohafield} eq 'biblio.seriestitle' ) {
247 $value = $data->{seriestitle};
251 push @catalog_details, $biblio_form_builder->generate_subfield_form(
254 subfield => $subfield,
256 index_tag => $index_tag,
265 $budget_id = $data->{'budget_id'};
268 subscriptionid => $data->{subscriptionid},
271 $basket = GetBasket( $data->{'basketno'} );
272 $basketno = $basket->{'basketno'};
274 @order_user_ids = GetOrderUsers($ordernumber);
275 foreach my $order_user_id (@order_user_ids) {
276 # FIXME Could be improved with search -in
277 my $order_patron = Koha::Patrons->find( $order_user_id );
278 push @order_users, $order_patron if $order_patron;
281 $biblionumber = $data->{biblionumber};
284 # - no ordernumber but a biblionumber: from a subscription, from an existing record
285 # - no ordernumber, no biblionumber: from a suggestion, from a new order
286 if ( not $ordernumber or $biblionumber ) {
287 if ( C4::Context->preference('UseACQFrameworkForBiblioRecords') ) {
288 my $biblio = Koha::Biblios->find($biblionumber);
289 my $record = $biblio ? $biblio->metadata->record : undef;
290 my $biblio_form_builder = Koha::UI::Form::Builder::Biblio->new(
292 biblionumber => $biblionumber,
295 foreach my $tag ( sort keys %{$tagslib} ) {
297 next if $tag eq $itemnumber_tag; # skip items fields
298 my @fields = $biblionumber ? $record->field($tag) : ();
299 my $index_tag = int(rand(1000000));
300 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
301 my $mss = $tagslib->{$tag}{$subfield};
302 next if IsMarcStructureInternal($mss);
303 next if $mss->{tab} == -1;
304 # We only need to display the values
305 my $value = join '; ', map { $tag < 10 ? $_->data : $_->subfield( $subfield ) } @fields;
307 push @catalog_details, $biblio_form_builder->generate_subfield_form(
310 subfield => $subfield,
312 index_tag => $index_tag,
323 $template->param( catalog_details => \@catalog_details, );
326 $suggestion = GetSuggestionInfo($suggestionid) if $suggestionid;
328 my $active_currency = Koha::Acquisition::Currencies->get_active;
330 # build bookfund list
331 my $patron = Koha::Patrons->find( $loggedinuser )->unblessed;
333 my $budget = GetBudget($budget_id);
335 my $budget_loop = [];
336 my $budgets = GetBudgetHierarchy;
337 foreach my $r (@{$budgets}) {
338 next unless (CanUserUseBudget($patron, $r, $userflags));
339 push @{$budget_loop}, {
340 b_id => $r->{budget_id},
341 b_txt => $r->{budget_name},
342 b_sort1_authcat => $r->{'sort1_authcat'},
343 b_sort2_authcat => $r->{'sort2_authcat'},
344 b_active => $r->{budget_period_active},
345 b_sel => ( $r->{budget_id} == $budget_id ) ? 1 : 0,
346 b_level => $r->{budget_level},
351 $template->param( sort1 => $data->{'sort1'} );
352 $template->param( sort2 => $data->{'sort2'} );
354 if ( $basketobj->effective_create_items eq 'ordering' ) {
355 # Check if ACQ framework exists
356 my $marc = GetMarcStructure( 1, 'ACQ', { unsafe => 1 } );
358 $template->param( 'NoACQframework' => 1 );
361 AcqCreateItemOrdering => 1,
362 UniqueItemFields => C4::Context->preference('UniqueItemFields'),
366 my @itemtypes = Koha::ItemTypes->search( {}, { order_by => { -asc => "description" } } )->as_list;
368 if ( defined $from_subscriptionid ) {
369 # Get the last received order for this subscription
370 my $lastOrderReceived = Koha::Acquisition::Orders->search(
372 subscriptionid => $from_subscriptionid,
373 datereceived => { '!=' => undef }
377 [ { -desc => 'datereceived' }, { -desc => 'ordernumber' } ]
380 if ( $lastOrderReceived->count ) {
381 $lastOrderReceived = $lastOrderReceived->next->unblessed; # FIXME We should send the object to the template
382 $budget_id = $lastOrderReceived->{budgetid};
383 $data->{listprice} = $lastOrderReceived->{listprice};
384 $data->{uncertainprice} = $lastOrderReceived->{uncertainprice};
385 $data->{tax_rate} = $lastOrderReceived->{tax_rate_on_ordering};
386 $data->{discount} = $lastOrderReceived->{discount};
387 $data->{rrp} = $lastOrderReceived->{rrp};
388 $data->{replacementprice} = $lastOrderReceived->{replacementprice};
389 $data->{ecost} = $lastOrderReceived->{ecost};
390 $data->{quantity} = $lastOrderReceived->{quantity};
391 $data->{unitprice} = $lastOrderReceived->{unitprice};
392 $data->{order_internalnote} = $lastOrderReceived->{order_internalnote};
393 $data->{order_vendornote} = $lastOrderReceived->{order_vendornote};
394 $data->{sort1} = $lastOrderReceived->{sort1};
395 $data->{sort2} = $lastOrderReceived->{sort2};
397 $basket = GetBasket( $input->param('basketno') );
400 my $subscription = Koha::Subscriptions->find($from_subscriptionid);
402 subscriptionid => $from_subscriptionid,
403 subscription => $subscription,
407 # Find the items.barcode subfield for barcode validations
408 my (undef, $barcode_subfield) = GetMarcFromKohaField( 'items.barcode' );
411 # get option values for TaxRates syspref
412 my @gst_values = map {
414 }, split( '\|', C4::Context->preference("TaxRates") );
416 my $quantity = $input->param('rr_quantity_to_order') ?
417 $input->param('rr_quantity_to_order') :
421 # Get additional fields
423 my @additional_fields = Koha::AdditionalFields->search({ tablename => 'aqorders' })->as_list;
424 my %additional_field_values;
427 my $order = Koha::Acquisition::Orders->find($ordernumber);
428 foreach my $value ($order->additional_field_values->as_list) {
429 $additional_field_values{$value->field_id} = $value->value;
431 $items = $order->items;
432 } elsif ( $biblionumber ) {
433 foreach my $af (@additional_fields) {
434 if ($af->marcfield) {
435 $record //= Koha::Biblios->find($biblionumber)->metadata->record;
436 my ($field, $subfield) = split /\$/, $af->marcfield;
437 $additional_field_values{$af->id} = $record->subfield($field, $subfield);
442 additional_fields => \@additional_fields,
443 additional_field_values => \%additional_field_values,
449 existing => $biblionumber,
450 # basket informations
451 basketname => $basket->{'basketname'},
452 basketnote => $basket->{'note'},
453 booksellerid => $basket->{'booksellerid'},
454 basketbooksellernote => $basket->{booksellernote},
455 basketcontractno => $basket->{contractnumber},
456 basketcontractname => $contract->{contractname},
457 creationdate => $basket->{creationdate},
458 authorisedby => $basket->{'authorisedby'},
459 authorisedbyname => $basket->{'authorisedbyname'},
460 closedate => $basket->{'closedate'},
462 suggestionid => $suggestion->{suggestionid},
463 surnamesuggestedby => $suggestion->{surnamesuggestedby},
464 firstnamesuggestedby => $suggestion->{firstnamesuggestedby},
465 biblionumber => $biblionumber,
466 uncertainprice => $data->{'uncertainprice'},
467 discount_2dp => sprintf( "%.2f", $bookseller->discount ) , # for display
468 discount => $bookseller->discount,
469 orderdiscount_2dp => sprintf( "%.2f", $data->{'discount'} || 0 ),
470 orderdiscount => $data->{'discount'},
471 order_internalnote => $data->{'order_internalnote'},
472 order_vendornote => $data->{'order_vendornote'},
473 listincgst => $bookseller->listincgst,
474 invoiceincgst => $bookseller->invoiceincgst,
475 cur_active_sym => $active_currency->symbol,
476 cur_active => $active_currency->currency,
477 currencies => Koha::Acquisition::Currencies->search,
478 currency => $data->{currency},
479 vendor_currency => $bookseller->listprice,
480 orderexists => ( $new eq 'yes' ) ? 0 : 1,
481 title => $data->{'title'},
482 author => $data->{'author'},
483 publicationyear => $data->{'publicationyear'} ? $data->{'publicationyear'} : $data->{'copyrightdate'},
484 editionstatement => $data->{'editionstatement'},
485 budget_loop => $budget_loop,
486 isbn => $data->{'isbn'},
487 ean => $data->{'ean'},
488 seriestitle => $data->{'seriestitle'},
489 itemtypeloop => \@itemtypes,
490 quantity => $quantity,
491 quantityrec => $quantity,
492 quantitysugg => $data->{quantitysugg},
493 rrp => $data->{'rrp'},
494 replacementprice => $data->{'replacementprice'},
495 gst_values => \@gst_values,
496 tax_rate => $data->{tax_rate_on_ordering} ? $data->{tax_rate_on_ordering}+0.0 : $bookseller->tax_rate ? $bookseller->tax_rate+0.0 : 0,
497 listprice => sprintf( "%.2f", $data->{listprice} || $data->{price} || $listprice),
498 total => sprintf( "%.2f", ($data->{ecost} || 0) * ($data->{'quantity'} || 0) ),
499 ecost => sprintf( "%.2f", $data->{ecost} || 0),
500 unitprice => sprintf( "%.2f", $data->{unitprice} || 0),
501 publishercode => $data->{'publishercode'},
502 barcode_subfield => $barcode_subfield,
503 import_batch_id => $import_batch_id,
504 acqcreate => $basketobj->effective_create_items eq "ordering" ? 1 : "",
505 users_ids => join(':', @order_user_ids),
506 users => \@order_users,
507 (uc(C4::Context->preference("marcflavour"))) => 1,
508 estimated_delivery_date => $data->{estimated_delivery_date},
511 output_html_with_http_headers $input, $cookie, $template->output;
514 =head2 MARCfindbreeding
516 $record = MARCfindbreeding($breedingid);
518 Look up the import record repository for the record with
519 record with id $breedingid. If found, returns the decoded
520 MARC::Record; otherwise, -1 is returned (FIXME).
521 Returns as second parameter the character encoding.
525 sub MARCfindbreeding {
527 my ($marc, $encoding) = GetImportRecordMarc($id);
528 # remove the - in isbn, koha store isbn without any -
530 my $record = MARC::Record->new_from_usmarc($marc);
531 my ($isbnfield,$isbnsubfield) = GetMarcFromKohaField( 'biblioitems.isbn' );
532 if ( $record->field($isbnfield) ) {
533 foreach my $field ( $record->field($isbnfield) ) {
534 foreach my $subfield ( $field->subfield($isbnsubfield) ) {
535 my $newisbn = $field->subfield($isbnsubfield);
537 $field->update( $isbnsubfield => $newisbn );
541 # fix the unimarc 100 coded field (with unicode information)
542 if ($marcflavour eq 'UNIMARC' && $record->subfield(100,'a')) {
543 my $f100a=$record->subfield(100,'a');
544 my $f100 = $record->field(100);
545 my $f100temp = $f100->as_string;
546 $record->delete_field($f100);
547 if ( length($f100temp) > 28 ) {
548 substr( $f100temp, 26, 2, "50" );
549 $f100->update( 'a' => $f100temp );
550 my $f100 = MARC::Field->new( '100', '', '', 'a' => $f100temp );
551 $record->insert_fields_ordered($f100);
555 if ( !defined(ref($record)) ) {
559 # normalize author : probably UNIMARC specific...
560 if ( C4::Context->preference("z3950NormalizeAuthor")
561 and C4::Context->preference("z3950AuthorAuthFields") )
563 my ( $tag, $subfield ) = GetMarcFromKohaField( "biblio.author" );
566 C4::Context->preference("z3950AuthorAuthFields");
567 my @auth_fields = split /,/, $auth_fields;
570 if ( $record->field($tag) ) {
571 foreach my $tmpfield ( $record->field($tag)->subfields ) {
573 my $subfieldcode = shift @$tmpfield;
574 my $subfieldvalue = shift @$tmpfield;
576 $field->add_subfields(
577 "$subfieldcode" => $subfieldvalue )
578 if ( $subfieldcode ne $subfield );
582 MARC::Field->new( $tag, "", "",
583 $subfieldcode => $subfieldvalue )
584 if ( $subfieldcode ne $subfield );
588 $record->delete_field( $record->field($tag) );
589 foreach my $fieldtag (@auth_fields) {
590 next unless ( $record->field($fieldtag) );
591 my $lastname = $record->field($fieldtag)->subfield('a');
592 my $firstname = $record->field($fieldtag)->subfield('b');
593 my $title = $record->field($fieldtag)->subfield('c');
594 my $number = $record->field($fieldtag)->subfield('d');
596 $field->add_subfields(
597 "$subfield" => ucfirst($title) . " "
598 . ucfirst($firstname) . " "
602 $field->add_subfields(
603 "$subfield" => ucfirst($firstname) . ", "
604 . ucfirst($lastname) );
607 $record->insert_fields_ordered($field);
609 return $record, $encoding;
616 my ($duplicatetitle)= @_;
617 ($template, $loggedinuser, $cookie) = get_template_and_user(
619 template_name => "acqui/neworderempty_duplicate.tt",
622 flagsrequired => { acquisition => 'order_manage' },
627 biblionumber => $biblionumber,
628 basketno => $basketno,
629 booksellerid => $basket->{'booksellerid'},
630 breedingid => $breedingid,
631 duplicatetitle => $duplicatetitle,
632 (uc(C4::Context->preference("marcflavour"))) => 1
635 output_html_with_http_headers $input, $cookie, $template->output;