From e5c44980eed37ccf21ee2e0d95e7e5b205eec995 Mon Sep 17 00:00:00 2001 From: Matt Blenkinsop Date: Wed, 11 Oct 2023 15:20:14 +0000 Subject: [PATCH] Bug 35026: Refactor addorderiso2709.pl to use the MarcOrder class MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This script uses the newly created MarcOrder class to refactor the script into a cleaner controller function. This MarcOrder class will also be used in bug 34355 to automate the creation of order lines from marc records. Test plan: 1) In system preferences, click Search and then select the Acquisitions option from the left hand menu 2) Paste the following into MarcFieldsToOrder price: 975$p quantity: 975$q budget_code: 975$h 3) Paste the following into MarcItemFieldsToOrder homebranch: 949$a holdingbranch: 949$b itype: 949$y nonpublic_note: 949$x public_note: 949$z loc: 949$c ccode: 949$8 notforloan: 949$7 uri: 949$u copyno: 949$t price: 949$g replacementprice: 949$v itemcallnumber: 949$o quantity: 949$k budget_code: 949$l Now save the sysprefs 4) Navigate to acquisitions and go into a basket 5) Click Add to basket and select “From a new file” 6) Download the file attached to this bug 7) Import the file and when the job is complete click “Add staged files to basket” 8) Click the checkbox next to the record to display the items and confirm that the data matches the mappings from the file that you imported - there should be 8 items, grouped in 4 pairs of identical items 9) Fill in the required fields and click “Save” 10) That basket should be correctly populated with an order matching the file that you imported Signed-off-by: Barbara Johnson Signed-off-by: Nick Clemens Signed-off-by: Katrin Fischer --- Koha/MarcOrder.pm | 33 ++- acqui/addorderiso2709.pl | 604 ++++----------------------------------- 2 files changed, 90 insertions(+), 547 deletions(-) diff --git a/Koha/MarcOrder.pm b/Koha/MarcOrder.pm index 82dd86653f..09cb633a00 100644 --- a/Koha/MarcOrder.pm +++ b/Koha/MarcOrder.pm @@ -661,6 +661,14 @@ sub create_order_lines { return; } +=head3 import_batches_list + +Fetches import batches matching the batch to be added to the basket and adds these to the $template + +Koha::MarcOrder->import_batches_list($template); + +=cut + sub import_batches_list { my ( $self, $template ) = @_; my $batches = GetImportBatchRangeDesc(); @@ -699,6 +707,15 @@ sub import_batches_list { $template->param( num_results => $num_batches ); } +=head3 + +For an import batch, this function reads the files and creates all the relevant data pertaining to that file +It then passes this to the $template variable to be shown in the UI + +Koha::MarcOrder->import_biblios_list( $template, $cgiparams->{'import_batch_id'} ); + +=cut + sub import_biblios_list { my ( $self, $template, $import_batch_id ) = @_; my $batch = GetImportBatch( $import_batch_id, 'staged' ); @@ -797,7 +814,7 @@ sub import_biblios_list { 'uri', 'copyno', 'price', 'replacementprice', 'itemcallnumber', 'quantity', 'budget_code' ] ); - if ( %$alliteminfos != -1 ) { + if ( !$alliteminfos || %$alliteminfos != -1 ) { my $item_homebranch = $alliteminfos->{homebranch}; my $item_holdingbranch = $alliteminfos->{holdingbranch}; my $item_itype = $alliteminfos->{itype}; @@ -855,7 +872,7 @@ sub import_biblios_list { push @list, \%cellrecord; # If MarcItemFieldsToOrder is not set, we use MarcFieldsToOrder to populate the order form. - if ( %$alliteminfos == -1 ) { + if ( $alliteminfos || %$alliteminfos == -1 ) { $cellrecord{price} = $price || ''; $cellrecord{replacementprice} = $replacementprice || ''; $cellrecord{quantity} = $quantity || ''; @@ -896,6 +913,12 @@ sub import_biblios_list { _batch_info( $template, $batch ); } +=head3 + +Creates a hash of information to be used about an import batch in the template + +=cut + sub _batch_info { my ( $template, $batch ) = @_; $template->param( @@ -928,6 +951,12 @@ sub _batch_info { _add_matcher_list( $batch->{'matcher_id'}, $template ); } +=head3 + +Adds a list of available matchers based on an import batch + +=cut + sub _add_matcher_list { my ( $current_matcher_id, $template ) = @_; my @matchers = C4::Matcher::GetMatcherList(); diff --git a/acqui/addorderiso2709.pl b/acqui/addorderiso2709.pl index 4b4d899031..16fc83a9e0 100755 --- a/acqui/addorderiso2709.pl +++ b/acqui/addorderiso2709.pl @@ -30,7 +30,7 @@ use Scalar::Util qw( looks_like_number ); use C4::Context; use C4::Auth qw( get_template_and_user ); use C4::Output qw( output_html_with_http_headers ); -use C4::ImportBatch qw( SetImportBatchStatus GetImportBatch GetImportBatchRangeDesc GetNumberOfNonZ3950ImportBatches GetImportBatchOverlayAction GetImportBatchNoMatchAction GetImportBatchItemAction ); +use C4::ImportBatch qw( SetImportBatchStatus ); use C4::Matcher; use C4::Search qw( FindDuplicate ); use C4::Biblio qw( @@ -41,7 +41,7 @@ use C4::Biblio qw( TransformHtmlToXml ); use C4::Items qw( PrepareItemrecordDisplay AddItemFromMarc ); -use C4::Budgets qw( GetBudget GetBudgets GetBudgetHierarchy CanUserUseBudget GetBudgetByCode ); +use C4::Budgets qw( GetBudget GetBudgets GetBudgetHierarchy CanUserUseBudget ); use C4::Suggestions; # GetSuggestion use C4::Members; @@ -54,6 +54,7 @@ use Koha::Acquisition::Booksellers; use Koha::ImportBatches; use Koha::Import::Records; use Koha::Patrons; +use Koha::MarcOrder; my $input = CGI->new; my ($template, $loggedinuser, $cookie, $userflags) = get_template_and_user({ @@ -90,7 +91,7 @@ my $basket = Koha::Acquisition::Baskets->find( $cgiparams->{basketno} ); if ($op eq ""){ $template->param("basketno" => $cgiparams->{'basketno'}); #display batches - import_batches_list($template); + Koha::MarcOrder->import_batches_list($template); # # 2nd step = display the content of the chosen file # @@ -104,7 +105,7 @@ if ($op eq ""){ bookseller => $bookseller, "allmatch" => $allmatch, ); - import_biblios_list($template, $cgiparams->{'import_batch_id'}); + Koha::MarcOrder->import_biblios_list($template, $cgiparams->{'import_batch_id'}); if ( $basket->effective_create_items eq 'ordering' && !$basket->is_standing ) { # prepare empty item form my $cell = PrepareItemrecordDisplay( '', '', undef, 'ACQ' ); @@ -146,236 +147,66 @@ if ($op eq ""){ my @import_record_id_selected = $input->multi_param("import_record_id"); my $matcher_id = $input->param('matcher_id'); my $active_currency = Koha::Acquisition::Currencies->get_active; - my $biblio_count = 0; while( my $import_record = $import_records->next ){ - $biblio_count++; - my $duplifound = 0; - # Check if this import_record_id was selected - next if not grep { $_ eq $import_record->import_record_id } @import_record_id_selected; - my $marcrecord = $import_record->get_marc_record || die "couldn't translate marc information"; - my $matches = $import_record->get_import_record_matches({ chosen => 1 }); - my $match = $matches->count ? $matches->next : undef; - my $biblionumber = $match ? $match->candidate_match_id : 0; - my $c_quantity = - $input->param( 'quantity_' . $import_record->import_record_id ) - || GetMarcQuantity( $marcrecord, C4::Context->preference('marcflavour') ) - || 1; - my $c_budget_id = - $input->param( 'budget_id_' . $import_record->import_record_id ) - || $input->param('all_budget_id') - || $budget_id; - my $c_discount = $input->param( 'discount_' . $import_record->import_record_id ); - my $c_sort1 = $input->param( 'sort1_' . $import_record->import_record_id ) || $input->param('all_sort1') || ''; - my $c_sort2 = $input->param( 'sort2_' . $import_record->import_record_id ) || $input->param('all_sort2') || ''; - my $c_replacement_price = $input->param( 'replacementprice_' . $import_record->import_record_id ); - my $c_price = $input->param( 'price_' . $import_record->import_record_id ); - # Insert the biblio, or find it through matcher - if ( $biblionumber ) { # If matched during staging we can continue - $import_record->status('imported')->store; - if( $overlay_action eq 'replace' ){ - my $biblio = Koha::Biblios->find( $biblionumber ); - $import_record->replace({ biblio => $biblio }); - } - } else { # Otherwise we check for duplicates, and skip if they exist - if ($matcher_id) { - if ( $matcher_id eq '_TITLE_AUTHOR_' ) { - $duplifound = 1 if FindDuplicate($marcrecord); - } - else { - my $matcher = C4::Matcher->fetch($matcher_id); - my @matches = $matcher->get_matches( $marcrecord, my $max_matches = 1 ); - $duplifound = 1 if @matches; - } - - $duplinbatch = $import_batch_id and next if $duplifound; - } - - # remove hyphens (-) from ISBN - # FIXME: This should probably be optional - my ( $isbnfield, $isbnsubfield ) = GetMarcFromKohaField( 'biblioitems.isbn' ); - if ( $marcrecord->field($isbnfield) ) { - foreach my $field ( $marcrecord->field($isbnfield) ) { - foreach my $subfield ( $field->subfield($isbnsubfield) ) { - my $newisbn = $field->subfield($isbnsubfield); - $newisbn =~ s/-//g; - $field->update( $isbnsubfield => $newisbn ); - } - } - } - - # add the biblio - ( $biblionumber, undef ) = AddBiblio( $marcrecord, $cgiparams->{'frameworkcode'} || '' ); - $import_record->status('imported')->store; - } - - $import_record->import_biblio->matched_biblionumber($biblionumber)->store; - - # Add items from MarcItemFieldsToOrder - my @homebranches = $input->multi_param( 'homebranch_' . $import_record->import_record_id ); - my $count = scalar @homebranches; - my @holdingbranches = $input->multi_param( 'holdingbranch_' . $import_record->import_record_id ); - my @itypes = $input->multi_param( 'itype_' . $import_record->import_record_id ); - my @nonpublic_notes = $input->multi_param( 'nonpublic_note_' . $import_record->import_record_id ); - my @public_notes = $input->multi_param( 'public_note_' . $import_record->import_record_id ); - my @locs = $input->multi_param( 'loc_' . $import_record->import_record_id ); - my @ccodes = $input->multi_param( 'ccode_' . $import_record->import_record_id ); - my @notforloans = $input->multi_param( 'notforloan_' . $import_record->import_record_id ); - my @uris = $input->multi_param( 'uri_' . $import_record->import_record_id ); - my @copynos = $input->multi_param( 'copyno_' . $import_record->import_record_id ); - my @budget_ids = - $input->multi_param( 'budget_code_' . $import_record->import_record_id ); # bad field name used in template! + my $marcrecord = $import_record->get_marc_record || die "couldn't translate marc information"; + my @homebranches = $input->multi_param( 'homebranch_' . $import_record->import_record_id ); + my @holdingbranches = $input->multi_param( 'holdingbranch_' . $import_record->import_record_id ); + my @itypes = $input->multi_param( 'itype_' . $import_record->import_record_id ); + my @nonpublic_notes = $input->multi_param( 'nonpublic_note_' . $import_record->import_record_id ); + my @public_notes = $input->multi_param( 'public_note_' . $import_record->import_record_id ); + my @locs = $input->multi_param( 'loc_' . $import_record->import_record_id ); + my @ccodes = $input->multi_param( 'ccode_' . $import_record->import_record_id ); + my @notforloans = $input->multi_param( 'notforloan_' . $import_record->import_record_id ); + my @uris = $input->multi_param( 'uri_' . $import_record->import_record_id ); + my @copynos = $input->multi_param( 'copyno_' . $import_record->import_record_id ); + my @budget_codes = $input->multi_param( 'budget_code_' . $import_record->import_record_id ); my @itemprices = $input->multi_param( 'itemprice_' . $import_record->import_record_id ); my @replacementprices = $input->multi_param( 'itemreplacementprice_' . $import_record->import_record_id ); my @itemcallnumbers = $input->multi_param( 'itemcallnumber_' . $import_record->import_record_id ); - my @coded_location_qualifiers = - $input->multi_param( 'coded_location_qualifier_' . $import_record->import_record_id ); - my @barcodes = $input->multi_param( 'barcode_' . $import_record->import_record_id ); - my @enumchrons = $input->multi_param( 'enumchron_' . $import_record->import_record_id ); - my $itemcreation = 0; - - my @itemnumbers; - for (my $i = 0; $i < $count; $i++) { - $itemcreation = 1; - my $item = Koha::Item->new( - { - biblionumber => $biblionumber, - homebranch => $homebranches[$i], - holdingbranch => $holdingbranches[$i], - itemnotes_nonpublic => $nonpublic_notes[$i], - itemnotes => $public_notes[$i], - location => $locs[$i], - ccode => $ccodes[$i], - itype => $itypes[$i], - notforloan => $notforloans[$i], - uri => $uris[$i], - copynumber => $copynos[$i], - price => $itemprices[$i], - replacementprice => $replacementprices[$i], - itemcallnumber => $itemcallnumbers[$i], - coded_location_qualifier => $coded_location_qualifiers[$i], - barcode => $barcodes[$i], - enumchron => $enumchrons[$i], - } - )->store; - push( @itemnumbers, $item->itemnumber ); - } - if ($itemcreation == 1) { - # Group orderlines from MarcItemFieldsToOrder - my $budget_hash; - for (my $i = 0; $i < $count; $i++) { - $budget_ids[$i] = $budget_id if !$budget_ids[$i]; # Use default budget if no budget selected in the UI - $budget_hash->{ $budget_ids[$i] }->{quantity} += 1; - $budget_hash->{ $budget_ids[$i] }->{price} = $itemprices[$i]; - $budget_hash->{ $budget_ids[$i] }->{replacementprice} = - $replacementprices[$i]; - $budget_hash->{ $budget_ids[$i] }->{itemnumbers} //= []; - push @{ $budget_hash->{ $budget_ids[$i] }->{itemnumbers} }, - $itemnumbers[$i]; - } - - # Create orderlines from MarcItemFieldsToOrder - while(my ($budget_id, $infos) = each %$budget_hash) { - if ($budget_id) { - my %orderinfo = ( - biblionumber => $biblionumber, - basketno => $cgiparams->{'basketno'}, - quantity => $infos->{quantity}, - budget_id => $budget_id, - currency => $cgiparams->{'all_currency'}, - ); - - my $price = $infos->{price}; - if ($price){ - # in France, the cents separator is the , but sometimes, ppl use a . - # in this case, the price will be x100 when unformatted ! Replace the . by a , to get a proper price calculation - $price =~ s/\./,/ if C4::Context->preference("CurrencyFormat") eq "FR"; - $price = Koha::Number::Price->new($price)->unformat; - $orderinfo{tax_rate_on_ordering} = $bookseller->tax_rate; - $orderinfo{tax_rate_on_receiving} = $bookseller->tax_rate; - my $order_discount = $c_discount ? $c_discount : $bookseller->discount; - $orderinfo{discount} = $order_discount; - $orderinfo{rrp} = $price; - $orderinfo{ecost} = $order_discount ? $price * ( 1 - $order_discount / 100 ) : $price; - $orderinfo{listprice} = $orderinfo{rrp} / $active_currency->rate; - $orderinfo{unitprice} = $orderinfo{ecost}; - $orderinfo{sort1} = $c_sort1; - $orderinfo{sort2} = $c_sort2; - } else { - $orderinfo{listprice} = 0; - } - $orderinfo{replacementprice} = $infos->{replacementprice} || 0; - - # remove uncertainprice flag if we have found a price in the MARC record - $orderinfo{uncertainprice} = 0 if $orderinfo{listprice}; - my $order = Koha::Acquisition::Order->new( \%orderinfo ); - $order->populate_with_prices_for_ordering(); - $order->populate_with_prices_for_receiving(); - $order->store; - $order->add_item( $_ ) for @{ $budget_hash->{$budget_id}->{itemnumbers} }; - } - } - } else { - # 3rd add order - my $patron = Koha::Patrons->find( $loggedinuser ); - # get quantity in the MARC record (1 if none) - my $quantity = GetMarcQuantity($marcrecord, C4::Context->preference('marcflavour')) || 1; - my %orderinfo = ( - biblionumber => $biblionumber, - basketno => $cgiparams->{'basketno'}, - quantity => $c_quantity, - branchcode => $patron->branchcode, - budget_id => $c_budget_id, - uncertainprice => 1, - sort1 => $c_sort1, - sort2 => $c_sort2, - order_internalnote => $cgiparams->{'all_order_internalnote'}, - order_vendornote => $cgiparams->{'all_order_vendornote'}, - currency => $cgiparams->{'all_currency'}, - replacementprice => $c_replacement_price, - ); - # get the price if there is one. - if ($c_price){ - # in France, the cents separator is the , but sometimes, ppl use a . - # in this case, the price will be x100 when unformatted ! Replace the . by a , to get a proper price calculation - $c_price =~ s/\./,/ if C4::Context->preference("CurrencyFormat") eq "FR"; - $c_price = Koha::Number::Price->new($c_price)->unformat; - $orderinfo{tax_rate_on_ordering} = $bookseller->tax_rate; - $orderinfo{tax_rate_on_receiving} = $bookseller->tax_rate; - my $order_discount = $c_discount ? $c_discount : $bookseller->discount; - $orderinfo{discount} = $order_discount; - $orderinfo{rrp} = $c_price; - $orderinfo{ecost} = $order_discount ? $c_price * ( 1 - $order_discount / 100 ) : $c_price; - $orderinfo{listprice} = $orderinfo{rrp} / $active_currency->rate; - $orderinfo{unitprice} = $orderinfo{ecost}; - } else { - $orderinfo{listprice} = 0; - } + my $client_item_fields = { + homebranches => \@homebranches, + holdingbranches => \@holdingbranches, + itypes => \@itypes, + nonpublic_notes => \@nonpublic_notes, + public_notes => \@public_notes, + locs => \@locs, + ccodes => \@ccodes, + notforloans => \@notforloans, + uris => \@uris, + copynos => \@copynos, + budget_codes => \@budget_codes, + itemprices => \@itemprices, + replacementprices => \@replacementprices, + itemcallnumbers => \@itemcallnumbers, + c_quantity => shift(@quantities) + || GetMarcQuantity( $marcrecord, C4::Context->preference('marcflavour') ) + || 1, + c_budget_id => shift(@budgets_id) || $input->param('all_budget_id') || $budget_id, + c_discount => shift(@discount), + c_sort1 => shift(@sort1) || $input->param('all_sort1') || '', + c_sort2 => shift(@sort2) || $input->param('all_sort2') || '', + c_replacement_price => shift(@orderreplacementprices), + c_price => shift(@prices) || GetMarcPrice( $marcrecord, C4::Context->preference('marcflavour') ), + }; + + my $args = { + import_batch_id => $import_batch_id, + import_record => $import_record, + matcher_id => $matcher_id, + overlay_action => $overlay_action, + agent => 'client', + import_record_id_selected => \@import_record_id_selected, + client_item_fields => $client_item_fields, + basket_id => $cgiparams->{'basketno'}, + vendor => $bookseller, + budget_id => $budget_id, + }; + my $result = Koha::MarcOrder->import_record_and_create_order_lines($args); + + $duplinbatch = $result->{duplicates_in_batch} if $result->{duplicates_in_batch}; + next if $result->{skip}; # If a duplicate is found, or the import record wasn't selected it will be skipped - # remove uncertainprice flag if we have found a price in the MARC record - $orderinfo{uncertainprice} = 0 if $orderinfo{listprice}; - - my $order = Koha::Acquisition::Order->new( \%orderinfo ); - $order->populate_with_prices_for_ordering(); - $order->populate_with_prices_for_receiving(); - $order->store; - - # 4th, add items if applicable - # parse the item sent by the form, and create an item just for the import_record_id we are dealing with - # this is not optimised, but it's working ! - if ( $basket->effective_create_items eq 'ordering' && !$basket->is_standing ) { - my @tags = $input->multi_param('tag'); - my @subfields = $input->multi_param('subfield'); - my @field_values = $input->multi_param('field_value'); - my @serials = $input->multi_param('serial'); - my $xml = TransformHtmlToXml( \@tags, \@subfields, \@field_values ); - my $record = MARC::Record::new_from_xml( $xml, 'UTF-8' ); - for (my $qtyloop=1;$qtyloop <= $c_quantity;$qtyloop++) { - my ( $biblionumber, undef, $itemnumber ) = AddItemFromMarc( $record, $biblionumber ); - $order->add_item( $itemnumber ); - } - } - } $imported++; } @@ -421,320 +252,3 @@ foreach my $r ( @{$budgets_hierarchy} ) { $template->param( budget_loop => $budget_loop,); output_html_with_http_headers $input, $cookie, $template->output; - - -sub import_batches_list { - my ($template) = @_; - my $batches = GetImportBatchRangeDesc(); - - my @list = (); - foreach my $batch (@$batches) { - if ( $batch->{'import_status'} =~ /^staged$|^reverted$/ && $batch->{'record_type'} eq 'biblio') { - # check if there is at least 1 line still staged - my $import_records_count = Koha::Import::Records->search({ - import_batch_id => $batch->{'import_batch_id'}, - status => $batch->{import_status} - })->count; - if ( $import_records_count ) { - push @list, { - import_batch_id => $batch->{'import_batch_id'}, - num_records => $batch->{'num_records'}, - num_items => $batch->{'num_items'}, - staged_date => $batch->{'upload_timestamp'}, - import_status => $batch->{'import_status'}, - file_name => $batch->{'file_name'}, - comments => $batch->{'comments'}, - }; - } else { - # if there are no more line to includes, set the status to imported - # FIXME This should be removed in the future. - SetImportBatchStatus( $batch->{'import_batch_id'}, 'imported' ); - } - } - } - $template->param(batch_list => \@list); - my $num_batches = GetNumberOfNonZ3950ImportBatches(); - $template->param(num_results => $num_batches); -} - -sub import_biblios_list { - my ($template, $import_batch_id) = @_; - my $batch = GetImportBatch($import_batch_id,'staged'); - return () unless $batch and $batch->{import_status} =~ /^staged$|^reverted$/; - my $import_records = Koha::Import::Records->search({ - import_batch_id => $import_batch_id, - status => $batch->{import_status} - }); - my @list = (); - my $item_error = 0; - - my $ccodes = { map { $_->{authorised_value} => $_->{opac_description} } Koha::AuthorisedValues->get_descriptions_by_koha_field( { frameworkcode => '', kohafield => 'items.ccode' } ) }; - my $locations = { map { $_->{authorised_value} => $_->{opac_description} } Koha::AuthorisedValues->get_descriptions_by_koha_field( { frameworkcode => '', kohafield => 'items.location' } ) }; - my $notforloans = { map { $_->{authorised_value} => $_->{lib} } Koha::AuthorisedValues->get_descriptions_by_koha_field( { frameworkcode => '', kohafield => 'items.notforloan' } ) }; - # location list - my @locations; - foreach (sort keys %$locations) { - push @locations, { code => $_, description => "$_ - " . $locations->{$_} }; - } - my @ccodes; - foreach (sort {$ccodes->{$a} cmp $ccodes->{$b}} keys %$ccodes) { - push @ccodes, { code => $_, description => $ccodes->{$_} }; - } - my @notforloans; - foreach (sort {$notforloans->{$a} cmp $notforloans->{$b}} keys %$notforloans) { - push @notforloans, { code => $_, description => $notforloans->{$_} }; - } - - my $biblio_count = 0; - while ( my $import_record = $import_records->next ) { - my $item_id = 1; - $biblio_count++; - my $matches = $import_record->get_import_record_matches({ chosen => 1 }); - my $match = $matches->count ? $matches->next : undef; - my $match_biblio = $match ? Koha::Biblios->find({ biblionumber => $match->candidate_match_id }) : undef; - my %cellrecord = ( - import_record_id => $import_record->import_record_id, - import_biblio => $import_record->import_biblio, - import => 1, - status => $import_record->status, - record_sequence => $import_record->record_sequence, - overlay_status => $import_record->overlay_status, - match_biblionumber => $match ? $match->candidate_match_id : 0, - match_citation => $match_biblio ? ($match_biblio->title || '') . ' ' .( $match_biblio->author || ''): '', - match_score => $match ? $match->score : 0, - ); - my $marcrecord = $import_record->get_marc_record || die "couldn't translate marc information"; - - my $infos = get_infos_syspref('MarcFieldsToOrder', $marcrecord, ['price', 'quantity', 'budget_code', 'discount', 'sort1', 'sort2','replacementprice']); - my $price = looks_like_number($infos->{price}) ? $infos->{price} : GetMarcPrice( $marcrecord, C4::Context->preference('marcflavour') ); - my $replacementprice = $infos->{replacementprice}; - my $quantity = $infos->{quantity}; - my $budget_code = $infos->{budget_code}; - my $discount = $infos->{discount}; - my $sort1 = $infos->{sort1}; - my $sort2 = $infos->{sort2}; - my $budget_id; - - if ($budget_code) { - my $biblio_budget = GetBudgetByCode($budget_code); - if ($biblio_budget) { - $budget_id = $biblio_budget->{budget_id}; - } - } - - # Items - my @itemlist = (); - my $all_items_quantity = 0; - my $alliteminfos = get_marc_item_fields_to_order($marcrecord); - if ($alliteminfos != -1) { - foreach my $iteminfos (@$alliteminfos) { - # Quantity is required, default to one if not supplied - my $quantity = delete $iteminfos->{quantity} || 1; - - # Handle incorrectly named original parameters for MarcItemFieldsToOrder - $iteminfos->{location} = delete $iteminfos->{loc} if $iteminfos->{loc}; - $iteminfos->{copynumber} = delete $iteminfos->{copyno} if $iteminfos->{copyno}; - # Price is handled as "itemprice" in the UI form to distinguish from MarcFieldsToOrder - $iteminfos->{itemprice} = delete $iteminfos->{price} if $iteminfos->{price}; - - # Convert budge code to a budget id - my $item_budget_code = delete $iteminfos->{budget_code}; - if ( $item_budget_code ) { - my $item_budget = GetBudgetByCode( $item_budget_code ); - $iteminfos->{budget_id} = $item_budget->{budget_id} || $budget_id; - } - - $iteminfos->{price} ||= $price; # Fallback to order price if no item price was defined - - # Clone the item data for the needed quantity - # Add the incremented item id for each item in that quantity - for (my $i = 0; $i < $quantity; $i++) { - my $itemrecord = { %$iteminfos }; - $itemrecord->{item_id} = $item_id++; - $all_items_quantity++; - push @itemlist, $itemrecord; - } - } - - $cellrecord{'iteminfos'} = \@itemlist; - } else { - $cellrecord{'item_error'} = 1; - } - push @list, \%cellrecord; - - # If MarcItemFieldsToOrder is not set, we use MarcFieldsToOrder to populate the order form. - if ($alliteminfos == -1 || scalar(@$alliteminfos) == 0) { - $cellrecord{price} = $price || ''; - $cellrecord{replacementprice} = $replacementprice || ''; - $cellrecord{quantity} = $quantity || ''; - $cellrecord{budget_id} = $budget_id || ''; - } else { - # When using MarcItemFields to order we want the order to have the same quantity as total items - $cellrecord{quantity} = $all_items_quantity; - } - # The fields discount, sort1, and sort2 only exist at the order level, so always use MarcItemFieldsToOrder - $cellrecord{discount} = $discount || ''; - $cellrecord{sort1} = $sort1 || ''; - $cellrecord{sort2} = $sort2 || ''; - - } - my $num_records = $batch->{'num_records'}; - my $overlay_action = GetImportBatchOverlayAction($import_batch_id); - my $nomatch_action = GetImportBatchNoMatchAction($import_batch_id); - my $item_action = GetImportBatchItemAction($import_batch_id); - $template->param(import_biblio_list => \@list, - num_results => $num_records, - import_batch_id => $import_batch_id, - "overlay_action_${overlay_action}" => 1, - overlay_action => $overlay_action, - "nomatch_action_${nomatch_action}" => 1, - nomatch_action => $nomatch_action, - "item_action_${item_action}" => 1, - item_action => $item_action, - item_error => $item_error, - libraries => Koha::Libraries->search, - locationloop => \@locations, - itemtypes => Koha::ItemTypes->search, - ccodeloop => \@ccodes, - notforloanloop => \@notforloans, - ); - batch_info($template, $batch); -} - -sub batch_info { - my ($template, $batch) = @_; - $template->param(batch_info => 1, - file_name => $batch->{'file_name'}, - comments => $batch->{'comments'}, - import_status => $batch->{'import_status'}, - upload_timestamp => $batch->{'upload_timestamp'}, - num_records => $batch->{'num_records'}, - num_items => $batch->{'num_items'}); - if ($batch->{'num_records'} > 0) { - if ($batch->{'import_status'} eq 'staged' or $batch->{'import_status'} eq 'reverted') { - $template->param(can_commit => 1); - } - if ($batch->{'import_status'} eq 'imported') { - $template->param(can_revert => 1); - } - } - if (defined $batch->{'matcher_id'}) { - my $matcher = C4::Matcher->fetch($batch->{'matcher_id'}); - if (defined $matcher) { - $template->param('current_matcher_id' => $batch->{'matcher_id'}, - 'current_matcher_code' => $matcher->code(), - 'current_matcher_description' => $matcher->description()); - } - } - add_matcher_list($batch->{'matcher_id'}, $template); -} - -sub add_matcher_list { - my ($current_matcher_id, $template) = @_; - my @matchers = C4::Matcher::GetMatcherList(); - if (defined $current_matcher_id) { - for (my $i = 0; $i <= $#matchers; $i++) { - if ($matchers[$i]->{'matcher_id'} == $current_matcher_id) { - $matchers[$i]->{'selected'} = 1; - } - } - } - $template->param(available_matchers => \@matchers); -} - -sub get_infos_syspref { - my ($syspref_name, $record, $field_list) = @_; - my $yaml = C4::Context->yaml_preference($syspref_name); - - my $r; - for my $field_name ( @$field_list ) { - next unless exists $yaml->{$field_name}; - my @fields = split /\|/, $yaml->{$field_name}; - for my $field ( @fields ) { - my ( $f, $sf ) = split /\$/, $field; - next unless $f and $sf; - if ( my $v = $record->subfield( $f, $sf ) ) { - $r->{$field_name} = $v; - } - last if $yaml->{$field}; - } - } - return $r; -} - -sub equal_number_of_fields { - my ($tags_list, $record) = @_; - my $tag_fields_count; - for my $tag (@$tags_list) { - my @fields = $record->field($tag); - $tag_fields_count->{$tag} = scalar @fields; - } - - my $tags_count; - foreach my $key ( keys %$tag_fields_count ) { - if ( $tag_fields_count->{$key} > 0 ) { # Having 0 of a field is ok - $tags_count //= $tag_fields_count->{$key}; # Start with the count from the first occurrence - return -1 if $tag_fields_count->{$key} != $tags_count; # All counts of various fields should be equal if they exist - } - } - - return $tags_count; -} - -sub get_marc_item_fields_to_order { - my ($record) = @_; - - my $syspref = C4::Context->preference('MarcItemFieldsToOrder'); - $syspref = "$syspref\n\n"; # YAML is anal on ending \n. Surplus does not hurt - my $yaml = eval { - YAML::XS::Load(Encode::encode_utf8($syspref)); - }; - if ( $@ ) { - warn "Unable to parse $syspref syspref : $@"; - return (); - } - - my @result; - my @tags_list; - - # Check tags in syspref definition - for my $field_name ( keys %$yaml ) { - my @fields = split /\|/, $yaml->{$field_name}; - for my $field ( @fields ) { - my ( $f, $sf ) = split /\$/, $field; - next unless $f and $sf; - push @tags_list, $f; - } - } - @tags_list = List::MoreUtils::uniq(@tags_list); - - my $tags_count = equal_number_of_fields(\@tags_list, $record); - # Return if the number of these fields in the record is not the same. - return -1 if $tags_count == -1; - - # Gather the fields - my $fields_hash; - foreach my $tag (@tags_list) { - my @tmp_fields; - foreach my $field ($record->field($tag)) { - push @tmp_fields, $field; - } - $fields_hash->{$tag} = \@tmp_fields; - } - - for (my $i = 0; $i < $tags_count; $i++) { - my $r; - for my $field_name ( keys %$yaml ) { - my @fields = split /\|/, $yaml->{$field_name}; - for my $field ( @fields ) { - my ( $f, $sf ) = split /\$/, $field; - next unless $f and $sf; - my $v = $fields_hash->{$f}[$i] ? $fields_hash->{$f}[$i]->subfield( $sf ) : undef; - $r->{$field_name} = $v if (defined $v); - last if $yaml->{$field}; - } - } - push @result, $r; - } - return \@result; -} -- 2.39.5