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');
121 our ( $template, $loggedinuser, $cookie, $userflags ) = get_template_and_user(
123 template_name => "acqui/neworderempty.tt",
126 flagsrequired => { acquisition => 'order_manage' },
130 our $marcflavour = C4::Context->preference('marcflavour');
133 my $order = GetOrder($ordernumber);
134 $basketno = $order->{'basketno'};
137 our $basket = GetBasket($basketno);
138 my $basketobj = Koha::Acquisition::Baskets->find($basketno);
139 $booksellerid = $basket->{booksellerid} unless $booksellerid;
140 my $bookseller = Koha::Acquisition::Booksellers->find($booksellerid);
141 $data = GetOrder($ordernumber) if $ordernumber;
143 output_and_exit( $input, $cookie, $template, 'unknown_basket') unless $basketobj;
144 output_and_exit( $input, $cookie, $template, 'unknown_vendor') unless $bookseller;
147 ordernumber => $ordernumber,
148 basketno => $basketno,
150 booksellerid => $basket->{'booksellerid'},
151 name => $bookseller->name,
153 output_and_exit( $input, $cookie, $template, 'order_cannot_be_edited' )
154 if $ordernumber and ( $basketobj->closedate || $data->{orderstatus} eq "complete" );
156 my $contract = GetContract({
157 contractnumber => $basket->{contractnumber}
160 #simple parameters reading (all in one :-)
161 our $params = $input->Vars;
162 my $listprice=0; # the price, that can be in MARC record if we have one
163 if ( $ordernumber eq '' and defined $params->{'breedingid'}){
164 #we want to import from the breeding reservoir (from a z3950 search)
165 my ($marcrecord, $encoding) = MARCfindbreeding($params->{'breedingid'});
166 die("Could not find the selected record in the reservoir, bailing") unless $marcrecord;
168 # Remove all the items (952) from the imported record
169 foreach my $item ($marcrecord->field('952')) {
170 $marcrecord->delete_field($item);
175 ($biblionumber,$duplicatetitle) = FindDuplicate($marcrecord);
176 if($biblionumber && !$input->param('use_external_source')) {
177 #if duplicate record found and user did not decide yet, first warn user
178 #and let them choose between using a new record or an existing record
179 Load_Duplicate($duplicatetitle);
182 #from this point: add a new record
183 C4::Acquisition::FillWithDefaultValues($marcrecord, {only_mandatory => 1});
185 $params->{'frameworkcode'} or $params->{'frameworkcode'} = "";
186 ( $biblionumber, $bibitemnum ) = AddBiblio( $marcrecord, $params->{'frameworkcode'} );
187 # get the price if there is one.
188 $listprice = GetMarcPrice($marcrecord, $marcflavour);
189 SetImportRecordStatus($params->{'breedingid'}, 'imported');
191 SetMatchedBiblionumber( $params->{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 $budget_id ||= $data->{'budgetid'} // 0;
212 if ( not $biblionumber and Koha::BiblioFrameworks->find('ACQ') ) {
213 my $biblio_form_builder = Koha::UI::Form::Builder::Biblio->new();
214 foreach my $tag ( sort keys %{$tagslib} ) {
216 next if $tag eq $itemnumber_tag; # skip items fields
217 my $index_tag = int(rand(1000000));
218 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
219 my $mss = $tagslib->{$tag}{$subfield};
220 next if IsMarcStructureInternal($mss);
221 next if $mss->{tab} == -1;
222 my $value = $mss->{defaultvalue};
224 if ($suggestionid and $mss->{kohafield}) {
225 # Reading suggestion info if ordering from a suggestion
226 if ( $mss->{kohafield} eq 'biblio.title' ) {
227 $value = $data->{title};
229 elsif ( $mss->{kohafield} eq 'biblio.author' ) {
230 $value = $data->{author};
232 elsif ( $mss->{kohafield} eq 'biblioitems.publishercode' ) {
233 $value = $data->{publishercode};
235 elsif ( $mss->{kohafield} eq 'biblioitems.editionstatement' ) {
236 $value = $data->{editionstatement};
238 elsif ( $mss->{kohafield} eq 'biblioitems.publicationyear' ) {
239 $value = $data->{publicationyear};
241 elsif ( $mss->{kohafield} eq 'biblioitems.isbn' ) {
242 $value = $data->{isbn};
244 elsif ( $mss->{kohafield} eq 'biblio.seriestitle' ) {
245 $value = $data->{seriestitle};
249 push @catalog_details, $biblio_form_builder->generate_subfield_form(
252 subfield => $subfield,
254 index_tag => $index_tag,
263 $budget_id = $data->{'budget_id'};
266 subscriptionid => $data->{subscriptionid},
269 $basket = GetBasket( $data->{'basketno'} );
270 $basketno = $basket->{'basketno'};
272 @order_user_ids = GetOrderUsers($ordernumber);
273 foreach my $order_user_id (@order_user_ids) {
274 # FIXME Could be improved with search -in
275 my $order_patron = Koha::Patrons->find( $order_user_id );
276 push @order_users, $order_patron if $order_patron;
279 $biblionumber = $data->{biblionumber};
282 # - no ordernumber but a biblionumber: from a subscription, from an existing record
283 # - no ordernumber, no biblionumber: from a suggestion, from a new order
284 if ( not $ordernumber or $biblionumber ) {
285 if ( C4::Context->preference('UseACQFrameworkForBiblioRecords') ) {
286 my $biblio = Koha::Biblios->find($biblionumber);
287 my $record = $biblio ? $biblio->metadata->record : undef;
288 my $biblio_form_builder = Koha::UI::Form::Builder::Biblio->new(
290 biblionumber => $biblionumber,
293 foreach my $tag ( sort keys %{$tagslib} ) {
295 next if $tag eq $itemnumber_tag; # skip items fields
296 my @fields = $biblionumber ? $record->field($tag) : ();
297 my $index_tag = int(rand(1000000));
298 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
299 my $mss = $tagslib->{$tag}{$subfield};
300 next if IsMarcStructureInternal($mss);
301 next if $mss->{tab} == -1;
302 # We only need to display the values
303 my $value = join '; ', map { $tag < 10 ? $_->data : $_->subfield( $subfield ) } @fields;
305 push @catalog_details, $biblio_form_builder->generate_subfield_form(
308 subfield => $subfield,
310 index_tag => $index_tag,
321 $template->param( catalog_details => \@catalog_details, );
324 $suggestion = GetSuggestionInfo($suggestionid) if $suggestionid;
326 my $active_currency = Koha::Acquisition::Currencies->get_active;
328 # build bookfund list
329 my $patron = Koha::Patrons->find( $loggedinuser )->unblessed;
331 my $budget = GetBudget($budget_id);
333 my $budget_loop = [];
334 my $budgets = GetBudgetHierarchy;
335 foreach my $r (@{$budgets}) {
336 next unless (CanUserUseBudget($patron, $r, $userflags));
337 push @{$budget_loop}, {
338 b_id => $r->{budget_id},
339 b_txt => $r->{budget_name},
340 b_sort1_authcat => $r->{'sort1_authcat'},
341 b_sort2_authcat => $r->{'sort2_authcat'},
342 b_active => $r->{budget_period_active},
343 b_sel => ( $r->{budget_id} == $budget_id ) ? 1 : 0,
344 b_level => $r->{budget_level},
349 $template->param( sort1 => $data->{'sort1'} );
350 $template->param( sort2 => $data->{'sort2'} );
352 if ( $basketobj->effective_create_items eq 'ordering' ) {
353 # Check if ACQ framework exists
354 my $marc = GetMarcStructure( 1, 'ACQ', { unsafe => 1 } );
356 $template->param( 'NoACQframework' => 1 );
359 AcqCreateItemOrdering => 1,
360 UniqueItemFields => C4::Context->preference('UniqueItemFields'),
364 my @itemtypes = Koha::ItemTypes->search( {}, { order_by => { -asc => "description" } } )->as_list;
366 if ( defined $from_subscriptionid ) {
367 # Get the last received order for this subscription
368 my $lastOrderReceived = Koha::Acquisition::Orders->search(
370 subscriptionid => $from_subscriptionid,
371 datereceived => { '!=' => undef }
375 [ { -desc => 'datereceived' }, { -desc => 'ordernumber' } ]
378 if ( $lastOrderReceived->count ) {
379 $lastOrderReceived = $lastOrderReceived->next->unblessed; # FIXME We should send the object to the template
380 $budget_id = $lastOrderReceived->{budgetid};
381 $data->{listprice} = $lastOrderReceived->{listprice};
382 $data->{uncertainprice} = $lastOrderReceived->{uncertainprice};
383 $data->{tax_rate} = $lastOrderReceived->{tax_rate_on_ordering};
384 $data->{discount} = $lastOrderReceived->{discount};
385 $data->{rrp} = $lastOrderReceived->{rrp};
386 $data->{replacementprice} = $lastOrderReceived->{replacementprice};
387 $data->{ecost} = $lastOrderReceived->{ecost};
388 $data->{quantity} = $lastOrderReceived->{quantity};
389 $data->{unitprice} = $lastOrderReceived->{unitprice};
390 $data->{order_internalnote} = $lastOrderReceived->{order_internalnote};
391 $data->{order_vendornote} = $lastOrderReceived->{order_vendornote};
392 $data->{sort1} = $lastOrderReceived->{sort1};
393 $data->{sort2} = $lastOrderReceived->{sort2};
395 $basket = GetBasket( $input->param('basketno') );
398 my $subscription = Koha::Subscriptions->find($from_subscriptionid);
400 subscriptionid => $from_subscriptionid,
401 subscription => $subscription,
405 # Find the items.barcode subfield for barcode validations
406 my (undef, $barcode_subfield) = GetMarcFromKohaField( 'items.barcode' );
409 # get option values for TaxRates syspref
410 my @gst_values = map {
412 }, split( '\|', C4::Context->preference("TaxRates") );
414 my $quantity = $input->param('rr_quantity_to_order') ?
415 $input->param('rr_quantity_to_order') :
419 # Get additional fields
421 my @additional_fields = Koha::AdditionalFields->search({ tablename => 'aqorders' })->as_list;
422 my %additional_field_values;
425 my $order = Koha::Acquisition::Orders->find($ordernumber);
426 foreach my $value ($order->additional_field_values->as_list) {
427 $additional_field_values{$value->field_id} = $value->value;
429 $items = $order->items;
430 } elsif ( $biblionumber ) {
431 foreach my $af (@additional_fields) {
432 if ($af->marcfield) {
433 $record //= Koha::Biblios->find($biblionumber)->metadata->record;
434 my ($field, $subfield) = split /\$/, $af->marcfield;
435 $additional_field_values{$af->id} = $record->subfield($field, $subfield);
440 additional_fields => \@additional_fields,
441 additional_field_values => \%additional_field_values,
447 existing => $biblionumber,
448 # basket informations
449 basketname => $basket->{'basketname'},
450 basketnote => $basket->{'note'},
451 booksellerid => $basket->{'booksellerid'},
452 basketbooksellernote => $basket->{booksellernote},
453 basketcontractno => $basket->{contractnumber},
454 basketcontractname => $contract->{contractname},
455 creationdate => $basket->{creationdate},
456 authorisedby => $basket->{'authorisedby'},
457 authorisedbyname => $basket->{'authorisedbyname'},
458 closedate => $basket->{'closedate'},
460 suggestionid => $suggestion->{suggestionid},
461 surnamesuggestedby => $suggestion->{surnamesuggestedby},
462 firstnamesuggestedby => $suggestion->{firstnamesuggestedby},
463 biblionumber => $biblionumber,
464 uncertainprice => $data->{'uncertainprice'},
465 discount_2dp => sprintf( "%.2f", $bookseller->discount ) , # for display
466 discount => $bookseller->discount,
467 orderdiscount_2dp => sprintf( "%.2f", $data->{'discount'} || 0 ),
468 orderdiscount => $data->{'discount'},
469 order_internalnote => $data->{'order_internalnote'},
470 order_vendornote => $data->{'order_vendornote'},
471 listincgst => $bookseller->listincgst,
472 invoiceincgst => $bookseller->invoiceincgst,
473 cur_active_sym => $active_currency->symbol,
474 cur_active => $active_currency->currency,
475 currencies => Koha::Acquisition::Currencies->search,
476 currency => $data->{currency},
477 vendor_currency => $bookseller->listprice,
478 orderexists => ( $new eq 'yes' ) ? 0 : 1,
479 title => $data->{'title'},
480 author => $data->{'author'},
481 publicationyear => $data->{'publicationyear'} ? $data->{'publicationyear'} : $data->{'copyrightdate'},
482 editionstatement => $data->{'editionstatement'},
483 budget_loop => $budget_loop,
484 isbn => $data->{'isbn'},
485 ean => $data->{'ean'},
486 seriestitle => $data->{'seriestitle'},
487 itemtypeloop => \@itemtypes,
488 quantity => $quantity,
489 quantityrec => $quantity,
490 rrp => $data->{'rrp'},
491 replacementprice => $data->{'replacementprice'},
492 gst_values => \@gst_values,
493 tax_rate => $data->{tax_rate_on_ordering} ? $data->{tax_rate_on_ordering}+0.0 : $bookseller->tax_rate ? $bookseller->tax_rate+0.0 : 0,
494 listprice => sprintf( "%.2f", $data->{listprice} || $data->{price} || $listprice),
495 total => sprintf( "%.2f", ($data->{ecost} || 0) * ($data->{'quantity'} || 0) ),
496 ecost => sprintf( "%.2f", $data->{ecost} || 0),
497 unitprice => sprintf( "%.2f", $data->{unitprice} || 0),
498 publishercode => $data->{'publishercode'},
499 barcode_subfield => $barcode_subfield,
500 import_batch_id => $import_batch_id,
501 acqcreate => $basketobj->effective_create_items eq "ordering" ? 1 : "",
502 users_ids => join(':', @order_user_ids),
503 users => \@order_users,
504 (uc(C4::Context->preference("marcflavour"))) => 1,
505 estimated_delivery_date => $data->{estimated_delivery_date},
508 output_html_with_http_headers $input, $cookie, $template->output;
511 =head2 MARCfindbreeding
513 $record = MARCfindbreeding($breedingid);
515 Look up the import record repository for the record with
516 record with id $breedingid. If found, returns the decoded
517 MARC::Record; otherwise, -1 is returned (FIXME).
518 Returns as second parameter the character encoding.
522 sub MARCfindbreeding {
524 my ($marc, $encoding) = GetImportRecordMarc($id);
525 # remove the - in isbn, koha store isbn without any -
527 my $record = MARC::Record->new_from_usmarc($marc);
528 my ($isbnfield,$isbnsubfield) = GetMarcFromKohaField( 'biblioitems.isbn' );
529 if ( $record->field($isbnfield) ) {
530 foreach my $field ( $record->field($isbnfield) ) {
531 foreach my $subfield ( $field->subfield($isbnsubfield) ) {
532 my $newisbn = $field->subfield($isbnsubfield);
534 $field->update( $isbnsubfield => $newisbn );
538 # fix the unimarc 100 coded field (with unicode information)
539 if ($marcflavour eq 'UNIMARC' && $record->subfield(100,'a')) {
540 my $f100a=$record->subfield(100,'a');
541 my $f100 = $record->field(100);
542 my $f100temp = $f100->as_string;
543 $record->delete_field($f100);
544 if ( length($f100temp) > 28 ) {
545 substr( $f100temp, 26, 2, "50" );
546 $f100->update( 'a' => $f100temp );
547 my $f100 = MARC::Field->new( '100', '', '', 'a' => $f100temp );
548 $record->insert_fields_ordered($f100);
552 if ( !defined(ref($record)) ) {
556 # normalize author : probably UNIMARC specific...
557 if ( C4::Context->preference("z3950NormalizeAuthor")
558 and C4::Context->preference("z3950AuthorAuthFields") )
560 my ( $tag, $subfield ) = GetMarcFromKohaField( "biblio.author" );
563 C4::Context->preference("z3950AuthorAuthFields");
564 my @auth_fields = split /,/, $auth_fields;
567 if ( $record->field($tag) ) {
568 foreach my $tmpfield ( $record->field($tag)->subfields ) {
570 my $subfieldcode = shift @$tmpfield;
571 my $subfieldvalue = shift @$tmpfield;
573 $field->add_subfields(
574 "$subfieldcode" => $subfieldvalue )
575 if ( $subfieldcode ne $subfield );
579 MARC::Field->new( $tag, "", "",
580 $subfieldcode => $subfieldvalue )
581 if ( $subfieldcode ne $subfield );
585 $record->delete_field( $record->field($tag) );
586 foreach my $fieldtag (@auth_fields) {
587 next unless ( $record->field($fieldtag) );
588 my $lastname = $record->field($fieldtag)->subfield('a');
589 my $firstname = $record->field($fieldtag)->subfield('b');
590 my $title = $record->field($fieldtag)->subfield('c');
591 my $number = $record->field($fieldtag)->subfield('d');
593 $field->add_subfields(
594 "$subfield" => ucfirst($title) . " "
595 . ucfirst($firstname) . " "
599 $field->add_subfields(
600 "$subfield" => ucfirst($firstname) . ", "
601 . ucfirst($lastname) );
604 $record->insert_fields_ordered($field);
606 return $record, $encoding;
613 my ($duplicatetitle)= @_;
614 ($template, $loggedinuser, $cookie) = get_template_and_user(
616 template_name => "acqui/neworderempty_duplicate.tt",
619 flagsrequired => { acquisition => 'order_manage' },
624 biblionumber => $biblionumber,
625 basketno => $basketno,
626 booksellerid => $basket->{'booksellerid'},
627 breedingid => $params->{'breedingid'},
628 duplicatetitle => $duplicatetitle,
629 (uc(C4::Context->preference("marcflavour"))) => 1
632 output_html_with_http_headers $input, $cookie, $template->output;