Lines 30-36
use Scalar::Util qw( looks_like_number );
Link Here
|
30 |
use C4::Context; |
30 |
use C4::Context; |
31 |
use C4::Auth qw( get_template_and_user ); |
31 |
use C4::Auth qw( get_template_and_user ); |
32 |
use C4::Output qw( output_html_with_http_headers ); |
32 |
use C4::Output qw( output_html_with_http_headers ); |
33 |
use C4::ImportBatch qw( SetImportBatchStatus GetImportBatch GetImportBatchRangeDesc GetNumberOfNonZ3950ImportBatches GetImportBatchOverlayAction GetImportBatchNoMatchAction GetImportBatchItemAction ); |
33 |
use C4::ImportBatch qw( SetImportBatchStatus ); |
34 |
use C4::Matcher; |
34 |
use C4::Matcher; |
35 |
use C4::Search qw( FindDuplicate ); |
35 |
use C4::Search qw( FindDuplicate ); |
36 |
use C4::Biblio qw( |
36 |
use C4::Biblio qw( |
Lines 41-47
use C4::Biblio qw(
Link Here
|
41 |
TransformHtmlToXml |
41 |
TransformHtmlToXml |
42 |
); |
42 |
); |
43 |
use C4::Items qw( PrepareItemrecordDisplay AddItemFromMarc ); |
43 |
use C4::Items qw( PrepareItemrecordDisplay AddItemFromMarc ); |
44 |
use C4::Budgets qw( GetBudget GetBudgets GetBudgetHierarchy CanUserUseBudget GetBudgetByCode ); |
44 |
use C4::Budgets qw( GetBudget GetBudgets GetBudgetHierarchy CanUserUseBudget ); |
45 |
use C4::Suggestions; # GetSuggestion |
45 |
use C4::Suggestions; # GetSuggestion |
46 |
use C4::Members; |
46 |
use C4::Members; |
47 |
|
47 |
|
Lines 54-59
use Koha::Acquisition::Booksellers;
Link Here
|
54 |
use Koha::ImportBatches; |
54 |
use Koha::ImportBatches; |
55 |
use Koha::Import::Records; |
55 |
use Koha::Import::Records; |
56 |
use Koha::Patrons; |
56 |
use Koha::Patrons; |
|
|
57 |
use Koha::MarcOrder; |
57 |
|
58 |
|
58 |
my $input = CGI->new; |
59 |
my $input = CGI->new; |
59 |
my ($template, $loggedinuser, $cookie, $userflags) = get_template_and_user({ |
60 |
my ($template, $loggedinuser, $cookie, $userflags) = get_template_and_user({ |
Lines 90-96
my $basket = Koha::Acquisition::Baskets->find( $cgiparams->{basketno} );
Link Here
|
90 |
if ($op eq ""){ |
91 |
if ($op eq ""){ |
91 |
$template->param("basketno" => $cgiparams->{'basketno'}); |
92 |
$template->param("basketno" => $cgiparams->{'basketno'}); |
92 |
#display batches |
93 |
#display batches |
93 |
import_batches_list($template); |
94 |
Koha::MarcOrder->import_batches_list($template); |
94 |
# |
95 |
# |
95 |
# 2nd step = display the content of the chosen file |
96 |
# 2nd step = display the content of the chosen file |
96 |
# |
97 |
# |
Lines 104-110
if ($op eq ""){
Link Here
|
104 |
bookseller => $bookseller, |
105 |
bookseller => $bookseller, |
105 |
"allmatch" => $allmatch, |
106 |
"allmatch" => $allmatch, |
106 |
); |
107 |
); |
107 |
import_biblios_list($template, $cgiparams->{'import_batch_id'}); |
108 |
Koha::MarcOrder->import_biblios_list($template, $cgiparams->{'import_batch_id'}); |
108 |
if ( $basket->effective_create_items eq 'ordering' && !$basket->is_standing ) { |
109 |
if ( $basket->effective_create_items eq 'ordering' && !$basket->is_standing ) { |
109 |
# prepare empty item form |
110 |
# prepare empty item form |
110 |
my $cell = PrepareItemrecordDisplay( '', '', undef, 'ACQ' ); |
111 |
my $cell = PrepareItemrecordDisplay( '', '', undef, 'ACQ' ); |
Lines 146-381
if ($op eq ""){
Link Here
|
146 |
my @import_record_id_selected = $input->multi_param("import_record_id"); |
147 |
my @import_record_id_selected = $input->multi_param("import_record_id"); |
147 |
my $matcher_id = $input->param('matcher_id'); |
148 |
my $matcher_id = $input->param('matcher_id'); |
148 |
my $active_currency = Koha::Acquisition::Currencies->get_active; |
149 |
my $active_currency = Koha::Acquisition::Currencies->get_active; |
149 |
my $biblio_count = 0; |
|
|
150 |
while( my $import_record = $import_records->next ){ |
150 |
while( my $import_record = $import_records->next ){ |
151 |
$biblio_count++; |
151 |
my $marcrecord = $import_record->get_marc_record || die "couldn't translate marc information"; |
152 |
my $duplifound = 0; |
152 |
my @homebranches = $input->multi_param( 'homebranch_' . $import_record->import_record_id ); |
153 |
# Check if this import_record_id was selected |
153 |
my @holdingbranches = $input->multi_param( 'holdingbranch_' . $import_record->import_record_id ); |
154 |
next if not grep { $_ eq $import_record->import_record_id } @import_record_id_selected; |
154 |
my @itypes = $input->multi_param( 'itype_' . $import_record->import_record_id ); |
155 |
my $marcrecord = $import_record->get_marc_record || die "couldn't translate marc information"; |
155 |
my @nonpublic_notes = $input->multi_param( 'nonpublic_note_' . $import_record->import_record_id ); |
156 |
my $matches = $import_record->get_import_record_matches({ chosen => 1 }); |
156 |
my @public_notes = $input->multi_param( 'public_note_' . $import_record->import_record_id ); |
157 |
my $match = $matches->count ? $matches->next : undef; |
157 |
my @locs = $input->multi_param( 'loc_' . $import_record->import_record_id ); |
158 |
my $biblionumber = $match ? $match->candidate_match_id : 0; |
158 |
my @ccodes = $input->multi_param( 'ccode_' . $import_record->import_record_id ); |
159 |
my $c_quantity = |
159 |
my @notforloans = $input->multi_param( 'notforloan_' . $import_record->import_record_id ); |
160 |
$input->param( 'quantity_' . $import_record->import_record_id ) |
160 |
my @uris = $input->multi_param( 'uri_' . $import_record->import_record_id ); |
161 |
|| GetMarcQuantity( $marcrecord, C4::Context->preference('marcflavour') ) |
161 |
my @copynos = $input->multi_param( 'copyno_' . $import_record->import_record_id ); |
162 |
|| 1; |
162 |
my @budget_codes = $input->multi_param( 'budget_code_' . $import_record->import_record_id ); |
163 |
my $c_budget_id = |
|
|
164 |
$input->param( 'budget_id_' . $import_record->import_record_id ) |
165 |
|| $input->param('all_budget_id') |
166 |
|| $budget_id; |
167 |
my $c_discount = $input->param( 'discount_' . $import_record->import_record_id ); |
168 |
my $c_sort1 = $input->param( 'sort1_' . $import_record->import_record_id ) || $input->param('all_sort1') || ''; |
169 |
my $c_sort2 = $input->param( 'sort2_' . $import_record->import_record_id ) || $input->param('all_sort2') || ''; |
170 |
my $c_replacement_price = $input->param( 'replacementprice_' . $import_record->import_record_id ); |
171 |
my $c_price = $input->param( 'price_' . $import_record->import_record_id ); |
172 |
# Insert the biblio, or find it through matcher |
173 |
if ( $biblionumber ) { # If matched during staging we can continue |
174 |
$import_record->status('imported')->store; |
175 |
if( $overlay_action eq 'replace' ){ |
176 |
my $biblio = Koha::Biblios->find( $biblionumber ); |
177 |
$import_record->replace({ biblio => $biblio }); |
178 |
} |
179 |
} else { # Otherwise we check for duplicates, and skip if they exist |
180 |
if ($matcher_id) { |
181 |
if ( $matcher_id eq '_TITLE_AUTHOR_' ) { |
182 |
$duplifound = 1 if FindDuplicate($marcrecord); |
183 |
} |
184 |
else { |
185 |
my $matcher = C4::Matcher->fetch($matcher_id); |
186 |
my @matches = $matcher->get_matches( $marcrecord, my $max_matches = 1 ); |
187 |
$duplifound = 1 if @matches; |
188 |
} |
189 |
|
190 |
$duplinbatch = $import_batch_id and next if $duplifound; |
191 |
} |
192 |
|
193 |
# remove hyphens (-) from ISBN |
194 |
# FIXME: This should probably be optional |
195 |
my ( $isbnfield, $isbnsubfield ) = GetMarcFromKohaField( 'biblioitems.isbn' ); |
196 |
if ( $marcrecord->field($isbnfield) ) { |
197 |
foreach my $field ( $marcrecord->field($isbnfield) ) { |
198 |
foreach my $subfield ( $field->subfield($isbnsubfield) ) { |
199 |
my $newisbn = $field->subfield($isbnsubfield); |
200 |
$newisbn =~ s/-//g; |
201 |
$field->update( $isbnsubfield => $newisbn ); |
202 |
} |
203 |
} |
204 |
} |
205 |
|
206 |
# add the biblio |
207 |
( $biblionumber, undef ) = AddBiblio( $marcrecord, $cgiparams->{'frameworkcode'} || '' ); |
208 |
$import_record->status('imported')->store; |
209 |
} |
210 |
|
211 |
$import_record->import_biblio->matched_biblionumber($biblionumber)->store; |
212 |
|
213 |
# Add items from MarcItemFieldsToOrder |
214 |
my @homebranches = $input->multi_param( 'homebranch_' . $import_record->import_record_id ); |
215 |
my $count = scalar @homebranches; |
216 |
my @holdingbranches = $input->multi_param( 'holdingbranch_' . $import_record->import_record_id ); |
217 |
my @itypes = $input->multi_param( 'itype_' . $import_record->import_record_id ); |
218 |
my @nonpublic_notes = $input->multi_param( 'nonpublic_note_' . $import_record->import_record_id ); |
219 |
my @public_notes = $input->multi_param( 'public_note_' . $import_record->import_record_id ); |
220 |
my @locs = $input->multi_param( 'loc_' . $import_record->import_record_id ); |
221 |
my @ccodes = $input->multi_param( 'ccode_' . $import_record->import_record_id ); |
222 |
my @notforloans = $input->multi_param( 'notforloan_' . $import_record->import_record_id ); |
223 |
my @uris = $input->multi_param( 'uri_' . $import_record->import_record_id ); |
224 |
my @copynos = $input->multi_param( 'copyno_' . $import_record->import_record_id ); |
225 |
my @budget_ids = |
226 |
$input->multi_param( 'budget_code_' . $import_record->import_record_id ); # bad field name used in template! |
227 |
my @itemprices = $input->multi_param( 'itemprice_' . $import_record->import_record_id ); |
163 |
my @itemprices = $input->multi_param( 'itemprice_' . $import_record->import_record_id ); |
228 |
my @replacementprices = $input->multi_param( 'replacementprice_' . $import_record->import_record_id ); |
164 |
my @replacementprices = $input->multi_param( 'replacementprice_' . $import_record->import_record_id ); |
229 |
my @itemcallnumbers = $input->multi_param( 'itemcallnumber_' . $import_record->import_record_id ); |
165 |
my @itemcallnumbers = $input->multi_param( 'itemcallnumber_' . $import_record->import_record_id ); |
230 |
my @coded_location_qualifiers = |
|
|
231 |
$input->multi_param( 'coded_location_qualifier_' . $import_record->import_record_id ); |
232 |
my @barcodes = $input->multi_param( 'barcode_' . $import_record->import_record_id ); |
233 |
my @enumchrons = $input->multi_param( 'enumchron_' . $import_record->import_record_id ); |
234 |
my $itemcreation = 0; |
235 |
|
236 |
my @itemnumbers; |
237 |
for (my $i = 0; $i < $count; $i++) { |
238 |
$itemcreation = 1; |
239 |
my $item = Koha::Item->new( |
240 |
{ |
241 |
biblionumber => $biblionumber, |
242 |
homebranch => $homebranches[$i], |
243 |
holdingbranch => $holdingbranches[$i], |
244 |
itemnotes_nonpublic => $nonpublic_notes[$i], |
245 |
itemnotes => $public_notes[$i], |
246 |
location => $locs[$i], |
247 |
ccode => $ccodes[$i], |
248 |
itype => $itypes[$i], |
249 |
notforloan => $notforloans[$i], |
250 |
uri => $uris[$i], |
251 |
copynumber => $copynos[$i], |
252 |
price => $itemprices[$i], |
253 |
replacementprice => $replacementprices[$i], |
254 |
itemcallnumber => $itemcallnumbers[$i], |
255 |
coded_location_qualifier => $coded_location_qualifiers[$i], |
256 |
barcode => $barcodes[$i], |
257 |
enumchron => $enumchrons[$i], |
258 |
} |
259 |
)->store; |
260 |
push( @itemnumbers, $item->itemnumber ); |
261 |
} |
262 |
if ($itemcreation == 1) { |
263 |
# Group orderlines from MarcItemFieldsToOrder |
264 |
my $budget_hash; |
265 |
for (my $i = 0; $i < $count; $i++) { |
266 |
$budget_ids[$i] = $budget_id if !$budget_ids[$i]; # Use default budget if no budget selected in the UI |
267 |
$budget_hash->{ $budget_ids[$i] }->{quantity} += 1; |
268 |
$budget_hash->{ $budget_ids[$i] }->{price} = $itemprices[$i]; |
269 |
$budget_hash->{ $budget_ids[$i] }->{replacementprice} = |
270 |
$replacementprices[$i]; |
271 |
$budget_hash->{ $budget_ids[$i] }->{itemnumbers} //= []; |
272 |
push @{ $budget_hash->{ $budget_ids[$i] }->{itemnumbers} }, |
273 |
$itemnumbers[$i]; |
274 |
} |
275 |
|
276 |
# Create orderlines from MarcItemFieldsToOrder |
277 |
while(my ($budget_id, $infos) = each %$budget_hash) { |
278 |
if ($budget_id) { |
279 |
my %orderinfo = ( |
280 |
biblionumber => $biblionumber, |
281 |
basketno => $cgiparams->{'basketno'}, |
282 |
quantity => $infos->{quantity}, |
283 |
budget_id => $budget_id, |
284 |
currency => $cgiparams->{'all_currency'}, |
285 |
); |
286 |
|
287 |
my $price = $infos->{price}; |
288 |
if ($price){ |
289 |
# in France, the cents separator is the , but sometimes, ppl use a . |
290 |
# in this case, the price will be x100 when unformatted ! Replace the . by a , to get a proper price calculation |
291 |
$price =~ s/\./,/ if C4::Context->preference("CurrencyFormat") eq "FR"; |
292 |
$price = Koha::Number::Price->new($price)->unformat; |
293 |
$orderinfo{tax_rate_on_ordering} = $bookseller->tax_rate; |
294 |
$orderinfo{tax_rate_on_receiving} = $bookseller->tax_rate; |
295 |
my $order_discount = $c_discount ? $c_discount : $bookseller->discount; |
296 |
$orderinfo{discount} = $order_discount; |
297 |
$orderinfo{rrp} = $price; |
298 |
$orderinfo{ecost} = $order_discount ? $price * ( 1 - $order_discount / 100 ) : $price; |
299 |
$orderinfo{listprice} = $orderinfo{rrp} / $active_currency->rate; |
300 |
$orderinfo{unitprice} = $orderinfo{ecost}; |
301 |
$orderinfo{sort1} = $c_sort1; |
302 |
$orderinfo{sort2} = $c_sort2; |
303 |
} else { |
304 |
$orderinfo{listprice} = 0; |
305 |
} |
306 |
$orderinfo{replacementprice} = $infos->{replacementprice} || 0; |
307 |
|
308 |
# remove uncertainprice flag if we have found a price in the MARC record |
309 |
$orderinfo{uncertainprice} = 0 if $orderinfo{listprice}; |
310 |
|
166 |
|
311 |
my $order = Koha::Acquisition::Order->new( \%orderinfo ); |
167 |
my $client_item_fields = { |
312 |
$order->populate_with_prices_for_ordering(); |
168 |
homebranches => \@homebranches, |
313 |
$order->populate_with_prices_for_receiving(); |
169 |
holdingbranches => \@holdingbranches, |
314 |
$order->store; |
170 |
itypes => \@itypes, |
315 |
$order->add_item( $_ ) for @{ $budget_hash->{$budget_id}->{itemnumbers} }; |
171 |
nonpublic_notes => \@nonpublic_notes, |
316 |
} |
172 |
public_notes => \@public_notes, |
317 |
} |
173 |
locs => \@locs, |
318 |
} else { |
174 |
ccodes => \@ccodes, |
319 |
# 3rd add order |
175 |
notforloans => \@notforloans, |
320 |
my $patron = Koha::Patrons->find( $loggedinuser ); |
176 |
uris => \@uris, |
321 |
# get quantity in the MARC record (1 if none) |
177 |
copynos => \@copynos, |
322 |
my $quantity = GetMarcQuantity($marcrecord, C4::Context->preference('marcflavour')) || 1; |
178 |
budget_codes => \@budget_codes, |
323 |
my %orderinfo = ( |
179 |
itemprices => \@itemprices, |
324 |
biblionumber => $biblionumber, |
180 |
replacementprices => \@replacementprices, |
325 |
basketno => $cgiparams->{'basketno'}, |
181 |
itemcallnumbers => \@itemcallnumbers, |
326 |
quantity => $c_quantity, |
182 |
c_quantity => shift(@quantities) |
327 |
branchcode => $patron->branchcode, |
183 |
|| GetMarcQuantity( $marcrecord, C4::Context->preference('marcflavour') ) |
328 |
budget_id => $c_budget_id, |
184 |
|| 1, |
329 |
uncertainprice => 1, |
185 |
c_budget_id => shift(@budgets_id) || $input->param('all_budget_id') || $budget_id, |
330 |
sort1 => $c_sort1, |
186 |
c_discount => shift(@discount), |
331 |
sort2 => $c_sort2, |
187 |
c_sort1 => shift(@sort1) || $input->param('all_sort1') || '', |
332 |
order_internalnote => $cgiparams->{'all_order_internalnote'}, |
188 |
c_sort2 => shift(@sort2) || $input->param('all_sort2') || '', |
333 |
order_vendornote => $cgiparams->{'all_order_vendornote'}, |
189 |
c_replacement_price => shift(@orderreplacementprices), |
334 |
currency => $cgiparams->{'all_currency'}, |
190 |
c_price => shift(@prices) || GetMarcPrice( $marcrecord, C4::Context->preference('marcflavour') ), |
335 |
replacementprice => $c_replacement_price, |
191 |
}; |
336 |
); |
192 |
|
337 |
# get the price if there is one. |
193 |
my $args = { |
338 |
if ($c_price){ |
194 |
import_batch_id => $import_batch_id, |
339 |
# in France, the cents separator is the , but sometimes, ppl use a . |
195 |
import_record => $import_record, |
340 |
# in this case, the price will be x100 when unformatted ! Replace the . by a , to get a proper price calculation |
196 |
matcher_id => $matcher_id, |
341 |
$c_price =~ s/\./,/ if C4::Context->preference("CurrencyFormat") eq "FR"; |
197 |
overlay_action => $overlay_action, |
342 |
$c_price = Koha::Number::Price->new($c_price)->unformat; |
198 |
agent => 'client', |
343 |
$orderinfo{tax_rate_on_ordering} = $bookseller->tax_rate; |
199 |
import_record_id_selected => \@import_record_id_selected, |
344 |
$orderinfo{tax_rate_on_receiving} = $bookseller->tax_rate; |
200 |
client_item_fields => $client_item_fields, |
345 |
my $order_discount = $c_discount ? $c_discount : $bookseller->discount; |
201 |
basket_id => $cgiparams->{'basketno'}, |
346 |
$orderinfo{discount} = $order_discount; |
202 |
vendor => $bookseller, |
347 |
$orderinfo{rrp} = $c_price; |
203 |
budget_id => $budget_id, |
348 |
$orderinfo{ecost} = $order_discount ? $c_price * ( 1 - $order_discount / 100 ) : $c_price; |
204 |
}; |
349 |
$orderinfo{listprice} = $orderinfo{rrp} / $active_currency->rate; |
205 |
my $result = Koha::MarcOrder->import_record_and_create_order_lines($args); |
350 |
$orderinfo{unitprice} = $orderinfo{ecost}; |
206 |
|
351 |
} else { |
207 |
$duplinbatch = $result->{duplicates_in_batch} if $result->{duplicates_in_batch}; |
352 |
$orderinfo{listprice} = 0; |
208 |
next if $result->{skip}; # If a duplicate is found, or the import record wasn't selected it will be skipped |
353 |
} |
|
|
354 |
|
209 |
|
355 |
# remove uncertainprice flag if we have found a price in the MARC record |
|
|
356 |
$orderinfo{uncertainprice} = 0 if $orderinfo{listprice}; |
357 |
|
358 |
my $order = Koha::Acquisition::Order->new( \%orderinfo ); |
359 |
$order->populate_with_prices_for_ordering(); |
360 |
$order->populate_with_prices_for_receiving(); |
361 |
$order->store; |
362 |
|
363 |
# 4th, add items if applicable |
364 |
# parse the item sent by the form, and create an item just for the import_record_id we are dealing with |
365 |
# this is not optimised, but it's working ! |
366 |
if ( $basket->effective_create_items eq 'ordering' && !$basket->is_standing ) { |
367 |
my @tags = $input->multi_param('tag'); |
368 |
my @subfields = $input->multi_param('subfield'); |
369 |
my @field_values = $input->multi_param('field_value'); |
370 |
my @serials = $input->multi_param('serial'); |
371 |
my $xml = TransformHtmlToXml( \@tags, \@subfields, \@field_values ); |
372 |
my $record = MARC::Record::new_from_xml( $xml, 'UTF-8' ); |
373 |
for (my $qtyloop=1;$qtyloop <= $c_quantity;$qtyloop++) { |
374 |
my ( $biblionumber, undef, $itemnumber ) = AddItemFromMarc( $record, $biblionumber ); |
375 |
$order->add_item( $itemnumber ); |
376 |
} |
377 |
} |
378 |
} |
379 |
$imported++; |
210 |
$imported++; |
380 |
} |
211 |
} |
381 |
|
212 |
|
Lines 421-740
foreach my $r ( @{$budgets_hierarchy} ) {
Link Here
|
421 |
$template->param( budget_loop => $budget_loop,); |
252 |
$template->param( budget_loop => $budget_loop,); |
422 |
|
253 |
|
423 |
output_html_with_http_headers $input, $cookie, $template->output; |
254 |
output_html_with_http_headers $input, $cookie, $template->output; |
424 |
|
|
|
425 |
|
426 |
sub import_batches_list { |
427 |
my ($template) = @_; |
428 |
my $batches = GetImportBatchRangeDesc(); |
429 |
|
430 |
my @list = (); |
431 |
foreach my $batch (@$batches) { |
432 |
if ( $batch->{'import_status'} =~ /^staged$|^reverted$/ && $batch->{'record_type'} eq 'biblio') { |
433 |
# check if there is at least 1 line still staged |
434 |
my $import_records_count = Koha::Import::Records->search({ |
435 |
import_batch_id => $batch->{'import_batch_id'}, |
436 |
status => $batch->{import_status} |
437 |
})->count; |
438 |
if ( $import_records_count ) { |
439 |
push @list, { |
440 |
import_batch_id => $batch->{'import_batch_id'}, |
441 |
num_records => $batch->{'num_records'}, |
442 |
num_items => $batch->{'num_items'}, |
443 |
staged_date => $batch->{'upload_timestamp'}, |
444 |
import_status => $batch->{'import_status'}, |
445 |
file_name => $batch->{'file_name'}, |
446 |
comments => $batch->{'comments'}, |
447 |
}; |
448 |
} else { |
449 |
# if there are no more line to includes, set the status to imported |
450 |
# FIXME This should be removed in the future. |
451 |
SetImportBatchStatus( $batch->{'import_batch_id'}, 'imported' ); |
452 |
} |
453 |
} |
454 |
} |
455 |
$template->param(batch_list => \@list); |
456 |
my $num_batches = GetNumberOfNonZ3950ImportBatches(); |
457 |
$template->param(num_results => $num_batches); |
458 |
} |
459 |
|
460 |
sub import_biblios_list { |
461 |
my ($template, $import_batch_id) = @_; |
462 |
my $batch = GetImportBatch($import_batch_id,'staged'); |
463 |
return () unless $batch and $batch->{import_status} =~ /^staged$|^reverted$/; |
464 |
my $import_records = Koha::Import::Records->search({ |
465 |
import_batch_id => $import_batch_id, |
466 |
status => $batch->{import_status} |
467 |
}); |
468 |
my @list = (); |
469 |
my $item_error = 0; |
470 |
|
471 |
my $ccodes = { map { $_->{authorised_value} => $_->{opac_description} } Koha::AuthorisedValues->get_descriptions_by_koha_field( { frameworkcode => '', kohafield => 'items.ccode' } ) }; |
472 |
my $locations = { map { $_->{authorised_value} => $_->{opac_description} } Koha::AuthorisedValues->get_descriptions_by_koha_field( { frameworkcode => '', kohafield => 'items.location' } ) }; |
473 |
my $notforloans = { map { $_->{authorised_value} => $_->{lib} } Koha::AuthorisedValues->get_descriptions_by_koha_field( { frameworkcode => '', kohafield => 'items.notforloan' } ) }; |
474 |
# location list |
475 |
my @locations; |
476 |
foreach (sort keys %$locations) { |
477 |
push @locations, { code => $_, description => "$_ - " . $locations->{$_} }; |
478 |
} |
479 |
my @ccodes; |
480 |
foreach (sort {$ccodes->{$a} cmp $ccodes->{$b}} keys %$ccodes) { |
481 |
push @ccodes, { code => $_, description => $ccodes->{$_} }; |
482 |
} |
483 |
my @notforloans; |
484 |
foreach (sort {$notforloans->{$a} cmp $notforloans->{$b}} keys %$notforloans) { |
485 |
push @notforloans, { code => $_, description => $notforloans->{$_} }; |
486 |
} |
487 |
|
488 |
my $biblio_count = 0; |
489 |
while ( my $import_record = $import_records->next ) { |
490 |
my $item_id = 1; |
491 |
$biblio_count++; |
492 |
my $matches = $import_record->get_import_record_matches({ chosen => 1 }); |
493 |
my $match = $matches->count ? $matches->next : undef; |
494 |
my $match_biblio = $match ? Koha::Biblios->find({ biblionumber => $match->candidate_match_id }) : undef; |
495 |
my %cellrecord = ( |
496 |
import_record_id => $import_record->import_record_id, |
497 |
import_biblio => $import_record->import_biblio, |
498 |
import => 1, |
499 |
status => $import_record->status, |
500 |
record_sequence => $import_record->record_sequence, |
501 |
overlay_status => $import_record->overlay_status, |
502 |
match_biblionumber => $match ? $match->candidate_match_id : 0, |
503 |
match_citation => $match_biblio ? ($match_biblio->title || '') . ' ' .( $match_biblio->author || ''): '', |
504 |
match_score => $match ? $match->score : 0, |
505 |
); |
506 |
my $marcrecord = $import_record->get_marc_record || die "couldn't translate marc information"; |
507 |
|
508 |
my $infos = get_infos_syspref('MarcFieldsToOrder', $marcrecord, ['price', 'quantity', 'budget_code', 'discount', 'sort1', 'sort2','replacementprice']); |
509 |
my $price = looks_like_number($infos->{price}) ? $infos->{price} : GetMarcPrice( $marcrecord, C4::Context->preference('marcflavour') ); |
510 |
my $replacementprice = $infos->{replacementprice}; |
511 |
my $quantity = $infos->{quantity}; |
512 |
my $budget_code = $infos->{budget_code}; |
513 |
my $discount = $infos->{discount}; |
514 |
my $sort1 = $infos->{sort1}; |
515 |
my $sort2 = $infos->{sort2}; |
516 |
my $budget_id; |
517 |
|
518 |
if ($budget_code) { |
519 |
my $biblio_budget = GetBudgetByCode($budget_code); |
520 |
if ($biblio_budget) { |
521 |
$budget_id = $biblio_budget->{budget_id}; |
522 |
} |
523 |
} |
524 |
|
525 |
# Items |
526 |
my @itemlist = (); |
527 |
my $all_items_quantity = 0; |
528 |
my $alliteminfos = get_marc_item_fields_to_order($marcrecord); |
529 |
if ($alliteminfos != -1) { |
530 |
foreach my $iteminfos (@$alliteminfos) { |
531 |
# Quantity is required, default to one if not supplied |
532 |
my $quantity = delete $iteminfos->{quantity} || 1; |
533 |
|
534 |
# Handle incorrectly named original parameters for MarcItemFieldsToOrder |
535 |
$iteminfos->{location} = delete $iteminfos->{loc} if $iteminfos->{loc}; |
536 |
$iteminfos->{copynumber} = delete $iteminfos->{copyno} if $iteminfos->{copyno}; |
537 |
# Price is handled as "itemprice" in the UI form to distinguish from MarcFieldsToOrder |
538 |
$iteminfos->{itemprice} = delete $iteminfos->{price} if $iteminfos->{price}; |
539 |
|
540 |
# Convert budge code to a budget id |
541 |
my $item_budget_code = delete $iteminfos->{budget_code}; |
542 |
if ( $item_budget_code ) { |
543 |
my $item_budget = GetBudgetByCode( $item_budget_code ); |
544 |
$iteminfos->{budget_id} = $item_budget->{budget_id} || $budget_id; |
545 |
} |
546 |
|
547 |
$iteminfos->{price} ||= $price; # Fallback to order price if no item price was defined |
548 |
|
549 |
# Clone the item data for the needed quantity |
550 |
# Add the incremented item id for each item in that quantity |
551 |
for (my $i = 0; $i < $quantity; $i++) { |
552 |
my $itemrecord = { %$iteminfos }; |
553 |
$itemrecord->{item_id} = $item_id++; |
554 |
$all_items_quantity++; |
555 |
push @itemlist, $itemrecord; |
556 |
} |
557 |
} |
558 |
|
559 |
$cellrecord{'iteminfos'} = \@itemlist; |
560 |
} else { |
561 |
$cellrecord{'item_error'} = 1; |
562 |
} |
563 |
push @list, \%cellrecord; |
564 |
|
565 |
# If MarcItemFieldsToOrder is not set, we use MarcFieldsToOrder to populate the order form. |
566 |
if ($alliteminfos == -1 || scalar(@$alliteminfos) == 0) { |
567 |
$cellrecord{price} = $price || ''; |
568 |
$cellrecord{replacementprice} = $replacementprice || ''; |
569 |
$cellrecord{quantity} = $quantity || ''; |
570 |
$cellrecord{budget_id} = $budget_id || ''; |
571 |
} else { |
572 |
# When using MarcItemFields to order we want the order to have the same quantity as total items |
573 |
$cellrecord{quantity} = $all_items_quantity; |
574 |
} |
575 |
# The fields discount, sort1, and sort2 only exist at the order level, so always use MarcItemFieldsToOrder |
576 |
$cellrecord{discount} = $discount || ''; |
577 |
$cellrecord{sort1} = $sort1 || ''; |
578 |
$cellrecord{sort2} = $sort2 || ''; |
579 |
|
580 |
} |
581 |
my $num_records = $batch->{'num_records'}; |
582 |
my $overlay_action = GetImportBatchOverlayAction($import_batch_id); |
583 |
my $nomatch_action = GetImportBatchNoMatchAction($import_batch_id); |
584 |
my $item_action = GetImportBatchItemAction($import_batch_id); |
585 |
$template->param(import_biblio_list => \@list, |
586 |
num_results => $num_records, |
587 |
import_batch_id => $import_batch_id, |
588 |
"overlay_action_${overlay_action}" => 1, |
589 |
overlay_action => $overlay_action, |
590 |
"nomatch_action_${nomatch_action}" => 1, |
591 |
nomatch_action => $nomatch_action, |
592 |
"item_action_${item_action}" => 1, |
593 |
item_action => $item_action, |
594 |
item_error => $item_error, |
595 |
libraries => Koha::Libraries->search, |
596 |
locationloop => \@locations, |
597 |
itemtypes => Koha::ItemTypes->search, |
598 |
ccodeloop => \@ccodes, |
599 |
notforloanloop => \@notforloans, |
600 |
); |
601 |
batch_info($template, $batch); |
602 |
} |
603 |
|
604 |
sub batch_info { |
605 |
my ($template, $batch) = @_; |
606 |
$template->param(batch_info => 1, |
607 |
file_name => $batch->{'file_name'}, |
608 |
comments => $batch->{'comments'}, |
609 |
import_status => $batch->{'import_status'}, |
610 |
upload_timestamp => $batch->{'upload_timestamp'}, |
611 |
num_records => $batch->{'num_records'}, |
612 |
num_items => $batch->{'num_items'}); |
613 |
if ($batch->{'num_records'} > 0) { |
614 |
if ($batch->{'import_status'} eq 'staged' or $batch->{'import_status'} eq 'reverted') { |
615 |
$template->param(can_commit => 1); |
616 |
} |
617 |
if ($batch->{'import_status'} eq 'imported') { |
618 |
$template->param(can_revert => 1); |
619 |
} |
620 |
} |
621 |
if (defined $batch->{'matcher_id'}) { |
622 |
my $matcher = C4::Matcher->fetch($batch->{'matcher_id'}); |
623 |
if (defined $matcher) { |
624 |
$template->param('current_matcher_id' => $batch->{'matcher_id'}, |
625 |
'current_matcher_code' => $matcher->code(), |
626 |
'current_matcher_description' => $matcher->description()); |
627 |
} |
628 |
} |
629 |
add_matcher_list($batch->{'matcher_id'}, $template); |
630 |
} |
631 |
|
632 |
sub add_matcher_list { |
633 |
my ($current_matcher_id, $template) = @_; |
634 |
my @matchers = C4::Matcher::GetMatcherList(); |
635 |
if (defined $current_matcher_id) { |
636 |
for (my $i = 0; $i <= $#matchers; $i++) { |
637 |
if ($matchers[$i]->{'matcher_id'} == $current_matcher_id) { |
638 |
$matchers[$i]->{'selected'} = 1; |
639 |
} |
640 |
} |
641 |
} |
642 |
$template->param(available_matchers => \@matchers); |
643 |
} |
644 |
|
645 |
sub get_infos_syspref { |
646 |
my ($syspref_name, $record, $field_list) = @_; |
647 |
my $yaml = C4::Context->yaml_preference($syspref_name); |
648 |
|
649 |
my $r; |
650 |
for my $field_name ( @$field_list ) { |
651 |
next unless exists $yaml->{$field_name}; |
652 |
my @fields = split /\|/, $yaml->{$field_name}; |
653 |
for my $field ( @fields ) { |
654 |
my ( $f, $sf ) = split /\$/, $field; |
655 |
next unless $f and $sf; |
656 |
if ( my $v = $record->subfield( $f, $sf ) ) { |
657 |
$r->{$field_name} = $v; |
658 |
} |
659 |
last if $yaml->{$field}; |
660 |
} |
661 |
} |
662 |
return $r; |
663 |
} |
664 |
|
665 |
sub equal_number_of_fields { |
666 |
my ($tags_list, $record) = @_; |
667 |
my $tag_fields_count; |
668 |
for my $tag (@$tags_list) { |
669 |
my @fields = $record->field($tag); |
670 |
$tag_fields_count->{$tag} = scalar @fields; |
671 |
} |
672 |
|
673 |
my $tags_count; |
674 |
foreach my $key ( keys %$tag_fields_count ) { |
675 |
if ( $tag_fields_count->{$key} > 0 ) { # Having 0 of a field is ok |
676 |
$tags_count //= $tag_fields_count->{$key}; # Start with the count from the first occurrence |
677 |
return -1 if $tag_fields_count->{$key} != $tags_count; # All counts of various fields should be equal if they exist |
678 |
} |
679 |
} |
680 |
|
681 |
return $tags_count; |
682 |
} |
683 |
|
684 |
sub get_marc_item_fields_to_order { |
685 |
my ($record) = @_; |
686 |
|
687 |
my $syspref = C4::Context->preference('MarcItemFieldsToOrder'); |
688 |
$syspref = "$syspref\n\n"; # YAML is anal on ending \n. Surplus does not hurt |
689 |
my $yaml = eval { |
690 |
YAML::XS::Load(Encode::encode_utf8($syspref)); |
691 |
}; |
692 |
if ( $@ ) { |
693 |
warn "Unable to parse $syspref syspref : $@"; |
694 |
return (); |
695 |
} |
696 |
|
697 |
my @result; |
698 |
my @tags_list; |
699 |
|
700 |
# Check tags in syspref definition |
701 |
for my $field_name ( keys %$yaml ) { |
702 |
my @fields = split /\|/, $yaml->{$field_name}; |
703 |
for my $field ( @fields ) { |
704 |
my ( $f, $sf ) = split /\$/, $field; |
705 |
next unless $f and $sf; |
706 |
push @tags_list, $f; |
707 |
} |
708 |
} |
709 |
@tags_list = List::MoreUtils::uniq(@tags_list); |
710 |
|
711 |
my $tags_count = equal_number_of_fields(\@tags_list, $record); |
712 |
# Return if the number of these fields in the record is not the same. |
713 |
return -1 if $tags_count == -1; |
714 |
|
715 |
# Gather the fields |
716 |
my $fields_hash; |
717 |
foreach my $tag (@tags_list) { |
718 |
my @tmp_fields; |
719 |
foreach my $field ($record->field($tag)) { |
720 |
push @tmp_fields, $field; |
721 |
} |
722 |
$fields_hash->{$tag} = \@tmp_fields; |
723 |
} |
724 |
|
725 |
for (my $i = 0; $i < $tags_count; $i++) { |
726 |
my $r; |
727 |
for my $field_name ( keys %$yaml ) { |
728 |
my @fields = split /\|/, $yaml->{$field_name}; |
729 |
for my $field ( @fields ) { |
730 |
my ( $f, $sf ) = split /\$/, $field; |
731 |
next unless $f and $sf; |
732 |
my $v = $fields_hash->{$f}[$i] ? $fields_hash->{$f}[$i]->subfield( $sf ) : undef; |
733 |
$r->{$field_name} = $v if (defined $v); |
734 |
last if $yaml->{$field}; |
735 |
} |
736 |
} |
737 |
push @result, $r; |
738 |
} |
739 |
return \@result; |
740 |
} |
741 |
- |