Bug 18309: Add UNIMARC field 214 and its subfields
[koha.git] / t / db_dependent / Overdues.t
blob85c3502c6a6f641c0f5063833e9b63c5ca84d67e
1 #!/usr/bin/perl;
3 use Modern::Perl;
4 use Test::More tests => 17;
6 use C4::Context;
7 use Koha::Database;
8 use Koha::Libraries;
10 use t::lib::Mocks;
11 use t::lib::TestBuilder;
13 use_ok('C4::Overdues');
14 can_ok('C4::Overdues', 'GetOverdueMessageTransportTypes');
15 can_ok('C4::Overdues', 'GetBranchcodesWithOverdueRules');
17 my $schema = Koha::Database->new->schema;
18 my $builder = t::lib::TestBuilder->new;
20 $schema->storage->txn_begin;
21 my $dbh = C4::Context->dbh;
23 $dbh->do(q|DELETE FROM letter|);
24 $dbh->do(q|DELETE FROM message_queue|);
25 $dbh->do(q|DELETE FROM message_transport_types|);
26 $dbh->do(q|DELETE FROM overduerules|);
27 $dbh->do(q|DELETE FROM overduerules_transport_types|);
29 $dbh->do(q|
30     INSERT INTO message_transport_types( message_transport_type ) VALUES ('email'), ('phone'), ('print'), ('sms')
31 |);
33 $dbh->do(q|
34     INSERT INTO overduerules ( overduerules_id, branchcode, categorycode ) VALUES
35     (1, 'CPL', 'PT'),
36     (2, 'CPL', 'YA'),
37     (3, '', 'PT'),
38     (4, '', 'YA')
39 |);
41 $dbh->do(q|INSERT INTO overduerules_transport_types (overduerules_id, letternumber, message_transport_type) VALUES
42     (1, 1, 'email'),
43     (1, 2, 'sms'),
44     (1, 3, 'email'),
45     (2, 3, 'print'),
46     (3, 1, 'email'),
47     (3, 2, 'email'),
48     (3, 2, 'sms'),
49     (3, 3, 'sms'),
50     (3, 3, 'email'),
51     (3, 3, 'print'),
52     (4, 2, 'sms')
53 |);
55 my $mtts;
57 $mtts = C4::Overdues::GetOverdueMessageTransportTypes('CPL', 'PT');
58 is( $mtts, undef, 'GetOverdueMessageTransportTypes: returns undef if no letternumber given' );
60 $mtts = C4::Overdues::GetOverdueMessageTransportTypes('CPL', undef, 1);
61 is( $mtts, undef, 'GetOverdueMessageTransportTypes: returns undef if no categorycode given' );
63 $mtts = C4::Overdues::GetOverdueMessageTransportTypes('CPL');
64 is( $mtts, undef, 'GetOverdueMessageTransportTypes: returns undef if no letternumber and categorycode given' );
66 $mtts = C4::Overdues::GetOverdueMessageTransportTypes('CPL', 'PT', 1);
67 is_deeply( $mtts, ['email'], 'GetOverdueMessageTransportTypes: first overdue is by email for PT (CPL)' );
69 $mtts = C4::Overdues::GetOverdueMessageTransportTypes('CPL', 'PT', 2);
70 is_deeply( $mtts, ['sms'], 'GetOverdueMessageTransportTypes: second overdue is by sms for PT (CPL)' );
72 $mtts = C4::Overdues::GetOverdueMessageTransportTypes('CPL', 'PT', 3);
73 is_deeply( $mtts, ['email'], 'GetOverdueMessageTransportTypes: third overdue is by email for PT (CPL)' );
75 $mtts = C4::Overdues::GetOverdueMessageTransportTypes('', 'PT', 1);
76 is_deeply( $mtts, ['email'], 'GetOverdueMessageTransportTypes: first overdue is by email for PT (default)' );
78 $mtts = C4::Overdues::GetOverdueMessageTransportTypes('', 'PT', 2);
79 is_deeply( $mtts, ['email', 'sms'], 'GetOverdueMessageTransportTypes: second overdue is by email and sms for PT (default)' );
81 $mtts = C4::Overdues::GetOverdueMessageTransportTypes('', 'PT', 3);
82 is_deeply( $mtts, ['print', 'sms', 'email'], 'GetOverdueMessageTransportTypes: third overdue is by print, sms and email for PT (default). With print in first.' );
84 # Test GetBranchcodesWithOverdueRules
85 $dbh->do(q|DELETE FROM overduerules|);
86 $dbh->do(q|
87     INSERT INTO overduerules
88         ( branchcode,categorycode, delay1,letter1,debarred1, delay2,letter2,debarred2, delay3,letter3,debarred3 )
89         VALUES
90         ( '', '', 1, 'LETTER_CODE1', 1, 5, 'LETTER_CODE2', 1, 10, 'LETTER_CODE3', 1 )
91 |);
93 my @branchcodes = map { $_->branchcode } Koha::Libraries->search;
95 my @overdue_branches = C4::Overdues::GetBranchcodesWithOverdueRules();
96 is_deeply( [ sort @overdue_branches ], [ sort @branchcodes ], 'If a default rule exists, all branches should be returned' );
98 $dbh->do(q|
99     INSERT INTO overduerules
100         ( branchcode,categorycode, delay1,letter1,debarred1, delay2,letter2,debarred2, delay3,letter3,debarred3 )
101         VALUES
102         ( 'CPL', '', 1, 'LETTER_CODE1', 1, 5, 'LETTER_CODE2', 1, 10, 'LETTER_CODE3', 1 )
105 @overdue_branches = C4::Overdues::GetBranchcodesWithOverdueRules();
106 is_deeply( [ sort @overdue_branches ], [ sort @branchcodes ], 'If a default rule exists and a specific rule exists, all branches should be returned' );
108 $dbh->do(q|DELETE FROM overduerules|);
109 $dbh->do(q|
110     INSERT INTO overduerules
111         ( branchcode,categorycode, delay1,letter1,debarred1, delay2,letter2,debarred2, delay3,letter3,debarred3 )
112         VALUES
113         ( 'CPL', '', 1, 'LETTER_CODE1', 1, 5, 'LETTER_CODE2', 1, 10, 'LETTER_CODE3', 1 )
116 @overdue_branches = C4::Overdues::GetBranchcodesWithOverdueRules();
117 is_deeply( \@overdue_branches, ['CPL'] , 'If only a specific rule exist, only 1 branch should be returned' );
119 $dbh->do(q|DELETE FROM overduerules|);
120 $dbh->do(q|
121     INSERT INTO overduerules
122         ( branchcode,categorycode, delay1,letter1,debarred1, delay2,letter2,debarred2, delay3,letter3,debarred3 )
123         VALUES
124         ( 'CPL', '', 1, 'LETTER_CODE1_CPL', 1, 5, 'LETTER_CODE2_CPL', 1, 10, 'LETTER_CODE3_CPL', 1 ),
125         ( 'MPL', '', 1, 'LETTER_CODE1_MPL', 1, 5, 'LETTER_CODE2_MPL', 1, 10, 'LETTER_CODE3_MPL', 1 )
128 @overdue_branches = C4::Overdues::GetBranchcodesWithOverdueRules();
129 is_deeply( \@overdue_branches, ['CPL', 'MPL'] , 'If only 2 specific rules exist, 2 branches should be returned' );
131 $schema->storage->txn_rollback;
133 subtest 'UpdateFine tests' => sub {
135     plan tests => 25;
137     $schema->storage->txn_begin;
139     t::lib::Mocks::mock_preference( 'MaxFine', '100' );
141     my $patron    = $builder->build_object( { class => 'Koha::Patrons' } );
142     my $item1     = $builder->build_sample_item();
143     my $item2     = $builder->build_sample_item();
144     my $checkout1 = $builder->build_object(
145         {
146             class => 'Koha::Checkouts',
147             value => { itemnumber => $item1->itemnumber }
148         }
149     );
150     my $checkout2 = $builder->build_object(
151         {
152             class => 'Koha::Checkouts',
153             value => { itemnumber => $item2->itemnumber }
154         }
155     );
157     # Try to add 0 amount fine
158     UpdateFine(
159         {
160             issue_id       => $checkout1->issue_id,
161             itemnumber     => $item1->itemnumber,
162             borrowernumber => $patron->borrowernumber,
163             amount         => '0',
164             due            => $checkout1->date_due
165         }
166     );
168     my $fines = Koha::Account::Lines->search(
169         { borrowernumber => $patron->borrowernumber } );
170     is( $fines->count, 0, "No fine added when amount is 0" );
172     # Add fine 1
173     UpdateFine(
174         {
175             issue_id       => $checkout1->issue_id,
176             itemnumber     => $item1->itemnumber,
177             borrowernumber => $patron->borrowernumber,
178             amount         => '50',
179             due            => $checkout1->date_due
180         }
181     );
183     $fines = Koha::Account::Lines->search(
184         { borrowernumber => $patron->borrowernumber } );
185     is( $fines->count, 1, "Fine added when amount is greater than 0" );
186     my $fine = $fines->next;
187     is( $fine->amount, '50.000000', "Fine amount correctly set to 50" );
188     is( $fine->issue_id, $checkout1->issue_id, "Fine is associated with the correct issue" );
189     is( $fine->itemnumber, $checkout1->itemnumber, "Fine is associated with the correct item" );
191     # Increase fine 1
192     UpdateFine(
193         {
194             issue_id       => $checkout1->issue_id,
195             itemnumber     => $item1->itemnumber,
196             borrowernumber => $patron->borrowernumber,
197             amount         => '80',
198             due            => $checkout1->date_due
199         }
200     );
202     $fines = Koha::Account::Lines->search(
203         { borrowernumber => $patron->borrowernumber } );
204     is( $fines->count, 1, "Existing fine updated" );
205     $fine = $fines->next;
206     is( $fine->amount, '80.000000', "Fine amount correctly updated to 80" );
208     # Add fine 2
209     UpdateFine(
210         {
211             issue_id       => $checkout2->issue_id,
212             itemnumber     => $item2->itemnumber,
213             borrowernumber => $patron->borrowernumber,
214             amount         => '30',
215             due            => $checkout2->date_due
216         }
217     );
219     $fines = Koha::Account::Lines->search(
220         { borrowernumber => $patron->borrowernumber },
221         { order_by       => { '-asc' => 'accountlines_id' } }
222     );
223     is( $fines->count,        2,    "New fine added for second checkout" );
224     $fine = $fines->next;
225     is( $fine->amount, '80.000000', "First fine amount unchanged" );
226     my $fine2 = $fines->next;
227     is( $fine2->amount, '20.000000', "Second fine capped at '20' by MaxFine" );
228     is( $fine2->issue_id, $checkout2->issue_id, "Second fine is associated with the correct issue" );
229     is( $fine2->itemnumber, $checkout2->itemnumber, "Second fine is associated with the correct item" );
231     # Partial pay fine 1
232     $fine->amountoutstanding('50')->store;
233     UpdateFine(
234         {
235             issue_id       => $checkout2->issue_id,
236             itemnumber     => $item2->itemnumber,
237             borrowernumber => $patron->borrowernumber,
238             amount         => '30',
239             due            => $checkout2->date_due
240         }
241     );
243     $fines = Koha::Account::Lines->search(
244         { borrowernumber => $patron->borrowernumber },
245         { order_by       => { '-asc' => 'accountlines_id' } }
246     );
247     is( $fines->count,        2,    "Still two fines after second checkout update" );
248     $fine = $fines->next;
249     is( $fine->amount, '80.000000', "First fine amount unchanged" );
250     $fine2 = $fines->next;
251     is( $fine2->amount, '30.000000', "Second fine increased after partial payment of first" );
253     # Fix fine 1, create third fine
254     $fine->status('RETURNED')->store;
255     UpdateFine(
256         {
257             issue_id       => $checkout1->issue_id,
258             itemnumber     => $item1->itemnumber,
259             borrowernumber => $patron->borrowernumber,
260             amount         => '30',
261             due            => $checkout1->date_due
262         }
263     );
265     $fines = Koha::Account::Lines->search(
266         { borrowernumber => $patron->borrowernumber },
267         { order_by       => { '-asc' => 'accountlines_id' } }
268     );
269     is( $fines->count,        3,    "Third fine added for overdue renewal" );
270     $fine = $fines->next;
271     is( $fine->amount, '80.000000', "First fine amount unchanged" );
272     $fine2 = $fines->next;
273     is( $fine2->amount, '30.000000', "Second fine amount unchanged" );
274     my $fine3 = $fines->next;
275     is( $fine3->amount, '20.000000', "Third fine amount capped due to MaxFine" );
276     is( $fine3->issue_id, $checkout1->issue_id, "Third fine is associated with the correct issue" );
277     is( $fine3->itemnumber, $checkout1->itemnumber, "Third fine is associated with the correct item" );
279     # FIXME: Add test to check whether sundry/manual charges are included within MaxFine.
280     # FIXME: Add test to ensure other charges are not included within MaxFine.
282     # Disable MaxFine
283     t::lib::Mocks::mock_preference( 'MaxFine', '0' );
284     UpdateFine(
285         {
286             issue_id       => $checkout1->issue_id,
287             itemnumber     => $item1->itemnumber,
288             borrowernumber => $patron->borrowernumber,
289             amount         => '30',
290             due            => $checkout1->date_due
291         }
292     );
294     $fines = Koha::Account::Lines->search(
295         { borrowernumber => $patron->borrowernumber },
296         { order_by       => { '-asc' => 'accountlines_id' } }
297     );
298     is( $fines->count,        3,    "Still only three fines after MaxFine cap removed" );
299     $fine = $fines->next;
300     is( $fine->amount, '80.000000', "First fine amount unchanged" );
301     $fine2 = $fines->next;
302     is( $fine2->amount, '30.000000', "Second fine amount unchanged" );
303     $fine3 = $fines->next;
304     is( $fine3->amount, '30.000000', "Third fine increased now MaxFine cap is disabled" );
306     $schema->storage->txn_rollback;