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