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

(-)a/Koha/CirculationRules.pm (+3 lines)
Lines 79-84 our $RULE_KINDS = { Link Here
79
    cap_fine_to_replacement_price => {
79
    cap_fine_to_replacement_price => {
80
        scope => [ 'branchcode', 'categorycode', 'itemtype' ],
80
        scope => [ 'branchcode', 'categorycode', 'itemtype' ],
81
    },
81
    },
82
    expire_reserves_charge => {
83
        scope => [ 'branchcode', 'categorycode', 'itemtype' ],
84
    },
82
    chargeperiod => {
85
    chargeperiod => {
83
        scope => [ 'branchcode', 'categorycode', 'itemtype' ],
86
        scope => [ 'branchcode', 'categorycode', 'itemtype' ],
84
    },
87
    },
(-)a/Koha/Hold.pm (-1 / +21 lines)
Lines 371-378 sub cancel { Link Here
371
            # now fix the priority on the others....
371
            # now fix the priority on the others....
372
            C4::Reserves::_FixPriority({ biblionumber => $self->biblionumber });
372
            C4::Reserves::_FixPriority({ biblionumber => $self->biblionumber });
373
373
374
            my $item = $self->item;
375
376
            my $controlbranch = C4::Context->preference('ReservesControlBranch');
377
            my $branchcode  = undef;
378
            if ( $item && $controlbranch eq "ItemHomeLibrary" ) {
379
                $branchcode  = $item->homebranch;
380
            }
381
            elsif ( $controlbranch eq "PatronLibrary" ) {
382
                $branchcode  = $self->borrower->branchcode;
383
            }
384
385
            my $rule = Koha::CirculationRules->get_effective_rule(
386
                {
387
                    categorycode => $self->borrower->categorycode,
388
                    itemtype     => $item ? $item->effective_itemtype : $self->biblio->itemtype,
389
                    branchcode   => $branchcode,
390
                    rule_name    => 'expire_reserves_charge',
391
                }
392
            );
374
            # and, if desired, charge a cancel fee
393
            # and, if desired, charge a cancel fee
375
            my $charge = C4::Context->preference("ExpireReservesMaxPickUpDelayCharge");
394
            my $charge = $rule && $rule->rule_value // C4::Context->preference("ExpireReservesMaxPickUpDelayCharge");
395
376
            if ( $charge && $params->{'charge_cancel_fee'} ) {
396
            if ( $charge && $params->{'charge_cancel_fee'} ) {
377
                my $account =
397
                my $account =
378
                  Koha::Account->new( { patron_id => $self->borrowernumber } );
398
                  Koha::Account->new( { patron_id => $self->borrowernumber } );
(-)a/admin/smart-rules.pl (+3 lines)
Lines 111-116 if ($op eq 'delete') { Link Here
111
                opacitemholds                    => undef,
111
                opacitemholds                    => undef,
112
                overduefinescap                  => undef,
112
                overduefinescap                  => undef,
113
                cap_fine_to_replacement_price    => undef,
113
                cap_fine_to_replacement_price    => undef,
114
                expire_reserves_charge           => undef,
114
                article_requests                 => undef,
115
                article_requests                 => undef,
115
                note                             => undef,
116
                note                             => undef,
116
            }
117
            }
Lines 288-293 elsif ($op eq 'add') { Link Here
288
    my $article_requests = $input->param('article_requests') || 'no';
289
    my $article_requests = $input->param('article_requests') || 'no';
289
    my $overduefinescap = $input->param('overduefinescap') || '';
290
    my $overduefinescap = $input->param('overduefinescap') || '';
290
    my $cap_fine_to_replacement_price = ($input->param('cap_fine_to_replacement_price') || '') eq 'on';
291
    my $cap_fine_to_replacement_price = ($input->param('cap_fine_to_replacement_price') || '') eq 'on';
292
    my $expire_reserves_charge = $input->param('expire_reserves_charge') // '';
291
    my $note = $input->param('note');
293
    my $note = $input->param('note');
292
    $debug and warn "Adding $br, $bor, $itemtype, $fine, $maxissueqty, $maxonsiteissueqty, $cap_fine_to_replacement_price";
294
    $debug and warn "Adding $br, $bor, $itemtype, $fine, $maxissueqty, $maxonsiteissueqty, $cap_fine_to_replacement_price";
293
295
Lines 320-325 elsif ($op eq 'add') { Link Here
320
        opacitemholds                 => $opacitemholds,
322
        opacitemholds                 => $opacitemholds,
321
        overduefinescap               => $overduefinescap,
323
        overduefinescap               => $overduefinescap,
322
        cap_fine_to_replacement_price => $cap_fine_to_replacement_price,
324
        cap_fine_to_replacement_price => $cap_fine_to_replacement_price,
325
        expire_reserves_charge        => $expire_reserves_charge,
323
        article_requests              => $article_requests,
326
        article_requests              => $article_requests,
324
        note                          => $note,
327
        note                          => $note,
325
    };
328
    };
(-)a/installer/data/mysql/updatedatabase.pl (+1 lines)
Lines 20696-20701 if( CheckVersion( $DBversion ) ) { Link Here
20696
        auto_renew
20696
        auto_renew
20697
        no_auto_renewal_after
20697
        no_auto_renewal_after
20698
        no_auto_renewal_after_hard_limit
20698
        no_auto_renewal_after_hard_limit
20699
        expire_reserves_charge
20699
        reservesallowed
20700
        reservesallowed
20700
        holds_per_record
20701
        holds_per_record
20701
        holds_per_day
20702
        holds_per_day
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt (-3 / +14 lines)
Lines 102-107 Link Here
102
                <th>Fine grace period</th>
102
                <th>Fine grace period</th>
103
                <th>Overdue fines cap (amount)</th>
103
                <th>Overdue fines cap (amount)</th>
104
                <th>Cap fine at replacement price</th>
104
                <th>Cap fine at replacement price</th>
105
                <th>Expire reserve charge</th>
105
                <th>Suspension in days (day)</th>
106
                <th>Suspension in days (day)</th>
106
                <th>Max. suspension duration (day)</th>
107
                <th>Max. suspension duration (day)</th>
107
                <th>Suspension charging interval</th>
108
                <th>Suspension charging interval</th>
Lines 141-146 Link Here
141
                        [% SET firstremind = all_rules.$c.$i.firstremind %]
142
                        [% SET firstremind = all_rules.$c.$i.firstremind %]
142
                        [% SET overduefinescap = all_rules.$c.$i.overduefinescap %]
143
                        [% SET overduefinescap = all_rules.$c.$i.overduefinescap %]
143
                        [% SET cap_fine_to_replacement_price = all_rules.$c.$i.cap_fine_to_replacement_price %]
144
                        [% SET cap_fine_to_replacement_price = all_rules.$c.$i.cap_fine_to_replacement_price %]
145
                        [% SET expire_reserves_charge = all_rules.$c.$i.expire_reserves_charge %]
144
                        [% SET finedays = all_rules.$c.$i.finedays %]
146
                        [% SET finedays = all_rules.$c.$i.finedays %]
145
                        [% SET maxsuspensiondays = all_rules.$c.$i.maxsuspensiondays %]
147
                        [% SET maxsuspensiondays = all_rules.$c.$i.maxsuspensiondays %]
146
                        [% SET suspension_chargeperiod = all_rules.$c.$i.suspension_chargeperiod %]
148
                        [% SET suspension_chargeperiod = all_rules.$c.$i.suspension_chargeperiod %]
Lines 158-164 Link Here
158
                        [% SET article_requests = all_rules.$c.$i.article_requests %]
160
                        [% SET article_requests = all_rules.$c.$i.article_requests %]
159
                        [% SET rentaldiscount = all_rules.$c.$i.rentaldiscount %]
161
                        [% SET rentaldiscount = all_rules.$c.$i.rentaldiscount %]
160
162
161
                        [% SET show_rule = note || maxissueqty || maxonsiteissueqty || issuelength || daysmode || lengthunit || hardduedate || hardduedatecompare || fine || chargeperiod || chargeperiod_charge_at || firstremind || overduefinescap || cap_fine_to_replacement_price || finedays || maxsuspensiondays || suspension_chargeperiod || renewalsallowed || renewalperiod || norenewalbefore || auto_renew || no_auto_renewal_after || no_auto_renewal_after_hard_limit || reservesallowed || holds_per_day || holds_per_record || onshelfholds || opacitemholds || article_requests || rentaldiscount %]
163
                        [% SET show_rule = note || maxissueqty || maxonsiteissueqty || issuelength || daysmode || lengthunit || hardduedate || hardduedatecompare || fine || chargeperiod || chargeperiod_charge_at || firstremind || overduefinescap || cap_fine_to_replacement_price || expire_reserves_charge || finedays || maxsuspensiondays || suspension_chargeperiod || renewalsallowed || renewalperiod || norenewalbefore || auto_renew || no_auto_renewal_after || no_auto_renewal_after_hard_limit || reservesallowed || holds_per_day || holds_per_record || onshelfholds || opacitemholds || article_requests || rentaldiscount %]
162
                        [% IF show_rule %]
164
                        [% IF show_rule %]
163
                            [% SET row_count = row_count + 1 %]
165
                            [% SET row_count = row_count + 1 %]
164
                            <tr row_countd="row_[% row_count | html %]">
166
                            <tr row_countd="row_[% row_count | html %]">
Lines 246-251 Link Here
246
                                            <input type="checkbox" disabled="disabled" />
248
                                            <input type="checkbox" disabled="disabled" />
247
                                        [% END %]
249
                                        [% END %]
248
                                    </td>
250
                                    </td>
251
                                    <td>
252
                                        [% UNLESS expire_reserves_charge %]
253
                                            <a href="/cgi-bin/koha/admin/preferences.pl?op=search&amp;searchfield=ExpireReservesMaxPickUpDelayCharge">Use global</a>
254
                                        [% ELSE %]
255
                                            [% expire_reserves_charge | html %]
256
                                        [% END %]
257
                                    </td>
249
                                    <td>[% finedays | html %]</td>
258
                                    <td>[% finedays | html %]</td>
250
                                    <td>[% maxsuspensiondays | html %]</td>
259
                                    <td>[% maxsuspensiondays | html %]</td>
251
                                    <td>[% suspension_chargeperiod | html %]</td>
260
                                    <td>[% suspension_chargeperiod | html %]</td>
Lines 381-386 Link Here
381
                    <td><input type="text" name="firstremind" id="firstremind" size="2" /> </td>
390
                    <td><input type="text" name="firstremind" id="firstremind" size="2" /> </td>
382
                    <td><input type="text" name="overduefinescap" id="overduefinescap" size="6" /> </td>
391
                    <td><input type="text" name="overduefinescap" id="overduefinescap" size="6" /> </td>
383
                    <td><input type="checkbox" name="cap_fine_to_replacement_price" id="cap_fine_to_replacement_price" /></td>
392
                    <td><input type="checkbox" name="cap_fine_to_replacement_price" id="cap_fine_to_replacement_price" /></td>
393
                    <td><input type="text" name="expire_reserves_charge" id="expire_reserves_charge" size="6"/></td>
384
                    <td><input type="text" name="finedays" id="fined" size="3" /> </td>
394
                    <td><input type="text" name="finedays" id="fined" size="3" /> </td>
385
                    <td><input type="text" name="maxsuspensiondays" id="maxsuspensiondays" size="3" /> </td>
395
                    <td><input type="text" name="maxsuspensiondays" id="maxsuspensiondays" size="3" /> </td>
386
                    <td><input type="text" name="suspension_chargeperiod" id="suspension_chargeperiod" size="3" /> </td>
396
                    <td><input type="text" name="suspension_chargeperiod" id="suspension_chargeperiod" size="3" /> </td>
Lines 448-453 Link Here
448
                      <th>Fine grace period</th>
458
                      <th>Fine grace period</th>
449
                      <th>Overdue fines cap (amount)</th>
459
                      <th>Overdue fines cap (amount)</th>
450
                      <th>Cap fine at replacement price</th>
460
                      <th>Cap fine at replacement price</th>
461
                      <th>Expire reserve charge</th>
451
                      <th>Suspension in days (day)</th>
462
                      <th>Suspension in days (day)</th>
452
                      <th>Max. suspension duration (day)</th>
463
                      <th>Max. suspension duration (day)</th>
453
                      <th>Suspension charging interval</th>
464
                      <th>Suspension charging interval</th>
Lines 1020-1026 Link Here
1020
                        }
1031
                        }
1021
                        $(current_column).find("input[type='text']").val(input_value);
1032
                        $(current_column).find("input[type='text']").val(input_value);
1022
                        $(current_column).find("select").val(select_value);
1033
                        $(current_column).find("select").val(select_value);
1023
                    } else if ( i == 15 ) {
1034
                    } else if ( i == 16 ) {
1024
                        // specific processing for cap_fine_to_replacement_price
1035
                        // specific processing for cap_fine_to_replacement_price
1025
                        var cap_fine_to_replacement_price = $(this).find("input[type='checkbox']");
1036
                        var cap_fine_to_replacement_price = $(this).find("input[type='checkbox']");
1026
                        $('#cap_fine_to_replacement_price').prop('checked', cap_fine_to_replacement_price.is(':checked') );
1037
                        $('#cap_fine_to_replacement_price').prop('checked', cap_fine_to_replacement_price.is(':checked') );
Lines 1045-1051 Link Here
1045
                            // Remove potential previous input added
1056
                            // Remove potential previous input added
1046
                            $(current_column).find("input").remove();
1057
                            $(current_column).find("input").remove();
1047
                            $(current_column).append("<input type='hidden' name='"+name+"' value='"+val+"' />");
1058
                            $(current_column).append("<input type='hidden' name='"+name+"' value='"+val+"' />");
1048
                        } else if ( i == 5 || i == 6 || i == 25 || i == 26 || i == 27 ) {
1059
                        } else if ( i == 5 || i == 6 || i == 26 || i == 27 || i == 28 ) {
1049
                            // If the value is not an integer for
1060
                            // If the value is not an integer for
1050
                            //     - "Current checkouts allowed"
1061
                            //     - "Current checkouts allowed"
1051
                            //     - "Current on-site checkouts allowed"
1062
                            //     - "Current on-site checkouts allowed"
(-)a/t/db_dependent/Holds/Holdfine.t (-1 / +199 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/perl
2
3
use Modern::Perl;
4
5
use C4::Context;
6
use Koha::CirculationRules;
7
8
use Test::More tests => 13;
9
10
use t::lib::TestBuilder;
11
use t::lib::Mocks;
12
use Koha::Holds;
13
14
use Koha::Account;
15
use Koha::Account::DebitTypes;
16
17
BEGIN {
18
    use_ok('C4::Reserves');
19
}
20
21
my $schema = Koha::Database->schema;
22
$schema->storage->txn_begin;
23
my $dbh = C4::Context->dbh;
24
25
my $builder = t::lib::TestBuilder->new;
26
27
my $library1 = $builder->build({
28
    source => 'Branch',
29
});
30
31
my $bib_title = "Test Title";
32
33
my $borrower = $builder->build({
34
    source => 'Borrower',
35
    value => {
36
        branchcode => $library1->{branchcode},
37
    }
38
});
39
40
my $borrowernumber = $borrower->{borrowernumber};
41
my $library_A_code = $library1->{branchcode};
42
43
my $biblio = $builder->build_sample_biblio({itemtype=>'BK'});
44
my $biblionumber = $biblio->biblionumber;
45
my $item1 = $builder->build_sample_item({
46
    biblionumber => $biblionumber,
47
    itype => 'CF',
48
    homebranch => $library_A_code,
49
    holdingbranch => $library_A_code
50
});
51
my $item2 = $builder->build_sample_item({
52
    biblionumber => $biblionumber,
53
    itype => 'MU',
54
    homebranch => $library_A_code,
55
    holdingbranch => $library_A_code
56
});
57
my $item3 = $builder->build_sample_item({
58
    biblionumber => $biblionumber,
59
    itype => 'MX',
60
    homebranch => $library_A_code,
61
    holdingbranch => $library_A_code
62
});
63
64
$dbh->do("DELETE FROM circulation_rules");
65
Koha::CirculationRules->set_rules(
66
    {
67
        itemtype     => 'BK',
68
        categorycode => undef,
69
        branchcode   => undef,
70
        rules        => {
71
            expire_reserves_charge => '111'
72
        }
73
    }
74
);
75
Koha::CirculationRules->set_rules(
76
    {
77
        itemtype     => 'CF',
78
        categorycode => undef,
79
        branchcode   => undef,
80
        rules        => {
81
            expire_reserves_charge => '222'
82
        }
83
    }
84
);
85
Koha::CirculationRules->set_rules(
86
    {
87
        itemtype     => 'MU',
88
        categorycode => undef,
89
        branchcode   => undef,
90
        rules        => {
91
            expire_reserves_charge => undef
92
        }
93
    }
94
);
95
96
# TEST: Hold first available
97
my $reserve_id = AddReserve(
98
    {
99
        branchcode     => $library_A_code,
100
        borrowernumber => $borrowernumber,
101
        biblionumber   => $biblionumber,
102
        priority       => 1,
103
    }
104
);
105
106
my $account = Koha::Account->new({ patron_id => $borrowernumber });
107
108
my ( $status ) = CheckReserves($item1->id);
109
is( $status, 'Reserved', "Hold for the first available created" );
110
111
my $start_balance = $account->balance();
112
113
Koha::Holds->find( $reserve_id )->cancel({ charge_cancel_fee => 1 });
114
115
( $status ) = CheckReserves($item1->id);
116
is( $status, '', "Hold for the first available cancelled" );
117
118
is( $account->balance() - $start_balance, 111, "Account debt is 111" );
119
120
# TEST: Hold Computer File item
121
$reserve_id = AddReserve(
122
    {
123
        branchcode       => $library_A_code,
124
        borrowernumber   => $borrowernumber,
125
        biblionumber     => $biblionumber,
126
        priority         => 1,
127
        itemnumber       => $item1->itemnumber,
128
    }
129
);
130
131
$account = Koha::Account->new({ patron_id => $borrowernumber });
132
133
( $status ) = CheckReserves($item1->id);
134
is( $status, 'Reserved', "Hold for the CF created" );
135
136
$start_balance = $account->balance();
137
138
Koha::Holds->find( $reserve_id )->cancel({ charge_cancel_fee => 1 });
139
140
( $status ) = CheckReserves($item1->id);
141
is( $status, '', "Hold for the CF cancelled" );
142
143
is( $account->balance() - $start_balance, 222, "Account debt is 222" );
144
145
# TEST: Hold Music item that has 'expire_reserves_charge' set undef
146
t::lib::Mocks::mock_preference('ExpireReservesMaxPickUpDelayCharge', 333);
147
148
$reserve_id = AddReserve(
149
    {
150
        branchcode       => $library_A_code,
151
        borrowernumber   => $borrowernumber,
152
        biblionumber     => $biblionumber,
153
        priority         => 1,
154
        itemnumber       => $item2->itemnumber,
155
    }
156
);
157
158
$account = Koha::Account->new({ patron_id => $borrowernumber });
159
160
( $status ) = CheckReserves($item2->id);
161
is( $status, 'Reserved', "Hold for the MU created" );
162
163
$start_balance = $account->balance();
164
165
Koha::Holds->find( $reserve_id )->cancel({ charge_cancel_fee => 1 });
166
167
( $status ) = CheckReserves($item2->id);
168
is( $status, '', "Hold for the MU cancelled" );
169
170
is( $account->balance() - $start_balance, 333, "Account debt is 333" );
171
172
# TEST: Hold MX item that has no circulation rules
173
t::lib::Mocks::mock_preference('ExpireReservesMaxPickUpDelayCharge', 444);
174
175
$reserve_id = AddReserve(
176
    {
177
        branchcode       => $library_A_code,
178
        borrowernumber   => $borrowernumber,
179
        biblionumber     => $biblionumber,
180
        priority         => 1,
181
        itemnumber       => $item3->itemnumber,
182
    }
183
);
184
185
$account = Koha::Account->new({ patron_id => $borrowernumber });
186
187
( $status ) = CheckReserves($item3->id);
188
is( $status, 'Reserved', "Hold for the MX created" );
189
190
$start_balance = $account->balance();
191
192
Koha::Holds->find( $reserve_id )->cancel({ charge_cancel_fee => 1 });
193
194
( $status ) = CheckReserves($item3->id);
195
is( $status, '', "Hold for the MX cancelled" );
196
197
is( $account->balance() - $start_balance, 444, "Account debt is 444" );
198
199
$schema->storage->txn_rollback;

Return to bug 25711