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 # 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
368 @itemtypes = Koha::ItemTypes->search->as_list unless C4::Context->preference('item-level_itypes');
370 if ( defined $from_subscriptionid ) {
371 # Get the last received order for this subscription
372 my $lastOrderReceived = Koha::Acquisition::Orders->search(
374 subscriptionid => $from_subscriptionid,
375 datereceived => { '!=' => undef }
379 [ { -desc => 'datereceived' }, { -desc => 'ordernumber' } ]
382 if ( $lastOrderReceived->count ) {
383 $lastOrderReceived = $lastOrderReceived->next->unblessed; # FIXME We should send the object to the template
384 $budget_id = $lastOrderReceived->{budgetid};
385 $data->{listprice} = $lastOrderReceived->{listprice};
386 $data->{uncertainprice} = $lastOrderReceived->{uncertainprice};
387 $data->{tax_rate} = $lastOrderReceived->{tax_rate_on_ordering};
388 $data->{discount} = $lastOrderReceived->{discount};
389 $data->{rrp} = $lastOrderReceived->{rrp};
390 $data->{replacementprice} = $lastOrderReceived->{replacementprice};
391 $data->{ecost} = $lastOrderReceived->{ecost};
392 $data->{quantity} = $lastOrderReceived->{quantity};
393 $data->{unitprice} = $lastOrderReceived->{unitprice};
394 $data->{order_internalnote} = $lastOrderReceived->{order_internalnote};
395 $data->{order_vendornote} = $lastOrderReceived->{order_vendornote};
396 $data->{sort1} = $lastOrderReceived->{sort1};
397 $data->{sort2} = $lastOrderReceived->{sort2};
399 $basket = GetBasket( $input->param('basketno') );
402 my $subscription = Koha::Subscriptions->find($from_subscriptionid);
404 subscriptionid => $from_subscriptionid,
405 subscription => $subscription,
409 # Find the items.barcode subfield for barcode validations
410 my (undef, $barcode_subfield) = GetMarcFromKohaField( 'items.barcode' );
413 # get option values for TaxRates syspref
414 my @gst_values = map {
416 }, split( '\|', C4::Context->preference("TaxRates") );
418 my $quantity = $input->param('rr_quantity_to_order') ?
419 $input->param('rr_quantity_to_order') :
425 existing => $biblionumber,
426 # basket informations
427 basketname => $basket->{'basketname'},
428 basketnote => $basket->{'note'},
429 booksellerid => $basket->{'booksellerid'},
430 basketbooksellernote => $basket->{booksellernote},
431 basketcontractno => $basket->{contractnumber},
432 basketcontractname => $contract->{contractname},
433 creationdate => $basket->{creationdate},
434 authorisedby => $basket->{'authorisedby'},
435 authorisedbyname => $basket->{'authorisedbyname'},
436 closedate => $basket->{'closedate'},
438 suggestionid => $suggestion->{suggestionid},
439 surnamesuggestedby => $suggestion->{surnamesuggestedby},
440 firstnamesuggestedby => $suggestion->{firstnamesuggestedby},
441 biblionumber => $biblionumber,
442 uncertainprice => $data->{'uncertainprice'},
443 discount_2dp => sprintf( "%.2f", $bookseller->discount ) , # for display
444 discount => $bookseller->discount,
445 orderdiscount_2dp => sprintf( "%.2f", $data->{'discount'} || 0 ),
446 orderdiscount => $data->{'discount'},
447 order_internalnote => $data->{'order_internalnote'},
448 order_vendornote => $data->{'order_vendornote'},
449 listincgst => $bookseller->listincgst,
450 invoiceincgst => $bookseller->invoiceincgst,
451 cur_active_sym => $active_currency->symbol,
452 cur_active => $active_currency->currency,
453 currencies => Koha::Acquisition::Currencies->search,
454 currency => $data->{currency},
455 vendor_currency => $bookseller->listprice,
456 orderexists => ( $new eq 'yes' ) ? 0 : 1,
457 title => $data->{'title'},
458 author => $data->{'author'},
459 publicationyear => $data->{'publicationyear'} ? $data->{'publicationyear'} : $data->{'copyrightdate'},
460 editionstatement => $data->{'editionstatement'},
461 budget_loop => $budget_loop,
462 isbn => $data->{'isbn'},
463 ean => $data->{'ean'},
464 seriestitle => $data->{'seriestitle'},
465 itemtypeloop => \@itemtypes,
466 quantity => $quantity,
467 quantityrec => $quantity,
468 rrp => $data->{'rrp'},
469 replacementprice => $data->{'replacementprice'},
470 gst_values => \@gst_values,
471 tax_rate => $data->{tax_rate_on_ordering} ? $data->{tax_rate_on_ordering}+0.0 : $bookseller->tax_rate ? $bookseller->tax_rate+0.0 : 0,
472 listprice => sprintf( "%.2f", $data->{listprice} || $data->{price} || $listprice),
473 total => sprintf( "%.2f", ($data->{ecost} || 0) * ($data->{'quantity'} || 0) ),
474 ecost => sprintf( "%.2f", $data->{ecost} || 0),
475 unitprice => sprintf( "%.2f", $data->{unitprice} || 0),
476 publishercode => $data->{'publishercode'},
477 barcode_subfield => $barcode_subfield,
478 import_batch_id => $import_batch_id,
479 acqcreate => $basketobj->effective_create_items eq "ordering" ? 1 : "",
480 users_ids => join(':', @order_user_ids),
481 users => \@order_users,
482 (uc(C4::Context->preference("marcflavour"))) => 1
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;