Bug 11034: remove incorrect return for BiblioAutoLink
[koha.git] / tools / modborrowers.pl
1 #!/usr/bin/perl
2
3 # Copyright 2012 BibLibre
4 #
5 # This file is part of Koha.
6 #
7 # Koha is free software; you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later
10 # version.
11 #
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License along
17 # with Koha; if not, write to the Free Software Foundation, Inc.,
18 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 # modborrowers.pl
21 #
22 # Batch Edit Patrons
23 # Modification for patron's fields:
24 # surname firstname branchcode categorycode sort1 sort2 dateenrolled dateexpiry debarred debarredcomment borrowernotes
25 # And for patron attributes.
26
27 use Modern::Perl;
28 use CGI;
29 use C4::Auth;
30 use C4::Branch;
31 use C4::Koha;
32 use C4::Members;
33 use C4::Members::Attributes;
34 use C4::Members::AttributeTypes qw/GetAttributeTypes_hashref/;
35 use C4::Output;
36 use List::MoreUtils qw /any uniq/;
37 use Koha::List::Patron;
38
39 my $input = new CGI;
40 my $op = $input->param('op') || 'show_form';
41 my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
42     {   template_name   => "tools/modborrowers.tmpl",
43         query           => $input,
44         type            => "intranet",
45         authnotrequired => 0,
46         flagsrequired   => { tools => "edit_patrons" },
47     }
48 );
49
50 my %cookies   = parse CGI::Cookie($cookie);
51 my $sessionID = $cookies{'CGISESSID'}->value;
52 my $dbh       = C4::Context->dbh;
53
54 # Show borrower informations
55 if ( $op eq 'show' ) {
56     my $filefh         = $input->upload('uploadfile');
57     my $filecontent    = $input->param('filecontent');
58     my $patron_list_id = $input->param('patron_list_id');
59     my @borrowers;
60     my @cardnumbers;
61     my @notfoundcardnumbers;
62
63     # Get cardnumbers from a file or the input area
64     my @contentlist;
65     if ($filefh) {
66         while ( my $content = <$filefh> ) {
67             $content =~ s/[\r\n]*$//g;
68             push @cardnumbers, $content if $content;
69         }
70     } elsif ( $patron_list_id ) {
71         my ($list) = GetPatronLists( { patron_list_id => $patron_list_id } );
72
73         @cardnumbers =
74           $list->patron_list_patrons()->search_related('borrowernumber')
75           ->get_column('cardnumber')->all();
76
77     } else {
78         if ( my $list = $input->param('cardnumberlist') ) {
79             push @cardnumbers, split( /\s\n/, $list );
80         }
81     }
82
83     my $max_nb_attr = 0;
84     for my $cardnumber ( @cardnumbers ) {
85         my $borrower = GetBorrowerInfos( cardnumber => $cardnumber );
86         if ( $borrower ) {
87             $max_nb_attr = scalar( @{ $borrower->{patron_attributes} } )
88                 if scalar( @{ $borrower->{patron_attributes} } ) > $max_nb_attr;
89             push @borrowers, $borrower;
90         } else {
91             push @notfoundcardnumbers, $cardnumber;
92         }
93     }
94
95     # Just for a correct display
96     for my $borrower ( @borrowers ) {
97         my $length = scalar( @{ $borrower->{patron_attributes} } );
98         push @{ $borrower->{patron_attributes} }, {} for ( $length .. $max_nb_attr - 1);
99     }
100
101     # Construct the patron attributes list
102     my @patron_attributes_values;
103     my @patron_attributes_codes;
104     my $patron_attribute_types = C4::Members::AttributeTypes::GetAttributeTypes_hashref('all');
105     my $patron_categories = C4::Members::GetBorrowercategoryList;
106     for ( values %$patron_attribute_types ) {
107         my $attr_type = C4::Members::AttributeTypes->fetch( $_->{code} );
108         my $options = $attr_type->authorised_value_category
109             ? GetAuthorisedValues( $attr_type->authorised_value_category )
110             : undef;
111         push @patron_attributes_values,
112             {
113                 attribute_code => $_->{code},
114                 options        => $options,
115             };
116
117         my $category_code = $_->{category_code};
118         my ( $category_lib ) = map {
119             ( defined $category_code and $_->{categorycode} eq $category_code ) ? $_->{description} : ()
120         } @$patron_categories;
121         push @patron_attributes_codes,
122             {
123                 attribute_code => $_->{code},
124                 attribute_lib  => $_->{description},
125                 category_lib   => $category_lib,
126                 type           => $attr_type->authorised_value_category ? 'select' : 'text',
127             };
128     }
129
130     my @attributes_header = ();
131     for ( 1 .. scalar( $max_nb_attr ) ) {
132         push @attributes_header, { attribute => "Attributes $_" };
133     }
134     $template->param( borrowers => \@borrowers );
135     $template->param( attributes_header => \@attributes_header );
136     @notfoundcardnumbers = map { { cardnumber => $_ } } @notfoundcardnumbers;
137     $template->param( notfoundcardnumbers => \@notfoundcardnumbers )
138         if @notfoundcardnumbers;
139
140     # Construct drop-down list values
141     my $branches = GetBranchesLoop;
142     my @branches_option;
143     push @branches_option, { value => $_->{value}, lib => $_->{branchname} } for @$branches;
144     unshift @branches_option, { value => "", lib => "" };
145     my $categories = GetBorrowercategoryList;
146     my @categories_option;
147     push @categories_option, { value => $_->{categorycode}, lib => $_->{description} } for @$categories;
148     unshift @categories_option, { value => "", lib => "" };
149     my $bsort1 = GetAuthorisedValues("Bsort1");
150     my @sort1_option;
151     push @sort1_option, { value => $_->{authorised_value}, lib => $_->{lib} } for @$bsort1;
152     unshift @sort1_option, { value => "", lib => "" }
153         if @sort1_option;
154     my $bsort2 = GetAuthorisedValues("Bsort2");
155     my @sort2_option;
156     push @sort2_option, { value => $_->{authorised_value}, lib => $_->{lib} } for @$bsort2;
157     unshift @sort2_option, { value => "", lib => "" }
158         if @sort2_option;
159
160     my @mandatoryFields = split( /\|/, C4::Context->preference("BorrowerMandatoryField") );
161
162     my @fields = (
163         {
164             name => "surname",
165             type => "text",
166             mandatory => ( grep /surname/, @mandatoryFields ) ? 1 : 0
167         }
168         ,
169         {
170             name => "firstname",
171             type => "text",
172             mandatory => ( grep /surname/, @mandatoryFields ) ? 1 : 0,
173         }
174         ,
175         {
176             name => "branchcode",
177             type => "select",
178             option => \@branches_option,
179             mandatory => ( grep /branchcode/, @mandatoryFields ) ? 1 : 0,
180         }
181         ,
182         {
183             name => "categorycode",
184             type => "select",
185             option => \@categories_option,
186             mandatory => ( grep /categorycode/, @mandatoryFields ) ? 1 : 0,
187         }
188         ,
189         {
190             name => "sort1",
191             type => @sort1_option ? "select" : "text",
192             option => \@sort1_option,
193             mandatory => ( grep /sort1/, @mandatoryFields ) ? 1 : 0,
194         }
195         ,
196         {
197             name => "sort2",
198             type => @sort2_option ? "select" : "text",
199             option => \@sort2_option,
200             mandatory => ( grep /sort2/, @mandatoryFields ) ? 1 : 0,
201         }
202         ,
203         {
204             name => "dateenrolled",
205             type => "date",
206             mandatory => ( grep /dateenrolled/, @mandatoryFields ) ? 1 : 0,
207         }
208         ,
209         {
210             name => "dateexpiry",
211             type => "date",
212             mandatory => ( grep /dateexpiry/, @mandatoryFields ) ? 1 : 0,
213         }
214         ,
215         {
216             name => "debarred",
217             type => "date",
218             mandatory => ( grep /debarred/, @mandatoryFields ) ? 1 : 0,
219         }
220         ,
221         {
222             name => "debarredcomment",
223             type => "text",
224             mandatory => ( grep /debarredcomment/, @mandatoryFields ) ? 1 : 0,
225         }
226         ,
227         {
228             name => "borrowernotes",
229             type => "text",
230             mandatory => ( grep /borrowernotes/, @mandatoryFields ) ? 1 : 0,
231         }
232     );
233
234     $template->param('patron_attributes_codes', \@patron_attributes_codes);
235     $template->param('patron_attributes_values', \@patron_attributes_values);
236
237     $template->param( fields => \@fields );
238 }
239
240 # Process modifications
241 if ( $op eq 'do' ) {
242
243     my @disabled = $input->param('disable_input');
244     my $infos;
245     for my $field ( qw/surname firstname branchcode categorycode sort1 sort2 dateenrolled dateexpiry debarred debarredcomment borrowernotes/ ) {
246         my $value = $input->param($field);
247         $infos->{$field} = $value if $value;
248         $infos->{$field} = "" if grep { /^$field$/ } @disabled;
249     }
250
251     my @attributes = $input->param('patron_attributes');
252     my @attr_values = $input->param('patron_attributes_value');
253
254     my @errors;
255     my @borrowernumbers = $input->param('borrowernumber');
256     # For each borrower selected
257     for my $borrowernumber ( @borrowernumbers ) {
258         # If at least one field are filled, we want to modify the borrower
259         if ( defined $infos ) {
260             $infos->{borrowernumber} = $borrowernumber;
261             my $success = ModMember(%$infos);
262             push @errors, { error => "can_not_update", borrowernumber => $infos->{borrowernumber} } if not $success;
263         }
264
265         #
266         my $borrower_categorycode = GetBorrowerCategorycode $borrowernumber;
267         my $i=0;
268         for ( @attributes ) {
269             my $attribute;
270             $attribute->{code} = $_;
271             $attribute->{attribute} = $attr_values[$i];
272             my $attr_type = C4::Members::AttributeTypes->fetch( $_ );
273             # If this borrower is not in the category of this attribute, we don't want to modify this attribute
274             ++$i and next if $attr_type->{category_code} and $attr_type->{category_code} ne $borrower_categorycode;
275             my $valuename = "attr" . $i . "_value";
276             if ( grep { /^$valuename$/ } @disabled ) {
277                 # The attribute is disabled, we remove it for this borrower !
278                 eval {
279                     C4::Members::Attributes::DeleteBorrowerAttribute( $borrowernumber, $attribute );
280                 };
281                 push @errors, { error => $@ } if $@;
282             } else {
283                 # Attribute's value is empty, we don't want to modify it
284                 ++$i and next if not $attribute->{attribute};
285
286                 eval {
287                     C4::Members::Attributes::UpdateBorrowerAttribute( $borrowernumber, $attribute );
288                 };
289                 push @errors, { error => $@ } if $@;
290             }
291             $i++;
292         }
293     }
294     $op = "show_results"; # We have process modifications, the user want to view its
295
296     # Construct the results list
297     my @borrowers;
298     my $max_nb_attr = 0;
299     for my $borrowernumber ( @borrowernumbers ) {
300         my $borrower = GetBorrowerInfos( borrowernumber => $borrowernumber );
301         if ( $borrower ) {
302             $max_nb_attr = scalar( @{ $borrower->{patron_attributes} } )
303                 if scalar( @{ $borrower->{patron_attributes} } ) > $max_nb_attr;
304             push @borrowers, $borrower;
305         }
306     }
307     my @patron_attributes_option;
308     for my $borrower ( @borrowers ) {
309         push @patron_attributes_option, { value => "$_->{code}", lib => $_->{code} } for @{ $borrower->{patron_attributes} };
310         my $length = scalar( @{ $borrower->{patron_attributes} } );
311         push @{ $borrower->{patron_attributes} }, {} for ( $length .. $max_nb_attr - 1);
312     }
313
314     my @attributes_header = ();
315     for ( 1 .. scalar( $max_nb_attr ) ) {
316         push @attributes_header, { attribute => "Attributes $_" };
317     }
318
319     $template->param( borrowers => \@borrowers );
320     $template->param( attributes_header => \@attributes_header );
321
322     $template->param( borrowers => \@borrowers );
323     $template->param( errors => \@errors );
324 } else {
325
326     $template->param( patron_lists => [ GetPatronLists() ] );
327 }
328
329 $template->param(
330     op => $op,
331 );
332 output_html_with_http_headers $input, $cookie, $template->output;
333 exit;
334
335 sub GetBorrowerInfos {
336     my ( %info ) = @_;
337     my $borrower = GetMember( %info );
338     if ( $borrower ) {
339         $borrower->{branchname} = GetBranchName( $borrower->{branchcode} );
340         for ( qw(dateenrolled dateexpiry debarred) ) {
341             my $userdate = $borrower->{$_};
342             unless ($userdate && $userdate ne "0000-00-00" and $userdate ne "9999-12-31") {
343                 $borrower->{$_} = '';
344                 next;
345             }
346             $borrower->{$_} = $userdate || '';
347         }
348         $borrower->{category_description} = GetBorrowercategory( $borrower->{categorycode} )->{description};
349         my $attr_loop = C4::Members::Attributes::GetBorrowerAttributes( $borrower->{borrowernumber} );
350         $borrower->{patron_attributes} = $attr_loop;
351     }
352     return $borrower;
353 }