From: Jason Etheridge Date: Thu, 12 Jan 2023 06:16:29 +0000 (-0500) Subject: LP1965446 Option to Disable Title-Level Holds on Bib Records with Parts X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=ada4bf78e0e6898ab7d39b27eb403cd0870fa1db;p=working%2FEvergreen.git LP1965446 Option to Disable Title-Level Holds on Bib Records with Parts This feature adds one global flag and one library setting, respectively: * circ.holds.allow_require_monographic_part_when_present Holds: Enable the Require Monographic Part When Present library setting. * circ.holds.require_monographic_part_when_present Require Monographic Part when Present Normally the selection of a monographic part during hold placement is optional if there is at least one copy on the bib without a monographic part. A true value for this setting and for the global flag will require part selection even under this condition. This essentially removes the All/Any Parts option from the part selection drop-down, for both versions of the public catalog (TPAC and BOOPAC), and for the Angular staff catalog interface. We also test for this at the API level, which will catch situations where the UI may have stale information on the state of the flag and setting, or when the API is being invoked by third parties under this condition. We will throw a TITLE_HOLD_WHEN_MONOGRAPHIC_PART_REQUIRED event if a title hold is effectively disallowed based on the presence of monographic parts and lack of part selection. Signed-off-by: Jason Etheridge --- diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/hold/hold.component.html b/Open-ILS/src/eg2/src/app/staff/catalog/hold/hold.component.html index d447492cb2..932d042780 100644 --- a/Open-ILS/src/eg2/src/app/staff/catalog/hold/hold.component.html +++ b/Open-ILS/src/eg2/src/app/staff/catalog/hold/hold.component.html @@ -316,8 +316,8 @@
diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/hold/hold.component.ts b/Open-ILS/src/eg2/src/app/staff/catalog/hold/hold.component.ts index a74bc37354..9b7d1ff8f9 100644 --- a/Open-ILS/src/eg2/src/app/staff/catalog/hold/hold.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/catalog/hold/hold.component.ts @@ -245,7 +245,7 @@ export class HoldComponent implements OnInit { getTargetMeta(): Promise { return new Promise(resolve => { - this.holds.getHoldTargetMeta(this.holdType, this.holdTargets) + this.holds.getHoldTargetMeta(this.holdType, this.holdTargets, this.auth.user().ws_ou()) .subscribe( meta => { this.holdContexts.filter(ctx => ctx.holdTarget === meta.target) diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm index 6e9878be21..bd61588149 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm @@ -2877,6 +2877,48 @@ sub _check_title_hold_is_possible { # $holdable_formats is now unused. We pre-filter the MR's records. my $e = new_editor(); + + # T holds on records that have parts are normally OK, but if the record has + # no non-part copies, the hold will ultimately fail, so let's test for that. + # + # If the global flag circ.holds.allow_require_monographic_part_when_present is + # enabled, and the library setting circ.holds.require_monographic_part_when_present + # is active, then any configured parts for the bib is enough to disallow title holds. + my $part_required = 0; + my $parts = $e->search_biblio_monograph_part( + { + record => $titleid + }, {idlist=>1} ); + + if ($parts) { + my $part_required_flag = $e->retrieve_config_global_flag('circ.holds.allow_require_monographic_part_when_present'); + $part_required_flag = ($part_required_flag and $U->is_true($part_required_flag->enabled)); + $part_required = $part_required_flag && $U->ou_ancestor_setting_value($request_lib->id, 'circ.holds.require_monographic_part_when_present'); + if (!$part_required) { + my $np_copies = $e->json_query({ + select => { acp => [{column => 'id', transform => 'count', alias => 'count'}]}, + from => {acp => {acn => {}, acpm => {type => 'left'}}}, + where => { + '+acp' => {deleted => 'f'}, + '+acn' => {deleted => 'f', record => $titleid}, + '+acpm' => {id => undef} + } + }); + $part_required = 1 if $np_copies->[0]->{count} == 0; + } + } + if ($part_required) { + $logger->info("title hold when monographic part required"); + return ( + 0, 0, [ + new OpenILS::Event( + "TITLE_HOLD_WHEN_MONOGRAPHIC_PART_REQUIRED", + "payload" => {"fail_part" => "monographic_part_required"} + ) + ] + ); + } + my %org_filter = create_ranged_org_filter($e, $selection_ou, $depth); # this monster will grab the id and circ_lib of all of the "holdable" copies for the given record @@ -5153,6 +5195,7 @@ sub hold_metadata { issuance => $issuance, part => $part, parts => [], + part_required => 'f', bibrecord => $bre, metarecord => $metarecord, metarecord_filters => {} @@ -5178,6 +5221,35 @@ sub hold_metadata { {order_by => {bmp => 'label_sortkey'}} ] ); + + # T holds on records that have parts are normally OK, but if the record has + # no non-part copies, the hold will ultimately fail. When that happens, + # require the user to select a part. + # + # If the global flag circ.holds.allow_require_monographic_part_when_present is + # enabled, and the library setting circ.holds.require_monographic_part_when_present + # is active, then any configured parts for the bib is enough to disallow title holds. + my $part_required = 0; + if ($meta->{parts}) { + my $part_required_flag = $e->retrieve_config_global_flag('circ.holds.allow_require_monographic_part_when_present'); + $part_required_flag = ($part_required_flag and $U->is_true($part_required_flag->enabled)); + my $part_required_org = $org_id || $U->get_org_tree->id; + $part_required = $part_required_flag + && $U->ou_ancestor_setting_value($part_required_org, 'circ.holds.require_monographic_part_when_present'); + if (!$part_required) { + my $np_copies = $e->json_query({ + select => { acp => [{column => 'id', transform => 'count', alias => 'count'}]}, + from => {acp => {acn => {}, acpm => {type => 'left'}}}, + where => { + '+acp' => {deleted => 'f'}, + '+acn' => {deleted => 'f', record => $bre->id}, + '+acpm' => {id => undef} + } + }); + $part_required = 1 if $np_copies->[0]->{count} == 0; + } + } + $meta->{part_required} = $part_required; } if ($meta->{metarecord}) { diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm index fab9dd6a6e..367f096111 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm @@ -374,6 +374,12 @@ sub load_common { my $geo_org = $ctx->{physical_loc} || $self->cgi->param('loc') || $ctx->{aou_tree}->()->id; my $geo_sort_for_org = $ctx->{get_org_setting}->($geo_org, 'opac.holdings_sort_by_geographic_proximity'); $ctx->{geo_sort} = $geo_sort && $U->is_true($geo_sort_for_org); + my $part_required_flag = $e->retrieve_config_global_flag('circ.holds.allow_require_monographic_part_when_present'); + $part_required_flag = ($part_required_flag and $U->is_true($part_required_flag->enabled)); + my $part_required_org = $ctx->{physical_loc} || $self->cgi->param('locg') || $self->cgi->param('loc') || $ctx->{aou_tree}->()->id; + my $part_required_setting = $ctx->{get_org_setting}->($part_required_org, 'circ.holds.require_monographic_part_when_present'); + my $part_required = $part_required_flag && $part_required_setting; + $ctx->{part_required_when_present} = $part_required; # capture some commonly accessed pages $ctx->{home_page} = $ctx->{proto} . '://' . $ctx->{hostname} . $self->ctx->{opac_root} . "/home"; diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm index 78bba4acac..49d72bab3a 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm @@ -1619,21 +1619,28 @@ sub load_place_hold { {record => $rec->id} ); - # T holds on records that have parts are OK, but if the record has - # no non-part copies, the hold will ultimately fail. When that - # happens, require the user to select a part. + # T holds on records that have parts are normally OK, but if the record has + # no non-part copies, the hold will ultimately fail. When that happens, + # require the user to select a part. + # + # If the global flag circ.holds.allow_require_monographic_part_when_present is + # enabled, and the library setting circ.holds.require_monographic_part_when_present + # is active, then any configured parts for the bib is enough to disallow title holds. my $part_required = 0; if (@$parts) { - my $np_copies = $e->json_query({ - select => { acp => [{column => 'id', transform => 'count', alias => 'count'}]}, - from => {acp => {acn => {}, acpm => {type => 'left'}}}, - where => { - '+acp' => {deleted => 'f'}, - '+acn' => {deleted => 'f', record => $rec->id}, - '+acpm' => {id => undef} - } - }); - $part_required = 1 if $np_copies->[0]->{count} == 0; + $part_required = $ctx->{part_required_when_present}; + if (!$part_required) { + my $np_copies = $e->json_query({ + select => { acp => [{column => 'id', transform => 'count', alias => 'count'}]}, + from => {acp => {acn => {}, acpm => {type => 'left'}}}, + where => { + '+acp' => {deleted => 'f'}, + '+acn' => {deleted => 'f', record => $rec->id}, + '+acpm' => {id => undef} + } + }); + $part_required = 1 if $np_copies->[0]->{count} == 0; + } } push(@hold_data, $data_filler->({ diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql index ddfabe46ae..f8238c3d2e 100644 --- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql +++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql @@ -21503,6 +21503,33 @@ VALUES ( 'integer' ); +-- eparts + +INSERT INTO config.global_flag (name, value, enabled, label) +VALUES ( + 'circ.holds.allow_require_monographic_part_when_present', + NULL, + FALSE, + oils_i18n_gettext( + 'circ.holds.allow_require_monographic_part_when_present', + 'Holds: Enable the Require Monographic Part When Present library setting.', + 'cgf', 'label' + ) +); + +INSERT INTO config.org_unit_setting_type (name, label, grp, description, datatype) +VALUES ( + 'circ.holds.require_monographic_part_when_present', + oils_i18n_gettext('circ.holds.require_monographic_part_when_present', + 'Require Monographic Part when Present', + 'coust', 'label'), + 'circ', + oils_i18n_gettext('circ.holds.require_monographic_part_when_present', + 'Normally the selection of a monographic part during hold placement is optional if there is at least one copy on the bib without a monographic part. A true value for this setting will require part selection even under this condition.', + 'coust', 'description'), + 'bool' +); + ------------------- Disabled example A/T defintions ------------------------------ -- Create a "dummy" slot when applicable, and trigger the "offer curbside" events diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.eparts.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.eparts.sql new file mode 100644 index 0000000000..98dd366701 --- /dev/null +++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.eparts.sql @@ -0,0 +1,33 @@ +BEGIN; + +-- check whether patch can be applied +SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version); + +-- 950.data.seed-values.sql + +INSERT INTO config.global_flag (name, value, enabled, label) +VALUES ( + 'circ.holds.allow_require_monographic_part_when_present', + NULL, + FALSE, + oils_i18n_gettext( + 'circ.holds.allow_require_monographic_part_when_present', + 'Holds: Enable the Require Monographic Part When Present library setting.', + 'cgf', 'label' + ) +); + +INSERT INTO config.org_unit_setting_type (name, label, grp, description, datatype) +VALUES ( + 'circ.holds.require_monographic_part_when_present', + oils_i18n_gettext('circ.holds.require_monographic_part_when_present', + 'Require Monographic Part when Present', + 'coust', 'label'), + 'circ', + oils_i18n_gettext('circ.holds.require_monographic_part_when_present', + 'Normally the selection of a monographic part during hold placement is optional if there is at least one copy on the bib without a monographic part. A true value for this setting will require part selection even under this condition.', + 'coust', 'description'), + 'bool' +); + +COMMIT; diff --git a/Open-ILS/src/templates-bootstrap/opac/parts/hold_error_messages.tt2 b/Open-ILS/src/templates-bootstrap/opac/parts/hold_error_messages.tt2 index 407ea52daf..f36a0ac433 100755 --- a/Open-ILS/src/templates-bootstrap/opac/parts/hold_error_messages.tt2 +++ b/Open-ILS/src/templates-bootstrap/opac/parts/hold_error_messages.tt2 @@ -23,6 +23,7 @@ "status.holdable" => l("The item is not in a holdable status"), "no_item" => l("The system could not find this item"), "no_ultimate_items" => l("The system could not find any items to match this hold request"), + "monographic_part_required" => l("Title hold request invalid when monographic part required"), "no_matchpoint" => l("System rules do not define how to handle this item"), "no_user" => l("The system could not find this patron"), "transit_range" => l("The item cannot transit this far") diff --git a/Open-ILS/src/templates/opac/parts/hold_error_messages.tt2 b/Open-ILS/src/templates/opac/parts/hold_error_messages.tt2 index 407ea52daf..f36a0ac433 100644 --- a/Open-ILS/src/templates/opac/parts/hold_error_messages.tt2 +++ b/Open-ILS/src/templates/opac/parts/hold_error_messages.tt2 @@ -23,6 +23,7 @@ "status.holdable" => l("The item is not in a holdable status"), "no_item" => l("The system could not find this item"), "no_ultimate_items" => l("The system could not find any items to match this hold request"), + "monographic_part_required" => l("Title hold request invalid when monographic part required"), "no_matchpoint" => l("System rules do not define how to handle this item"), "no_user" => l("The system could not find this patron"), "transit_range" => l("The item cannot transit this far") diff --git a/Open-ILS/web/js/dojo/openils/circ/nls/selfcheck.js b/Open-ILS/web/js/dojo/openils/circ/nls/selfcheck.js index 438d55678b..e9e8e60da6 100644 --- a/Open-ILS/web/js/dojo/openils/circ/nls/selfcheck.js +++ b/Open-ILS/web/js/dojo/openils/circ/nls/selfcheck.js @@ -41,6 +41,7 @@ "FAIL_PART_config_rule_age_hold_protect_prox": "The item is too new to transit this far", "FAIL_PART_no_item": "The system could not find this item", "FAIL_PART_no_ultimate_items": "The system could not find any items to match this hold request", + "FAIL_PART_monographic_part_required": "Title hold request invalid when monographic part required", "FAIL_PART_no_matchpoint": "System rules do not define how to handle this item", "FAIL_PART_no_user": "The system could not find this patron", "FAIL_PART_transit_range": "The item cannot transit this far", diff --git a/docs/RELEASE_NOTES_NEXT/miscellaneous.adoc b/docs/RELEASE_NOTES_NEXT/miscellaneous.adoc index f650dfb546..9df3bf828e 100644 --- a/docs/RELEASE_NOTES_NEXT/miscellaneous.adoc +++ b/docs/RELEASE_NOTES_NEXT/miscellaneous.adoc @@ -1 +1,21 @@ * Add patron home library code as a column to the View Holds grid in the staff catalog record details page (LP#1991726) + +* LP1965446 Option to Disable Title-Level Holds on Bib Records with Parts + + This feature adds one global flag and one library setting, respectively: + + * circ.holds.allow_require_monographic_part_when_present + Holds: Enable the Require Monographic Part When Present library setting. + * circ.holds.require_monographic_part_when_present + Require Monographic Part when Present + + Normally the selection of a monographic part during hold placement is optional if there is at least one copy + on the bib without a monographic part. A true value for this setting and for the global flag will require + part selection even under this condition. This essentially removes the All/Any Parts option from the part + selection drop-down, for both versions of the public catalog (TPAC and BOOPAC), and for the Angular staff + catalog interface. + + We also test for this at the API level, which will catch situations where the UI may have stale information + on the state of the flag and setting, or when the API is being invoked by third parties under this condition. + We will throw a TITLE_HOLD_WHEN_MONOGRAPHIC_PART_REQUIRED event if a title hold is effectively disallowed + based on the presence of monographic parts and lack of part selection.