LP#1670407 Add tests for xact_finish close/re-open
[working/Evergreen.git] / Open-ILS / src / perlmods / live_t / 09-lp1198465_neg_balances.t
1 #!perl
2
3 use Test::More tests => 129;
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 ok(
535     $summary->xact_finish ne '',
536     'xact_finish is set due to 0.00 balance'
537 );
538
539 ### check-in the lost copy
540
541 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
542 if (my $item_resp = $item_req->recv) {
543     if (my $item = $item_resp->content) {
544         is(
545             ref $item,
546             'Fieldmapper::asset::copy',
547             'open-ils.storage.direct.asset.copy.retrieve returned acp object'
548         );
549         is(
550             $item->status,
551             3,
552             'Item with id = ' . $item_id . ' has status of LOST'
553         );
554     }
555 }
556
557 $checkin_resp = $script->do_checkin_override({
558     barcode => $item_barcode});
559 is(
560     $checkin_resp->{ilsevent},
561     0,
562     'Checkin returned a SUCCESS event'
563 );
564
565 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
566 if (my $item_resp = $item_req->recv) {
567     if (my $item = $item_resp->content) {
568         ok(
569             $item->status == 7 || $item->status == 0,
570             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
571         );
572     }
573 }
574
575 ### verify ending state
576
577 $summary = fetch_billable_xact_summary($xact_id);
578 is(
579     $summary->balance_owed,
580     '-50.00',
581     'Patron has a negative balance (credit) of 50.00 due to overpayment'
582 );
583
584 ok(
585     !defined($summary->xact_finish),
586     'xact_finish is not set due to non-zero balance'
587 );
588
589
590 ##############################
591 # 14. RERUN of Case 12. Test negative balance settings on fines
592 # SETTINGS: Prohibit negative balances on bills for overdue materials
593 ##############################
594
595 ### Setup use case variables
596 $xact_id = 16;
597 $item_id = 17;
598 $item_barcode = 'CONC4000052';
599
600 # Setup Org Unit Settings
601 # ALREADY SET:
602 #    'bill.prohibit_negative_balance_on_overdues' => 1
603
604 $summary = fetch_billable_xact_summary($xact_id);
605 ok( $summary, 'CASE 14b: Found the transaction summary');
606 is(
607     $summary->balance_owed,
608     '0.70',
609     'Starting balance owed is 0.70 for overdue fines'
610 );
611
612 ### partially pay the bill
613 $payment_blob = {
614     userid => $patron_id,
615     note => '09-lp1198465_neg_balances.t',
616     payment_type => 'cash_payment',
617     patron_credit => '0.00',
618     payments => [ [ $xact_id, '0.20' ] ]
619 };
620 $pay_resp = pay_bills($payment_blob);
621
622 is(
623     scalar( @{ $pay_resp->{payments} } ),
624     1,
625     'Payment response included one payment id'
626 );
627
628 $summary = fetch_billable_xact_summary($xact_id);
629 is(
630     $summary->balance_owed,
631     '0.50',
632     'Remaining balance of 0.50 after payment'
633 );
634
635 ### Check in using Amnesty Mode
636 $checkin_resp = $script->do_checkin_override({
637     barcode => $item_barcode,
638     void_overdues => 1
639 });
640 is(
641     $checkin_resp->{ilsevent},
642     0,
643     'Checkin returned a SUCCESS event'
644 );
645
646 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
647 if (my $item_resp = $item_req->recv) {
648     if (my $item = $item_resp->content) {
649         ok(
650             $item->status == 7 || $item->status == 0,
651             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
652         );
653     }
654 }
655
656 ### verify ending state
657 $summary = fetch_billable_xact_summary($xact_id);
658 is(
659     $summary->balance_owed,
660     '0.00',
661     'Patron has a balance of 0.00 (negative balance prevented)'
662 );
663
664
665 ##############################
666 # 3. Basic No Negative Balance Test
667 ##############################
668
669 # Re-setup first patron
670 $patron_id = 4;
671 $patron_usrname = '99999355250';
672
673 # Look up the patron
674 if ($user_obj = retrieve_patron($patron_id)) {
675     is(
676         ref $user_obj,
677         'Fieldmapper::actor::user',
678         'open-ils.storage.direct.actor.user.retrieve returned aou object'
679     );
680     is(
681         $user_obj->usrname,
682         $patron_usrname,
683         'Patron with id = ' . $patron_id . ' has username ' . $patron_usrname
684     );
685 }
686
687
688 ### Setup use case variables
689 $xact_id = 3;
690 $item_id = 4;
691 $item_barcode = 'CONC4000039';
692
693 # Setup Org Unit Settings
694 $settings = {
695     'bill.prohibit_negative_balance_on_overdues' => 0, #unset from previous test
696     'bill.prohibit_negative_balance_default' => 1
697 };
698 $apputils->simplereq(
699     'open-ils.actor',
700     'open-ils.actor.org_unit.settings.update',
701     $script->authtoken,
702     $org_id,
703     $settings
704 );
705
706 $summary = fetch_billable_xact_summary($xact_id);
707 ok( $summary, 'CASE 3: Found the transaction summary');
708 is(
709     $summary->balance_owed,
710     '50.00',
711     'Starting balance owed is 50.00 for lost item'
712 );
713
714 ### check-in the lost copy
715
716 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
717 if (my $item_resp = $item_req->recv) {
718     if (my $item = $item_resp->content) {
719         is(
720             $item->status,
721             3,
722             'Item with id = ' . $item_id . ' has status of LOST'
723         );
724     }
725 }
726
727 $checkin_resp = $script->do_checkin_override({
728     barcode => $item_barcode});
729 is(
730     $checkin_resp->{ilsevent},
731     0,
732     'Checkin returned a SUCCESS event'
733 );
734
735 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
736 if (my $item_resp = $item_req->recv) {
737     if (my $item = $item_resp->content) {
738         ok(
739             $item->status == 7 || $item->status == 0,
740             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
741         );
742     }
743 }
744
745 ### verify ending state
746
747 $summary = fetch_billable_xact_summary($xact_id);
748 is(
749     $summary->balance_owed,
750     '0.00',
751     'Patron has a balance of 0.00 (negative balance prevented)'
752 );
753
754 ##############################
755 # 4. Prohibit Negative Balances with Partial Payment
756 ##############################
757
758 ### Setup use case variables
759 $xact_id = 4;
760 $item_id = 5;
761 $item_barcode = 'CONC4000040';
762
763 # Setup Org Unit Settings
764 # ALREADY SET:
765 #     'bill.prohibit_negative_balance_default' => 1
766
767 $summary = fetch_billable_xact_summary($xact_id);
768 ok( $summary, 'CASE 4: Found the transaction summary');
769 is(
770     $summary->balance_owed,
771     '50.00',
772     'Starting balance owed is 50.00 for lost item'
773 );
774
775 ### confirm the copy is lost
776 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
777 if (my $item_resp = $item_req->recv) {
778     if (my $item = $item_resp->content) {
779         is(
780             $item->status,
781             3,
782             'Item with id = ' . $item_id . ' has status of LOST'
783         );
784     }
785 }
786
787 ### partially pay the bill
788 $payment_blob = {
789     userid => $patron_id,
790     note => '09-lp1198465_neg_balances.t',
791     payment_type => 'cash_payment',
792     patron_credit => '0.00',
793     payments => [ [ $xact_id, '10.00' ] ]
794 };
795 $pay_resp = pay_bills($payment_blob);
796
797 is(
798     scalar( @{ $pay_resp->{payments} } ),
799     1,
800     'Payment response included one payment id'
801 );
802
803 $summary = fetch_billable_xact_summary($xact_id);
804 is(
805     $summary->balance_owed,
806     '40.00',
807     'Remaining balance of 40.00 after payment'
808 );
809
810 ### check-in the lost copy
811 $checkin_resp = $script->do_checkin_override({
812     barcode => $item_barcode});
813 is(
814     $checkin_resp->{ilsevent},
815     0,
816     'Checkin returned a SUCCESS event'
817 );
818
819 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
820 if (my $item_resp = $item_req->recv) {
821     if (my $item = $item_resp->content) {
822         ok(
823             $item->status == 7 || $item->status == 0,
824             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
825         );
826     }
827 }
828
829 ### verify ending state
830
831 $summary = fetch_billable_xact_summary($xact_id);
832 is(
833     $summary->balance_owed,
834     '0.00',
835     'Patron has a balance of 0.00 (negative balance prevented)'
836 );
837
838
839 ###############################
840 ## 11. Manually voiding lost book fee does not result in negative balances
841 ###############################
842 #
843 #### Setup use case variables
844 #$xact_id = 5;
845 #$item_id = 6;
846 #$item_barcode = 'CONC4000040';
847 #
848 ## Setup Org Unit Settings
849 # ALREADY SET:
850 #     'bill.prohibit_negative_balance_default' => 1
851 #
852 #$summary = fetch_billable_xact_summary($xact_id);
853 #ok( $summary, 'CASE 11: Found the transaction summary');
854 #is(
855 #    $summary->balance_owed,
856 #    '50.00',
857 #    'Starting balance owed is 50.00 for lost item'
858 #);
859 #
860 #### confirm the copy is lost
861 #$item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
862 #if (my $item_resp = $item_req->recv) {
863 #    if (my $item = $item_resp->content) {
864 #        is(
865 #            $item->status,
866 #            3,
867 #            'Item with id = ' . $item_id . ' has status of LOST'
868 #        );
869 #    }
870 #}
871 #
872 #### partially pay the bill
873 #$payment_blob = {
874 #    userid => $patron_id,
875 #    note => '09-lp1198465_neg_balances.t',
876 #    payment_type => 'cash_payment',
877 #    patron_credit => '0.00',
878 #    payments => [ [ $xact_id, '10.00' ] ]
879 #};
880 #$pay_resp = pay_bills($payment_blob);
881 #
882 #is(
883 #    scalar( @{ $pay_resp->{payments} } ),
884 #    1,
885 #    'Payment response included one payment id'
886 #);
887 #
888 #$summary = fetch_billable_xact_summary($xact_id);
889 #is(
890 #    $summary->balance_owed,
891 #    '40.00',
892 #    'Remaining balance of 40.00 after payment'
893 #);
894 #
895 #### TODO: manually void "the rest" of the bill (i.e. prevent neg bal)
896 #### XXX: HARDCODING billing id for now; should look up the LOST bill for this xact?
897 #my @billing_ids = (6);
898 #my $void_resp = void_bills(\@billing_ids);
899 #
900 #is(
901 #    $void_resp,
902 #    '1',
903 #    'Voiding was successful'
904 #);
905 #
906 #### verify ending state
907 #
908 #$summary = fetch_billable_xact_summary($xact_id);
909 #is(
910 #    $summary->balance_owed,
911 #    '0.00',
912 #    'Patron has a balance of 0.00 (negative balance prohibited)'
913 #);
914
915
916 ##############################
917 # 12. Test negative balance settings on fines
918 ##############################
919
920 # Setup next patron
921 $patron_id = 5;
922 $patron_usrname = '99999387993';
923
924 # Look up the patron
925 if ($user_obj = retrieve_patron($patron_id)) {
926     is(
927         ref $user_obj,
928         'Fieldmapper::actor::user',
929         'open-ils.storage.direct.actor.user.retrieve returned aou object'
930     );
931     is(
932         $user_obj->usrname,
933         $patron_usrname,
934         'Patron with id = ' . $patron_id . ' has username ' . $patron_usrname
935     );
936 }
937
938 ### Setup use case variables
939 $xact_id = 7;
940 $item_id = 8;
941 $item_barcode = 'CONC4000043';
942
943 # Setup Org Unit Settings
944 # ALREADY SET:
945 #     'bill.prohibit_negative_balance_default' => 1
946
947 $summary = fetch_billable_xact_summary($xact_id);
948 ok( $summary, 'CASE 12: Found the transaction summary');
949 is(
950     $summary->balance_owed,
951     '0.70',
952     'Starting balance owed is 0.70 for overdue fines'
953 );
954
955 ### partially pay the bill
956 $payment_blob = {
957     userid => $patron_id,
958     note => '09-lp1198465_neg_balances.t',
959     payment_type => 'cash_payment',
960     patron_credit => '0.00',
961     payments => [ [ $xact_id, '0.20' ] ]
962 };
963 $pay_resp = pay_bills($payment_blob);
964
965 is(
966     scalar( @{ $pay_resp->{payments} } ),
967     1,
968     'Payment response included one payment id'
969 );
970
971 $summary = fetch_billable_xact_summary($xact_id);
972 is(
973     $summary->balance_owed,
974     '0.50',
975     'Remaining balance of 0.50 after payment'
976 );
977
978 ### Check in using Amnesty Mode
979 $checkin_resp = $script->do_checkin_override({
980     barcode => $item_barcode,
981     void_overdues => 1
982 });
983 is(
984     $checkin_resp->{ilsevent},
985     0,
986     'Checkin returned a SUCCESS event'
987 );
988
989 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
990 if (my $item_resp = $item_req->recv) {
991     if (my $item = $item_resp->content) {
992         ok(
993             $item->status == 7 || $item->status == 0,
994             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
995         );
996     }
997 }
998
999 ### verify ending state
1000 $summary = fetch_billable_xact_summary($xact_id);
1001 is(
1002     $summary->balance_owed,
1003     '0.00',
1004     'Patron has a balance of 0.00 (remaining fines forgiven)'
1005 );
1006
1007
1008 ##############################
1009 # 10. Interval Testing
1010 ##############################
1011
1012 # Setup Org Unit Settings
1013 # ALREADY SET:
1014 #     'bill.prohibit_negative_balance_default' => 1
1015
1016 # Setup Org Unit Settings
1017 $settings = {
1018     'bill.negative_balance_interval_default' => '1 hour'
1019 };
1020
1021 $apputils->simplereq(
1022     'open-ils.actor',
1023     'open-ils.actor.org_unit.settings.update',
1024     $script->authtoken,
1025     $org_id,
1026     $settings
1027 );
1028
1029 ### Setup use case variables
1030 $xact_id = 8;
1031 $item_id = 9;
1032 $item_barcode = 'CONC4000044';
1033
1034 $summary = fetch_billable_xact_summary($xact_id);
1035 ok( $summary, 'CASE 10.1: Found the transaction summary');
1036 is(
1037     $summary->balance_owed,
1038     '0.00',
1039     'Starting balance owed is 0.00 (LOST fee paid)'
1040 );
1041
1042 ### Check in first item (right after its payment)
1043 $checkin_resp = $script->do_checkin_override({
1044     barcode => $item_barcode,
1045 });
1046 is(
1047     $checkin_resp->{ilsevent},
1048     0,
1049     'Checkin returned a SUCCESS event'
1050 );
1051
1052 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
1053 if (my $item_resp = $item_req->recv) {
1054     if (my $item = $item_resp->content) {
1055         ok(
1056             $item->status == 7 || $item->status == 0,
1057             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
1058         );
1059     }
1060 }
1061
1062 ### verify ending state for 10.1
1063 $summary = fetch_billable_xact_summary($xact_id);
1064 is(
1065     $summary->balance_owed,
1066     '-50.00',
1067     'Patron has a balance of -50.00 (lost item returned during interval)'
1068 );
1069
1070 ### Setup use case variables
1071 $xact_id = 9;
1072 $item_id = 10;
1073 $item_barcode = 'CONC4000045';
1074
1075 $summary = fetch_billable_xact_summary($xact_id);
1076 ok( $summary, 'CASE 10.2: Found the transaction summary');
1077 is(
1078     $summary->balance_owed,
1079     '0.00',
1080     'Starting balance owed is 0.00 (LOST fee paid)'
1081 );
1082
1083 ### Check in second item (2 hours after its payment)
1084 $checkin_resp = $script->do_checkin_override({
1085     barcode => $item_barcode,
1086 });
1087 is(
1088     $checkin_resp->{ilsevent},
1089     0,
1090     'Checkin returned a SUCCESS event'
1091 );
1092
1093 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
1094 if (my $item_resp = $item_req->recv) {
1095     if (my $item = $item_resp->content) {
1096         ok(
1097             $item->status == 7 || $item->status == 0,
1098             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
1099         );
1100     }
1101 }
1102
1103 ### verify ending state
1104 $summary = fetch_billable_xact_summary($xact_id);
1105 is(
1106     $summary->balance_owed,
1107     '0.00',
1108     'Patron has a balance of 0.00 (lost item returned after interval)'
1109 );
1110
1111
1112 #############################
1113 # 6. Restores Overdue Fines Appropriately, No Previous "Voids", Patron Will Not Owe On Lost Item Return
1114 #############################
1115
1116 ### Setup use case variables
1117 $xact_id = 10;
1118 $item_id = 11;
1119 $item_barcode = 'CONC4000046';
1120
1121 # Setup Org Unit Settings
1122 $settings = {
1123     'bill.negative_balance_interval_default' => 0, #unset previous setting
1124     'circ.void_overdue_on_lost' => 1,
1125     'circ.restore_overdue_on_lost_return' => 1,
1126     'circ.lost.generate_overdue_on_checkin' => 1
1127 };
1128
1129 $apputils->simplereq(
1130     'open-ils.actor',
1131     'open-ils.actor.org_unit.settings.update',
1132     $script->authtoken,
1133     $org_id,
1134     $settings
1135 );
1136
1137 $summary = fetch_billable_xact_summary($xact_id);
1138 ok( $summary, 'CASE 6: Found the transaction summary');
1139 is(
1140     $summary->balance_owed,
1141     '40.00',
1142     'Starting balance owed is 40.00 for partially paid lost item'
1143 );
1144
1145 ### check-in the lost copy
1146
1147 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
1148 if (my $item_resp = $item_req->recv) {
1149     if (my $item = $item_resp->content) {
1150         is(
1151             ref $item,
1152             'Fieldmapper::asset::copy',
1153             'open-ils.storage.direct.asset.copy.retrieve returned acp object'
1154         );
1155         is(
1156             $item->status,
1157             3,
1158             'Item with id = ' . $item_id . ' has status of LOST'
1159         );
1160     }
1161 }
1162
1163 $checkin_resp = $script->do_checkin_override({
1164     barcode => $item_barcode});
1165 is(
1166     $checkin_resp->{ilsevent},
1167     0,
1168     'Checkin returned a SUCCESS event'
1169 );
1170
1171 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
1172 if (my $item_resp = $item_req->recv) {
1173     if (my $item = $item_resp->content) {
1174         ok(
1175             $item->status == 7 || $item->status == 0,
1176             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
1177         );
1178     }
1179 }
1180
1181 ### verify ending state
1182
1183 $summary = fetch_billable_xact_summary($xact_id);
1184 is(
1185     $summary->balance_owed,
1186     '0.00',
1187     'Patron has a balance of 0.00 (negative balance prevented)'
1188 );
1189
1190
1191 #############################
1192 # 7. Restores Overdue Fines Appropriately, No Previous "Voids", Patron Will Still Owe On Lost Item Return
1193 #############################
1194
1195 ### Setup use case variables
1196 $xact_id = 11;
1197 $item_id = 12;
1198 $item_barcode = 'CONC4000047';
1199
1200 # Setup Org Unit Settings
1201 # ALREADY SET:
1202 #     'bill.prohibit_negative_balance_default' => 1
1203 #     'circ.void_overdue_on_lost' => 1,
1204 #     'circ.restore_overdue_on_lost_return' => 1,
1205 #     'circ.lost.generate_overdue_on_checkin' => 1
1206
1207 $apputils->simplereq(
1208     'open-ils.actor',
1209     'open-ils.actor.org_unit.settings.update',
1210     $script->authtoken,
1211     $org_id,
1212     $settings
1213 );
1214
1215 $summary = fetch_billable_xact_summary($xact_id);
1216 ok( $summary, 'CASE 7: Found the transaction summary');
1217 is(
1218     $summary->balance_owed,
1219     '0.70',
1220     'Starting balance owed is 0.70 for overdues'
1221 );
1222
1223 ### mark item as LOST
1224 $apputils->simplereq(
1225     'open-ils.circ',
1226     'open-ils.circ.circulation.set_lost',
1227     $script->authtoken,
1228     {barcode => $item_barcode}
1229 );
1230
1231 $summary = fetch_billable_xact_summary($xact_id);
1232 ok( $summary, 'Found the transaction summary');
1233 is(
1234     $summary->balance_owed,
1235     '50.00',
1236     'New balance owed is 50.00 for LOST fee'
1237 );
1238
1239 ### partially pay the bill
1240 $payment_blob = {
1241     userid => $patron_id,
1242     note => '09-lp1198465_neg_balances.t',
1243     payment_type => 'cash_payment',
1244     patron_credit => '0.00',
1245     payments => [ [ $xact_id, '0.10' ] ]
1246 };
1247 $pay_resp = pay_bills($payment_blob);
1248
1249 is(
1250     scalar( @{ $pay_resp->{payments} } ),
1251     1,
1252     'Payment response included one payment id'
1253 );
1254
1255 $summary = fetch_billable_xact_summary($xact_id);
1256 is(
1257     $summary->balance_owed,
1258     '49.90',
1259     'Remaining balance of 49.90 after payment'
1260 );
1261
1262 ### check-in the lost copy
1263
1264 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
1265 if (my $item_resp = $item_req->recv) {
1266     if (my $item = $item_resp->content) {
1267         is(
1268             ref $item,
1269             'Fieldmapper::asset::copy',
1270             'open-ils.storage.direct.asset.copy.retrieve returned acp object'
1271         );
1272         is(
1273             $item->status,
1274             3,
1275             'Item with id = ' . $item_id . ' has status of LOST'
1276         );
1277     }
1278 }
1279
1280 $checkin_resp = $script->do_checkin_override({
1281     barcode => $item_barcode});
1282 is(
1283     $checkin_resp->{ilsevent},
1284     0,
1285     'Checkin returned a SUCCESS event'
1286 );
1287
1288 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
1289 if (my $item_resp = $item_req->recv) {
1290     if (my $item = $item_resp->content) {
1291         ok(
1292             $item->status == 7 || $item->status == 0,
1293             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
1294         );
1295     }
1296 }
1297
1298 ### verify ending state
1299
1300 $summary = fetch_billable_xact_summary($xact_id);
1301 is(
1302     $summary->balance_owed,
1303     '0.60',
1304     'Patron has a balance of 0.60 due to reinstated overdue fines'
1305 );
1306
1307
1308 #############################
1309 # 9. Restore Overdue Fines Appropriately, Previous Voids, Negative Balance Allowed
1310 #############################
1311
1312 ### Setup use case variables
1313 $xact_id = 12;
1314 $item_id = 13;
1315 $item_barcode = 'CONC4000048';
1316
1317 # Setup Org Unit Settings
1318 # ALREADY SET:
1319 #     'bill.prohibit_negative_balance_default' => 1
1320 #     'circ.void_overdue_on_lost' => 1,
1321 #     'circ.restore_overdue_on_lost_return' => 1,
1322 #     'circ.lost.generate_overdue_on_checkin' => 1
1323
1324 $apputils->simplereq(
1325     'open-ils.actor',
1326     'open-ils.actor.org_unit.settings.update',
1327     $script->authtoken,
1328     $org_id,
1329     $settings
1330 );
1331
1332 $summary = fetch_billable_xact_summary($xact_id);
1333 ok( $summary, 'CASE 9: Found the transaction summary');
1334 is(
1335     $summary->balance_owed,
1336     '50.00',
1337     'Starting balance owed is 50.00 for lost item'
1338 );
1339
1340 ### partially pay the bill
1341 $payment_blob = {
1342     userid => $patron_id,
1343     note => '09-lp1198465_neg_balances.t',
1344     payment_type => 'cash_payment',
1345     patron_credit => '0.00',
1346     payments => [ [ $xact_id, '10.00' ] ]
1347 };
1348 $pay_resp = pay_bills($payment_blob);
1349
1350 is(
1351     scalar( @{ $pay_resp->{payments} } ),
1352     1,
1353     'Payment response included one payment id'
1354 );
1355
1356 $summary = fetch_billable_xact_summary($xact_id);
1357 is(
1358     $summary->balance_owed,
1359     '40.00',
1360     'Remaining balance of 40.00 after payment'
1361 );
1362
1363 ### check-in the lost copy
1364
1365 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
1366 if (my $item_resp = $item_req->recv) {
1367     if (my $item = $item_resp->content) {
1368         is(
1369             ref $item,
1370             'Fieldmapper::asset::copy',
1371             'open-ils.storage.direct.asset.copy.retrieve returned acp object'
1372         );
1373         is(
1374             $item->status,
1375             3,
1376             'Item with id = ' . $item_id . ' has status of LOST'
1377         );
1378     }
1379 }
1380
1381 $checkin_resp = $script->do_checkin_override({
1382     barcode => $item_barcode});
1383 is(
1384     $checkin_resp->{ilsevent},
1385     0,
1386     'Checkin returned a SUCCESS event'
1387 );
1388
1389 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
1390 if (my $item_resp = $item_req->recv) {
1391     if (my $item = $item_resp->content) {
1392         ok(
1393             $item->status == 7 || $item->status == 0,
1394             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
1395         );
1396     }
1397 }
1398
1399 ### verify ending state
1400
1401 $summary = fetch_billable_xact_summary($xact_id);
1402 is(
1403     $summary->balance_owed,
1404     '0.00',
1405     'Patron has a balance of 0.00 (negative balance prevented)'
1406 );
1407
1408
1409 #############################
1410 # 8. Restore Overdue Fines Appropriately, Previous Voids, Negative Balance Allowed
1411 #############################
1412
1413 ## TODO: consider using a later xact_id/item_id, instead of reverting back to user 4
1414
1415 # Setup first patron (again)
1416 $patron_id = 4;
1417 $patron_usrname = '99999355250';
1418
1419 # Look up the patron
1420 if ($user_obj = retrieve_patron($patron_id)) {
1421     is(
1422         ref $user_obj,
1423         'Fieldmapper::actor::user',
1424         'open-ils.storage.direct.actor.user.retrieve returned aou object'
1425     );
1426     is(
1427         $user_obj->usrname,
1428         $patron_usrname,
1429         'Patron with id = ' . $patron_id . ' has username ' . $patron_usrname
1430     );
1431 }
1432
1433 ### Setup use case variables
1434 $xact_id = 6;
1435 $item_id = 7;
1436 $item_barcode = 'CONC4000042';
1437
1438 # Setup Org Unit Settings
1439 # ALREADY SET:
1440 #     'circ.void_overdue_on_lost' => 1,
1441 #     'circ.restore_overdue_on_lost_return' => 1,
1442 #     'circ.lost.generate_overdue_on_checkin' => 1
1443 $settings = {
1444     'bill.prohibit_negative_balance_default' => 0
1445 };
1446
1447 $apputils->simplereq(
1448     'open-ils.actor',
1449     'open-ils.actor.org_unit.settings.update',
1450     $script->authtoken,
1451     $org_id,
1452     $settings
1453 );
1454
1455 $summary = fetch_billable_xact_summary($xact_id);
1456 ok( $summary, 'CASE 8: Found the transaction summary');
1457 is(
1458     $summary->balance_owed,
1459     '50.00',
1460     'Starting balance owed is 50.00 for lost item'
1461 );
1462
1463 ### partially pay the bill
1464 $payment_blob = {
1465     userid => $patron_id,
1466     note => '09-lp1198465_neg_balances.t',
1467     payment_type => 'cash_payment',
1468     patron_credit => '0.00',
1469     payments => [ [ $xact_id, '10.00' ] ]
1470 };
1471 $pay_resp = pay_bills($payment_blob);
1472
1473 is(
1474     scalar( @{ $pay_resp->{payments} } ),
1475     1,
1476     'Payment response included one payment id'
1477 );
1478
1479 $summary = fetch_billable_xact_summary($xact_id);
1480 is(
1481     $summary->balance_owed,
1482     '40.00',
1483     'Remaining balance of 40.00 after payment'
1484 );
1485
1486 ### check-in the lost copy
1487
1488 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
1489 if (my $item_resp = $item_req->recv) {
1490     if (my $item = $item_resp->content) {
1491         is(
1492             ref $item,
1493             'Fieldmapper::asset::copy',
1494             'open-ils.storage.direct.asset.copy.retrieve returned acp object'
1495         );
1496         is(
1497             $item->status,
1498             3,
1499             'Item with id = ' . $item_id . ' has status of LOST'
1500         );
1501     }
1502 }
1503
1504 $checkin_resp = $script->do_checkin_override({
1505     barcode => $item_barcode});
1506 is(
1507     $checkin_resp->{ilsevent},
1508     0,
1509     'Checkin returned a SUCCESS event'
1510 );
1511
1512 $item_req = $storage_ses->request('open-ils.storage.direct.asset.copy.retrieve', $item_id);
1513 if (my $item_resp = $item_req->recv) {
1514     if (my $item = $item_resp->content) {
1515         ok(
1516             $item->status == 7 || $item->status == 0,
1517             'Item with id = ' . $item_id . ' has status of Reshelving or Available after fresh Storage request'
1518         );
1519     }
1520 }
1521
1522 ### verify ending state
1523
1524 $summary = fetch_billable_xact_summary($xact_id);
1525 is(
1526     $summary->balance_owed,
1527     '-7.00',
1528     'Patron has a negative balance of 7.00 due to overpayment'
1529 );
1530
1531
1532
1533 $script->logout();
1534
1535