From 2c5f17d7b25d17a3f142534105dc00111b971303 Mon Sep 17 00:00:00 2001 From: Paul Poulain Date: Mon, 25 Jul 2011 10:25:52 +0200 Subject: [PATCH] Bug 5725 : Batch Modifications for Biblios Squashed commit of the following: commit 66282fed94564969f0368e27c7231116a2d1c0fe Author: Chris Cormack Date: Tue Feb 22 08:43:24 2011 +1300 Bug 5725 : Follow up fixing permissions thanks to Paul Poulain commit 4d0241aea5be13b00abbc6100dc98ec87f816081 Author: Paul Poulain Date: Mon Jan 10 17:22:31 2011 +0100 Bug 5725 follow up Owen noticed the batchedit was not working. This was because we made a patch months ago to change the GetBiblio API (the 1st returned arg is useless) This patch is not in main trunk, resulting in the error owen has noticed. This patch goes back to official API (even if it is clumsy : the patch we did does not apply anymore) commit 19b3e0ecc57af1c2151340328bf06e26882b7863 Author: Paul Poulain Date: Wed Dec 15 20:47:21 2010 +0100 Bug 5725 : MT #2991 (Feature) Batch biblio modifications This patch add a new feature of batch biblio modifications, it permit to select biblios from basket, and modify fields of them setting Rebased to fix whitespace issues. --- C4/Biblio.pm | 90 +++++ koha-tmpl/intranet-tmpl/prog/en/js/basket.js | 6 + .../prog/en/modules/basket/basket.tmpl | 366 ++++++++++++++++++++ .../prog/en/modules/tools/batchedit.tt | 227 ++++++++++++ tools/batchedit.pl | 222 ++++++++++++ 5 files changed, 911 insertions(+), 0 deletions(-) create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/basket/basket.tmpl create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/tools/batchedit.tt create mode 100755 tools/batchedit.pl diff --git a/C4/Biblio.pm b/C4/Biblio.pm index a91562c..d445224 100644 --- a/C4/Biblio.pm +++ b/C4/Biblio.pm @@ -128,6 +128,7 @@ BEGIN { &TransformHtmlToXml &PrepareItemrecordDisplay &GetNoZebraIndexes + &BatchModField ); } @@ -3681,6 +3682,95 @@ sub get_biblio_authorised_values { return $authorised_values; } +=head3 BatchModField + + Mod subfields in field record + + returns 1,$record if succeed + returns 0,$record if Action was not processed + returns -1 if no record + returns -2 if no action done on record + +=cut + +sub BatchModField { + my ( $record, $field, $subfield, $action, $condval, $nocond, $repval ) = @_; + + return -1 unless $record; + $condval=NormalizeString($condval); + my $condition=qr/$condval/; + + if($action eq "add"){ + for my $rfield ($record->field($field)){ + $rfield->add_subfields( $subfield => $repval ); + } + return 1; + }elsif($action eq "addfield"){ + my $new_field = MARC::Field->new($field,'','', + $subfield => $repval); + $record->insert_fields_ordered($new_field); + return 1; + } else { + my $done=0; + for my $rfield ($record->field($field)) { + if ($subfield && $subfield ne "@"){ + my @subfields = $rfield->subfields(); + my @subfields_to_add; + foreach my $subf (@subfields) { + if ($subf->[0] eq $subfield){ + $subf->[1]=NormalizeString($subf->[1]); + if ( $action eq "mod" ) { + if ( $nocond ne "true" && $subf->[1] =~ s/$condition/$repval/) { + $done=1; + } + if ($nocond eq "true"){ + $subf->[1] = $repval; + $done=1; + } + } elsif ( $action eq "del" ) { + if ( $subf->[1] =~ m/$condition/ || $nocond eq "true" ) { + $done=1; + next; + } + } + } + push @subfields_to_add,@$subf; + } + if ($done){ + if (@subfields_to_add){ + $rfield->replace_with(MARC::Field->new($rfield->tag,$rfield->indicator(1),$rfield->indicator(2),@subfields_to_add)); + } + else { + my $count= $record->delete_field($rfield); + } + } + } + else { + if ($action eq "del"){ + my $count=$record->delete_field($rfield); + $done=1; + } + else { + if ($field < 10){ + my $value=$record->field($field)->data(); + if ($value=~ s/$condition/$repval/){ + $record->field($field)->update($value); + $done=1; + + } + if ( $nocond eq 'true'){ + $record->field($field)->update($repval); + $done=1; + } + } + } + } + } + return ($done,$record); + } + return -2; +} + 1; __END__ diff --git a/koha-tmpl/intranet-tmpl/prog/en/js/basket.js b/koha-tmpl/intranet-tmpl/prog/en/js/basket.js index 9946cf7..03dc306 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/js/basket.js +++ b/koha-tmpl/intranet-tmpl/prog/en/js/basket.js @@ -433,4 +433,10 @@ $(document).ready(function(){ if(basketcount){ updateBasket(basketcount); } }); +function batchEdit(){ + var valCookie = readCookie(nameCookie); + var strCookie = nameParam + "=" + valCookie; + var loc = CGIBIN + "tools/batchedit.pl?" + strCookie; + window.opener.location = loc; +} diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/basket/basket.tmpl b/koha-tmpl/intranet-tmpl/prog/en/modules/basket/basket.tmpl new file mode 100644 index 0000000..6699bde --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/basket/basket.tmpl @@ -0,0 +1,366 @@ + +<!-- TMPL_IF NAME="LibraryNameTitle" --><!-- TMPL_VAR NAME="LibraryNameTitle" --><!-- TMPL_ELSE -->Koha Online<!-- /TMPL_IF --> Catalog › Your Cart + + + +/includes/favicon.ico" type="image/x-icon" /> + + + + + + + + + + +
+
+ +

Your Cart

+ +
+ +
+ + + +

Select All Clear All | Selected items : + + Remove + + + | Add to a list + + + + | Place Hold + + +

+
+ +

+ + + + + + " name="bib" id="bib" onclick="selRecord(value,checked)" /> + + + + +

+ + &rft.btitle=&rft.date=&rft.tpages=&rft.isbn=&rft.aucorp=&rft.place=&rft.pub=&rft.edition=&rft.series=&rft.genre="> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ISBN
Author(s) + +

+ + + +

+ + + +

+ + +
Publisher +
Details
Collection
Subject(s) +

+ +

+
Copyright
Notes + +

-

+
Unified title
Serial
Dewey
Classification
LCCN
URL(s) + +

+
+ + +
+

Location(s) +

+ + + () + +

+ This record has no items.
+ +
+ + + +

+

+ Select All + Clear All + | Selected items : +Remove + + + | Add to a list + + + + | Place Hold + + + + +

+ + + + + + + + + + + + + + + + + + + + +
 TitleItem TypeLocation
+ " name="bib" id="bib" onclick="selRecord(value,checked);" /> + + ',)"> + + + +

- + + - + +

+ +

+ + + &rft.btitle=&rft.date=&rft.tpages=&rft.isbn=&rft.aucorp=&rft.place=&rft.pub=&rft.edition=&rft.series=&rft.genre="> + +
+

+ + + () + +

+ This record has no items.
+ + + +<< Back to Cart + +
+ +
+ + +
+
+ + diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/batchedit.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/batchedit.tt new file mode 100644 index 0000000..981e995 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/batchedit.tt @@ -0,0 +1,227 @@ +[% INCLUDE 'doc-head-open.inc' %] +Koha › Tools › Batch Deletion of Items +[% INCLUDE 'doc-head-close.inc' %] + +[% UNLESS ( modsuccess ) %] + + +[% END %] + + +[% INCLUDE 'header.inc' %] +[% INCLUDE 'cat-search.inc' %] +
+
+
+
+ +
+[% IF ( inputform ) %] +

Batch records modification

+
+ Use a file +
    +
  1. +
+
+
+ Or enter records one by one +
    +
  1. + + +
  2. +
+
+[% ELSE %] +

List of records:

+ + + + [% IF ( moddone ) %] [% END %] + + + [% FOREACH biblioinfo IN biblioinfos %] + + + + + [% IF ( biblioinfo.moddone ) %] + [% IF ( biblioinfo.OK ) %] + + [% END %] + + [% END %] +
BiblionumberTitleAuthorStatus
[% biblioinfo.biblionumber %][% biblioinfo.title %][% biblioinfo.author %] + [% ELSE %] + + [% END %] + [% IF ( biblioinfo.OK ) %]OK[% END %] + [% IF ( No_Actions ) %]Nothing done[% END %] + [% IF ( biblioinfo.Actions_Failed ) %]Some Actions failed. List Follow :
    [% FOREACH failed_action IN biblioinfo.failed_actions %]
  • [% failed_action.action %]
  • [% END %]
[% END %] +
+[% END %] + +[% IF ( moddone ) %] +
All operations processed
+[% ELSE %] +
+

Modification rules:

+ + + + + + + + + + + + + + + + + + + +
FieldSubfieldActionCondition ValueValue 
+ + + + + + + + All + + +
+ +
+
+[% END %] +
+
+
+
+ + diff --git a/tools/batchedit.pl b/tools/batchedit.pl new file mode 100755 index 0000000..0f666b1 --- /dev/null +++ b/tools/batchedit.pl @@ -0,0 +1,222 @@ +#!/usr/bin/perl + + +# Copyright 2010 SARL BibLibre +# +# 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, +# Suite 330, Boston, MA 02111-1307 USA + +use CGI; +use strict; +use C4::Output; +use C4::Auth; +use C4::Branch; +use C4::Koha; +use C4::Biblio; +use C4::Context; +use C4::Debug; +use JSON; + +my $input = new CGI; +my $dbh = C4::Context->dbh; + +my $filefh = $input->param('uploadfile'); +my $recordslist = $input->param('recordslist'); +my $bib_list = $input->param('bib_list'); +my @biblionumbers; + +if ($filefh) { + while ( my $biblionumber = <$filefh> ) { + $biblionumber =~ s/[\r\n]*$//g; + push @biblionumbers, $biblionumber if $biblionumber; + } +} elsif ($recordslist) { + push @biblionumbers, split( /\s\n/, $recordslist ); +} elsif ($bib_list) { + push @biblionumbers, split('/', $bib_list); +} + +my $op = $input->param('op'); +my ($template, $loggedinuser, $cookie); + +my $frameworkcode=""; +my $tagslib = &GetMarcStructure(1,$frameworkcode); +my %report_actions; + +if($input->param('field') and not defined $op){ + ($template, $loggedinuser, $cookie) + = get_template_and_user({template_name => "acqui/ajax.tmpl", + query => $input, + type => "intranet", + authnotrequired => 0, + flagsrequired => { tools => "batchedit" }, + }); + + + my $tag = $input->param('field'); + my $subfield = $input->param('subfield'); + + if($input->param('subfield')){ + my $branches = GetBranchesLoop(); + + my @authorised_values; + if ( $tagslib->{$tag}->{$subfield}->{authorised_value} ) { + if ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "branches" ) { + foreach my $thisbranch (@$branches) { + push @authorised_values, { + code => $thisbranch->{value}, + value => $thisbranch->{branchname}, + }; + # $value = $thisbranch->{value} if $thisbranch->{selected}; + } + }elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "itemtypes" ) { + my $sth = $dbh->prepare("SELECT itemtype,description FROM itemtypes ORDER BY description"); + $sth->execute(); + while ( my ( $itemtype, $description ) = $sth->fetchrow_array ) { + push @authorised_values, { + code => $itemtype, + value => $description, + }; + } + + }else { + # Getting the fields where the item location is + my ($location_field, $location_subfield) = GetMarcFromKohaField('items.location', $frameworkcode); + + # Getting the name of the authorised values' category for item location + my $item_location_category = $tagslib->{$location_field}->{$location_subfield}->{'authorised_value'}; + # Are we dealing with item location ? + my $item_location = ($tagslib->{$tag}->{$subfield}->{authorised_value} eq $item_location_category) ? 1 : 0; + + # If so, we sort by authorised_value, else by libelle + my $orderby = $item_location ? 'authorised_value' : 'lib'; + + my $authorised_values_sth = $dbh->prepare("SELECT authorised_value,lib FROM authorised_values WHERE category=? ORDER BY $orderby"); + + $authorised_values_sth->execute( $tagslib->{$tag}->{$subfield}->{authorised_value}); + + + while ( my ( $value, $lib ) = $authorised_values_sth->fetchrow_array ) { + push @authorised_values, { + code => $value, + value => ($item_location) ? $value . " - " . $lib : $lib, + }; + + } + } + } + $template->param('return' => to_json(\@authorised_values)); + }else{ + my @modifiablesubf; + + foreach my $subfield (sort keys %{$tagslib->{$tag}}) { + next if subfield_is_koha_internal_p($subfield); + next if $subfield eq "@"; + next if ($tagslib->{$tag}->{$subfield}->{'tab'} eq "10"); + my %subfield_data; + $subfield_data{subfield} = $subfield; + push @modifiablesubf, \%subfield_data; + } + $template->param('return' => to_json(\@modifiablesubf)); + } + + + output_html_with_http_headers $input, $cookie, $template->output; + exit; +}else{ + ($template, $loggedinuser, $cookie) + = get_template_and_user({template_name => "tools/batchedit.tmpl", + query => $input, + type => "intranet", + authnotrequired => 0, + flagsrequired => { tools => "batchedit" }, + }); + + $template->param( inputform => 1, ) unless @biblionumbers; + + if(!defined $op) { + my @modifiablefields; + + foreach my $tag (sort keys %{$tagslib}) { + my %subfield_data; + foreach my $subfield (sort keys %{$tagslib->{$tag}}) { + next if $subfield_data{tag}; + next if subfield_is_koha_internal_p($subfield); + next if ($tagslib->{$tag}->{$subfield}->{'tab'} eq "10"); + + $subfield_data{tag} = $tag; + + push @modifiablefields, \%subfield_data; + } + } + + $template->param( marcfields => \@modifiablefields, + bib_list => $input->param('bib_list'), + ); + + }else{ + my @fields = $input->param('field'); + my @subfields = $input->param('subfield'); + my @actions = $input->param('action'); + my @condvals = $input->param('condval'); + my @nocondvals = $input->param('nocondval'); + my @repvals = $input->param('repval'); + foreach my $biblionumber ( @biblionumbers ){ + my $record = GetMarcBiblio($biblionumber); + my ($count, $biblio) = GetBiblio($biblionumber); + my $report = 0; + my @failed_actions; + for(my $i = 0 ; $i < scalar(@fields) ; $i++ ){ + my $field = $fields[$i]; + my $subfield = $subfields[$i]; + my $action = $actions[$i]; + my $condval = $condvals[$i]; + my $nocond = $nocondvals[$i]; + my $repval = $repvals[$i]; + + my ($result,$record) = BatchModField($record, $field, $subfield, $action, $condval, $nocond, $repval); + push @failed_actions, {action=>"$field $subfield $action ".($nocond eq "true"?"all":$condval)." $repval"} if ($result<=0); + } + if (@failed_actions == scalar(@fields)){ + $report_actions{$biblionumber}->{status}="No_Actions"; + } + elsif (@failed_actions>0 and @failed_actions < scalar(@fields)){ + $report_actions{$biblionumber}->{status}="Actions_Failed"; + $report_actions{$biblionumber}->{failed_actions}=\@failed_actions; + } + elsif (@failed_actions == 0){ + $report_actions{$biblionumber}->{status}="OK"; + } + ModBiblio($record, $biblionumber, $biblio->{frameworkcode}) unless ($report); + } + $template->param('moddone' => 1); + } + +} + +my @biblioinfos; + +for my $biblionumber (@biblionumbers){ + my ($count,$biblio) = GetBiblio($biblionumber); + if (defined $op){ + $biblio->{$report_actions{$biblionumber}->{status}}=1; + $biblio->{failed_actions}=$report_actions{$biblionumber}->{failed_actions}; + } + push @biblioinfos, $biblio; +} + +$template->param(biblioinfos => \@biblioinfos); +output_html_with_http_headers $input, $cookie, $template->output; +exit; -- 1.7.4.1