age-circs.sql: bugfixes
[sitka/sitka-tools.git] / maintenance / age-circs.sql
index a5b5353..b31a4d4 100644 (file)
 
 BEGIN;
 
+\echo 'utility function for testing interval'
+CREATE OR REPLACE FUNCTION sitka.is_valid_interval(TEXT) RETURNS BOOL AS $$
+BEGIN
+  RETURN CASE WHEN $1::INTERVAL IS NULL THEN FALSE ELSE TRUE END;
+EXCEPTION WHEN OTHERS THEN
+  RETURN FALSE;
+END;
+$$ LANGUAGE plpgsql;
+
 \echo 'exception matrix table'
 CREATE TABLE sitka.age_circ_exception_matrix (
   id SERIAL NOT NULL,
@@ -71,9 +80,9 @@ CREATE OR REPLACE FUNCTION sitka.age_circs(cutoff DATE, max_circ_count BIGINT) R
 DECLARE
   today                DATE;
   potential_aged_circ  action.circulation%ROWTYPE;
-  circ_chain_tail      action.circulation%ROWTYPE;
-  usr_keep_start       actor.usr_setting%ROWTYPE;
-  usr_keep_age         actor.usr_setting%ROWTYPE;
+  circ_chain_finish    TIMESTAMP WITH TIME ZONE;
+  usr_keep_start       TEXT;
+  usr_keep_age         TEXT;
   circ_cutoff          DATE;
   has_exception        BOOL;
   circs_aged           INT;
@@ -82,7 +91,8 @@ BEGIN
 
   -- TODO: more strictness here?
   CREATE TEMPORARY TABLE circs_to_age AS
-    SELECT c.id FROM action.circulation c
+    SELECT c.id, NULL::TIMESTAMP WITH TIME ZONE AS circ_chain_tail_xact_finish
+    FROM action.circulation c
     JOIN money.materialized_billable_xact_summary m ON c.id = m.id
     WHERE c.xact_finish IS NOT NULL AND c.xact_finish < cutoff
     AND m.balance_owed = 0
@@ -95,22 +105,34 @@ BEGIN
     JOIN action.circulation b ON a.id = b.id
   LOOP
 
+    -- reset variables
+    circ_chain_finish := NULL;
+    usr_keep_start    := NULL;
+    usr_keep_age      := NULL;
+
     -- use the cutoff param as the default cutoff date for the current circ
     circ_cutoff := cutoff;
 
     -- renewals create a "chain" of circs; find the last circ in the current chain
-    SELECT * INTO circ_chain_tail FROM action.circ_chain(potential_aged_circ.id) ORDER BY xact_start DESC LIMIT 1;
+    SELECT MAX(xact_finish) INTO circ_chain_finish FROM action.circ_chain(potential_aged_circ.id);
+    UPDATE circs_to_age SET circ_chain_tail_xact_finish = circ_chain_finish WHERE id = potential_aged_circ.id;
 
     -- user's history.circ.retention_start setting, if any, overrides default cutoff date
-    -- (we are ignoring history.circ.retention_age which does not appear to be in use)
-    usr_keep_start.value := NULL;
-    SELECT * INTO usr_keep_start FROM actor.usr_setting WHERE usr = potential_aged_circ.usr AND name = 'history.circ.retention_start';
-    IF usr_keep_start.value IS NOT NULL THEN
-      circ_cutoff := oils_json_to_text(usr_keep_start.value)::DATE;
+    SELECT value INTO usr_keep_start FROM actor.usr_setting WHERE usr = potential_aged_circ.usr AND name = 'history.circ.retention_start';
+    IF usr_keep_start IS NOT NULL THEN
+        circ_cutoff := oils_json_to_text(usr_keep_start)::DATE;
+    END IF;
+
+    -- trim cutoff to user's history.circ.retention_age, if set
+    SELECT oils_json_to_text(value) INTO usr_keep_age FROM actor.usr_setting WHERE usr = potential_aged_circ.usr AND name = 'history.circ.retention_age';
+    IF usr_keep_age IS NOT NULL AND sitka.is_valid_interval(usr_keep_age) IS TRUE THEN
+        IF (now() - usr_keep_age::INTERVAL)::DATE > circ_cutoff THEN
+        circ_cutoff := (now() - oils_json_to_text(usr_keep_age)::INTERVAL)::DATE;
+        END IF;
     END IF;
 
     -- don't age the chain if the last circ is later than the cutoff
-    IF circ_chain_tail.xact_finish IS NULL OR circ_chain_tail.xact_finish > circ_cutoff THEN
+    IF circ_chain_finish IS NULL OR circ_chain_finish > circ_cutoff THEN
       DELETE FROM circs_to_age WHERE id IN (SELECT id FROM action.circ_chain(potential_aged_circ.id));
       CONTINUE; -- proceed to next potential_aged_circ
     END IF;
@@ -126,10 +148,6 @@ BEGIN
 
   END LOOP;
 
-  -- log the aging of this circ
-  INSERT INTO sitka.aged_circs (id, circ_chain_tail_xact_finish, delete_date)
-    SELECT id, circ_chain_tail.xact_finish, today FROM circs_to_age;
-
   -- update user circ counts
   CREATE TEMPORARY TABLE usr_circ_totals AS
     SELECT a.usr, (EXTRACT(month FROM a.xact_start)) AS month,
@@ -157,11 +175,13 @@ BEGIN
   SET usr_post_code = NULL, usr_birth_year = NULL
   WHERE usr_post_code IS NOT NULL OR usr_birth_year IS NOT NULL;
 
+  INSERT INTO sitka.aged_circs (id, circ_chain_tail_xact_finish, delete_date)
+    SELECT id, circ_chain_tail_xact_finish, today FROM circs_to_age;
+
   SELECT count(*) INTO circs_aged FROM circs_to_age;
   DROP TABLE circs_to_age;
   RETURN circs_aged;
-END;
-$$ LANGUAGE plpgsql;
+END; $$ LANGUAGE plpgsql;
 
 SAVEPOINT ready;