--- /dev/null
+#!perl
+use strict; use warnings;
+use Test::More tests => 30;
+use OpenILS::Utils::TestUtils;
+use OpenILS::Const qw(:const);
+
+diag("Test LP 1694058 multiple hold placement.");
+
+my $script = OpenILS::Utils::TestUtils->new();
+my $U = 'OpenILS::Application::AppUtils';
+
+use constant {
+ BR1_WORKSTATION => 'BR1-test-lp1694058-multiple-hold-placement.t',
+ BR1_ID => 4,
+ BR2_ID => 5,
+ PATRON1_BARCODE => '99999376864',
+ PATRON2_BARCODE => '99999342948',
+ RECORD_ID => 3,
+ METARECORD_ID => 13,
+ COPY_ID => 2503,
+};
+
+# Because this may run multiple times, without a DB reload, we search
+# for the workstation before registering it. Takes an authtoken, the
+# id of the workstation lib, and the name of the workstation.
+sub find_or_register_workstation {
+ my ($authtoken, $lib, $workstation) = @_;
+ my $ws;
+ my $r = $U->simplereq(
+ 'open-ils.actor',
+ 'open-ils.actor.workstation.list',
+ $authtoken,
+ $lib
+ );
+ if ($r && $r->{$lib}) {
+ $ws = grep {$_->name() eq $workstation} @{$r->{$lib}};
+ }
+ unless ($ws) {
+ $ws = $script->register_workstation($workstation, $lib);
+ }
+ return $ws;
+}
+
+
+# Keep track of hold ids, so we can cancel them later.
+my @holds = ();
+
+# Login as admin at BR1.
+my $authtoken = $script->authenticate({
+ username=>'admin',
+ password=>'demo123',
+ type=>'staff'
+});
+ok(
+ $script->authtoken,
+ 'Have an authtoken'
+);
+
+# Register workstation.
+my $ws = find_or_register_workstation($authtoken, BR1_ID, BR1_WORKSTATION);
+ok(
+ ! ref $ws,
+ 'Found or registered workstation'
+);
+
+# Logout.
+$script->logout();
+ok(
+ ! $script->authtoken,
+ 'Successfully logged out'
+);
+
+# Login as admin at BR1 using the workstation.
+$authtoken = $script->authenticate({
+ username=>'admin',
+ password=>'demo123',
+ type=>'staff',
+ workstation => BR1_WORKSTATION
+});
+ok(
+ $script->authtoken,
+ 'Have an authtoken'
+);
+
+# Check that OILS_SETTING_MAX_DUPLICATE_HOLDS is not set at BR1 and ancestors.
+my $setting_value = $U->ou_ancestor_setting_value(BR1_ID, OILS_SETTING_MAX_DUPLICATE_HOLDS);
+ok(
+ ! $setting_value,
+ 'circ.holds.max_duplicate_holds is not set for BR1'
+);
+
+# Check that OILS_SETTING_MAX_DUPLICATE_HOLDS is not set at BR2 and ancestors.
+$setting_value = $U->ou_ancestor_setting_value(BR2_ID, OILS_SETTING_MAX_DUPLICATE_HOLDS);
+ok(
+ ! $setting_value,
+ 'circ.holds.max_duplicate_holds is not set for BR2'
+);
+
+# Set OILS_SETTING_MAX_DUPLICATE_HOLDS to 5 at BR1.
+$setting_value = $U->simplereq(
+ 'open-ils.actor',
+ 'open-ils.actor.org_unit.settings.update',
+ $authtoken,
+ BR1_ID,
+ {OILS_SETTING_MAX_DUPLICATE_HOLDS, 5}
+);
+ok(
+ ! ref $setting_value,
+ 'circ.holds.max_duplicate_holds set to 5 for BR1'
+);
+
+# Retrieve PATRON1.
+my $patron1 = $U->simplereq(
+ 'open-ils.actor',
+ 'open-ils.actor.user.fleshed.retrieve_by_barcode',
+ $authtoken,
+ PATRON1_BARCODE
+);
+isa_ok(
+ ref $patron1,
+ 'Fieldmapper::actor::user',
+ 'Got patron 1'
+) or BAIL_OUT('Need Patron1');
+
+# Create a circ session for holds placement.
+my $circ_session = $script->session('open-ils.circ');
+
+# Place 5 holds for RECORD_ID for PATRON1. Expect success.
+my $request = $circ_session->request(
+ 'open-ils.circ.holds.test_and_create.batch',
+ $authtoken,
+ {
+ hold_type => 'T',
+ patronid => $patron1->id(),
+ pickup_lib => $patron1->home_ou()
+ },
+ [RECORD_ID, RECORD_ID, RECORD_ID, RECORD_ID, RECORD_ID]
+);
+my $success = 0;
+while (my $response = $request->recv()) {
+ my $result = $response->content();
+ if ($result->{result} && !ref $result->{result}) {
+ $success++;
+ push(@holds, $result->{result});
+ }
+}
+$request->finish();
+is(
+ $success,
+ 5,
+ 'Placed 5 title holds for Patron 1'
+);
+
+# Place 1 hold for RECORD_ID for PATRON1. Expect HOLD_EXISTS.
+$request = $circ_session->request(
+ 'open-ils.circ.holds.test_and_create.batch',
+ $authtoken,
+ {
+ hold_type => 'T',
+ patronid => $patron1->id(),
+ pickup_lib => $patron1->home_ou()
+ },
+ [RECORD_ID]
+);
+my $textcode;
+while (my $response = $request->recv()) {
+ my $result = $response->content();
+ if ($result->{result} && ref($result->{result}) eq 'ARRAY') {
+ if (grep {$_->{textcode} eq 'HOLD_EXISTS'} @{$result->{result}}) {
+ $textcode = 'HOLD_EXISTS';
+ }
+ }
+}
+$request->finish();
+is(
+ $textcode,
+ 'HOLD_EXISTS',
+ 'Got HOLD_EXISTS placing 6th title hold for patron 1'
+);
+
+# Place 5 holds for METARECORD_ID for PATRON1. Expect success.
+$request = $circ_session->request(
+ 'open-ils.circ.holds.test_and_create.batch',
+ $authtoken,
+ {
+ hold_type => 'M',
+ patronid => $patron1->id(),
+ pickup_lib => $patron1->home_ou()
+ },
+ [METARECORD_ID, METARECORD_ID, METARECORD_ID, METARECORD_ID, METARECORD_ID]
+);
+$success = 0;
+while (my $response = $request->recv()) {
+ my $result = $response->content();
+ if ($result->{result} && !ref $result->{result}) {
+ $success++;
+ push(@holds, $result->{result});
+ }
+}
+$request->finish();
+is(
+ $success,
+ 5,
+ 'Placed 5 metarecord holds for Patron 1'
+);
+
+# Place 1 hold for METARECORD_ID for PATRON1. Expect HOLD_EXISTS.
+$request = $circ_session->request(
+ 'open-ils.circ.holds.test_and_create.batch',
+ $authtoken,
+ {
+ hold_type => 'M',
+ patronid => $patron1->id(),
+ pickup_lib => $patron1->home_ou()
+ },
+ [METARECORD_ID]
+);
+$textcode = '';
+while (my $response = $request->recv()) {
+ my $result = $response->content();
+ if ($result->{result} && ref($result->{result}) eq 'ARRAY') {
+ if (grep {$_->{textcode} eq 'HOLD_EXISTS'} @{$result->{result}}) {
+ $textcode = 'HOLD_EXISTS';
+ }
+ }
+}
+$request->finish();
+is(
+ $textcode,
+ 'HOLD_EXISTS',
+ 'Got HOLD_EXISTS placing 6th metarecord hold for patron 1'
+);
+
+# Place 5 holds for COPY_ID for PATRON1. Expect 1 success and 4 HOLD_EXISTS.
+$request = $circ_session->request(
+ 'open-ils.circ.holds.test_and_create.batch',
+ $authtoken,
+ {
+ hold_type => 'C',
+ patronid => $patron1->id(),
+ pickup_lib => $patron1->home_ou()
+ },
+ [COPY_ID, COPY_ID, COPY_ID, COPY_ID, COPY_ID]
+);
+$success = 0;
+$textcode = 0; # Using textcode as int this time.
+while (my $response = $request->recv()) {
+ my $result = $response->content();
+ if ($result->{result} && ref($result->{result}) eq 'ARRAY') {
+ if (grep {$_->{textcode} eq 'HOLD_EXISTS'} @{$result->{result}}) {
+ $textcode++;
+ }
+ } elsif ($result->{result}) {
+ $success++;
+ push(@holds, $result->{result});
+ }
+}
+$request->finish();
+is(
+ $success,
+ 1,
+ 'Placed 1 copy hold for patron 1'
+);
+is(
+ $textcode,
+ 4,
+ 'Got 4 HOLD_EXISTS on copy holds for patron 1'
+);
+
+# Retrieve PATRON2.
+my $patron2 = $U->simplereq(
+ 'open-ils.actor',
+ 'open-ils.actor.user.fleshed.retrieve_by_barcode',
+ $authtoken,
+ PATRON2_BARCODE
+);
+isa_ok(
+ ref $patron2,
+ 'Fieldmapper::actor::user',
+ 'Got patron 2'
+) or BAIL_OUT('Need Patron 2');
+
+# Place 5 holds for RECORD_ID for PATRON2. Expect 1 success and 4 HOLD_EXISTS.
+$request = $circ_session->request(
+ 'open-ils.circ.holds.test_and_create.batch',
+ $authtoken,
+ {
+ hold_type => 'T',
+ patronid => $patron2->id(),
+ pickup_lib => $patron2->home_ou()
+ },
+ [RECORD_ID, RECORD_ID, RECORD_ID, RECORD_ID, RECORD_ID]
+);
+$success = 0;
+$textcode = 0; # Using textcode as int this time.
+while (my $response = $request->recv()) {
+ my $result = $response->content();
+ if ($result->{result} && ref($result->{result}) eq 'ARRAY') {
+ if (grep {$_->{textcode} eq 'HOLD_EXISTS'} @{$result->{result}}) {
+ $textcode++;
+ }
+ } elsif ($result->{result}) {
+ $success++;
+ push(@holds, $result->{result});
+ }
+}
+$request->finish();
+is(
+ $success,
+ 1,
+ 'Placed 1 title hold for patron 2'
+);
+is(
+ $textcode,
+ 4,
+ 'Got 4 HOLD_EXISTS on title holds for patron 2'
+);
+
+# Place 5 holds for METARECORD_ID for PATRON2. Expect 1 success and 4 HOLD_EXISTS.
+$request = $circ_session->request(
+ 'open-ils.circ.holds.test_and_create.batch',
+ $authtoken,
+ {
+ hold_type => 'M',
+ patronid => $patron2->id(),
+ pickup_lib => $patron2->home_ou()
+ },
+ [METARECORD_ID, METARECORD_ID, METARECORD_ID, METARECORD_ID, METARECORD_ID]
+);
+$success = 0;
+$textcode = 0; # Using textcode as int this time.
+while (my $response = $request->recv()) {
+ my $result = $response->content();
+ if ($result->{result} && ref($result->{result}) eq 'ARRAY') {
+ if (grep {$_->{textcode} eq 'HOLD_EXISTS'} @{$result->{result}}) {
+ $textcode++;
+ }
+ } elsif ($result->{result}) {
+ $success++;
+ push(@holds, $result->{result});
+ }
+}
+$request->finish();
+is(
+ $success,
+ 1,
+ 'Placed 1 metarecord hold for patron 2'
+);
+is(
+ $textcode,
+ 4,
+ 'Got 4 HOLD_EXISTS on metarecord holds for patron 2'
+);
+
+# Place 5 holds for COPY_ID for PATRON2. Expect 1 success and 4 HOLD_EXISTS.
+$request = $circ_session->request(
+ 'open-ils.circ.holds.test_and_create.batch',
+ $authtoken,
+ {
+ hold_type => 'C',
+ patronid => $patron2->id(),
+ pickup_lib => $patron2->home_ou()
+ },
+ [COPY_ID, COPY_ID, COPY_ID, COPY_ID, COPY_ID]
+);
+$success = 0;
+$textcode = 0; # Using textcode as int this time.
+while (my $response = $request->recv()) {
+ my $result = $response->content();
+ if ($result->{result} && ref($result->{result}) eq 'ARRAY') {
+ if (grep {$_->{textcode} eq 'HOLD_EXISTS'} @{$result->{result}}) {
+ $textcode++;
+ }
+ } elsif ($result->{result}) {
+ $success++;
+ push(@holds, $result->{result});
+ }
+}
+$request->finish();
+is(
+ $success,
+ 1,
+ 'Placed 1 copy hold for patron 2'
+);
+is(
+ $textcode,
+ 4,
+ 'Got 4 HOLD_EXISTS on copy holds for patron 2'
+);
+
+# Cancel all of the holds placed.
+# How many successes we expect.
+my $expect = scalar(@holds);
+$success = 0;
+foreach my $hold (@holds) {
+ my $result = $circ_session->request(
+ 'open-ils.circ.hold.cancel',
+ $authtoken,
+ $hold,
+ 5,
+ 'LP 1694058 perl test'
+ )->gather(1);
+ if ($result && ! ref $result) {
+ $success++;
+ }
+}
+is(
+ $success,
+ $expect,
+ "Cancelled $expect holds"
+);
+
+# Reset @holds
+@holds = ();
+
+# Test the permission by logging in as patron 1 and placing a title and metarecord hold.
+
+# Login as patron1.
+my $patron_auth = $script->authenticate({
+ username => $patron1->usrname(),
+ password => 'leona1234',
+ type => 'opac'
+});
+ok(
+ $patron_auth,
+ 'Logged in as patron 1'
+);
+
+# Place 5 holds for RECORD_ID as PATRON1. Expect 1 success and 4 HOLD_EXISTS.
+$request = $circ_session->request(
+ 'open-ils.circ.holds.test_and_create.batch',
+ $patron_auth,
+ {
+ hold_type => 'T',
+ patronid => $patron1->id(),
+ pickup_lib => $patron1->home_ou()
+ },
+ [RECORD_ID, RECORD_ID, RECORD_ID, RECORD_ID, RECORD_ID]
+);
+$success = 0;
+$textcode = 0; # Using textcode as int this time.
+while (my $response = $request->recv()) {
+ my $result = $response->content();
+ if ($result->{result} && ref($result->{result}) eq 'ARRAY') {
+ if (grep {$_->{textcode} eq 'HOLD_EXISTS'} @{$result->{result}}) {
+ $textcode++;
+ }
+ } elsif ($result->{result}) {
+ $success++;
+ push(@holds, $result->{result});
+ }
+}
+$request->finish();
+is(
+ $success,
+ 1,
+ 'Patron 1 placed 1 title hold'
+);
+is(
+ $textcode,
+ 4,
+ 'Patron 1 got 4 HOLD_EXISTS on title holds'
+);
+
+# Ditto for metarecord holds:
+$request = $circ_session->request(
+ 'open-ils.circ.holds.test_and_create.batch',
+ $patron_auth,
+ {
+ hold_type => 'T',
+ patronid => $patron1->id(),
+ pickup_lib => $patron1->home_ou()
+ },
+ [METARECORD_ID, METARECORD_ID, METARECORD_ID, METARECORD_ID, METARECORD_ID]
+);
+$success = 0;
+$textcode = 0; # Using textcode as int this time.
+while (my $response = $request->recv()) {
+ my $result = $response->content();
+ if ($result->{result} && ref($result->{result}) eq 'ARRAY') {
+ if (grep {$_->{textcode} eq 'HOLD_EXISTS'} @{$result->{result}}) {
+ $textcode++;
+ }
+ } elsif ($result->{result}) {
+ $success++;
+ push(@holds, $result->{result});
+ }
+}
+$request->finish();
+is(
+ $success,
+ 1,
+ 'Patron 1 placed 1 metarecord hold'
+);
+is(
+ $textcode,
+ 4,
+ 'Patron 1 got 4 HOLD_EXISTS on metarecord holds'
+);
+
+# Cancel the patron-placed holds.
+$expect = scalar(@holds);
+$success = 0;
+foreach my $hold (@holds) {
+ my $result = $circ_session->request(
+ 'open-ils.circ.hold.cancel',
+ $patron_auth,
+ $hold,
+ 6,
+ 'LP 1694058 perl test'
+ )->gather(1);
+ if ($result && ! ref $result) {
+ $success++;
+ }
+}
+is(
+ $success,
+ $expect,
+ "Cancelled $expect patron holds"
+);
+
+# Reset @holds
+@holds = ();
+
+# Unset OILS_SETTING_MAX_DUPLICATE_HOLDS at BR1.
+$setting_value = $U->simplereq(
+ 'open-ils.actor',
+ 'open-ils.actor.org_unit.settings.update',
+ $authtoken,
+ BR1_ID,
+ {OILS_SETTING_MAX_DUPLICATE_HOLDS, undef}
+);
+ok(
+ ! ref $setting_value,
+ 'circ.holds.max_duplicate_holds unset for BR1'
+);
+
+# Logout. Because of a "bug" in Cronscript.pm, we need to log out in the order that we logged in.
+$script->logout($authtoken);
+$script->logout($patron_auth);
+ok(
+ ! $script->authtoken,
+ 'Successfully logged out'
+);
+