Koha/tools/modborrowers.pl
Jonathan Druart 9030800e78 Bug 15367: Do not display repeatable patron attributes in the batch patron modification
The repeatable patron attributes are not correctly managed and can cause
data lost. To avoid that, the easier way is not to display them in the
batch patron modification tool.
This should be implemented, as a new enhancement.

Test plan:
Create some patron attributes, some should be repeatable.
Use the batch patron modification tool to modify patrons.
With this patch, the patron attributes marked as repeatable won't be
display anymore.

Signed-off-by: Bernardo Gonzalez Kriegel <bgkriegel@gmail.com>
Works as described, no koha-qa errors

Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>

Signed-off-by: Brendan Gallagher brendan@bywatersolutions.com
2016-01-12 15:35:50 +00:00

378 lines
13 KiB
Perl
Executable file

#!/usr/bin/perl
# Copyright 2012 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 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 <http://www.gnu.org/licenses>.
# modborrowers.pl
#
# Batch Edit Patrons
# Modification for patron's fields:
# surname firstname branchcode categorycode city state zipcode country sort1
# sort2 dateenrolled dateexpiry borrowernotes
# And for patron attributes.
use Modern::Perl;
use CGI qw ( -utf8 );
use C4::Auth;
use C4::Branch;
use C4::Koha;
use C4::Members;
use C4::Members::Attributes;
use C4::Members::AttributeTypes qw/GetAttributeTypes_hashref/;
use C4::Output;
use List::MoreUtils qw /any uniq/;
use Koha::DateUtils qw( dt_from_string );
use Koha::List::Patron;
my $input = new CGI;
my $op = $input->param('op') || 'show_form';
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
{ template_name => "tools/modborrowers.tt",
query => $input,
type => "intranet",
authnotrequired => 0,
flagsrequired => { tools => "edit_patrons" },
}
);
my %cookies = parse CGI::Cookie($cookie);
my $sessionID = $cookies{'CGISESSID'}->value;
my $dbh = C4::Context->dbh;
# Show borrower informations
if ( $op eq 'show' ) {
my $filefh = $input->upload('uploadfile');
my $filecontent = $input->param('filecontent');
my $patron_list_id = $input->param('patron_list_id');
my @borrowers;
my @cardnumbers;
my @notfoundcardnumbers;
# Get cardnumbers from a file or the input area
my @contentlist;
if ($filefh) {
while ( my $content = <$filefh> ) {
$content =~ s/[\r\n]*$//g;
push @cardnumbers, $content if $content;
}
} elsif ( $patron_list_id ) {
my ($list) = GetPatronLists( { patron_list_id => $patron_list_id } );
@cardnumbers =
$list->patron_list_patrons()->search_related('borrowernumber')
->get_column('cardnumber')->all();
} else {
if ( my $list = $input->param('cardnumberlist') ) {
push @cardnumbers, split( /\s\n/, $list );
}
}
my $max_nb_attr = 0;
for my $cardnumber ( @cardnumbers ) {
my $borrower = GetBorrowerInfos( cardnumber => $cardnumber );
if ( $borrower ) {
$max_nb_attr = scalar( @{ $borrower->{patron_attributes} } )
if scalar( @{ $borrower->{patron_attributes} } ) > $max_nb_attr;
push @borrowers, $borrower;
} else {
push @notfoundcardnumbers, $cardnumber;
}
}
# Just for a correct display
for my $borrower ( @borrowers ) {
my $length = scalar( @{ $borrower->{patron_attributes} } );
push @{ $borrower->{patron_attributes} }, {} for ( $length .. $max_nb_attr - 1);
}
# Construct the patron attributes list
my @patron_attributes_values;
my @patron_attributes_codes;
my $patron_attribute_types = C4::Members::AttributeTypes::GetAttributeTypes_hashref('all');
my $patron_categories = C4::Members::GetBorrowercategoryList;
for ( values %$patron_attribute_types ) {
my $attr_type = C4::Members::AttributeTypes->fetch( $_->{code} );
# TODO Repeatable attributes are not correctly managed and can cause data lost.
# This should be implemented.
next if $attr_type->{repeatable};
my $options = $attr_type->authorised_value_category
? GetAuthorisedValues( $attr_type->authorised_value_category )
: undef;
push @patron_attributes_values,
{
attribute_code => $_->{code},
options => $options,
};
my $category_code = $_->{category_code};
my ( $category_lib ) = map {
( defined $category_code and $_->{categorycode} eq $category_code ) ? $_->{description} : ()
} @$patron_categories;
push @patron_attributes_codes,
{
attribute_code => $_->{code},
attribute_lib => $_->{description},
category_lib => $category_lib,
type => $attr_type->authorised_value_category ? 'select' : 'text',
};
}
my @attributes_header = ();
for ( 1 .. scalar( $max_nb_attr ) ) {
push @attributes_header, { attribute => "Attributes $_" };
}
$template->param( borrowers => \@borrowers );
$template->param( attributes_header => \@attributes_header );
@notfoundcardnumbers = map { { cardnumber => $_ } } @notfoundcardnumbers;
$template->param( notfoundcardnumbers => \@notfoundcardnumbers )
if @notfoundcardnumbers;
# Construct drop-down list values
my $branches = GetBranchesLoop;
my @branches_option;
push @branches_option, { value => $_->{value}, lib => $_->{branchname} } for @$branches;
unshift @branches_option, { value => "", lib => "" };
my $categories = GetBorrowercategoryList;
my @categories_option;
push @categories_option, { value => $_->{categorycode}, lib => $_->{description} } for @$categories;
unshift @categories_option, { value => "", lib => "" };
my $bsort1 = GetAuthorisedValues("Bsort1");
my @sort1_option;
push @sort1_option, { value => $_->{authorised_value}, lib => $_->{lib} } for @$bsort1;
unshift @sort1_option, { value => "", lib => "" }
if @sort1_option;
my $bsort2 = GetAuthorisedValues("Bsort2");
my @sort2_option;
push @sort2_option, { value => $_->{authorised_value}, lib => $_->{lib} } for @$bsort2;
unshift @sort2_option, { value => "", lib => "" }
if @sort2_option;
my @mandatoryFields = split( /\|/, C4::Context->preference("BorrowerMandatoryField") );
my @fields = (
{
name => "surname",
type => "text",
mandatory => ( grep /surname/, @mandatoryFields ) ? 1 : 0
}
,
{
name => "firstname",
type => "text",
mandatory => ( grep /firstname/, @mandatoryFields ) ? 1 : 0,
}
,
{
name => "branchcode",
type => "select",
option => \@branches_option,
mandatory => ( grep /branchcode/, @mandatoryFields ) ? 1 : 0,
}
,
{
name => "categorycode",
type => "select",
option => \@categories_option,
mandatory => ( grep /categorycode/, @mandatoryFields ) ? 1 : 0,
}
,
{
name => "city",
type => "text",
mandatory => ( grep /city/, @mandatoryFields ) ? 1 : 0,
}
,
{
name => "state",
type => "text",
mandatory => ( grep /state/, @mandatoryFields ) ? 1 : 0,
}
,
{
name => "zipcode",
type => "text",
mandatory => ( grep /zipcode/, @mandatoryFields ) ? 1 : 0,
}
,
{
name => "country",
type => "text",
mandatory => ( grep /country/, @mandatoryFields ) ? 1 : 0,
}
,
{
name => "sort1",
type => @sort1_option ? "select" : "text",
option => \@sort1_option,
mandatory => ( grep /sort1/, @mandatoryFields ) ? 1 : 0,
}
,
{
name => "sort2",
type => @sort2_option ? "select" : "text",
option => \@sort2_option,
mandatory => ( grep /sort2/, @mandatoryFields ) ? 1 : 0,
}
,
{
name => "dateenrolled",
type => "date",
mandatory => ( grep /dateenrolled/, @mandatoryFields ) ? 1 : 0,
}
,
{
name => "dateexpiry",
type => "date",
mandatory => ( grep /dateexpiry/, @mandatoryFields ) ? 1 : 0,
}
,
{
name => "borrowernotes",
type => "text",
mandatory => ( grep /borrowernotes/, @mandatoryFields ) ? 1 : 0,
}
);
$template->param('patron_attributes_codes', \@patron_attributes_codes);
$template->param('patron_attributes_values', \@patron_attributes_values);
$template->param( fields => \@fields );
}
# Process modifications
if ( $op eq 'do' ) {
my @disabled = $input->param('disable_input');
my $infos;
for my $field ( qw/surname firstname branchcode categorycode city state zipcode country sort1 sort2 dateenrolled dateexpiry borrowernotes/ ) {
my $value = $input->param($field);
$infos->{$field} = $value if $value;
$infos->{$field} = "" if grep { /^$field$/ } @disabled;
}
for my $field ( qw( dateenrolled dateexpiry ) ) {
$infos->{$field} = dt_from_string($infos->{$field});
}
my @attributes = $input->param('patron_attributes');
my @attr_values = $input->param('patron_attributes_value');
my @errors;
my @borrowernumbers = $input->param('borrowernumber');
# For each borrower selected
for my $borrowernumber ( @borrowernumbers ) {
# If at least one field are filled, we want to modify the borrower
if ( defined $infos ) {
$infos->{borrowernumber} = $borrowernumber;
my $success = ModMember(%$infos);
if (!$success) {
my $borrowerinfo = GetBorrowerInfos( borrowernumber => $borrowernumber );
$infos->{cardnumber} = $borrowerinfo->{cardnumber} || '';
push @errors, { error => "can_not_update", borrowernumber => $infos->{borrowernumber}, cardnumber => $infos->{cardnumber} };
}
}
#
my $borrower_categorycode = GetBorrowerCategorycode $borrowernumber;
my $i=0;
for ( @attributes ) {
my $attribute;
$attribute->{code} = $_;
$attribute->{attribute} = $attr_values[$i];
my $attr_type = C4::Members::AttributeTypes->fetch( $_ );
# If this borrower is not in the category of this attribute, we don't want to modify this attribute
++$i and next if $attr_type->{category_code} and $attr_type->{category_code} ne $borrower_categorycode;
my $valuename = "attr" . $i . "_value";
if ( grep { /^$valuename$/ } @disabled ) {
# The attribute is disabled, we remove it for this borrower !
eval {
C4::Members::Attributes::DeleteBorrowerAttribute( $borrowernumber, $attribute );
};
push @errors, { error => $@ } if $@;
} else {
# Attribute's value is empty, we don't want to modify it
++$i and next if not $attribute->{attribute};
eval {
C4::Members::Attributes::UpdateBorrowerAttribute( $borrowernumber, $attribute );
};
push @errors, { error => $@ } if $@;
}
$i++;
}
}
$op = "show_results"; # We have process modifications, the user want to view its
# Construct the results list
my @borrowers;
my $max_nb_attr = 0;
for my $borrowernumber ( @borrowernumbers ) {
my $borrower = GetBorrowerInfos( borrowernumber => $borrowernumber );
if ( $borrower ) {
$max_nb_attr = scalar( @{ $borrower->{patron_attributes} } )
if scalar( @{ $borrower->{patron_attributes} } ) > $max_nb_attr;
push @borrowers, $borrower;
}
}
my @patron_attributes_option;
for my $borrower ( @borrowers ) {
push @patron_attributes_option, { value => "$_->{code}", lib => $_->{code} } for @{ $borrower->{patron_attributes} };
my $length = scalar( @{ $borrower->{patron_attributes} } );
push @{ $borrower->{patron_attributes} }, {} for ( $length .. $max_nb_attr - 1);
}
my @attributes_header = ();
for ( 1 .. scalar( $max_nb_attr ) ) {
push @attributes_header, { attribute => "Attributes $_" };
}
$template->param( borrowers => \@borrowers );
$template->param( attributes_header => \@attributes_header );
$template->param( borrowers => \@borrowers );
$template->param( errors => \@errors );
} else {
$template->param( patron_lists => [ GetPatronLists() ] );
}
$template->param(
op => $op,
);
output_html_with_http_headers $input, $cookie, $template->output;
exit;
sub GetBorrowerInfos {
my ( %info ) = @_;
my $borrower = GetMember( %info );
if ( $borrower ) {
$borrower->{branchname} = GetBranchName( $borrower->{branchcode} );
for ( qw(dateenrolled dateexpiry) ) {
my $userdate = $borrower->{$_};
unless ($userdate && $userdate ne "0000-00-00" and $userdate ne "9999-12-31") {
$borrower->{$_} = '';
next;
}
$borrower->{$_} = $userdate || '';
}
$borrower->{category_description} = GetBorrowercategory( $borrower->{categorycode} )->{description};
my $attr_loop = C4::Members::Attributes::GetBorrowerAttributes( $borrower->{borrowernumber} );
$borrower->{patron_attributes} = $attr_loop;
}
return $borrower;
}