<field name="copy_active" reporter:datatype="bool" reporter:label="Sets Item Active"/>
<field name="restrict_copy_delete" reporter:datatype="bool" reporter:label="Restrict Deletion"/>
<field name="is_available" reporter:datatype="bool" reporter:label="Available"/>
+ <field name="hopeless_prone" reporter:datatype="bool" reporter:label="Prone to Hopeless Holds?"/>
</fields>
<links/>
<permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
<field reporter:label="Current Shelf Lib" name="current_shelf_lib" reporter:datatype="org_unit"/>
<field reporter:label="Behind Desk" name="behind_desk" reporter:datatype="bool"/>
<field reporter:label="Acquisition Request" name="acq_request" reporter:datatype="link" />
+ <field reporter:label="Hopeless Date" name="hopeless_date" reporter:datatype="timestamp"/>
</fields>
<links>
<link field="fulfillment_lib" reltype="has_a" key="id" map="" class="aou"/>
<field reporter:label="Is Staff Hold?" name="is_staff_hold" reporter:datatype="bool" />
<field reporter:label="Potential Copies" name="potential_copies" reporter:datatype="int" />
<field reporter:label="Behind Desk" name="behind_desk" reporter:datatype="bool"/>
+ <field reporter:label="Hopeless Date" name="hopeless_date" reporter:datatype="timestamp"/>
</fields>
<links>
<link field="fulfillment_lib" reltype="has_a" key="id" map="" class="aou"/>
<field reporter:label="Current Shelf Lib" name="current_shelf_lib" reporter:datatype="org_unit"/>
<field reporter:label="Behind Desk" name="behind_desk" reporter:datatype="bool"/>
<field reporter:label="Acquisition Request" name="acq_request" reporter:datatype="link" />
+ <field reporter:label="Hopeless Date" name="hopeless_date" reporter:datatype="timestamp"/>
</fields>
<links>
<link field="fulfillment_lib" reltype="has_a" key="id" map="" class="aou"/>
{{hold.ucard_barcode}}
</a>
</div>
- <!-- for balance -->
- <div class="well-label" i18n></div>
- <div class="well-label" i18n></div>
+ <div class="well-label" i18n>Hopeless Date</div>
+ <div class="well-value">{{hold.hopeless_date | formatValue:'timestamp'}}</div>
</div>
</div>
<eg-grid-column i18n-label label="Shelf Expire Time" path='shelf_expire_time' datatype="timestamp" [hidden]="true"></eg-grid-column>
<eg-grid-column i18n-label label="Current Shelf Library" path='current_shelf_lib' [hidden]="true"></eg-grid-column>
<eg-grid-column i18n-label label="Behind Desk" path='behind_desk' datatype="bool" [hidden]="true"></eg-grid-column>
+ <eg-grid-column i18n-label label="Hopeless Date" path='hopeless_date' datatype="timestamp" [hidden]="true"></eg-grid-column>
<eg-grid-column i18n-label label="Status" path='hold_status' [hidden]="true"></eg-grid-column>
<eg-grid-column i18n-label label="Clearable" path='clear_me' datatype="bool" [hidden]="true"></eg-grid-column>
<eg-grid-column i18n-label label="Is Staff-placed Hold" path='is_staff_hold' datatype="bool" [hidden]="true"></eg-grid-column>
h.request_lib, h.requestor, h.usr, h.selection_ou, h.selection_depth, h.pickup_lib,
h.hold_type, h.holdable_formats, h.phone_notify, h.email_notify, h.sms_notify,
h.sms_carrier, h.frozen, h.thaw_date, h.shelf_time, h.cut_in_line, h.mint_condition,
- h.shelf_expire_time, h.current_shelf_lib, h.behind_desk,
+ h.shelf_expire_time, h.current_shelf_lib, h.behind_desk, h.hopeless_date,
CASE WHEN h.cancel_time IS NOT NULL THEN 6
WHEN h.frozen AND h.capture_time IS NULL THEN 7
# Map of org id to 1. Any org in the map is closed.
$self->{closed_orgs} = {map {$_ => 1} @closed_orgs};
+
+ my $hopeless_prone = $self->editor->search_config_copy_status({
+ hopeless_prone => 't'
+ });
+ $self->{hopeless_prone_status_ids} = { map { $_->id => 1} @{ $hopeless_prone } };
}
return $self->exit_targeter("Error creating hold copy maps", 1);
}
+# Hopeless Date logic based on copy map
+sub handle_hopeless_date {
+ my ($self) = @_;
+ my $e = $self->editor;
+ my $hold = $self->hold;
+ my $need_update = 0;
+
+ # If copy map is empty and hopeless date is not already set,
+ # then set it. Otherwise, let's check the items for Hopeless
+ # Prone statuses. If all are hopeless then set the hopeless
+ # date if needed. If at least one is not hopeless, then
+ # clear the the hopeless date if not already unset.
+
+ if (scalar(@{$self->copies}) == 0) {
+ $logger->debug('Hopeless Holds logic (hold id ' . $hold->id . '): no copies');
+ if (!$hold->hopeless_date) {
+ $logger->debug('Hopeless Holds logic (hold id ' . $hold->id . '): setting hopeless_date');
+ $hold->hopeless_date('now');
+ $need_update = 1;
+ }
+ } else {
+ my $all_hopeless = 1;
+ foreach my $copy_hash (@{$self->copies}) {
+ if (!$self->parent->{hopeless_prone_status_ids}->{$copy_hash->{status}}) {
+ $all_hopeless = 0;
+ }
+ }
+ if ($all_hopeless) {
+ $logger->debug('Hopeless Holds logic (hold id ' . $hold->id . '): all copies have hopeless prone status');
+ if (!$hold->hopeless_date) {
+ $logger->debug('Hopeless Holds logic (hold id ' . $hold->id . '): setting hopeless_date');
+ $hold->hopeless_date('now');
+ $need_update = 1;
+ }
+ } else {
+ $logger->debug('Hopeless Holds logic (hold id ' . $hold->id . '): at least one copy without a hopeless prone status');
+ if ($hold->hopeless_date) {
+ $logger->debug('Hopeless Holds logic (hold id ' . $hold->id . '): clearing hopeless_date');
+ $hold->clear_hopeless_date;
+ $need_update = 1;
+ }
+ }
+ }
+
+ if ($need_update) {
+ $logger->debug('Hopeless Holds logic (hold id ' . $hold->id . '): attempting update');
+ $e->update_action_hold_request($hold)
+ or return $self->exit_targeter(
+ "Error updating Hopeless Date for hold request", 1);
+ # FIXME: sanity-check, will a commit happen further down the line for all use cases?
+ }
+}
+
# unique set of circ lib IDs for all in-progress copy blobs.
sub get_copy_circ_libs {
my $self = shift;
return unless $self->get_hold_copies;
return unless $self->update_copy_maps;
+ # Hopeless Date logic based on copy map
+
+ $self->handle_hopeless_date;
+
# Confirm that we have something to work on. If we have no
# copies at this point, there's also nothing to recall.
return unless $self->handle_no_copies;
opac_visible BOOL NOT NULL DEFAULT FALSE,
copy_active BOOL NOT NULL DEFAULT FALSE,
restrict_copy_delete BOOL NOT NULL DEFAULT FALSE,
- is_available BOOL NOT NULL DEFAULT FALSE
+ is_available BOOL NOT NULL DEFAULT FALSE,
+ hopeless_prone BOOL NOT NULL DEFAULT FALSE
);
COMMENT ON TABLE config.copy_status IS $$
Copy Statuses
mint_condition BOOL NOT NULL DEFAULT TRUE,
shelf_expire_time TIMESTAMPTZ,
current_shelf_lib INT REFERENCES actor.org_unit DEFERRABLE INITIALLY DEFERRED,
- behind_desk BOOLEAN NOT NULL DEFAULT FALSE
+ behind_desk BOOLEAN NOT NULL DEFAULT FALSE,
+ hopeless_date TIMESTAMP WITH TIME ZONE
);
ALTER TABLE action.hold_request ADD CONSTRAINT sms_check CHECK (
sms_notify IS NULL
--- /dev/null
+BEGIN;
+
+SELECT evergreen.upgrade_deps_block_check('YYYY', :eg_version);
+
+ALTER TABLE config.copy_status ADD COLUMN hopeless_prone BOOL NOT NULL DEFAULT FALSE; -- 002.schema.config.sql
+ALTER TABLE action.hold_request ADD COLUMN hopeless_date TIMESTAMP WITH TIME ZONE; -- 090.schema.action.sql
+
+COMMIT;
<eg-grid-field label="[% l('Shelf Expire Time') %]" path='hold.shelf_expire_time' datatype="timestamp" hidden></eg-grid-field>
<eg-grid-field label="[% l('Current Shelf Library') %]" path='hold.current_shelf_lib' hidden></eg-grid-field>
<eg-grid-field label="[% l('Behind Desk') %]" path='hold.behind_desk' datatype="bool" hidden></eg-grid-field>
+ <eg-grid-field label="[% l('Hopeless Date') %]" path='hold.hopeless_date' datatype="timestamp" hidden></eg-grid-field>
<eg-grid-field label="[% l('Status') %]" path='hold.hold_status' hidden></eg-grid-field>
<eg-grid-field label="[% l('Clearable') %]" path='hold.clear_me' datatype="bool" hidden></eg-grid-field>
<eg-grid-field label="[% l('Is Staff-placed Hold') %]" path='hold.is_staff_hold' datatype="bool" hidden></eg-grid-field>
<eg-grid-field label="[% l('Shelf Expire Time') %]" path='hold.shelf_expire_time' datatype="timestamp" hidden></eg-grid-field>
<eg-grid-field label="[% l('Current Shelf Library') %]" path='hold.current_shelf_lib' hidden></eg-grid-field>
<eg-grid-field label="[% l('Behind Desk') %]" path='hold.behind_desk' datatype="bool" hidden></eg-grid-field>
+ <eg-grid-field label="[% l('Hopeless Date') %]" path='hold.hopeless_date' datatype="timestamp" hidden></eg-grid-field>
<eg-grid-field label="[% l('Status') %]" path='hold.hold_status' hidden></eg-grid-field>
<eg-grid-field label="[% l('Clearable') %]" path='hold.clear_me' datatype="bool" hidden></eg-grid-field>
<eg-grid-field label="[% l('Is Staff-placed Hold') %]" path='hold.is_staff_hold' datatype="bool" hidden></eg-grid-field>
<div class="flex-cell">[% l('Cancel Note') %]</div>
<div class="flex-cell well">{{hold.cancel_note()}}</div>
</div>
+<div class="flex-row">
+ <div class="flex-cell">[% l('Hopeless Date') %]</div>
+ <div class="flex-cell well">{{hold.hopeless_date() | date:$root.egDateAndTimeFormat}}</div>
+ <!-- for balance -->
+ <div class="flex-cell"></div>
+ <div class="flex-cell well"></div>
+ <div class="flex-cell"></div>
+ <div class="flex-cell well"></div>
+</div>
<ul class="nav nav-tabs pad-vert" ng-init="detail_tab='notes'">
<li ng-class="{active : detail_tab == 'notes'}">