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