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;
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 $biblio = Koha::Biblios->find($biblionumber);
300 my $record = $biblio ? $biblio->metadata->record : undef;
301 foreach my $tag ( sort keys %{$tagslib} ) {
303 next if $tag eq $itemnumber_tag; # skip items fields
304 my @fields = $biblionumber ? $record->field($tag) : ();
305 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
306 my $mss = $tagslib->{$tag}{$subfield};
307 next if IsMarcStructureInternal($mss);
308 next if $mss->{tab} == -1;
309 # We only need to display the values
310 my $value = join '; ', map { $tag < 10 ? $_->data : $_->subfield( $subfield ) } @fields;
312 push @catalog_details, {
314 subfield => $subfield,
324 $template->param( catalog_details => \@catalog_details, );
327 $suggestion = GetSuggestionInfo($suggestionid) if $suggestionid;
329 my $active_currency = Koha::Acquisition::Currencies->get_active;
331 # build bookfund list
332 my $patron = Koha::Patrons->find( $loggedinuser )->unblessed;
334 my $budget = GetBudget($budget_id);
336 my $budget_loop = [];
337 my $budgets = GetBudgetHierarchy;
338 foreach my $r (@{$budgets}) {
339 next unless (CanUserUseBudget($patron, $r, $userflags));
340 push @{$budget_loop}, {
341 b_id => $r->{budget_id},
342 b_txt => $r->{budget_name},
343 b_sort1_authcat => $r->{'sort1_authcat'},
344 b_sort2_authcat => $r->{'sort2_authcat'},
345 b_active => $r->{budget_period_active},
346 b_sel => ( $r->{budget_id} == $budget_id ) ? 1 : 0,
347 b_level => $r->{budget_level},
352 $template->param( sort1 => $data->{'sort1'} );
353 $template->param( sort2 => $data->{'sort2'} );
355 if ($basketobj->effective_create_items eq 'ordering' && !$ordernumber) {
356 # Check if ACQ framework exists
357 my $marc = GetMarcStructure(1, 'ACQ', { unsafe => 1 } );
359 $template->param('NoACQframework' => 1);
362 AcqCreateItemOrdering => 1,
363 UniqueItemFields => C4::Context->preference('UniqueItemFields'),
367 my @itemtypes = Koha::ItemTypes->search->as_list;
369 if ( defined $from_subscriptionid ) {
370 # Get the last received order for this subscription
371 my $lastOrderReceived = Koha::Acquisition::Orders->search(
373 subscriptionid => $from_subscriptionid,
374 datereceived => { '!=' => undef }
378 [ { -desc => 'datereceived' }, { -desc => 'ordernumber' } ]
381 if ( $lastOrderReceived->count ) {
382 $lastOrderReceived = $lastOrderReceived->next->unblessed; # FIXME We should send the object to the template
383 $budget_id = $lastOrderReceived->{budgetid};
384 $data->{listprice} = $lastOrderReceived->{listprice};
385 $data->{uncertainprice} = $lastOrderReceived->{uncertainprice};
386 $data->{tax_rate} = $lastOrderReceived->{tax_rate_on_ordering};
387 $data->{discount} = $lastOrderReceived->{discount};
388 $data->{rrp} = $lastOrderReceived->{rrp};
389 $data->{replacementprice} = $lastOrderReceived->{replacementprice};
390 $data->{ecost} = $lastOrderReceived->{ecost};
391 $data->{quantity} = $lastOrderReceived->{quantity};
392 $data->{unitprice} = $lastOrderReceived->{unitprice};
393 $data->{order_internalnote} = $lastOrderReceived->{order_internalnote};
394 $data->{order_vendornote} = $lastOrderReceived->{order_vendornote};
395 $data->{sort1} = $lastOrderReceived->{sort1};
396 $data->{sort2} = $lastOrderReceived->{sort2};
398 $basket = GetBasket( $input->param('basketno') );
401 my $subscription = Koha::Subscriptions->find($from_subscriptionid);
403 subscriptionid => $from_subscriptionid,
404 subscription => $subscription,
408 # Find the items.barcode subfield for barcode validations
409 my (undef, $barcode_subfield) = GetMarcFromKohaField( 'items.barcode' );
412 # get option values for TaxRates syspref
413 my @gst_values = map {
415 }, split( '\|', C4::Context->preference("TaxRates") );
417 my $quantity = $input->param('rr_quantity_to_order') ?
418 $input->param('rr_quantity_to_order') :
424 existing => $biblionumber,
425 # basket informations
426 basketname => $basket->{'basketname'},
427 basketnote => $basket->{'note'},
428 booksellerid => $basket->{'booksellerid'},
429 basketbooksellernote => $basket->{booksellernote},
430 basketcontractno => $basket->{contractnumber},
431 basketcontractname => $contract->{contractname},
432 creationdate => $basket->{creationdate},
433 authorisedby => $basket->{'authorisedby'},
434 authorisedbyname => $basket->{'authorisedbyname'},
435 closedate => $basket->{'closedate'},
437 suggestionid => $suggestion->{suggestionid},
438 surnamesuggestedby => $suggestion->{surnamesuggestedby},
439 firstnamesuggestedby => $suggestion->{firstnamesuggestedby},
440 biblionumber => $biblionumber,
441 uncertainprice => $data->{'uncertainprice'},
442 discount_2dp => sprintf( "%.2f", $bookseller->discount ) , # for display
443 discount => $bookseller->discount,
444 orderdiscount_2dp => sprintf( "%.2f", $data->{'discount'} || 0 ),
445 orderdiscount => $data->{'discount'},
446 order_internalnote => $data->{'order_internalnote'},
447 order_vendornote => $data->{'order_vendornote'},
448 listincgst => $bookseller->listincgst,
449 invoiceincgst => $bookseller->invoiceincgst,
450 cur_active_sym => $active_currency->symbol,
451 cur_active => $active_currency->currency,
452 currencies => Koha::Acquisition::Currencies->search,
453 currency => $data->{currency},
454 vendor_currency => $bookseller->listprice,
455 orderexists => ( $new eq 'yes' ) ? 0 : 1,
456 title => $data->{'title'},
457 author => $data->{'author'},
458 publicationyear => $data->{'publicationyear'} ? $data->{'publicationyear'} : $data->{'copyrightdate'},
459 editionstatement => $data->{'editionstatement'},
460 budget_loop => $budget_loop,
461 isbn => $data->{'isbn'},
462 ean => $data->{'ean'},
463 seriestitle => $data->{'seriestitle'},
464 itemtypeloop => \@itemtypes,
465 quantity => $quantity,
466 quantityrec => $quantity,
467 rrp => $data->{'rrp'},
468 replacementprice => $data->{'replacementprice'},
469 gst_values => \@gst_values,
470 tax_rate => $data->{tax_rate_on_ordering} ? $data->{tax_rate_on_ordering}+0.0 : $bookseller->tax_rate ? $bookseller->tax_rate+0.0 : 0,
471 listprice => sprintf( "%.2f", $data->{listprice} || $data->{price} || $listprice),
472 total => sprintf( "%.2f", ($data->{ecost} || 0) * ($data->{'quantity'} || 0) ),
473 ecost => sprintf( "%.2f", $data->{ecost} || 0),
474 unitprice => sprintf( "%.2f", $data->{unitprice} || 0),
475 publishercode => $data->{'publishercode'},
476 barcode_subfield => $barcode_subfield,
477 import_batch_id => $import_batch_id,
478 acqcreate => $basketobj->effective_create_items eq "ordering" ? 1 : "",
479 users_ids => join(':', @order_user_ids),
480 users => \@order_users,
481 (uc(C4::Context->preference("marcflavour"))) => 1,
482 estimated_delivery_date => $data->{estimated_delivery_date},
485 output_html_with_http_headers $input, $cookie, $template->output;
488 =head2 MARCfindbreeding
490 $record = MARCfindbreeding($breedingid);
492 Look up the import record repository for the record with
493 record with id $breedingid. If found, returns the decoded
494 MARC::Record; otherwise, -1 is returned (FIXME).
495 Returns as second parameter the character encoding.
499 sub MARCfindbreeding {
501 my ($marc, $encoding) = GetImportRecordMarc($id);
502 # remove the - in isbn, koha store isbn without any -
504 my $record = MARC::Record->new_from_usmarc($marc);
505 my ($isbnfield,$isbnsubfield) = GetMarcFromKohaField( 'biblioitems.isbn' );
506 if ( $record->field($isbnfield) ) {
507 foreach my $field ( $record->field($isbnfield) ) {
508 foreach my $subfield ( $field->subfield($isbnsubfield) ) {
509 my $newisbn = $field->subfield($isbnsubfield);
511 $field->update( $isbnsubfield => $newisbn );
515 # fix the unimarc 100 coded field (with unicode information)
516 if ($marcflavour eq 'UNIMARC' && $record->subfield(100,'a')) {
517 my $f100a=$record->subfield(100,'a');
518 my $f100 = $record->field(100);
519 my $f100temp = $f100->as_string;
520 $record->delete_field($f100);
521 if ( length($f100temp) > 28 ) {
522 substr( $f100temp, 26, 2, "50" );
523 $f100->update( 'a' => $f100temp );
524 my $f100 = MARC::Field->new( '100', '', '', 'a' => $f100temp );
525 $record->insert_fields_ordered($f100);
529 if ( !defined(ref($record)) ) {
533 # normalize author : probably UNIMARC specific...
534 if ( C4::Context->preference("z3950NormalizeAuthor")
535 and C4::Context->preference("z3950AuthorAuthFields") )
537 my ( $tag, $subfield ) = GetMarcFromKohaField( "biblio.author" );
540 C4::Context->preference("z3950AuthorAuthFields");
541 my @auth_fields = split /,/, $auth_fields;
544 if ( $record->field($tag) ) {
545 foreach my $tmpfield ( $record->field($tag)->subfields ) {
547 my $subfieldcode = shift @$tmpfield;
548 my $subfieldvalue = shift @$tmpfield;
550 $field->add_subfields(
551 "$subfieldcode" => $subfieldvalue )
552 if ( $subfieldcode ne $subfield );
556 MARC::Field->new( $tag, "", "",
557 $subfieldcode => $subfieldvalue )
558 if ( $subfieldcode ne $subfield );
562 $record->delete_field( $record->field($tag) );
563 foreach my $fieldtag (@auth_fields) {
564 next unless ( $record->field($fieldtag) );
565 my $lastname = $record->field($fieldtag)->subfield('a');
566 my $firstname = $record->field($fieldtag)->subfield('b');
567 my $title = $record->field($fieldtag)->subfield('c');
568 my $number = $record->field($fieldtag)->subfield('d');
570 $field->add_subfields(
571 "$subfield" => ucfirst($title) . " "
572 . ucfirst($firstname) . " "
576 $field->add_subfields(
577 "$subfield" => ucfirst($firstname) . ", "
578 . ucfirst($lastname) );
581 $record->insert_fields_ordered($field);
583 return $record, $encoding;
590 my ($duplicatetitle)= @_;
591 ($template, $loggedinuser, $cookie) = get_template_and_user(
593 template_name => "acqui/neworderempty_duplicate.tt",
596 flagsrequired => { acquisition => 'order_manage' },
601 biblionumber => $biblionumber,
602 basketno => $basketno,
603 booksellerid => $basket->{'booksellerid'},
604 breedingid => $params->{'breedingid'},
605 duplicatetitle => $duplicatetitle,
606 (uc(C4::Context->preference("marcflavour"))) => 1
609 output_html_with_http_headers $input, $cookie, $template->output;