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 #my $acq_mss = Koha::MarcSubfieldStructures->search({ frameworkcode => 'ACQ', tagfield => { '!=' => $itemnumber_tag } });
211 foreach my $tag ( sort keys %{$tagslib} ) {
213 next if $tag eq $itemnumber_tag; # skip items fields
214 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
215 my $mss = $tagslib->{$tag}{$subfield};
216 next if IsMarcStructureInternal($mss);
217 next if $mss->{tab} == -1;
218 my $value = $mss->{defaultvalue};
220 if ($suggestionid and $mss->{kohafield}) {
221 # Reading suggestion info if ordering from a suggestion
222 if ( $mss->{kohafield} eq 'biblio.title' ) {
223 $value = $data->{title};
225 elsif ( $mss->{kohafield} eq 'biblio.author' ) {
226 $value = $data->{author};
228 elsif ( $mss->{kohafield} eq 'biblioitems.publishercode' ) {
229 $value = $data->{publishercode};
231 elsif ( $mss->{kohafield} eq 'biblioitems.editionstatement' ) {
232 $value = $data->{editionstatement};
234 elsif ( $mss->{kohafield} eq 'biblioitems.publicationyear' ) {
235 $value = $data->{publicationyear};
237 elsif ( $mss->{kohafield} eq 'biblioitems.isbn' ) {
238 $value = $data->{isbn};
240 elsif ( $mss->{kohafield} eq 'biblio.seriestitle' ) {
241 $value = $data->{seriestitle};
247 # get today date & replace <<YYYY>>, <<YY>>, <<MM>>, <<DD>> if provided in the default value
248 my $today_dt = dt_from_string;
249 my $year = $today_dt->strftime('%Y');
250 my $shortyear = $today_dt->strftime('%y');
251 my $month = $today_dt->strftime('%m');
252 my $day = $today_dt->strftime('%d');
253 $value =~ s/<<YYYY>>/$year/g;
254 $value =~ s/<<YY>>/$shortyear/g;
255 $value =~ s/<<MM>>/$month/g;
256 $value =~ s/<<DD>>/$day/g;
258 # And <<USER>> with surname (?)
260 ( C4::Context->userenv
261 ? C4::Context->userenv->{'surname'}
262 : "superlibrarian" );
263 $value =~ s/<<USER>>/$username/g;
265 push @catalog_details, {
267 subfield => $subfield,
268 %$mss, # Do we need plugins support (?)
276 $data = GetOrder($ordernumber);
277 $budget_id = $data->{'budget_id'};
280 subscriptionid => $data->{subscriptionid},
283 $basket = GetBasket( $data->{'basketno'} );
284 $basketno = $basket->{'basketno'};
286 @order_user_ids = GetOrderUsers($ordernumber);
287 foreach my $order_user_id (@order_user_ids) {
288 # FIXME Could be improved with search -in
289 my $order_patron = Koha::Patrons->find( $order_user_id );
290 push @order_users, $order_patron if $order_patron;
293 $biblionumber = $data->{biblionumber};
296 # - no ordernumber but a biblionumber: from a subscription, from an existing record
297 # - no ordernumber, no biblionumber: from a suggestion, from a new order
298 if ( not $ordernumber or $biblionumber ) {
299 if ( C4::Context->preference('UseACQFrameworkForBiblioRecords') ) {
300 my $record = $biblionumber ? GetMarcBiblio({ biblionumber => $biblionumber }) : 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 @currencies = Koha::Acquisition::Currencies->search;
330 my $active_currency = Koha::Acquisition::Currencies->get_active;
332 # build bookfund list
333 my $patron = Koha::Patrons->find( $loggedinuser )->unblessed;
335 my $budget = GetBudget($budget_id);
337 my $budget_loop = [];
338 my $budgets = GetBudgetHierarchy;
339 foreach my $r (@{$budgets}) {
340 next unless (CanUserUseBudget($patron, $r, $userflags));
341 push @{$budget_loop}, {
342 b_id => $r->{budget_id},
343 b_txt => $r->{budget_name},
344 b_sort1_authcat => $r->{'sort1_authcat'},
345 b_sort2_authcat => $r->{'sort2_authcat'},
346 b_active => $r->{budget_period_active},
347 b_sel => ( $r->{budget_id} == $budget_id ) ? 1 : 0,
348 b_level => $r->{budget_level},
353 $template->param( sort1 => $data->{'sort1'} );
354 $template->param( sort2 => $data->{'sort2'} );
356 if ($basketobj->effective_create_items eq 'ordering' && !$ordernumber) {
357 # Check if ACQ framework exists
358 my $marc = GetMarcStructure(1, 'ACQ', { unsafe => 1 } );
360 $template->param('NoACQframework' => 1);
363 AcqCreateItemOrdering => 1,
364 UniqueItemFields => C4::Context->preference('UniqueItemFields'),
368 # Get the item types list, but only if item_level_itype is YES. Otherwise, it will be in the item, no need to display it in the biblio
370 @itemtypes = Koha::ItemTypes->search unless C4::Context->preference('item-level_itypes');
372 if ( defined $from_subscriptionid ) {
373 # Get the last received order for this subscription
374 my $lastOrderReceived = Koha::Acquisition::Orders->search(
376 subscriptionid => $from_subscriptionid,
377 datereceived => { '!=' => undef }
381 [ { -desc => 'datereceived' }, { -desc => 'ordernumber' } ]
384 if ( $lastOrderReceived->count ) {
385 $lastOrderReceived = $lastOrderReceived->next->unblessed; # FIXME We should send the object to the template
386 $budget_id = $lastOrderReceived->{budgetid};
387 $data->{listprice} = $lastOrderReceived->{listprice};
388 $data->{uncertainprice} = $lastOrderReceived->{uncertainprice};
389 $data->{tax_rate} = $lastOrderReceived->{tax_rate_on_ordering};
390 $data->{discount} = $lastOrderReceived->{discount};
391 $data->{rrp} = $lastOrderReceived->{rrp};
392 $data->{replacementprice} = $lastOrderReceived->{replacementprice};
393 $data->{ecost} = $lastOrderReceived->{ecost};
394 $data->{quantity} = $lastOrderReceived->{quantity};
395 $data->{unitprice} = $lastOrderReceived->{unitprice};
396 $data->{order_internalnote} = $lastOrderReceived->{order_internalnote};
397 $data->{order_vendornote} = $lastOrderReceived->{order_vendornote};
398 $data->{sort1} = $lastOrderReceived->{sort1};
399 $data->{sort2} = $lastOrderReceived->{sort2};
401 $basket = GetBasket( $input->param('basketno') );
404 my $subscription = Koha::Subscriptions->find($from_subscriptionid);
406 subscriptionid => $from_subscriptionid,
407 subscription => $subscription,
411 # Find the items.barcode subfield for barcode validations
412 my (undef, $barcode_subfield) = GetMarcFromKohaField( 'items.barcode' );
415 # get option values for TaxRates syspref
416 my @gst_values = map {
418 }, split( '\|', C4::Context->preference("TaxRates") );
420 my $quantity = $input->param('rr_quantity_to_order') ?
421 $input->param('rr_quantity_to_order') :
427 existing => $biblionumber,
428 # basket informations
429 basketname => $basket->{'basketname'},
430 basketnote => $basket->{'note'},
431 booksellerid => $basket->{'booksellerid'},
432 basketbooksellernote => $basket->{booksellernote},
433 basketcontractno => $basket->{contractnumber},
434 basketcontractname => $contract->{contractname},
435 creationdate => $basket->{creationdate},
436 authorisedby => $basket->{'authorisedby'},
437 authorisedbyname => $basket->{'authorisedbyname'},
438 closedate => $basket->{'closedate'},
440 suggestionid => $suggestion->{suggestionid},
441 surnamesuggestedby => $suggestion->{surnamesuggestedby},
442 firstnamesuggestedby => $suggestion->{firstnamesuggestedby},
443 biblionumber => $biblionumber,
444 uncertainprice => $data->{'uncertainprice'},
445 discount_2dp => sprintf( "%.2f", $bookseller->discount ) , # for display
446 discount => $bookseller->discount,
447 orderdiscount_2dp => sprintf( "%.2f", $data->{'discount'} || 0 ),
448 orderdiscount => $data->{'discount'},
449 order_internalnote => $data->{'order_internalnote'},
450 order_vendornote => $data->{'order_vendornote'},
451 listincgst => $bookseller->listincgst,
452 invoiceincgst => $bookseller->invoiceincgst,
453 cur_active_sym => $active_currency->symbol,
454 cur_active => $active_currency->currency,
455 currencies => \@currencies,
456 currency => $data->{currency},
457 vendor_currency => $bookseller->listprice,
458 orderexists => ( $new eq 'yes' ) ? 0 : 1,
459 title => $data->{'title'},
460 author => $data->{'author'},
461 publicationyear => $data->{'publicationyear'} ? $data->{'publicationyear'} : $data->{'copyrightdate'},
462 editionstatement => $data->{'editionstatement'},
463 budget_loop => $budget_loop,
464 isbn => $data->{'isbn'},
465 ean => $data->{'ean'},
466 seriestitle => $data->{'seriestitle'},
467 itemtypeloop => \@itemtypes,
468 quantity => $quantity,
469 quantityrec => $quantity,
470 rrp => $data->{'rrp'},
471 replacementprice => $data->{'replacementprice'},
472 gst_values => \@gst_values,
473 tax_rate => $data->{tax_rate_on_ordering} ? $data->{tax_rate_on_ordering}+0.0 : $bookseller->tax_rate ? $bookseller->tax_rate+0.0 : 0,
474 listprice => sprintf( "%.2f", $data->{listprice} || $data->{price} || $listprice),
475 total => sprintf( "%.2f", ($data->{ecost} || 0) * ($data->{'quantity'} || 0) ),
476 ecost => sprintf( "%.2f", $data->{ecost} || 0),
477 unitprice => sprintf( "%.2f", $data->{unitprice} || 0),
478 publishercode => $data->{'publishercode'},
479 barcode_subfield => $barcode_subfield,
480 import_batch_id => $import_batch_id,
481 acqcreate => $basketobj->effective_create_items eq "ordering" ? 1 : "",
482 users_ids => join(':', @order_user_ids),
483 users => \@order_users,
484 (uc(C4::Context->preference("marcflavour"))) => 1
487 output_html_with_http_headers $input, $cookie, $template->output;
490 =head2 MARCfindbreeding
492 $record = MARCfindbreeding($breedingid);
494 Look up the import record repository for the record with
495 record with id $breedingid. If found, returns the decoded
496 MARC::Record; otherwise, -1 is returned (FIXME).
497 Returns as second parameter the character encoding.
501 sub MARCfindbreeding {
503 my ($marc, $encoding) = GetImportRecordMarc($id);
504 # remove the - in isbn, koha store isbn without any -
506 my $record = MARC::Record->new_from_usmarc($marc);
507 my ($isbnfield,$isbnsubfield) = GetMarcFromKohaField( 'biblioitems.isbn' );
508 if ( $record->field($isbnfield) ) {
509 foreach my $field ( $record->field($isbnfield) ) {
510 foreach my $subfield ( $field->subfield($isbnsubfield) ) {
511 my $newisbn = $field->subfield($isbnsubfield);
513 $field->update( $isbnsubfield => $newisbn );
517 # fix the unimarc 100 coded field (with unicode information)
518 if ($marcflavour eq 'UNIMARC' && $record->subfield(100,'a')) {
519 my $f100a=$record->subfield(100,'a');
520 my $f100 = $record->field(100);
521 my $f100temp = $f100->as_string;
522 $record->delete_field($f100);
523 if ( length($f100temp) > 28 ) {
524 substr( $f100temp, 26, 2, "50" );
525 $f100->update( 'a' => $f100temp );
526 my $f100 = MARC::Field->new( '100', '', '', 'a' => $f100temp );
527 $record->insert_fields_ordered($f100);
531 if ( !defined(ref($record)) ) {
535 # normalize author : probably UNIMARC specific...
536 if ( C4::Context->preference("z3950NormalizeAuthor")
537 and C4::Context->preference("z3950AuthorAuthFields") )
539 my ( $tag, $subfield ) = GetMarcFromKohaField( "biblio.author" );
542 C4::Context->preference("z3950AuthorAuthFields");
543 my @auth_fields = split /,/, $auth_fields;
546 if ( $record->field($tag) ) {
547 foreach my $tmpfield ( $record->field($tag)->subfields ) {
549 my $subfieldcode = shift @$tmpfield;
550 my $subfieldvalue = shift @$tmpfield;
552 $field->add_subfields(
553 "$subfieldcode" => $subfieldvalue )
554 if ( $subfieldcode ne $subfield );
558 MARC::Field->new( $tag, "", "",
559 $subfieldcode => $subfieldvalue )
560 if ( $subfieldcode ne $subfield );
564 $record->delete_field( $record->field($tag) );
565 foreach my $fieldtag (@auth_fields) {
566 next unless ( $record->field($fieldtag) );
567 my $lastname = $record->field($fieldtag)->subfield('a');
568 my $firstname = $record->field($fieldtag)->subfield('b');
569 my $title = $record->field($fieldtag)->subfield('c');
570 my $number = $record->field($fieldtag)->subfield('d');
572 $field->add_subfields(
573 "$subfield" => ucfirst($title) . " "
574 . ucfirst($firstname) . " "
578 $field->add_subfields(
579 "$subfield" => ucfirst($firstname) . ", "
580 . ucfirst($lastname) );
583 $record->insert_fields_ordered($field);
585 return $record, $encoding;
592 my ($duplicatetitle)= @_;
593 ($template, $loggedinuser, $cookie) = get_template_and_user(
595 template_name => "acqui/neworderempty_duplicate.tt",
598 flagsrequired => { acquisition => 'order_manage' },
603 biblionumber => $biblionumber,
604 basketno => $basketno,
605 booksellerid => $basket->{'booksellerid'},
606 breedingid => $params->{'breedingid'},
607 duplicatetitle => $duplicatetitle,
608 (uc(C4::Context->preference("marcflavour"))) => 1
611 output_html_with_http_headers $input, $cookie, $template->output;