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 );
84 IsMarcStructureInternal
86 use C4::Output qw( output_and_exit output_html_with_http_headers );
88 use C4::Search qw( FindDuplicate );
90 #needed for z3950 import:
91 use C4::ImportBatch qw( SetImportRecordStatus SetMatchedBiblionumber GetImportRecordMarc );
93 use Koha::Acquisition::Booksellers;
94 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;
103 our $input = CGI->new;
104 my $booksellerid = $input->param('booksellerid'); # FIXME: else ERROR!
105 my $budget_id = $input->param('budget_id') || 0;
106 my $title = $input->param('title');
107 my $author = $input->param('author');
108 my $publicationyear = $input->param('publicationyear');
109 my $ordernumber = $input->param('ordernumber') || '';
110 our $biblionumber = $input->param('biblionumber');
111 our $basketno = $input->param('basketno');
112 my $suggestionid = $input->param('suggestionid');
113 my $uncertainprice = $input->param('uncertainprice');
114 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 !
115 my $from_subscriptionid = $input->param('from_subscriptionid');
119 our ( $template, $loggedinuser, $cookie, $userflags ) = get_template_and_user(
121 template_name => "acqui/neworderempty.tt",
124 flagsrequired => { acquisition => 'order_manage' },
128 our $marcflavour = C4::Context->preference('marcflavour');
131 my $order = GetOrder($ordernumber);
132 $basketno = $order->{'basketno'};
135 our $basket = GetBasket($basketno);
136 my $basketobj = Koha::Acquisition::Baskets->find( $basketno );
137 $booksellerid = $basket->{booksellerid} unless $booksellerid;
138 my $bookseller = Koha::Acquisition::Booksellers->find( $booksellerid );
140 output_and_exit( $input, $cookie, $template, 'unknown_basket') unless $basketobj;
141 output_and_exit( $input, $cookie, $template, 'unknown_vendor') unless $bookseller;
144 ordernumber => $ordernumber,
145 basketno => $basketno,
147 booksellerid => $basket->{'booksellerid'},
148 name => $bookseller->name,
150 output_and_exit( $input, $cookie, $template, 'order_cannot_be_edited' )
151 if $ordernumber and $basketobj->closedate;
153 my $contract = GetContract({
154 contractnumber => $basket->{contractnumber}
157 #simple parameters reading (all in one :-)
158 our $params = $input->Vars;
159 my $listprice=0; # the price, that can be in MARC record if we have one
160 if ( $ordernumber eq '' and defined $params->{'breedingid'}){
161 #we want to import from the breeding reservoir (from a z3950 search)
162 my ($marcrecord, $encoding) = MARCfindbreeding($params->{'breedingid'});
163 die("Could not find the selected record in the reservoir, bailing") unless $marcrecord;
165 # Remove all the items (952) from the imported record
166 foreach my $item ($marcrecord->field('952')) {
167 $marcrecord->delete_field($item);
172 ($biblionumber,$duplicatetitle) = FindDuplicate($marcrecord);
173 if($biblionumber && !$input->param('use_external_source')) {
174 #if duplicate record found and user did not decide yet, first warn user
175 #and let them choose between using a new record or an existing record
176 Load_Duplicate($duplicatetitle);
179 #from this point: add a new record
180 C4::Acquisition::FillWithDefaultValues($marcrecord, {only_mandatory => 1});
182 $params->{'frameworkcode'} or $params->{'frameworkcode'} = "";
183 ( $biblionumber, $bibitemnum ) = AddBiblio( $marcrecord, $params->{'frameworkcode'} );
184 # get the price if there is one.
185 $listprice = GetMarcPrice($marcrecord, $marcflavour);
186 SetImportRecordStatus($params->{'breedingid'}, 'imported');
188 SetMatchedBiblionumber( $params->{breedingid}, $biblionumber );
193 my ( @order_user_ids, @order_users, @catalog_details );
194 our $tagslib = GetMarcStructure(1, 'ACQ', { unsafe => 1 } );
195 my ( $itemnumber_tag, $itemnumber_subtag ) = GetMarcFromKohaField( 'items.itemnumber' );
196 if ( not $ordernumber ) { # create order
199 if ( $biblionumber ) {
200 $data = GetBiblioData($biblionumber);
202 # get suggestion fields if applicable. If it's a subscription renewal, then the biblio already exists
203 # otherwise, retrieve suggestion information.
204 elsif ($suggestionid) {
205 $data = GetSuggestion($suggestionid);
206 $budget_id ||= $data->{'budgetid'} // 0;
209 if ( not $biblionumber and Koha::BiblioFrameworks->find('ACQ') ) {
210 foreach my $tag ( sort keys %{$tagslib} ) {
212 next if $tag eq $itemnumber_tag; # skip items fields
213 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
214 my $mss = $tagslib->{$tag}{$subfield};
215 next if IsMarcStructureInternal($mss);
216 next if $mss->{tab} == -1;
217 my $value = $mss->{defaultvalue};
219 if ($suggestionid and $mss->{kohafield}) {
220 # Reading suggestion info if ordering from a suggestion
221 if ( $mss->{kohafield} eq 'biblio.title' ) {
222 $value = $data->{title};
224 elsif ( $mss->{kohafield} eq 'biblio.author' ) {
225 $value = $data->{author};
227 elsif ( $mss->{kohafield} eq 'biblioitems.publishercode' ) {
228 $value = $data->{publishercode};
230 elsif ( $mss->{kohafield} eq 'biblioitems.editionstatement' ) {
231 $value = $data->{editionstatement};
233 elsif ( $mss->{kohafield} eq 'biblioitems.publicationyear' ) {
234 $value = $data->{publicationyear};
236 elsif ( $mss->{kohafield} eq 'biblioitems.isbn' ) {
237 $value = $data->{isbn};
239 elsif ( $mss->{kohafield} eq 'biblio.seriestitle' ) {
240 $value = $data->{seriestitle};
246 # get today date & replace <<YYYY>>, <<YY>>, <<MM>>, <<DD>> if provided in the default value
247 my $today_dt = dt_from_string;
248 my $year = $today_dt->strftime('%Y');
249 my $shortyear = $today_dt->strftime('%y');
250 my $month = $today_dt->strftime('%m');
251 my $day = $today_dt->strftime('%d');
252 $value =~ s/<<YYYY>>/$year/g;
253 $value =~ s/<<YY>>/$shortyear/g;
254 $value =~ s/<<MM>>/$month/g;
255 $value =~ s/<<DD>>/$day/g;
257 # And <<USER>> with surname (?)
259 ( C4::Context->userenv
260 ? C4::Context->userenv->{'surname'}
261 : "superlibrarian" );
262 $value =~ s/<<USER>>/$username/g;
264 push @catalog_details, {
266 subfield => $subfield,
267 %$mss, # Do we need plugins support (?)
275 $data = GetOrder($ordernumber);
276 $budget_id = $data->{'budget_id'};
279 subscriptionid => $data->{subscriptionid},
282 $basket = GetBasket( $data->{'basketno'} );
283 $basketno = $basket->{'basketno'};
285 @order_user_ids = GetOrderUsers($ordernumber);
286 foreach my $order_user_id (@order_user_ids) {
287 # FIXME Could be improved with search -in
288 my $order_patron = Koha::Patrons->find( $order_user_id );
289 push @order_users, $order_patron if $order_patron;
292 $biblionumber = $data->{biblionumber};
295 # - no ordernumber but a biblionumber: from a subscription, from an existing record
296 # - no ordernumber, no biblionumber: from a suggestion, from a new order
297 if ( not $ordernumber or $biblionumber ) {
298 if ( C4::Context->preference('UseACQFrameworkForBiblioRecords') ) {
299 my $record = $biblionumber ? GetMarcBiblio({ biblionumber => $biblionumber }) : undef;
300 foreach my $tag ( sort keys %{$tagslib} ) {
302 next if $tag eq $itemnumber_tag; # skip items fields
303 my @fields = $biblionumber ? $record->field($tag) : ();
304 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
305 my $mss = $tagslib->{$tag}{$subfield};
306 next if IsMarcStructureInternal($mss);
307 next if $mss->{tab} == -1;
308 # We only need to display the values
309 my $value = join '; ', map { $tag < 10 ? $_->data : $_->subfield( $subfield ) } @fields;
311 push @catalog_details, {
313 subfield => $subfield,
323 $template->param( catalog_details => \@catalog_details, );
326 $suggestion = GetSuggestionInfo($suggestionid) if $suggestionid;
328 my $active_currency = Koha::Acquisition::Currencies->get_active;
330 # build bookfund list
331 my $patron = Koha::Patrons->find( $loggedinuser )->unblessed;
333 my $budget = GetBudget($budget_id);
335 my $budget_loop = [];
336 my $budgets = GetBudgetHierarchy;
337 foreach my $r (@{$budgets}) {
338 next unless (CanUserUseBudget($patron, $r, $userflags));
339 push @{$budget_loop}, {
340 b_id => $r->{budget_id},
341 b_txt => $r->{budget_name},
342 b_sort1_authcat => $r->{'sort1_authcat'},
343 b_sort2_authcat => $r->{'sort2_authcat'},
344 b_active => $r->{budget_period_active},
345 b_sel => ( $r->{budget_id} == $budget_id ) ? 1 : 0,
346 b_level => $r->{budget_level},
351 $template->param( sort1 => $data->{'sort1'} );
352 $template->param( sort2 => $data->{'sort2'} );
354 if ($basketobj->effective_create_items eq 'ordering' && !$ordernumber) {
355 # Check if ACQ framework exists
356 my $marc = GetMarcStructure(1, 'ACQ', { unsafe => 1 } );
358 $template->param('NoACQframework' => 1);
361 AcqCreateItemOrdering => 1,
362 UniqueItemFields => C4::Context->preference('UniqueItemFields'),
366 my @itemtypes = Koha::ItemTypes->search->as_list;
368 if ( defined $from_subscriptionid ) {
369 # Get the last received order for this subscription
370 my $lastOrderReceived = Koha::Acquisition::Orders->search(
372 subscriptionid => $from_subscriptionid,
373 datereceived => { '!=' => undef }
377 [ { -desc => 'datereceived' }, { -desc => 'ordernumber' } ]
380 if ( $lastOrderReceived->count ) {
381 $lastOrderReceived = $lastOrderReceived->next->unblessed; # FIXME We should send the object to the template
382 $budget_id = $lastOrderReceived->{budgetid};
383 $data->{listprice} = $lastOrderReceived->{listprice};
384 $data->{uncertainprice} = $lastOrderReceived->{uncertainprice};
385 $data->{tax_rate} = $lastOrderReceived->{tax_rate_on_ordering};
386 $data->{discount} = $lastOrderReceived->{discount};
387 $data->{rrp} = $lastOrderReceived->{rrp};
388 $data->{replacementprice} = $lastOrderReceived->{replacementprice};
389 $data->{ecost} = $lastOrderReceived->{ecost};
390 $data->{quantity} = $lastOrderReceived->{quantity};
391 $data->{unitprice} = $lastOrderReceived->{unitprice};
392 $data->{order_internalnote} = $lastOrderReceived->{order_internalnote};
393 $data->{order_vendornote} = $lastOrderReceived->{order_vendornote};
394 $data->{sort1} = $lastOrderReceived->{sort1};
395 $data->{sort2} = $lastOrderReceived->{sort2};
397 $basket = GetBasket( $input->param('basketno') );
400 my $subscription = Koha::Subscriptions->find($from_subscriptionid);
402 subscriptionid => $from_subscriptionid,
403 subscription => $subscription,
407 # Find the items.barcode subfield for barcode validations
408 my (undef, $barcode_subfield) = GetMarcFromKohaField( 'items.barcode' );
411 # get option values for TaxRates syspref
412 my @gst_values = map {
414 }, split( '\|', C4::Context->preference("TaxRates") );
416 my $quantity = $input->param('rr_quantity_to_order') ?
417 $input->param('rr_quantity_to_order') :
423 existing => $biblionumber,
424 # basket informations
425 basketname => $basket->{'basketname'},
426 basketnote => $basket->{'note'},
427 booksellerid => $basket->{'booksellerid'},
428 basketbooksellernote => $basket->{booksellernote},
429 basketcontractno => $basket->{contractnumber},
430 basketcontractname => $contract->{contractname},
431 creationdate => $basket->{creationdate},
432 authorisedby => $basket->{'authorisedby'},
433 authorisedbyname => $basket->{'authorisedbyname'},
434 closedate => $basket->{'closedate'},
436 suggestionid => $suggestion->{suggestionid},
437 surnamesuggestedby => $suggestion->{surnamesuggestedby},
438 firstnamesuggestedby => $suggestion->{firstnamesuggestedby},
439 biblionumber => $biblionumber,
440 uncertainprice => $data->{'uncertainprice'},
441 discount_2dp => sprintf( "%.2f", $bookseller->discount ) , # for display
442 discount => $bookseller->discount,
443 orderdiscount_2dp => sprintf( "%.2f", $data->{'discount'} || 0 ),
444 orderdiscount => $data->{'discount'},
445 order_internalnote => $data->{'order_internalnote'},
446 order_vendornote => $data->{'order_vendornote'},
447 listincgst => $bookseller->listincgst,
448 invoiceincgst => $bookseller->invoiceincgst,
449 cur_active_sym => $active_currency->symbol,
450 cur_active => $active_currency->currency,
451 currencies => Koha::Acquisition::Currencies->search,
452 currency => $data->{currency},
453 vendor_currency => $bookseller->listprice,
454 orderexists => ( $new eq 'yes' ) ? 0 : 1,
455 title => $data->{'title'},
456 author => $data->{'author'},
457 publicationyear => $data->{'publicationyear'} ? $data->{'publicationyear'} : $data->{'copyrightdate'},
458 editionstatement => $data->{'editionstatement'},
459 budget_loop => $budget_loop,
460 isbn => $data->{'isbn'},
461 ean => $data->{'ean'},
462 seriestitle => $data->{'seriestitle'},
463 itemtypeloop => \@itemtypes,
464 quantity => $quantity,
465 quantityrec => $quantity,
466 rrp => $data->{'rrp'},
467 replacementprice => $data->{'replacementprice'},
468 gst_values => \@gst_values,
469 tax_rate => $data->{tax_rate_on_ordering} ? $data->{tax_rate_on_ordering}+0.0 : $bookseller->tax_rate ? $bookseller->tax_rate+0.0 : 0,
470 listprice => sprintf( "%.2f", $data->{listprice} || $data->{price} || $listprice),
471 total => sprintf( "%.2f", ($data->{ecost} || 0) * ($data->{'quantity'} || 0) ),
472 ecost => sprintf( "%.2f", $data->{ecost} || 0),
473 unitprice => sprintf( "%.2f", $data->{unitprice} || 0),
474 publishercode => $data->{'publishercode'},
475 barcode_subfield => $barcode_subfield,
476 import_batch_id => $import_batch_id,
477 acqcreate => $basketobj->effective_create_items eq "ordering" ? 1 : "",
478 users_ids => join(':', @order_user_ids),
479 users => \@order_users,
480 (uc(C4::Context->preference("marcflavour"))) => 1
483 output_html_with_http_headers $input, $cookie, $template->output;
486 =head2 MARCfindbreeding
488 $record = MARCfindbreeding($breedingid);
490 Look up the import record repository for the record with
491 record with id $breedingid. If found, returns the decoded
492 MARC::Record; otherwise, -1 is returned (FIXME).
493 Returns as second parameter the character encoding.
497 sub MARCfindbreeding {
499 my ($marc, $encoding) = GetImportRecordMarc($id);
500 # remove the - in isbn, koha store isbn without any -
502 my $record = MARC::Record->new_from_usmarc($marc);
503 my ($isbnfield,$isbnsubfield) = GetMarcFromKohaField( 'biblioitems.isbn' );
504 if ( $record->field($isbnfield) ) {
505 foreach my $field ( $record->field($isbnfield) ) {
506 foreach my $subfield ( $field->subfield($isbnsubfield) ) {
507 my $newisbn = $field->subfield($isbnsubfield);
509 $field->update( $isbnsubfield => $newisbn );
513 # fix the unimarc 100 coded field (with unicode information)
514 if ($marcflavour eq 'UNIMARC' && $record->subfield(100,'a')) {
515 my $f100a=$record->subfield(100,'a');
516 my $f100 = $record->field(100);
517 my $f100temp = $f100->as_string;
518 $record->delete_field($f100);
519 if ( length($f100temp) > 28 ) {
520 substr( $f100temp, 26, 2, "50" );
521 $f100->update( 'a' => $f100temp );
522 my $f100 = MARC::Field->new( '100', '', '', 'a' => $f100temp );
523 $record->insert_fields_ordered($f100);
527 if ( !defined(ref($record)) ) {
531 # normalize author : probably UNIMARC specific...
532 if ( C4::Context->preference("z3950NormalizeAuthor")
533 and C4::Context->preference("z3950AuthorAuthFields") )
535 my ( $tag, $subfield ) = GetMarcFromKohaField( "biblio.author" );
538 C4::Context->preference("z3950AuthorAuthFields");
539 my @auth_fields = split /,/, $auth_fields;
542 if ( $record->field($tag) ) {
543 foreach my $tmpfield ( $record->field($tag)->subfields ) {
545 my $subfieldcode = shift @$tmpfield;
546 my $subfieldvalue = shift @$tmpfield;
548 $field->add_subfields(
549 "$subfieldcode" => $subfieldvalue )
550 if ( $subfieldcode ne $subfield );
554 MARC::Field->new( $tag, "", "",
555 $subfieldcode => $subfieldvalue )
556 if ( $subfieldcode ne $subfield );
560 $record->delete_field( $record->field($tag) );
561 foreach my $fieldtag (@auth_fields) {
562 next unless ( $record->field($fieldtag) );
563 my $lastname = $record->field($fieldtag)->subfield('a');
564 my $firstname = $record->field($fieldtag)->subfield('b');
565 my $title = $record->field($fieldtag)->subfield('c');
566 my $number = $record->field($fieldtag)->subfield('d');
568 $field->add_subfields(
569 "$subfield" => ucfirst($title) . " "
570 . ucfirst($firstname) . " "
574 $field->add_subfields(
575 "$subfield" => ucfirst($firstname) . ", "
576 . ucfirst($lastname) );
579 $record->insert_fields_ordered($field);
581 return $record, $encoding;
588 my ($duplicatetitle)= @_;
589 ($template, $loggedinuser, $cookie) = get_template_and_user(
591 template_name => "acqui/neworderempty_duplicate.tt",
594 flagsrequired => { acquisition => 'order_manage' },
599 biblionumber => $biblionumber,
600 basketno => $basketno,
601 booksellerid => $basket->{'booksellerid'},
602 breedingid => $params->{'breedingid'},
603 duplicatetitle => $duplicatetitle,
604 (uc(C4::Context->preference("marcflavour"))) => 1
607 output_html_with_http_headers $input, $cookie, $template->output;