View | Details | Raw Unified | Return to bug 11897
Collapse All | Expand All

(-)a/misc/cronjobs/stockrotation.pl (-144 / +180 lines)
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
- 

Return to bug 11897