Active date
authorThomas Berezansky <tsbere@mvlc.org>
Mon, 13 Jun 2011 01:11:13 +0000 (21:11 -0400)
committerBill Erickson <berick@esilibrary.com>
Tue, 21 Jun 2011 19:51:40 +0000 (15:51 -0400)
Record the date a copy first became "active" after creation in active_date.
Offer Org Unit setting for using the active date for age hold protection.
Any copy without an active_date, with age hold protect using it, will be
    protected until it has an active date. Regardless of create_date.
Circ/Hold matrix can match on item age based on active_date.

Active is defined as entering a status with copy_active set to true. By default:

Available
Checked out
Reshelving
On holds shelf
ILL
Reserves
On reservation shelf

Signed-off-by: Thomas Berezansky <tsbere@mvlc.org>
Signed-off-by: Bill Erickson <berick@esilibrary.com>
24 files changed:
Open-ILS/examples/fm_IDL.xml
Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/asset.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/config.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/serial.pm
Open-ILS/src/perlmods/lib/OpenILS/Utils/PermitHold.pm
Open-ILS/src/sql/Pg/002.schema.config.sql
Open-ILS/src/sql/Pg/040.schema.asset.sql
Open-ILS/src/sql/Pg/099.matrix_weights.sql
Open-ILS/src/sql/Pg/100.circ_matrix.sql
Open-ILS/src/sql/Pg/110.hold_matrix.sql
Open-ILS/src/sql/Pg/210.schema.serials.sql
Open-ILS/src/sql/Pg/950.data.seed-values.sql
Open-ILS/web/conify/global/config/copy_status.html
Open-ILS/web/js/dojo/openils/conify/nls/conify.js
Open-ILS/web/opac/locale/en-US/lang.dtd
Open-ILS/web/opac/locale/en-US/opac.dtd
Open-ILS/web/opac/skin/craftsman/xml/rdetail/rdetail_cn_details.xml
Open-ILS/web/opac/skin/default/js/copy_details.js
Open-ILS/web/opac/skin/default/xml/rdetail/rdetail_cn_details.xml
Open-ILS/web/templates/default/conify/global/config/circ_matrix_matchpoint.tt2
Open-ILS/xul/staff_client/server/cat/copy_editor.js
Open-ILS/xul/staff_client/server/circ/alternate_copy_summary.js
Open-ILS/xul/staff_client/server/circ/alternate_copy_summary.xul
Open-ILS/xul/staff_client/server/locale/en-US/cat.properties

index e41464e..ce42aa3 100644 (file)
@@ -1154,6 +1154,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
             <field reporter:label="MARC Form" name="marc_form" oils_persist:primitive="string" reporter:datatype="float"/>
             <field reporter:label="Videorecording Format" name="marc_vr_format" oils_persist:primitive="string" reporter:datatype="float"/>
             <field reporter:label="Reference?" name="ref_flag" reporter:datatype="float"/>
+            <field reporter:label="Item Age &lt;" name="item_age" reporter:datatype="float"/>
         </fields>
         <links/>
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
@@ -1182,6 +1183,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
             <field reporter:label="Reference?" name="ref_flag" reporter:datatype="float"/>
             <field reporter:label="User Age: Lower Bound" name="usr_age_lower_bound" reporter:datatype="float"/>
             <field reporter:label="User Age: Upper Bound" name="usr_age_upper_bound" reporter:datatype="float"/>
+            <field reporter:label="Item Age &lt;" name="item_age" reporter:datatype="float"/>
         </fields>
         <links/>
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
@@ -1235,6 +1237,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <field reporter:label="MARC Bib Level" name="marc_bib_level" oils_persist:primitive="string" reporter:datatype="link"/>
                        <field reporter:label="Videorecording Format" name="marc_vr_format" oils_persist:primitive="string" reporter:datatype="link"/>
                        <field reporter:label="Reference?" name="ref_flag" reporter:datatype="bool"/>
+            <field reporter:label="Item Age &lt;" name="item_age" reporter:datatype="text"/>
                        <field reporter:label="Holdable?" name="holdable" reporter:datatype="bool"/>
                        <field reporter:label="Range is from Owning Lib?" name="distance_is_from_owner" reporter:datatype="bool"/>
                        <field reporter:label="Transit Range" name="transit_range" reporter:datatype="link"/>
@@ -1287,6 +1290,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
             <field reporter:label="Juvenile?" name="juvenile_flag" reporter:datatype="bool"/>
                        <field reporter:label="User Age: Lower Bound" name="usr_age_lower_bound" reporter:datatype="text"/>
                        <field reporter:label="User Age: Upper Bound" name="usr_age_upper_bound" reporter:datatype="text"/>
+            <field reporter:label="Item Age &lt;" name="item_age" reporter:datatype="text"/>
                        <field reporter:label="Circulate?" name="circulate" reporter:datatype="bool"/>
                        <field reporter:label="Duration Rule" name="duration_rule" reporter:datatype="link"/>
                        <field reporter:label="Recurring Fine Rule" name="recurring_fine_rule" reporter:datatype="link"/>
@@ -2709,6 +2713,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <field name="id" reporter:selector="name" reporter:datatype="id"/>
                        <field name="name"  reporter:datatype="text" oils_persist:i18n="true"/>
                        <field name="opac_visible" reporter:datatype="bool"/>
+            <field name="copy_active" reporter:datatype="bool"/>
                </fields>
                <links/>
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
@@ -3787,6 +3792,7 @@ SELECT  usr,
                        <field reporter:label="Can Circulate" name="circulate" reporter:datatype="bool"/>
                        <field reporter:label="Copy Number on Volume" name="copy_number" reporter:datatype="text"/>
                        <field reporter:label="Creation Date/Time" name="create_date" reporter:datatype="timestamp"/>
+                       <field reporter:label="Active Date/Time" name="active_date" reporter:datatype="timestamp"/>
                        <field reporter:label="Creating User" name="creator" reporter:datatype="link"/>
                        <field reporter:label="Is Deleted" name="deleted" reporter:datatype="bool"/>
                        <field reporter:label="Dummy ISBN" name="dummy_isbn" reporter:datatype="text"/>
@@ -4813,6 +4819,7 @@ SELECT  usr,
                        <field reporter:label="Can Circulate" name="circulate" reporter:datatype="bool"/>
                        <field reporter:label="Copy Number on Volume" name="copy_number" reporter:datatype="text"/>
                        <field reporter:label="Creation Date/Time" name="create_date" reporter:datatype="timestamp"/>
+                       <field reporter:label="Active Date/Time" name="active_date" reporter:datatype="timestamp"/>
                        <field reporter:label="Creating User" name="creator" reporter:datatype="link"/>
                        <field reporter:label="Is Deleted" name="deleted" reporter:datatype="bool"/>
                        <field reporter:label="Dummy ISBN" name="dummy_isbn" reporter:datatype="text"/>
index 6cecb8d..0fc1061 100644 (file)
@@ -72,7 +72,7 @@ __PACKAGE__->columns( Essential => qw/call_number barcode creator create_date ed
                                   fine_level circulate deposit price ref opac_visible
                                   circ_as_type circ_modifier deposit_amount location mint_condition
                                   holdable dummy_title dummy_author deleted alert_message
-                                  age_protect floating cost status_changed_time/ );
+                                  age_protect floating cost status_changed_time active_date/ );
 
 #-------------------------------------------------------------------------------
 package asset::copy_part_map;
index da03f1f..5034730 100644 (file)
@@ -73,7 +73,7 @@ package config::copy_status;
 use base qw/config/;
 __PACKAGE__->table('config_copy_status');
 __PACKAGE__->columns(Primary => 'id');
-__PACKAGE__->columns(Essential => qw/name holdable opac_visible/);
+__PACKAGE__->columns(Essential => qw/name holdable opac_visible copy_active/);
 #-------------------------------------------------------------------------------
 
 package config::net_access_level;
index 431c672..0264aa6 100644 (file)
@@ -45,7 +45,7 @@ __PACKAGE__->columns( Essential => qw/call_number barcode creator create_date ed
                                   fine_level circulate deposit price ref opac_visible dummy_isbn
                                   circ_as_type circ_modifier deposit_amount location mint_condition
                                   holdable dummy_title dummy_author deleted alert_message
-                                  age_protect floating summary_contents detailed_contents/ );
+                                  age_protect floating summary_contents detailed_contents active_date/ );
 
 #-------------------------------------------------------------------------------
 package serial::record_entry;
index 47a561a..39bfaeb 100644 (file)
@@ -162,13 +162,19 @@ sub check_age_protect {
                { order_by => 'age' }
        );
 
-       # Now, now many seconds old is this copy
-       my $create_date = DateTime::Format::ISO8601
-               ->new
-               ->parse_datetime( OpenSRF::Utils::cleanse_ISO8601($copy->create_date) )
-               ->epoch;
-
-       my $age = time - $create_date;
+    my $age_protect_date = $copy->create_date;
+    $age_protect_date = $copy->active_date if($U->ou_ancestor_setting_value($copy->circ_lib, 'circ.holds.age_protect.active_date'));
+
+    my $age = 0;
+    my $age_protect_parsed;
+    if($age_protect_date) {
+       # Now, now many seconds old is this copy
+           $age_protect_parsed = DateTime::Format::ISO8601
+                   ->new
+               ->parse_datetime( OpenSRF::Utils::cleanse_ISO8601($age_protect_date) )
+               ->epoch;
+           $age = time - $age_protect_parsed;
+    }
 
        for my $protection ( @$protection_list ) {
 
@@ -180,7 +186,7 @@ sub check_age_protect {
                # How many seconds old does the copy have to be to escape age protection
                my $interval = OpenSRF::Utils::interval_to_seconds($protection->age);
 
-               $logger->info("age_protect interval=$interval, create_date=$create_date, age=$age");
+               $logger->info("age_protect interval=$interval, age_protect_date=$age_protect_parsed, age=$age");
 
                if( $interval > $age ) { 
                        # if age of the item is less than the protection interval, 
index e2922c4..d998f7f 100644 (file)
@@ -349,7 +349,8 @@ CREATE TABLE config.copy_status (
        id              SERIAL  PRIMARY KEY,
        name            TEXT    NOT NULL UNIQUE,
        holdable        BOOL    NOT NULL DEFAULT FALSE,
-       opac_visible    BOOL    NOT NULL DEFAULT FALSE
+       opac_visible    BOOL    NOT NULL DEFAULT FALSE,
+    copy_active  BOOL    NOT NULL DEFAULT FALSE
 );
 COMMENT ON TABLE config.copy_status IS $$
 Copy Statuses
index 010c3bc..ddb116a 100644 (file)
@@ -80,6 +80,7 @@ CREATE TABLE asset.copy (
        floating                BOOL                            NOT NULL DEFAULT FALSE,
        dummy_isbn      TEXT,
        status_changed_time TIMESTAMP WITH TIME ZONE,
+       active_date TIMESTAMP WITH TIME ZONE,
        mint_condition      BOOL        NOT NULL DEFAULT TRUE,
     cost    NUMERIC(8,2)
 );
@@ -118,6 +119,23 @@ RETURNS TRIGGER AS $$
 BEGIN
     IF NEW.status <> OLD.status THEN
         NEW.status_changed_time := now();
+        IF NEW.active_date IS NULL AND NEW.status IN (SELECT id FROM config.copy_status WHERE copy_active = true) THEN
+            NEW.active_date := now();
+        END IF;
+    END IF;
+    RETURN NEW;
+END;
+$$ LANGUAGE plpgsql;
+
+-- Need to check on initial create. Fast adds, manual edit of status at create, etc.
+CREATE OR REPLACE FUNCTION asset.acp_created()
+RETURNS TRIGGER AS $$
+BEGIN
+    IF NEW.active_date IS NULL AND NEW.status IN (SELECT id FROM config.copy_status WHERE copy_active = true) THEN
+        NEW.active_date := now();
+    END IF;
+    IF NEW.status_changed_time IS NULL THEN
+        NEW.status_changed_time := now();
     END IF;
     RETURN NEW;
 END;
@@ -127,6 +145,10 @@ CREATE TRIGGER acp_status_changed_trig
     BEFORE UPDATE ON asset.copy
     FOR EACH ROW EXECUTE PROCEDURE asset.acp_status_changed();
 
+CREATE TRIGGER acp_created_trig
+    BEFORE INSERT ON asset.copy
+    FOR EACH ROW EXECUTE PROCEDURE asset.acp_created();
+
 CREATE TABLE asset.stat_cat_sip_fields (
     field   CHAR(2) PRIMARY KEY,
     name    TEXT    NOT NULL,
index febf569..5854d3e 100644 (file)
@@ -19,7 +19,8 @@ CREATE TABLE config.circ_matrix_weights (
     juvenile_flag           NUMERIC(6,2)   NOT NULL,
     is_renewal              NUMERIC(6,2)   NOT NULL,
     usr_age_lower_bound     NUMERIC(6,2)   NOT NULL,
-    usr_age_upper_bound     NUMERIC(6,2)   NOT NULL
+    usr_age_upper_bound     NUMERIC(6,2)   NOT NULL,
+    item_age                NUMERIC(6,2)   NOT NULL
 );
 
 -- Hold Matrix Weights
@@ -39,7 +40,8 @@ CREATE TABLE config.hold_matrix_weights (
     marc_bib_level          NUMERIC(6,2)   NOT NULL,
     marc_vr_format          NUMERIC(6,2)   NOT NULL,
     juvenile_flag           NUMERIC(6,2)   NOT NULL,
-    ref_flag                NUMERIC(6,2)   NOT NULL
+    ref_flag                NUMERIC(6,2)   NOT NULL,
+    item_age                NUMERIC(6,2)   NOT NULL
 );
 
 -- Linking between weights and org units
index fadc392..9074ba7 100644 (file)
@@ -69,6 +69,7 @@ CREATE TABLE config.circ_matrix_matchpoint (
     is_renewal           BOOL,
     usr_age_lower_bound  INTERVAL,
     usr_age_upper_bound  INTERVAL,
+    item_age             INTERVAL,
     -- "Result" Fields
     circulate            BOOL,   -- Hard "can't circ" flag requiring an override
     duration_rule        INT     REFERENCES config.rule_circ_duration (id) DEFERRABLE INITIALLY DEFERRED,
@@ -83,7 +84,7 @@ CREATE TABLE config.circ_matrix_matchpoint (
 );
 
 -- Nulls don't count for a constraint match, so we have to coalesce them into something that does.
-CREATE UNIQUE INDEX ccmm_once_per_paramset ON config.circ_matrix_matchpoint (org_unit, grp, COALESCE(circ_modifier, ''), COALESCE(marc_type, ''), COALESCE(marc_form, ''), COALESCE(marc_bib_level,''), COALESCE(marc_vr_format, ''), COALESCE(copy_circ_lib::TEXT, ''), COALESCE(copy_owning_lib::TEXT, ''), COALESCE(user_home_ou::TEXT, ''), COALESCE(ref_flag::TEXT, ''), COALESCE(juvenile_flag::TEXT, ''), COALESCE(is_renewal::TEXT, ''), COALESCE(usr_age_lower_bound::TEXT, ''), COALESCE(usr_age_upper_bound::TEXT, '')) WHERE active;
+CREATE UNIQUE INDEX ccmm_once_per_paramset ON config.circ_matrix_matchpoint (org_unit, grp, COALESCE(circ_modifier, ''), COALESCE(marc_type, ''), COALESCE(marc_form, ''), COALESCE(marc_bib_level,''), COALESCE(marc_vr_format, ''), COALESCE(copy_circ_lib::TEXT, ''), COALESCE(copy_owning_lib::TEXT, ''), COALESCE(user_home_ou::TEXT, ''), COALESCE(ref_flag::TEXT, ''), COALESCE(juvenile_flag::TEXT, ''), COALESCE(is_renewal::TEXT, ''), COALESCE(usr_age_lower_bound::TEXT, ''), COALESCE(usr_age_upper_bound::TEXT, ''), COALESCE(item_age::TEXT, '')) WHERE active;
 
 -- Tests for max items out by circ_modifier
 CREATE TABLE config.circ_matrix_circ_mod_test (
@@ -109,6 +110,7 @@ DECLARE
     matchpoint      config.circ_matrix_matchpoint%ROWTYPE;
     weights         config.circ_matrix_weights%ROWTYPE;
     user_age        INTERVAL;
+    my_item_age     INTERVAL;
     denominator     NUMERIC(6,2);
     row_list        INT[];
     result          action.found_circ_matrix_matchpoint;
@@ -125,6 +127,11 @@ BEGIN
         SELECT INTO user_age age(user_object.dob);
     END IF;
 
+    -- Ditto
+    IF item_object.active_date IS NOT NULL THEN
+        SELECT INTO my_item_age age(item_object.active_date);
+    END IF;
+
     -- Grab the closest set circ weight setting.
     SELECT INTO weights cw.*
       FROM config.weight_assoc wa
@@ -151,6 +158,7 @@ BEGIN
         weights.is_renewal          := 7.0;
         weights.usr_age_lower_bound := 0.0;
         weights.usr_age_upper_bound := 0.0;
+        weights.item_age            := 0.0;
     END IF;
 
     -- Determine the max (expected) depth (+1) of the org tree and max depth of the permisson tree
@@ -194,6 +202,7 @@ BEGIN
                 AND (m.marc_bib_level           IS NULL OR m.marc_bib_level = rec_descriptor.bib_level)
                 AND (m.marc_vr_format           IS NULL OR m.marc_vr_format = rec_descriptor.vr_format)
                 AND (m.ref_flag                 IS NULL OR m.ref_flag = item_object.ref)
+                AND (m.item_age                 IS NULL OR (my_item_age IS NOT NULL AND m.item_age > my_item_age))
           ORDER BY
                 -- Permission Groups
                 CASE WHEN upgad.distance        IS NOT NULL THEN 2^(2*weights.grp - (upgad.distance/denominator)) ELSE 0.0 END +
@@ -213,7 +222,11 @@ BEGIN
                 CASE WHEN m.marc_type           IS NOT NULL THEN 4^weights.marc_type ELSE 0.0 END +
                 CASE WHEN m.marc_form           IS NOT NULL THEN 4^weights.marc_form ELSE 0.0 END +
                 CASE WHEN m.marc_vr_format      IS NOT NULL THEN 4^weights.marc_vr_format ELSE 0.0 END +
-                CASE WHEN m.ref_flag            IS NOT NULL THEN 4^weights.ref_flag ELSE 0.0 END DESC,
+                CASE WHEN m.ref_flag            IS NOT NULL THEN 4^weights.ref_flag ELSE 0.0 END +
+                -- Item age has a slight adjustment to weight based on value.
+                -- This should ensure that a shorter age limit comes first when all else is equal.
+                -- NOTE: This assumes that intervals will normally be in days.
+                CASE WHEN m.item_age            IS NOT NULL THEN 4^weights.item_age - 1 + 86400/EXTRACT(EPOCH FROM m.item_age) ELSE 0.0 END DESC,
                 -- Final sort on id, so that if two rules have the same sorting in the previous sort they have a defined order
                 -- This prevents "we changed the table order by updating a rule, and we started getting different results"
                 m.id LOOP
index 5ffa88f..76a1259 100644 (file)
@@ -47,6 +47,7 @@ CREATE TABLE config.hold_matrix_matchpoint (
     marc_vr_format          TEXT,
     juvenile_flag           BOOL,
     ref_flag                BOOL,
+    item_age                INTERVAL,
     -- "Result" Fields
     holdable                BOOL    NOT NULL DEFAULT TRUE,                -- Hard "can't hold" flag requiring an override
     distance_is_from_owner  BOOL    NOT NULL DEFAULT FALSE,                -- How to calculate transit_range.  True means owning lib, false means copy circ lib
@@ -58,7 +59,7 @@ CREATE TABLE config.hold_matrix_matchpoint (
 );
 
 -- Nulls don't count for a constraint match, so we have to coalesce them into something that does.
-CREATE UNIQUE INDEX chmm_once_per_paramset ON config.hold_matrix_matchpoint (COALESCE(user_home_ou::TEXT, ''), COALESCE(request_ou::TEXT, ''), COALESCE(pickup_ou::TEXT, ''), COALESCE(item_owning_ou::TEXT, ''), COALESCE(item_circ_ou::TEXT, ''), COALESCE(usr_grp::TEXT, ''), COALESCE(requestor_grp::TEXT, ''), COALESCE(circ_modifier, ''), COALESCE(marc_type, ''), COALESCE(marc_form, ''), COALESCE(marc_bib_level, ''), COALESCE(marc_vr_format, ''), COALESCE(juvenile_flag::TEXT, ''), COALESCE(ref_flag::TEXT, '')) WHERE active;
+CREATE UNIQUE INDEX chmm_once_per_paramset ON config.hold_matrix_matchpoint (COALESCE(user_home_ou::TEXT, ''), COALESCE(request_ou::TEXT, ''), COALESCE(pickup_ou::TEXT, ''), COALESCE(item_owning_ou::TEXT, ''), COALESCE(item_circ_ou::TEXT, ''), COALESCE(usr_grp::TEXT, ''), COALESCE(requestor_grp::TEXT, ''), COALESCE(circ_modifier, ''), COALESCE(marc_type, ''), COALESCE(marc_form, ''), COALESCE(marc_bib_level, ''), COALESCE(marc_vr_format, ''), COALESCE(juvenile_flag::TEXT, ''), COALESCE(ref_flag::TEXT, ''), COALESCE(item_age::TEXT, '')) WHERE active;
 
 CREATE OR REPLACE FUNCTION action.find_hold_matrix_matchpoint(pickup_ou integer, request_ou integer, match_item bigint, match_user integer, match_requestor integer)
   RETURNS integer AS
@@ -68,6 +69,7 @@ DECLARE
     user_object         actor.usr%ROWTYPE;
     item_object         asset.copy%ROWTYPE;
     item_cn_object      asset.call_number%ROWTYPE;
+    my_item_age         INTERVAL;
     rec_descriptor      metabib.rec_descriptor%ROWTYPE;
     matchpoint          config.hold_matrix_matchpoint%ROWTYPE;
     weights             config.hold_matrix_weights%ROWTYPE;
@@ -79,6 +81,10 @@ BEGIN
     SELECT INTO item_cn_object      * FROM asset.call_number        WHERE id = item_object.call_number;
     SELECT INTO rec_descriptor      * FROM metabib.rec_descriptor   WHERE record = item_cn_object.record;
 
+    IF item_object.active_date IS NOT NULL THEN
+        SELECT INTO my_item_age age(item_object.active_date);
+    END IF;
+
     -- The item's owner should probably be the one determining if the item is holdable
     -- How to decide that is debatable. Decided to default to the circ library (where the item lives)
     -- This flag will allow for setting it to the owning library (where the call number "lives")
@@ -99,7 +105,7 @@ BEGIN
         SELECT INTO weights hw.*
           FROM config.weight_assoc wa
                JOIN config.hold_matrix_weights hw ON (hw.id = wa.hold_weights)
-               JOIN actor.org_unit_ancestors_distance( cn_object.owning_lib ) d ON (wa.org_unit = d.id)
+               JOIN actor.org_unit_ancestors_distance( item_cn_object.owning_lib ) d ON (wa.org_unit = d.id)
           WHERE active
           ORDER BY d.distance
           LIMIT 1;
@@ -121,6 +127,7 @@ BEGIN
         weights.marc_vr_format  := 1.0;
         weights.juvenile_flag   := 4.0;
         weights.ref_flag        := 0.0;
+        weights.item_age        := 0.0;
     END IF;
 
     -- Determine the max (expected) depth (+1) of the org tree and max depth of the permisson tree
@@ -176,6 +183,7 @@ BEGIN
             AND (m.marc_bib_level       IS NULL OR m.marc_bib_level = rec_descriptor.bib_level)
             AND (m.marc_vr_format       IS NULL OR m.marc_vr_format = rec_descriptor.vr_format)
             AND (m.ref_flag             IS NULL OR m.ref_flag = item_object.ref)
+            AND (m.item_age             IS NULL OR (my_item_age IS NOT NULL AND m.item_age > my_item_age))
       ORDER BY
             -- Permission Groups
             CASE WHEN rpgad.distance    IS NOT NULL THEN 2^(2*weights.requestor_grp - (rpgad.distance/denominator)) ELSE 0.0 END +
@@ -193,7 +201,11 @@ BEGIN
             CASE WHEN m.marc_type       IS NOT NULL THEN 4^weights.marc_type ELSE 0.0 END +
             CASE WHEN m.marc_form       IS NOT NULL THEN 4^weights.marc_form ELSE 0.0 END +
             CASE WHEN m.marc_vr_format  IS NOT NULL THEN 4^weights.marc_vr_format ELSE 0.0 END +
-            CASE WHEN m.ref_flag        IS NOT NULL THEN 4^weights.ref_flag ELSE 0.0 END DESC,
+            CASE WHEN m.ref_flag        IS NOT NULL THEN 4^weights.ref_flag ELSE 0.0 END +
+            -- Item age has a slight adjustment to weight based on value.
+            -- This should ensure that a shorter age limit comes first when all else is equal.
+            -- NOTE: This assumes that intervals will normally be in days.
+            CASE WHEN m.item_age            IS NOT NULL THEN 4^weights.item_age - 86400/EXTRACT(EPOCH FROM m.item_age) ELSE 0.0 END DESC,
             -- Final sort on id, so that if two rules have the same sorting in the previous sort they have a defined order
             -- This prevents "we changed the table order by updating a rule, and we started getting different results"
             m.id;
@@ -217,6 +229,8 @@ DECLARE
     ou_skip              actor.org_unit_setting%ROWTYPE;
     result            action.matrix_test_result;
     hold_test        config.hold_matrix_matchpoint%ROWTYPE;
+    use_active_date   TEXT;
+    age_protect_date  TIMESTAMP WITH TIME ZONE;
     hold_count        INT;
     hold_transit_prox    INT;
     frozen_hold_count    INT;
@@ -357,8 +371,17 @@ BEGIN
 
     IF item_object.age_protect IS NOT NULL THEN
         SELECT INTO age_protect_object * FROM config.rule_age_hold_protect WHERE id = item_object.age_protect;
-
-        IF item_object.create_date + age_protect_object.age > NOW() THEN
+        IF hold_test.distance_is_from_owner THEN
+            SELECT INTO use_active_date value FROM actor.org_unit_ancestor_setting('circ.holds.age_protect.active_date', item_cn_object.owning_lib);
+        ELSE
+            SELECT INTO use_active_date value FROM actor.org_unit_ancestor_setting('circ.holds.age_protect.active_date', item_object.circ_lib);
+        END IF;
+        IF use_active_date = 'true' THEN
+            age_protect_date := COALESCE(item_object.active_date, NOW());
+        ELSE
+            age_protect_date := item_object.create_date;
+        END IF;
+        IF age_protect_date + age_protect_object.age > NOW() THEN
             IF hold_test.distance_is_from_owner THEN
                 SELECT INTO item_cn_object * FROM asset.call_number WHERE id = item_object.call_number;
                 SELECT INTO hold_transit_prox prox FROM actor.org_unit_proximity WHERE from_org = item_cn_object.owning_lib AND to_org = pickup_ou;
index 9b884b6..29617cd 100644 (file)
@@ -230,6 +230,11 @@ CREATE TRIGGER sunit_status_changed_trig
     BEFORE UPDATE ON serial.unit
     FOR EACH ROW EXECUTE PROCEDURE asset.acp_status_changed();
 
+-- ditto
+CREATE TRIGGER sunit_created_trig
+    BEFORE INSERT ON serial.unit
+    FOR EACH ROW EXECUTE PROCEDURE asset.acp_created();
+
 CREATE TABLE serial.item (
        id              SERIAL  PRIMARY KEY,
        creator         INT     NOT NULL
index 35651d2..8dd539c 100644 (file)
@@ -215,22 +215,22 @@ INSERT INTO config.rule_age_hold_protect VALUES
        (2, oils_i18n_gettext(2, '6month', 'crahp', 'name'), '6 months', 2);
 SELECT SETVAL('config.rule_age_hold_protect_id_seq'::TEXT, 100);
 
-INSERT INTO config.copy_status (id,name,holdable,opac_visible) VALUES (0,oils_i18n_gettext(0, 'Available', 'ccs', 'name'),'t','t');
-INSERT INTO config.copy_status (id,name,holdable,opac_visible) VALUES (1,oils_i18n_gettext(1, 'Checked out', 'ccs', 'name'),'t','t');
+INSERT INTO config.copy_status (id,name,holdable,opac_visible,copy_active) VALUES (0,oils_i18n_gettext(0, 'Available', 'ccs', 'name'),'t','t','t');
+INSERT INTO config.copy_status (id,name,holdable,opac_visible,copy_active) VALUES (1,oils_i18n_gettext(1, 'Checked out', 'ccs', 'name'),'t','t','t');
 INSERT INTO config.copy_status (id,name) VALUES (2,oils_i18n_gettext(2, 'Bindery', 'ccs', 'name'));
 INSERT INTO config.copy_status (id,name) VALUES (3,oils_i18n_gettext(3, 'Lost', 'ccs', 'name'));
 INSERT INTO config.copy_status (id,name) VALUES (4,oils_i18n_gettext(4, 'Missing', 'ccs', 'name'));
 INSERT INTO config.copy_status (id,name,holdable,opac_visible) VALUES (5,oils_i18n_gettext(5, 'In process', 'ccs', 'name'),'t','t');
 INSERT INTO config.copy_status (id,name,holdable,opac_visible) VALUES (6,oils_i18n_gettext(6, 'In transit', 'ccs', 'name'),'t','t');
-INSERT INTO config.copy_status (id,name,holdable,opac_visible) VALUES (7,oils_i18n_gettext(7, 'Reshelving', 'ccs', 'name'),'t','t');
-INSERT INTO config.copy_status (id,name,holdable,opac_visible) VALUES (8,oils_i18n_gettext(8, 'On holds shelf', 'ccs', 'name'),'t','t');
+INSERT INTO config.copy_status (id,name,holdable,opac_visible,copy_active) VALUES (7,oils_i18n_gettext(7, 'Reshelving', 'ccs', 'name'),'t','t','t');
+INSERT INTO config.copy_status (id,name,holdable,opac_visible,copy_active) VALUES (8,oils_i18n_gettext(8, 'On holds shelf', 'ccs', 'name'),'t','t','t');
 INSERT INTO config.copy_status (id,name,holdable,opac_visible) VALUES (9,oils_i18n_gettext(9, 'On order', 'ccs', 'name'),'t','t');
-INSERT INTO config.copy_status (id,name) VALUES (10,oils_i18n_gettext(10, 'ILL', 'ccs', 'name'));
+INSERT INTO config.copy_status (id,name,copy_active) VALUES (10,oils_i18n_gettext(10, 'ILL', 'ccs', 'name'),'t');
 INSERT INTO config.copy_status (id,name) VALUES (11,oils_i18n_gettext(11, 'Cataloging', 'ccs', 'name'));
-INSERT INTO config.copy_status (id,name,opac_visible) VALUES (12,oils_i18n_gettext(12, 'Reserves', 'ccs', 'name'),'t');
+INSERT INTO config.copy_status (id,name,opac_visible,copy_active) VALUES (12,oils_i18n_gettext(12, 'Reserves', 'ccs', 'name'),'t','t');
 INSERT INTO config.copy_status (id,name) VALUES (13,oils_i18n_gettext(13, 'Discard/Weed', 'ccs', 'name'));
 INSERT INTO config.copy_status (id,name) VALUES (14,oils_i18n_gettext(14, 'Damaged', 'ccs', 'name'));
-INSERT INTO config.copy_status (id,name) VALUES (15,oils_i18n_gettext(15, 'On reservation shelf', 'ccs', 'name'));
+INSERT INTO config.copy_status (id,name,copy_active) VALUES (15,oils_i18n_gettext(15, 'On reservation shelf', 'ccs', 'name'),'t');
 
 SELECT SETVAL('config.copy_status_id_seq'::TEXT, 100);
 
@@ -2278,20 +2278,20 @@ INSERT INTO asset.call_number VALUES (-1,1,NOW(),1,NOW(),-1,1,'UNCATALOGED');
 -- circ matrix
 INSERT INTO config.circ_matrix_matchpoint (org_unit,grp,circulate,duration_rule,recurring_fine_rule,max_fine_rule) VALUES (1,1,true,11,1,1);
 
-INSERT INTO config.circ_matrix_weights(name, org_unit, grp, circ_modifier, marc_type, marc_form, marc_bib_level, marc_vr_format, copy_circ_lib, copy_owning_lib, user_home_ou, ref_flag, juvenile_flag, is_renewal, usr_age_upper_bound, usr_age_lower_bound) VALUES 
-    ('Default', 10.0, 11.0, 5.0, 4.0, 3.0, 2.0, 2.0, 8.0, 8.0, 8.0, 1.0, 6.0, 7.0, 0.0, 0.0),
-    ('Org_Unit_First', 11.0, 10.0, 5.0, 4.0, 3.0, 2.0, 2.0, 8.0, 8.0, 8.0, 1.0, 6.0, 7.0, 0.0, 0.0),
-    ('Item_Owner_First', 8.0, 8.0, 5.0, 4.0, 3.0, 2.0, 2.0, 10.0, 11.0, 8.0, 1.0, 6.0, 7.0, 0.0, 0.0),
-    ('All_Equal', 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+INSERT INTO config.circ_matrix_weights(name, org_unit, grp, circ_modifier, marc_type, marc_form, marc_bib_level, marc_vr_format, copy_circ_lib, copy_owning_lib, user_home_ou, ref_flag, juvenile_flag, is_renewal, usr_age_upper_bound, usr_age_lower_bound, item_age) VALUES 
+    ('Default', 10.0, 11.0, 5.0, 4.0, 3.0, 2.0, 2.0, 8.0, 8.0, 8.0, 1.0, 6.0, 7.0, 0.0, 0.0, 0.0),
+    ('Org_Unit_First', 11.0, 10.0, 5.0, 4.0, 3.0, 2.0, 2.0, 8.0, 8.0, 8.0, 1.0, 6.0, 7.0, 0.0, 0.0, 0.0),
+    ('Item_Owner_First', 8.0, 8.0, 5.0, 4.0, 3.0, 2.0, 2.0, 10.0, 11.0, 8.0, 1.0, 6.0, 7.0, 0.0, 0.0, 0.0),
+    ('All_Equal', 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
 
 -- hold matrix - 110.hold_matrix.sql:
 INSERT INTO config.hold_matrix_matchpoint (requestor_grp) VALUES (1);
 
-INSERT INTO config.hold_matrix_weights(name, user_home_ou, request_ou, pickup_ou, item_owning_ou, item_circ_ou, usr_grp, requestor_grp, circ_modifier, marc_type, marc_form, marc_bib_level, marc_vr_format, juvenile_flag, ref_flag) VALUES
-    ('Default', 5.0, 5.0, 5.0, 5.0, 5.0, 7.0, 8.0, 4.0, 3.0, 2.0, 1.0, 1.0, 4.0, 0.0),
-    ('Item_Owner_First', 5.0, 5.0, 5.0, 8.0, 7.0, 5.0, 5.0, 4.0, 3.0, 2.0, 1.0, 1.0, 4.0, 0.0),
-    ('User_Before_Requestor', 5.0, 5.0, 5.0, 5.0, 5.0, 8.0, 7.0, 4.0, 3.0, 2.0, 1.0, 1.0, 4.0, 0.0),
-    ('All_Equal', 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+INSERT INTO config.hold_matrix_weights(name, user_home_ou, request_ou, pickup_ou, item_owning_ou, item_circ_ou, usr_grp, requestor_grp, circ_modifier, marc_type, marc_form, marc_bib_level, marc_vr_format, juvenile_flag, ref_flag, item_age) VALUES
+    ('Default', 5.0, 5.0, 5.0, 5.0, 5.0, 7.0, 8.0, 4.0, 3.0, 2.0, 1.0, 1.0, 4.0, 0.0, 0.0),
+    ('Item_Owner_First', 5.0, 5.0, 5.0, 8.0, 7.0, 5.0, 5.0, 4.0, 3.0, 2.0, 1.0, 1.0, 4.0, 0.0, 0.0),
+    ('User_Before_Requestor', 5.0, 5.0, 5.0, 5.0, 5.0, 8.0, 7.0, 4.0, 3.0, 2.0, 1.0, 1.0, 4.0, 0.0, 0.0),
+    ('All_Equal', 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
 
 -- dynamic weight associations
 INSERT INTO config.weight_assoc(active, org_unit, circ_weights, hold_weights) VALUES
@@ -2427,6 +2427,11 @@ INSERT into config.org_unit_setting_type
     oils_i18n_gettext('circ.holds.min_estimated_wait_interval', 'When predicting the amount of time a patron will be waiting for a hold to be fulfilled, this is the minimum estimated length of time to assume an item will be checked out. Examples: "2 weeks", "5 days"', 'coust', 'description'),
     'interval'),
 
+( 'circ.holds.age_protect.active_date',
+    oils_i18n_gettext('circ.holds.age_protect.active_date', 'Holds: Use Active Date for Age Protection', 'coust', 'label'),
+    oils_i18n_gettext('circ.holds.age_protect.active_date', 'When calculating age protection rules use the active date instead of the creation date.', 'coust', 'description'),
+    'bool'),
+
 ( 'circ.selfcheck.patron_login_timeout',
     oils_i18n_gettext('circ.selfcheck.patron_login_timeout', 'Selfcheck: Patron Login Timeout (in seconds)', 'coust', 'label'),
     oils_i18n_gettext('circ.selfcheck.patron_login_timeout', 'Number of seconds of inactivity before the patron is logged out of the selfcheck interface', 'coust', 'description'),
index 943fd24..262eaf2 100644 (file)
@@ -82,6 +82,8 @@
                 if (attr == 'opac_visible' && typeof n != 'string')
                     this.setValue(item, 'opac_visible', n ? 't' : 'f');
 
+                if (attr == 'copy_active' && typeof n != 'string')
+                    this.setValue(item, 'copy_active', n ? 't' : 'f');
             };
 
             dojo.addOnUnload( function (event) {
                                                                                                return false;
                                                                                        }
                                                                                  }
+                                                                               },
+                                                                               { name : ccs_strings.COPY_ACTIVE,
+                                                                                 field : "copy_active",
+                                                                                 editor : dojox.grid.editors.bool,
+                                                                                 get : function (row) {
+                                                                                       var r = window.status_data_model.getRow(row);
+                                                                                       if (r) {
+                                                                                               var h = r.copy_active;
+                                                                                               if (h == 't' || h === true) return true;
+                                                                                               return false;
+                                                                                       }
+                                                                                 }
                                                                                }
                                                                        ]
                                                                ]
index 363d21d..c482bb6 100644 (file)
@@ -6,6 +6,7 @@
        "CONFIRM_EXIT_PGT": "There are unsaved modified permission maps. Click OK to save these changes, or Cancel to abandon them.",
        "CONFIRM_EXIT_PPL": "There are unsaved modified permissions. Click OK to save these changes, or Cancel to abandon them.",
        "CONFIRM_UNSAVED_CHANGES": "There are unsaved changes to one or more organization types. Click OK to save these changes, or Cancel to abandon them.",
+       "COPY_ACTIVE": "Sets copy active",
        "ERROR_CALLING_METHOD_AOUT": "Problem calling method to create child organization type",
        "ERROR_CALLING_METHOD_CAM": "Problem calling method to create new ${0}",
        "ERROR_CALLING_METHOD_CCS": "Problem calling method to create new copy status",
index 893059a..67c73b2 100644 (file)
 <!ENTITY staff.browse_list.circulate "Circulate">
 <!ENTITY staff.browse_list.copy_number "Copy Number">
 <!ENTITY staff.browse_list.create_date "Creation Date">
+<!ENTITY staff.browse_list.active_date "Active Date">
 <!ENTITY staff.browse_list.creator "Creator">
 <!ENTITY staff.browse_list.deposit "Deposit">
 <!ENTITY staff.browse_list.deposit_amount "Deposit Amount">
 <!ENTITY staff.cat.copy_summary.created.label "Created:">
 <!ENTITY staff.cat.copy_summary.edited.label "Edited:">
 <!ENTITY staff.cat.copy_summary.age_protect.label "Age Protect:">
+<!ENTITY staff.cat.copy_summary.active_date.label "Active Date:">
 <!ENTITY staff.cat.copy_summary.total_circs.label "Total Circulations:">
 <!ENTITY staff.cat.copy_summary.alternate_view.label "Alternate View">
 <!ENTITY staff.cat.copy_summary.alternate_view.accesskey "">
 <!ENTITY staff.circ.alternate_copy_summary.Copy_Location.label "Copy Location">
 <!ENTITY staff.circ.alternate_copy_summary.Renewal_Type.label "Renewal Type">
 <!ENTITY staff.circ.alternate_copy_summary.Date_Created.label "Date Created">
+<!ENTITY staff.circ.alternate_copy_summary.Date_Active.label "Date Active">
 <!ENTITY staff.circ.alternate_copy_summary.Status_Changed_Time.label "Status Changed">
 <!ENTITY staff.circ.alternate_copy_summary.Due_Date.label "Due Date">
 <!ENTITY staff.circ.alternate_copy_summary.Edition.label "Edition">
index 8203ce4..cac50e0 100644 (file)
@@ -494,6 +494,7 @@ Please see a librarian to renew your account.">
 <!ENTITY rdetail.cn.location "Location">
 <!ENTITY rdetail.cn.hold.age "Age Hold Protection">
 <!ENTITY rdetail.cn.genesis "Create Date">
+<!ENTITY rdetail.cn.active "Active Date">
 <!ENTITY rdetail.cn.holdable "Holdable">
 <!ENTITY rdetail.cn.due "Due Date">
 <!ENTITY rdetail.cn.more "more info...">
index 116f1fb..6dc5120 100644 (file)
@@ -15,6 +15,7 @@
                                                                        <td>&rdetail.cn.location;</td>
                                                                        <td name='age_protect_label' class='hide_me'>&rdetail.cn.hold.age;</td>
                                                                        <td name='create_date_label' class='hide_me'>&rdetail.cn.genesis;</td>
+                                    <td name='active_date_label' class='hide_me'>&rdetail.cn.active;</td>
                                                                        <td name='holdable_label' class='hide_me'>&rdetail.cn.holdable;</td>
                                                                        <td name='due_date_label' class='hide_me'>&rdetail.cn.due;</td>
                                                                </tr>
@@ -33,6 +34,7 @@
                                                                        <td name='location'> </td>
                                                                        <td name='age_protect_value' class='hide_me'>&rdetail.cn.disabled;</td>
                                                                        <td name='create_date_value' class='hide_me'> </td>
+                                    <td name='active_date_value' class='hide_me'> </td>
        
                                                                        <td name='copy_holdable_td' class='hide_me'>
                                                                                <span name='copy_is_holdable'> </span>
index c4c623a..253e671 100644 (file)
@@ -31,6 +31,7 @@ function cpdBuild( contextTbody, contextRow, record, callnumber, orgid, depth, c
                /* unhide before we unhide/clone the parent */
                unHideMe($n(templateRow, 'age_protect_label'));
                unHideMe($n(templateRow, 'create_date_label'));
+        unHideMe($n(templateRow, 'active_date_label'));
                unHideMe($n(templateRow, 'holdable_label'));
        }
 
@@ -205,6 +206,7 @@ function cpdDrawCopies(r) {
                /* unhide before we unhide/clone the parent */
                unHideMe($n(copyrow, 'age_protect_value'));
                unHideMe($n(copyrow, 'create_date_value'));
+        unHideMe($n(copyrow, 'active_date_value'));
                unHideMe($n(copyrow, 'copy_holdable_td'));
        }
 
@@ -343,6 +345,12 @@ function cpdDrawCopy(r) {
                cd = cd.replace(/T.*/, '');
                $n(row, 'create_date_value').appendChild(text(cd));
 
+        var ad = copy.active_date();
+        if(ad) {
+            ad = ad.replace(/T.*/, '');
+            $n(row, 'active_date_value').appendChild(text(ad));
+        }
+
                var yes = $('rdetail.yes').innerHTML;
                var no = $('rdetail.no').innerHTML;
 
index f937089..d443b9f 100644 (file)
@@ -16,6 +16,7 @@
                                                                <td name='copy_part_label' class='hide_me'>&rdetail.cn.part;</td>
                                                                <td name='age_protect_label' class='hide_me'>&rdetail.cn.hold.age;</td>
                                                                <td name='create_date_label' class='hide_me'>&rdetail.cn.genesis;</td>
+                                <td name='active_date_label' class='hide_me'>&rdetail.cn.active;</td>
                                                                <td name='holdable_label' class='hide_me'>&rdetail.cn.holdable;</td>
                                                                <td name='due_date_label' class='hide_me'>&rdetail.cn.due;</td>
                                                        </tr>
@@ -41,6 +42,7 @@
                                                                <td name='copy_part' class='hide_me'> </td>
                                                                <td name='age_protect_value' class='hide_me'>&rdetail.cn.disabled;</td>
                                                                <td name='create_date_value' class='hide_me'> </td>
+                                <td name='active_date_value' class='hide_me'> </td>
 
                                                                <td name='copy_holdable_td' class='hide_me'>
                                                                        <span name='copy_is_holdable'> </span>
index bd19e7e..e3725a2 100644 (file)
@@ -9,7 +9,7 @@
     <table  jsId="cmGrid"
             style="height: 600px;"
             dojoType="openils.widget.AutoGrid"
-            fieldOrder="['id', 'active', 'grp', 'org_unit', 'copy_circ_lib', 'copy_owning_lib', 'user_home_ou', 'is_renewal', 'juvenile_flag', 'circ_modifier', 'marc_type', 'marc_form', 'marc_bib_level', 'marc_vr_format', 'ref_flag', 'usr_age_lower_bound', 'usr_age_upper_bound', 'circulate', 'duration_rule', 'renewals', 'hard_due_date', 'recurring_fine_rule', 'grace_period', 'max_fine_rule', 'available_copy_hold_ratio', 'total_copy_hold_ratio', 'script_test']"
+            fieldOrder="['id', 'active', 'grp', 'org_unit', 'copy_circ_lib', 'copy_owning_lib', 'user_home_ou', 'is_renewal', 'juvenile_flag', 'circ_modifier', 'marc_type', 'marc_form', 'marc_bib_level', 'marc_vr_format', 'ref_flag', 'usr_age_lower_bound', 'usr_age_upper_bound', 'item_age', 'circulate', 'duration_rule', 'renewals', 'hard_due_date', 'recurring_fine_rule', 'grace_period', 'max_fine_rule', 'available_copy_hold_ratio', 'total_copy_hold_ratio', 'script_test']"
             defaultCellWidth='"auto"'
             query="{id: '*'}"
             fmClass='ccmm'
index 5512b36..3991283 100644 (file)
@@ -866,6 +866,12 @@ g.panes_and_field_names = {
         }
     ],
     [
+        $('catStrings').getString('staff.cat.copy_editor.field.active_date.label'),
+        { 
+            render: 'util.date.formatted_date( fm.active_date(), "%F");',
+        }
+    ],
+    [
         $('catStrings').getString('staff.cat.copy_editor.field.creator.label'),
         { 
             render: 'fm.creator();',
index bfb015c..af6d1c0 100644 (file)
@@ -135,6 +135,7 @@ function load_item() {
         set("floating", '');
         set("copy_number", '');
         set("copy_create_date", '');
+        set("copy_active_date", '');
         set("status_changed_time", '');
         set("copy_creator", '');
         set("deleted", '');
@@ -197,6 +198,7 @@ function load_item() {
             set("floating", get_localized_bool( details.copy.floating() )); 
             set("copy_number", details.copy.copy_number()); 
             set("copy_create_date", util.date.formatted_date( details.copy.create_date(), '%{localized}' )); 
+            set("copy_active_date", util.date.formatted_date( details.copy.active_date(), '%{localized}' ));
             set("status_changed_time", util.date.formatted_date( details.copy.status_changed_time(), '%{localized}' )); 
             set("copy_creator", details.copy.creator()); 
             set("deleted", details.copy.deleted()); 
index 2b21d65..2091b43 100644 (file)
                                 <textbox name="checkout_workstation" readonly="true" context="clipboard"/>
                             </row>
                             <row>
-                                <label value="&staff.circ.alternate_copy_summary.Status_Changed_Time.label;" />
-                                <textbox name="status_changed_time" readonly="true" context="clipboard"/>
+                                <label value="&staff.circ.alternate_copy_summary.Date_Active.label;" />
+                                <textbox name="copy_active_date" readonly="true" context="clipboard"/>
                                 <label value="&staff.circ.alternate_copy_summary.Fine_Level.label;" />
                                 <textbox name="fine_level" readonly="true" context="clipboard"/>
                                 <label value="&staff.circ.alternate_copy_summary.Total_Circs___Prev_Year.label;" />
                                 <textbox name="duration_rule" readonly="true" context="clipboard"/>
                             </row>
                             <row>
-                                <label value="&staff.circ.alternate_copy_summary.Copy_ID.label;" />
-                                <textbox name="copy_id" readonly="true" context="clipboard"/>
+                                <label value="&staff.circ.alternate_copy_summary.Status_Changed_Time.label;" />
+                                <textbox name="status_changed_time" readonly="true" context="clipboard"/>
                                 <label value="&staff.circ.alternate_copy_summary.Reference.label;" />
                                 <textbox name="ref" readonly="true" context="clipboard"/>
                                 <!--
                                 <textbox name="recurring_fine_rule" readonly="true" context="clipboard"/>
                             </row>
                             <row>
-                                <label value="&staff.circ.alternate_copy_summary.TCN.label;" />
-                                <textbox name="tcn" readonly="true" context="clipboard"/>
+                                <label value="&staff.circ.alternate_copy_summary.Copy_ID.label;" />
+                                <textbox name="copy_id" readonly="true" context="clipboard"/>
                                 <label value="&staff.circ.alternate_copy_summary.OPAC_Visible.label;" />
                                 <textbox name="opac_visible" readonly="true" context="clipboard"/>
                                 <label value="&staff.circ.alternate_copy_summary.Remaining_Renewals.label;" />
                                 <textbox name="max_fine_rule" readonly="true" context="clipboard"/>
                             </row>
                             <row>
-                                <label value="&staff.circ.alternate_copy_summary.Floating.label;" />
-                                <textbox name="floating" readonly="true" context="clipboard"/>
+                                <label value="&staff.circ.alternate_copy_summary.TCN.label;" />
+                                <textbox name="tcn" readonly="true" context="clipboard"/>
                                 <label value="&staff.circ.alternate_copy_summary.Holdable.label;" />
                                 <textbox name="holdable" readonly="true" context="clipboard"/>
                                 <spacer /><spacer />
                                 <textbox name="checkin_time" readonly="true" context="clipboard"/>
                             </row>
                             <row>
-                                <spacer /><spacer />
+                                <label value="&staff.circ.alternate_copy_summary.Floating.label;" />
+                                <textbox name="floating" readonly="true" context="clipboard"/>
                                 <label value="&staff.circ.alternate_copy_summary.Circulate.label;" />
                                 <textbox name="circulate" readonly="true" context="clipboard"/>
                                 <!--
index b2d4373..0287758 100644 (file)
@@ -166,6 +166,7 @@ staff.cat.copy_editor.field.creator.label=Creator
 staff.cat.copy_editor.field.last_editor.label=Last Editor
 staff.cat.copy_editor.field.barcode.label=Barcode
 staff.cat.copy_editor.field.creation_date.label=Creation Date
+staff.cat.copy_editor.field.active_date.label=Active Date
 staff.cat.copy_editor.field.last_edit_date.label=Last Edit Date
 staff.cat.copy_editor.field.location.label=Location/Collection
 staff.cat.copy_editor.field.circulation_library.label=Circulation Library