|
Lines 24-56
use Try::Tiny qw( catch try );
Link Here
|
| 24 |
|
24 |
|
| 25 |
use C4::Auth qw( get_template_and_user haspermission ); |
25 |
use C4::Auth qw( get_template_and_user haspermission ); |
| 26 |
use C4::Output qw( output_html_with_http_headers ); |
26 |
use C4::Output qw( output_html_with_http_headers ); |
| 27 |
use C4::Biblio qw( |
27 |
use C4::Circulation qw( barcodedecode ); |
| 28 |
DelBiblio |
|
|
| 29 |
GetAuthorisedValueDesc |
| 30 |
GetMarcFromKohaField |
| 31 |
GetMarcStructure |
| 32 |
IsMarcStructureInternal |
| 33 |
TransformHtmlToXml |
| 34 |
); |
| 35 |
use C4::Items qw( GetItemsInfo Item2Marc ModItemFromMarc ); |
| 36 |
use C4::Circulation qw( barcodedecode LostItem IsItemIssued ); |
| 37 |
use C4::Context; |
28 |
use C4::Context; |
| 38 |
use C4::Koha; |
|
|
| 39 |
use C4::BackgroundJob; |
| 40 |
use C4::ClassSource qw( GetClassSources GetClassSource ); |
| 41 |
use MARC::File::XML; |
29 |
use MARC::File::XML; |
| 42 |
use List::MoreUtils qw( uniq ); |
30 |
use List::MoreUtils qw( uniq ); |
|
|
31 |
use Encode qw( encode_utf8 ); |
| 43 |
|
32 |
|
| 44 |
use Koha::Database; |
33 |
use Koha::Database; |
|
|
34 |
use Koha::DateUtils qw( dt_from_string ); |
| 45 |
use Koha::Exceptions::Exception; |
35 |
use Koha::Exceptions::Exception; |
| 46 |
use Koha::AuthorisedValues; |
|
|
| 47 |
use Koha::Biblios; |
36 |
use Koha::Biblios; |
| 48 |
use Koha::DateUtils qw( dt_from_string ); |
|
|
| 49 |
use Koha::Items; |
37 |
use Koha::Items; |
| 50 |
use Koha::ItemTypes; |
|
|
| 51 |
use Koha::Patrons; |
38 |
use Koha::Patrons; |
| 52 |
use Koha::SearchEngine::Indexer; |
39 |
use Koha::Item::Attributes; |
|
|
40 |
use Koha::BackgroundJob::BatchDeleteItem; |
| 41 |
use Koha::BackgroundJob::BatchUpdateItem; |
| 53 |
use Koha::UI::Form::Builder::Item; |
42 |
use Koha::UI::Form::Builder::Item; |
|
|
43 |
use Koha::UI::Table::Builder::Items; |
| 54 |
|
44 |
|
| 55 |
my $input = CGI->new; |
45 |
my $input = CGI->new; |
| 56 |
my $dbh = C4::Context->dbh; |
46 |
my $dbh = C4::Context->dbh; |
|
Lines 90-342
my $restrictededition = $uid ? haspermission($uid, {'tools' => 'items_batchmod_
Link Here
|
| 90 |
# In case user is a superlibrarian, edition is not restricted |
80 |
# In case user is a superlibrarian, edition is not restricted |
| 91 |
$restrictededition = 0 if ($restrictededition != 0 && C4::Context->IsSuperLibrarian()); |
81 |
$restrictededition = 0 if ($restrictededition != 0 && C4::Context->IsSuperLibrarian()); |
| 92 |
|
82 |
|
| 93 |
$template->param(del => $del); |
|
|
| 94 |
|
| 95 |
my $nextop=""; |
83 |
my $nextop=""; |
| 96 |
my @errors; # store errors found while checking data BEFORE saving item. |
84 |
my $display_items; |
| 97 |
my $items_display_hashref; |
|
|
| 98 |
our $tagslib = &GetMarcStructure(1); |
| 99 |
|
| 100 |
my $deleted_items = 0; # Number of deleted items |
| 101 |
my $deleted_records = 0; # Number of deleted records ( with no items attached ) |
| 102 |
my $not_deleted_items = 0; # Number of items that could not be deleted |
| 103 |
my @not_deleted; # List of the itemnumbers that could not be deleted |
| 104 |
my $modified_items = 0; # Numbers of modified items |
| 105 |
my $modified_fields = 0; # Numbers of modified fields |
| 106 |
|
85 |
|
| 107 |
my %cookies = parse CGI::Cookie($cookie); |
86 |
my %cookies = parse CGI::Cookie($cookie); |
| 108 |
my $sessionID = $cookies{'CGISESSID'}->value; |
87 |
my $sessionID = $cookies{'CGISESSID'}->value; |
| 109 |
|
88 |
|
|
|
89 |
my @messages; |
| 110 |
|
90 |
|
| 111 |
#--- ---------------------------------------------------------------------------- |
91 |
if ( $op eq "action" ) { |
| 112 |
if ($op eq "action") { |
92 |
|
| 113 |
#------------------------------------------------------------------------------- |
93 |
if ($del) { |
| 114 |
my @tags = $input->multi_param('tag'); |
|
|
| 115 |
my @subfields = $input->multi_param('subfield'); |
| 116 |
my @values = $input->multi_param('field_value'); |
| 117 |
my @searches = $input->multi_param('regex_search'); |
| 118 |
my @replaces = $input->multi_param('regex_replace'); |
| 119 |
my @modifiers = $input->multi_param('regex_modifiers'); |
| 120 |
|
| 121 |
my $upd_biblionumbers; |
| 122 |
my $del_biblionumbers; |
| 123 |
if ( $del ) { |
| 124 |
try { |
94 |
try { |
| 125 |
my $schema = Koha::Database->new->schema; |
95 |
my $params = { |
| 126 |
$schema->txn_do( |
96 |
record_ids => \@itemnumbers, |
| 127 |
sub { |
97 |
delete_biblios => $del_records, |
| 128 |
foreach my $itemnumber (@itemnumbers) { |
98 |
}; |
| 129 |
my $item = Koha::Items->find($itemnumber); |
99 |
my $job_id = |
| 130 |
next |
100 |
Koha::BackgroundJob::BatchDeleteItem->new->enqueue($params); |
| 131 |
unless $item |
101 |
$nextop = 'enqueued'; |
| 132 |
; # Should have been tested earlier, but just in case... |
102 |
$template->param( job_id => $job_id, ); |
| 133 |
my $itemdata = $item->unblessed; |
|
|
| 134 |
my $return = $item->safe_delete; |
| 135 |
if ( ref( $return ) ) { |
| 136 |
$deleted_items++; |
| 137 |
push @$upd_biblionumbers, $itemdata->{'biblionumber'}; |
| 138 |
} |
| 139 |
else { |
| 140 |
$not_deleted_items++; |
| 141 |
push @not_deleted, |
| 142 |
{ |
| 143 |
biblionumber => $itemdata->{'biblionumber'}, |
| 144 |
itemnumber => $itemdata->{'itemnumber'}, |
| 145 |
barcode => $itemdata->{'barcode'}, |
| 146 |
title => $itemdata->{'title'}, |
| 147 |
reason => $return, |
| 148 |
}; |
| 149 |
} |
| 150 |
|
| 151 |
# If there are no items left, delete the biblio |
| 152 |
if ($del_records) { |
| 153 |
my $itemscount = Koha::Biblios->find( $itemdata->{'biblionumber'} )->items->count; |
| 154 |
if ( $itemscount == 0 ) { |
| 155 |
my $error = DelBiblio( $itemdata->{'biblionumber'}, { skip_record_index => 1 } ); |
| 156 |
unless ($error) { |
| 157 |
$deleted_records++; |
| 158 |
push @$del_biblionumbers, $itemdata->{'biblionumber'}; |
| 159 |
if ( $src eq 'CATALOGUING' ) { |
| 160 |
# We are coming catalogue/detail.pl, there were items from a single bib record |
| 161 |
$template->param( biblio_deleted => 1 ); |
| 162 |
} |
| 163 |
} |
| 164 |
} |
| 165 |
} |
| 166 |
} |
| 167 |
if (@not_deleted) { |
| 168 |
Koha::Exceptions::Exception->throw( |
| 169 |
'Some items have not been deleted, rolling back'); |
| 170 |
} |
| 171 |
} |
| 172 |
); |
| 173 |
} |
103 |
} |
| 174 |
catch { |
104 |
catch { |
| 175 |
warn $_; |
105 |
warn $_; |
| 176 |
if ( $_->isa('Koha::Exceptions::Exception') ) { |
106 |
push @messages, |
| 177 |
$template->param( deletion_failed => 1 ); |
107 |
{ |
| 178 |
} |
108 |
type => 'error', |
| 179 |
die "Something terrible has happened!" |
109 |
code => 'cannot_enqueue_job', |
| 180 |
if ($_ =~ /Rollback failed/); # Rollback failed |
110 |
error => $_, |
|
|
111 |
}; |
| 112 |
$template->param( view => 'errors' ); |
| 181 |
}; |
113 |
}; |
| 182 |
} |
114 |
} |
| 183 |
|
115 |
|
| 184 |
else { # modification |
116 |
else { # modification |
| 185 |
|
117 |
|
| 186 |
my @columns = Koha::Items->columns; |
118 |
my @item_columns = Koha::Items->columns; |
| 187 |
|
119 |
|
| 188 |
my $new_item_data; |
120 |
my $new_item_data; |
| 189 |
my @columns_with_regex; |
121 |
my ( $columns_with_regex ); |
| 190 |
for my $c ( @columns ) { |
122 |
my @subfields_to_blank = $input->multi_param('disable_input'); |
| 191 |
if ( $c eq 'more_subfields_xml' ) { |
123 |
my @more_subfields = $input->multi_param("items.more_subfields_xml"); |
| 192 |
my @more_subfields_xml = $input->multi_param("items.more_subfields_xml"); |
124 |
for my $item_column (@item_columns) { |
| 193 |
my @unlinked_item_subfields; |
125 |
my @attributes = ($item_column); |
| 194 |
for my $subfield ( @more_subfields_xml ) { |
126 |
my $cgi_param_prefix = 'items.'; |
| 195 |
my $v = $input->param('items.more_subfields_xml_' . $subfield); |
127 |
if ( $item_column eq 'more_subfields_xml' ) { |
| 196 |
push @unlinked_item_subfields, $subfield, $v; |
128 |
@attributes = (); |
| 197 |
} |
129 |
$cgi_param_prefix = 'items.more_subfields_xml_'; |
| 198 |
if ( @unlinked_item_subfields ) { |
130 |
for my $subfield (@more_subfields) { |
| 199 |
my $marc = MARC::Record->new(); |
131 |
push @attributes, $subfield; |
| 200 |
# use of tag 999 is arbitrary, and doesn't need to match the item tag |
|
|
| 201 |
# used in the framework |
| 202 |
$marc->append_fields(MARC::Field->new('999', ' ', ' ', @unlinked_item_subfields)); |
| 203 |
$marc->encoding("UTF-8"); |
| 204 |
# FIXME This is WRONG! We need to use the values that haven't been modified by the batch tool! |
| 205 |
$new_item_data->{more_subfields_xml} = $marc->as_xml("USMARC"); |
| 206 |
next; |
| 207 |
} |
132 |
} |
| 208 |
$new_item_data->{more_subfields_xml} = undef; |
133 |
} |
| 209 |
# FIXME deal with more_subfields_xml and @subfields_to_blank |
|
|
| 210 |
} elsif ( grep { $c eq $_ } @subfields_to_blank ) { |
| 211 |
# Empty this column |
| 212 |
$new_item_data->{$c} = undef |
| 213 |
} else { |
| 214 |
|
134 |
|
| 215 |
my @v = grep { $_ ne "" } |
135 |
for my $attr (@attributes) { |
| 216 |
uniq $input->multi_param( "items." . $c ); |
|
|
| 217 |
|
136 |
|
| 218 |
next unless @v; |
137 |
my $cgi_var_name = $cgi_param_prefix |
|
|
138 |
. encode_utf8($attr) |
| 139 |
; # We need to deal correctly with encoding on subfield codes |
| 219 |
|
140 |
|
| 220 |
$new_item_data->{$c} = join ' | ', @v; |
141 |
if ( grep { $attr eq $_ } @subfields_to_blank ) { |
| 221 |
} |
142 |
|
|
|
143 |
# Empty this column |
| 144 |
$new_item_data->{$attr} = undef; |
| 145 |
} |
| 146 |
elsif ( my $regex_search = |
| 147 |
$input->param( $cgi_var_name . '_regex_search' ) ) |
| 148 |
{ |
| 149 |
$columns_with_regex->{$attr} = { |
| 150 |
search => $regex_search, |
| 151 |
replace => |
| 152 |
$input->param( $cgi_var_name . '_regex_replace' ), |
| 153 |
modifiers => |
| 154 |
$input->param( $cgi_var_name . '_regex_modifiers' ) |
| 155 |
}; |
| 156 |
} |
| 157 |
else { |
| 158 |
my @v = |
| 159 |
grep { $_ ne "" } uniq $input->multi_param($cgi_var_name); |
| 222 |
|
160 |
|
| 223 |
if ( my $regex_search = $input->param('items.'.$c.'_regex_search') ) { |
161 |
next unless @v; |
| 224 |
push @columns_with_regex, $c; |
162 |
|
|
|
163 |
$new_item_data->{$attr} = join '|', @v; |
| 164 |
} |
| 225 |
} |
165 |
} |
| 226 |
} |
166 |
} |
| 227 |
|
167 |
|
|
|
168 |
my $params = { |
| 169 |
record_ids => \@itemnumbers, |
| 170 |
regex_mod => $columns_with_regex, |
| 171 |
new_values => $new_item_data, |
| 172 |
exclude_from_local_holds_priority => ( |
| 173 |
defined $exclude_from_local_holds_priority |
| 174 |
&& $exclude_from_local_holds_priority ne "" |
| 175 |
) |
| 176 |
? $exclude_from_local_holds_priority |
| 177 |
: undef, |
| 178 |
|
| 179 |
}; |
| 228 |
try { |
180 |
try { |
| 229 |
my $schema = Koha::Database->new->schema; |
181 |
my $job_id = |
| 230 |
$schema->txn_do( |
182 |
Koha::BackgroundJob::BatchUpdateItem->new->enqueue($params); |
| 231 |
sub { |
183 |
$nextop = 'enqueued'; |
| 232 |
|
184 |
$template->param( job_id => $job_id, ); |
| 233 |
foreach my $itemnumber (@itemnumbers) { |
|
|
| 234 |
my $item = Koha::Items->find($itemnumber); |
| 235 |
next |
| 236 |
unless $item |
| 237 |
; # Should have been tested earlier, but just in case... |
| 238 |
my $itemdata = $item->unblessed; |
| 239 |
|
| 240 |
my $modified_holds_priority = 0; |
| 241 |
if ( defined $exclude_from_local_holds_priority && $exclude_from_local_holds_priority ne "" ) { |
| 242 |
if(!defined $item->exclude_from_local_holds_priority || $item->exclude_from_local_holds_priority != $exclude_from_local_holds_priority) { |
| 243 |
$item->exclude_from_local_holds_priority($exclude_from_local_holds_priority)->store; |
| 244 |
$modified_holds_priority = 1; |
| 245 |
} |
| 246 |
} |
| 247 |
|
| 248 |
my $modified = 0; |
| 249 |
for my $c ( @columns_with_regex ) { |
| 250 |
my $regex_search = $input->param('items.'.$c.'_regex_search'); |
| 251 |
my $old_value = $item->$c; |
| 252 |
|
| 253 |
my $value = apply_regex( |
| 254 |
{ |
| 255 |
search => $regex_search, |
| 256 |
replace => $input->param( |
| 257 |
'items' . $c . '_regex_replace' |
| 258 |
), |
| 259 |
modifiers => $input->param( |
| 260 |
'items' . $c . '_regex_modifiers' |
| 261 |
), |
| 262 |
value => $old_value, |
| 263 |
} |
| 264 |
); |
| 265 |
unless ( $old_value eq $value ) { |
| 266 |
$modified++; |
| 267 |
$item->$c($value); |
| 268 |
} |
| 269 |
} |
| 270 |
|
| 271 |
$modified += scalar(keys %$new_item_data); # FIXME This is incorrect if old value == new value. Should we loop of the keys and compare the before/after values? |
| 272 |
if ( $modified) { |
| 273 |
my $itemlost_pre = $item->itemlost; |
| 274 |
$item->set($new_item_data)->store({skip_record_index => 1}); |
| 275 |
|
| 276 |
push @$upd_biblionumbers, $itemdata->{'biblionumber'}; |
| 277 |
|
| 278 |
LostItem( |
| 279 |
$item->itemnumber, 'batchmod', undef, |
| 280 |
{ skip_record_index => 1 } |
| 281 |
) if $item->itemlost |
| 282 |
and not $itemlost_pre; |
| 283 |
} |
| 284 |
|
| 285 |
$modified_items++ if $modified || $modified_holds_priority; |
| 286 |
$modified_fields += $modified + $modified_holds_priority; |
| 287 |
} |
| 288 |
} |
| 289 |
); |
| 290 |
} |
185 |
} |
| 291 |
catch { |
186 |
catch { |
| 292 |
warn $_; |
187 |
push @messages, |
| 293 |
die "Something terrible has happened!" |
188 |
{ |
| 294 |
if ($_ =~ /Rollback failed/); # Rollback failed |
189 |
type => 'error', |
|
|
190 |
code => 'cannot_enqueue_job', |
| 191 |
error => $_, |
| 192 |
}; |
| 193 |
$template->param( view => 'errors' ); |
| 295 |
}; |
194 |
}; |
| 296 |
} |
195 |
} |
| 297 |
|
196 |
|
| 298 |
$upd_biblionumbers = [ uniq @$upd_biblionumbers ]; # Only update each bib once |
|
|
| 299 |
|
| 300 |
# Don't send specialUpdate for records we are going to delete |
| 301 |
my %del_bib_hash = map{ $_ => undef } @$del_biblionumbers; |
| 302 |
@$upd_biblionumbers = grep( ! exists( $del_bib_hash{$_} ), @$upd_biblionumbers ); |
| 303 |
|
| 304 |
my $indexer = Koha::SearchEngine::Indexer->new({ index => $Koha::SearchEngine::BIBLIOS_INDEX }); |
| 305 |
$indexer->index_records( $upd_biblionumbers, 'specialUpdate', "biblioserver", undef ) if @$upd_biblionumbers; |
| 306 |
$indexer->index_records( $del_biblionumbers, 'recordDelete', "biblioserver", undef ) if @$del_biblionumbers; |
| 307 |
|
| 308 |
# Once the job is done |
| 309 |
# If we have a reasonable amount of items, we display them |
| 310 |
my $max_items = $del ? C4::Context->preference("MaxItemsToDisplayForBatchDel") : C4::Context->preference("MaxItemsToDisplayForBatchMod"); |
| 311 |
if (scalar(@itemnumbers) <= $max_items ){ |
| 312 |
if (scalar(@itemnumbers) <= 1000 ) { |
| 313 |
$items_display_hashref=BuildItemsData(@itemnumbers); |
| 314 |
} else { |
| 315 |
# Else, we only display the barcode |
| 316 |
my @simple_items_display = map { |
| 317 |
my $itemnumber = $_; |
| 318 |
my $item = Koha::Items->find($itemnumber); |
| 319 |
{ |
| 320 |
itemnumber => $itemnumber, |
| 321 |
barcode => $item ? ( $item->barcode // q{} ) : q{}, |
| 322 |
biblionumber => $item ? $item->biblio->biblionumber : q{}, |
| 323 |
}; |
| 324 |
} @itemnumbers; |
| 325 |
$template->param("simple_items_display" => \@simple_items_display); |
| 326 |
} |
| 327 |
} else { |
| 328 |
$template->param( "too_many_items_display" => scalar(@itemnumbers) ); |
| 329 |
$template->param( "job_completed" => 1 ); |
| 330 |
} |
| 331 |
|
| 332 |
|
| 333 |
# Calling the template |
| 334 |
$template->param( |
| 335 |
modified_items => $modified_items, |
| 336 |
modified_fields => $modified_fields, |
| 337 |
); |
| 338 |
|
| 339 |
} |
197 |
} |
|
|
198 |
|
| 199 |
$template->param( |
| 200 |
messages => \@messages, |
| 201 |
); |
| 340 |
# |
202 |
# |
| 341 |
#------------------------------------------------------------------------------- |
203 |
#------------------------------------------------------------------------------- |
| 342 |
# build screen with existing items. and "new" one |
204 |
# build screen with existing items. and "new" one |
|
Lines 372-381
if ($op eq "show"){
Link Here
|
| 372 |
} |
234 |
} |
| 373 |
} else { |
235 |
} else { |
| 374 |
if (defined $biblionumber && !@itemnumbers){ |
236 |
if (defined $biblionumber && !@itemnumbers){ |
| 375 |
my @all_items = GetItemsInfo( $biblionumber ); |
237 |
my $biblio = Koha::Biblios->find($biblionumber); |
| 376 |
foreach my $itm (@all_items) { |
238 |
@itemnumbers = $biblio ? $biblio->items->get_column('itemnumber') : (); |
| 377 |
push @itemnumbers, $itm->{itemnumber}; |
|
|
| 378 |
} |
| 379 |
} |
239 |
} |
| 380 |
if ( my $list = $input->param('barcodelist') ) { |
240 |
if ( my $list = $input->param('barcodelist') ) { |
| 381 |
my @barcodelist = grep /\S/, ( split /[$split_chars]/, $list ); |
241 |
my @barcodelist = grep /\S/, ( split /[$split_chars]/, $list ); |
|
Lines 398-404
if ($op eq "show"){
Link Here
|
| 398 |
: C4::Context->preference("MaxItemsToDisplayForBatchMod"); |
258 |
: C4::Context->preference("MaxItemsToDisplayForBatchMod"); |
| 399 |
$template->param("too_many_items_process" => scalar(@itemnumbers)) if !$del && scalar(@itemnumbers) > C4::Context->preference("MaxItemsToProcessForBatchMod"); |
259 |
$template->param("too_many_items_process" => scalar(@itemnumbers)) if !$del && scalar(@itemnumbers) > C4::Context->preference("MaxItemsToProcessForBatchMod"); |
| 400 |
if (scalar(@itemnumbers) <= ( $max_display_items // 1000 ) ) { |
260 |
if (scalar(@itemnumbers) <= ( $max_display_items // 1000 ) ) { |
| 401 |
$items_display_hashref=BuildItemsData(@itemnumbers); |
261 |
$display_items = 1; |
| 402 |
} else { |
262 |
} else { |
| 403 |
$template->param("too_many_items_display" => scalar(@itemnumbers)); |
263 |
$template->param("too_many_items_display" => scalar(@itemnumbers)); |
| 404 |
# Even if we do not display the items, we need the itemnumbers |
264 |
# Even if we do not display the items, we need the itemnumbers |
|
Lines 406-415
if ($op eq "show"){
Link Here
|
| 406 |
} |
266 |
} |
| 407 |
|
267 |
|
| 408 |
# now, build the item form for entering a new item |
268 |
# now, build the item form for entering a new item |
| 409 |
my @loop_data =(); |
|
|
| 410 |
my $branch_limit = C4::Context->userenv ? C4::Context->userenv->{"branch"} : ""; |
| 411 |
|
| 412 |
my $pref_itemcallnumber = C4::Context->preference('itemcallnumber'); |
| 413 |
|
269 |
|
| 414 |
# Getting list of subfields to keep when restricted batchmod edit is enabled |
270 |
# Getting list of subfields to keep when restricted batchmod edit is enabled |
| 415 |
my @subfields_to_allow = $restrictededition ? split ' ', C4::Context->preference('SubfieldsToAllowForRestrictedBatchmod') : (); |
271 |
my @subfields_to_allow = $restrictededition ? split ' ', C4::Context->preference('SubfieldsToAllowForRestrictedBatchmod') : (); |
|
Lines 422-428
if ($op eq "show"){
Link Here
|
| 422 |
? ( subfields_to_allow => \@subfields_to_allow ) |
278 |
? ( subfields_to_allow => \@subfields_to_allow ) |
| 423 |
: () |
279 |
: () |
| 424 |
), |
280 |
), |
| 425 |
subfields_to_ignore => ['items.barcode'], |
281 |
ignore_not_allowed_subfields => 1, |
|
|
282 |
kohafields_to_ignore => ['items.barcode'], |
| 426 |
prefill_with_default_values => $use_default_values, |
283 |
prefill_with_default_values => $use_default_values, |
| 427 |
default_branches_empty => 1, |
284 |
default_branches_empty => 1, |
| 428 |
} |
285 |
} |
|
Lines 437-623
if ($op eq "show"){
Link Here
|
| 437 |
$nextop="action" |
294 |
$nextop="action" |
| 438 |
} # -- End action="show" |
295 |
} # -- End action="show" |
| 439 |
|
296 |
|
| 440 |
$template->param(%$items_display_hashref) if $items_display_hashref; |
297 |
if ( $display_items ) { |
| 441 |
$template->param( |
298 |
my $items_table = |
| 442 |
op => $nextop, |
299 |
Koha::UI::Table::Builder::Items->new( { itemnumbers => \@itemnumbers } ) |
| 443 |
); |
300 |
->build_table; |
| 444 |
$template->param( $op => 1 ) if $op; |
|
|
| 445 |
|
| 446 |
if ($op eq "action") { |
| 447 |
|
| 448 |
#my @not_deleted_loop = map{{itemnumber=>$_}}@not_deleted; |
| 449 |
|
| 450 |
$template->param( |
301 |
$template->param( |
| 451 |
not_deleted_items => $not_deleted_items, |
302 |
items => $items_table->{items}, |
| 452 |
deleted_items => $deleted_items, |
303 |
item_header_loop => $items_table->{headers}, |
| 453 |
delete_records => $del_records, |
|
|
| 454 |
deleted_records => $deleted_records, |
| 455 |
not_deleted_loop => \@not_deleted |
| 456 |
); |
304 |
); |
| 457 |
} |
305 |
} |
| 458 |
|
306 |
|
| 459 |
foreach my $error (@errors) { |
307 |
$template->param( |
| 460 |
$template->param($error => 1) if $error; |
308 |
op => $nextop, |
| 461 |
} |
309 |
del => $del, |
| 462 |
$template->param(src => $src); |
310 |
( $op ? ( $op => 1 ) : () ), |
| 463 |
$template->param(biblionumber => $biblionumber); |
311 |
src => $src, |
| 464 |
output_html_with_http_headers $input, $cookie, $template->output; |
312 |
biblionumber => $biblionumber, |
| 465 |
exit; |
313 |
); |
| 466 |
|
|
|
| 467 |
|
| 468 |
# ---------------- Functions |
| 469 |
|
| 470 |
sub BuildItemsData{ |
| 471 |
my @itemnumbers=@_; |
| 472 |
# now, build existiing item list |
| 473 |
my %witness; #---- stores the list of subfields used at least once, with the "meaning" of the code |
| 474 |
my @big_array; |
| 475 |
#---- finds where items.itemnumber is stored |
| 476 |
my ( $itemtagfield, $itemtagsubfield) = &GetMarcFromKohaField( "items.itemnumber" ); |
| 477 |
my ($branchtagfield, $branchtagsubfield) = &GetMarcFromKohaField( "items.homebranch" ); |
| 478 |
foreach my $itemnumber (@itemnumbers){ |
| 479 |
my $itemdata = Koha::Items->find($itemnumber); |
| 480 |
next unless $itemdata; # Should have been tested earlier, but just in case... |
| 481 |
$itemdata = $itemdata->unblessed; |
| 482 |
my $itemmarc=Item2Marc($itemdata); |
| 483 |
my %this_row; |
| 484 |
foreach my $field (grep {$_->tag() eq $itemtagfield} $itemmarc->fields()) { |
| 485 |
# loop through each subfield |
| 486 |
my $itembranchcode=$field->subfield($branchtagsubfield); |
| 487 |
if ($itembranchcode && C4::Context->preference("IndependentBranches")) { |
| 488 |
#verifying rights |
| 489 |
my $userenv = C4::Context->userenv(); |
| 490 |
unless (C4::Context->IsSuperLibrarian() or (($userenv->{'branch'} eq $itembranchcode))){ |
| 491 |
$this_row{'nomod'}=1; |
| 492 |
} |
| 493 |
} |
| 494 |
my $tag=$field->tag(); |
| 495 |
foreach my $subfield ($field->subfields) { |
| 496 |
my ($subfcode,$subfvalue)=@$subfield; |
| 497 |
next if ($tagslib->{$tag}->{$subfcode}->{tab} ne 10 |
| 498 |
&& $tag ne $itemtagfield |
| 499 |
&& $subfcode ne $itemtagsubfield); |
| 500 |
|
| 501 |
$witness{$subfcode} = $tagslib->{$tag}->{$subfcode}->{lib} if ($tagslib->{$tag}->{$subfcode}->{tab} eq 10); |
| 502 |
if ($tagslib->{$tag}->{$subfcode}->{tab} eq 10) { |
| 503 |
$this_row{$subfcode}=GetAuthorisedValueDesc( $tag, |
| 504 |
$subfcode, $subfvalue, '', $tagslib) |
| 505 |
|| $subfvalue; |
| 506 |
} |
| 507 |
|
| 508 |
$this_row{itemnumber} = $subfvalue if ($tag eq $itemtagfield && $subfcode eq $itemtagsubfield); |
| 509 |
} |
| 510 |
} |
| 511 |
|
| 512 |
# grab title, author, and ISBN to identify bib that the item |
| 513 |
# belongs to in the display |
| 514 |
my $biblio = Koha::Biblios->find( $itemdata->{biblionumber} ); |
| 515 |
$this_row{title} = $biblio->title; |
| 516 |
$this_row{author} = $biblio->author; |
| 517 |
$this_row{isbn} = $biblio->biblioitem->isbn; |
| 518 |
$this_row{biblionumber} = $biblio->biblionumber; |
| 519 |
$this_row{holds} = $biblio->holds->count; |
| 520 |
$this_row{item_holds} = Koha::Holds->search( { itemnumber => $itemnumber } )->count; |
| 521 |
$this_row{item} = Koha::Items->find($itemnumber); |
| 522 |
|
| 523 |
if (%this_row) { |
| 524 |
push(@big_array, \%this_row); |
| 525 |
} |
| 526 |
} |
| 527 |
@big_array = sort {$a->{0} cmp $b->{0}} @big_array; |
| 528 |
|
| 529 |
# now, construct template ! |
| 530 |
# First, the existing items for display |
| 531 |
my @item_value_loop; |
| 532 |
my @witnesscodessorted=sort keys %witness; |
| 533 |
for my $row ( @big_array ) { |
| 534 |
my %row_data; |
| 535 |
my @item_fields = map +{ field => $_ || '' }, @$row{ @witnesscodessorted }; |
| 536 |
$row_data{item_value} = [ @item_fields ]; |
| 537 |
$row_data{itemnumber} = $row->{itemnumber}; |
| 538 |
#reporting this_row values |
| 539 |
$row_data{'nomod'} = $row->{'nomod'}; |
| 540 |
$row_data{bibinfo} = $row->{bibinfo}; |
| 541 |
$row_data{author} = $row->{author}; |
| 542 |
$row_data{title} = $row->{title}; |
| 543 |
$row_data{isbn} = $row->{isbn}; |
| 544 |
$row_data{biblionumber} = $row->{biblionumber}; |
| 545 |
$row_data{holds} = $row->{holds}; |
| 546 |
$row_data{item_holds} = $row->{item_holds}; |
| 547 |
$row_data{item} = $row->{item}; |
| 548 |
$row_data{safe_to_delete} = $row->{item}->safe_to_delete; |
| 549 |
my $is_on_loan = C4::Circulation::IsItemIssued( $row->{itemnumber} ); |
| 550 |
$row_data{onloan} = $is_on_loan ? 1 : 0; |
| 551 |
push(@item_value_loop,\%row_data); |
| 552 |
} |
| 553 |
my @header_loop=map { { header_value=> $witness{$_}} } @witnesscodessorted; |
| 554 |
|
| 555 |
my @cannot_be_deleted = map { |
| 556 |
$_->{safe_to_delete} == 1 ? () : $_->{item}->barcode |
| 557 |
} @item_value_loop; |
| 558 |
return { |
| 559 |
item_loop => \@item_value_loop, |
| 560 |
cannot_be_deleted => \@cannot_be_deleted, |
| 561 |
item_header_loop => \@header_loop |
| 562 |
}; |
| 563 |
} |
| 564 |
|
| 565 |
#BE WARN : it is not the general case |
| 566 |
# This function can be OK in the item marc record special case |
| 567 |
# Where subfield is not repeated |
| 568 |
# And where we are sure that field should correspond |
| 569 |
# And $tag>10 |
| 570 |
sub UpdateMarcWith { |
| 571 |
my ($marcfrom,$marcto)=@_; |
| 572 |
my ( $itemtag, $itemtagsubfield) = &GetMarcFromKohaField( "items.itemnumber" ); |
| 573 |
my $fieldfrom=$marcfrom->field($itemtag); |
| 574 |
my @fields_to=$marcto->field($itemtag); |
| 575 |
my $modified = 0; |
| 576 |
|
| 577 |
return $modified unless $fieldfrom; |
| 578 |
|
| 579 |
foreach my $subfield ( $fieldfrom->subfields() ) { |
| 580 |
foreach my $field_to_update ( @fields_to ) { |
| 581 |
if ( $subfield->[1] ) { |
| 582 |
unless ( $field_to_update->subfield($subfield->[0]) eq $subfield->[1] ) { |
| 583 |
$modified++; |
| 584 |
$field_to_update->update( $subfield->[0] => $subfield->[1] ); |
| 585 |
} |
| 586 |
} |
| 587 |
else { |
| 588 |
$modified++; |
| 589 |
$field_to_update->delete_subfield( code => $subfield->[0] ); |
| 590 |
} |
| 591 |
} |
| 592 |
} |
| 593 |
return $modified; |
| 594 |
} |
| 595 |
|
| 596 |
sub apply_regex { |
| 597 |
my ($params) = @_; |
| 598 |
my $search = $params->{search}; |
| 599 |
my $replace = $params->{replace}; |
| 600 |
my $modifiers = $params->{modifiers} || []; |
| 601 |
my $value = $params->{value}; |
| 602 |
|
| 603 |
my @available_modifiers = qw( i g ); |
| 604 |
my $retained_modifiers = q||; |
| 605 |
for my $modifier ( split //, @$modifiers ) { |
| 606 |
$retained_modifiers .= $modifier |
| 607 |
if grep { /$modifier/ } @available_modifiers; |
| 608 |
} |
| 609 |
if ( $retained_modifiers =~ m/^(ig|gi)$/ ) { |
| 610 |
$value =~ s/$search/$replace/ig; |
| 611 |
} |
| 612 |
elsif ( $retained_modifiers eq 'i' ) { |
| 613 |
$value =~ s/$search/$replace/i; |
| 614 |
} |
| 615 |
elsif ( $retained_modifiers eq 'g' ) { |
| 616 |
$value =~ s/$search/$replace/g; |
| 617 |
} |
| 618 |
else { |
| 619 |
$value =~ s/$search/$replace/; |
| 620 |
} |
| 621 |
|
314 |
|
| 622 |
return $value; |
315 |
output_html_with_http_headers $input, $cookie, $template->output; |
| 623 |
} |
|
|
| 624 |
- |
|
|