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

(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/letter.tt (-2 lines)
Lines 340-347 Link Here
340
        </div>
340
        </div>
341
        [% END %]
341
        [% END %]
342
342
343
        [% IF code.search('DGST') %] <span class="overdue">Warning, this is a template for a Digest, as such, any references to branch data ( e.g. branches.branchname ) will refer to the borrower's home branch.</span> [% END %]
344
345
        <input type="hidden" id="redirect" name="redirect" value="" />
343
        <input type="hidden" id="redirect" name="redirect" value="" />
346
        <input type="hidden" name="searchfield" value="[% searchfield %]" />
344
        <input type="hidden" name="searchfield" value="[% searchfield %]" />
347
    </form>
345
    </form>
(-)a/misc/cronjobs/advance_notices.pl (-38 / +93 lines)
Lines 174-179 my $nomail; # -n: No mai Link Here
174
my $mindays     = 0;                                                # -m: Maximum number of days in advance to send notices
174
my $mindays     = 0;                                                # -m: Maximum number of days in advance to send notices
175
my $maxdays     = 30;                                               # -e: the End of the time period
175
my $maxdays     = 30;                                               # -e: the End of the time period
176
my $verbose     = 0;                                                # -v: verbose
176
my $verbose     = 0;                                                # -v: verbose
177
my $digest_per_branch = 0;                                          # -digest-per-branch: Prepare and send digests per branch
177
my $itemscontent = join(',',qw( date_due title author barcode ));
178
my $itemscontent = join(',',qw( date_due title author barcode ));
178
179
179
my $help    = 0;
180
my $help    = 0;
Lines 186-191 GetOptions( Link Here
186
            'n'              => \$nomail,
187
            'n'              => \$nomail,
187
            'm:i'            => \$maxdays,
188
            'm:i'            => \$maxdays,
188
            'v'              => \$verbose,
189
            'v'              => \$verbose,
190
            'digest-per-branch' => \$digest_per_branch,
189
            'itemscontent=s' => \$itemscontent,
191
            'itemscontent=s' => \$itemscontent,
190
       )or pod2usage(2);
192
       )or pod2usage(2);
191
pod2usage(1) if $help;
193
pod2usage(1) if $help;
Lines 218-225 warn 'found ' . scalar( @$upcoming_dues ) . ' issues' if $verbose; Link Here
218
220
219
# hash of borrowernumber to number of items upcoming
221
# hash of borrowernumber to number of items upcoming
220
# for patrons wishing digests only.
222
# for patrons wishing digests only.
221
my $upcoming_digest;
223
my $upcoming_digest = {};
222
my $due_digest;
224
my $due_digest = {};
223
225
224
my $dbh = C4::Context->dbh();
226
my $dbh = C4::Context->dbh();
225
my $sth = $dbh->prepare(<<'END_SQL');
227
my $sth = $dbh->prepare(<<'END_SQL');
Lines 250-257 UPCOMINGITEM: foreach my $upcoming ( @$upcoming_dues ) { Link Here
250
        
252
        
251
        if ( $borrower_preferences->{'wants_digest'} ) {
253
        if ( $borrower_preferences->{'wants_digest'} ) {
252
            # cache this one to process after we've run through all of the items.
254
            # cache this one to process after we've run through all of the items.
253
            $due_digest->{ $upcoming->{borrowernumber} }->{email} = $from_address;
255
            if ($digest_per_branch) {
254
            $due_digest->{ $upcoming->{borrowernumber} }->{count}++;
256
                $due_digest->{ $upcoming->{branchcode} }->{ $upcoming->{borrowernumber} }->{email} = $from_address;
257
                $due_digest->{ $upcoming->{branchcode} }->{ $upcoming->{borrowernumber} }->{count}++;
258
            } else {
259
                $due_digest->{ $upcoming->{borrowernumber} }->{email} = $from_address;
260
                $due_digest->{ $upcoming->{borrowernumber} }->{count}++;
261
            }
255
        } else {
262
        } else {
256
            my $item = Koha::Items->find( $upcoming->{itemnumber} );
263
            my $item = Koha::Items->find( $upcoming->{itemnumber} );
257
            my $letter_type = 'DUE';
264
            my $letter_type = 'DUE';
Lines 283-290 UPCOMINGITEM: foreach my $upcoming ( @$upcoming_dues ) { Link Here
283
290
284
        if ( $borrower_preferences->{'wants_digest'} ) {
291
        if ( $borrower_preferences->{'wants_digest'} ) {
285
            # cache this one to process after we've run through all of the items.
292
            # cache this one to process after we've run through all of the items.
286
            $upcoming_digest->{ $upcoming->{borrowernumber} }->{email} = $from_address;
293
            if ($digest_per_branch) {
287
            $upcoming_digest->{ $upcoming->{borrowernumber} }->{count}++;
294
                $upcoming_digest->{ $upcoming->{branchcode} }->{ $upcoming->{borrowernumber} }->{email} = $from_address;
295
                $upcoming_digest->{ $upcoming->{branchcode} }->{ $upcoming->{borrowernumber} }->{count}++;
296
            } else {
297
                $upcoming_digest->{ $upcoming->{borrowernumber} }->{email} = $from_address;
298
                $upcoming_digest->{ $upcoming->{borrowernumber} }->{count}++;
299
            }
288
        } else {
300
        } else {
289
            my $item = Koha::Items->find( $upcoming->{itemnumber} );
301
            my $item = Koha::Items->find( $upcoming->{itemnumber} );
290
            my $letter_type = 'PREDUE';
302
            my $letter_type = 'PREDUE';
Lines 342-373 SELECT biblio.*, items.*, issues.* Link Here
342
    AND (TO_DAYS(date_due)-TO_DAYS(NOW()) = ?)
354
    AND (TO_DAYS(date_due)-TO_DAYS(NOW()) = ?)
343
END_SQL
355
END_SQL
344
356
345
send_digests({
357
if ($digest_per_branch) {
346
    sth => $sth_digest,
358
    while (my ($branchcode, $digests) = each %$upcoming_digest) {
347
    digests => $upcoming_digest,
359
        send_digests({
348
    letter_code => 'PREDUEDGST',
360
            sth => $sth_digest,
349
    get_item_info => sub {
361
            digests => $digests,
350
        my $params = shift;
362
            letter_code => 'PREDUEDGST',
351
        $params->{sth}->execute($params->{borrowernumber},
363
            branchcode => $branchcode,
352
                      $params->{borrower_preferences}->{'days_in_advance'});
364
            get_item_info => sub {
353
        return sub {
365
                my $params = shift;
354
            $params->{sth}->fetchrow_hashref;
366
                $params->{sth}->execute($params->{borrowernumber},
355
        };
367
                                        $params->{borrower_preferences}->{'days_in_advance'});
368
                return sub {
369
                    $params->{sth}->fetchrow_hashref;
370
                };
371
            }
372
        });
356
    }
373
    }
357
});
374
358
375
    while (my ($branchcode, $digests) = each %$due_digest) {
359
send_digests({
376
        send_digests({
360
    sth => $sth_digest,
377
            sth => $sth_digest,
361
    digest => $due_digest,
378
            digest => $due_digest,
362
    letter_code => 'DUEGST',
379
            letter_code => 'DUEGST',
363
    get_item_info => sub {
380
            branchcode => $branchcode,
364
        my $params = shift;
381
            get_item_info => sub {
365
        $params->{sth}->execute($params->{borrowernumber}, 0);
382
                my $params = shift;
366
        return sub {
383
                $params->{sth}->execute($params->{borrowernumber}, 0);
367
            $params->{sth}->fetchrow_hashref;
384
                return sub {
368
        };
385
                    $params->{sth}->fetchrow_hashref;
386
                };
387
            }
388
        });
369
    }
389
    }
370
});
390
} else {
391
    send_digests({
392
        sth => $sth_digest,
393
        digests => $upcoming_digest,
394
        letter_code => 'PREDUEDGST',
395
        get_item_info => sub {
396
            my $params = shift;
397
            $params->{sth}->execute($params->{borrowernumber},
398
                                    $params->{borrower_preferences}->{'days_in_advance'});
399
            return sub {
400
                $params->{sth}->fetchrow_hashref;
401
            };
402
        }
403
    });
404
405
    send_digests({
406
        sth => $sth_digest,
407
        digest => $due_digest,
408
        letter_code => 'DUEGST',
409
        get_item_info => sub {
410
            my $params = shift;
411
            $params->{sth}->execute($params->{borrowernumber}, 0);
412
            return sub {
413
                $params->{sth}->fetchrow_hashref;
414
            };
415
        }
416
    });
417
}
371
418
372
=head1 METHODS
419
=head1 METHODS
373
420
Lines 471-476 sub send_digests { Link Here
471
        my $count = $digest->{count};
518
        my $count = $digest->{count};
472
        my $from_address = $digest->{email};
519
        my $from_address = $digest->{email};
473
520
521
        my %branch_info;
522
        my $branchcode;
523
524
        if (defined($params->{branchcode})) {
525
            %branch_info = ();
526
            $branchcode = $params->{branchcode};
527
        } else {
528
            ## Get branch info for borrowers home library.
529
            %branch_info = get_branch_info( $borrowernumber );
530
            $branchcode = $branch_info{'branches.branchcode'};
531
        }
532
474
        my $borrower_preferences =
533
        my $borrower_preferences =
475
            C4::Members::Messaging::GetMessagingPreferences(
534
            C4::Members::Messaging::GetMessagingPreferences(
476
                {
535
                {
Lines 491-499 sub send_digests { Link Here
491
            $titles .= C4::Letters::get_item_content( { item => $item_info, item_content_fields => \@item_content_fields } );
550
            $titles .= C4::Letters::get_item_content( { item => $item_info, item_content_fields => \@item_content_fields } );
492
        }
551
        }
493
552
494
        ## Get branch info for borrowers home library.
495
        my %branch_info = get_branch_info( $borrowernumber );
496
497
        foreach my $transport ( keys %{ $borrower_preferences->{'transports'} } ) {
553
        foreach my $transport ( keys %{ $borrower_preferences->{'transports'} } ) {
498
            my $letter = parse_letter(
554
            my $letter = parse_letter(
499
                {
555
                {
Lines 502-514 sub send_digests { Link Here
502
                    substitute     => {
558
                    substitute     => {
503
                        count           => $count,
559
                        count           => $count,
504
                        'items.content' => $titles,
560
                        'items.content' => $titles,
505
                        %branch_info,
561
                        %branch_info
506
                    },
562
                    },
507
                    branchcode             => $branch_info{"branches.branchcode"},
563
                    branchcode     => $branchcode,
508
                    message_transport_type => $transport,
564
                    message_transport_type => $transport
509
                }
565
                }
510
                )
566
            ) || warn "no letter of type '$params->{letter_type}' found for borrowernumber $borrowernumber. Please see sample_notices.sql";
511
                or warn "no letter of type '$params->{letter_type}' found for borrowernumber $borrowernumber. Please see sample_notices.sql";
512
            push @letters, $letter if $letter;
567
            push @letters, $letter if $letter;
513
        }
568
        }
514
569
(-)a/t/db_dependent/cronjobs/advance_notices_digest.t (-117 / +194 lines)
Lines 19-25 Link Here
19
19
20
use Modern::Perl;
20
use Modern::Perl;
21
21
22
use Test::More tests => 3;
22
use Test::More tests => 8;
23
use t::lib::TestBuilder;
23
use t::lib::TestBuilder;
24
use DateTime;
24
use DateTime;
25
use File::Spec;
25
use File::Spec;
Lines 30-184 my $scriptDir = dirname(File::Spec->rel2abs( __FILE__ )); Link Here
30
30
31
my $dbh = C4::Context->dbh;
31
my $dbh = C4::Context->dbh;
32
32
33
# Set only to avoid exception.
33
my $library1;
34
$ENV{"OVERRIDE_SYSPREF_dateformat"} = 'metric';
34
my $library2;
35
35
my $library3;
36
$dbh->{AutoCommit} = 0;
36
my $borrower;
37
$dbh->{RaiseError} = 1;
37
38
38
sub build_test_objects {
39
my $builder = t::lib::TestBuilder->new;
39
    $dbh->{AutoCommit} = 0;
40
40
    $dbh->{RaiseError} = 1;
41
my $library1 = $builder->build({
41
42
    source => 'Branch',
42
    # Set only to avoid exception.
43
});
43
    $ENV{"OVERRIDE_SYSPREF_dateformat"} = 'metric';
44
my $library2 = $builder->build({
44
45
    source => 'Branch',
45
    my $builder = t::lib::TestBuilder->new;
46
});
46
47
my $library3 = $builder->build({
47
    $library1 = $builder->build({
48
    source => 'Branch',
48
        source => 'Branch',
49
});
49
    });
50
my $borrower = $builder->build({
50
    $library2 = $builder->build({
51
    source => 'Borrower',
51
        source => 'Branch',
52
    value => {
52
    });
53
        branchcode => $library1->{branchcode},
53
    $library3 = $builder->build({
54
    }
54
        source => 'Branch',
55
});
55
    });
56
$dbh->do(<<DELETESQL);
56
    $borrower = $builder->build({
57
        source => 'Borrower',
58
        value => {
59
            branchcode => $library1->{branchcode},
60
        }
61
    });
62
    $dbh->do(<<DELETESQL);
57
DELETE FROM letter
63
DELETE FROM letter
58
 WHERE module='circulation'
64
 WHERE module='circulation'
59
   AND code = 'PREDUEDGST'
65
   AND code = 'PREDUEDGST'
60
   AND message_transport_type='email'
66
   AND message_transport_type='email'
61
   AND branchcode=''
67
   AND branchcode=''
62
DELETESQL
68
DELETESQL
63
$dbh->do(<<DELETESQL);
69
70
    $dbh->do(<<DELETESQL);
64
DELETE FROM message_attributes WHERE message_name = 'Advance_Notice'
71
DELETE FROM message_attributes WHERE message_name = 'Advance_Notice'
65
DELETESQL
72
DELETESQL
66
73
67
my $message_attribute = $builder->build({
74
    my $message_attribute = $builder->build({
68
    source => 'MessageAttribute',
75
        source => 'MessageAttribute',
69
    value => {
76
        value => {
70
        message_name => 'Advance_Notice'
77
            message_name => 'Advance_Notice'
71
    }
78
        }
72
});
79
    });
73
74
my $letter = $builder->build({
75
    source => 'Letter',
76
    value => {
77
        module => 'circulation',
78
        code => 'PREDUEDGST',
79
        branchcode => '',
80
        message_transport_type => 'email',
81
        lang => 'default',
82
        is_html => 0,
83
        content => '<<count>> <<branches.branchname>>'
84
    }
85
});
86
my $borrower_message_preference = $builder->build({
87
    source => 'BorrowerMessagePreference',
88
    value => {
89
        borrowernumber => $borrower->{borrowernumber},
90
        wants_digest => 1,
91
        days_in_advance => 1,
92
        message_attribute_id => $message_attribute->{message_attribute_id}
93
    }
94
});
95
80
96
my $borrower_message_transport_preference = $builder->build({
81
    my $letter = $builder->build({
97
    source => 'BorrowerMessageTransportPreference',
82
        source => 'Letter',
98
    value => {
83
        value => {
99
        borrower_message_preference_id => $borrower_message_preference->{borrower_message_preference_id},
84
            module => 'circulation',
100
        message_transport_type => 'email'
85
            code => 'PREDUEDGST',
101
    }
86
            branchcode => '',
102
});
87
            message_transport_type => 'email',
103
88
            lang => 'default',
104
my $biblio = $builder->build({
89
            is_html => 0,
105
    source => 'Biblio',
90
            content => '<<count>> <<branches.branchname>>'
106
});
91
        }
107
my $biblioitem = $builder->build({
92
    });
108
    source => 'Biblioitem',
93
    my $borrower_message_preference = $builder->build({
109
    value => {
94
        source => 'BorrowerMessagePreference',
110
        biblionumber => $biblio->{biblionumber}
95
        value => {
111
    }
96
            borrowernumber => $borrower->{borrowernumber},
112
});
97
            wants_digest => 1,
113
my $item1 = $builder->build({
98
            days_in_advance => 1,
114
    source => 'Item'
99
            message_attribute_id => $message_attribute->{message_attribute_id}
115
});
100
        }
116
my $item2 = $builder->build({
101
    });
117
    source => 'Item'
102
118
});
103
    my $borrower_message_transport_preference = $builder->build({
119
my $now = DateTime->now();
104
        source => 'BorrowerMessageTransportPreference',
120
my $tomorrow = $now->add(days => 1)->strftime('%F');
105
        value => {
121
106
            borrower_message_preference_id => $borrower_message_preference->{borrower_message_preference_id},
122
my $issue1 = $builder->build({
107
            message_transport_type => 'email'
123
    source => 'Issue',
108
        }
124
    value => {
109
    });
125
        date_due => $tomorrow,
126
        itemnumber => $item1->{itemnumber},
127
        branchcode => $library1->{branchcode},
128
        borrowernumber => $borrower->{borrowernumber},
129
        returndate => undef
130
    }
131
});
132
133
my $issue2 = $builder->build({
134
    source => 'Issue',
135
    value => {
136
        date_due => $tomorrow,
137
        itemnumber => $item2->{itemnumber},
138
        branchcode => $library2->{branchcode},
139
        branchcode => $library3->{branchcode},
140
        borrowernumber => $borrower->{borrowernumber},
141
        returndate => undef
142
    }
143
});
144
110
145
C4::Context->set_preference('EnhancedMessagingPreferences', 1);
111
    my $biblio = $builder->build({
112
        source => 'Biblio',
113
    });
114
    my $biblioitem = $builder->build({
115
        source => 'Biblioitem',
116
        value => {
117
            biblionumber => $biblio->{biblionumber}
118
        }
119
    });
120
    my $item1 = $builder->build({
121
        source => 'Item'
122
    });
123
    my $item2 = $builder->build({
124
        source => 'Item'
125
    });
126
    my $item3 = $builder->build({
127
        source => 'Item'
128
    });
129
    my $now = DateTime->now();
130
    my $tomorrow = $now->add(days => 1)->strftime('%F');
146
131
147
my $script = '';
132
    my $issue1 = $builder->build({
133
        source => 'Issue',
134
        value => {
135
            date_due => $tomorrow,
136
            itemnumber => $item1->{itemnumber},
137
            branchcode => $library2->{branchcode},
138
            borrowernumber => $borrower->{borrowernumber},
139
            returndate => undef
140
        }
141
    });
142
143
    my $issue2 = $builder->build({
144
        source => 'Issue',
145
        value => {
146
            date_due => $tomorrow,
147
            itemnumber => $item2->{itemnumber},
148
            branchcode => $library3->{branchcode},
149
            borrowernumber => $borrower->{borrowernumber},
150
            returndate => undef
151
        }
152
                                 });
153
    my $issue3 = $builder->build({
154
        source => 'Issue',
155
        value => {
156
            date_due => $tomorrow,
157
            itemnumber => $item3->{itemnumber},
158
            branchcode => $library3->{branchcode},
159
            borrowernumber => $borrower->{borrowernumber},
160
            returndate => undef
161
        }
162
    });
163
164
    C4::Context->set_preference('EnhancedMessagingPreferences', 1);
165
}
166
167
sub run_script {
168
    my $script = shift;
169
    local @ARGV = @_;
170
171
    ## no critic
172
173
    # We simulate script execution by evaluating the script code in the context
174
    # of this unit test.
175
176
    eval $script; #Violates 'ProhibitStringyEval'
177
178
    ## use critic
179
180
    die $@ if $@;
181
}
182
183
my $scriptContent = '';
148
my $scriptFile = "$scriptDir/../../../misc/cronjobs/advance_notices.pl";
184
my $scriptFile = "$scriptDir/../../../misc/cronjobs/advance_notices.pl";
149
open my $scriptfh, "<", $scriptFile or die "Failed to open $scriptFile: $!";
185
open my $scriptfh, "<", $scriptFile or die "Failed to open $scriptFile: $!";
150
186
151
while (<$scriptfh>) {
187
while (<$scriptfh>) {
152
    $script .= $_;
188
    $scriptContent .= $_;
153
}
189
}
154
close $scriptfh;
190
close $scriptfh;
155
191
156
@ARGV = ('advanced_notices.pl', '-c');
192
my $sthmq = $dbh->prepare('SELECT * FROM message_queue WHERE borrowernumber = ?');
157
158
## no critic
159
160
# We simulate script execution by evaluating the script code in the context
161
# of this unit test.
162
193
163
eval $script; #Violates 'ProhibitStringyEval'
194
#
195
# Test default behavior
196
#
164
197
165
## use critic
198
build_test_objects();
166
199
167
die $@ if $@;
200
run_script($scriptContent, 'advanced_notices.pl', '-c');
168
201
169
my $sthmq = $dbh->prepare('SELECT * FROM message_queue WHERE borrowernumber = ?');
170
$sthmq->execute($borrower->{borrowernumber});
202
$sthmq->execute($borrower->{borrowernumber});
171
203
172
my $messages = $sthmq->fetchall_hashref('message_id');
204
my $messages = $sthmq->fetchall_hashref('message_id');
173
205
174
is(scalar(keys %$messages), 1, 'There is one message in the queue');
206
is(scalar(keys %$messages), 1, 'There is one message in the queue');
207
175
for my $message (keys %$messages) {
208
for my $message (keys %$messages) {
176
    $messages->{$message}->{content} =~ /(\d+) (.*)/;
209
    $messages->{$message}->{content} =~ /(\d+) (.*)/;
177
    my $count = $1;
210
    my $count = $1;
178
    my $branchname = $2;
211
    my $branchname = $2;
179
212
180
    is ($count, '2', 'Issue count is 2');
213
    is ($count, '3', 'Issue count is 3');
181
    is ($branchname, $library1->{branchname}, 'Branchname is that of borrowers home branch.');
214
    is ($branchname, $library1->{branchname}, 'Branchname is that of borrowers home branch.');
182
}
215
}
183
216
184
$dbh->rollback;
217
$dbh->rollback;
185
- 
218
219
#
220
# Test -digest-per-branch
221
#
222
223
build_test_objects();
224
225
run_script($scriptContent, 'advanced_notices.pl', '-c', '-digest-per-branch');
226
227
$sthmq->execute($borrower->{borrowernumber});
228
229
$messages = $sthmq->fetchall_hashref('message_id');
230
231
is(scalar(keys %$messages), 2, 'There are two messages in the queue');
232
233
my %expected = (
234
    $library2->{branchname} => {
235
        count => 1,
236
    },
237
    $library3->{branchname} => {
238
        count => 2,
239
    }
240
 );
241
242
my %expected_branchnames = (
243
    $library2->{branchname} => 1,
244
    $library3->{branchname} => 1
245
);
246
247
my $i = 0;
248
for my $message (keys %$messages) {
249
    $messages->{$message}->{content} =~ /(\d+) (.*)/;
250
    my $count = $1;
251
    my $branchname = $2;
252
253
    ok ($expected_branchnames{$branchname}, 'Branchname is that of expected issuing branch.');
254
255
    $expected_branchnames{$branchname} = 0;
256
257
    is ($count, $expected{$branchname}->{count}, 'Issue count is ' . $expected{$branchname}->{count});
258
259
    $i++;
260
}
261
262
$dbh->rollback;

Return to bug 20478