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;
104 our $input = CGI->new;
105 my $booksellerid = $input->param('booksellerid'); # FIXME: else ERROR!
106 my $budget_id = $input->param('budget_id') || 0;
107 my $title = $input->param('title');
108 my $author = $input->param('author');
109 my $publicationyear = $input->param('publicationyear');
110 my $ordernumber = $input->param('ordernumber') || '';
111 our $biblionumber = $input->param('biblionumber');
112 our $basketno = $input->param('basketno');
113 my $suggestionid = $input->param('suggestionid');
114 my $uncertainprice = $input->param('uncertainprice');
115 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 !
116 my $from_subscriptionid = $input->param('from_subscriptionid');
120 our ( $template, $loggedinuser, $cookie, $userflags ) = get_template_and_user(
122 template_name => "acqui/neworderempty.tt",
125 flagsrequired => { acquisition => 'order_manage' },
129 our $marcflavour = C4::Context->preference('marcflavour');
132 my $order = GetOrder($ordernumber);
133 $basketno = $order->{'basketno'};
136 our $basket = GetBasket($basketno);
137 my $basketobj = Koha::Acquisition::Baskets->find($basketno);
138 $booksellerid = $basket->{booksellerid} unless $booksellerid;
139 my $bookseller = Koha::Acquisition::Booksellers->find($booksellerid);
140 $data = GetOrder($ordernumber) if $ordernumber;
142 output_and_exit( $input, $cookie, $template, 'unknown_basket') unless $basketobj;
143 output_and_exit( $input, $cookie, $template, 'unknown_vendor') unless $bookseller;
146 ordernumber => $ordernumber,
147 basketno => $basketno,
149 booksellerid => $basket->{'booksellerid'},
150 name => $bookseller->name,
152 output_and_exit( $input, $cookie, $template, 'order_cannot_be_edited' )
153 if $ordernumber and ( $basketobj->closedate || $data->{orderstatus} eq "complete" );
155 my $contract = GetContract({
156 contractnumber => $basket->{contractnumber}
159 #simple parameters reading (all in one :-)
160 our $params = $input->Vars;
161 my $listprice=0; # the price, that can be in MARC record if we have one
162 if ( $ordernumber eq '' and defined $params->{'breedingid'}){
163 #we want to import from the breeding reservoir (from a z3950 search)
164 my ($marcrecord, $encoding) = MARCfindbreeding($params->{'breedingid'});
165 die("Could not find the selected record in the reservoir, bailing") unless $marcrecord;
167 # Remove all the items (952) from the imported record
168 foreach my $item ($marcrecord->field('952')) {
169 $marcrecord->delete_field($item);
174 ($biblionumber,$duplicatetitle) = FindDuplicate($marcrecord);
175 if($biblionumber && !$input->param('use_external_source')) {
176 #if duplicate record found and user did not decide yet, first warn user
177 #and let them choose between using a new record or an existing record
178 Load_Duplicate($duplicatetitle);
181 #from this point: add a new record
182 C4::Acquisition::FillWithDefaultValues($marcrecord, {only_mandatory => 1});
184 $params->{'frameworkcode'} or $params->{'frameworkcode'} = "";
185 ( $biblionumber, $bibitemnum ) = AddBiblio( $marcrecord, $params->{'frameworkcode'} );
186 # get the price if there is one.
187 $listprice = GetMarcPrice($marcrecord, $marcflavour);
188 SetImportRecordStatus($params->{'breedingid'}, 'imported');
190 SetMatchedBiblionumber( $params->{breedingid}, $biblionumber );
195 my ( @order_user_ids, @order_users, @catalog_details );
196 our $tagslib = GetMarcStructure(1, 'ACQ', { unsafe => 1 } );
197 my ( $itemnumber_tag, $itemnumber_subtag ) = GetMarcFromKohaField( 'items.itemnumber' );
198 if ( not $ordernumber ) { # create order
201 if ( $biblionumber ) {
202 $data = GetBiblioData($biblionumber);
204 # get suggestion fields if applicable. If it's a subscription renewal, then the biblio already exists
205 # otherwise, retrieve suggestion information.
206 elsif ($suggestionid) {
207 $data = GetSuggestion($suggestionid);
208 $budget_id ||= $data->{'budgetid'} // 0;
211 if ( not $biblionumber and Koha::BiblioFrameworks->find('ACQ') ) {
212 my $biblio_form_builder = Koha::UI::Form::Builder::Biblio->new();
213 foreach my $tag ( sort keys %{$tagslib} ) {
215 next if $tag eq $itemnumber_tag; # skip items fields
216 my $index_tag = int(rand(1000000));
217 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
218 my $mss = $tagslib->{$tag}{$subfield};
219 next if IsMarcStructureInternal($mss);
220 next if $mss->{tab} == -1;
221 my $value = $mss->{defaultvalue};
223 if ($suggestionid and $mss->{kohafield}) {
224 # Reading suggestion info if ordering from a suggestion
225 if ( $mss->{kohafield} eq 'biblio.title' ) {
226 $value = $data->{title};
228 elsif ( $mss->{kohafield} eq 'biblio.author' ) {
229 $value = $data->{author};
231 elsif ( $mss->{kohafield} eq 'biblioitems.publishercode' ) {
232 $value = $data->{publishercode};
234 elsif ( $mss->{kohafield} eq 'biblioitems.editionstatement' ) {
235 $value = $data->{editionstatement};
237 elsif ( $mss->{kohafield} eq 'biblioitems.publicationyear' ) {
238 $value = $data->{publicationyear};
240 elsif ( $mss->{kohafield} eq 'biblioitems.isbn' ) {
241 $value = $data->{isbn};
243 elsif ( $mss->{kohafield} eq 'biblio.seriestitle' ) {
244 $value = $data->{seriestitle};
248 push @catalog_details, $biblio_form_builder->generate_subfield_form(
251 subfield => $subfield,
253 index_tag => $index_tag,
262 $budget_id = $data->{'budget_id'};
265 subscriptionid => $data->{subscriptionid},
268 $basket = GetBasket( $data->{'basketno'} );
269 $basketno = $basket->{'basketno'};
271 @order_user_ids = GetOrderUsers($ordernumber);
272 foreach my $order_user_id (@order_user_ids) {
273 # FIXME Could be improved with search -in
274 my $order_patron = Koha::Patrons->find( $order_user_id );
275 push @order_users, $order_patron if $order_patron;
278 $biblionumber = $data->{biblionumber};
281 # - no ordernumber but a biblionumber: from a subscription, from an existing record
282 # - no ordernumber, no biblionumber: from a suggestion, from a new order
283 if ( not $ordernumber or $biblionumber ) {
284 if ( C4::Context->preference('UseACQFrameworkForBiblioRecords') ) {
285 my $biblio = Koha::Biblios->find($biblionumber);
286 my $record = $biblio ? $biblio->metadata->record : undef;
287 my $biblio_form_builder = Koha::UI::Form::Builder::Biblio->new(
289 biblionumber => $biblionumber,
292 foreach my $tag ( sort keys %{$tagslib} ) {
294 next if $tag eq $itemnumber_tag; # skip items fields
295 my @fields = $biblionumber ? $record->field($tag) : ();
296 my $index_tag = int(rand(1000000));
297 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
298 my $mss = $tagslib->{$tag}{$subfield};
299 next if IsMarcStructureInternal($mss);
300 next if $mss->{tab} == -1;
301 # We only need to display the values
302 my $value = join '; ', map { $tag < 10 ? $_->data : $_->subfield( $subfield ) } @fields;
304 push @catalog_details, $biblio_form_builder->generate_subfield_form(
307 subfield => $subfield,
309 index_tag => $index_tag,
320 $template->param( catalog_details => \@catalog_details, );
323 $suggestion = GetSuggestionInfo($suggestionid) if $suggestionid;
325 my $active_currency = Koha::Acquisition::Currencies->get_active;
327 # build bookfund list
328 my $patron = Koha::Patrons->find( $loggedinuser )->unblessed;
330 my $budget = GetBudget($budget_id);
332 my $budget_loop = [];
333 my $budgets = GetBudgetHierarchy;
334 foreach my $r (@{$budgets}) {
335 next unless (CanUserUseBudget($patron, $r, $userflags));
336 push @{$budget_loop}, {
337 b_id => $r->{budget_id},
338 b_txt => $r->{budget_name},
339 b_sort1_authcat => $r->{'sort1_authcat'},
340 b_sort2_authcat => $r->{'sort2_authcat'},
341 b_active => $r->{budget_period_active},
342 b_sel => ( $r->{budget_id} == $budget_id ) ? 1 : 0,
343 b_level => $r->{budget_level},
348 $template->param( sort1 => $data->{'sort1'} );
349 $template->param( sort2 => $data->{'sort2'} );
351 if ($basketobj->effective_create_items eq 'ordering' && !$ordernumber) {
352 # Check if ACQ framework exists
353 my $marc = GetMarcStructure(1, 'ACQ', { unsafe => 1 } );
355 $template->param('NoACQframework' => 1);
358 AcqCreateItemOrdering => 1,
359 UniqueItemFields => C4::Context->preference('UniqueItemFields'),
363 my @itemtypes = Koha::ItemTypes->search( {}, { order_by => { -asc => "description" } } )->as_list;
365 if ( defined $from_subscriptionid ) {
366 # Get the last received order for this subscription
367 my $lastOrderReceived = Koha::Acquisition::Orders->search(
369 subscriptionid => $from_subscriptionid,
370 datereceived => { '!=' => undef }
374 [ { -desc => 'datereceived' }, { -desc => 'ordernumber' } ]
377 if ( $lastOrderReceived->count ) {
378 $lastOrderReceived = $lastOrderReceived->next->unblessed; # FIXME We should send the object to the template
379 $budget_id = $lastOrderReceived->{budgetid};
380 $data->{listprice} = $lastOrderReceived->{listprice};
381 $data->{uncertainprice} = $lastOrderReceived->{uncertainprice};
382 $data->{tax_rate} = $lastOrderReceived->{tax_rate_on_ordering};
383 $data->{discount} = $lastOrderReceived->{discount};
384 $data->{rrp} = $lastOrderReceived->{rrp};
385 $data->{replacementprice} = $lastOrderReceived->{replacementprice};
386 $data->{ecost} = $lastOrderReceived->{ecost};
387 $data->{quantity} = $lastOrderReceived->{quantity};
388 $data->{unitprice} = $lastOrderReceived->{unitprice};
389 $data->{order_internalnote} = $lastOrderReceived->{order_internalnote};
390 $data->{order_vendornote} = $lastOrderReceived->{order_vendornote};
391 $data->{sort1} = $lastOrderReceived->{sort1};
392 $data->{sort2} = $lastOrderReceived->{sort2};
394 $basket = GetBasket( $input->param('basketno') );
397 my $subscription = Koha::Subscriptions->find($from_subscriptionid);
399 subscriptionid => $from_subscriptionid,
400 subscription => $subscription,
404 # Find the items.barcode subfield for barcode validations
405 my (undef, $barcode_subfield) = GetMarcFromKohaField( 'items.barcode' );
408 # get option values for TaxRates syspref
409 my @gst_values = map {
411 }, split( '\|', C4::Context->preference("TaxRates") );
413 my $quantity = $input->param('rr_quantity_to_order') ?
414 $input->param('rr_quantity_to_order') :
420 existing => $biblionumber,
421 # basket informations
422 basketname => $basket->{'basketname'},
423 basketnote => $basket->{'note'},
424 booksellerid => $basket->{'booksellerid'},
425 basketbooksellernote => $basket->{booksellernote},
426 basketcontractno => $basket->{contractnumber},
427 basketcontractname => $contract->{contractname},
428 creationdate => $basket->{creationdate},
429 authorisedby => $basket->{'authorisedby'},
430 authorisedbyname => $basket->{'authorisedbyname'},
431 closedate => $basket->{'closedate'},
433 suggestionid => $suggestion->{suggestionid},
434 surnamesuggestedby => $suggestion->{surnamesuggestedby},
435 firstnamesuggestedby => $suggestion->{firstnamesuggestedby},
436 biblionumber => $biblionumber,
437 uncertainprice => $data->{'uncertainprice'},
438 discount_2dp => sprintf( "%.2f", $bookseller->discount ) , # for display
439 discount => $bookseller->discount,
440 orderdiscount_2dp => sprintf( "%.2f", $data->{'discount'} || 0 ),
441 orderdiscount => $data->{'discount'},
442 order_internalnote => $data->{'order_internalnote'},
443 order_vendornote => $data->{'order_vendornote'},
444 listincgst => $bookseller->listincgst,
445 invoiceincgst => $bookseller->invoiceincgst,
446 cur_active_sym => $active_currency->symbol,
447 cur_active => $active_currency->currency,
448 currencies => Koha::Acquisition::Currencies->search,
449 currency => $data->{currency},
450 vendor_currency => $bookseller->listprice,
451 orderexists => ( $new eq 'yes' ) ? 0 : 1,
452 title => $data->{'title'},
453 author => $data->{'author'},
454 publicationyear => $data->{'publicationyear'} ? $data->{'publicationyear'} : $data->{'copyrightdate'},
455 editionstatement => $data->{'editionstatement'},
456 budget_loop => $budget_loop,
457 isbn => $data->{'isbn'},
458 ean => $data->{'ean'},
459 seriestitle => $data->{'seriestitle'},
460 itemtypeloop => \@itemtypes,
461 quantity => $quantity,
462 quantityrec => $quantity,
463 rrp => $data->{'rrp'},
464 replacementprice => $data->{'replacementprice'},
465 gst_values => \@gst_values,
466 tax_rate => $data->{tax_rate_on_ordering} ? $data->{tax_rate_on_ordering}+0.0 : $bookseller->tax_rate ? $bookseller->tax_rate+0.0 : 0,
467 listprice => sprintf( "%.2f", $data->{listprice} || $data->{price} || $listprice),
468 total => sprintf( "%.2f", ($data->{ecost} || 0) * ($data->{'quantity'} || 0) ),
469 ecost => sprintf( "%.2f", $data->{ecost} || 0),
470 unitprice => sprintf( "%.2f", $data->{unitprice} || 0),
471 publishercode => $data->{'publishercode'},
472 barcode_subfield => $barcode_subfield,
473 import_batch_id => $import_batch_id,
474 acqcreate => $basketobj->effective_create_items eq "ordering" ? 1 : "",
475 users_ids => join(':', @order_user_ids),
476 users => \@order_users,
477 (uc(C4::Context->preference("marcflavour"))) => 1,
478 estimated_delivery_date => $data->{estimated_delivery_date},
481 output_html_with_http_headers $input, $cookie, $template->output;
484 =head2 MARCfindbreeding
486 $record = MARCfindbreeding($breedingid);
488 Look up the import record repository for the record with
489 record with id $breedingid. If found, returns the decoded
490 MARC::Record; otherwise, -1 is returned (FIXME).
491 Returns as second parameter the character encoding.
495 sub MARCfindbreeding {
497 my ($marc, $encoding) = GetImportRecordMarc($id);
498 # remove the - in isbn, koha store isbn without any -
500 my $record = MARC::Record->new_from_usmarc($marc);
501 my ($isbnfield,$isbnsubfield) = GetMarcFromKohaField( 'biblioitems.isbn' );
502 if ( $record->field($isbnfield) ) {
503 foreach my $field ( $record->field($isbnfield) ) {
504 foreach my $subfield ( $field->subfield($isbnsubfield) ) {
505 my $newisbn = $field->subfield($isbnsubfield);
507 $field->update( $isbnsubfield => $newisbn );
511 # fix the unimarc 100 coded field (with unicode information)
512 if ($marcflavour eq 'UNIMARC' && $record->subfield(100,'a')) {
513 my $f100a=$record->subfield(100,'a');
514 my $f100 = $record->field(100);
515 my $f100temp = $f100->as_string;
516 $record->delete_field($f100);
517 if ( length($f100temp) > 28 ) {
518 substr( $f100temp, 26, 2, "50" );
519 $f100->update( 'a' => $f100temp );
520 my $f100 = MARC::Field->new( '100', '', '', 'a' => $f100temp );
521 $record->insert_fields_ordered($f100);
525 if ( !defined(ref($record)) ) {
529 # normalize author : probably UNIMARC specific...
530 if ( C4::Context->preference("z3950NormalizeAuthor")
531 and C4::Context->preference("z3950AuthorAuthFields") )
533 my ( $tag, $subfield ) = GetMarcFromKohaField( "biblio.author" );
536 C4::Context->preference("z3950AuthorAuthFields");
537 my @auth_fields = split /,/, $auth_fields;
540 if ( $record->field($tag) ) {
541 foreach my $tmpfield ( $record->field($tag)->subfields ) {
543 my $subfieldcode = shift @$tmpfield;
544 my $subfieldvalue = shift @$tmpfield;
546 $field->add_subfields(
547 "$subfieldcode" => $subfieldvalue )
548 if ( $subfieldcode ne $subfield );
552 MARC::Field->new( $tag, "", "",
553 $subfieldcode => $subfieldvalue )
554 if ( $subfieldcode ne $subfield );
558 $record->delete_field( $record->field($tag) );
559 foreach my $fieldtag (@auth_fields) {
560 next unless ( $record->field($fieldtag) );
561 my $lastname = $record->field($fieldtag)->subfield('a');
562 my $firstname = $record->field($fieldtag)->subfield('b');
563 my $title = $record->field($fieldtag)->subfield('c');
564 my $number = $record->field($fieldtag)->subfield('d');
566 $field->add_subfields(
567 "$subfield" => ucfirst($title) . " "
568 . ucfirst($firstname) . " "
572 $field->add_subfields(
573 "$subfield" => ucfirst($firstname) . ", "
574 . ucfirst($lastname) );
577 $record->insert_fields_ordered($field);
579 return $record, $encoding;
586 my ($duplicatetitle)= @_;
587 ($template, $loggedinuser, $cookie) = get_template_and_user(
589 template_name => "acqui/neworderempty_duplicate.tt",
592 flagsrequired => { acquisition => 'order_manage' },
597 biblionumber => $biblionumber,
598 basketno => $basketno,
599 booksellerid => $basket->{'booksellerid'},
600 breedingid => $params->{'breedingid'},
601 duplicatetitle => $duplicatetitle,
602 (uc(C4::Context->preference("marcflavour"))) => 1
605 output_html_with_http_headers $input, $cookie, $template->output;