From 3e4f0333559a13bd21db8f74f38ffbd59a90b33d Mon Sep 17 00:00:00 2001 From: Jonathan Druart Date: Thu, 12 Dec 2013 21:13:53 +0100 Subject: [PATCH] Bug 11395: Add a batch record modification This patch offers a new tool to modify records in a batch. This feature adds: - a new pl/tt files tools/batch_record_modification - a new permission: tools > records_batchmod Test plan for biblios: 0/ Create a new marc modification template with some actions. 1/ Generate a list of biblionumbers you want to modify. There are two ways to generate a list of biblionumbers: - using the basket: do a search, add some biblio to your basket, open the basket and click on the "Action" button > "Modify" - generating a list from a report 2/ On the "Batch record modification" tool verify: - information is correct. - the preview link show you the needed record. 3/ After clicking on the "Modify selected recors" button, verify the records have been modified as you wanted. Test plan for authority: 0/ Create a new marc modification template with some actions. 1/ Generate a list of authid using a report: 2/ On the "Batch record modification" tool verify: - authorities are display with the summary. - the preview link show you the needed record. 3/ After clicking on the "Modify selected recors" button, verify the records have been modified as you wanted. Catch of errors: if an error occurs during the modification process, the tool displays an error message. --- .../en/modules/tools/batch_record_modification.tt | 237 +++++++++++++++++++ tools/batch_record_modification.pl | 261 +++++++++++++++++++++ 2 files changed, 498 insertions(+) create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/tools/batch_record_modification.tt create mode 100755 tools/batch_record_modification.pl diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/batch_record_modification.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/batch_record_modification.tt new file mode 100644 index 0000000..2ce3481 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/batch_record_modification.tt @@ -0,0 +1,237 @@ +[% PROCESS 'authorities-search-results.inc' %] +[% INCLUDE 'doc-head-open.inc' %] +Koha › Tools › Batch record modification +[% INCLUDE 'doc-head-close.inc' %] +[% INCLUDE 'greybox.inc' %] + +[% INCLUDE 'datatables.inc' %] + + + + + +[% INCLUDE 'header.inc' %] +[% INCLUDE 'cat-search.inc' %] + + + +
+
+
+
+

Batch record modification

+ [% FOREACH message IN messages %] + [% IF message.type == 'success' %] +
+ [% ELSIF message.type == 'warning' %] +
+ [% ELSIF message.type == 'error' %] +
+ [% END %] + [% biblio.title %] + [% IF message.code == 'no_action_defined_for_the_template' %] + The selected template (id=[% message.mmtid%]) does not exist or no action is defined. + [% ELSIF message.code == 'biblio_not_exists' %] + The biblionumber [% message.biblionumber %] does not exist in the database. + [% ELSIF message.code == 'authority_not_exists' %] + The authority id [% message.authid %] does not exist in the database. + [% ELSIF message.code == 'biblio_not_modified' %] + The biblio [% message.biblionumber %] has not been modified. An error occurred on modifying it. + [% ELSIF message.code == 'authority_not_modified' %] + The authority [% message.authid %] has not been modified. An error occurred on modifying it. + [% ELSIF message.code == 'biblio_modified' %] + The biblio [% message.biblionumber %] has successfully been modified. + [% ELSIF message.code == 'authority_modified' %] + The authority [% message.authid %] has successfully been modified. + [% END %] + [% IF message.error %] + (The error was: [% message.error%], see the Koha logfile for more information). + [% END %] +
+ [% END %] + [% IF view == 'form' %] +
+
+ Record type +
    +
  1. +
  2. +
+
+
+ Use a file +
    +
  1. +
+
+
+ Or enter a list of record numbers +
    +
  1. + + +
  2. +
+
+
+ Use MARC Modification Template: +
    +
  1. + + +
  2. +
+
+
+ + + Cancel +
+
+ [% ELSIF view == 'list' %] + [% IF records %] + [% IF recordtype == 'biblio' %] + +
+ + + + + + + + + + + [% FOR biblio IN records %] + + + + + + [% END %] + +
BiblionumberTitlePreview
[% biblio.biblionumber %][% biblio.title %]Preview MARC + +
+
Reminder: this action will modify all selected biblios!
+ [% ELSE %] + + + + + + + + + + + + + [% FOR authority IN records %] + + + + + + [% END %] + +
AuthidSummaryPreview
[% authority.authid %][% PROCESS authresult summary=authority.summary %]Preview MARC +
+
Reminder: this action will modify all selected authorities!
+ [% END %] +
+ + + + + + + Cancel +
+
+
Job progress:
0%
+
+
+
+ [% ELSE %] + There is no record ids defined. + [% END %] + [% ELSIF view == 'report' %] + [% IF report.total_records == report.total_success %] + All records have successfully been modified! + [% ELSE %] + [% report.total_success %] / [% report.total_records %] records have successfully been modified. + Some errors occurred. + [% END %] +

New batch record modification

+ [% ELSIF view == 'errors' %] + [% FOR error IN errors %] + [% IF error == 'no_template_defined' %] + No MARC modification template is defined. You have to create at least one template for using this tool. + [% END %] + [% END %] + [% ELSE %] + No action defined for the template. + [% END %] +
+
+
+ [% INCLUDE 'tools-menu.inc' %] +
+
+[% INCLUDE 'intranet-bottom.inc' %] diff --git a/tools/batch_record_modification.pl b/tools/batch_record_modification.pl new file mode 100755 index 0000000..bec2f9e --- /dev/null +++ b/tools/batch_record_modification.pl @@ -0,0 +1,261 @@ +#!/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 +# + +use Modern::Perl; + +use CGI; +use List::MoreUtils qw( uniq ); + +use C4::Auth qw( get_template_and_user ); +use C4::Output qw( output_html_with_http_headers ); +use C4::AuthoritiesMarc qw( BuildSummary GetAuthTypeCode ModAuthority ); +use C4::BackgroundJob; +use C4::Biblio qw( GetMarcBiblio ModBiblio ); +use C4::MarcModificationTemplates qw( GetModificationTemplateActions GetModificationTemplates ModifyRecordWithTemplate ); +use Koha::Authority; + +my $input = new CGI; +our $dbh = C4::Context->dbh; +my $op = $input->param('op') // q|form|; +my $recordtype = $input->param('recordtype') // 'biblio'; +my $mmtid = $input->param('marc_modification_template_id'); + +my ( @messages ); + +my ( $template, $loggedinuser, $cookie ) = get_template_and_user({ + template_name => 'tools/batch_record_modification.tt', + query => $input, + type => "intranet", + authnotrequired => 0, + flagsrequired => { tools => 'biblio_batchmod' }, +}); + + +my $sessionID = $input->cookie("CGISESSID"); + +my $runinbackground = $input->param('runinbackground'); +my $completedJobID = $input->param('completedJobID'); +if ( $completedJobID ) { + my $job = C4::BackgroundJob->fetch($sessionID, $completedJobID); + my $report = $job->get('report'); + my $messages = $job->get('messages'); + $template->param( + report => $report, + messages => $messages, + view => 'report', + ); + output_html_with_http_headers $input, $cookie, $template->output; + exit; +} + +my @templates = GetModificationTemplates(); +unless ( @templates ) { + $op = 'error'; + $template->param( + view => 'errors', + errors => ['no_template_defined'], + ); + output_html_with_http_headers $input, $cookie, $template->output; +} + +if ( $mmtid ) { + my @actions = GetModificationTemplateActions( $mmtid ); + unless ( @actions ) { + $op = 'form'; + push @messages, { + type => 'error', + code => 'no_action_defined_for_the_template', + mmtid => $mmtid, + }; + } +} + +if ( $op eq 'form' ) { + # Display the form + $template->param( + view => 'form', + MarcModificationTemplatesLoop => \@templates, + ); +} elsif ( $op eq 'list' ) { + # List all records to process + my ( @records, @record_ids ); + if ( my $bib_list = $input->param('bib_list') ) { + # Come from the basket + @record_ids = split /\//, $bib_list; + $recordtype = 'biblio'; + } elsif ( my $uploadfile = $input->param('uploadfile') ) { + # A file of id is given + while ( my $content = <$uploadfile> ) { + next unless $content; + $content =~ s/[\r\n]*$//; + push @record_ids, $content if $content; + } + } else { + # The user enters manually the list of id + push @record_ids, split( /\s\n/, $input->param('recordnumber_list') ); + } + + for my $record_id ( uniq @record_ids ) { + if ( $recordtype eq 'biblio' ) { + # Retrieve biblio information + my $biblio = C4::Biblio::GetBiblio( $record_id ); + unless ( $biblio ) { + push @messages, { + type => 'warning', + code => 'biblio_not_exists', + biblionumber => $record_id, + }; + next; + } + push @records, $biblio; + } else { + # Retrieve authority information + my $authority = Koha::Authority->get_from_authid( $record_id ); + unless ( $authority ) { + push @messages, { + type => 'warning', + code => 'authority_not_exists', + authid => $record_id, + }; + next; + } + + push @records, { + authid => $record_id, + summary => C4::AuthoritiesMarc::BuildSummary( $authority->record, $record_id ), + }; + } + } + $template->param( + records => \@records, + mmtid => $mmtid, + view => 'list', + ); +} elsif ( $op eq 'modify' ) { + # We want to modify selected records! + my @record_ids = $input->param('record_id'); + + my ( $job ); + if ( $runinbackground ) { + my $job_size = scalar( @record_ids ); + $job = C4::BackgroundJob->new( $sessionID, "FIXME", $ENV{SCRIPT_NAME}, $job_size ); + my $job_id = $job->id; + if (my $pid = fork) { + $dbh->{InactiveDestroy} = 1; + + my $reply = CGI->new(""); + print $reply->header(-type => 'text/html'); + print '{"jobID":"' . $job_id . '"}'; + exit 0; + } elsif (defined $pid) { + close STDOUT; + close STDERR; + } else { + warn "fork failed while attempting to run $ENV{'SCRIPT_NAME'} as a background job"; + exit 0; + } + } + + my $report = { + total_records => 0, + total_success => 0, + }; + my $progress = 0; + $dbh->{RaiseError} = 1; + RECORD_IDS: for my $record_id ( sort { $a <=> $b } @record_ids ) { + $report->{total_records}++; + next unless $record_id; + + if ( $recordtype eq 'biblio' ) { + # Biblios + my $biblionumber = $record_id; + + # Finally, modify the biblio + my $error = eval { + my $record = GetMarcBiblio( $biblionumber ); + ModifyRecordWithTemplate( $mmtid, $record ); + ModBiblio( $record, $biblionumber ); + }; + if ( $error and $error != 1 or $@ ) { # ModBiblio returns 1 if everything as gone well + push @messages, { + type => 'error', + code => 'biblio_not_modified', + biblionumber => $biblionumber, + error => ($@ ? $@ : $error), + }; + } else { + push @messages, { + type => 'success', + code => 'biblio_modified', + biblionumber => $biblionumber, + }; + $report->{total_success}++; + } + } else { + # Authorities + my $authid = $record_id; + my $error = eval { + my $authority = Koha::Authority->get_from_authid( $authid ); + my $record = $authority->record; + ModifyRecordWithTemplate( $mmtid, $record ); + ModAuthority( $authid, $record, GetAuthTypeCode( $authid ) ); + }; + if ( $error and $error != $authid or $@ ) { + push @messages, { + type => 'error', + code => 'authority_not_modified', + authid => $authid, + error => ($@ ? $@ : 0), + }; + } else { + push @messages, { + type => 'success', + code => 'authority_modified', + authid => $authid, + }; + $report->{total_success}++; + } + } + + $job->set({ + view => 'report', + report => $report, + messages => \@messages, + }); + $job->progress( ++$progress ) if $runinbackground; + } + + if ($runinbackground) { + $job->finish if defined $job; + } else { + $template->param( + view => 'report', + report => $report, + messages => \@messages, + ); + } +} + +$template->param( + messages => \@messages, + recordtype => $recordtype, +); + +output_html_with_http_headers $input, $cookie, $template->output; -- 2.0.0.rc2