Lines 115-165
use Koha::Email;
Link Here
|
115 |
use Koha::StockRotationRotas; |
115 |
use Koha::StockRotationRotas; |
116 |
|
116 |
|
117 |
my $admin_email = ''; |
117 |
my $admin_email = ''; |
118 |
my $branch = 0; |
118 |
my $branch = 0; |
119 |
my $execute = 0; |
119 |
my $execute = 0; |
120 |
my $report = 'full'; |
120 |
my $report = 'full'; |
121 |
my $send_all = 0; |
121 |
my $send_all = 0; |
122 |
my $send_email = 0; |
122 |
my $send_email = 0; |
123 |
|
123 |
|
124 |
my $ok = GetOptions( |
124 |
my $ok = GetOptions( |
125 |
'admin-email|a=s' => \$admin_email, |
125 |
'admin-email|a=s' => \$admin_email, |
126 |
'branchcode|b=s' => sub { |
126 |
'branchcode|b=s' => sub { |
127 |
my ($opt_name, $opt_value) = @_; |
127 |
my ( $opt_name, $opt_value ) = @_; |
128 |
my $branches = Koha::Libraries->search( |
128 |
my $branches = Koha::Libraries->search( {}, |
129 |
{}, { order_by => { -asc => 'branchname'} } |
129 |
{ order_by => { -asc => 'branchname' } } ); |
130 |
); |
|
|
131 |
my $brnch = $branches->find($opt_value); |
130 |
my $brnch = $branches->find($opt_value); |
132 |
if ( $brnch ) { |
131 |
if ($brnch) { |
133 |
$branch = $brnch; |
132 |
$branch = $brnch; |
134 |
return $brnch; |
133 |
return $brnch; |
135 |
} else { |
134 |
} |
|
|
135 |
else { |
136 |
printf("Option $opt_name should be one of (name -> code):\n"); |
136 |
printf("Option $opt_name should be one of (name -> code):\n"); |
137 |
while ( my $candidate = $branches->next ) { |
137 |
while ( my $candidate = $branches->next ) { |
138 |
printf( |
138 |
printf( " %-40s -> %s\n", |
139 |
" %-40s -> %s\n", $candidate->branchname, |
139 |
$candidate->branchname, $candidate->branchcode ); |
140 |
$candidate->branchcode |
|
|
141 |
); |
142 |
} |
140 |
} |
143 |
exit 1 |
141 |
exit 1; |
144 |
} |
142 |
} |
145 |
}, |
143 |
}, |
146 |
'execute|x' => \$execute, |
144 |
'execute|x' => \$execute, |
147 |
'report|r=s' => sub { |
145 |
'report|r=s' => sub { |
148 |
my ($opt_name, $opt_value) = @_; |
146 |
my ( $opt_name, $opt_value ) = @_; |
149 |
if ( $opt_value eq 'full' || $opt_value eq 'email' ) { |
147 |
if ( $opt_value eq 'full' || $opt_value eq 'email' ) { |
150 |
$report = $opt_value; |
148 |
$report = $opt_value; |
151 |
} else { |
149 |
} |
|
|
150 |
else { |
152 |
printf("Option $opt_name should be either 'email' or 'full'.\n"); |
151 |
printf("Option $opt_name should be either 'email' or 'full'.\n"); |
153 |
exit 1; |
152 |
exit 1; |
154 |
} |
153 |
} |
155 |
}, |
154 |
}, |
156 |
'send-all|S' => \$send_all, |
155 |
'send-all|S' => \$send_all, |
157 |
'send-email|s' => \$send_email, |
156 |
'send-email|s' => \$send_email, |
158 |
'help|h|?' => sub { HelpMessage } |
157 |
'help|h|?' => sub { HelpMessage } |
159 |
); |
158 |
); |
160 |
exit 1 unless ( $ok ); |
159 |
exit 1 unless ($ok); |
161 |
|
160 |
|
162 |
$send_email++ if ( $send_all ); # if we send all, then we must want emails. |
161 |
$send_email++ if ($send_all); # if we send all, then we must want emails. |
163 |
|
162 |
|
164 |
=head2 Helpers |
163 |
=head2 Helpers |
165 |
|
164 |
|
Lines 177-195
This procedure WILL mess with your database.
Link Here
|
177 |
=cut |
176 |
=cut |
178 |
|
177 |
|
179 |
sub execute { |
178 |
sub execute { |
180 |
my ( $data ) = @_; |
179 |
my ($data) = @_; |
181 |
|
180 |
|
182 |
# Begin transaction |
181 |
# Begin transaction |
183 |
my $schema = Koha::Database->new->schema; |
182 |
my $schema = Koha::Database->new->schema; |
184 |
$schema->storage->txn_begin; |
183 |
$schema->storage->txn_begin; |
185 |
|
184 |
|
186 |
# Carry out db updates |
185 |
# Carry out db updates |
187 |
foreach my $item (@{$data->{items}}) { |
186 |
foreach my $item ( @{ $data->{items} } ) { |
188 |
my $reason = $item->{reason}; |
187 |
my $reason = $item->{reason}; |
189 |
if ( $reason eq 'repatriation' ) { |
188 |
if ( $reason eq 'repatriation' ) { |
190 |
$item->{object}->repatriate; |
189 |
$item->{object}->repatriate; |
191 |
} elsif ( grep { $reason eq $_ } |
190 |
} |
192 |
qw/in-demand advancement initiation/ ) { |
191 |
elsif ( grep { $reason eq $_ } qw/in-demand advancement initiation/ ) { |
193 |
$item->{object}->advance; |
192 |
$item->{object}->advance; |
194 |
} |
193 |
} |
195 |
} |
194 |
} |
Lines 212-221
No data in the database is manipulated by this procedure.
Link Here
|
212 |
=cut |
211 |
=cut |
213 |
|
212 |
|
214 |
sub report_full { |
213 |
sub report_full { |
215 |
my ( $data ) = @_; |
214 |
my ($data) = @_; |
216 |
|
215 |
|
217 |
my $header = ""; |
216 |
my $header = ""; |
218 |
my $body = ""; |
217 |
my $body = ""; |
|
|
218 |
|
219 |
# Summary |
219 |
# Summary |
220 |
$header .= sprintf " |
220 |
$header .= sprintf " |
221 |
STOCKROTATION REPORT |
221 |
STOCKROTATION REPORT |
Lines 231-266
STOCKROTATION REPORT
Link Here
|
231 |
Total items to be repatriated: %5u |
231 |
Total items to be repatriated: %5u |
232 |
Total items to be advanced: %5u |
232 |
Total items to be advanced: %5u |
233 |
Total items in demand: %5u\n\n", |
233 |
Total items in demand: %5u\n\n", |
234 |
$data->{sum_rotas}, $data->{rotas_inactive}, $data->{rotas_active}, |
234 |
$data->{sum_rotas}, $data->{rotas_inactive}, $data->{rotas_active}, |
235 |
$data->{sum_items}, $data->{items_inactive}, $data->{stationary}, |
235 |
$data->{sum_items}, $data->{items_inactive}, $data->{stationary}, |
236 |
$data->{actionable}, $data->{initiable}, $data->{repatriable}, |
236 |
$data->{actionable}, $data->{initiable}, $data->{repatriable}, |
237 |
$data->{advanceable}, $data->{indemand}; |
237 |
$data->{advanceable}, $data->{indemand}; |
238 |
|
238 |
|
239 |
if (@{$data->{rotas}}) { # Per Rota details |
239 |
if ( @{ $data->{rotas} } ) { # Per Rota details |
240 |
$body .= sprintf "ROTAS DETAIL\n------------\n\n"; |
240 |
$body .= sprintf "ROTAS DETAIL\n------------\n\n"; |
241 |
foreach my $rota (@{$data->{rotas}}) { |
241 |
foreach my $rota ( @{ $data->{rotas} } ) { |
242 |
$body .= sprintf "Details for %s [%s]:\n", |
242 |
$body .= sprintf "Details for %s [%s]:\n", |
243 |
$rota->{name}, $rota->{id}; |
243 |
$rota->{name}, $rota->{id}; |
244 |
$body .= sprintf "\n Items:"; # Rota item details |
244 |
$body .= sprintf "\n Items:"; # Rota item details |
245 |
if (@{$rota->{items}}) { |
245 |
if ( @{ $rota->{items} } ) { |
246 |
$body .= join("", map { _print_item($_) } @{$rota->{items}}); |
246 |
$body .= |
247 |
} else { |
247 |
join( "", map { _print_item($_) } @{ $rota->{items} } ); |
248 |
$body .= sprintf |
|
|
249 |
"\n No items to be processed for this rota.\n"; |
250 |
} |
248 |
} |
251 |
$body .= sprintf "\n Log:"; # Rota log details |
249 |
else { |
252 |
if (@{$rota->{log}}) { |
250 |
$body .= |
253 |
$body .= join("", map { _print_item($_) } @{$rota->{log}}); |
251 |
sprintf "\n No items to be processed for this rota.\n"; |
254 |
} else { |
252 |
} |
|
|
253 |
$body .= sprintf "\n Log:"; # Rota log details |
254 |
if ( @{ $rota->{log} } ) { |
255 |
$body .= join( "", map { _print_item($_) } @{ $rota->{log} } ); |
256 |
} |
257 |
else { |
255 |
$body .= sprintf "\n No items in log for this rota.\n\n"; |
258 |
$body .= sprintf "\n No items in log for this rota.\n\n"; |
256 |
} |
259 |
} |
257 |
} |
260 |
} |
258 |
} |
261 |
} |
259 |
return [ $header, { |
262 |
return [ |
260 |
body => $body, # The body of the report |
263 |
$header, |
261 |
status => 1, # We have a meaningful report |
264 |
{ |
262 |
no_branch_email => 1, # We don't expect branch email in report |
265 |
body => $body, # The body of the report |
263 |
} ]; |
266 |
status => 1, # We have a meaningful report |
|
|
267 |
no_branch_email => 1, # We don't expect branch email in report |
268 |
} |
269 |
]; |
264 |
} |
270 |
} |
265 |
|
271 |
|
266 |
=head3 report_email |
272 |
=head3 report_email |
Lines 282-314
No data in the database is manipulated by this procedure.
Link Here
|
282 |
sub report_email { |
288 |
sub report_email { |
283 |
my ( $data, $branch ) = @_; |
289 |
my ( $data, $branch ) = @_; |
284 |
|
290 |
|
285 |
my $out = []; |
291 |
my $out = []; |
286 |
my $header = ""; |
292 |
my $header = ""; |
|
|
293 |
|
287 |
# Summary |
294 |
# Summary |
288 |
my $branched = $data->{branched}; |
295 |
my $branched = $data->{branched}; |
289 |
my $flag = 0; |
296 |
my $flag = 0; |
290 |
|
297 |
|
291 |
$header .= sprintf " |
298 |
$header .= sprintf " |
292 |
BRANCH-BASED STOCKROTATION REPORT |
299 |
BRANCH-BASED STOCKROTATION REPORT |
293 |
---------------------------------\n"; |
300 |
---------------------------------\n"; |
294 |
push @{$out}, $header; |
301 |
push @{$out}, $header; |
295 |
|
302 |
|
296 |
if ( $branch ) { # Branch limited report |
303 |
if ($branch) { # Branch limited report |
297 |
push @{$out}, _report_per_branch( |
304 |
push @{$out}, _report_per_branch( $branched->{ $branch->branchcode } ); |
298 |
$branched->{$branch->branchcode}, $branch->branchcode, |
305 |
} |
299 |
$branch->branchname |
306 |
elsif ( $data->{actionable} ) { # Full email report |
300 |
); |
307 |
while ( my ( $branchcode_id, $details ) = each %{$branched} ) { |
301 |
} elsif ( $data->{actionable} ) { # Full email report |
308 |
push @{$out}, _report_per_branch($details) |
302 |
while ( my ($branchcode_id, $details) = each %{$branched} ) { |
309 |
if ( @{ $details->{items} } ); |
303 |
push @{$out}, _report_per_branch( |
|
|
304 |
$details, $details->{code}, $details->{name} |
305 |
) if ( @{$details->{items}} ); |
306 |
} |
310 |
} |
307 |
} else { |
311 |
} |
|
|
312 |
else { |
308 |
push @{$out}, { |
313 |
push @{$out}, { |
309 |
body => sprintf " |
314 |
body => sprintf " |
310 |
No actionable items at any libraries.\n\n", # The body of the report |
315 |
No actionable items at any libraries.\n\n", # The body of the report |
311 |
no_branch_email => 1, # We don't expect branch email in report |
316 |
no_branch_email => 1, # We don't expect branch email in report |
312 |
}; |
317 |
}; |
313 |
} |
318 |
} |
314 |
return $out; |
319 |
return $out; |
Lines 328-358
No data in the database is manipulated by this procedure.
Link Here
|
328 |
=cut |
333 |
=cut |
329 |
|
334 |
|
330 |
sub _report_per_branch { |
335 |
sub _report_per_branch { |
331 |
my ( $per_branch, $branchcode, $branchname ) = @_; |
336 |
my ($branch) = @_; |
332 |
|
337 |
|
333 |
my $out = ""; |
|
|
334 |
my $status = 0; |
338 |
my $status = 0; |
|
|
339 |
if ( $branch && @{ $branch->{items} } ) { |
340 |
$status = 1; |
341 |
} |
335 |
|
342 |
|
336 |
$out .= sprintf "\nStockrotation report for '%s' [%s]:\n", |
343 |
if ( |
337 |
$branchname || "N/A", $branchcode || "N/A"; |
344 |
my $letter = C4::Letters::GetPreparedLetter( |
338 |
if ( $per_branch && @{$per_branch->{items}} ) { |
345 |
module => 'circulation', |
339 |
$out .= sprintf " |
346 |
letter_code => "SR_SLIP", |
340 |
Email: %s |
347 |
message_transport_type => 'email', |
341 |
Phone: %s |
348 |
substitute => $branch |
342 |
Items:", |
349 |
) |
343 |
$per_branch->{email} || "N/A", $per_branch->{phone} || "N/A"; |
350 |
) |
344 |
$status++; |
351 |
{ |
345 |
} else { |
352 |
return { |
346 |
$out .= sprintf "No items to be processed for this branch.\n\n"; |
353 |
letter => $letter, |
|
|
354 |
email_address => $branch->{email}, |
355 |
$status |
356 |
}; |
347 |
} |
357 |
} |
348 |
$out .= join("", map { |
358 |
return; |
349 |
_print_item($_) unless $_->{reason} eq 'in-demand' |
|
|
350 |
} @{$per_branch->{items}}); |
351 |
return { |
352 |
body => $out, # The body of the report |
353 |
email_address => $per_branch->{email}, # The branch email address |
354 |
status => $status, # We may have empty report... |
355 |
}; |
356 |
} |
359 |
} |
357 |
|
360 |
|
358 |
=head3 _print_item |
361 |
=head3 _print_item |
Lines 369-375
No data in the database is manipulated by this procedure.
Link Here
|
369 |
=cut |
372 |
=cut |
370 |
|
373 |
|
371 |
sub _print_item { |
374 |
sub _print_item { |
372 |
my ( $item ) = @_; |
375 |
my ($item) = @_; |
373 |
return sprintf " |
376 |
return sprintf " |
374 |
Title: %s |
377 |
Title: %s |
375 |
Author: %s |
378 |
Author: %s |
Lines 379-389
sub _print_item {
Link Here
|
379 |
On loan?: %s |
382 |
On loan?: %s |
380 |
Status: %s |
383 |
Status: %s |
381 |
Current Library: %s [%s]\n\n", |
384 |
Current Library: %s [%s]\n\n", |
382 |
$item->{title} || "N/A", $item->{author} || "N/A", |
385 |
$item->{title} || "N/A", $item->{author} || "N/A", |
383 |
$item->{callnumber} || "N/A", $item->{location} || "N/A", |
386 |
$item->{callnumber} || "N/A", $item->{location} || "N/A", |
384 |
$item->{barcode} || "N/A", $item->{onloan} ? 'Yes' : 'No', |
387 |
$item->{barcode} || "N/A", $item->{onloan} ? 'Yes' : 'No', |
385 |
$item->{reason} || "N/A", $item->{branch}->branchname, |
388 |
$item->{reason} || "N/A", $item->{branch}->branchname, |
386 |
$item->{branch}->branchcode; |
389 |
$item->{branch}->branchcode; |
387 |
} |
390 |
} |
388 |
|
391 |
|
389 |
=head3 emit |
392 |
=head3 emit |
Lines 405-411
die.
Link Here
|
405 |
=cut |
408 |
=cut |
406 |
|
409 |
|
407 |
sub emit { |
410 |
sub emit { |
408 |
my ( $params ) = @_; |
411 |
my ($params) = @_; |
409 |
|
412 |
|
410 |
# REPORT is an arrayref of at least 2 elements: |
413 |
# REPORT is an arrayref of at least 2 elements: |
411 |
# - The header for the report, which will be repeated for each part |
414 |
# - The header for the report, which will be repeated for each part |
Lines 415-486
sub emit {
Link Here
|
415 |
# - part->{email_address}: the email address to send the report to |
418 |
# - part->{email_address}: the email address to send the report to |
416 |
my $report = $params->{report}; |
419 |
my $report = $params->{report}; |
417 |
my $header = shift @{$report}; |
420 |
my $header = shift @{$report}; |
418 |
my $parts = $report; |
421 |
my $parts = $report; |
419 |
|
422 |
|
420 |
foreach my $part (@{$parts}) { |
423 |
my @emails; |
421 |
# The final message is the header + body of this part. |
424 |
foreach my $part ( @{$parts} ) { |
422 |
my $msg = $header . $part->{body}; |
|
|
423 |
$msg .= "No database updates have been performed.\n\n" |
424 |
unless ( $params->{execute} ); |
425 |
|
426 |
if ( $params->{send_email} ) { # Only email if emails requested |
427 |
if ( $part->{status} || $params->{send_all} ) { |
428 |
# We have a report to send, or we want to send even empty |
429 |
# reports. |
430 |
my $message = Koha::Email->new; |
431 |
|
432 |
# Collate 'to' addresses |
433 |
my @to = (); |
434 |
if ( $part->{email_address} ) { |
435 |
push @to, $part->{email_address}; |
436 |
} elsif ( !$part->{no_branch_email} ) { |
437 |
$msg = "***We tried to send a branch report, but we have no email address for this branch.***\n\n" . $msg; |
438 |
push @to, C4::Context->preference('KohaAdminEmailAddress') |
439 |
if ( C4::Context->preference('KohaAdminEmailAddress') ); |
440 |
} |
441 |
push @to, $params->{admin_email} if $params->{admin_email}; |
442 |
|
425 |
|
443 |
# Create email data. |
426 |
if ( $part->{status} || $params->{send_all} ) { |
444 |
my %mail = $message->create_message_headers( |
427 |
|
445 |
{ |
428 |
# We have a report to send, or we want to send even empty |
446 |
to => join("; ", @to), |
429 |
# reports. |
447 |
subject => "Stockrotation Email Report", |
|
|
448 |
message => Encode::encode("utf8", $msg), |
449 |
contenttype => 'text/plain; charset="utf8"', |
450 |
} |
451 |
); |
452 |
|
430 |
|
453 |
# Send or die. |
431 |
# Send to branch |
454 |
die($Mail::Sendmail::error) |
432 |
my $addressee; |
455 |
unless Mail::Sendmail::sendmail(%mail); |
433 |
if ( $part->{email_address} ) { |
|
|
434 |
$addressee = $part->{email_address}; |
456 |
} |
435 |
} |
|
|
436 |
elsif ( !$part->{no_branch_email} ) { |
457 |
|
437 |
|
458 |
} else { # Else emit to stdout. |
438 |
#push @emails, "***We tried to send a branch report, but we have no email address for this branch.***\n\n"; |
459 |
printf $msg; |
439 |
$addressee = C4::Context->preference('KohaAdminEmailAddress') |
|
|
440 |
if ( C4::Context->preference('KohaAdminEmailAddress') ); |
441 |
} |
442 |
|
443 |
if ( $params->{send_email} ) { # Only email if emails requested |
444 |
C4::Letters::EnqueueLetter( |
445 |
{ |
446 |
letter => $part->{letter}, |
447 |
to_address => $addressee, |
448 |
from_address => |
449 |
C4::Context->preference('KohaAdminEmailAddress'), |
450 |
message_transport_type => 'email', |
451 |
} |
452 |
) |
453 |
or warn "can't enqueue letter $part->{letter} for $addressee"; |
454 |
|
455 |
# Copy to admin? |
456 |
if ( $params->{admin_email} ) { |
457 |
C4::Letters::EnqueueLetter( |
458 |
{ |
459 |
letter => $part->{letter}, |
460 |
to_address => $params->{admin_email}, |
461 |
from_address => |
462 |
C4::Context->preference('KohaAdminEmailAddress'), |
463 |
message_transport_type => 'email', |
464 |
} |
465 |
) |
466 |
or warn |
467 |
"can't enqueue letter $part->{letter} for $params->{admin_email}"; |
468 |
} |
469 |
} |
470 |
else { |
471 |
my $email = |
472 |
"-------- Email message --------" . "\n\n" |
473 |
. "From: " |
474 |
. C4::Context->preference('KohaAdminEmailAddress') . "\n" |
475 |
. "To: " |
476 |
. $addressee . "\n" |
477 |
. "Subject: " |
478 |
. $part->{letter}->{title} . "\n\n" |
479 |
. $part->{letter}->{content}; |
480 |
push @emails, $email; |
481 |
} |
460 |
} |
482 |
} |
461 |
} |
483 |
} |
|
|
484 |
|
485 |
# Emit to stdout instead of email? |
486 |
if ( !$params->{send_email} ) { |
487 |
|
488 |
# The final message is the header + body of this part. |
489 |
my $msg = $header; |
490 |
$msg .= "No database updates have been performed.\n\n" |
491 |
unless ( $params->{execute} ); |
492 |
|
493 |
# Append email reports to message |
494 |
$msg .= join( "\n\n", @emails ); |
495 |
printf $msg; |
496 |
} |
462 |
} |
497 |
} |
463 |
|
498 |
|
464 |
#### Main Code |
499 |
#### Main Code |
465 |
|
500 |
|
466 |
# Compile Stockrotation Report data |
501 |
# Compile Stockrotation Report data |
467 |
my $rotas = Koha::StockRotationRotas->search; |
502 |
my $rotas = Koha::StockRotationRotas->search; |
468 |
my $data = $rotas->investigate; |
503 |
my $data = $rotas->investigate; |
469 |
|
504 |
|
470 |
# Perform db updates if requested |
505 |
# Perform db updates if requested |
471 |
execute($data) if ( $execute ); |
506 |
execute($data) if ($execute); |
472 |
|
507 |
|
473 |
# Emit Reports |
508 |
# Emit Reports |
474 |
my $out_report = {}; |
509 |
my $out_report = {}; |
475 |
$out_report = report_email($data, $branch) if $report eq 'email'; |
510 |
$out_report = report_email( $data, $branch ) if $report eq 'email'; |
476 |
$out_report = report_full($data, $branch) if $report eq 'full'; |
511 |
$out_report = report_full( $data, $branch ) if $report eq 'full'; |
477 |
emit({ |
512 |
emit( |
478 |
admin_email => $admin_email, |
513 |
{ |
479 |
execute => $execute, |
514 |
admin_email => $admin_email, |
480 |
report => $out_report, |
515 |
execute => $execute, |
481 |
send_all => $send_all, |
516 |
report => $out_report, |
482 |
send_email => $send_email, |
517 |
send_all => $send_all, |
483 |
}); |
518 |
send_email => $send_email, |
|
|
519 |
} |
520 |
); |
484 |
|
521 |
|
485 |
=head1 AUTHOR |
522 |
=head1 AUTHOR |
486 |
|
523 |
|
487 |
- |
|
|