Lines 39-59
use Koha::Patron::Categories;
Link Here
|
39 |
use Koha::Patrons; |
39 |
use Koha::Patrons; |
40 |
use Koha::Script -cron; |
40 |
use Koha::Script -cron; |
41 |
|
41 |
|
42 |
my $lost; # key=lost value, value=num days. |
42 |
my $lost; # key=lost value, value=num days. |
43 |
my ($charge, $verbose, $confirm, $quiet); |
43 |
my ( $charge, $verbose, $confirm, $quiet ); |
44 |
my $endrange = 366; |
44 |
my $endrange = 366; |
45 |
my $mark_returned; |
45 |
my $mark_returned; |
46 |
my $borrower_category = []; |
46 |
my $borrower_category = []; |
47 |
my $skip_borrower_category = []; |
47 |
my $skip_borrower_category = []; |
48 |
my $itemtype = []; |
48 |
my $itemtype = []; |
49 |
my $skip_itemtype = []; |
49 |
my $skip_itemtype = []; |
50 |
my $help=0; |
50 |
my $help = 0; |
51 |
my $man=0; |
51 |
my $man = 0; |
52 |
my $list_categories = 0; |
52 |
my $list_categories = 0; |
53 |
my $list_itemtypes = 0; |
53 |
my $list_itemtypes = 0; |
54 |
my @skip_lost_values; |
54 |
my @skip_lost_values; |
55 |
|
55 |
|
56 |
my $command_line_options = join(" ",@ARGV); |
56 |
my $command_line_options = join( " ", @ARGV ); |
57 |
|
57 |
|
58 |
GetOptions( |
58 |
GetOptions( |
59 |
'l|lost=s%' => \$lost, |
59 |
'l|lost=s%' => \$lost, |
Lines 74-115
GetOptions(
Link Here
|
74 |
'skip-lost-value=s' => \@skip_lost_values, |
74 |
'skip-lost-value=s' => \@skip_lost_values, |
75 |
); |
75 |
); |
76 |
|
76 |
|
77 |
if ( $man ) { |
77 |
if ($man) { |
78 |
pod2usage( -verbose => 2 |
78 |
pod2usage( -verbose => 2 -exitval => 0 ); |
79 |
-exitval => 0 |
|
|
80 |
); |
81 |
} |
79 |
} |
82 |
|
80 |
|
83 |
if ( $help ) { |
81 |
if ($help) { |
84 |
pod2usage( -verbose => 1, |
82 |
pod2usage( |
85 |
-exitval => 0 |
83 |
-verbose => 1, |
86 |
); |
84 |
-exitval => 0 |
|
|
85 |
); |
87 |
} |
86 |
} |
88 |
|
87 |
|
89 |
if ( scalar @$borrower_category && scalar @$skip_borrower_category) { |
88 |
if ( scalar @$borrower_category && scalar @$skip_borrower_category ) { |
90 |
pod2usage( -verbose => 1, |
89 |
pod2usage( |
91 |
-message => "The options --category and --skip-category are mutually exclusive.\n" |
90 |
-verbose => 1, |
92 |
. "Use one or the other.", |
91 |
-message => "The options --category and --skip-category are mutually exclusive.\n" . "Use one or the other.", |
93 |
-exitval => 1 |
92 |
-exitval => 1 |
94 |
); |
93 |
); |
95 |
} |
94 |
} |
96 |
|
95 |
|
97 |
if ( scalar @$itemtype && scalar @$skip_itemtype) { |
96 |
if ( scalar @$itemtype && scalar @$skip_itemtype ) { |
98 |
pod2usage( -verbose => 1, |
97 |
pod2usage( |
99 |
-message => "The options --itemtype and --skip-itemtype are mutually exclusive.\n" |
98 |
-verbose => 1, |
100 |
. "Use one or the other.", |
99 |
-message => "The options --itemtype and --skip-itemtype are mutually exclusive.\n" . "Use one or the other.", |
101 |
-exitval => 1 |
100 |
-exitval => 1 |
102 |
); |
101 |
); |
103 |
} |
102 |
} |
104 |
|
103 |
|
105 |
if ( $list_categories ) { |
104 |
if ($list_categories) { |
106 |
|
105 |
|
107 |
my @categories = Koha::Patron::Categories->search()->get_column('categorycode'); |
106 |
my @categories = Koha::Patron::Categories->search()->get_column('categorycode'); |
108 |
print "\nBorrower Categories: " . join( " ", @categories ) . "\n\n"; |
107 |
print "\nBorrower Categories: " . join( " ", @categories ) . "\n\n"; |
109 |
exit 0; |
108 |
exit 0; |
110 |
} |
109 |
} |
111 |
|
110 |
|
112 |
if ( $list_itemtypes ) { |
111 |
if ($list_itemtypes) { |
113 |
my @itemtypes = Koha::ItemTypes->search()->get_column('itemtype'); |
112 |
my @itemtypes = Koha::ItemTypes->search()->get_column('itemtype'); |
114 |
print "\nItemtypes: " . join( " ", @itemtypes ) . "\n\n"; |
113 |
print "\nItemtypes: " . join( " ", @itemtypes ) . "\n\n"; |
115 |
exit 0; |
114 |
exit 0; |
Lines 252-286
near-term release, so this script is not intended to have a long lifetime.
Link Here
|
252 |
# |
251 |
# |
253 |
|
252 |
|
254 |
unless ( scalar @skip_lost_values ) { |
253 |
unless ( scalar @skip_lost_values ) { |
255 |
my $preference = C4::Context->preference( 'DefaultLongOverdueSkipLostStatuses' ); |
254 |
my $preference = C4::Context->preference('DefaultLongOverdueSkipLostStatuses'); |
256 |
@skip_lost_values = split( ',', $preference ); |
255 |
@skip_lost_values = split( ',', $preference ); |
257 |
} |
256 |
} |
258 |
|
257 |
|
259 |
if ( ! defined($lost) ) { |
258 |
if ( !defined($lost) ) { |
260 |
my $longoverdue_value = C4::Context->preference('DefaultLongOverdueLostValue'); |
259 |
my $longoverdue_value = C4::Context->preference('DefaultLongOverdueLostValue'); |
261 |
my $longoverdue_days = C4::Context->preference('DefaultLongOverdueDays'); |
260 |
my $longoverdue_days = C4::Context->preference('DefaultLongOverdueDays'); |
262 |
if(defined($longoverdue_value) and defined($longoverdue_days) and $longoverdue_value ne '' and $longoverdue_days ne '' and $longoverdue_days >= 0) { |
261 |
if ( defined($longoverdue_value) |
|
|
262 |
and defined($longoverdue_days) |
263 |
and $longoverdue_value ne '' |
264 |
and $longoverdue_days ne '' |
265 |
and $longoverdue_days >= 0 ) |
266 |
{ |
263 |
$lost->{$longoverdue_days} = $longoverdue_value; |
267 |
$lost->{$longoverdue_days} = $longoverdue_value; |
264 |
} |
268 |
} else { |
265 |
else { |
269 |
pod2usage( |
266 |
pod2usage( { |
270 |
{ |
267 |
-exitval => 1, |
271 |
-exitval => 1, |
268 |
-msg => q|ERROR: No --lost (-l) option or system preferences DefaultLongOverdueLostValue/DefaultLongOverdueDays defined|, |
272 |
-msg => |
269 |
} ); |
273 |
q|ERROR: No --lost (-l) option or system preferences DefaultLongOverdueLostValue/DefaultLongOverdueDays defined|, |
|
|
274 |
} |
275 |
); |
270 |
} |
276 |
} |
271 |
} |
277 |
} |
272 |
if ( ! defined($charge) ) { |
278 |
|
|
|
279 |
if ( !defined($charge) ) { |
273 |
my $charge_value = C4::Context->preference('DefaultLongOverdueChargeValue'); |
280 |
my $charge_value = C4::Context->preference('DefaultLongOverdueChargeValue'); |
274 |
if(defined($charge_value) and $charge_value ne '') { |
281 |
if ( defined($charge_value) and $charge_value ne '' ) { |
275 |
$charge = $charge_value; |
282 |
$charge = $charge_value; |
276 |
} |
283 |
} |
277 |
} |
284 |
} |
|
|
285 |
|
286 |
if ( C4::Context->preference('DefaultLongOverdueBorrowerCategories') ) { |
287 |
my $categories = C4::Context->preference('DefaultLongOverdueBorrowerCategories'); |
288 |
$borrower_category = [ split( ',', $categories ) ]; |
289 |
} |
290 |
|
291 |
if ( C4::Context->preference('DefaultLongOverdueSkipBorrowerCategories') ) { |
292 |
my $categories = C4::Context->preference('DefaultLongOverdueSkipBorrowerCategories'); |
293 |
$skip_borrower_category = [ split( ',', $categories ) ]; |
294 |
} |
295 |
|
278 |
unless ($confirm) { |
296 |
unless ($confirm) { |
279 |
$verbose = 1; # If you're not running it for real, then the whole point is the print output. |
297 |
$verbose = 1; # If you're not running it for real, then the whole point is the print output. |
280 |
print "### TEST MODE -- NO ACTIONS TAKEN ###\n"; |
298 |
print "### TEST MODE -- NO ACTIONS TAKEN ###\n"; |
281 |
} |
299 |
} |
282 |
|
300 |
|
283 |
cronlogaction({ info => $command_line_options }); |
301 |
cronlogaction( { info => $command_line_options } ); |
284 |
|
302 |
|
285 |
# In my opinion, this line is safe SQL to have outside the API. --atz |
303 |
# In my opinion, this line is safe SQL to have outside the API. --atz |
286 |
our $bounds_sth = C4::Context->dbh->prepare("SELECT DATE_SUB(CURDATE(), INTERVAL ? DAY)"); |
304 |
our $bounds_sth = C4::Context->dbh->prepare("SELECT DATE_SUB(CURDATE(), INTERVAL ? DAY)"); |
Lines 292-304
sub bounds {
Link Here
|
292 |
|
310 |
|
293 |
# FIXME - This sql should be inside the API. |
311 |
# FIXME - This sql should be inside the API. |
294 |
sub longoverdue_sth { |
312 |
sub longoverdue_sth { |
295 |
my ( $params ) = @_; |
313 |
my ($params) = @_; |
296 |
my $skip_lost_values = $params->{skip_lost_values}; |
314 |
my $skip_lost_values = $params->{skip_lost_values}; |
297 |
|
315 |
|
298 |
my $skip_lost_values_sql = q{}; |
316 |
my $skip_lost_values_sql = q{}; |
299 |
if ( @$skip_lost_values ) { |
317 |
if (@$skip_lost_values) { |
300 |
my $values = join( ',', map { qq{'$_'} } @$skip_lost_values ); |
318 |
my $values = join( ',', map { qq{'$_'} } @$skip_lost_values ); |
301 |
$skip_lost_values_sql = "AND itemlost NOT IN ( $values )" |
319 |
$skip_lost_values_sql = "AND itemlost NOT IN ( $values )"; |
302 |
} |
320 |
} |
303 |
|
321 |
|
304 |
my $query = " |
322 |
my $query = " |
Lines 317-326
sub longoverdue_sth {
Link Here
|
317 |
my $dbh = C4::Context->dbh; |
335 |
my $dbh = C4::Context->dbh; |
318 |
|
336 |
|
319 |
my @available_categories = Koha::Patron::Categories->search()->get_column('categorycode'); |
337 |
my @available_categories = Koha::Patron::Categories->search()->get_column('categorycode'); |
320 |
$borrower_category = [ map { uc $_ } @$borrower_category ]; |
338 |
$borrower_category = [ map { uc $_ } @$borrower_category ]; |
321 |
$skip_borrower_category = [ map { uc $_} @$skip_borrower_category ]; |
339 |
$skip_borrower_category = [ map { uc $_ } @$skip_borrower_category ]; |
322 |
my %category_to_process; |
340 |
my %category_to_process; |
323 |
for my $cat ( @$borrower_category ) { |
341 |
for my $cat (@$borrower_category) { |
324 |
unless ( grep { $_ eq $cat } @available_categories ) { |
342 |
unless ( grep { $_ eq $cat } @available_categories ) { |
325 |
pod2usage( |
343 |
pod2usage( |
326 |
'-exitval' => 1, |
344 |
'-exitval' => 1, |
Lines 329-336
for my $cat ( @$borrower_category ) {
Link Here
|
329 |
} |
347 |
} |
330 |
$category_to_process{$cat} = 1; |
348 |
$category_to_process{$cat} = 1; |
331 |
} |
349 |
} |
332 |
if ( @$skip_borrower_category ) { |
350 |
if (@$skip_borrower_category) { |
333 |
for my $cat ( @$skip_borrower_category ) { |
351 |
for my $cat (@$skip_borrower_category) { |
334 |
unless ( grep { $_ eq $cat } @available_categories ) { |
352 |
unless ( grep { $_ eq $cat } @available_categories ) { |
335 |
pod2usage( |
353 |
pod2usage( |
336 |
'-exitval' => 1, |
354 |
'-exitval' => 1, |
Lines 345-354
if ( @$skip_borrower_category ) {
Link Here
|
345 |
my $filter_borrower_categories = ( scalar @$borrower_category || scalar @$skip_borrower_category ); |
363 |
my $filter_borrower_categories = ( scalar @$borrower_category || scalar @$skip_borrower_category ); |
346 |
|
364 |
|
347 |
my @available_itemtypes = Koha::ItemTypes->search()->get_column('itemtype'); |
365 |
my @available_itemtypes = Koha::ItemTypes->search()->get_column('itemtype'); |
348 |
$itemtype = [ map { uc $_ } @$itemtype ]; |
366 |
$itemtype = [ map { uc $_ } @$itemtype ]; |
349 |
$skip_itemtype = [ map { uc $_} @$skip_itemtype ]; |
367 |
$skip_itemtype = [ map { uc $_ } @$skip_itemtype ]; |
350 |
my %itemtype_to_process; |
368 |
my %itemtype_to_process; |
351 |
for my $it ( @$itemtype ) { |
369 |
for my $it (@$itemtype) { |
352 |
unless ( grep { $_ eq $it } @available_itemtypes ) { |
370 |
unless ( grep { $_ eq $it } @available_itemtypes ) { |
353 |
pod2usage( |
371 |
pod2usage( |
354 |
'-exitval' => 1, |
372 |
'-exitval' => 1, |
Lines 357-364
for my $it ( @$itemtype ) {
Link Here
|
357 |
} |
375 |
} |
358 |
$itemtype_to_process{$it} = 1; |
376 |
$itemtype_to_process{$it} = 1; |
359 |
} |
377 |
} |
360 |
if ( @$skip_itemtype ) { |
378 |
if (@$skip_itemtype) { |
361 |
for my $it ( @$skip_itemtype ) { |
379 |
for my $it (@$skip_itemtype) { |
362 |
unless ( grep { $_ eq $it } @available_itemtypes ) { |
380 |
unless ( grep { $_ eq $it } @available_itemtypes ) { |
363 |
pod2usage( |
381 |
pod2usage( |
364 |
'-exitval' => 1, |
382 |
'-exitval' => 1, |
Lines 375-427
my $filter_itemtypes = ( scalar @$itemtype || scalar @$skip_itemtype );
Link Here
|
375 |
my $count; |
393 |
my $count; |
376 |
my @report; |
394 |
my @report; |
377 |
my $total = 0; |
395 |
my $total = 0; |
378 |
my $i = 0; |
396 |
my $i = 0; |
379 |
|
397 |
|
380 |
# FIXME - The item is only marked returned if you supply --charge . |
398 |
# FIXME - The item is only marked returned if you supply --charge . |
381 |
# We need a better way to handle this. |
399 |
# We need a better way to handle this. |
382 |
# |
400 |
# |
383 |
my $sth_items = longoverdue_sth({ skip_lost_values => \@skip_lost_values }); |
401 |
my $sth_items = longoverdue_sth( { skip_lost_values => \@skip_lost_values } ); |
384 |
|
402 |
|
385 |
foreach my $startrange (sort keys %$lost) { |
403 |
foreach my $startrange ( sort keys %$lost ) { |
386 |
if( my $lostvalue = $lost->{$startrange} ) { |
404 |
if ( my $lostvalue = $lost->{$startrange} ) { |
387 |
my ($date1) = bounds($startrange); |
405 |
my ($date1) = bounds($startrange); |
388 |
my ($date2) = bounds( $endrange); |
406 |
my ($date2) = bounds($endrange); |
|
|
407 |
|
389 |
# print "\nRange ", ++$i, "\nDue $startrange - $endrange days ago ($date2 to $date1), lost => $lostvalue\n" if($verbose); |
408 |
# print "\nRange ", ++$i, "\nDue $startrange - $endrange days ago ($date2 to $date1), lost => $lostvalue\n" if($verbose); |
390 |
$verbose and |
409 |
$verbose |
391 |
printf "\nRange %s\nDue %3s - %3s days ago (%s to %s), lost => %s\n", ++$i, |
410 |
and printf "\nRange %s\nDue %3s - %3s days ago (%s to %s), lost => %s\n", ++$i, |
392 |
$startrange, $endrange, $date2, $date1, $lostvalue; |
411 |
$startrange, $endrange, $date2, $date1, $lostvalue; |
393 |
$sth_items->execute($startrange, $endrange, $lostvalue); |
412 |
$sth_items->execute( $startrange, $endrange, $lostvalue ); |
394 |
$count=0; |
413 |
$count = 0; |
395 |
ITEM: while (my $row=$sth_items->fetchrow_hashref) { |
414 |
ITEM: while ( my $row = $sth_items->fetchrow_hashref ) { |
396 |
if( $filter_borrower_categories ) { |
415 |
if ($filter_borrower_categories) { |
397 |
my $category = uc Koha::Patrons->find( $row->{borrowernumber} )->categorycode(); |
416 |
my $category = uc Koha::Patrons->find( $row->{borrowernumber} )->categorycode(); |
398 |
next ITEM unless ( $category_to_process{ $category } ); |
417 |
next ITEM unless ( $category_to_process{$category} ); |
399 |
} |
418 |
} |
400 |
if ($filter_itemtypes) { |
419 |
if ($filter_itemtypes) { |
401 |
my $it = uc Koha::Items->find( $row->{itemnumber} )->effective_itemtype(); |
420 |
my $it = uc Koha::Items->find( $row->{itemnumber} )->effective_itemtype(); |
402 |
next ITEM unless ( $itemtype_to_process{$it} ); |
421 |
next ITEM unless ( $itemtype_to_process{$it} ); |
403 |
} |
422 |
} |
404 |
printf ("Due %s: item %5s from borrower %5s to lost: %s\n", $row->{date_due}, $row->{itemnumber}, $row->{borrowernumber}, $lostvalue) if($verbose); |
423 |
printf( |
405 |
if($confirm) { |
424 |
"Due %s: item %5s from borrower %5s to lost: %s\n", $row->{date_due}, $row->{itemnumber}, |
406 |
Koha::Items->find( $row->{itemnumber} )->itemlost($lostvalue) |
425 |
$row->{borrowernumber}, $lostvalue |
407 |
->store; |
426 |
) if ($verbose); |
|
|
427 |
if ($confirm) { |
428 |
Koha::Items->find( $row->{itemnumber} )->itemlost($lostvalue)->store; |
408 |
if ( $charge && $charge eq $lostvalue ) { |
429 |
if ( $charge && $charge eq $lostvalue ) { |
409 |
LostItem( $row->{'itemnumber'}, 'cronjob', $mark_returned ); |
430 |
LostItem( $row->{'itemnumber'}, 'cronjob', $mark_returned ); |
410 |
} elsif ( $mark_returned ) { |
431 |
} elsif ($mark_returned) { |
411 |
my $patron = Koha::Patrons->find( $row->{borrowernumber} ); |
432 |
my $patron = Koha::Patrons->find( $row->{borrowernumber} ); |
412 |
MarkIssueReturned($row->{borrowernumber},$row->{itemnumber},undef,$patron->privacy) |
433 |
MarkIssueReturned( $row->{borrowernumber}, $row->{itemnumber}, undef, $patron->privacy ); |
413 |
} |
434 |
} |
414 |
} |
435 |
} |
415 |
$count++; |
436 |
$count++; |
416 |
} |
437 |
} |
417 |
push @report, { |
438 |
push @report, { |
418 |
startrange => $startrange, |
439 |
startrange => $startrange, |
419 |
endrange => $endrange, |
440 |
endrange => $endrange, |
420 |
range => "$startrange - $endrange", |
441 |
range => "$startrange - $endrange", |
421 |
date1 => $date1, |
442 |
date1 => $date1, |
422 |
date2 => $date2, |
443 |
date2 => $date2, |
423 |
lostvalue => $lostvalue, |
444 |
lostvalue => $lostvalue, |
424 |
count => $count, |
445 |
count => $count, |
425 |
}; |
446 |
}; |
426 |
$total += $count; |
447 |
$total += $count; |
427 |
} |
448 |
} |
Lines 429-449
foreach my $startrange (sort keys %$lost) {
Link Here
|
429 |
} |
450 |
} |
430 |
|
451 |
|
431 |
sub summarize { |
452 |
sub summarize { |
432 |
my $arg = shift; # ref to array |
453 |
my $arg = shift; # ref to array |
433 |
my $got_items = shift || 0; # print "count" line for items |
454 |
my $got_items = shift || 0; # print "count" line for items |
434 |
my @report = @$arg or return; |
455 |
my @report = @$arg or return; |
435 |
my $i = 0; |
456 |
my $i = 0; |
436 |
for my $range (@report) { |
457 |
for my $range (@report) { |
437 |
printf "\nRange %s\nDue %3s - %3s days ago (%s to %s), lost => %s\n", ++$i, |
458 |
printf "\nRange %s\nDue %3s - %3s days ago (%s to %s), lost => %s\n", ++$i, |
438 |
map {$range->{$_}} qw(startrange endrange date2 date1 lostvalue); |
459 |
map { $range->{$_} } qw(startrange endrange date2 date1 lostvalue); |
439 |
$got_items and printf " %4s items\n", $range->{count}; |
460 |
$got_items and printf " %4s items\n", $range->{count}; |
440 |
} |
461 |
} |
441 |
} |
462 |
} |
442 |
|
463 |
|
443 |
if (!$quiet){ |
464 |
if ( !$quiet ) { |
444 |
print "\n### LONGOVERDUE SUMMARY ###"; |
465 |
print "\n### LONGOVERDUE SUMMARY ###"; |
445 |
summarize (\@report, 1); |
466 |
summarize( \@report, 1 ); |
446 |
print "\nTOTAL: $total items\n"; |
467 |
print "\nTOTAL: $total items\n"; |
447 |
} |
468 |
} |
448 |
|
469 |
|
449 |
cronlogaction({ action => 'End', info => "COMPLETED" }); |
470 |
cronlogaction( { action => 'End', info => "COMPLETED" } ); |
450 |
- |
|
|