lp1811710: toward hopeless holds, backend and existing UI's
authorJason Etheridge <jason@EquinoxInitiative.org>
Wed, 17 Apr 2019 12:29:53 +0000 (08:29 -0400)
committerChris Sharp <csharp@georgialibraries.org>
Tue, 15 Sep 2020 15:13:15 +0000 (11:13 -0400)
Signed-off-by: Jason Etheridge <jason@EquinoxInitiative.org>
Signed-off-by: Galen Charlton <gmc@equinoxinitiative.org>
Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Signed-off-by: Chris Sharp <csharp@georgialibraries.org>

Open-ILS/examples/fm_IDL.xml
Open-ILS/src/eg2/src/app/staff/share/holds/detail.component.html
Open-ILS/src/eg2/src/app/staff/share/holds/grid.component.html
Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm
Open-ILS/src/perlmods/lib/OpenILS/Utils/HoldTargeter.pm
Open-ILS/src/sql/Pg/002.schema.config.sql
Open-ILS/src/sql/Pg/090.schema.action.sql
Open-ILS/src/sql/Pg/upgrade/YYYY.schema.hopeless_holds.sql [new file with mode: 0644]
Open-ILS/src/templates/staff/cat/catalog/t_holds.tt2
Open-ILS/src/templates/staff/circ/holds/t_shelf_list.tt2
Open-ILS/src/templates/staff/circ/share/t_hold_details.tt2

index 11dcf07..5ec1ff4 100644 (file)
@@ -4603,6 +4603,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
             <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">
@@ -6574,6 +6575,7 @@ SELECT  usr,
                        <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"/>
@@ -6739,6 +6741,7 @@ SELECT  usr,
                        <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"/>
@@ -6810,6 +6813,7 @@ SELECT  usr,
                        <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"/>
index daeeb89..bc7e4f6 100644 (file)
@@ -91,9 +91,8 @@
         {{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>
 
index 7a9aceb..9cead96 100644 (file)
       <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>
index 5c2583c..7cf6e26 100644 (file)
@@ -2166,7 +2166,7 @@ SELECT  h.id, h.request_time, h.capture_time, h.fulfillment_time, h.checkin_time
         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
index 44685cf..3816822 100644 (file)
@@ -203,6 +203,11 @@ sub init {
 
     # 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 } };
 }
 
 
@@ -628,6 +633,59 @@ sub update_copy_maps {
     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;
@@ -1264,6 +1322,10 @@ sub target {
     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;
index 6dab77e..2978fe8 100644 (file)
@@ -442,7 +442,8 @@ CREATE TABLE config.copy_status (
        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
index 0a4bb2c..f62a9fa 100644 (file)
@@ -469,7 +469,8 @@ CREATE TABLE action.hold_request (
        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
diff --git a/Open-ILS/src/sql/Pg/upgrade/YYYY.schema.hopeless_holds.sql b/Open-ILS/src/sql/Pg/upgrade/YYYY.schema.hopeless_holds.sql
new file mode 100644 (file)
index 0000000..7205a71
--- /dev/null
@@ -0,0 +1,8 @@
+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;
index f50be4c..0579075 100644 (file)
   <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>
index bbd8679..c89823c 100644 (file)
   <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>
index ab2b752..ece4719 100644 (file)
   <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'}">