]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/sql/Pg/090.schema.action.sql
1. Add new column parent_circ to action.circulation, to connect
[Evergreen.git] / Open-ILS / src / sql / Pg / 090.schema.action.sql
1 /*
2  * Copyright (C) 2004-2008  Georgia Public Library Service
3  * Copyright (C) 2007-2008  Equinox Software, Inc.
4  * Mike Rylander <miker@esilibrary.com> 
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  */
17
18 DROP SCHEMA action CASCADE;
19
20 BEGIN;
21
22 CREATE SCHEMA action;
23
24 CREATE TABLE action.in_house_use (
25         id              SERIAL                          PRIMARY KEY,
26         item            BIGINT                          NOT NULL REFERENCES asset.copy (id) DEFERRABLE INITIALLY DEFERRED,
27         staff           INT                             NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
28         org_unit        INT                             NOT NULL REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED,
29         use_time        TIMESTAMP WITH TIME ZONE        NOT NULL DEFAULT NOW()
30 );
31 CREATE INDEX action_in_house_use_staff_idx      ON action.in_house_use ( staff );
32
33 CREATE TABLE action.non_cataloged_circulation (
34         id              SERIAL                          PRIMARY KEY,
35         patron          INT                             NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
36         staff           INT                             NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
37         circ_lib        INT                             NOT NULL REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED,
38         item_type       INT                             NOT NULL REFERENCES config.non_cataloged_type (id) DEFERRABLE INITIALLY DEFERRED,
39         circ_time       TIMESTAMP WITH TIME ZONE        NOT NULL DEFAULT NOW()
40 );
41 CREATE INDEX action_non_cat_circ_patron_idx ON action.non_cataloged_circulation ( patron );
42 CREATE INDEX action_non_cat_circ_staff_idx  ON action.non_cataloged_circulation ( staff );
43
44 CREATE TABLE action.non_cat_in_house_use (
45         id              SERIAL                          PRIMARY KEY,
46         item_type       BIGINT                          NOT NULL REFERENCES config.non_cataloged_type(id) DEFERRABLE INITIALLY DEFERRED,
47         staff           INT                             NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
48         org_unit        INT                             NOT NULL REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED,
49         use_time        TIMESTAMP WITH TIME ZONE        NOT NULL DEFAULT NOW()
50 );
51 CREATE INDEX non_cat_in_house_use_staff_idx ON action.non_cat_in_house_use ( staff );
52
53 CREATE TABLE action.survey (
54         id              SERIAL                          PRIMARY KEY,
55         owner           INT                             NOT NULL REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED,
56         start_date      TIMESTAMP WITH TIME ZONE        NOT NULL DEFAULT NOW(),
57         end_date        TIMESTAMP WITH TIME ZONE        NOT NULL DEFAULT NOW() + '10 years'::INTERVAL,
58         usr_summary     BOOL                            NOT NULL DEFAULT FALSE,
59         opac            BOOL                            NOT NULL DEFAULT FALSE,
60         poll            BOOL                            NOT NULL DEFAULT FALSE,
61         required        BOOL                            NOT NULL DEFAULT FALSE,
62         name            TEXT                            NOT NULL,
63         description     TEXT                            NOT NULL
64 );
65 CREATE UNIQUE INDEX asv_once_per_owner_idx ON action.survey (owner,name);
66
67 CREATE TABLE action.survey_question (
68         id              SERIAL  PRIMARY KEY,
69         survey          INT     NOT NULL REFERENCES action.survey DEFERRABLE INITIALLY DEFERRED,
70         question        TEXT    NOT NULL
71 );
72
73 CREATE TABLE action.survey_answer (
74         id              SERIAL  PRIMARY KEY,
75         question        INT     NOT NULL REFERENCES action.survey_question DEFERRABLE INITIALLY DEFERRED,
76         answer          TEXT    NOT NULL
77 );
78
79 CREATE SEQUENCE action.survey_response_group_id_seq;
80
81 CREATE TABLE action.survey_response (
82         id                      BIGSERIAL                       PRIMARY KEY,
83         response_group_id       INT,
84         usr                     INT, -- REFERENCES actor.usr
85         survey                  INT                             NOT NULL REFERENCES action.survey DEFERRABLE INITIALLY DEFERRED,
86         question                INT                             NOT NULL REFERENCES action.survey_question DEFERRABLE INITIALLY DEFERRED,
87         answer                  INT                             NOT NULL REFERENCES action.survey_answer DEFERRABLE INITIALLY DEFERRED,
88         answer_date             TIMESTAMP WITH TIME ZONE,
89         effective_date          TIMESTAMP WITH TIME ZONE        NOT NULL DEFAULT NOW()
90 );
91 CREATE INDEX action_survey_response_usr_idx ON action.survey_response ( usr );
92
93 CREATE OR REPLACE FUNCTION action.survey_response_answer_date_fixup () RETURNS TRIGGER AS '
94 BEGIN
95         NEW.answer_date := NOW();
96         RETURN NEW;
97 END;
98 ' LANGUAGE 'plpgsql';
99 CREATE TRIGGER action_survey_response_answer_date_fixup_tgr
100         BEFORE INSERT ON action.survey_response
101         FOR EACH ROW
102         EXECUTE PROCEDURE action.survey_response_answer_date_fixup ();
103
104
105 CREATE TABLE action.circulation (
106         target_copy             BIGINT                          NOT NULL, -- asset.copy.id
107         circ_lib                INT                             NOT NULL, -- actor.org_unit.id
108         circ_staff              INT                             NOT NULL, -- actor.usr.id
109         checkin_staff           INT,                                      -- actor.usr.id
110         checkin_lib             INT,                                      -- actor.org_unit.id
111         renewal_remaining       INT                             NOT NULL, -- derived from "circ duration" rule
112         due_date                TIMESTAMP WITH TIME ZONE,
113         stop_fines_time         TIMESTAMP WITH TIME ZONE,
114         checkin_time            TIMESTAMP WITH TIME ZONE,
115         create_time             TIMESTAMP WITH TIME ZONE    NOT NULL DEFAULT NOW(),
116         duration                INTERVAL,                                 -- derived from "circ duration" rule
117         fine_interval           INTERVAL                        NOT NULL DEFAULT '1 day'::INTERVAL, -- derived from "circ fine" rule
118         recuring_fine           NUMERIC(6,2),                             -- derived from "circ fine" rule
119         max_fine                NUMERIC(6,2),                             -- derived from "max fine" rule
120         phone_renewal           BOOL                            NOT NULL DEFAULT FALSE,
121         desk_renewal            BOOL                            NOT NULL DEFAULT FALSE,
122         opac_renewal            BOOL                            NOT NULL DEFAULT FALSE,
123         duration_rule           TEXT                            NOT NULL, -- name of "circ duration" rule
124         recuring_fine_rule      TEXT                            NOT NULL, -- name of "circ fine" rule
125         max_fine_rule           TEXT                            NOT NULL, -- name of "max fine" rule
126         stop_fines              TEXT                            CHECK (stop_fines IN ('CHECKIN','CLAIMSRETURNED','LOST','MAXFINES','RENEW','LONGOVERDUE')),
127         workstation         INT        REFERENCES actor.workstation(id)
128                                        ON DELETE SET NULL
129                                                                    DEFERRABLE INITIALLY DEFERRED,
130         checkin_workstation INT        REFERENCES actor.workstation(id)
131                                        ON DELETE SET NULL
132                                                                    DEFERRABLE INITIALLY DEFERRED,
133         checkin_scan_time   TIMESTAMP WITH TIME ZONE
134 ) INHERITS (money.billable_xact);
135 ALTER TABLE action.circulation ADD PRIMARY KEY (id);
136 ALTER TABLE action.circulation
137         ADD COLUMN parent_circ BIGINT
138         REFERENCES action.circulation( id )
139         DEFERRABLE INITIALLY DEFERRED;
140 CREATE INDEX circ_open_xacts_idx ON action.circulation (usr) WHERE xact_finish IS NULL;
141 CREATE INDEX circ_outstanding_idx ON action.circulation (usr) WHERE checkin_time IS NULL;
142 CREATE INDEX circ_checkin_time ON "action".circulation (checkin_time) WHERE checkin_time IS NOT NULL;
143 CREATE INDEX circ_circ_lib_idx ON "action".circulation (circ_lib);
144 CREATE INDEX circ_open_date_idx ON "action".circulation (xact_start) WHERE xact_finish IS NULL;
145 CREATE INDEX circ_all_usr_idx       ON action.circulation ( usr );
146 CREATE INDEX circ_circ_staff_idx    ON action.circulation ( circ_staff );
147 CREATE INDEX circ_checkin_staff_idx ON action.circulation ( checkin_staff );
148 CREATE UNIQUE INDEX circ_parent_idx ON action.circulation ( parent_circ ) WHERE parent_circ IS NOT NULL;
149
150
151 CREATE TRIGGER mat_summary_create_tgr AFTER INSERT ON action.circulation FOR EACH ROW EXECUTE PROCEDURE money.mat_summary_create ();
152 CREATE TRIGGER mat_summary_change_tgr AFTER UPDATE ON action.circulation FOR EACH ROW EXECUTE PROCEDURE money.mat_summary_update ();
153 CREATE TRIGGER mat_summary_remove_tgr AFTER DELETE ON action.circulation FOR EACH ROW EXECUTE PROCEDURE money.mat_summary_delete ();
154
155
156 CREATE TABLE action.aged_circulation (
157         usr_post_code           TEXT,
158         usr_home_ou             INT     NOT NULL,
159         usr_profile             INT     NOT NULL,
160         usr_birth_year          INT,
161         copy_call_number        INT     NOT NULL,
162         copy_location           INT     NOT NULL,
163         copy_owning_lib         INT     NOT NULL,
164         copy_circ_lib           INT     NOT NULL,
165         copy_bib_record         BIGINT  NOT NULL,
166         LIKE action.circulation
167
168 );
169 ALTER TABLE action.aged_circulation ADD PRIMARY KEY (id);
170 ALTER TABLE action.aged_circulation DROP COLUMN usr;
171 CREATE INDEX aged_circ_circ_lib_idx ON "action".aged_circulation (circ_lib);
172 CREATE INDEX aged_circ_start_idx ON "action".aged_circulation (xact_start);
173 CREATE INDEX aged_circ_copy_circ_lib_idx ON "action".aged_circulation (copy_circ_lib);
174 CREATE INDEX aged_circ_copy_owning_lib_idx ON "action".aged_circulation (copy_owning_lib);
175 CREATE INDEX aged_circ_copy_location_idx ON "action".aged_circulation (copy_location);
176
177 CREATE OR REPLACE VIEW action.all_circulation AS
178         SELECT  id,usr_post_code, usr_home_ou, usr_profile, usr_birth_year, copy_call_number, copy_location,
179                 copy_owning_lib, copy_circ_lib, copy_bib_record, xact_start, xact_finish, target_copy,
180                 circ_lib, circ_staff, checkin_staff, checkin_lib, renewal_remaining, due_date,
181                 stop_fines_time, checkin_time, create_time, duration, fine_interval, recuring_fine,
182                 max_fine, phone_renewal, desk_renewal, opac_renewal, duration_rule, recuring_fine_rule,
183                 max_fine_rule, stop_fines
184           FROM  action.aged_circulation
185                         UNION ALL
186         SELECT  DISTINCT circ.id,COALESCE(a.post_code,b.post_code) AS usr_post_code, p.home_ou AS usr_home_ou, p.profile AS usr_profile, EXTRACT(YEAR FROM p.dob)::INT AS usr_birth_year,
187                 cp.call_number AS copy_call_number, cp.location AS copy_location, cn.owning_lib AS copy_owning_lib, cp.circ_lib AS copy_circ_lib,
188                 cn.record AS copy_bib_record, circ.xact_start, circ.xact_finish, circ.target_copy, circ.circ_lib, circ.circ_staff, circ.checkin_staff,
189                 circ.checkin_lib, circ.renewal_remaining, circ.due_date, circ.stop_fines_time, circ.checkin_time, circ.create_time, circ.duration,
190                 circ.fine_interval, circ.recuring_fine, circ.max_fine, circ.phone_renewal, circ.desk_renewal, circ.opac_renewal, circ.duration_rule,
191                 circ.recuring_fine_rule, circ.max_fine_rule, circ.stop_fines
192           FROM  action.circulation circ
193                 JOIN asset.copy cp ON (circ.target_copy = cp.id)
194                 JOIN asset.call_number cn ON (cp.call_number = cn.id)
195                 JOIN actor.usr p ON (circ.usr = p.id)
196                 LEFT JOIN actor.usr_address a ON (p.mailing_address = a.id)
197                 LEFT JOIN actor.usr_address b ON (p.billing_address = a.id);
198
199 CREATE OR REPLACE FUNCTION action.age_circ_on_delete () RETURNS TRIGGER AS $$
200 BEGIN
201         INSERT INTO action.aged_circulation
202                 (id,usr_post_code, usr_home_ou, usr_profile, usr_birth_year, copy_call_number, copy_location,
203                 copy_owning_lib, copy_circ_lib, copy_bib_record, xact_start, xact_finish, target_copy,
204                 circ_lib, circ_staff, checkin_staff, checkin_lib, renewal_remaining, due_date,
205                 stop_fines_time, checkin_time, create_time, duration, fine_interval, recuring_fine,
206                 max_fine, phone_renewal, desk_renewal, opac_renewal, duration_rule, recuring_fine_rule,
207             max_fine_rule, stop_fines, checkin_workstation, checkin_scan_time, parent_circ)
208           SELECT
209                 id,usr_post_code, usr_home_ou, usr_profile, usr_birth_year, copy_call_number, copy_location,
210                 copy_owning_lib, copy_circ_lib, copy_bib_record, xact_start, xact_finish, target_copy,
211                 circ_lib, circ_staff, checkin_staff, checkin_lib, renewal_remaining, due_date,
212                 stop_fines_time, checkin_time, create_time, duration, fine_interval, recuring_fine,
213                 max_fine, phone_renewal, desk_renewal, opac_renewal, duration_rule, recuring_fine_rule,
214                 max_fine_rule, stop_fines, checkin_workstation, checkin_scan_time, parent_circ
215             FROM action.all_circulation WHERE id = OLD.id;
216
217         RETURN OLD;
218 END;
219 $$ LANGUAGE 'plpgsql';
220
221 CREATE TRIGGER action_circulation_aging_tgr
222         BEFORE DELETE ON action.circulation
223         FOR EACH ROW
224         EXECUTE PROCEDURE action.age_circ_on_delete ();
225
226
227 CREATE OR REPLACE VIEW action.open_circulation AS
228         SELECT  *
229           FROM  action.circulation
230           WHERE checkin_time IS NULL
231           ORDER BY due_date;
232                 
233
234 CREATE OR REPLACE VIEW action.billable_circulations AS
235         SELECT  *
236           FROM  action.circulation
237           WHERE xact_finish IS NULL;
238
239 CREATE VIEW stats.fleshed_circulation AS
240         SELECT  c.*,
241                 CAST(c.xact_start AS DATE) AS start_date_day,
242                 CAST(c.xact_finish AS DATE) AS finish_date_day,
243                 DATE_TRUNC('hour', c.xact_start) AS start_date_hour,
244                 DATE_TRUNC('hour', c.xact_finish) AS finish_date_hour,
245                 cp.call_number_label,
246                 cp.owning_lib,
247                 cp.item_lang,
248                 cp.item_type,
249                 cp.item_form
250         FROM    "action".circulation c
251                 JOIN stats.fleshed_copy cp ON (cp.id = c.target_copy);
252
253
254 CREATE OR REPLACE FUNCTION action.circulation_claims_returned () RETURNS TRIGGER AS $$
255 BEGIN
256         IF OLD.stop_fines IS NULL OR OLD.stop_fines <> NEW.stop_fines THEN
257                 IF NEW.stop_fines = 'CLAIMSRETURNED' THEN
258                         UPDATE actor.usr SET claims_returned_count = claims_returned_count + 1 WHERE id = NEW.usr;
259                 END IF;
260                 IF NEW.stop_fines = 'LOST' THEN
261                         UPDATE asset.copy SET status = 3 WHERE id = NEW.target_copy;
262                 END IF;
263         END IF;
264         RETURN NEW;
265 END;
266 $$ LANGUAGE 'plpgsql';
267 CREATE TRIGGER action_circulation_stop_fines_tgr
268         BEFORE UPDATE ON action.circulation
269         FOR EACH ROW
270         EXECUTE PROCEDURE action.circulation_claims_returned ();
271
272 CREATE TABLE action.hold_request_cancel_cause (
273     id      SERIAL  PRIMARY KEY,
274     label   TEXT    UNIQUE
275 );
276 INSERT INTO action.hold_request_cancel_cause (id,label) VALUES (1,'Untargeted expiration');
277 INSERT INTO action.hold_request_cancel_cause (id,label) VALUES (2,'Hold Shelf expiration');
278 INSERT INTO action.hold_request_cancel_cause (id,label) VALUES (3,'Patron via phone');
279 INSERT INTO action.hold_request_cancel_cause (id,label) VALUES (4,'Patron in person');
280 INSERT INTO action.hold_request_cancel_cause (id,label) VALUES (5,'Staff forced');
281 INSERT INTO action.hold_request_cancel_cause (id,label) VALUES (6,'Patron via OPAC');
282 SELECT SETVAL('action.hold_request_cancel_cause_id_seq', 100);
283
284 CREATE TABLE action.hold_request (
285         id                      SERIAL                          PRIMARY KEY,
286         request_time            TIMESTAMP WITH TIME ZONE        NOT NULL DEFAULT NOW(),
287         capture_time            TIMESTAMP WITH TIME ZONE,
288         fulfillment_time        TIMESTAMP WITH TIME ZONE,
289         checkin_time            TIMESTAMP WITH TIME ZONE,
290         return_time             TIMESTAMP WITH TIME ZONE,
291         prev_check_time         TIMESTAMP WITH TIME ZONE,
292         expire_time             TIMESTAMP WITH TIME ZONE,
293         cancel_time             TIMESTAMP WITH TIME ZONE,
294         cancel_cause    INT REFERENCES action.hold_request_cancel_cause (id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
295         cancel_note             TEXT,
296         target                  BIGINT                          NOT NULL, -- see hold_type
297         current_copy            BIGINT                          REFERENCES asset.copy (id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
298         fulfillment_staff       INT                             REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
299         fulfillment_lib         INT                             REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED,
300         request_lib             INT                             NOT NULL REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED,
301         requestor               INT                             NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
302         usr                     INT                             NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
303         selection_ou            INT                             NOT NULL,
304         selection_depth         INT                             NOT NULL DEFAULT 0,
305         pickup_lib              INT                             NOT NULL REFERENCES actor.org_unit DEFERRABLE INITIALLY DEFERRED,
306         hold_type               TEXT                            NOT NULL CHECK (hold_type IN ('M','T','V','C')),
307         holdable_formats        TEXT,
308         phone_notify            TEXT,
309         email_notify            BOOL                            NOT NULL DEFAULT TRUE,
310         frozen                  BOOL                            NOT NULL DEFAULT FALSE,
311         thaw_date               TIMESTAMP WITH TIME ZONE,
312         shelf_time              TIMESTAMP WITH TIME ZONE
313 );
314
315 CREATE INDEX hold_request_target_idx ON action.hold_request (target);
316 CREATE INDEX hold_request_usr_idx ON action.hold_request (usr);
317 CREATE INDEX hold_request_pickup_lib_idx ON action.hold_request (pickup_lib);
318 CREATE INDEX hold_request_current_copy_idx ON action.hold_request (current_copy);
319 CREATE INDEX hold_request_prev_check_time_idx ON action.hold_request (prev_check_time);
320 CREATE INDEX hold_request_fulfillment_staff_idx ON action.hold_request ( fulfillment_staff );
321 CREATE INDEX hold_request_requestor_idx         ON action.hold_request ( requestor );
322
323
324 CREATE TABLE action.hold_request_note (
325
326     id     BIGSERIAL PRIMARY KEY,
327     hold   BIGINT    NOT NULL REFERENCES action.hold_request (id)
328                               ON DELETE CASCADE
329                               DEFERRABLE INITIALLY DEFERRED,
330     title  TEXT      NOT NULL,
331     body   TEXT      NOT NULL,
332     slip   BOOL      NOT NULL DEFAULT FALSE,
333     pub    BOOL      NOT NULL DEFAULT FALSE,
334     staff  BOOL      NOT NULL DEFAULT FALSE  -- created by staff
335
336 );
337 CREATE INDEX ahrn_hold_idx ON action.hold_request_note (hold);
338
339
340 CREATE TABLE action.hold_notification (
341         id              SERIAL                          PRIMARY KEY,
342         hold            INT                             NOT NULL REFERENCES action.hold_request (id)
343                                                                         ON DELETE CASCADE
344                                                                         DEFERRABLE INITIALLY DEFERRED,
345         notify_staff    INT                     REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
346         notify_time     TIMESTAMP WITH TIME ZONE        NOT NULL DEFAULT NOW(),
347         method          TEXT                            NOT NULL, -- email address or phone number
348         note            TEXT
349 );
350 CREATE INDEX ahn_hold_idx ON action.hold_notification (hold);
351 CREATE INDEX ahn_notify_staff_idx ON action.hold_notification ( notify_staff );
352
353 CREATE TABLE action.hold_copy_map (
354         id              SERIAL  PRIMARY KEY,
355         hold            INT     NOT NULL REFERENCES action.hold_request (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
356         target_copy     BIGINT  NOT NULL REFERENCES asset.copy (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
357         CONSTRAINT copy_once_per_hold UNIQUE (hold,target_copy)
358 );
359 -- CREATE INDEX acm_hold_idx ON action.hold_copy_map (hold);
360 CREATE INDEX acm_copy_idx ON action.hold_copy_map (target_copy);
361
362 CREATE TABLE action.transit_copy (
363         id                      SERIAL                          PRIMARY KEY,
364         source_send_time        TIMESTAMP WITH TIME ZONE,
365         dest_recv_time          TIMESTAMP WITH TIME ZONE,
366         target_copy             BIGINT                          NOT NULL REFERENCES asset.copy (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
367         source                  INT                             NOT NULL REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED,
368         dest                    INT                             NOT NULL REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED,
369         prev_hop                INT                             REFERENCES action.transit_copy (id) DEFERRABLE INITIALLY DEFERRED,
370         copy_status             INT                             NOT NULL REFERENCES config.copy_status (id) DEFERRABLE INITIALLY DEFERRED,
371         persistant_transfer     BOOL                            NOT NULL DEFAULT FALSE
372 );
373 CREATE INDEX active_transit_dest_idx ON "action".transit_copy (dest); 
374 CREATE INDEX active_transit_source_idx ON "action".transit_copy (source);
375 CREATE INDEX active_transit_cp_idx ON "action".transit_copy (target_copy);
376
377
378 CREATE TABLE action.hold_transit_copy (
379         hold    INT     REFERENCES action.hold_request (id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED
380 ) INHERITS (action.transit_copy);
381 ALTER TABLE action.hold_transit_copy ADD PRIMARY KEY (id);
382 ALTER TABLE action.hold_transit_copy ADD CONSTRAINT ahtc_tc_fkey FOREIGN KEY (target_copy) REFERENCES asset.copy (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
383 CREATE INDEX active_hold_transit_dest_idx ON "action".hold_transit_copy (dest);
384 CREATE INDEX active_hold_transit_source_idx ON "action".hold_transit_copy (source);
385 CREATE INDEX active_hold_transit_cp_idx ON "action".hold_transit_copy (target_copy);
386
387
388 CREATE TABLE action.unfulfilled_hold_list (
389         id              BIGSERIAL                       PRIMARY KEY,
390         current_copy    BIGINT                          NOT NULL,
391         hold            INT                             NOT NULL,
392         circ_lib        INT                             NOT NULL,
393         fail_time       TIMESTAMP WITH TIME ZONE        NOT NULL DEFAULT NOW()
394 );
395 CREATE INDEX uhr_hold_idx ON action.unfulfilled_hold_list (hold);
396
397 CREATE OR REPLACE VIEW action.unfulfilled_hold_loops AS
398     SELECT  u.hold,
399             c.circ_lib,
400             count(*)
401       FROM  action.unfulfilled_hold_list u
402             JOIN asset.copy c ON (c.id = u.current_copy)
403       GROUP BY 1,2;
404
405 CREATE OR REPLACE VIEW action.unfulfilled_hold_min_loop AS
406     SELECT  hold,
407             min(count)
408       FROM  action.unfulfilled_hold_loops
409       GROUP BY 1;
410
411 CREATE OR REPLACE VIEW action.unfulfilled_hold_innermost_loop AS
412     SELECT  DISTINCT l.*
413       FROM  action.unfulfilled_hold_loops l
414             JOIN action.unfulfilled_hold_min_loop m USING (hold)
415       WHERE l.count = m.min;
416
417
418 COMMIT;
419