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' && !$ordernumber) {
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;
424 my $order = Koha::Acquisition::Orders->find($ordernumber);
425 foreach my $value ($order->additional_field_values->as_list) {
426 $additional_field_values{$value->field_id} = $value->value;
428 } elsif ( $biblionumber ) {
429 foreach my $af (@additional_fields) {
430 if ($af->marcfield) {
431 $record //= Koha::Biblios->find($biblionumber)->metadata->record;
432 my ($field, $subfield) = split /\$/, $af->marcfield;
433 $additional_field_values{$af->id} = $record->subfield($field, $subfield);
438 additional_fields => \@additional_fields,
439 additional_field_values => \%additional_field_values,
444 existing => $biblionumber,
445 # basket informations
446 basketname => $basket->{'basketname'},
447 basketnote => $basket->{'note'},
448 booksellerid => $basket->{'booksellerid'},
449 basketbooksellernote => $basket->{booksellernote},
450 basketcontractno => $basket->{contractnumber},
451 basketcontractname => $contract->{contractname},
452 creationdate => $basket->{creationdate},
453 authorisedby => $basket->{'authorisedby'},
454 authorisedbyname => $basket->{'authorisedbyname'},
455 closedate => $basket->{'closedate'},
457 suggestionid => $suggestion->{suggestionid},
458 surnamesuggestedby => $suggestion->{surnamesuggestedby},
459 firstnamesuggestedby => $suggestion->{firstnamesuggestedby},
460 biblionumber => $biblionumber,
461 uncertainprice => $data->{'uncertainprice'},
462 discount_2dp => sprintf( "%.2f", $bookseller->discount ) , # for display
463 discount => $bookseller->discount,
464 orderdiscount_2dp => sprintf( "%.2f", $data->{'discount'} || 0 ),
465 orderdiscount => $data->{'discount'},
466 order_internalnote => $data->{'order_internalnote'},
467 order_vendornote => $data->{'order_vendornote'},
468 listincgst => $bookseller->listincgst,
469 invoiceincgst => $bookseller->invoiceincgst,
470 cur_active_sym => $active_currency->symbol,
471 cur_active => $active_currency->currency,
472 currencies => Koha::Acquisition::Currencies->search,
473 currency => $data->{currency},
474 vendor_currency => $bookseller->listprice,
475 orderexists => ( $new eq 'yes' ) ? 0 : 1,
476 title => $data->{'title'},
477 author => $data->{'author'},
478 publicationyear => $data->{'publicationyear'} ? $data->{'publicationyear'} : $data->{'copyrightdate'},
479 editionstatement => $data->{'editionstatement'},
480 budget_loop => $budget_loop,
481 isbn => $data->{'isbn'},
482 ean => $data->{'ean'},
483 seriestitle => $data->{'seriestitle'},
484 itemtypeloop => \@itemtypes,
485 quantity => $quantity,
486 quantityrec => $quantity,
487 rrp => $data->{'rrp'},
488 replacementprice => $data->{'replacementprice'},
489 gst_values => \@gst_values,
490 tax_rate => $data->{tax_rate_on_ordering} ? $data->{tax_rate_on_ordering}+0.0 : $bookseller->tax_rate ? $bookseller->tax_rate+0.0 : 0,
491 listprice => sprintf( "%.2f", $data->{listprice} || $data->{price} || $listprice),
492 total => sprintf( "%.2f", ($data->{ecost} || 0) * ($data->{'quantity'} || 0) ),
493 ecost => sprintf( "%.2f", $data->{ecost} || 0),
494 unitprice => sprintf( "%.2f", $data->{unitprice} || 0),
495 publishercode => $data->{'publishercode'},
496 barcode_subfield => $barcode_subfield,
497 import_batch_id => $import_batch_id,
498 acqcreate => $basketobj->effective_create_items eq "ordering" ? 1 : "",
499 users_ids => join(':', @order_user_ids),
500 users => \@order_users,
501 (uc(C4::Context->preference("marcflavour"))) => 1,
502 estimated_delivery_date => $data->{estimated_delivery_date},
505 output_html_with_http_headers $input, $cookie, $template->output;
508 =head2 MARCfindbreeding
510 $record = MARCfindbreeding($breedingid);
512 Look up the import record repository for the record with
513 record with id $breedingid. If found, returns the decoded
514 MARC::Record; otherwise, -1 is returned (FIXME).
515 Returns as second parameter the character encoding.
519 sub MARCfindbreeding {
521 my ($marc, $encoding) = GetImportRecordMarc($id);
522 # remove the - in isbn, koha store isbn without any -
524 my $record = MARC::Record->new_from_usmarc($marc);
525 my ($isbnfield,$isbnsubfield) = GetMarcFromKohaField( 'biblioitems.isbn' );
526 if ( $record->field($isbnfield) ) {
527 foreach my $field ( $record->field($isbnfield) ) {
528 foreach my $subfield ( $field->subfield($isbnsubfield) ) {
529 my $newisbn = $field->subfield($isbnsubfield);
531 $field->update( $isbnsubfield => $newisbn );
535 # fix the unimarc 100 coded field (with unicode information)
536 if ($marcflavour eq 'UNIMARC' && $record->subfield(100,'a')) {
537 my $f100a=$record->subfield(100,'a');
538 my $f100 = $record->field(100);
539 my $f100temp = $f100->as_string;
540 $record->delete_field($f100);
541 if ( length($f100temp) > 28 ) {
542 substr( $f100temp, 26, 2, "50" );
543 $f100->update( 'a' => $f100temp );
544 my $f100 = MARC::Field->new( '100', '', '', 'a' => $f100temp );
545 $record->insert_fields_ordered($f100);
549 if ( !defined(ref($record)) ) {
553 # normalize author : probably UNIMARC specific...
554 if ( C4::Context->preference("z3950NormalizeAuthor")
555 and C4::Context->preference("z3950AuthorAuthFields") )
557 my ( $tag, $subfield ) = GetMarcFromKohaField( "biblio.author" );
560 C4::Context->preference("z3950AuthorAuthFields");
561 my @auth_fields = split /,/, $auth_fields;
564 if ( $record->field($tag) ) {
565 foreach my $tmpfield ( $record->field($tag)->subfields ) {
567 my $subfieldcode = shift @$tmpfield;
568 my $subfieldvalue = shift @$tmpfield;
570 $field->add_subfields(
571 "$subfieldcode" => $subfieldvalue )
572 if ( $subfieldcode ne $subfield );
576 MARC::Field->new( $tag, "", "",
577 $subfieldcode => $subfieldvalue )
578 if ( $subfieldcode ne $subfield );
582 $record->delete_field( $record->field($tag) );
583 foreach my $fieldtag (@auth_fields) {
584 next unless ( $record->field($fieldtag) );
585 my $lastname = $record->field($fieldtag)->subfield('a');
586 my $firstname = $record->field($fieldtag)->subfield('b');
587 my $title = $record->field($fieldtag)->subfield('c');
588 my $number = $record->field($fieldtag)->subfield('d');
590 $field->add_subfields(
591 "$subfield" => ucfirst($title) . " "
592 . ucfirst($firstname) . " "
596 $field->add_subfields(
597 "$subfield" => ucfirst($firstname) . ", "
598 . ucfirst($lastname) );
601 $record->insert_fields_ordered($field);
603 return $record, $encoding;
610 my ($duplicatetitle)= @_;
611 ($template, $loggedinuser, $cookie) = get_template_and_user(
613 template_name => "acqui/neworderempty_duplicate.tt",
616 flagsrequired => { acquisition => 'order_manage' },
621 biblionumber => $biblionumber,
622 basketno => $basketno,
623 booksellerid => $basket->{'booksellerid'},
624 breedingid => $params->{'breedingid'},
625 duplicatetitle => $duplicatetitle,
626 (uc(C4::Context->preference("marcflavour"))) => 1
629 output_html_with_http_headers $input, $cookie, $template->output;