|
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]); |