|
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( 'itemreplacementprice_' . $import_record->import_record_id ); |
164 |
my @replacementprices = $input->multi_param( 'itemreplacementprice_' . $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 |
- |