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 our $biblionumber = $input->param('biblionumber');
107 our $basketno = $input->param('basketno');
108 our $breedingid = $input->param('breedingid');
109 my $booksellerid = $input->param('booksellerid'); # FIXME: else ERROR!
110 my $budget_id = $input->param('budget_id') || 0;
111 my $title = $input->param('title');
112 my $author = $input->param('author');
113 my $publicationyear = $input->param('publicationyear');
114 my $ordernumber = $input->param('ordernumber') || '';
115 my $suggestionid = $input->param('suggestionid');
116 my $uncertainprice = $input->param('uncertainprice');
117 my $from_subscriptionid = $input->param('from_subscriptionid');
118 my $frameworkcode = $input->param('frameworkcode') // q{};
120 # if this is filled, we come from a staged file, and we will return here after saving the order !
121 my $import_batch_id = $input->param('import_batch_id');
125 my $op = $input->param('op') || q{};
127 our ( $template, $loggedinuser, $cookie, $userflags ) = get_template_and_user(
129 template_name => "acqui/neworderempty.tt",
132 flagsrequired => { acquisition => 'order_manage' },
136 our $marcflavour = C4::Context->preference('marcflavour');
139 my $order = GetOrder($ordernumber);
140 $basketno = $order->{'basketno'};
143 our $basket = GetBasket($basketno);
144 my $basketobj = Koha::Acquisition::Baskets->find($basketno);
145 $booksellerid = $basket->{booksellerid} unless $booksellerid;
146 my $bookseller = Koha::Acquisition::Booksellers->find($booksellerid);
147 $data = GetOrder($ordernumber) if $ordernumber;
149 output_and_exit( $input, $cookie, $template, 'unknown_basket') unless $basketobj;
150 output_and_exit( $input, $cookie, $template, 'unknown_vendor') unless $bookseller;
153 ordernumber => $ordernumber,
154 basketno => $basketno,
156 booksellerid => $basket->{'booksellerid'},
157 name => $bookseller->name,
159 output_and_exit( $input, $cookie, $template, 'order_cannot_be_edited' )
160 if $ordernumber and ( $basketobj->closedate || $data->{orderstatus} eq "complete" );
162 my $contract = GetContract({
163 contractnumber => $basket->{contractnumber}
166 my $listprice=0; # the price, that can be in MARC record if we have one
167 if ( $ordernumber eq '' and defined $breedingid ){
168 #we want to import from the breeding reservoir (from a z3950 search)
169 my ($marcrecord, $encoding) = MARCfindbreeding($breedingid);
170 die("Could not find the selected record in the reservoir, bailing") unless $marcrecord;
172 # Remove all the items (952) from the imported record
173 foreach my $item ($marcrecord->field('952')) {
174 $marcrecord->delete_field($item);
179 ($biblionumber,$duplicatetitle) = FindDuplicate($marcrecord);
180 if($biblionumber && $op ne 'cud-use_external_source') {
181 #if duplicate record found and user did not decide yet, first warn user
182 #and let them choose between using a new record or an existing record
183 Load_Duplicate($duplicatetitle);
186 #from this point: add a new record
187 C4::Acquisition::FillWithDefaultValues($marcrecord, {only_mandatory => 1});
189 ( $biblionumber, $bibitemnum ) = AddBiblio( $marcrecord, $frameworkcode );
190 # get the price if there is one.
191 $listprice = GetMarcPrice($marcrecord, $marcflavour);
192 SetImportRecordStatus( $breedingid, 'imported' );
194 SetMatchedBiblionumber( $breedingid, $biblionumber );
199 my ( @order_user_ids, @order_users, @catalog_details );
200 our $tagslib = GetMarcStructure(1, 'ACQ', { unsafe => 1 } );
201 my ( $itemnumber_tag, $itemnumber_subtag ) = GetMarcFromKohaField( 'items.itemnumber' );
202 if ( not $ordernumber ) { # create order
205 if ( $biblionumber ) {
206 $data = GetBiblioData($biblionumber);
208 # get suggestion fields if applicable. If it's a subscription renewal, then the biblio already exists
209 # otherwise, retrieve suggestion information.
210 elsif ($suggestionid) {
211 $data = GetSuggestion($suggestionid);
212 $data->{quantitysugg} = $data->{quantity};
213 undef $data->{quantity};
214 $budget_id ||= $data->{'budgetid'} // 0;
217 if ( not $biblionumber and Koha::BiblioFrameworks->find('ACQ') ) {
218 my $biblio_form_builder = Koha::UI::Form::Builder::Biblio->new();
219 foreach my $tag ( sort keys %{$tagslib} ) {
221 next if $tag eq $itemnumber_tag; # skip items fields
222 my $index_tag = int(rand(1000000));
223 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
224 my $mss = $tagslib->{$tag}{$subfield};
225 next if IsMarcStructureInternal($mss);
226 next if $mss->{tab} == -1;
227 my $value = $mss->{defaultvalue};
229 if ($suggestionid and $mss->{kohafield}) {
230 # Reading suggestion info if ordering from a suggestion
231 if ( $mss->{kohafield} eq 'biblio.title' ) {
232 $value = $data->{title};
234 elsif ( $mss->{kohafield} eq 'biblio.author' ) {
235 $value = $data->{author};
237 elsif ( $mss->{kohafield} eq 'biblioitems.publishercode' ) {
238 $value = $data->{publishercode};
240 elsif ( $mss->{kohafield} eq 'biblioitems.editionstatement' ) {
241 $value = $data->{editionstatement};
243 elsif ( $mss->{kohafield} eq 'biblioitems.publicationyear' ) {
244 $value = $data->{publicationyear};
246 elsif ( $mss->{kohafield} eq 'biblioitems.isbn' ) {
247 $value = $data->{isbn};
249 elsif ( $mss->{kohafield} eq 'biblio.seriestitle' ) {
250 $value = $data->{seriestitle};
254 push @catalog_details, $biblio_form_builder->generate_subfield_form(
257 subfield => $subfield,
259 index_tag => $index_tag,
268 $budget_id = $data->{'budget_id'};
271 subscriptionid => $data->{subscriptionid},
274 $basket = GetBasket( $data->{'basketno'} );
275 $basketno = $basket->{'basketno'};
277 @order_user_ids = GetOrderUsers($ordernumber);
278 foreach my $order_user_id (@order_user_ids) {
279 # FIXME Could be improved with search -in
280 my $order_patron = Koha::Patrons->find( $order_user_id );
281 push @order_users, $order_patron if $order_patron;
284 $biblionumber = $data->{biblionumber};
287 # - no ordernumber but a biblionumber: from a subscription, from an existing record
288 # - no ordernumber, no biblionumber: from a suggestion, from a new order
289 if ( not $ordernumber or $biblionumber ) {
290 if ( C4::Context->preference('UseACQFrameworkForBiblioRecords') ) {
291 my $biblio = Koha::Biblios->find($biblionumber);
292 my $record = $biblio ? $biblio->metadata->record : undef;
293 my $biblio_form_builder = Koha::UI::Form::Builder::Biblio->new(
295 biblionumber => $biblionumber,
298 foreach my $tag ( sort keys %{$tagslib} ) {
300 next if $tag eq $itemnumber_tag; # skip items fields
301 my @fields = $biblionumber ? $record->field($tag) : ();
302 my $index_tag = int(rand(1000000));
303 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
304 my $mss = $tagslib->{$tag}{$subfield};
305 next if IsMarcStructureInternal($mss);
306 next if $mss->{tab} == -1;
307 # We only need to display the values
308 my $value = join '; ', map { $tag < 10 ? $_->data : $_->subfield( $subfield ) } @fields;
310 push @catalog_details, $biblio_form_builder->generate_subfield_form(
313 subfield => $subfield,
315 index_tag => $index_tag,
326 $template->param( catalog_details => \@catalog_details, );
329 $suggestion = GetSuggestionInfo($suggestionid) if $suggestionid;
331 my $active_currency = Koha::Acquisition::Currencies->get_active;
333 # build bookfund list
334 my $patron = Koha::Patrons->find( $loggedinuser )->unblessed;
336 my $budget = GetBudget($budget_id);
338 my $budget_loop = [];
339 my $budgets = GetBudgetHierarchy;
340 foreach my $r (@{$budgets}) {
341 next unless (CanUserUseBudget($patron, $r, $userflags));
342 push @{$budget_loop}, {
343 b_id => $r->{budget_id},
344 b_txt => $r->{budget_name},
345 b_sort1_authcat => $r->{'sort1_authcat'},
346 b_sort2_authcat => $r->{'sort2_authcat'},
347 b_active => $r->{budget_period_active},
348 b_sel => ( $r->{budget_id} == $budget_id ) ? 1 : 0,
349 b_level => $r->{budget_level},
354 $template->param( sort1 => $data->{'sort1'} );
355 $template->param( sort2 => $data->{'sort2'} );
357 if ( $basketobj->effective_create_items eq 'ordering' ) {
358 # Check if ACQ framework exists
359 my $marc = GetMarcStructure( 1, 'ACQ', { unsafe => 1 } );
361 $template->param( 'NoACQframework' => 1 );
364 AcqCreateItemOrdering => 1,
365 UniqueItemFields => C4::Context->preference('UniqueItemFields'),
369 my @itemtypes = Koha::ItemTypes->search( {}, { order_by => { -asc => "description" } } )->as_list;
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') :
424 # Get additional fields
426 my @additional_fields = Koha::AdditionalFields->search({ tablename => 'aqorders' })->as_list;
427 my %additional_field_values;
430 my $order = Koha::Acquisition::Orders->find($ordernumber);
431 foreach my $value ($order->additional_field_values->as_list) {
432 $additional_field_values{$value->field_id} = $value->value;
434 $items = $order->items;
435 } elsif ( $biblionumber ) {
436 foreach my $af (@additional_fields) {
437 if ($af->marcfield) {
438 $record //= Koha::Biblios->find($biblionumber)->metadata->record;
439 my ($field, $subfield) = split /\$/, $af->marcfield;
440 $additional_field_values{$af->id} = $record->subfield($field, $subfield);
445 additional_fields => \@additional_fields,
446 additional_field_values => \%additional_field_values,
452 existing => $biblionumber,
454 # basket informations
455 basketname => $basket->{'basketname'},
456 basketnote => $basket->{'note'},
457 booksellerid => $basket->{'booksellerid'},
458 basketbooksellernote => $basket->{booksellernote},
459 basketcontractno => $basket->{contractnumber},
460 basketcontractname => $contract->{contractname},
461 creationdate => $basket->{creationdate},
462 authorisedby => $basket->{'authorisedby'},
463 authorisedbyname => $basket->{'authorisedbyname'},
464 closedate => $basket->{'closedate'},
467 suggestionid => $suggestion->{suggestionid},
468 surnamesuggestedby => $suggestion->{surnamesuggestedby},
469 firstnamesuggestedby => $suggestion->{firstnamesuggestedby},
470 biblionumber => $biblionumber,
471 uncertainprice => $data->{'uncertainprice'},
472 discount_2dp => sprintf( "%.2f", $bookseller->discount ), # for display
473 discount => $bookseller->discount,
474 orderdiscount_2dp => sprintf( "%.2f", $data->{'discount'} || 0 ),
475 orderdiscount => $data->{'discount'},
476 order_internalnote => $data->{'order_internalnote'},
477 order_vendornote => $data->{'order_vendornote'},
478 listincgst => $bookseller->listincgst,
479 invoiceincgst => $bookseller->invoiceincgst,
480 cur_active_sym => $active_currency->symbol,
481 cur_active => $active_currency->currency,
482 currencies => Koha::Acquisition::Currencies->search,
483 currency => $data->{currency},
484 vendor_currency => $bookseller->listprice,
485 orderexists => ( $new eq 'yes' ) ? 0 : 1,
486 title => $data->{'title'},
487 author => $data->{'author'},
488 publicationyear => $data->{'publicationyear'} ? $data->{'publicationyear'} : $data->{'copyrightdate'},
489 editionstatement => $data->{'editionstatement'},
490 budget_loop => $budget_loop,
491 isbn => $data->{'isbn'},
492 ean => $data->{'ean'},
493 seriestitle => $data->{'seriestitle'},
494 itemtypeloop => \@itemtypes,
495 quantity => $quantity,
496 quantityrec => $quantity,
497 quantitysugg => $data->{quantitysugg},
498 rrp => $data->{'rrp'},
499 replacementprice => $data->{'replacementprice'},
500 gst_values => \@gst_values,
501 tax_rate => $data->{tax_rate_on_ordering} ? $data->{tax_rate_on_ordering} + 0.0
502 : $bookseller->tax_rate ? $bookseller->tax_rate + 0.0
504 listprice => sprintf( "%.2f", $data->{listprice} || $data->{price} || $listprice ),
505 total => sprintf( "%.2f", ( $data->{ecost} || 0 ) * ( $data->{'quantity'} || 0 ) ),
506 ecost => sprintf( "%.2f", $data->{ecost} || 0 ),
507 unitprice => sprintf( "%.2f", $data->{unitprice} || 0 ),
508 publishercode => $data->{'publishercode'},
509 barcode_subfield => $barcode_subfield,
510 import_batch_id => $import_batch_id,
511 acqcreate => $basketobj->effective_create_items eq "ordering" ? 1 : "",
512 users_ids => join( ':', @order_user_ids ),
513 users => \@order_users,
514 ( uc( C4::Context->preference("marcflavour") ) ) => 1,
515 estimated_delivery_date => $data->{estimated_delivery_date},
518 output_html_with_http_headers $input, $cookie, $template->output;
521 =head2 MARCfindbreeding
523 $record = MARCfindbreeding($breedingid);
525 Look up the import record repository for the record with
526 record with id $breedingid. If found, returns the decoded
527 MARC::Record; otherwise, -1 is returned (FIXME).
528 Returns as second parameter the character encoding.
532 sub MARCfindbreeding {
534 my ($marc, $encoding) = GetImportRecordMarc($id);
535 # remove the - in isbn, koha store isbn without any -
537 my $record = MARC::Record->new_from_usmarc($marc);
538 my ($isbnfield,$isbnsubfield) = GetMarcFromKohaField( 'biblioitems.isbn' );
539 if ( $record->field($isbnfield) ) {
540 foreach my $field ( $record->field($isbnfield) ) {
541 foreach my $subfield ( $field->subfield($isbnsubfield) ) {
542 my $newisbn = $field->subfield($isbnsubfield);
544 $field->update( $isbnsubfield => $newisbn );
548 # fix the unimarc 100 coded field (with unicode information)
549 if ($marcflavour eq 'UNIMARC' && $record->subfield(100,'a')) {
550 my $f100a=$record->subfield(100,'a');
551 my $f100 = $record->field(100);
552 my $f100temp = $f100->as_string;
553 $record->delete_field($f100);
554 if ( length($f100temp) > 28 ) {
555 substr( $f100temp, 26, 2, "50" );
556 $f100->update( 'a' => $f100temp );
557 my $f100 = MARC::Field->new( '100', '', '', 'a' => $f100temp );
558 $record->insert_fields_ordered($f100);
562 if ( !defined(ref($record)) ) {
566 # normalize author : probably UNIMARC specific...
567 if ( C4::Context->preference("z3950NormalizeAuthor")
568 and C4::Context->preference("z3950AuthorAuthFields") )
570 my ( $tag, $subfield ) = GetMarcFromKohaField( "biblio.author" );
573 C4::Context->preference("z3950AuthorAuthFields");
574 my @auth_fields = split /,/, $auth_fields;
577 if ( $record->field($tag) ) {
578 foreach my $tmpfield ( $record->field($tag)->subfields ) {
580 my $subfieldcode = shift @$tmpfield;
581 my $subfieldvalue = shift @$tmpfield;
583 $field->add_subfields(
584 "$subfieldcode" => $subfieldvalue )
585 if ( $subfieldcode ne $subfield );
589 MARC::Field->new( $tag, "", "",
590 $subfieldcode => $subfieldvalue )
591 if ( $subfieldcode ne $subfield );
595 $record->delete_field( $record->field($tag) );
596 foreach my $fieldtag (@auth_fields) {
597 next unless ( $record->field($fieldtag) );
598 my $lastname = $record->field($fieldtag)->subfield('a');
599 my $firstname = $record->field($fieldtag)->subfield('b');
600 my $title = $record->field($fieldtag)->subfield('c');
601 my $number = $record->field($fieldtag)->subfield('d');
603 $field->add_subfields(
604 "$subfield" => ucfirst($title) . " "
605 . ucfirst($firstname) . " "
609 $field->add_subfields(
610 "$subfield" => ucfirst($firstname) . ", "
611 . ucfirst($lastname) );
614 $record->insert_fields_ordered($field);
616 return $record, $encoding;
623 my ($duplicatetitle)= @_;
624 ($template, $loggedinuser, $cookie) = get_template_and_user(
626 template_name => "acqui/neworderempty_duplicate.tt",
629 flagsrequired => { acquisition => 'order_manage' },
634 biblionumber => $biblionumber,
635 basketno => $basketno,
636 booksellerid => $basket->{'booksellerid'},
637 breedingid => $breedingid,
638 duplicatetitle => $duplicatetitle,
639 (uc(C4::Context->preference("marcflavour"))) => 1
642 output_html_with_http_headers $input, $cookie, $template->output;