diff --git a/C4/Items.pm b/C4/Items.pm index 26e9342a6b..51479ecfeb 100644 --- a/C4/Items.pm +++ b/C4/Items.pm @@ -35,6 +35,7 @@ use DateTime::Format::MySQL; use Data::Dumper; # used as part of logging item record changes, not just for # debugging; so please don't remove this use Koha::DateUtils qw/dt_from_string/; +use Koha::Database; use Koha::Database; @@ -473,6 +474,7 @@ sub _build_default_values_for_mod_marc { location => undef, permanent_location => undef, materials => undef, + new => undef, notforloan => 0, # paidfor => undef, # commented, see bug 12817 price => undef, @@ -2198,7 +2200,8 @@ sub _koha_new_item { enumchron = ?, more_subfields_xml = ?, copynumber = ?, - stocknumber = ? + stocknumber = ?, + new = ? "; my $sth = $dbh->prepare($query); my $today = output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 }); @@ -2242,6 +2245,7 @@ sub _koha_new_item { $item->{'more_subfields_xml'}, $item->{'copynumber'}, $item->{'stocknumber'}, + $item->{'new'}, ); my $itemnumber; @@ -3135,4 +3139,94 @@ sub PrepareItemrecordDisplay { }; } +=head2 columns + + my @columns = C4::Items::columns(); + +Returns an array of items' table columns on success, +and an empty array on failure. + +=cut + +sub columns { + my $rs = Koha::Database->new->schema->resultset('Item'); + return $rs->result_source->columns; +} + +=head2 biblioitems_columns + + my @columns = C4::Items::biblioitems_columns(); + +Returns an array of biblioitems' table columns on success, +and an empty array on failure. + +=cut + +sub biblioitems_columns { + my $rs = Koha::Database->new->schema->resultset('Biblioitem'); + return $rs->result_source->columns; +} + +sub ToggleNewStatus { + my ( $params ) = @_; + my @rules = @{ $params->{rules} }; + my $report_only = $params->{report_only}; + + my $dbh = C4::Context->dbh; + my @errors; + my @item_columns = map { "items.$_" } C4::Items::columns; + my @biblioitem_columns = map { "biblioitems.$_" } C4::Items::biblioitems_columns; + my $report; + for my $rule ( @rules ) { + my $age = $rule->{age}; + my $conditions = $rule->{conditions}; + my $substitutions = $rule->{substitutions}; + my @params; + + my $query = q| + SELECT items.biblionumber, items.itemnumber + FROM items + LEFT JOIN biblioitems ON biblioitems.biblionumber = items.biblionumber + WHERE 1 + |; + for my $condition ( @$conditions ) { + if ( + grep {/^$condition->{field}$/} @item_columns + or grep {/^$condition->{field}$/} @biblioitem_columns + ) { + if ( $condition->{value} =~ /\|/ ) { + my @values = split /\|/, $condition->{value}; + $query .= qq| AND $condition->{field} IN (| + . join( ',', ('?') x scalar @values ) + . q|)|; + push @params, @values; + } else { + $query .= qq| AND $condition->{field} = ?|; + push @params, $condition->{value}; + } + } + } + if ( defined $age ) { + $query .= q| AND TO_DAYS(NOW()) - TO_DAYS(dateaccessioned) >= ? |; + push @params, $age; + } + my $sth = $dbh->prepare($query); + $sth->execute( @params ); + while ( my $values = $sth->fetchrow_hashref ) { + my $biblionumber = $values->{biblionumber}; + my $itemnumber = $values->{itemnumber}; + my $item = C4::Items::GetItem( $itemnumber ); + for my $substitution ( @$substitutions ) { + next unless $substitution->{field}; + C4::Items::ModItem( {$substitution->{field} => $substitution->{value}}, $biblionumber, $itemnumber ) + unless $report_only; + push @{ $report->{$itemnumber} }, $substitution; + } + } + } + + return $report; +} + + 1; diff --git a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css b/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css index b8a857d47c..23283048d2 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css +++ b/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css @@ -2815,6 +2815,7 @@ span.onsite_checkout { border-radius: 4px; border : 1px solid #FFF2CE; } + div.lastchecked { padding : .2em 1em; border: 2px solid #BCDB89; @@ -2845,3 +2846,32 @@ div#cn_browser_table_wrapper > table#cn_browser_table { margin: auto; width:90%; } + +/* Tools > automatic_item_modification_by_age */ +div.rules { + display: block; +} +div#new_rule, div.rule { + background-color: #F4F8F9; + border: 2px solid #B9D8D9; + border-radius: 5px; + margin: .3em; + padding: .3em; +} + +div.duration, div.blocks { + border: 2px solid #B9D8D9; + border-radius: 5px 5px 5px 5px; + margin: .3em; + padding: 0 .3em .3em .3em; +} + +div.duration h5, div.blocks h5 { + padding-bottom: 4px; + padding-left: 0.2em; + background-color: #E6F0F2; + border-radius: 1px; +} +div.duration span, div.blocks div { + display:block; +} diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/help/tools/automatic_item_modification_by_age.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/help/tools/automatic_item_modification_by_age.tt new file mode 100644 index 0000000000..8fdda1ba4e --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/help/tools/automatic_item_modification_by_age.tt @@ -0,0 +1,45 @@ +[% INCLUDE 'help-top.inc' %] +

Automatic item modifications by age configuration

+ +

This configuration page allows to configure the rules for the automatic item modifications by age cronjob script.

+ +

Libraries can manage the 'new' status for items. With this script, it will be possible to:

+

+ +

How to work the configuration page?

+

There are 3 values to define:

+

The duration

+

This value corresponds to the duration an item is considered as new.

+

The conditions

+

Conditions should be defined if you want to test some values before to substitute fields in the items.

+

They are cumulatives but you can separate with a pipe '|' for a field with several values.

+

The substitutions

+

Substitutions are changes to apply to the matching items.

+

At least one substitution must be defined, else there is no sense to launch the script.

+

If the value is an empty string, the field will be deleted.

+

Examples

+

You want to remove the items.new value for items created 10 days ago:

+ + +

You want to change the items.ccode=1 to items.ccode=2 for items created 7 days ago. +

+ +

How to execute the cronjob script?

+

The cronjob script is misc/cronjobs/automatic_item_modification_by_age.pl.

+

Try the -h parameter in order to see the help.

+

Without any parameter, the script will be launched in a dry-run mode. If the -c (or --confirm) flag is given, the script will apply the changes.

+ +[% INCLUDE 'help-bottom.inc' %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/automatic_item_modification_by_age.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/automatic_item_modification_by_age.tt new file mode 100644 index 0000000000..a08e96d022 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/automatic_item_modification_by_age.tt @@ -0,0 +1,294 @@ +[% INCLUDE 'doc-head-open.inc' %] +Koha › Tools › Automatic item modifications by age +[% INCLUDE 'doc-head-close.inc' %] + + + +[% INCLUDE 'header.inc' %] +[% INCLUDE 'cat-search.inc' %] + + +
+
+
+
+

Automatic item modifications by age

+
+ Edit +
+ [% FOR message IN messages %] + [% IF message.type == "error" %] +
+ [% END %] + [% IF message.code == "unable_to_load_configuration" %] + An error occurs: Unable to load the configuration. + [% END %] +
+ [% END %] + + [% IF op == 'edit_form' %] +
+
+

List of rules

+
+ [% FOR rule IN rules %] + [% SET id = loop.count %] +
+ +
+
Age
+ days +
+
+
Conditions
+ [% FOR condition IN rule.conditions %] +
+ + = + + + +
+ [% END %] +
+
+
Substitutions
+ [% FOR substitution IN rule.substitutions %] +
+ + = + + + +
+ [% END %] +
+ Remove this rule +
+ [% END %] +
+
+ There is no rule defined. +
+
+ + Cancel + +
+
+
+

Add a new rule

+
+ +
+
Age
+ days +
+
+
Conditions
+
+ + = + + + +
+
+
+
Substitutions
+
+ + = + + + +
+
+ Add this rule + Remove this rule +
+ [% ELSIF rules and op == 'show' %] +
+

List of rules

+ [% FOR rule IN rules %] +
+
+
Age
+ [% IF rule.age.defined and rule.age.length > 0 %] + [% rule.age %] days + [% ELSE %] + There is no age for this rule. + [% END %] +
+
+
Conditions
+ [% FOR condition IN rule.conditions %] + [% IF condition.field %] +
+ [% condition.field %] = [% condition.value %] +
+ [% ELSE %] + There is no condition for this rule. + [% END %] + [% END %] +
+
+
Substitutions
+ [% FOR substitution IN rule.substitutions %] +
+ [% substitution.field %] = [% substitution.value %] +
+ [% END %] +
+
+ [% END %] +
+ [% ELSE %] + There is no rule defined. Please click on the edit button. + [% END %] + +
+
+
+ [% INCLUDE 'tools-menu.inc' %] +
+
+[% INCLUDE 'intranet-bottom.inc' %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt index 629ce84726..bb54f54642 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt @@ -129,6 +129,11 @@
Modify a batch of records (biblios or authorities)
[% END %] + [% IF ( CAN_user_tools_items_batchmod ) %] +
Automatic item modifications by age
+
Define rules to modify items by age
+ [% END %] + [% IF ( CAN_user_tools_export_catalog ) %]
Export data
Export bibliographic, holdings, and authority records
diff --git a/misc/cronjobs/automatic_item_modification_by_age.pl b/misc/cronjobs/automatic_item_modification_by_age.pl new file mode 100755 index 0000000000..51effd32b1 --- /dev/null +++ b/misc/cronjobs/automatic_item_modification_by_age.pl @@ -0,0 +1,106 @@ +#!/usr/bin/perl + +use Modern::Perl; + +use Getopt::Long; +use Pod::Usage; +use JSON; + +use C4::Context; +use C4::Items; + +# Getting options +my ( $verbose, $help, $confirm ); +my $result = GetOptions( + 'h|help' => \$help, + 'v|verbose' => \$verbose, + 'c|confirm' => \$confirm, +); + +pod2usage(1) if $help; +$verbose = 1 unless $confirm; + +# Load configuration from the syspref +my $syspref_content = C4::Context->preference('automatic_item_modification_by_age_configuration'); +my $rules = eval { JSON::from_json( $syspref_content ) }; +pod2usage({ -message => "Unable to load the configuration : $@", -exitval => 1 }) + if $@; + +my $report = C4::Items::ToggleNewStatus( { rules => $rules, report_only => not $confirm } ); + +if ( $verbose ) { + if ( $report ) { + say "Item to modify:"; + while ( my ( $itemnumber, $substitutions ) = each %$report ) { + for my $substitution ( @$substitutions ) { + if ( defined $substitution->{value} and $substitution->{value} ne q|| ) { + say "\titemnumber $itemnumber: $substitution->{field}=$substitution->{value}"; + } else { + say "\titemnumber $itemnumber: field $substitution->{field} to delete"; + } + } + } + } else { + say "There is no item to modify"; + } +} + +exit(0); + +__END__ + +=head1 NAME + +automatic_item_modification_by_age.pl + +=head1 SYNOPSIS + +./automatic_item_modification_by_age.pl -h + +Toggle recent acquisitions status. +Use this script to delete "new" status for items. + +=head1 OPTIONS + +=over 8 + +=item B<-h|--help> + +Prints this help message. + +=item B<-v|--verbose> + +Set the verbose flag. + +=item B<-c|--confirm> + +The script will modify the items. + +=back + +=head1 AUTHOR + +Jonathan Druart + +=head1 COPYRIGHT + +Copyright 2013 BibLibre + +=head1 LICENSE + +This file is part of Koha. + +Koha is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +Koha is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Koha; if not, see . + +=cut diff --git a/t/db_dependent/Items/AutomaticItemModificationByAge.t b/t/db_dependent/Items/AutomaticItemModificationByAge.t new file mode 100644 index 0000000000..3f2943c942 --- /dev/null +++ b/t/db_dependent/Items/AutomaticItemModificationByAge.t @@ -0,0 +1,283 @@ +#!/usr/bin/perl + +use Modern::Perl; +use Test::More tests => 16; +use MARC::Record; +use MARC::Field; +use DateTime; +use DateTime::Duration; + +use C4::Biblio; +use C4::Context; +use C4::Items; +use Koha::DateUtils; + +my $dbh = C4::Context->dbh; +$dbh->{AutoCommit} = 0; +$dbh->{RaiseError} = 1; + +$dbh->do(q| + DELETE FROM marc_subfield_structure + WHERE kohafield = 'items.new' OR kohafield = 'items.stocknumber' +|); + +my $new_tagfield = 'i'; +$dbh->do(qq| + INSERT INTO marc_subfield_structure(tagfield, tagsubfield, kohafield, frameworkcode) + VALUES ( 952, '$new_tagfield', 'items.new', '' ) +|); + +my $record = MARC::Record->new(); +$record->append_fields( + MARC::Field->new('100', ' ', ' ', a => 'Moffat, Steven'), + MARC::Field->new('245', ' ', ' ', a => 'Silence in the library'), + MARC::Field->new('942', ' ', ' ', c => 'ITEMTYPE_T'), +); +my ($biblionumber, undef) = C4::Biblio::AddBiblio($record, ''); + +my ($item_bibnum, $item_bibitemnum, $itemnumber) = C4::Items::AddItem( + { + homebranch => 'CPL', + holdingbranch => 'CPL', + new => 'new_value', + ccode => 'FIC', + }, + $biblionumber +); + +my $item = C4::Items::GetItem( $itemnumber ); +is ( $item->{new}, 'new_value', q|AddItem insert the 'new' field| ); + +my ( $tagfield, undef ) = GetMarcFromKohaField('items.itemnumber', ''); +my $marc_item = C4::Items::GetMarcItem( $biblionumber, $itemnumber ); +is( $marc_item->subfield($tagfield, $new_tagfield), 'new_value', q|Koha mapping is correct|); + +# Update the items.new field if items.ccode eq 'FIC' => should be updated +my @rules = ( + { + conditions => [ + { + field => 'items.ccode', + value => 'FIC', + }, + ], + substitutions => [ + { + field => 'items.new', + value => 'updated_value', + }, + ], + age => '0', + }, +); + +C4::Items::ToggleNewStatus( { rules => \@rules } ); + +my $modified_item = C4::Items::GetItem( $itemnumber ); +is( $modified_item->{new}, 'updated_value', q|ToggleNewStatus: The new value is updated|); +$marc_item = C4::Items::GetMarcItem( $biblionumber, $itemnumber ); +is( $marc_item->subfield($tagfield, $new_tagfield), 'updated_value', q|ToggleNewStatus: The new value is updated| ); + +# Update the items.new field if items.ccode eq 'DONT_EXIST' => should not be updated +@rules = ( + { + conditions => [ + { + field => 'items.ccode', + value => 'DONT_EXIST', + }, + ], + substitutions => [ + { + field => 'items.new', + value => 'new_updated_value', + }, + ], + age => '0', + }, +); + +C4::Items::ToggleNewStatus( { rules => \@rules } ); + +$modified_item = C4::Items::GetItem( $itemnumber ); +is( $modified_item->{new}, 'updated_value', q|ToggleNewStatus: The new value is not updated|); +$marc_item = C4::Items::GetMarcItem( $biblionumber, $itemnumber ); +is( $marc_item->subfield($tagfield, $new_tagfield), 'updated_value', q|ToggleNewStatus: The new value is not updated| ); + +# Play with age +$item = C4::Items::GetItem( $itemnumber ); +my $dt_today = dt_from_string; +my $days5ago = $dt_today->add_duration( DateTime::Duration->new( days => -5 ) ); + +C4::Items::ModItem( { dateaccessioned => $days5ago }, $biblionumber, $itemnumber ); +$item = C4::Items::GetItem( $itemnumber ); + +@rules = ( + { + conditions => [ + { + field => 'items.ccode', + value => 'FIC', + }, + ], + substitutions => [ + { + field => 'items.new', + value => 'new_updated_value', + }, + ], + age => '10', + }, +); +C4::Items::ToggleNewStatus( { rules => \@rules } ); +$modified_item = C4::Items::GetItem( $itemnumber ); +is( $modified_item->{new}, 'updated_value', q|ToggleNewStatus: Age = 10 : The new value is not updated|); + +$rules[0]->{age} = 5; +$rules[0]->{substitutions}[0]{value} = 'new_updated_value5'; +C4::Items::ToggleNewStatus( { rules => \@rules } ); +$modified_item = C4::Items::GetItem( $itemnumber ); +is( $modified_item->{new}, 'new_updated_value5', q|ToggleNewStatus: Age = 5 : The new value is updated|); + +$rules[0]->{age} = ''; +$rules[0]->{substitutions}[0]{value} = 'new_updated_value_empty_string'; +C4::Items::ToggleNewStatus( { rules => \@rules } ); +$modified_item = C4::Items::GetItem( $itemnumber ); +is( $modified_item->{new}, 'new_updated_value_empty_string', q|ToggleNewStatus: Age = '' : The new value is updated|); + +$rules[0]->{age} = undef; +$rules[0]->{substitutions}[0]{value} = 'new_updated_value_undef'; +C4::Items::ToggleNewStatus( { rules => \@rules } ); +$modified_item = C4::Items::GetItem( $itemnumber ); +is( $modified_item->{new}, 'new_updated_value_undef', q|ToggleNewStatus: Age = undef : The new value is updated|); + +# Field deletion +@rules = ( + { + conditions => [ + { + field => 'items.ccode', + value => 'FIC', + }, + ], + substitutions => [ + { + field => 'items.new', + value => '', + }, + ], + age => '0', + }, +); + +C4::Items::ToggleNewStatus( { rules => \@rules } ); + +$modified_item = C4::Items::GetItem( $itemnumber ); +is( $modified_item->{new}, '', q|ToggleNewStatus: The new value is empty|); +$marc_item = C4::Items::GetMarcItem( $biblionumber, $itemnumber ); +is( $marc_item->subfield($tagfield, $new_tagfield), undef, q|ToggleNewStatus: The new field is removed from the item marc| ); + +# conditions multiple +@rules = ( + { + conditions => [ + { + field => 'items.ccode', + value => 'FIC', + }, + { + field => 'items.homebranch', + value => 'CPL', + }, + ], + substitutions => [ + { + field => 'items.new', + value => 'new_value', + }, + ], + age => '0', + }, +); + +C4::Items::ToggleNewStatus( { rules => \@rules } ); + +$modified_item = C4::Items::GetItem( $itemnumber ); +is( $modified_item->{new}, 'new_value', q|ToggleNewStatus: conditions multiple: all match, the new value is updated|); + +@rules = ( + { + conditions => [ + { + field => 'items.ccode', + value => 'FIC', + }, + { + field => 'items.homebranch', + value => 'DONT_EXIST', + }, + ], + substitutions => [ + { + field => 'items.new', + value => 'new_updated_value', + }, + ], + age => '0', + }, +); + +C4::Items::ToggleNewStatus( { rules => \@rules } ); + +$modified_item = C4::Items::GetItem( $itemnumber ); +is( $modified_item->{new}, 'new_value', q|ToggleNewStatus: conditions multiple: at least 1 condition does not match, the new value is not updated|); + +@rules = ( + { + conditions => [ + { + field => 'items.ccode', + value => 'FIC|NFIC', + }, + { + field => 'items.homebranch', + value => 'MPL|CPL', + }, + ], + substitutions => [ + { + field => 'items.new', + value => 'new_updated_value', + }, + ], + age => '0', + }, +); + +C4::Items::ToggleNewStatus( { rules => \@rules } ); + +$modified_item = C4::Items::GetItem( $itemnumber ); +is( $modified_item->{new}, 'new_updated_value', q|ToggleNewStatus: conditions multiple: the 2 conditions match, the new value is updated|); + +@rules = ( + { + conditions => [ + { + field => 'biblioitems.itemtype', + value => 'ITEMTYPE_T', + }, + ], + substitutions => [ + { + field => 'items.new', + value => 'another_new_updated_value', + }, + ], + age => '0', + }, +); + +C4::Items::ToggleNewStatus( { rules => \@rules } ); + +$modified_item = C4::Items::GetItem( $itemnumber ); +is( $modified_item->{new}, 'another_new_updated_value', q|ToggleNewStatus: conditions on biblioitems|); diff --git a/tools/automatic_item_modification_by_age.pl b/tools/automatic_item_modification_by_age.pl new file mode 100755 index 0000000000..eca339cb39 --- /dev/null +++ b/tools/automatic_item_modification_by_age.pl @@ -0,0 +1,119 @@ +#!/usr/bin/perl + +# This file is part of Koha. +# +# Copyright 2013 BibLibre +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +=head1 NAME + +automatic_item_modification_by_age.pl: Update new status for items. + +=cut + +=head1 DESCRIPTION + +This script allows a user to update the new status for items. + +=cut + +use Modern::Perl; + +use CGI; +use JSON qw( to_json from_json ); + +use C4::Auth; +use C4::Context; +use C4::Items; +use C4::Output; +use C4::Koha; + +my $cgi = new CGI; + +# open template +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( + { + template_name => "tools/automatic_item_modification_by_age.tt", + query => $cgi, + type => "intranet", + authnotrequired => 0, + flagsrequired => { tools => 'items_batchmod' }, + } +); + +my $op = $cgi->param('op') // 'show'; + +my $syspref_name = q|automatic_item_modification_by_age_configuration|; +if ( $op eq 'update' ) { + my @rules; + my @unique_ids = $cgi->param('unique_id'); + for my $unique_id ( @unique_ids ) { + my @substitution_fields = $cgi->param("substitution_field_$unique_id"); + my @substitution_values = $cgi->param("substitution_value_$unique_id"); + my @condition_fields = $cgi->param("condition_field_$unique_id"); + my @condition_values = $cgi->param("condition_value_$unique_id"); + my $rule = { + substitutions => [], + conditions => [], + }; + for my $value ( @substitution_values ) { + my $field = shift @substitution_fields; + last unless $field; + push @{ $rule->{substitutions} }, { field => $field, value => $value }; + } + push @{ $rule->{substitutions} }, {} + unless @{ $rule->{substitutions} }; + for my $value ( @condition_values ) { + my $field = shift @condition_fields; + last unless $field; + push @{ $rule->{conditions} }, { field => $field, value => $value }; + } + push @{ $rule->{conditions} }, {} + unless @{ $rule->{conditions} }; + $rule->{age} = $cgi->param("age_$unique_id"); + push @rules, $rule; + } + my $syspref_content = to_json( \@rules ); + C4::Context->set_preference($syspref_name, $syspref_content); + + $op = 'show'; +} + +my @messages; +my $syspref_content = C4::Context->preference($syspref_name); +my $rules; +$rules = eval { JSON::from_json( $syspref_content ) } + if $syspref_content; +if ( $@ ) { + push @messages, { + type => 'error', + code => 'unable_to_load_configuration' + }; + $template->param( messages => \@messages ); + output_html_with_http_headers $cgi, $cookie, $template->output; + exit; +} + +my @item_fields = map { "items.$_" } C4::Items::columns; +my @biblioitem_fields = map { "biblioitems.$_" } C4::Items::biblioitems_columns; +$template->param( + op => $op, + messages => \@messages, + condition_fields => [ @item_fields, @biblioitem_fields ], + substitution_fields => \@item_fields, + rules => $rules, +); + +output_html_with_http_headers $cgi, $cookie, $template->output;