Lines 247-261
sub AddItemBatchFromMarc {
Link Here
|
247 |
next ITEMFIELD; |
247 |
next ITEMFIELD; |
248 |
} |
248 |
} |
249 |
|
249 |
|
250 |
_set_derived_columns_for_add($item); |
250 |
my $item_object = Koha::Item->new($item)->store; |
251 |
my ( $itemnumber, $error ) = _koha_new_item( $item, $item->{barcode} ); |
251 |
push @itemnumbers, $item_object->itemnumber; # FIXME not checking error |
252 |
warn $error if $error; |
|
|
253 |
push @itemnumbers, $itemnumber; # FIXME not checking error |
254 |
$item->{'itemnumber'} = $itemnumber; |
255 |
|
252 |
|
256 |
logaction("CATALOGUING", "ADD", $itemnumber, "item") if C4::Context->preference("CataloguingLog"); |
253 |
logaction("CATALOGUING", "ADD", $item->itemnumber, "item") if C4::Context->preference("CataloguingLog"); |
257 |
|
254 |
|
258 |
my $new_item_marc = _marc_from_item_hash($item, $frameworkcode, $unlinked_item_subfields); |
255 |
my $new_item_marc = _marc_from_item_hash($item->unblessed, $frameworkcode, $unlinked_item_subfields); |
259 |
$item_field->replace_with($new_item_marc->field($itemtag)); |
256 |
$item_field->replace_with($new_item_marc->field($itemtag)); |
260 |
} |
257 |
} |
261 |
|
258 |
|
Lines 270-352
sub AddItemBatchFromMarc {
Link Here
|
270 |
return (\@itemnumbers, \@errors); |
267 |
return (\@itemnumbers, \@errors); |
271 |
} |
268 |
} |
272 |
|
269 |
|
273 |
=head2 ModItemFromMarc |
|
|
274 |
|
275 |
ModItemFromMarc($item_marc, $biblionumber, $itemnumber); |
276 |
|
277 |
This function updates an item record based on a supplied |
278 |
C<MARC::Record> object containing an embedded item field. |
279 |
This API is meant for the use of C<additem.pl>; for |
280 |
other purposes, C<ModItem> should be used. |
281 |
|
282 |
This function uses the hash %default_values_for_mod_from_marc, |
283 |
which contains default values for item fields to |
284 |
apply when modifying an item. This is needed because |
285 |
if an item field's value is cleared, TransformMarcToKoha |
286 |
does not include the column in the |
287 |
hash that's passed to ModItem, which without |
288 |
use of this hash makes it impossible to clear |
289 |
an item field's value. See bug 2466. |
290 |
|
291 |
Note that only columns that can be directly |
292 |
changed from the cataloging and serials |
293 |
item editors are included in this hash. |
294 |
|
295 |
Returns item record |
296 |
|
297 |
=cut |
298 |
|
299 |
sub _build_default_values_for_mod_marc { |
300 |
# Has no framework parameter anymore, since Default is authoritative |
301 |
# for Koha to MARC mappings. |
302 |
|
303 |
my $cache = Koha::Caches->get_instance(); |
304 |
my $cache_key = "default_value_for_mod_marc-"; |
305 |
my $cached = $cache->get_from_cache($cache_key); |
306 |
return $cached if $cached; |
307 |
|
308 |
my $default_values = { |
309 |
barcode => undef, |
310 |
booksellerid => undef, |
311 |
ccode => undef, |
312 |
'items.cn_source' => undef, |
313 |
coded_location_qualifier => undef, |
314 |
copynumber => undef, |
315 |
damaged => 0, |
316 |
enumchron => undef, |
317 |
holdingbranch => undef, |
318 |
homebranch => undef, |
319 |
itemcallnumber => undef, |
320 |
itemlost => 0, |
321 |
itemnotes => undef, |
322 |
itemnotes_nonpublic => undef, |
323 |
itype => undef, |
324 |
location => undef, |
325 |
permanent_location => undef, |
326 |
materials => undef, |
327 |
new_status => undef, |
328 |
notforloan => 0, |
329 |
price => undef, |
330 |
replacementprice => undef, |
331 |
replacementpricedate => undef, |
332 |
restricted => undef, |
333 |
stack => undef, |
334 |
stocknumber => undef, |
335 |
uri => undef, |
336 |
withdrawn => 0, |
337 |
}; |
338 |
my %default_values_for_mod_from_marc; |
339 |
while ( my ( $field, $default_value ) = each %$default_values ) { |
340 |
my $kohafield = $field; |
341 |
$kohafield =~ s|^([^\.]+)$|items.$1|; |
342 |
$default_values_for_mod_from_marc{$field} = $default_value |
343 |
if C4::Biblio::GetMarcFromKohaField( $kohafield ); |
344 |
} |
345 |
|
346 |
$cache->set_in_cache($cache_key, \%default_values_for_mod_from_marc); |
347 |
return \%default_values_for_mod_from_marc; |
348 |
} |
349 |
|
350 |
sub ModItemFromMarc { |
270 |
sub ModItemFromMarc { |
351 |
my $item_marc = shift; |
271 |
my $item_marc = shift; |
352 |
my $biblionumber = shift; |
272 |
my $biblionumber = shift; |
Lines 359-374
sub ModItemFromMarc {
Link Here
|
359 |
$localitemmarc->append_fields( $item_marc->field($itemtag) ); |
279 |
$localitemmarc->append_fields( $item_marc->field($itemtag) ); |
360 |
my $item = TransformMarcToKoha( $localitemmarc, $frameworkcode, 'items' ); |
280 |
my $item = TransformMarcToKoha( $localitemmarc, $frameworkcode, 'items' ); |
361 |
my $default_values = _build_default_values_for_mod_marc(); |
281 |
my $default_values = _build_default_values_for_mod_marc(); |
|
|
282 |
my $item_object = Koha::Items->find($itemnumber); |
362 |
foreach my $item_field ( keys %$default_values ) { |
283 |
foreach my $item_field ( keys %$default_values ) { |
363 |
$item->{$item_field} = $default_values->{$item_field} |
284 |
$item_object->$item_field($default_values->{$item_field}) |
364 |
unless exists $item->{$item_field}; |
285 |
unless exists $item->{$item_field}; |
365 |
} |
286 |
} |
366 |
my $unlinked_item_subfields = _get_unlinked_item_subfields( $localitemmarc, $frameworkcode ); |
287 |
my $unlinked_item_subfields = _get_unlinked_item_subfields( $localitemmarc, $frameworkcode ); |
367 |
|
288 |
|
368 |
my $item_object = Koha::Items->find($itemnumber); |
|
|
369 |
$item_object->more_subfields_xml(_get_unlinked_subfields_xml($unlinked_item_subfields))->store; |
289 |
$item_object->more_subfields_xml(_get_unlinked_subfields_xml($unlinked_item_subfields))->store; |
|
|
290 |
$item_object->store; |
370 |
|
291 |
|
371 |
return $item_object->get_from_storage->unblessed; |
292 |
return $item_object->unblessed; |
372 |
} |
293 |
} |
373 |
|
294 |
|
374 |
=head2 ModItemTransfer |
295 |
=head2 ModItemTransfer |
Lines 1121-1321
the inner workings of C<C4::Items>.
Link Here
|
1121 |
|
1042 |
|
1122 |
=cut |
1043 |
=cut |
1123 |
|
1044 |
|
1124 |
=head2 %derived_columns |
|
|
1125 |
|
1126 |
This hash keeps track of item columns that |
1127 |
are strictly derived from other columns in |
1128 |
the item record and are not meant to be set |
1129 |
independently. |
1130 |
|
1131 |
Each key in the hash should be the name of a |
1132 |
column (as named by TransformMarcToKoha). Each |
1133 |
value should be hashref whose keys are the |
1134 |
columns on which the derived column depends. The |
1135 |
hashref should also contain a 'BUILDER' key |
1136 |
that is a reference to a sub that calculates |
1137 |
the derived value. |
1138 |
|
1139 |
=cut |
1140 |
|
1141 |
my %derived_columns = ( |
1142 |
'items.cn_sort' => { |
1143 |
'itemcallnumber' => 1, |
1144 |
'items.cn_source' => 1, |
1145 |
'BUILDER' => \&_calc_items_cn_sort, |
1146 |
} |
1147 |
); |
1148 |
|
1149 |
=head2 _set_derived_columns_for_add |
1150 |
|
1151 |
_set_derived_column_for_add($item); |
1152 |
|
1153 |
Given an item hash representing a new item to be added, |
1154 |
calculate any derived columns. Currently the only |
1155 |
such column is C<items.cn_sort>. |
1156 |
|
1157 |
=cut |
1158 |
|
1159 |
sub _set_derived_columns_for_add { |
1160 |
my $item = shift; |
1161 |
|
1162 |
foreach my $column (keys %derived_columns) { |
1163 |
my $builder = $derived_columns{$column}->{'BUILDER'}; |
1164 |
my $source_values = {}; |
1165 |
foreach my $source_column (keys %{ $derived_columns{$column} }) { |
1166 |
next if $source_column eq 'BUILDER'; |
1167 |
$source_values->{$source_column} = $item->{$source_column}; |
1168 |
} |
1169 |
$builder->($item, $source_values); |
1170 |
} |
1171 |
} |
1172 |
|
1173 |
=head2 _get_single_item_column |
1174 |
|
1175 |
_get_single_item_column($column, $itemnumber); |
1176 |
|
1177 |
Retrieves the value of a single column from an C<items> |
1178 |
row specified by C<$itemnumber>. |
1179 |
|
1180 |
=cut |
1181 |
|
1182 |
sub _get_single_item_column { |
1183 |
my $column = shift; |
1184 |
my $itemnumber = shift; |
1185 |
|
1186 |
my $dbh = C4::Context->dbh; |
1187 |
my $sth = $dbh->prepare("SELECT $column FROM items WHERE itemnumber = ?"); |
1188 |
$sth->execute($itemnumber); |
1189 |
my ($value) = $sth->fetchrow(); |
1190 |
return $value; |
1191 |
} |
1192 |
|
1193 |
=head2 _calc_items_cn_sort |
1194 |
|
1195 |
_calc_items_cn_sort($item, $source_values); |
1196 |
|
1197 |
Helper routine to calculate C<items.cn_sort>. |
1198 |
|
1199 |
=cut |
1200 |
|
1201 |
sub _calc_items_cn_sort { |
1202 |
my $item = shift; |
1203 |
my $source_values = shift; |
1204 |
|
1205 |
$item->{'items.cn_sort'} = GetClassSort($source_values->{'items.cn_source'}, $source_values->{'itemcallnumber'}, ""); |
1206 |
} |
1207 |
|
1208 |
=head2 _koha_new_item |
1209 |
|
1210 |
my ($itemnumber,$error) = _koha_new_item( $item, $barcode ); |
1211 |
|
1212 |
Perform the actual insert into the C<items> table. |
1213 |
|
1214 |
=cut |
1215 |
|
1216 |
sub _koha_new_item { |
1217 |
my ( $item, $barcode ) = @_; |
1218 |
my $dbh=C4::Context->dbh; |
1219 |
my $error; |
1220 |
$item->{permanent_location} //= $item->{location}; |
1221 |
_mod_item_dates( $item ); |
1222 |
my $query = |
1223 |
"INSERT INTO items SET |
1224 |
biblionumber = ?, |
1225 |
biblioitemnumber = ?, |
1226 |
barcode = ?, |
1227 |
dateaccessioned = ?, |
1228 |
booksellerid = ?, |
1229 |
homebranch = ?, |
1230 |
price = ?, |
1231 |
replacementprice = ?, |
1232 |
replacementpricedate = ?, |
1233 |
datelastborrowed = ?, |
1234 |
datelastseen = ?, |
1235 |
stack = ?, |
1236 |
notforloan = ?, |
1237 |
damaged = ?, |
1238 |
itemlost = ?, |
1239 |
withdrawn = ?, |
1240 |
itemcallnumber = ?, |
1241 |
coded_location_qualifier = ?, |
1242 |
restricted = ?, |
1243 |
itemnotes = ?, |
1244 |
itemnotes_nonpublic = ?, |
1245 |
holdingbranch = ?, |
1246 |
location = ?, |
1247 |
permanent_location = ?, |
1248 |
onloan = ?, |
1249 |
issues = ?, |
1250 |
renewals = ?, |
1251 |
reserves = ?, |
1252 |
cn_source = ?, |
1253 |
cn_sort = ?, |
1254 |
ccode = ?, |
1255 |
itype = ?, |
1256 |
materials = ?, |
1257 |
uri = ?, |
1258 |
enumchron = ?, |
1259 |
more_subfields_xml = ?, |
1260 |
copynumber = ?, |
1261 |
stocknumber = ?, |
1262 |
new_status = ? |
1263 |
"; |
1264 |
my $sth = $dbh->prepare($query); |
1265 |
my $today = output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 }); |
1266 |
$sth->execute( |
1267 |
$item->{'biblionumber'}, |
1268 |
$item->{'biblioitemnumber'}, |
1269 |
$barcode, |
1270 |
$item->{'dateaccessioned'}, |
1271 |
$item->{'booksellerid'}, |
1272 |
$item->{'homebranch'}, |
1273 |
$item->{'price'}, |
1274 |
$item->{'replacementprice'}, |
1275 |
$item->{'replacementpricedate'} || $today, |
1276 |
$item->{datelastborrowed}, |
1277 |
$item->{datelastseen} || $today, |
1278 |
$item->{stack}, |
1279 |
$item->{'notforloan'}, |
1280 |
$item->{'damaged'}, |
1281 |
$item->{'itemlost'}, |
1282 |
$item->{'withdrawn'}, |
1283 |
$item->{'itemcallnumber'}, |
1284 |
$item->{'coded_location_qualifier'}, |
1285 |
$item->{'restricted'}, |
1286 |
$item->{'itemnotes'}, |
1287 |
$item->{'itemnotes_nonpublic'}, |
1288 |
$item->{'holdingbranch'}, |
1289 |
$item->{'location'}, |
1290 |
$item->{'permanent_location'}, |
1291 |
$item->{'onloan'}, |
1292 |
$item->{'issues'}, |
1293 |
$item->{'renewals'}, |
1294 |
$item->{'reserves'}, |
1295 |
$item->{'items.cn_source'}, |
1296 |
$item->{'items.cn_sort'}, |
1297 |
$item->{'ccode'}, |
1298 |
$item->{'itype'}, |
1299 |
$item->{'materials'}, |
1300 |
$item->{'uri'}, |
1301 |
$item->{'enumchron'}, |
1302 |
$item->{'more_subfields_xml'}, |
1303 |
$item->{'copynumber'}, |
1304 |
$item->{'stocknumber'}, |
1305 |
$item->{'new_status'}, |
1306 |
); |
1307 |
|
1308 |
my $itemnumber; |
1309 |
if ( defined $sth->errstr ) { |
1310 |
$error.="ERROR in _koha_new_item $query".$sth->errstr; |
1311 |
} |
1312 |
else { |
1313 |
$itemnumber = $dbh->{'mysql_insertid'}; |
1314 |
} |
1315 |
|
1316 |
return ( $itemnumber, $error ); |
1317 |
} |
1318 |
|
1319 |
=head2 MoveItemFromBiblio |
1045 |
=head2 MoveItemFromBiblio |
1320 |
|
1046 |
|
1321 |
MoveItemFromBiblio($itenumber, $frombiblio, $tobiblio); |
1047 |
MoveItemFromBiblio($itenumber, $frombiblio, $tobiblio); |
Lines 1366-1399
sub MoveItemFromBiblio {
Link Here
|
1366 |
return; |
1092 |
return; |
1367 |
} |
1093 |
} |
1368 |
|
1094 |
|
1369 |
sub _mod_item_dates { # date formatting for date fields in item hash |
|
|
1370 |
my ( $item ) = @_; |
1371 |
return if !$item || ref($item) ne 'HASH'; |
1372 |
|
1373 |
my @keys = grep |
1374 |
{ $_ =~ /^onloan$|^date|date$|datetime$/ } |
1375 |
keys %$item; |
1376 |
# Incl. dateaccessioned,replacementpricedate,datelastborrowed,datelastseen |
1377 |
# NOTE: We do not (yet) have items fields ending with datetime |
1378 |
# Fields with _on$ have been handled already |
1379 |
|
1380 |
foreach my $key ( @keys ) { |
1381 |
next if !defined $item->{$key}; # skip undefs |
1382 |
my $dt = eval { dt_from_string( $item->{$key} ) }; |
1383 |
# eval: dt_from_string will die on us if we pass illegal dates |
1384 |
|
1385 |
my $newstr; |
1386 |
if( defined $dt && ref($dt) eq 'DateTime' ) { |
1387 |
if( $key =~ /datetime/ ) { |
1388 |
$newstr = DateTime::Format::MySQL->format_datetime($dt); |
1389 |
} else { |
1390 |
$newstr = DateTime::Format::MySQL->format_date($dt); |
1391 |
} |
1392 |
} |
1393 |
$item->{$key} = $newstr; # might be undef to clear garbage |
1394 |
} |
1395 |
} |
1396 |
|
1397 |
=head2 _marc_from_item_hash |
1095 |
=head2 _marc_from_item_hash |
1398 |
|
1096 |
|
1399 |
my $item_marc = _marc_from_item_hash($item, $frameworkcode[, $unlinked_item_subfields]); |
1097 |
my $item_marc = _marc_from_item_hash($item, $frameworkcode[, $unlinked_item_subfields]); |