LP 1198465: More tests for conditional negative balances
[working/Evergreen.git] / Open-ILS / src / perlmods / live_t / 09-lp1198465_neg_balances.t
1 #!perl
2
3 use Test::More tests => 127;
4
5 diag("Test features of Conditional Negative Balances code.");
6
7 use constant WORKSTATION_NAME => 'BR1-test-09-lp1198465_neg_balances.t';
8 use constant WORKSTATION_LIB => 4;
9
10 use strict; use warnings;
11
12 use DateTime;
13 use DateTime::Format::ISO8601;
14 use OpenSRF::Utils qw/cleanse_ISO8601/;
15 use OpenILS::Utils::TestUtils;
16 my $script = OpenILS::Utils::TestUtils->new();
17 use Data::Dumper;
18
19 our $apputils   = "OpenILS::Application::AppUtils";
20
21 my ($patron_id, $patron_usrname, $xact_id, $item_id, $item_barcode);
22 my ($summary, $payment_blob, $pay_resp, $item_req, $checkin_resp);
23 my $user_obj;
24 my $storage_ses = $script->session('open-ils.storage');
25
26
27 sub retrieve_patron {
28     my $patron_id = shift;
29
30     my $user_req = $storage_ses->request('open-ils.storage.direct.actor.user.retrieve', $patron_id);
31     if (my $user_resp = $user_req->recv) {
32         if (my $patron_obj = $user_resp->content) {
33             return $patron_obj;
34         }
35     }
36     return 0;
37 }
38
39 sub fetch_billable_xact_summary {
40     my $xact_id = shift;
41     my $ses = $script->session('open-ils.cstore');
42     my $req = $ses->request(
43         'open-ils.cstore.direct.money.billable_transaction_summary.retrieve',
44         $xact_id);
45
46     if (my $resp = $req->recv) {
47         return $resp->content;
48     } else {
49         return 0;
50     }
51 }
52
53 sub pay_bills {
54     my $payment_blob = shift;
55     my $resp = $apputils->simplereq(
56         'open-ils.circ',
57         'open-ils.circ.money.payment',
58         $script->authtoken,
59         $payment_blob,
60         $user_obj->last_xact_id
61     );
62
63     #refetch user_obj to get latest last_xact_id
64     $user_obj = retrieve_patron($patron_id)
65         or die 'Could not refetch patron';
66
67     return $resp;
68 }
69
70 sub void_bills {
71     my $billing_ids = shift; #array ref
72     my $resp = $apputils->simplereq(
73         'open-ils.circ',
74         'open-ils.circ.money.billing.void',
75         $script->authtoken,
76         @$billing_ids
77     );
78
79     return $resp;
80 }
81
82 #----------------------------------------------------------------
83 # The tests...  assumes stock sample data, full-auto install by
84 # eg_wheezy_installer.sh, etc.
85 #----------------------------------------------------------------
86
87 # Connect to Evergreen
88 $script->authenticate({
89     username => 'admin',
90     password => 'demo123',
91     type => 'staff'});
92 ok( $script->authtoken, 'Have an authtoken');
93
94 my $ws = $script->register_workstation(WORKSTATION_NAME,WORKSTATION_LIB);
95 ok( ! ref $ws, 'Registered a new workstation');
96
97 $script->logout();
98 $script->authenticate({
99     username => 'admin',
100     password => 'demo123',
101     type => 'staff',
102     workstation => WORKSTATION_NAME});
103 ok( $script->authtoken, 'Have an authtoken associated with the workstation');
104
105
106 ### TODO: verify that stock data is ready for testing
107
108 ### Setup Org Unit Settings that apply to all test cases
109
110 my $org_id = 1; #CONS
111 my $settings = {
112     'circ.max_item_price' => 50,
113     'circ.min_item_price' => 50,
114     'circ.void_lost_on_checkin' => 1
115 };
116
117 $apputils->simplereq(
118     'open-ils.actor',
119     'open-ils.actor.org_unit.settings.update',
120     $script->authtoken,
121     $org_id,
122     $settings
123 );
124
125 # Setup first patron
126 $patron_id = 4;
127 $patron_usrname = '99999355250';
128
129 # Look up the patron
130 if ($user_obj = retrieve_patron($patron_id)) {
131     is(
132         ref $user_obj,
133         'Fieldmapper::actor::user',
134         'open-ils.storage.direct.actor.user.retrieve returned aou object'
135     );
136     is(
137         $user_obj->usrname,
138         $patron_usrname,
139         'Patron with id = ' . $patron_id . ' has username ' . $patron_usrname
140     );
141 }
142
143
144 ##############################
145 # 1. No Prohibit Negative Balance Settings Are Enabled, Payment Made
146 ##############################
147
148 ### Setup use case variables
149 $xact_id = 1;
150 $item_id = 2;
151 $item_barcode = 'CONC4000037';
152
153 $summary = fetch_billable_xact_summary($xact_id);
154 ok( $summary, 'CASE 1: Found the transaction summary');
155 is(
156     $summary->balance_owed,
157     '50.00',
158     'Starting balance owed is 50.00 for lost item'
159 );
160
161 ### pay the whole bill
162 $payment_blob = {
163     userid => $patron_id,
164     note => '09-lp1198465_neg_balances.t',
165     payment_type => 'cash_payment',
166     patron_credit => '0.00',
167     payments => [ [ $xact_id, '50.00' ] ]
168 };
169 $pay_resp = pay_bills($payment_blob);
170
171 is(
172     scalar( @{ $pay_resp->{payments} } ),
173     1,
174     'Payment response included one payment id'
175 );
176
177 $summary = fetch_billable_xact_summary($xact_id);
178 is(
179     $summary->balance_owed,
180     '0.00',
181     'Remaining balance of 0.00 after payment'
182 );
183
184 ### check-in the lost copy
185
186 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
187 if (my $item_resp = $item_req->recv) {
188     if (my $item = $item_resp->content) {
189         is(
190             ref $item,
191             'Fieldmapper::asset::copy',
192             'open-ils.storage.direct.asset.copy.retrieve returned acp object'
193         );
194         is(
195             $item->status,
196             3,
197             'Item with id = ' . $item_id . ' has status of LOST'
198         );
199     }
200 }
201
202 $checkin_resp = $script->do_checkin_override({
203     barcode => $item_barcode});
204 is(
205     $checkin_resp->{ilsevent},
206     0,
207     'Checkin returned a SUCCESS event'
208 );
209
210 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
211 if (my $item_resp = $item_req->recv) {
212     if (my $item = $item_resp->content) {
213         ok(
214             $item->status == 7 || $item->status == 0,
215             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
216         );
217     }
218 }
219
220 ### verify ending state
221
222 $summary = fetch_billable_xact_summary($xact_id);
223 is(
224     $summary->balance_owed,
225     '-50.00',
226     'Patron has a negative balance (credit) of 50.00 due to overpayment'
227 );
228
229
230 ##############################
231 # 2. Negative Balance Settings Are Unset, No Payment Made
232 ##############################
233
234 ### Setup use case variables
235 $xact_id = 2;
236 $item_id = 3;
237 $item_barcode = 'CONC4000038';
238
239 $summary = fetch_billable_xact_summary($xact_id);
240 ok( $summary, 'CASE 2: Found the transaction summary');
241 is(
242     $summary->balance_owed,
243     '50.00',
244     'Starting balance owed is 50.00 for lost item'
245 );
246
247 ### check-in the lost copy
248
249 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
250 if (my $item_resp = $item_req->recv) {
251     if (my $item = $item_resp->content) {
252         is(
253             $item->status,
254             3,
255             'Item with id = ' . $item_id . ' has status of LOST'
256         );
257     }
258 }
259
260 $checkin_resp = $script->do_checkin_override({
261     barcode => $item_barcode});
262 is(
263     $checkin_resp->{ilsevent},
264     0,
265     'Checkin returned a SUCCESS event'
266 );
267
268 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
269 if (my $item_resp = $item_req->recv) {
270     if (my $item = $item_resp->content) {
271         ok(
272             $item->status == 7 || $item->status == 0,
273             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
274         );
275     }
276 }
277
278 ### verify ending state
279
280 $summary = fetch_billable_xact_summary($xact_id);
281 is(
282     $summary->balance_owed,
283     '0.00',
284     'Patron has a balance of 0.00'
285 );
286
287
288 ##############################
289 # 13. RERUN of Case 1. No Prohibit Negative Balance Settings Are Enabled, Payment Made
290 # SETTINGS: Prohibit negative balances on bills for lost materials
291 ##############################
292
293 # Setup next patron
294 $patron_id = 6;
295 $patron_usrname = '99999335859';
296
297 # Look up the patron
298 if ($user_obj = retrieve_patron($patron_id)) {
299     is(
300         ref $user_obj,
301         'Fieldmapper::actor::user',
302         'open-ils.storage.direct.actor.user.retrieve returned aou object'
303     );
304     is(
305         $user_obj->usrname,
306         $patron_usrname,
307         'Patron with id = ' . $patron_id . ' has username ' . $patron_usrname
308     );
309 }
310
311 ### Setup use case variables
312 $xact_id = 13;
313 $item_id = 14;
314 $item_barcode = 'CONC4000049';
315
316 # Setup Org Unit Settings
317 $settings = {
318     'bill.prohibit_negative_balance_on_lost' => 1
319 };
320 $apputils->simplereq(
321     'open-ils.actor',
322     'open-ils.actor.org_unit.settings.update',
323     $script->authtoken,
324     $org_id,
325     $settings
326 );
327
328 $summary = fetch_billable_xact_summary($xact_id);
329 ok( $summary, 'CASE 13a: Found the transaction summary');
330 is(
331     $summary->balance_owed,
332     '50.00',
333     'Starting balance owed is 50.00 for lost item'
334 );
335
336 ### pay the whole bill
337 $payment_blob = {
338     userid => $patron_id,
339     note => '09-lp1198465_neg_balances.t',
340     payment_type => 'cash_payment',
341     patron_credit => '0.00',
342     payments => [ [ $xact_id, '50.00' ] ]
343 };
344 $pay_resp = pay_bills($payment_blob);
345
346 is(
347     scalar( @{ $pay_resp->{payments} } ),
348     1,
349     'Payment response included one payment id'
350 );
351
352 $summary = fetch_billable_xact_summary($xact_id);
353 is(
354     $summary->balance_owed,
355     '0.00',
356     'Remaining balance of 0.00 after payment'
357 );
358
359 ### check-in the lost copy
360
361 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
362 if (my $item_resp = $item_req->recv) {
363     if (my $item = $item_resp->content) {
364         is(
365             ref $item,
366             'Fieldmapper::asset::copy',
367             'open-ils.storage.direct.asset.copy.retrieve returned acp object'
368         );
369         is(
370             $item->status,
371             3,
372             'Item with id = ' . $item_id . ' has status of LOST'
373         );
374     }
375 }
376
377 $checkin_resp = $script->do_checkin_override({
378     barcode => $item_barcode});
379 is(
380     $checkin_resp->{ilsevent},
381     0,
382     'Checkin returned a SUCCESS event'
383 );
384
385 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
386 if (my $item_resp = $item_req->recv) {
387     if (my $item = $item_resp->content) {
388         ok(
389             $item->status == 7 || $item->status == 0,
390             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
391         );
392     }
393 }
394
395 ### verify ending state
396
397 $summary = fetch_billable_xact_summary($xact_id);
398 is(
399     $summary->balance_owed,
400     '0.00',
401     'Patron has a balance of 0.00 (negative balance prevented)'
402 );
403
404
405 ##############################
406 # 13. RERUN of Case 12. Test negative balance settings on fines
407 # SETTINGS: Prohibit negative balances on bills for lost materials
408 ##############################
409
410 ### Setup use case variables
411 $xact_id = 14;
412 $item_id = 15;
413 $item_barcode = 'CONC4000050';
414
415 # Setup Org Unit Settings
416 # ALREADY SET:
417 #    'bill.prohibit_negative_balance_on_lost' => 1
418
419 $summary = fetch_billable_xact_summary($xact_id);
420 ok( $summary, 'CASE 13b: Found the transaction summary');
421 is(
422     $summary->balance_owed,
423     '0.70',
424     'Starting balance owed is 0.70 for overdue fines'
425 );
426
427 ### partially pay the bill
428 $payment_blob = {
429     userid => $patron_id,
430     note => '09-lp1198465_neg_balances.t',
431     payment_type => 'cash_payment',
432     patron_credit => '0.00',
433     payments => [ [ $xact_id, '0.20' ] ]
434 };
435 $pay_resp = pay_bills($payment_blob);
436
437 is(
438     scalar( @{ $pay_resp->{payments} } ),
439     1,
440     'Payment response included one payment id'
441 );
442
443 $summary = fetch_billable_xact_summary($xact_id);
444 is(
445     $summary->balance_owed,
446     '0.50',
447     'Remaining balance of 0.50 after payment'
448 );
449
450 ### Check in using Amnesty Mode
451 $checkin_resp = $script->do_checkin_override({
452     barcode => $item_barcode,
453     void_overdues => 1
454 });
455 is(
456     $checkin_resp->{ilsevent},
457     0,
458     'Checkin returned a SUCCESS event'
459 );
460
461 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
462 if (my $item_resp = $item_req->recv) {
463     if (my $item = $item_resp->content) {
464         ok(
465             $item->status == 7 || $item->status == 0,
466             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
467         );
468     }
469 }
470
471 ### verify ending state
472 $summary = fetch_billable_xact_summary($xact_id);
473 is(
474     $summary->balance_owed,
475     '-0.20',
476     'Patron has a negative balance of -0.20 (refund of overdue fine payment)'
477 );
478
479
480 ##############################
481 # 14. RERUN of Case 1. No Prohibit Negative Balance Settings Are Enabled, Payment Made
482 # SETTINGS: Prohibit negative balances on bills for overdue materials
483 ##############################
484
485 ### Setup use case variables
486 $xact_id = 15;
487 $item_id = 16;
488 $item_barcode = 'CONC4000051';
489
490 # Setup Org Unit Settings
491 $settings = {
492     'bill.prohibit_negative_balance_on_lost' => 0, #unset from previous test
493     'bill.prohibit_negative_balance_on_overdues' => 1
494 };
495 $apputils->simplereq(
496     'open-ils.actor',
497     'open-ils.actor.org_unit.settings.update',
498     $script->authtoken,
499     $org_id,
500     $settings
501 );
502
503 $summary = fetch_billable_xact_summary($xact_id);
504 ok( $summary, 'CASE 14a: Found the transaction summary');
505 is(
506     $summary->balance_owed,
507     '50.00',
508     'Starting balance owed is 50.00 for lost item'
509 );
510
511 ### pay the whole bill
512 $payment_blob = {
513     userid => $patron_id,
514     note => '09-lp1198465_neg_balances.t',
515     payment_type => 'cash_payment',
516     patron_credit => '0.00',
517     payments => [ [ $xact_id, '50.00' ] ]
518 };
519 $pay_resp = pay_bills($payment_blob);
520
521 is(
522     scalar( @{ $pay_resp->{payments} } ),
523     1,
524     'Payment response included one payment id'
525 );
526
527 $summary = fetch_billable_xact_summary($xact_id);
528 is(
529     $summary->balance_owed,
530     '0.00',
531     'Remaining balance of 0.00 after payment'
532 );
533
534 ### check-in the lost copy
535
536 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
537 if (my $item_resp = $item_req->recv) {
538     if (my $item = $item_resp->content) {
539         is(
540             ref $item,
541             'Fieldmapper::asset::copy',
542             'open-ils.storage.direct.asset.copy.retrieve returned acp object'
543         );
544         is(
545             $item->status,
546             3,
547             'Item with id = ' . $item_id . ' has status of LOST'
548         );
549     }
550 }
551
552 $checkin_resp = $script->do_checkin_override({
553     barcode => $item_barcode});
554 is(
555     $checkin_resp->{ilsevent},
556     0,
557     'Checkin returned a SUCCESS event'
558 );
559
560 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
561 if (my $item_resp = $item_req->recv) {
562     if (my $item = $item_resp->content) {
563         ok(
564             $item->status == 7 || $item->status == 0,
565             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
566         );
567     }
568 }
569
570 ### verify ending state
571
572 $summary = fetch_billable_xact_summary($xact_id);
573 is(
574     $summary->balance_owed,
575     '-50.00',
576     'Patron has a negative balance (credit) of 50.00 due to overpayment'
577 );
578
579
580 ##############################
581 # 14. RERUN of Case 12. Test negative balance settings on fines
582 # SETTINGS: Prohibit negative balances on bills for overdue materials
583 ##############################
584
585 ### Setup use case variables
586 $xact_id = 16;
587 $item_id = 17;
588 $item_barcode = 'CONC4000052';
589
590 # Setup Org Unit Settings
591 # ALREADY SET:
592 #    'bill.prohibit_negative_balance_on_overdues' => 1
593
594 $summary = fetch_billable_xact_summary($xact_id);
595 ok( $summary, 'CASE 14b: Found the transaction summary');
596 is(
597     $summary->balance_owed,
598     '0.70',
599     'Starting balance owed is 0.70 for overdue fines'
600 );
601
602 ### partially pay the bill
603 $payment_blob = {
604     userid => $patron_id,
605     note => '09-lp1198465_neg_balances.t',
606     payment_type => 'cash_payment',
607     patron_credit => '0.00',
608     payments => [ [ $xact_id, '0.20' ] ]
609 };
610 $pay_resp = pay_bills($payment_blob);
611
612 is(
613     scalar( @{ $pay_resp->{payments} } ),
614     1,
615     'Payment response included one payment id'
616 );
617
618 $summary = fetch_billable_xact_summary($xact_id);
619 is(
620     $summary->balance_owed,
621     '0.50',
622     'Remaining balance of 0.50 after payment'
623 );
624
625 ### Check in using Amnesty Mode
626 $checkin_resp = $script->do_checkin_override({
627     barcode => $item_barcode,
628     void_overdues => 1
629 });
630 is(
631     $checkin_resp->{ilsevent},
632     0,
633     'Checkin returned a SUCCESS event'
634 );
635
636 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
637 if (my $item_resp = $item_req->recv) {
638     if (my $item = $item_resp->content) {
639         ok(
640             $item->status == 7 || $item->status == 0,
641             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
642         );
643     }
644 }
645
646 ### verify ending state
647 $summary = fetch_billable_xact_summary($xact_id);
648 is(
649     $summary->balance_owed,
650     '0.00',
651     'Patron has a balance of 0.00 (negative balance prevented)'
652 );
653
654
655 ##############################
656 # 3. Basic No Negative Balance Test
657 ##############################
658
659 # Re-setup first patron
660 $patron_id = 4;
661 $patron_usrname = '99999355250';
662
663 # Look up the patron
664 if ($user_obj = retrieve_patron($patron_id)) {
665     is(
666         ref $user_obj,
667         'Fieldmapper::actor::user',
668         'open-ils.storage.direct.actor.user.retrieve returned aou object'
669     );
670     is(
671         $user_obj->usrname,
672         $patron_usrname,
673         'Patron with id = ' . $patron_id . ' has username ' . $patron_usrname
674     );
675 }
676
677
678 ### Setup use case variables
679 $xact_id = 3;
680 $item_id = 4;
681 $item_barcode = 'CONC4000039';
682
683 # Setup Org Unit Settings
684 $settings = {
685     'bill.prohibit_negative_balance_on_overdues' => 0, #unset from previous test
686     'bill.prohibit_negative_balance_default' => 1
687 };
688 $apputils->simplereq(
689     'open-ils.actor',
690     'open-ils.actor.org_unit.settings.update',
691     $script->authtoken,
692     $org_id,
693     $settings
694 );
695
696 $summary = fetch_billable_xact_summary($xact_id);
697 ok( $summary, 'CASE 3: Found the transaction summary');
698 is(
699     $summary->balance_owed,
700     '50.00',
701     'Starting balance owed is 50.00 for lost item'
702 );
703
704 ### check-in the lost copy
705
706 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
707 if (my $item_resp = $item_req->recv) {
708     if (my $item = $item_resp->content) {
709         is(
710             $item->status,
711             3,
712             'Item with id = ' . $item_id . ' has status of LOST'
713         );
714     }
715 }
716
717 $checkin_resp = $script->do_checkin_override({
718     barcode => $item_barcode});
719 is(
720     $checkin_resp->{ilsevent},
721     0,
722     'Checkin returned a SUCCESS event'
723 );
724
725 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
726 if (my $item_resp = $item_req->recv) {
727     if (my $item = $item_resp->content) {
728         ok(
729             $item->status == 7 || $item->status == 0,
730             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
731         );
732     }
733 }
734
735 ### verify ending state
736
737 $summary = fetch_billable_xact_summary($xact_id);
738 is(
739     $summary->balance_owed,
740     '0.00',
741     'Patron has a balance of 0.00 (negative balance prevented)'
742 );
743
744 ##############################
745 # 4. Prohibit Negative Balances with Partial Payment
746 ##############################
747
748 ### Setup use case variables
749 $xact_id = 4;
750 $item_id = 5;
751 $item_barcode = 'CONC4000040';
752
753 # Setup Org Unit Settings
754 # ALREADY SET:
755 #     'bill.prohibit_negative_balance_default' => 1
756
757 $summary = fetch_billable_xact_summary($xact_id);
758 ok( $summary, 'CASE 4: Found the transaction summary');
759 is(
760     $summary->balance_owed,
761     '50.00',
762     'Starting balance owed is 50.00 for lost item'
763 );
764
765 ### confirm the copy is lost
766 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
767 if (my $item_resp = $item_req->recv) {
768     if (my $item = $item_resp->content) {
769         is(
770             $item->status,
771             3,
772             'Item with id = ' . $item_id . ' has status of LOST'
773         );
774     }
775 }
776
777 ### partially pay the bill
778 $payment_blob = {
779     userid => $patron_id,
780     note => '09-lp1198465_neg_balances.t',
781     payment_type => 'cash_payment',
782     patron_credit => '0.00',
783     payments => [ [ $xact_id, '10.00' ] ]
784 };
785 $pay_resp = pay_bills($payment_blob);
786
787 is(
788     scalar( @{ $pay_resp->{payments} } ),
789     1,
790     'Payment response included one payment id'
791 );
792
793 $summary = fetch_billable_xact_summary($xact_id);
794 is(
795     $summary->balance_owed,
796     '40.00',
797     'Remaining balance of 40.00 after payment'
798 );
799
800 ### check-in the lost copy
801 $checkin_resp = $script->do_checkin_override({
802     barcode => $item_barcode});
803 is(
804     $checkin_resp->{ilsevent},
805     0,
806     'Checkin returned a SUCCESS event'
807 );
808
809 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
810 if (my $item_resp = $item_req->recv) {
811     if (my $item = $item_resp->content) {
812         ok(
813             $item->status == 7 || $item->status == 0,
814             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
815         );
816     }
817 }
818
819 ### verify ending state
820
821 $summary = fetch_billable_xact_summary($xact_id);
822 is(
823     $summary->balance_owed,
824     '0.00',
825     'Patron has a balance of 0.00 (negative balance prevented)'
826 );
827
828
829 ###############################
830 ## 11. Manually voiding lost book fee does not result in negative balances
831 ###############################
832 #
833 #### Setup use case variables
834 #$xact_id = 5;
835 #$item_id = 6;
836 #$item_barcode = 'CONC4000040';
837 #
838 ## Setup Org Unit Settings
839 # ALREADY SET:
840 #     'bill.prohibit_negative_balance_default' => 1
841 #
842 #$summary = fetch_billable_xact_summary($xact_id);
843 #ok( $summary, 'CASE 11: Found the transaction summary');
844 #is(
845 #    $summary->balance_owed,
846 #    '50.00',
847 #    'Starting balance owed is 50.00 for lost item'
848 #);
849 #
850 #### confirm the copy is lost
851 #$item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
852 #if (my $item_resp = $item_req->recv) {
853 #    if (my $item = $item_resp->content) {
854 #        is(
855 #            $item->status,
856 #            3,
857 #            'Item with id = ' . $item_id . ' has status of LOST'
858 #        );
859 #    }
860 #}
861 #
862 #### partially pay the bill
863 #$payment_blob = {
864 #    userid => $patron_id,
865 #    note => '09-lp1198465_neg_balances.t',
866 #    payment_type => 'cash_payment',
867 #    patron_credit => '0.00',
868 #    payments => [ [ $xact_id, '10.00' ] ]
869 #};
870 #$pay_resp = pay_bills($payment_blob);
871 #
872 #is(
873 #    scalar( @{ $pay_resp->{payments} } ),
874 #    1,
875 #    'Payment response included one payment id'
876 #);
877 #
878 #$summary = fetch_billable_xact_summary($xact_id);
879 #is(
880 #    $summary->balance_owed,
881 #    '40.00',
882 #    'Remaining balance of 40.00 after payment'
883 #);
884 #
885 #### TODO: manually void "the rest" of the bill (i.e. prevent neg bal)
886 #### XXX: HARDCODING billing id for now; should look up the LOST bill for this xact?
887 #my @billing_ids = (6);
888 #my $void_resp = void_bills(\@billing_ids);
889 #
890 #is(
891 #    $void_resp,
892 #    '1',
893 #    'Voiding was successful'
894 #);
895 #
896 #### verify ending state
897 #
898 #$summary = fetch_billable_xact_summary($xact_id);
899 #is(
900 #    $summary->balance_owed,
901 #    '0.00',
902 #    'Patron has a balance of 0.00 (negative balance prohibited)'
903 #);
904
905
906 ##############################
907 # 12. Test negative balance settings on fines
908 ##############################
909
910 # Setup next patron
911 $patron_id = 5;
912 $patron_usrname = '99999387993';
913
914 # Look up the patron
915 if ($user_obj = retrieve_patron($patron_id)) {
916     is(
917         ref $user_obj,
918         'Fieldmapper::actor::user',
919         'open-ils.storage.direct.actor.user.retrieve returned aou object'
920     );
921     is(
922         $user_obj->usrname,
923         $patron_usrname,
924         'Patron with id = ' . $patron_id . ' has username ' . $patron_usrname
925     );
926 }
927
928 ### Setup use case variables
929 $xact_id = 7;
930 $item_id = 8;
931 $item_barcode = 'CONC4000043';
932
933 # Setup Org Unit Settings
934 # ALREADY SET:
935 #     'bill.prohibit_negative_balance_default' => 1
936
937 $summary = fetch_billable_xact_summary($xact_id);
938 ok( $summary, 'CASE 12: Found the transaction summary');
939 is(
940     $summary->balance_owed,
941     '0.70',
942     'Starting balance owed is 0.70 for overdue fines'
943 );
944
945 ### partially pay the bill
946 $payment_blob = {
947     userid => $patron_id,
948     note => '09-lp1198465_neg_balances.t',
949     payment_type => 'cash_payment',
950     patron_credit => '0.00',
951     payments => [ [ $xact_id, '0.20' ] ]
952 };
953 $pay_resp = pay_bills($payment_blob);
954
955 is(
956     scalar( @{ $pay_resp->{payments} } ),
957     1,
958     'Payment response included one payment id'
959 );
960
961 $summary = fetch_billable_xact_summary($xact_id);
962 is(
963     $summary->balance_owed,
964     '0.50',
965     'Remaining balance of 0.50 after payment'
966 );
967
968 ### Check in using Amnesty Mode
969 $checkin_resp = $script->do_checkin_override({
970     barcode => $item_barcode,
971     void_overdues => 1
972 });
973 is(
974     $checkin_resp->{ilsevent},
975     0,
976     'Checkin returned a SUCCESS event'
977 );
978
979 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
980 if (my $item_resp = $item_req->recv) {
981     if (my $item = $item_resp->content) {
982         ok(
983             $item->status == 7 || $item->status == 0,
984             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
985         );
986     }
987 }
988
989 ### verify ending state
990 $summary = fetch_billable_xact_summary($xact_id);
991 is(
992     $summary->balance_owed,
993     '0.00',
994     'Patron has a balance of 0.00 (remaining fines forgiven)'
995 );
996
997
998 ##############################
999 # 10. Interval Testing
1000 ##############################
1001
1002 # Setup Org Unit Settings
1003 # ALREADY SET:
1004 #     'bill.prohibit_negative_balance_default' => 1
1005
1006 # Setup Org Unit Settings
1007 $settings = {
1008     'bill.negative_balance_interval_default' => '1 hour'
1009 };
1010
1011 $apputils->simplereq(
1012     'open-ils.actor',
1013     'open-ils.actor.org_unit.settings.update',
1014     $script->authtoken,
1015     $org_id,
1016     $settings
1017 );
1018
1019 ### Setup use case variables
1020 $xact_id = 8;
1021 $item_id = 9;
1022 $item_barcode = 'CONC4000044';
1023
1024 $summary = fetch_billable_xact_summary($xact_id);
1025 ok( $summary, 'CASE 10.1: Found the transaction summary');
1026 is(
1027     $summary->balance_owed,
1028     '0.00',
1029     'Starting balance owed is 0.00 (LOST fee paid)'
1030 );
1031
1032 ### Check in first item (right after its payment)
1033 $checkin_resp = $script->do_checkin_override({
1034     barcode => $item_barcode,
1035 });
1036 is(
1037     $checkin_resp->{ilsevent},
1038     0,
1039     'Checkin returned a SUCCESS event'
1040 );
1041
1042 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
1043 if (my $item_resp = $item_req->recv) {
1044     if (my $item = $item_resp->content) {
1045         ok(
1046             $item->status == 7 || $item->status == 0,
1047             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
1048         );
1049     }
1050 }
1051
1052 ### verify ending state for 10.1
1053 $summary = fetch_billable_xact_summary($xact_id);
1054 is(
1055     $summary->balance_owed,
1056     '-50.00',
1057     'Patron has a balance of -50.00 (lost item returned during interval)'
1058 );
1059
1060 ### Setup use case variables
1061 $xact_id = 9;
1062 $item_id = 10;
1063 $item_barcode = 'CONC4000045';
1064
1065 $summary = fetch_billable_xact_summary($xact_id);
1066 ok( $summary, 'CASE 10.2: Found the transaction summary');
1067 is(
1068     $summary->balance_owed,
1069     '0.00',
1070     'Starting balance owed is 0.00 (LOST fee paid)'
1071 );
1072
1073 ### Check in second item (2 hours after its payment)
1074 $checkin_resp = $script->do_checkin_override({
1075     barcode => $item_barcode,
1076 });
1077 is(
1078     $checkin_resp->{ilsevent},
1079     0,
1080     'Checkin returned a SUCCESS event'
1081 );
1082
1083 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
1084 if (my $item_resp = $item_req->recv) {
1085     if (my $item = $item_resp->content) {
1086         ok(
1087             $item->status == 7 || $item->status == 0,
1088             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
1089         );
1090     }
1091 }
1092
1093 ### verify ending state
1094 $summary = fetch_billable_xact_summary($xact_id);
1095 is(
1096     $summary->balance_owed,
1097     '0.00',
1098     'Patron has a balance of 0.00 (lost item returned after interval)'
1099 );
1100
1101
1102 #############################
1103 # 6. Restores Overdue Fines Appropriately, No Previous "Voids", Patron Will Not Owe On Lost Item Return
1104 #############################
1105
1106 ### Setup use case variables
1107 $xact_id = 10;
1108 $item_id = 11;
1109 $item_barcode = 'CONC4000046';
1110
1111 # Setup Org Unit Settings
1112 $settings = {
1113     'bill.negative_balance_interval_default' => 0, #unset previous setting
1114     'circ.void_overdue_on_lost' => 1,
1115     'circ.restore_overdue_on_lost_return' => 1,
1116     'circ.lost.generate_overdue_on_checkin' => 1
1117 };
1118
1119 $apputils->simplereq(
1120     'open-ils.actor',
1121     'open-ils.actor.org_unit.settings.update',
1122     $script->authtoken,
1123     $org_id,
1124     $settings
1125 );
1126
1127 $summary = fetch_billable_xact_summary($xact_id);
1128 ok( $summary, 'CASE 6: Found the transaction summary');
1129 is(
1130     $summary->balance_owed,
1131     '40.00',
1132     'Starting balance owed is 40.00 for partially paid lost item'
1133 );
1134
1135 ### check-in the lost copy
1136
1137 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
1138 if (my $item_resp = $item_req->recv) {
1139     if (my $item = $item_resp->content) {
1140         is(
1141             ref $item,
1142             'Fieldmapper::asset::copy',
1143             'open-ils.storage.direct.asset.copy.retrieve returned acp object'
1144         );
1145         is(
1146             $item->status,
1147             3,
1148             'Item with id = ' . $item_id . ' has status of LOST'
1149         );
1150     }
1151 }
1152
1153 $checkin_resp = $script->do_checkin_override({
1154     barcode => $item_barcode});
1155 is(
1156     $checkin_resp->{ilsevent},
1157     0,
1158     'Checkin returned a SUCCESS event'
1159 );
1160
1161 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
1162 if (my $item_resp = $item_req->recv) {
1163     if (my $item = $item_resp->content) {
1164         ok(
1165             $item->status == 7 || $item->status == 0,
1166             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
1167         );
1168     }
1169 }
1170
1171 ### verify ending state
1172
1173 $summary = fetch_billable_xact_summary($xact_id);
1174 is(
1175     $summary->balance_owed,
1176     '0.00',
1177     'Patron has a balance of 0.00 (negative balance prevented)'
1178 );
1179
1180
1181 #############################
1182 # 7. Restores Overdue Fines Appropriately, No Previous "Voids", Patron Will Still Owe On Lost Item Return
1183 #############################
1184
1185 ### Setup use case variables
1186 $xact_id = 11;
1187 $item_id = 12;
1188 $item_barcode = 'CONC4000047';
1189
1190 # Setup Org Unit Settings
1191 # ALREADY SET:
1192 #     'bill.prohibit_negative_balance_default' => 1
1193 #     'circ.void_overdue_on_lost' => 1,
1194 #     'circ.restore_overdue_on_lost_return' => 1,
1195 #     'circ.lost.generate_overdue_on_checkin' => 1
1196
1197 $apputils->simplereq(
1198     'open-ils.actor',
1199     'open-ils.actor.org_unit.settings.update',
1200     $script->authtoken,
1201     $org_id,
1202     $settings
1203 );
1204
1205 $summary = fetch_billable_xact_summary($xact_id);
1206 ok( $summary, 'CASE 7: Found the transaction summary');
1207 is(
1208     $summary->balance_owed,
1209     '0.70',
1210     'Starting balance owed is 0.70 for overdues'
1211 );
1212
1213 ### mark item as LOST
1214 $apputils->simplereq(
1215     'open-ils.circ',
1216     'open-ils.circ.circulation.set_lost',
1217     $script->authtoken,
1218     {barcode => $item_barcode}
1219 );
1220
1221 $summary = fetch_billable_xact_summary($xact_id);
1222 ok( $summary, 'Found the transaction summary');
1223 is(
1224     $summary->balance_owed,
1225     '50.00',
1226     'New balance owed is 50.00 for LOST fee'
1227 );
1228
1229 ### partially pay the bill
1230 $payment_blob = {
1231     userid => $patron_id,
1232     note => '09-lp1198465_neg_balances.t',
1233     payment_type => 'cash_payment',
1234     patron_credit => '0.00',
1235     payments => [ [ $xact_id, '0.10' ] ]
1236 };
1237 $pay_resp = pay_bills($payment_blob);
1238
1239 is(
1240     scalar( @{ $pay_resp->{payments} } ),
1241     1,
1242     'Payment response included one payment id'
1243 );
1244
1245 $summary = fetch_billable_xact_summary($xact_id);
1246 is(
1247     $summary->balance_owed,
1248     '49.90',
1249     'Remaining balance of 49.90 after payment'
1250 );
1251
1252 ### check-in the lost copy
1253
1254 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
1255 if (my $item_resp = $item_req->recv) {
1256     if (my $item = $item_resp->content) {
1257         is(
1258             ref $item,
1259             'Fieldmapper::asset::copy',
1260             'open-ils.storage.direct.asset.copy.retrieve returned acp object'
1261         );
1262         is(
1263             $item->status,
1264             3,
1265             'Item with id = ' . $item_id . ' has status of LOST'
1266         );
1267     }
1268 }
1269
1270 $checkin_resp = $script->do_checkin_override({
1271     barcode => $item_barcode});
1272 is(
1273     $checkin_resp->{ilsevent},
1274     0,
1275     'Checkin returned a SUCCESS event'
1276 );
1277
1278 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
1279 if (my $item_resp = $item_req->recv) {
1280     if (my $item = $item_resp->content) {
1281         ok(
1282             $item->status == 7 || $item->status == 0,
1283             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
1284         );
1285     }
1286 }
1287
1288 ### verify ending state
1289
1290 $summary = fetch_billable_xact_summary($xact_id);
1291 is(
1292     $summary->balance_owed,
1293     '0.60',
1294     'Patron has a balance of 0.60 due to reinstated overdue fines'
1295 );
1296
1297
1298 #############################
1299 # 9. Restore Overdue Fines Appropriately, Previous Voids, Negative Balance Allowed
1300 #############################
1301
1302 ### Setup use case variables
1303 $xact_id = 12;
1304 $item_id = 13;
1305 $item_barcode = 'CONC4000048';
1306
1307 # Setup Org Unit Settings
1308 # ALREADY SET:
1309 #     'bill.prohibit_negative_balance_default' => 1
1310 #     'circ.void_overdue_on_lost' => 1,
1311 #     'circ.restore_overdue_on_lost_return' => 1,
1312 #     'circ.lost.generate_overdue_on_checkin' => 1
1313
1314 $apputils->simplereq(
1315     'open-ils.actor',
1316     'open-ils.actor.org_unit.settings.update',
1317     $script->authtoken,
1318     $org_id,
1319     $settings
1320 );
1321
1322 $summary = fetch_billable_xact_summary($xact_id);
1323 ok( $summary, 'CASE 9: Found the transaction summary');
1324 is(
1325     $summary->balance_owed,
1326     '50.00',
1327     'Starting balance owed is 50.00 for lost item'
1328 );
1329
1330 ### partially pay the bill
1331 $payment_blob = {
1332     userid => $patron_id,
1333     note => '09-lp1198465_neg_balances.t',
1334     payment_type => 'cash_payment',
1335     patron_credit => '0.00',
1336     payments => [ [ $xact_id, '10.00' ] ]
1337 };
1338 $pay_resp = pay_bills($payment_blob);
1339
1340 is(
1341     scalar( @{ $pay_resp->{payments} } ),
1342     1,
1343     'Payment response included one payment id'
1344 );
1345
1346 $summary = fetch_billable_xact_summary($xact_id);
1347 is(
1348     $summary->balance_owed,
1349     '40.00',
1350     'Remaining balance of 40.00 after payment'
1351 );
1352
1353 ### check-in the lost copy
1354
1355 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
1356 if (my $item_resp = $item_req->recv) {
1357     if (my $item = $item_resp->content) {
1358         is(
1359             ref $item,
1360             'Fieldmapper::asset::copy',
1361             'open-ils.storage.direct.asset.copy.retrieve returned acp object'
1362         );
1363         is(
1364             $item->status,
1365             3,
1366             'Item with id = ' . $item_id . ' has status of LOST'
1367         );
1368     }
1369 }
1370
1371 $checkin_resp = $script->do_checkin_override({
1372     barcode => $item_barcode});
1373 is(
1374     $checkin_resp->{ilsevent},
1375     0,
1376     'Checkin returned a SUCCESS event'
1377 );
1378
1379 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
1380 if (my $item_resp = $item_req->recv) {
1381     if (my $item = $item_resp->content) {
1382         ok(
1383             $item->status == 7 || $item->status == 0,
1384             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
1385         );
1386     }
1387 }
1388
1389 ### verify ending state
1390
1391 $summary = fetch_billable_xact_summary($xact_id);
1392 is(
1393     $summary->balance_owed,
1394     '0.00',
1395     'Patron has a balance of 0.00 (negative balance prevented)'
1396 );
1397
1398
1399 #############################
1400 # 8. Restore Overdue Fines Appropriately, Previous Voids, Negative Balance Allowed
1401 #############################
1402
1403 ## TODO: consider using a later xact_id/item_id, instead of reverting back to user 4
1404
1405 # Setup first patron (again)
1406 $patron_id = 4;
1407 $patron_usrname = '99999355250';
1408
1409 # Look up the patron
1410 if ($user_obj = retrieve_patron($patron_id)) {
1411     is(
1412         ref $user_obj,
1413         'Fieldmapper::actor::user',
1414         'open-ils.storage.direct.actor.user.retrieve returned aou object'
1415     );
1416     is(
1417         $user_obj->usrname,
1418         $patron_usrname,
1419         'Patron with id = ' . $patron_id . ' has username ' . $patron_usrname
1420     );
1421 }
1422
1423 ### Setup use case variables
1424 $xact_id = 6;
1425 $item_id = 7;
1426 $item_barcode = 'CONC4000042';
1427
1428 # Setup Org Unit Settings
1429 # ALREADY SET:
1430 #     'circ.void_overdue_on_lost' => 1,
1431 #     'circ.restore_overdue_on_lost_return' => 1,
1432 #     'circ.lost.generate_overdue_on_checkin' => 1
1433 $settings = {
1434     'bill.prohibit_negative_balance_default' => 0
1435 };
1436
1437 $apputils->simplereq(
1438     'open-ils.actor',
1439     'open-ils.actor.org_unit.settings.update',
1440     $script->authtoken,
1441     $org_id,
1442     $settings
1443 );
1444
1445 $summary = fetch_billable_xact_summary($xact_id);
1446 ok( $summary, 'CASE 8: Found the transaction summary');
1447 is(
1448     $summary->balance_owed,
1449     '50.00',
1450     'Starting balance owed is 50.00 for lost item'
1451 );
1452
1453 ### partially pay the bill
1454 $payment_blob = {
1455     userid => $patron_id,
1456     note => '09-lp1198465_neg_balances.t',
1457     payment_type => 'cash_payment',
1458     patron_credit => '0.00',
1459     payments => [ [ $xact_id, '10.00' ] ]
1460 };
1461 $pay_resp = pay_bills($payment_blob);
1462
1463 is(
1464     scalar( @{ $pay_resp->{payments} } ),
1465     1,
1466     'Payment response included one payment id'
1467 );
1468
1469 $summary = fetch_billable_xact_summary($xact_id);
1470 is(
1471     $summary->balance_owed,
1472     '40.00',
1473     'Remaining balance of 40.00 after payment'
1474 );
1475
1476 ### check-in the lost copy
1477
1478 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
1479 if (my $item_resp = $item_req->recv) {
1480     if (my $item = $item_resp->content) {
1481         is(
1482             ref $item,
1483             'Fieldmapper::asset::copy',
1484             'open-ils.storage.direct.asset.copy.retrieve returned acp object'
1485         );
1486         is(
1487             $item->status,
1488             3,
1489             'Item with id = ' . $item_id . ' has status of LOST'
1490         );
1491     }
1492 }
1493
1494 $checkin_resp = $script->do_checkin_override({
1495     barcode => $item_barcode});
1496 is(
1497     $checkin_resp->{ilsevent},
1498     0,
1499     'Checkin returned a SUCCESS event'
1500 );
1501
1502 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
1503 if (my $item_resp = $item_req->recv) {
1504     if (my $item = $item_resp->content) {
1505         ok(
1506             $item->status == 7 || $item->status == 0,
1507             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
1508         );
1509     }
1510 }
1511
1512 ### verify ending state
1513
1514 $summary = fetch_billable_xact_summary($xact_id);
1515 is(
1516     $summary->balance_owed,
1517     '-7.00',
1518     'Patron has a negative balance of 7.00 due to overpayment'
1519 );
1520
1521
1522
1523 $script->logout();
1524
1525