Lp 1861319: Add Release Notes and Perl Live Tests
[Evergreen.git] / Open-ILS / src / perlmods / live_t / 32-lp1861319-circ-renewal-expired-patrons.t
1 #!perl
2 use strict; use warnings;
3 use Test::More tests => 18;
4 use OpenILS::Utils::TestUtils;
5 use OpenILS::Const qw(:const);
6 use OpenILS::Utils::DateTime;
7 use DateTime;
8 use DateTime::TimeZone;
9 use DateTime::Format::ISO8601;
10
11 # We need the local timezone for later.
12 my $localTZ = DateTime::TimeZone->new(name => 'local');
13
14 my $script = OpenILS::Utils::TestUtils->new();
15 my $U = 'OpenILS::Application::AppUtils';
16
17 diag("Test LP 1861319 Allow Circulation Renewal for Expired Patrons");
18
19 use constant {
20     BR1_ID => 4,
21     BR2_ID => 6,
22     BR1_WORKSTATION => 'BR1-lp1861319-test-renewal',
23     BR2_WORKSTATION => 'BR2-lp1861319-test renewal',
24     ADMIN_USER => 'admin',
25     ADMIN_PASS => 'demo123'
26 };
27
28 # Login
29 $script->authenticate({
30     username => ADMIN_USER,
31     password => ADMIN_PASS,
32     type => 'staff'
33 });
34 BAIL_OUT('Failed to Login') unless ($script->authtoken);
35
36 # Register BR1 workstation.
37 my $ws = $script->find_or_register_workstation(BR1_WORKSTATION, BR1_ID);
38 BAIL_OUT("Failed to register " . BR1_WORKSTATION) unless($ws);
39
40 # Logout
41 $script->logout();
42
43 # Login with BR1 Workstation
44 $script->authenticate({
45     username => ADMIN_USER,
46     password => ADMIN_PASS,
47     type => 'staff',
48     workstation => BR1_WORKSTATION
49 });
50 BAIL_OUT('Failed to login with ' . BR1_WORKSTATION) unless($script->authtoken);
51
52 # Get a cstore editor for later use.
53 my $editor = $script->editor(authtoken=>$script->authtoken);
54
55 # Check that the circ.renew.expired_patron_allow setting constant is defined
56 ok(defined(OILS_SETTING_ALLOW_RENEW_FOR_EXPIRED_PATRON),
57    'OILS_SETTING_ALLOW_RENEW_FOR_EXPIRED_PATRON constant exists');
58
59 # Check that the circ.renew.expired_patron_allow setting exists in the database
60 my $setting = $editor->search_config_org_unit_setting_type(
61     {name => OILS_SETTING_ALLOW_RENEW_FOR_EXPIRED_PATRON}
62 );
63 # Get the first/only one:
64 $setting = (defined($setting)) ? $setting->[0] : $setting;
65 ok(defined($setting), OILS_SETTING_ALLOW_RENEW_FOR_EXPIRED_PATRON . ' setting exists in database');
66
67 # Find a circulation with renewals remaining
68 my $circ = $editor->search_action_circulation([
69     {
70         circ_lib => BR1_ID,
71         checkin_time => undef,
72         renewal_remaining => {'>' => 0}
73     },
74     {limit => 1}
75 ]);
76 $circ = defined($circ) ? $circ->[0] : $circ;
77 isa_ok($circ, 'Fieldmapper::action::circulation', 'Found open circulation at BR1');
78
79 # Get the circ patron information.
80 my $patron = $editor->retrieve_actor_user($circ->usr);
81 isa_ok($patron, 'Fieldmapper::actor::user', 'Found circulation user');
82
83 # Expire the patron if they are not already expired.
84 my ($saved_expire_date);
85 SKIP: {
86     if (check_usr_expired($patron)) {
87         skip 'Patron already expired', 1;
88     } else {
89         $saved_expire_date = $patron->expire_date;
90         $patron->expire_date(DateTime->now()->set_time_zone($localTZ)->subtract(days => 1)->strftime('%FT%T%z'));
91         $editor->xact_begin;
92         if ($editor->update_actor_user($patron)) {
93             $editor->xact_commit;
94         } else {
95             $editor->xact_rollback;
96             BAIL_OUT("Patron update failed");
97         }
98         $patron = $editor->retrieve_actor_user($patron->id);
99         ok(check_usr_expired($patron), 'Patron set to expired.');
100     }
101 }
102
103 # Attempt a renewal. It should fail.
104 my $renew_params = {
105     copy_id => $circ->target_copy,
106     patron_id => $circ->usr,
107     desk_renewal => 1
108 };
109 my $result = $U->simplereq(
110     'open-ils.circ',
111     'open-ils.circ.renew.override',
112     $script->authtoken,
113     $renew_params
114 );
115 if (ref($result) eq 'ARRAY') {
116     $result = $result->[0];
117 }
118 is($result->{textcode}, 'PATRON_ACCOUNT_EXPIRED', 'Renewal failed: ' . $result->{textcode});
119
120 # Set the circ.renew.expired_patron_allow setting at BR1
121 $setting = Fieldmapper::actor::org_unit_setting->new;
122 $setting->name(OILS_SETTING_ALLOW_RENEW_FOR_EXPIRED_PATRON);
123 $setting->org_unit(BR1_ID);
124 $setting->value('true');
125 $editor->xact_begin;
126 $result = $editor->create_actor_org_unit_setting($setting);
127 if ($result) {
128     $editor->xact_commit;
129     ok($result, 'Set ' . OILS_SETTING_ALLOW_RENEW_FOR_EXPIRED_PATRON . ' for BR1');
130 } else {
131     $editor->xact_rollback;
132     BAIL_OUT("Failed to set " . OILS_SETTING_ALLOW_RENEW_FOR_EXPIRED_PATRON . ' for BR1');
133 }
134
135 # Attempt the renewal again, expect success.
136 $result = $U->simplereq(
137     'open-ils.circ',
138     'open-ils.circ.renew.override',
139     $script->authtoken,
140     $renew_params
141 );
142 if (ref($result) eq 'ARRAY') {
143     $result = $result->[0];
144 }
145 isnt($result->{textcode}, 'PATRON_ACCOUNT_EXPIRED', 'Renewal Result: ' . $result->{textcode});
146
147 # Find a circulating copy at BR1 that is not checked out.
148 my $copy = $editor->search_asset_copy([
149     {
150         circ_lib => BR1_ID,
151         status => OILS_COPY_STATUS_AVAILABLE,
152         circulate => 't'
153     },
154     {limit => 1}
155 ]);
156 $copy = defined($copy) ? $copy->[0] : $copy;
157 isa_ok($copy, 'Fieldmapper::asset::copy', 'Found copy at BR1');
158
159 # Check it out, expect failure
160 my $checkout_params = {
161     copy_id => $copy->id,
162     patron_id => $patron->id
163 };
164 $result = $U->simplereq(
165     'open-ils.circ',
166     'open-ils.circ.checkout.full.override',
167     $script->authtoken,
168     $checkout_params
169 );
170 if (ref($result) eq 'ARRAY') {
171     $result = $result->[0];
172 }
173 is($result->{textcode}, 'PATRON_ACCOUNT_EXPIRED', 'Checkout failed: ' . $result->{textcode});
174
175 # Reset the patron expire_date
176 if (defined($saved_expire_date)) {
177     $patron->expire_date($saved_expire_date);
178     $editor->xact_begin;
179     if ($editor->update_actor_user($patron)) {
180         $editor->xact_commit;
181     } else {
182         $editor->xact_rollback;
183     }
184     undef($saved_expire_date);
185 }
186
187 # Logout
188 $script->logout();
189
190 # Destroy our editor.
191 undef($editor);
192
193 # Login
194 $script->authenticate({
195     username => ADMIN_USER,
196     password => ADMIN_PASS,
197     type => 'staff'
198 });
199 BAIL_OUT('Failed to Login') unless ($script->authtoken);
200
201 # Register BR2 workstation.
202 $ws = $script->find_or_register_workstation(BR2_WORKSTATION, BR2_ID);
203 BAIL_OUT("Failed to register " . BR2_WORKSTATION) unless($ws);
204
205 # Logout
206 $script->logout();
207
208 # Login with BR2 Workstation
209 $script->authenticate({
210     username => ADMIN_USER,
211     password => ADMIN_PASS,
212     type => 'staff',
213     workstation => BR2_WORKSTATION
214 });
215 BAIL_OUT('Failed to login with ' . BR2_WORKSTATION) unless($script->authtoken);
216
217 # Get a new editor with our authtoken.
218 $editor = $script->editor(authtoken=>$script->authtoken);
219
220 # Find a circulation with renewals remaining at BR2
221 $circ = $editor->search_action_circulation([
222     {
223         circ_lib => BR2_ID,
224         checkin_time => undef,
225         renewal_remaining => {'>' => 0}
226     },
227     {limit => 1}
228 ]);
229 $circ = defined($circ) ? $circ->[0] : $circ;
230 isa_ok($circ, 'Fieldmapper::action::circulation', 'Found open circulation at BR2');
231
232 # Get the circ patron information.
233 $patron = $editor->retrieve_actor_user($circ->usr);
234 isa_ok($patron, 'Fieldmapper::actor::user', 'Found circulation user');
235
236 # Expire the patron if they are not already expired.
237 SKIP: {
238     if (check_usr_expired($patron)) {
239         skip 'Patron already expired', 1;
240     } else {
241         $saved_expire_date = $patron->expire_date;
242         $patron->expire_date(DateTime->now()->set_time_zone($localTZ)->subtract(days => 1)->strftime('%FT%T%z'));
243         $editor->xact_begin;
244         if ($editor->update_actor_user($patron)) {
245             $editor->xact_commit;
246             $patron = $editor->retrieve_actor_user($patron->id);
247             ok(check_usr_expired($patron), 'Patron set to expired.');
248         } else {
249             $editor->xact_rollback;
250             BAIL_OUT("Patron update failed");
251         }
252     }
253 }
254
255 # Attempt a renewal. It should fail.
256 $renew_params = {
257     copy_id => $circ->target_copy,
258     patron_id => $circ->usr,
259     desk_renewal => 1
260 };
261 $result = $U->simplereq(
262     'open-ils.circ',
263     'open-ils.circ.renew.override',
264     $script->authtoken,
265     $renew_params
266 );
267 if (ref($result) eq 'ARRAY') {
268     $result = $result->[0];
269 }
270 is($result->{textcode}, 'PATRON_ACCOUNT_EXPIRED', 'Renewal failed: ' . $result->{textcode});
271
272 # Reset the patron expire_date
273 if (defined($saved_expire_date)) {
274     $patron->expire_date($saved_expire_date);
275     $editor->xact_begin;
276     if ($editor->update_actor_user($patron)) {
277         $editor->xact_commit;
278         ok(!check_usr_expired($patron), 'Patron set to not expired');
279     } else {
280         $editor->xact_rollback;
281         BAIL_OUT('Patron expire date reset failed');
282     }
283     undef($saved_expire_date);
284 } else {
285     # Set patron expire date to 30 days in the future.
286     $saved_expire_date = $patron->expire_date;
287     $patron->expire_date(DateTime->now()->set_time_zone($localTZ)->add(days => 30)->strftime('%FT%T%z'));
288     $editor->xact_begin;
289     if ($editor->update_actor_user($patron)) {
290         $editor->xact_commit;
291         $patron = $editor->retrieve_actor_user($patron->id);
292         ok(!check_usr_expired($patron), 'Patron is not expired.');
293     } else {
294         $editor->xact_rollback;
295         BAIL_OUT("Patron update failed");
296     }
297 }
298
299 # Attempt renewal, expect success.
300 $result = $U->simplereq(
301     'open-ils.circ',
302     'open-ils.circ.renew.override',
303     $script->authtoken,
304     $renew_params
305 );
306 if (ref($result) eq 'ARRAY') {
307     $result = $result->[0];
308 }
309 isnt($result->{textcode}, 'PATRON_ACCOUNT_EXPIRED', 'Renewal Result: ' . $result->{textcode});
310
311 # Find a circulating copy at BR2 that is not checked out.
312 $copy = $editor->search_asset_copy([
313     {
314         circ_lib => BR2_ID,
315         status => OILS_COPY_STATUS_AVAILABLE,
316         circulate => 't'
317     },
318     {limit => 1}
319 ]);
320 $copy = defined($copy) ? $copy->[0] : $copy;
321 isa_ok($copy, 'Fieldmapper::asset::copy', 'Found copy at BR2');
322
323 # Check it out, expect failure
324 $checkout_params = {
325     copy_id => $copy->id,
326     patron_id => $patron->id
327 };
328 $result = $U->simplereq(
329     'open-ils.circ',
330     'open-ils.circ.checkout.full.override',
331     $script->authtoken,
332     $checkout_params
333 );
334 if (ref($result) eq 'ARRAY') {
335     $result = $result->[0];
336 }
337 isnt($result->{textcode}, 'PATRON_ACCOUNT_EXPIRED', 'Checkout result: ' . $result->{textcode});
338
339 # Reset the patron expire_date if necessary
340 if (defined($saved_expire_date)) {
341     $patron->expire_date($saved_expire_date);
342     $editor->xact_begin;
343     if ($editor->update_actor_user($patron)) {
344         $editor->xact_commit;
345     } else {
346         $editor->xact_rollback;
347     }
348     undef($saved_expire_date);
349 }
350
351 # Delete the setting from actor.org_unit_setting
352 $editor->xact_begin;
353 if ($editor->delete_actor_org_unit_setting($setting)) {
354     $editor->commit; # Commit so that we disconnect.
355 } else {
356     $editor->rollback;
357 }
358
359 # Logout
360 $script->logout(); # Not a test, just to be pedantic.
361
362 # Utiity functions
363 sub check_usr_expired {
364     my ($user) = @_;
365     my $expire = DateTime::Format::ISO8601->new->parse_datetime(
366         OpenILS::Utils::DateTime->clean_ISO8601($user->expire_date));
367     return (time > $expire->epoch);
368 }