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');
120 my $op = $input->param('op') || q{};
122 our ( $template, $loggedinuser, $cookie, $userflags ) = get_template_and_user(
124 template_name => "acqui/neworderempty.tt",
127 flagsrequired => { acquisition => 'order_manage' },
131 our $marcflavour = C4::Context->preference('marcflavour');
134 my $order = GetOrder($ordernumber);
135 $basketno = $order->{'basketno'};
138 our $basket = GetBasket($basketno);
139 my $basketobj = Koha::Acquisition::Baskets->find($basketno);
140 $booksellerid = $basket->{booksellerid} unless $booksellerid;
141 my $bookseller = Koha::Acquisition::Booksellers->find($booksellerid);
142 $data = GetOrder($ordernumber) if $ordernumber;
144 output_and_exit( $input, $cookie, $template, 'unknown_basket') unless $basketobj;
145 output_and_exit( $input, $cookie, $template, 'unknown_vendor') unless $bookseller;
148 ordernumber => $ordernumber,
149 basketno => $basketno,
151 booksellerid => $basket->{'booksellerid'},
152 name => $bookseller->name,
154 output_and_exit( $input, $cookie, $template, 'order_cannot_be_edited' )
155 if $ordernumber and ( $basketobj->closedate || $data->{orderstatus} eq "complete" );
157 my $contract = GetContract({
158 contractnumber => $basket->{contractnumber}
161 #simple parameters reading (all in one :-)
162 our $params = $input->Vars;
163 my $listprice=0; # the price, that can be in MARC record if we have one
164 if ( $ordernumber eq '' and defined $params->{'breedingid'}){
165 #we want to import from the breeding reservoir (from a z3950 search)
166 my ($marcrecord, $encoding) = MARCfindbreeding($params->{'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 $params->{'frameworkcode'} or $params->{'frameworkcode'} = "";
187 ( $biblionumber, $bibitemnum ) = AddBiblio( $marcrecord, $params->{'frameworkcode'} );
188 # get the price if there is one.
189 $listprice = GetMarcPrice($marcrecord, $marcflavour);
190 SetImportRecordStatus($params->{'breedingid'}, 'imported');
192 SetMatchedBiblionumber( $params->{breedingid}, $biblionumber );
197 my ( @order_user_ids, @order_users, @catalog_details );
198 our $tagslib = GetMarcStructure(1, 'ACQ', { unsafe => 1 } );
199 my ( $itemnumber_tag, $itemnumber_subtag ) = GetMarcFromKohaField( 'items.itemnumber' );
200 if ( not $ordernumber ) { # create order
203 if ( $biblionumber ) {
204 $data = GetBiblioData($biblionumber);
206 # get suggestion fields if applicable. If it's a subscription renewal, then the biblio already exists
207 # otherwise, retrieve suggestion information.
208 elsif ($suggestionid) {
209 $data = GetSuggestion($suggestionid);
210 $budget_id ||= $data->{'budgetid'} // 0;
213 if ( not $biblionumber and Koha::BiblioFrameworks->find('ACQ') ) {
214 my $biblio_form_builder = Koha::UI::Form::Builder::Biblio->new();
215 foreach my $tag ( sort keys %{$tagslib} ) {
217 next if $tag eq $itemnumber_tag; # skip items fields
218 my $index_tag = int(rand(1000000));
219 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
220 my $mss = $tagslib->{$tag}{$subfield};
221 next if IsMarcStructureInternal($mss);
222 next if $mss->{tab} == -1;
223 my $value = $mss->{defaultvalue};
225 if ($suggestionid and $mss->{kohafield}) {
226 # Reading suggestion info if ordering from a suggestion
227 if ( $mss->{kohafield} eq 'biblio.title' ) {
228 $value = $data->{title};
230 elsif ( $mss->{kohafield} eq 'biblio.author' ) {
231 $value = $data->{author};
233 elsif ( $mss->{kohafield} eq 'biblioitems.publishercode' ) {
234 $value = $data->{publishercode};
236 elsif ( $mss->{kohafield} eq 'biblioitems.editionstatement' ) {
237 $value = $data->{editionstatement};
239 elsif ( $mss->{kohafield} eq 'biblioitems.publicationyear' ) {
240 $value = $data->{publicationyear};
242 elsif ( $mss->{kohafield} eq 'biblioitems.isbn' ) {
243 $value = $data->{isbn};
245 elsif ( $mss->{kohafield} eq 'biblio.seriestitle' ) {
246 $value = $data->{seriestitle};
250 push @catalog_details, $biblio_form_builder->generate_subfield_form(
253 subfield => $subfield,
255 index_tag => $index_tag,
264 $budget_id = $data->{'budget_id'};
267 subscriptionid => $data->{subscriptionid},
270 $basket = GetBasket( $data->{'basketno'} );
271 $basketno = $basket->{'basketno'};
273 @order_user_ids = GetOrderUsers($ordernumber);
274 foreach my $order_user_id (@order_user_ids) {
275 # FIXME Could be improved with search -in
276 my $order_patron = Koha::Patrons->find( $order_user_id );
277 push @order_users, $order_patron if $order_patron;
280 $biblionumber = $data->{biblionumber};
283 # - no ordernumber but a biblionumber: from a subscription, from an existing record
284 # - no ordernumber, no biblionumber: from a suggestion, from a new order
285 if ( not $ordernumber or $biblionumber ) {
286 if ( C4::Context->preference('UseACQFrameworkForBiblioRecords') ) {
287 my $biblio = Koha::Biblios->find($biblionumber);
288 my $record = $biblio ? $biblio->metadata->record : undef;
289 my $biblio_form_builder = Koha::UI::Form::Builder::Biblio->new(
291 biblionumber => $biblionumber,
294 foreach my $tag ( sort keys %{$tagslib} ) {
296 next if $tag eq $itemnumber_tag; # skip items fields
297 my @fields = $biblionumber ? $record->field($tag) : ();
298 my $index_tag = int(rand(1000000));
299 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
300 my $mss = $tagslib->{$tag}{$subfield};
301 next if IsMarcStructureInternal($mss);
302 next if $mss->{tab} == -1;
303 # We only need to display the values
304 my $value = join '; ', map { $tag < 10 ? $_->data : $_->subfield( $subfield ) } @fields;
306 push @catalog_details, $biblio_form_builder->generate_subfield_form(
309 subfield => $subfield,
311 index_tag => $index_tag,
322 $template->param( catalog_details => \@catalog_details, );
325 $suggestion = GetSuggestionInfo($suggestionid) if $suggestionid;
327 my $active_currency = Koha::Acquisition::Currencies->get_active;
329 # build bookfund list
330 my $patron = Koha::Patrons->find( $loggedinuser )->unblessed;
332 my $budget = GetBudget($budget_id);
334 my $budget_loop = [];
335 my $budgets = GetBudgetHierarchy;
336 foreach my $r (@{$budgets}) {
337 next unless (CanUserUseBudget($patron, $r, $userflags));
338 push @{$budget_loop}, {
339 b_id => $r->{budget_id},
340 b_txt => $r->{budget_name},
341 b_sort1_authcat => $r->{'sort1_authcat'},
342 b_sort2_authcat => $r->{'sort2_authcat'},
343 b_active => $r->{budget_period_active},
344 b_sel => ( $r->{budget_id} == $budget_id ) ? 1 : 0,
345 b_level => $r->{budget_level},
350 $template->param( sort1 => $data->{'sort1'} );
351 $template->param( sort2 => $data->{'sort2'} );
353 if ( $basketobj->effective_create_items eq 'ordering' ) {
354 # Check if ACQ framework exists
355 my $marc = GetMarcStructure( 1, 'ACQ', { unsafe => 1 } );
357 $template->param( 'NoACQframework' => 1 );
360 AcqCreateItemOrdering => 1,
361 UniqueItemFields => C4::Context->preference('UniqueItemFields'),
365 my @itemtypes = Koha::ItemTypes->search( {}, { order_by => { -asc => "description" } } )->as_list;
367 if ( defined $from_subscriptionid ) {
368 # Get the last received order for this subscription
369 my $lastOrderReceived = Koha::Acquisition::Orders->search(
371 subscriptionid => $from_subscriptionid,
372 datereceived => { '!=' => undef }
376 [ { -desc => 'datereceived' }, { -desc => 'ordernumber' } ]
379 if ( $lastOrderReceived->count ) {
380 $lastOrderReceived = $lastOrderReceived->next->unblessed; # FIXME We should send the object to the template
381 $budget_id = $lastOrderReceived->{budgetid};
382 $data->{listprice} = $lastOrderReceived->{listprice};
383 $data->{uncertainprice} = $lastOrderReceived->{uncertainprice};
384 $data->{tax_rate} = $lastOrderReceived->{tax_rate_on_ordering};
385 $data->{discount} = $lastOrderReceived->{discount};
386 $data->{rrp} = $lastOrderReceived->{rrp};
387 $data->{replacementprice} = $lastOrderReceived->{replacementprice};
388 $data->{ecost} = $lastOrderReceived->{ecost};
389 $data->{quantity} = $lastOrderReceived->{quantity};
390 $data->{unitprice} = $lastOrderReceived->{unitprice};
391 $data->{order_internalnote} = $lastOrderReceived->{order_internalnote};
392 $data->{order_vendornote} = $lastOrderReceived->{order_vendornote};
393 $data->{sort1} = $lastOrderReceived->{sort1};
394 $data->{sort2} = $lastOrderReceived->{sort2};
396 $basket = GetBasket( $input->param('basketno') );
399 my $subscription = Koha::Subscriptions->find($from_subscriptionid);
401 subscriptionid => $from_subscriptionid,
402 subscription => $subscription,
406 # Find the items.barcode subfield for barcode validations
407 my (undef, $barcode_subfield) = GetMarcFromKohaField( 'items.barcode' );
410 # get option values for TaxRates syspref
411 my @gst_values = map {
413 }, split( '\|', C4::Context->preference("TaxRates") );
415 my $quantity = $input->param('rr_quantity_to_order') ?
416 $input->param('rr_quantity_to_order') :
420 # Get additional fields
422 my @additional_fields = Koha::AdditionalFields->search({ tablename => 'aqorders' })->as_list;
423 my %additional_field_values;
426 my $order = Koha::Acquisition::Orders->find($ordernumber);
427 foreach my $value ($order->additional_field_values->as_list) {
428 $additional_field_values{$value->field_id} = $value->value;
430 $items = $order->items;
431 } elsif ( $biblionumber ) {
432 foreach my $af (@additional_fields) {
433 if ($af->marcfield) {
434 $record //= Koha::Biblios->find($biblionumber)->metadata->record;
435 my ($field, $subfield) = split /\$/, $af->marcfield;
436 $additional_field_values{$af->id} = $record->subfield($field, $subfield);
441 additional_fields => \@additional_fields,
442 additional_field_values => \%additional_field_values,
448 existing => $biblionumber,
449 # basket informations
450 basketname => $basket->{'basketname'},
451 basketnote => $basket->{'note'},
452 booksellerid => $basket->{'booksellerid'},
453 basketbooksellernote => $basket->{booksellernote},
454 basketcontractno => $basket->{contractnumber},
455 basketcontractname => $contract->{contractname},
456 creationdate => $basket->{creationdate},
457 authorisedby => $basket->{'authorisedby'},
458 authorisedbyname => $basket->{'authorisedbyname'},
459 closedate => $basket->{'closedate'},
461 suggestionid => $suggestion->{suggestionid},
462 surnamesuggestedby => $suggestion->{surnamesuggestedby},
463 firstnamesuggestedby => $suggestion->{firstnamesuggestedby},
464 biblionumber => $biblionumber,
465 uncertainprice => $data->{'uncertainprice'},
466 discount_2dp => sprintf( "%.2f", $bookseller->discount ) , # for display
467 discount => $bookseller->discount,
468 orderdiscount_2dp => sprintf( "%.2f", $data->{'discount'} || 0 ),
469 orderdiscount => $data->{'discount'},
470 order_internalnote => $data->{'order_internalnote'},
471 order_vendornote => $data->{'order_vendornote'},
472 listincgst => $bookseller->listincgst,
473 invoiceincgst => $bookseller->invoiceincgst,
474 cur_active_sym => $active_currency->symbol,
475 cur_active => $active_currency->currency,
476 currencies => Koha::Acquisition::Currencies->search,
477 currency => $data->{currency},
478 vendor_currency => $bookseller->listprice,
479 orderexists => ( $new eq 'yes' ) ? 0 : 1,
480 title => $data->{'title'},
481 author => $data->{'author'},
482 publicationyear => $data->{'publicationyear'} ? $data->{'publicationyear'} : $data->{'copyrightdate'},
483 editionstatement => $data->{'editionstatement'},
484 budget_loop => $budget_loop,
485 isbn => $data->{'isbn'},
486 ean => $data->{'ean'},
487 seriestitle => $data->{'seriestitle'},
488 itemtypeloop => \@itemtypes,
489 quantity => $quantity,
490 quantityrec => $quantity,
491 rrp => $data->{'rrp'},
492 replacementprice => $data->{'replacementprice'},
493 gst_values => \@gst_values,
494 tax_rate => $data->{tax_rate_on_ordering} ? $data->{tax_rate_on_ordering}+0.0 : $bookseller->tax_rate ? $bookseller->tax_rate+0.0 : 0,
495 listprice => sprintf( "%.2f", $data->{listprice} || $data->{price} || $listprice),
496 total => sprintf( "%.2f", ($data->{ecost} || 0) * ($data->{'quantity'} || 0) ),
497 ecost => sprintf( "%.2f", $data->{ecost} || 0),
498 unitprice => sprintf( "%.2f", $data->{unitprice} || 0),
499 publishercode => $data->{'publishercode'},
500 barcode_subfield => $barcode_subfield,
501 import_batch_id => $import_batch_id,
502 acqcreate => $basketobj->effective_create_items eq "ordering" ? 1 : "",
503 users_ids => join(':', @order_user_ids),
504 users => \@order_users,
505 (uc(C4::Context->preference("marcflavour"))) => 1,
506 estimated_delivery_date => $data->{estimated_delivery_date},
509 output_html_with_http_headers $input, $cookie, $template->output;
512 =head2 MARCfindbreeding
514 $record = MARCfindbreeding($breedingid);
516 Look up the import record repository for the record with
517 record with id $breedingid. If found, returns the decoded
518 MARC::Record; otherwise, -1 is returned (FIXME).
519 Returns as second parameter the character encoding.
523 sub MARCfindbreeding {
525 my ($marc, $encoding) = GetImportRecordMarc($id);
526 # remove the - in isbn, koha store isbn without any -
528 my $record = MARC::Record->new_from_usmarc($marc);
529 my ($isbnfield,$isbnsubfield) = GetMarcFromKohaField( 'biblioitems.isbn' );
530 if ( $record->field($isbnfield) ) {
531 foreach my $field ( $record->field($isbnfield) ) {
532 foreach my $subfield ( $field->subfield($isbnsubfield) ) {
533 my $newisbn = $field->subfield($isbnsubfield);
535 $field->update( $isbnsubfield => $newisbn );
539 # fix the unimarc 100 coded field (with unicode information)
540 if ($marcflavour eq 'UNIMARC' && $record->subfield(100,'a')) {
541 my $f100a=$record->subfield(100,'a');
542 my $f100 = $record->field(100);
543 my $f100temp = $f100->as_string;
544 $record->delete_field($f100);
545 if ( length($f100temp) > 28 ) {
546 substr( $f100temp, 26, 2, "50" );
547 $f100->update( 'a' => $f100temp );
548 my $f100 = MARC::Field->new( '100', '', '', 'a' => $f100temp );
549 $record->insert_fields_ordered($f100);
553 if ( !defined(ref($record)) ) {
557 # normalize author : probably UNIMARC specific...
558 if ( C4::Context->preference("z3950NormalizeAuthor")
559 and C4::Context->preference("z3950AuthorAuthFields") )
561 my ( $tag, $subfield ) = GetMarcFromKohaField( "biblio.author" );
564 C4::Context->preference("z3950AuthorAuthFields");
565 my @auth_fields = split /,/, $auth_fields;
568 if ( $record->field($tag) ) {
569 foreach my $tmpfield ( $record->field($tag)->subfields ) {
571 my $subfieldcode = shift @$tmpfield;
572 my $subfieldvalue = shift @$tmpfield;
574 $field->add_subfields(
575 "$subfieldcode" => $subfieldvalue )
576 if ( $subfieldcode ne $subfield );
580 MARC::Field->new( $tag, "", "",
581 $subfieldcode => $subfieldvalue )
582 if ( $subfieldcode ne $subfield );
586 $record->delete_field( $record->field($tag) );
587 foreach my $fieldtag (@auth_fields) {
588 next unless ( $record->field($fieldtag) );
589 my $lastname = $record->field($fieldtag)->subfield('a');
590 my $firstname = $record->field($fieldtag)->subfield('b');
591 my $title = $record->field($fieldtag)->subfield('c');
592 my $number = $record->field($fieldtag)->subfield('d');
594 $field->add_subfields(
595 "$subfield" => ucfirst($title) . " "
596 . ucfirst($firstname) . " "
600 $field->add_subfields(
601 "$subfield" => ucfirst($firstname) . ", "
602 . ucfirst($lastname) );
605 $record->insert_fields_ordered($field);
607 return $record, $encoding;
614 my ($duplicatetitle)= @_;
615 ($template, $loggedinuser, $cookie) = get_template_and_user(
617 template_name => "acqui/neworderempty_duplicate.tt",
620 flagsrequired => { acquisition => 'order_manage' },
625 biblionumber => $biblionumber,
626 basketno => $basketno,
627 booksellerid => $basket->{'booksellerid'},
628 breedingid => $params->{'breedingid'},
629 duplicatetitle => $duplicatetitle,
630 (uc(C4::Context->preference("marcflavour"))) => 1
633 output_html_with_http_headers $input, $cookie, $template->output;