action.circulation
|
Data-Modifying Triggers: This table has BEFORE ROW trigger(s) that modify row data before write. Values you INSERT or UPDATE may differ from what is actually stored. See the Triggers section below. |
|
Deferrable Constraints: The following FK constraints are deferrable — they are checked at transaction end, not statement end: |
|
Trigger Side Effects: Writing to this table automatically triggers writes to other tables:
|
Columns
| Column | Type | Nullable | Default | Notes |
|---|---|---|---|---|
id PK |
|
No |
nextval('money.billable_xact_id_seq'::regclass) |
|
usr FK |
|
No |
||
xact_start |
|
No |
now() |
|
xact_finish |
|
Yes |
||
unrecovered |
|
Yes |
||
target_copy |
|
No |
||
circ_lib FK |
|
No |
||
circ_staff |
|
No |
||
checkin_staff |
|
Yes |
||
checkin_lib |
|
Yes |
||
renewal_remaining |
|
No |
||
grace_period |
|
No |
||
due_date |
|
Yes |
||
stop_fines_time |
|
Yes |
||
checkin_time |
|
Yes |
||
create_time |
|
No |
now() |
|
duration |
|
Yes |
||
fine_interval |
|
No |
'1 day'::interval |
|
recurring_fine |
|
Yes |
||
max_fine |
|
Yes |
||
phone_renewal |
|
No |
false |
|
desk_renewal |
|
No |
false |
|
opac_renewal |
|
No |
false |
|
duration_rule |
|
No |
||
recurring_fine_rule |
|
No |
||
max_fine_rule |
|
No |
||
stop_fines |
|
Yes |
||
workstation FK |
|
Yes |
||
checkin_workstation FK |
|
Yes |
||
copy_location FK |
|
No |
1 |
|
checkin_scan_time |
|
Yes |
||
auto_renewal |
|
No |
false |
|
auto_renewal_remaining |
|
Yes |
||
parent_circ FK |
|
Yes |
Foreign Keys
| Column(s) | References | On Delete | On Update | Deferrable | Constraint |
|---|---|---|---|---|---|
|
SET NULL |
NO ACTION |
DEFERRED |
|
|
|
NO ACTION |
NO ACTION |
DEFERRED |
|
|
|
SET NULL |
NO ACTION |
DEFERRED |
|
|
|
NO ACTION |
NO ACTION |
DEFERRED |
|
|
|
NO ACTION |
NO ACTION |
DEFERRED |
|
|
|
SET NULL |
NO ACTION |
DEFERRED |
|
Check Constraints
-
circulation_stop_fines_check:CHECK stop_fines = ANY (ARRAY['CHECKIN'::text, 'CLAIMSRETURNED'::text, 'LOST'::text, 'MAXFINES'::text, 'RENEW'::text, 'LONGOVERDUE'::text, 'CLAIMSNEVERCHECKEDOUT'::text])
Indexes
| Index | Method | Definition |
|---|---|---|
|
btree |
|
|
btree |
|
|
btree |
|
|
btree |
|
|
btree |
|
|
btree |
|
|
btree |
|
|
btree |
|
|
btree |
|
|
btree |
|
|
btree |
|
|
btree |
|
Triggers
| Trigger | Timing | Event | Level | Function |
|---|---|---|---|---|
|
BEFORE |
DELETE |
ROW |
|
|
BEFORE |
UPDATE |
ROW |
|
|
AFTER |
INSERT OR UPDATE |
ROW |
|
|
AFTER |
DELETE |
ROW |
|
|
AFTER |
INSERT |
ROW |
|
|
BEFORE |
INSERT |
ROW |
|
|
AFTER |
INSERT OR UPDATE |
ROW |
|
|
AFTER |
UPDATE |
ROW |
|
|
AFTER |
INSERT |
ROW |
|
|
AFTER |
DELETE |
ROW |
|
|
BEFORE |
INSERT OR UPDATE |
ROW |
Trigger Bodies
action_circulation_aging_tgr
Function: action.age_circ_on_delete()
Timing: BEFORE DELETE ROW
DECLARE
found char := 'N';
BEGIN
-- If there are any renewals for this circulation, don't archive or delete
-- it yet. We'll do so later, when we archive and delete the renewals.
SELECT 'Y' INTO found
FROM action.circulation
WHERE parent_circ = OLD.id
LIMIT 1;
IF found = 'Y' THEN
RETURN NULL; -- don't delete
END IF;
-- Archive a copy of the old row to action.aged_circulation
INSERT INTO action.aged_circulation
(id,usr_post_code, usr_home_ou, usr_profile, usr_birth_year, copy_call_number, copy_location,
copy_owning_lib, copy_circ_lib, copy_bib_record, xact_start, xact_finish, target_copy,
circ_lib, circ_staff, checkin_staff, checkin_lib, renewal_remaining, grace_period, due_date,
stop_fines_time, checkin_time, create_time, duration, fine_interval, recurring_fine,
max_fine, phone_renewal, desk_renewal, opac_renewal, duration_rule, recurring_fine_rule,
max_fine_rule, stop_fines, workstation, checkin_workstation, checkin_scan_time, parent_circ,
auto_renewal, auto_renewal_remaining)
SELECT
id,usr_post_code, usr_home_ou, usr_profile, usr_birth_year, copy_call_number, copy_location,
copy_owning_lib, copy_circ_lib, copy_bib_record, xact_start, xact_finish, target_copy,
circ_lib, circ_staff, checkin_staff, checkin_lib, renewal_remaining, grace_period, due_date,
stop_fines_time, checkin_time, create_time, duration, fine_interval, recurring_fine,
max_fine, phone_renewal, desk_renewal, opac_renewal, duration_rule, recurring_fine_rule,
max_fine_rule, stop_fines, workstation, checkin_workstation, checkin_scan_time, parent_circ,
auto_renewal, auto_renewal_remaining
FROM action.all_circulation WHERE id = OLD.id;
-- Migrate billings and payments to aged tables
SELECT 'Y' INTO found FROM config.global_flag
WHERE name = 'history.money.age_with_circs' AND enabled;
IF found = 'Y' THEN
PERFORM money.age_billings_and_payments_for_xact(OLD.id);
END IF;
-- Break the link with the user in action_trigger.event (warning: event_output may essentially have this information)
UPDATE
action_trigger.event e
SET
context_user = NULL
FROM
action.all_circulation c
WHERE
c.id = OLD.id
AND e.context_user = c.usr
AND e.target = c.id
AND e.event_def IN (
SELECT id
FROM action_trigger.event_definition
WHERE hook in (SELECT key FROM action_trigger.hook WHERE core_type = 'circ')
)
;
RETURN OLD;
END;
action_circulation_stop_fines_tgr
Function: action.circulation_claims_returned()
Timing: BEFORE UPDATE ROW
|
This trigger modifies the row before it is written (returns a modified |
BEGIN
IF OLD.stop_fines IS NULL OR OLD.stop_fines <> NEW.stop_fines THEN
IF NEW.stop_fines = 'CLAIMSRETURNED' THEN
UPDATE actor.usr SET claims_returned_count = claims_returned_count + 1 WHERE id = NEW.usr;
END IF;
IF NEW.stop_fines = 'CLAIMSNEVERCHECKEDOUT' THEN
UPDATE actor.usr SET claims_never_checked_out_count = claims_never_checked_out_count + 1 WHERE id = NEW.usr;
END IF;
IF NEW.stop_fines = 'LOST' THEN
UPDATE asset.copy SET status = 3 WHERE id = NEW.target_copy;
END IF;
END IF;
RETURN NEW;
END;
action_circulation_target_copy_trig
Function: evergreen.fake_fkey_tgr()
Timing: AFTER INSERT OR UPDATE ROW
DECLARE
copy_id BIGINT;
BEGIN
EXECUTE 'SELECT ($1).' || quote_ident(TG_ARGV[0]) INTO copy_id USING NEW;
IF copy_id IS NOT NULL THEN
PERFORM * FROM asset.copy WHERE id = copy_id;
IF NOT FOUND THEN
RAISE EXCEPTION 'Key (%.%=%) does not exist in asset.copy', TG_TABLE_SCHEMA, TG_TABLE_NAME, copy_id;
END IF;
END IF;
RETURN NULL;
END;
age_parent_circ
Function: action.age_parent_circ_on_delete()
Timing: AFTER DELETE ROW
BEGIN
-- Having deleted a renewal, we can delete the original circulation (or a previous
-- renewal, if that's what parent_circ is pointing to). That deletion will trigger
-- deletion of any prior parents, etc. recursively.
IF OLD.parent_circ IS NOT NULL THEN
DELETE FROM action.circulation
WHERE id = OLD.parent_circ;
END IF;
RETURN OLD;
END;
archive_stat_cats_tgr
Function: action.archive_stat_cats()
Timing: AFTER INSERT ROW
BEGIN
INSERT INTO action.archive_actor_stat_cat(xact, stat_cat, value)
SELECT NEW.id, asceum.stat_cat, asceum.stat_cat_entry
FROM actor.stat_cat_entry_usr_map asceum
JOIN actor.stat_cat sc ON asceum.stat_cat = sc.id
WHERE NEW.usr = asceum.target_usr AND sc.checkout_archive;
INSERT INTO action.archive_asset_stat_cat(xact, stat_cat, value)
SELECT NEW.id, ascecm.stat_cat, asce.value
FROM asset.stat_cat_entry_copy_map ascecm
JOIN asset.stat_cat sc ON ascecm.stat_cat = sc.id
JOIN asset.stat_cat_entry asce ON ascecm.stat_cat_entry = asce.id
WHERE NEW.target_copy = ascecm.owning_copy AND sc.checkout_archive;
RETURN NULL;
END;
fill_circ_copy_location_tgr
Function: action.fill_circ_copy_location()
Timing: BEFORE INSERT ROW
|
This trigger modifies the row before it is written (returns a modified |
BEGIN
SELECT INTO NEW.copy_location location FROM asset.copy WHERE id = NEW.target_copy;
RETURN NEW;
END;
maintain_usr_circ_history_tgr
Function: action.maintain_usr_circ_history()
Timing: AFTER INSERT OR UPDATE ROW
DECLARE
cur_circ BIGINT;
first_circ BIGINT;
BEGIN
-- Any retention value signifies history is enabled.
-- This assumes that clearing these values via external
-- process deletes the action.usr_circ_history rows.
-- TODO: replace these settings w/ a single bool setting?
PERFORM 1 FROM actor.usr_setting
WHERE usr = NEW.usr AND value IS NOT NULL AND name IN (
'history.circ.retention_age',
'history.circ.retention_start'
);
IF NOT FOUND THEN
RETURN NEW;
END IF;
IF TG_OP = 'INSERT' AND NEW.parent_circ IS NULL THEN
-- Starting a new circulation. Insert the history row.
INSERT INTO action.usr_circ_history
(usr, xact_start, target_copy, due_date, source_circ)
VALUES (
NEW.usr,
NEW.xact_start,
NEW.target_copy,
NEW.due_date,
NEW.id
);
RETURN NEW;
END IF;
-- find the first and last circs in the circ chain
-- for the currently modified circ.
FOR cur_circ IN SELECT id FROM action.circ_chain(NEW.id) LOOP
IF first_circ IS NULL THEN
first_circ := cur_circ;
CONTINUE;
END IF;
-- Allow the loop to continue so that at as the loop
-- completes cur_circ points to the final circulation.
END LOOP;
IF NEW.id <> cur_circ THEN
-- Modifying an intermediate circ. Ignore it.
RETURN NEW;
END IF;
-- Update the due_date/checkin_time on the history row if the current
-- circ is the last circ in the chain and an update is warranted.
UPDATE action.usr_circ_history
SET
due_date = NEW.due_date,
checkin_time = NEW.checkin_time
WHERE
source_circ = first_circ
AND (
due_date <> NEW.due_date OR (
(checkin_time IS NULL AND NEW.checkin_time IS NOT NULL) OR
(checkin_time IS NOT NULL AND NEW.checkin_time IS NULL) OR
(checkin_time <> NEW.checkin_time)
)
);
RETURN NEW;
END;
mat_summary_change_tgr
Function: money.mat_summary_update()
Timing: AFTER UPDATE ROW
BEGIN
UPDATE money.materialized_billable_xact_summary
SET usr = NEW.usr,
xact_start = NEW.xact_start,
xact_finish = NEW.xact_finish
WHERE id = NEW.id;
RETURN NEW;
END;
mat_summary_create_tgr
Function: money.mat_summary_create()
Timing: AFTER INSERT ROW
BEGIN
INSERT INTO money.materialized_billable_xact_summary (id, usr, xact_start, xact_finish, total_paid, total_owed, balance_owed, xact_type)
VALUES ( NEW.id, NEW.usr, NEW.xact_start, NEW.xact_finish, 0.0, 0.0, 0.0, TG_ARGV[0]);
RETURN NEW;
END;
mat_summary_remove_tgr
Function: money.mat_summary_delete()
Timing: AFTER DELETE ROW
BEGIN
DELETE FROM money.materialized_billable_xact_summary WHERE id = OLD.id;
RETURN OLD;
END;
push_due_date_tgr
Function: action.push_circ_due_time()
Timing: BEFORE INSERT OR UPDATE ROW
|
This trigger modifies the row before it is written (returns a modified |
DECLARE
proper_tz TEXT := COALESCE(
oils_json_to_text((
SELECT value
FROM actor.org_unit_ancestor_setting('lib.timezone',NEW.circ_lib)
LIMIT 1
)),
CURRENT_SETTING('timezone')
);
BEGIN
IF (EXTRACT(EPOCH FROM NEW.duration)::INT % EXTRACT(EPOCH FROM '1 day'::INTERVAL)::INT) = 0 -- day-granular duration
AND SUBSTRING((NEW.due_date AT TIME ZONE proper_tz)::TIME::TEXT FROM 1 FOR 8) <> '23:59:59' THEN -- has not yet been pushed
NEW.due_date = ((NEW.due_date AT TIME ZONE proper_tz)::DATE + '1 day'::INTERVAL - '1 second'::INTERVAL) || ' ' || proper_tz;
END IF;
RETURN NEW;
END;
Referenced By
The following tables have foreign keys pointing to action.circulation (4 referencing table(s)):
| Table | Referencing Column(s) | Referenced Column(s) | Constraint |
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|