Bug 30477: Add new UNIMARC installer translation files
[koha.git] / misc / cronjobs / update_patrons_category.pl
1 #!/usr/bin/perl
2
3 # This file is part of Koha.
4 #
5 # Koha is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # Koha is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18 use Modern::Perl;
19
20 use C4::Context;
21 use Getopt::Long qw( GetOptions );
22 use Pod::Usage qw( pod2usage );
23 use Koha::Logger;
24 use Koha::Patrons;
25 use Koha::Patron::Categories;
26 use Koha::DateUtils qw( dt_from_string );
27 use Koha::Script -cron;
28
29 =head1 NAME
30
31 update_patrons_category.pl - Given a set of parameters update selected patrons from one catgeory to another. Options are cumulative.
32
33 =head1 SYNOPSIS
34
35 update_patrons_category.pl -f=categorycode -t=categorycode
36                           [-b=branchcode] [--too_old] [--too_young] [-fo=X] [-fu=X]
37                           [-rb=date] [-ra=date] [-v]
38                           [--field column=value ...]
39
40 update_patrons_category.pl --help | --man
41
42 Options:
43
44    --help                   brief help message
45    --man                    full documentation
46    -too_old                 update if over  maximum age for current category
47    -too_young               update if under minimuum age  current category
48    -fo=X --fineover=X       update if fines over  X amount
49    -fu=X --fineunder=X      update if fines under X amount
50    -rb=date --regbefore     update if registration date is before given date
51    -ra=date --regafter      update if registration date is after a given date
52    -d --field name=value    where <name> is a column in the borrowers table, patrons will be updated if the field is equal to given <value>
53    --where <conditions>     where clause to add to the query
54    -v -verbose              verbose mode
55    -c --confirm             commit changes to db, no action will be taken unless this switch is included
56    -b --branch <branchname> only deal with patrons from this library/branch
57    -f --from <categorycode> change patron category from this category
58    -t --to   <categorycode> change patron category to this category
59
60 =head1 OPTIONS
61
62 =over 8
63
64 =item B<--help>
65
66 Print a brief help message and exits.
67
68 =item B<--man>
69
70 Prints the manual page and exits.
71
72 =item B<--verbose | -v>
73
74 Verbose. Without this flag set, only fatal errors are reported.
75
76 =item B<--confirm | -c>
77
78 Commit changes. Unless this flag set is, the script will report changes but not actually execute them on the database.
79
80 =item B<--branch | -b>
81
82 changes patrons for one specific branch. Use the value in the
83 branches.branchcode table.
84
85 =item B<--from | -f>
86
87 *required* defines the category to update. Expects the code from categories.categorycode.
88
89 =item B<--to | -t>
90
91 *required* defines the category patrons will be converted to. Expects the code from categories.categorycode.
92
93 =item B<--too_old>
94
95 Update patron only if they are above the maximum age range specified for the 'from' category.
96
97 =item B<--too_young>
98
99 Update patron only if they are below the minimum age range specified for the 'from' category.
100
101 =item B<--fineover=X | -fo=X>
102
103 Supply a number and only account with fines over this number will be updated.
104
105 =item B<--fineunder=X | -fu=X>
106
107 Supply a number and only account with fines under this number will be updated.
108
109 =item B<--regbefore=date | -rb=date>
110
111 Enter a date in ISO format YYYY-MM-DD and only patrons registered before this date wil be updated.
112
113 =item B<--regafter=date | -ra=date>
114
115 Enter a date in ISO format YYYY-MM-DD and only patrons registered after this date wil be updated.
116
117 =item B<--field column=value | -d column=value>
118
119 Use this flag to specify a column in the borrowers table and update only patrons whose value in that column equals the value supplied (repeatable)
120 A value of null will check for a field that is not set.
121
122 e.g.
123 --field dateexpiry=2016-01-01
124 will update all patrons who expired on that date, useful for schools etc.
125
126 =item B<--where $conditions>
127
128 Use this option to specify a condition built with columns from the borrowers table
129
130 e.g.
131 --where 'email IS NULL'
132 will update all patrons with no value for email
133
134 =back
135
136 =head1 DESCRIPTION
137
138 This script is designed to update patrons from one category to another.
139
140 =head1 USAGE EXAMPLES
141
142 C<update_patron_categories.pl> - Suggests that you read this help. :)
143
144 C<update_patron_categories.pl> -b=<branchcode> -f=<categorycode> -t=<categorycode> --confirm  - Processes a single branch, and updates the patron categories from fromcat to tocat.
145
146 C<update_patron_categories.pl> -b=<branchcode> -f=<categorycode> -t=<categorycode>  --too_old --confirm  - Processes a single branch, and updates the patron categories from fromcat to tocat for patrons over the age range of fromcat.
147
148 C<update_patron_categories.pl> -f=<categorycode> -t=<categorycode> -v  - Processes all branches, shows all messages, and reports the patrons who would be affected. Takes no action on the database.
149
150 =cut
151
152 # These variables are set by command line options.
153 # They are initially set to default values.
154
155 my $help    = 0;
156 my $man     = 0;
157 my $verbose = 0;
158 my $doit    = 0;
159 my $ageunder;
160 my $ageover;
161 my $remove_guarantors = 0;
162 my $fine_min;
163 my $fine_max;
164 my $fromcat;
165 my $tocat;
166 my $reg_bef;
167 my $reg_aft;
168 my $branch_lim;
169 my %fields;
170 my @where;
171
172 GetOptions(
173     'help|?'          => \$help,
174     'man'             => \$man,
175     'v|verbose'       => \$verbose,
176     'c|confirm'       => \$doit,
177     'f|from=s'        => \$fromcat,
178     't|to=s'          => \$tocat,
179     'too_old'         => \$ageover,
180     'too_young'       => \$ageunder,
181     'fo|finesover=s'  => \$fine_min,
182     'fu|finesunder=s' => \$fine_max,
183     'rb|regbefore=s'  => \$reg_bef,
184     'ra|regafter=s'   => \$reg_aft,
185     'b|branch=s'      => \$branch_lim,
186     'd|field=s'       => \%fields,
187     'where=s'         => \@where,
188 );
189
190 pod2usage(1) if $help;
191
192 pod2usage( -verbose => 2 ) if $man;
193
194 if ( not $fromcat && $tocat ) {    #make sure we've specified the info we need.
195     print "Must supply category from and to (-f & -t) please specify -help for usage tips.\n";
196     pod2usage(1);
197     exit;
198 }
199
200 ( $verbose && !$doit ) and print "No actions will be taken (test mode)\n";
201
202 $verbose and print "Will update patrons from $fromcat to $tocat with conditions below (if any)\n";
203
204 my %params;
205
206 if ( $reg_bef || $reg_aft ) {
207     my $date_bef;
208     my $date_aft;
209     if ( defined $reg_bef ) {
210         eval { $date_bef = dt_from_string( $reg_bef, 'iso' ); };
211     }
212     die "$reg_bef is not a valid date before, aborting! Use a date in format YYYY-MM-DD.$@"
213         if $@;
214     if ( defined $reg_aft ) {
215         eval { $date_aft = dt_from_string( $reg_aft, 'iso' ); };
216     }
217     die "$reg_bef is not a valid date after, aborting! Use a date in format YYYY-MM-DD.$@"
218         if $@;
219     $params{dateenrolled}{'<='} = $reg_bef if defined $date_bef;
220     $params{dateenrolled}{'>='} = $reg_aft if defined $date_aft;
221 }
222
223 my $cat_from = Koha::Patron::Categories->find($fromcat);
224 my $cat_to   = Koha::Patron::Categories->find($tocat);
225 die "Categories not found" unless $cat_from && $cat_to;
226
227 $params{"me.categorycode"} = $fromcat;
228 $params{"me.branchcode"} = $branch_lim if $branch_lim;
229
230 if ($verbose) {
231     print "Conditions:\n";
232     print "    Registered before $reg_bef\n"      if $reg_bef;
233     print "    Registered after  $reg_aft\n"      if $reg_aft;
234     print "    Total fines more than $fine_min\n" if $fine_min;
235     print "    Total fines less than $fine_max\n" if $fine_max;
236     print "    Age below minimum for " . $cat_from->description . "\n" if $ageunder;
237     print "    Age above maximum for " . $cat_from->description . "\n" if $ageover;
238     if ( defined $branch_lim ) {
239         print "    Branchcode of patron is $branch_lim\n";
240     }
241 }
242
243 while ( my ( $key, $value ) = each %fields ) {
244     $verbose and print "    Borrower column $key is $value\n";
245     $value = undef if lc($value) eq 'null';
246     $params{ "me." . $key } = $value;
247 }
248
249 my $where_literal = join ' AND ', @where;
250 my $target_patrons = Koha::Patrons->search( \%params );
251 $target_patrons = $target_patrons->search( \$where_literal ) if @where;
252 $target_patrons = $target_patrons->search_patrons_to_update_category(
253     {
254         from          => $fromcat,
255         search_params => \%params,
256         too_young     => $ageunder,
257         too_old       => $ageover,
258         fine_min      => $fine_min,
259         fine_max      => $fine_max,
260     }
261 );
262
263 my $patrons_found    = $target_patrons->count;
264 my $actually_updated = 0;
265 my $testdisplay      = $doit ? "" : "WOULD HAVE ";
266 if ($verbose) {
267     while ( my $target_patron = $target_patrons->next() ) {
268         $target_patron->discard_changes();
269         $verbose
270           and print $testdisplay
271           . "Updated "
272           . $target_patron->firstname() . " "
273           . $target_patron->surname()
274           . " from $fromcat to $tocat\n";
275     }
276     $target_patrons->reset;
277 }
278 if ($doit) {
279     $actually_updated = $target_patrons->update_category_to( { category => $tocat } );
280 }
281
282 $verbose and print "$patrons_found found, $actually_updated updated\n";