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