View | Details | Raw Unified | Return to bug 28445
Collapse All | Expand All

(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/html_helpers.inc (-5 / +7 lines)
Lines 116-122 Link Here
116
                            [% ELSE  %]
116
                            [% ELSE  %]
117
                                <a href="#" id="buttonDot_[%- mv.id | html -%]" class="[%- mv.class | html -%]" title="Tag editor">...</a>
117
                                <a href="#" id="buttonDot_[%- mv.id | html -%]" class="[%- mv.class | html -%]" title="Tag editor">...</a>
118
                            [% END %]
118
                            [% END %]
119
                            [%- mv.javascript | $raw -%]
119
                            [% UNLESS no_plugin %][%# FIXME - from batchMod-edit, jQuery is included at the end of the template and cataloguing plugins are not working in this situation %]
120
                                [%- mv.javascript | $raw -%]
121
                            [% END %]
120
                        [% END %]
122
                        [% END %]
121
                    [% ELSIF ( mv.type == 'text' ) %]
123
                    [% ELSIF ( mv.type == 'text' ) %]
122
                        [% IF mv.readonly %]
124
                        [% IF mv.readonly %]
Lines 142-150 Link Here
142
144
143
                    [% IF add_regex %]
145
                    [% IF add_regex %]
144
                        <span name="regex_fields" style="display: none;">
146
                        <span name="regex_fields" style="display: none;">
145
                            s/<input type="text" id="[% mv.id | html %]" name="regex_search" placeholder="regex pattern" />/
147
                            s/<input type="text" name="[% kohafield | html %]_regex_search" class="regex_search" placeholder="regex pattern" />/
146
                            <input type="text" id="[% mv.id | html %]" name="regex_replace" placeholder="regex replacement" />/
148
                            <input type="text" name="[% kohafield | html %]_regex_replace" class="regex_replace" placeholder="regex replacement" />/
147
                            <input type="text" id="[% mv.id | html %]" name="regex_modifiers" placeholder="ig" size="3" />
149
                            <input type="text" name="[% kohafield | html %]_regex_modifiers" class="regex_modifiers" placeholder="ig" size="3" />
148
                        </span>
150
                        </span>
149
                    [% END %]
151
                    [% END %]
150
152
Lines 162-168 Link Here
162
164
163
                    [% IF add_regex %]
165
                    [% IF add_regex %]
164
                        [% IF (mv.type == 'text' || mv.type == 'text2' || mv.type == 'textarea' ) %]
166
                        [% IF (mv.type == 'text' || mv.type == 'text2' || mv.type == 'textarea' ) %]
165
                            <a href="#" name="field_regex" id="[% subfield.id | html %]" >RegEx</a>
167
                            <a href="#" name="[% kohafield | html %]_field_regex" class="field_regex" id="[% subfield.id | html %]" >RegEx</a>
166
                        [% END %]
168
                        [% END %]
167
                    [% END %]
169
                    [% END %]
168
170
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/batchMod-edit.tt (-10 / +10 lines)
Lines 248-254 Link Here
248
                        <h2>Edit items</h2>
248
                        <h2>Edit items</h2>
249
                        <div class="hint">Checking the box right next to the subfield label will disable the entry and delete the subfield on all selected items. Leave fields blank to make no change.</div>
249
                        <div class="hint">Checking the box right next to the subfield label will disable the entry and delete the subfield on all selected items. Leave fields blank to make no change.</div>
250
                        <fieldset class="rows">
250
                        <fieldset class="rows">
251
                            [% PROCESS subfields_for_item subfields => subfields, add_regex => 1, add_delete_checkbox => 1 %]
251
                            [%# no_plugin from batchMod-edit, jQuery is included at the end of the template and cataloguing plugins are not working in this situation %]
252
                            [% PROCESS subfields_for_item subfields => subfields, add_regex => 1, add_delete_checkbox => 1, no_plugin => 1 %]
252
                        </fieldset>
253
                        </fieldset>
253
254
254
                        <fieldset class="rows">
255
                        <fieldset class="rows">
Lines 310-317 Link Here
310
                $("input[name='disable_input']").click(function() {
311
                $("input[name='disable_input']").click(function() {
311
                    var row = $(this).attr("id");
312
                    var row = $(this).attr("id");
312
                    row = row.replace("row","hint");
313
                    row = row.replace("row","hint");
313
                    var todisable = $(this).parent().find("[name='field_value'],[name='tag'],[name='subfield'],[name='mandatory']");
314
                    var todisable = $(this).parent().find(".input_marceditor,.tag,.subfield,.mandatory");
314
                    var regex_link = $(this).parent().find("[name='field_regex']");
315
                    var regex_link = $(this).parent().find(".field_regex");
315
                    if ($(this).is(":checked")) {
316
                    if ($(this).is(":checked")) {
316
                        $(todisable).prop('disabled', true);
317
                        $(todisable).prop('disabled', true);
317
                        $("#"+row).html(_("This subfield will be deleted"));
318
                        $("#"+row).html(_("This subfield will be deleted"));
Lines 322-333 Link Here
322
                        $(regex_link).show();
323
                        $(regex_link).show();
323
                    }
324
                    }
324
                });
325
                });
325
                $('a[name="field_regex"]').click(function() {
326
                $('a.field_regex').click(function() {
326
                    var id = $(this).attr('id');
327
                    var editor = $(this).parent().find(".input_marceditor");
327
                    var editor = $(this).parent().find("[name='field_value']");
328
                    var tag_editor = $(this).parent().find(".buttonDot");
328
                    var tag_editor = $(this).parent().find(".buttonDot");
329
                    var regex = $(this).parent().find("[name='regex_fields']");
329
                    var regex = $(this).parent().find("[name='regex_fields']");
330
                    var disable_input = $(this).parent().find("[name='disable_input']");
330
                    var disable_input = $(this).parent().find(".disable_input");
331
                    if ($(this).html() == 'RegEx') {
331
                    if ($(this).html() == 'RegEx') {
332
                        $(editor).hide();
332
                        $(editor).hide();
333
                        $(regex).show();
333
                        $(regex).show();
Lines 348-357 Link Here
348
        [% IF ( show ) %]
348
        [% IF ( show ) %]
349
            [%- # Loop over fields which may have plugin JavaScript -%]
349
            [%- # Loop over fields which may have plugin JavaScript -%]
350
            [%- UNLESS (too_many_items_process) -%]
350
            [%- UNLESS (too_many_items_process) -%]
351
                [%- FOREACH ite IN item -%]
351
                [%- FOREACH subfield IN subfields -%]
352
                    [% SET mv = ite.marc_value %]
352
                    [% SET mv = subfield.marc_value %]
353
                    [%- IF ( mv.type == 'text2' ) -%]
353
                    [%- IF ( mv.type == 'text2' ) -%]
354
                        <!-- subfield[% ite.tag | html %][% ite.subfield | html %][% ite.random | html %] -->
354
                        <!-- subfield[% subfield.tag | html %][% subfield.subfield | html %][% subfield.random | html %] -->
355
                        [% mv.javascript | $raw %]
355
                        [% mv.javascript | $raw %]
356
                    [%- END -%]
356
                    [%- END -%]
357
                [%- END -%]
357
                [%- END -%]
(-)a/tools/batchMod.pl (-120 / +159 lines)
Lines 117-167 if ($op eq "action") { Link Here
117
    my @searches  = $input->multi_param('regex_search');
117
    my @searches  = $input->multi_param('regex_search');
118
    my @replaces  = $input->multi_param('regex_replace');
118
    my @replaces  = $input->multi_param('regex_replace');
119
    my @modifiers = $input->multi_param('regex_modifiers');
119
    my @modifiers = $input->multi_param('regex_modifiers');
120
    my @disabled  = $input->multi_param('disable_input');
120
    my @subfields_to_blank = $input->multi_param('disable_input');
121
    # build indicator hash.
121
    # build indicator hash.
122
    my @ind_tag   = $input->multi_param('ind_tag');
122
    my @ind_tag   = $input->multi_param('ind_tag');
123
    my @indicator = $input->multi_param('indicator');
123
    my @indicator = $input->multi_param('indicator');
124
124
125
    # Is there something to modify ?
126
    # TODO : We shall use this var to warn the user in case no modification was done to the items
127
    my $values_to_modify = scalar(grep {!/^$/} @values) || scalar(grep {!/^$/} @searches);
128
    my $values_to_blank  = scalar(@disabled);
129
130
    my $marcitem;
131
132
    #initializing values for updates
133
    my (  $itemtagfield,   $itemtagsubfield) = &GetMarcFromKohaField( "items.itemnumber" );
134
    if ($values_to_modify){
135
        my $xml = TransformHtmlToXml(\@tags,\@subfields,\@values,\@indicator,\@ind_tag, 'ITEM');
136
        $marcitem = MARC::Record::new_from_xml($xml, 'UTF-8');
137
    }
138
    if ($values_to_blank){
139
        foreach my $disabledsubf (@disabled){
140
            if ($marcitem && $marcitem->field($itemtagfield)){
141
                $marcitem->field($itemtagfield)->update( $disabledsubf => "" );
142
            }
143
            else {
144
                $marcitem = MARC::Record->new();
145
                $marcitem->append_fields( MARC::Field->new( $itemtagfield, '', '', $disabledsubf => "" ) );
146
            }
147
        }
148
    }
149
150
    my $upd_biblionumbers;
125
    my $upd_biblionumbers;
151
    my $del_biblionumbers;
126
    my $del_biblionumbers;
152
    try {
127
    if ( $del ) {
153
        my $schema = Koha::Database->new->schema;
128
        try {
154
        $schema->txn_do(
129
            my $schema = Koha::Database->new->schema;
155
            sub {
130
            $schema->txn_do(
156
                # For each item
131
                sub {
157
                my $i = 1;
132
                    foreach my $itemnumber (@itemnumbers) {
158
                foreach my $itemnumber (@itemnumbers) {
133
                        my $item = Koha::Items->find($itemnumber);
159
                    my $item = Koha::Items->find($itemnumber);
134
                        next
160
                    next
135
                          unless $item
161
                      unless $item
136
                          ; # Should have been tested earlier, but just in case...
162
                      ; # Should have been tested earlier, but just in case...
137
                        my $itemdata = $item->unblessed;
163
                    my $itemdata = $item->unblessed;
164
                    if ($del) {
165
                        my $return = $item->safe_delete;
138
                        my $return = $item->safe_delete;
166
                        if ( ref( $return ) ) {
139
                        if ( ref( $return ) ) {
167
                            $deleted_items++;
140
                            $deleted_items++;
Lines 195-294 if ($op eq "action") { Link Here
195
                            }
168
                            }
196
                        }
169
                        }
197
                    }
170
                    }
198
                    else {
171
                    if (@not_deleted) {
199
                        my $modified_holds_priority = 0;
172
                        Koha::Exceptions::Exception->throw(
200
                        if ( defined $exclude_from_local_holds_priority && $exclude_from_local_holds_priority ne "" ) {
173
                            'Some items have not been deleted, rolling back');
201
                            if(!defined $item->exclude_from_local_holds_priority || $item->exclude_from_local_holds_priority != $exclude_from_local_holds_priority) {
174
                    }
202
                            $item->exclude_from_local_holds_priority($exclude_from_local_holds_priority)->store;
175
                }
203
                            $modified_holds_priority = 1;
176
            );
204
                        }
177
        }
205
                        }
178
        catch {
206
                        my $modified = 0;
179
            warn $_;
207
                        if ( $values_to_modify || $values_to_blank ) {
180
            if ( $_->isa('Koha::Exceptions::Exception') ) {
208
                            my $localmarcitem = Item2Marc($itemdata);
181
                $template->param( deletion_failed => 1 );
182
            }
183
            die "Something terrible has happened!"
184
                if ($_ =~ /Rollback failed/); # Rollback failed
185
        };
186
    }
209
187
210
                            for ( my $i = 0 ; $i < @tags ; $i++ ) {
188
    else { # modification
211
                                my $search = $searches[$i];
212
                                next unless $search;
213
189
214
                                my $tag = $tags[$i];
190
        my @columns = Koha::Items->columns;
215
                                my $subfield = $subfields[$i];
216
                                my $replace = $replaces[$i];
217
191
218
                                my $value = $localmarcitem->field( $tag )->subfield( $subfield );
192
        my $new_item_data;
219
                                my $old_value = $value;
193
        my @columns_with_regex;
194
        for my $c ( @columns ) {
195
            if ( $c eq 'more_subfields_xml' ) {
196
                my @more_subfields_xml = $input->multi_param("items.more_subfields_xml");
197
                my @unlinked_item_subfields;
198
                for my $subfield ( @more_subfields_xml ) {
199
                    my $v = $input->param('items.more_subfields_xml_' . $subfield);
200
                    push @unlinked_item_subfields, $subfield, $v;
201
                }
202
                if ( @unlinked_item_subfields ) {
203
                    my $marc = MARC::Record->new();
204
                    # use of tag 999 is arbitrary, and doesn't need to match the item tag
205
                    # used in the framework
206
                    $marc->append_fields(MARC::Field->new('999', ' ', ' ', @unlinked_item_subfields));
207
                    $marc->encoding("UTF-8");
208
                    # FIXME This is WRONG! We need to use the values that haven't been modified by the batch tool!
209
                    $new_item_data->{more_subfields_xml} = $marc->as_xml("USMARC");
210
                    next;
211
                }
212
                $new_item_data->{more_subfields_xml} = undef;
213
                # FIXME deal with more_subfields_xml and @subfields_to_blank
214
            } elsif ( grep { $c eq $_ } @subfields_to_blank ) {
215
                # Empty this column
216
                $new_item_data->{$c} = undef
217
            } else {
220
218
221
                                my @available_modifiers = qw( i g );
219
                my @v = grep { $_ ne "" }
222
                                my $retained_modifiers = q||;
220
                    uniq $input->multi_param( "items." . $c );
223
                                for my $modifier ( split //, $modifiers[$i] ) {
224
                                    $retained_modifiers .= $modifier
225
                                        if grep {/$modifier/} @available_modifiers;
226
                                }
227
                                if ( $retained_modifiers =~ m/^(ig|gi)$/ ) {
228
                                    $value =~ s/$search/$replace/ig;
229
                                }
230
                                elsif ( $retained_modifiers eq 'i' ) {
231
                                    $value =~ s/$search/$replace/i;
232
                                }
233
                                elsif ( $retained_modifiers eq 'g' ) {
234
                                    $value =~ s/$search/$replace/g;
235
                                }
236
                                else {
237
                                    $value =~ s/$search/$replace/;
238
                                }
239
221
240
                                my @fields_to = $localmarcitem->field($tag);
222
                next unless @v;
241
                                foreach my $field_to_update ( @fields_to ) {
223
242
                                    unless ( $old_value eq $value ) {
224
                $new_item_data->{$c} = join ' | ', @v;
243
                                        $modified++;
225
            }
244
                                        $field_to_update->update( $subfield => $value );
226
245
                                    }
227
            if ( my $regex_search = $input->param('items.'.$c.'_regex_search') ) {
246
                                }
228
                push @columns_with_regex, $c;
229
            }
230
        }
231
232
        try {
233
            my $schema = Koha::Database->new->schema;
234
            $schema->txn_do(
235
                sub {
236
237
                    foreach my $itemnumber (@itemnumbers) {
238
                        my $item = Koha::Items->find($itemnumber);
239
                        next
240
                          unless $item
241
                          ; # Should have been tested earlier, but just in case...
242
                        my $itemdata = $item->unblessed;
243
244
                        my $modified_holds_priority = 0;
245
                        if ( defined $exclude_from_local_holds_priority && $exclude_from_local_holds_priority ne "" ) {
246
                            if(!defined $item->exclude_from_local_holds_priority || $item->exclude_from_local_holds_priority != $exclude_from_local_holds_priority) {
247
                                $item->exclude_from_local_holds_priority($exclude_from_local_holds_priority)->store;
248
                                $modified_holds_priority = 1;
247
                            }
249
                            }
250
                        }
248
251
249
                            $modified += UpdateMarcWith( $marcitem, $localmarcitem );
252
                        my $modified = 0;
250
                            if ($modified) {
253
                        for my $c ( @columns_with_regex ) {
251
                                eval {
254
                            my $regex_search = $input->param('items.'.$c.'_regex_search');
252
                                    if (
255
                            my $old_value = $item->$c;
253
                                        my $item = ModItemFromMarc(
256
254
                                            $localmarcitem,
257
                            my $value = apply_regex(
255
                                            $itemdata->{biblionumber},
258
                                {
256
                                            $itemnumber,
259
                                    search  => $regex_search,
257
                                            { skip_record_index => 1 },
260
                                    replace => $input->param(
258
                                        )
261
                                        'items' . $c . '_regex_replace'
259
                                      )
262
                                    ),
260
                                    {
263
                                    modifiers => $input->param(
261
                                        LostItem(
264
                                        'items' . $c . '_regex_modifiers'
262
                                            $itemnumber,
265
                                    ),
263
                                            'batchmod',
266
                                    value => $old_value,
264
                                            undef,
267
                                }
265
                                            { skip_record_index => 1 }
268
                            );
266
                                        ) if $item->{itemlost}
269
                            unless ( $old_value eq $value ) {
267
                                          and not $itemdata->{itemlost};
270
                                $modified++;
268
                                    }
271
                                $item->$c($value);
269
                                };
270
                                push @$upd_biblionumbers, $itemdata->{'biblionumber'};
271
                            }
272
                            }
272
                        }
273
                        }
274
275
                        $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?
276
                        if ( $modified) {
277
                            my $itemlost_pre = $item->itemlost;
278
                            $item->set($new_item_data)->store({skip_record_index => 1});
279
280
                            push @$upd_biblionumbers, $itemdata->{'biblionumber'};
281
282
                            LostItem(
283
                                $item->itemnumber, 'batchmod', undef,
284
                                { skip_record_index => 1 }
285
                            ) if $item->itemlost
286
                                  and not $itemlost_pre;
287
                        }
288
273
                        $modified_items++ if $modified || $modified_holds_priority;
289
                        $modified_items++ if $modified || $modified_holds_priority;
274
                        $modified_fields += $modified + $modified_holds_priority;
290
                        $modified_fields += $modified + $modified_holds_priority;
275
                    }
291
                    }
276
                    $i++;
277
                }
278
                if (@not_deleted) {
279
                    Koha::Exceptions::Exception->throw(
280
                        'Some items have not been deleted, rolling back');
281
                }
292
                }
282
            }
293
            );
283
        );
284
    }
285
    catch {
286
        if ( $_->isa('Koha::Exceptions::Exception') ) {
287
            $template->param( deletion_failed => 1 );
288
        }
294
        }
289
        die "Something terrible has happened!"
295
        catch {
290
            if ($_ =~ /Rollback failed/); # Rollback failed
296
            warn $_;
291
    };
297
            die "Something terrible has happened!"
298
                if ($_ =~ /Rollback failed/); # Rollback failed
299
        };
300
    }
301
292
    $upd_biblionumbers = [ uniq @$upd_biblionumbers ]; # Only update each bib once
302
    $upd_biblionumbers = [ uniq @$upd_biblionumbers ]; # Only update each bib once
293
303
294
    # Don't send specialUpdate for records we are going to delete
304
    # Don't send specialUpdate for records we are going to delete
Lines 323-328 if ($op eq "action") { Link Here
323
        $template->param( "job_completed" => 1 );
333
        $template->param( "job_completed" => 1 );
324
    }
334
    }
325
335
336
326
    # Calling the template
337
    # Calling the template
327
    $template->param(
338
    $template->param(
328
        modified_items => $modified_items,
339
        modified_items => $modified_items,
Lines 591-593 sub UpdateMarcWith { Link Here
591
    }
602
    }
592
    return $modified;
603
    return $modified;
593
}
604
}
594
- 
605
606
sub apply_regex {
607
    my ($params) = @_;
608
    my $search   = $params->{search};
609
    my $replace  = $params->{replace};
610
    my $modifiers = $params->{modifiers} || [];
611
    my $value = $params->{value};
612
613
    my @available_modifiers = qw( i g );
614
    my $retained_modifiers  = q||;
615
    for my $modifier ( split //, @$modifiers ) {
616
        $retained_modifiers .= $modifier
617
          if grep { /$modifier/ } @available_modifiers;
618
    }
619
    if ( $retained_modifiers =~ m/^(ig|gi)$/ ) {
620
        $value =~ s/$search/$replace/ig;
621
    }
622
    elsif ( $retained_modifiers eq 'i' ) {
623
        $value =~ s/$search/$replace/i;
624
    }
625
    elsif ( $retained_modifiers eq 'g' ) {
626
        $value =~ s/$search/$replace/g;
627
    }
628
    else {
629
        $value =~ s/$search/$replace/;
630
    }
631
632
    return $value;
633
}

Return to bug 28445