|
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 |
- |
|
|