<div class="col-lg-2">
<ng-container *ngIf="ctx.holdMeta.parts.length">
<select class="form-control" (change)="setPart(ctx, $event)"
- [ngModel]="ctx.holdMeta.part ? ctx.holdMeta.part.id() : ''">
- <option value="" i18n>Any Part</option>
+ [ngModel]="ctx.holdMeta.part ? ctx.holdMeta.part.id() : (ctx.holdMeta.part_required ? ctx.holdMeta.parts[0].id() : '')">
+ <option *ngIf="!ctx.holdMeta.part_required" value="" i18n>Any Part</option>
<option *ngFor="let part of ctx.holdMeta.parts"
value="{{part.id()}}">{{part.label()}}</option>
</select>
getTargetMeta(): Promise<any> {
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)
# $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
issuance => $issuance,
part => $part,
parts => [],
+ part_required => 'f',
bibrecord => $bre,
metarecord => $metarecord,
metarecord_filters => {}
{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}) {
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";
{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->({
'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
--- /dev/null
+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;
"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")
"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")
"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",
* 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.