]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/sql/Pg/210.schema.serials.sql
Merge remote branch 'working/user/dbwells/shared_siss_editor'
[working/Evergreen.git] / Open-ILS / src / sql / Pg / 210.schema.serials.sql
1
2
3 DROP SCHEMA IF EXISTS serial CASCADE;
4
5 BEGIN;
6
7 CREATE SCHEMA serial;
8
9 CREATE TABLE serial.record_entry (
10         id              BIGSERIAL       PRIMARY KEY,
11         record          BIGINT          REFERENCES biblio.record_entry (id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
12         owning_lib      INT             NOT NULL DEFAULT 1 REFERENCES actor.org_unit (id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
13         creator         INT             NOT NULL DEFAULT 1,
14         editor          INT             NOT NULL DEFAULT 1,
15         source          INT,
16         create_date     TIMESTAMP WITH TIME ZONE        NOT NULL DEFAULT now(),
17         edit_date       TIMESTAMP WITH TIME ZONE        NOT NULL DEFAULT now(),
18         active          BOOL            NOT NULL DEFAULT TRUE,
19         deleted         BOOL            NOT NULL DEFAULT FALSE,
20         marc            TEXT,
21         last_xact_id    TEXT            NOT NULL
22 );
23 CREATE INDEX serial_record_entry_creator_idx ON serial.record_entry ( creator );
24 CREATE INDEX serial_record_entry_editor_idx ON serial.record_entry ( editor );
25 CREATE INDEX serial_record_entry_owning_lib_idx ON serial.record_entry ( owning_lib, deleted );
26 CREATE TRIGGER b_maintain_901 BEFORE INSERT OR UPDATE ON serial.record_entry FOR EACH ROW EXECUTE PROCEDURE evergreen.maintain_901();
27 CREATE TRIGGER c_maintain_control_numbers BEFORE INSERT OR UPDATE ON serial.record_entry FOR EACH ROW EXECUTE PROCEDURE maintain_control_numbers();
28
29 CREATE RULE protect_mfhd_delete AS ON DELETE TO serial.record_entry DO INSTEAD UPDATE serial.record_entry SET deleted = true WHERE old.id = serial.record_entry.id;
30
31 CREATE TABLE serial.subscription (
32         id                     SERIAL       PRIMARY KEY,
33         owning_lib             INT          NOT NULL DEFAULT 1 REFERENCES actor.org_unit (id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
34         start_date             TIMESTAMP WITH TIME ZONE     NOT NULL,
35         end_date               TIMESTAMP WITH TIME ZONE,    -- interpret NULL as current subscription
36         record_entry           BIGINT       REFERENCES biblio.record_entry (id)
37                                             ON DELETE SET NULL
38                                             DEFERRABLE INITIALLY DEFERRED,
39         expected_date_offset   INTERVAL
40         -- acquisitions/business-side tables link to here
41 );
42 CREATE INDEX serial_subscription_record_idx ON serial.subscription (record_entry);
43 CREATE INDEX serial_subscription_owner_idx ON serial.subscription (owning_lib);
44
45 CREATE TABLE serial.subscription_note (
46         id           SERIAL PRIMARY KEY,
47         subscription INT    NOT NULL
48                             REFERENCES serial.subscription (id)
49                             ON DELETE CASCADE
50                             DEFERRABLE INITIALLY DEFERRED,
51         creator      INT    NOT NULL
52                             REFERENCES actor.usr (id)
53                             DEFERRABLE INITIALLY DEFERRED,
54         create_date  TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
55         pub          BOOL   NOT NULL DEFAULT FALSE,
56         title        TEXT   NOT NULL,
57         value        TEXT   NOT NULL
58 );
59 CREATE INDEX serial_subscription_note_sub_idx ON serial.subscription_note (subscription);
60
61 CREATE TABLE serial.caption_and_pattern (
62         id           SERIAL       PRIMARY KEY,
63         subscription INT          NOT NULL
64                                   REFERENCES serial.subscription (id)
65                                   ON DELETE CASCADE
66                                   DEFERRABLE INITIALLY DEFERRED,
67         type         TEXT         NOT NULL
68                                   CONSTRAINT cap_type CHECK ( type in
69                                   ( 'basic', 'supplement', 'index' )),
70         create_date  TIMESTAMPTZ  NOT NULL DEFAULT now(),
71         start_date   TIMESTAMPTZ  NOT NULL DEFAULT now(),
72         end_date     TIMESTAMPTZ,
73         active       BOOL         NOT NULL DEFAULT FALSE,
74         pattern_code TEXT         NOT NULL,       -- must contain JSON
75         enum_1       TEXT,
76         enum_2       TEXT,
77         enum_3       TEXT,
78         enum_4       TEXT,
79         enum_5       TEXT,
80         enum_6       TEXT,
81         chron_1      TEXT,
82         chron_2      TEXT,
83         chron_3      TEXT,
84         chron_4      TEXT,
85         chron_5      TEXT
86 );
87 CREATE INDEX serial_caption_and_pattern_sub_idx ON serial.caption_and_pattern (subscription);
88
89 --at least one distribution per org_unit holding issues
90 CREATE TABLE serial.distribution (
91         id                    SERIAL  PRIMARY KEY,
92         record_entry          BIGINT  REFERENCES serial.record_entry (id)
93                                                                   ON DELETE SET NULL
94                                                                   DEFERRABLE INITIALLY DEFERRED,
95         summary_method        TEXT    CONSTRAINT sdist_summary_method_check
96                                       CHECK (summary_method IS NULL
97                                       OR summary_method IN ( 'add_to_sre',
98                                       'merge_with_sre', 'use_sre_only',
99                                       'use_sdist_only')),
100         subscription          INT     NOT NULL
101                                       REFERENCES serial.subscription (id)
102                                                                   ON DELETE CASCADE
103                                                                   DEFERRABLE INITIALLY DEFERRED,
104         holding_lib           INT     NOT NULL
105                                       REFERENCES actor.org_unit (id)
106                                                                   DEFERRABLE INITIALLY DEFERRED,
107         label                 TEXT    NOT NULL,
108         display_grouping      TEXT    NOT NULL DEFAULT 'chron'
109                                       CHECK (display_grouping IN ('enum', 'chron')),
110         receive_call_number   BIGINT  REFERENCES asset.call_number (id)
111                                       DEFERRABLE INITIALLY DEFERRED,
112         receive_unit_template INT     REFERENCES asset.copy_template (id)
113                                       DEFERRABLE INITIALLY DEFERRED,
114         bind_call_number      BIGINT  REFERENCES asset.call_number (id)
115                                       DEFERRABLE INITIALLY DEFERRED,
116         bind_unit_template    INT     REFERENCES asset.copy_template (id)
117                                       DEFERRABLE INITIALLY DEFERRED,
118         unit_label_prefix     TEXT,
119         unit_label_suffix     TEXT
120 );
121 CREATE UNIQUE INDEX one_dist_per_sre_idx ON serial.distribution (record_entry);
122 CREATE INDEX serial_distribution_sub_idx ON serial.distribution (subscription);
123 CREATE INDEX serial_distribution_holding_lib_idx ON serial.distribution (holding_lib);
124
125 CREATE TABLE serial.distribution_note (
126         id           SERIAL PRIMARY KEY,
127         distribution INT    NOT NULL
128                             REFERENCES serial.distribution (id)
129                             ON DELETE CASCADE
130                             DEFERRABLE INITIALLY DEFERRED,
131         creator      INT    NOT NULL
132                             REFERENCES actor.usr (id)
133                             DEFERRABLE INITIALLY DEFERRED,
134         create_date  TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
135         pub          BOOL   NOT NULL DEFAULT FALSE,
136         title        TEXT   NOT NULL,
137         value        TEXT   NOT NULL
138 );
139 CREATE INDEX serial_distribution_note_dist_idx ON serial.distribution_note (distribution);
140
141 CREATE TABLE serial.stream (
142         id              SERIAL  PRIMARY KEY,
143         distribution    INT     NOT NULL
144                                 REFERENCES serial.distribution (id)
145                                 ON DELETE CASCADE
146                                 DEFERRABLE INITIALLY DEFERRED,
147         routing_label   TEXT
148 );
149 CREATE INDEX serial_stream_dist_idx ON serial.stream (distribution);
150
151 CREATE UNIQUE INDEX label_once_per_dist
152         ON serial.stream (distribution, routing_label)
153         WHERE routing_label IS NOT NULL;
154
155 CREATE TABLE serial.routing_list_user (
156         id             SERIAL       PRIMARY KEY,
157         stream         INT          NOT NULL
158                                     REFERENCES serial.stream
159                                     ON DELETE CASCADE
160                                     DEFERRABLE INITIALLY DEFERRED,
161         pos            INT          NOT NULL DEFAULT 1,
162         reader         INT          REFERENCES actor.usr
163                                     ON DELETE CASCADE
164                                     DEFERRABLE INITIALLY DEFERRED,
165         department     TEXT,
166         note           TEXT,
167         CONSTRAINT one_pos_per_routing_list UNIQUE ( stream, pos ),
168         CONSTRAINT reader_or_dept CHECK
169         (
170             -- Recipient is a person or a department, but not both
171                 (reader IS NOT NULL AND department IS NULL) OR
172                 (reader IS NULL AND department IS NOT NULL)
173         )
174 );
175 CREATE INDEX serial_routing_list_user_stream_idx ON serial.routing_list_user (stream);
176 CREATE INDEX serial_routing_list_user_reader_idx ON serial.routing_list_user (reader);
177
178 CREATE TABLE serial.issuance (
179         id              SERIAL    PRIMARY KEY,
180         creator         INT       NOT NULL
181                                   REFERENCES actor.usr (id)
182                                                           DEFERRABLE INITIALLY DEFERRED,
183         editor          INT       NOT NULL
184                                   REFERENCES actor.usr (id)
185                                   DEFERRABLE INITIALLY DEFERRED,
186         create_date     TIMESTAMP WITH TIME ZONE        NOT NULL DEFAULT now(),
187         edit_date       TIMESTAMP WITH TIME ZONE        NOT NULL DEFAULT now(),
188         subscription    INT       NOT NULL
189                                   REFERENCES serial.subscription (id)
190                                   ON DELETE CASCADE
191                                   DEFERRABLE INITIALLY DEFERRED,
192         label           TEXT,
193         date_published  TIMESTAMP WITH TIME ZONE,
194         caption_and_pattern INT   REFERENCES serial.caption_and_pattern (id)
195                                   DEFERRABLE INITIALLY DEFERRED,
196         holding_code    TEXT,
197         holding_type    TEXT      CONSTRAINT valid_holding_type CHECK
198                                   (
199                                       holding_type IS NULL
200                                       OR holding_type IN ('basic','supplement','index')
201                                   ),
202         holding_link_id INT -- probably defunct
203         -- TODO: add columns for separate enumeration/chronology values
204 );
205 CREATE INDEX serial_issuance_sub_idx ON serial.issuance (subscription);
206 CREATE INDEX serial_issuance_caption_and_pattern_idx ON serial.issuance (caption_and_pattern);
207 CREATE INDEX serial_issuance_date_published_idx ON serial.issuance (date_published);
208
209 CREATE TABLE serial.unit (
210         sort_key          TEXT,
211         detailed_contents TEXT    NOT NULL,
212         summary_contents  TEXT    NOT NULL
213 ) INHERITS (asset.copy);
214 ALTER TABLE serial.unit ADD PRIMARY KEY (id);
215 CREATE UNIQUE INDEX unit_barcode_key ON serial.unit (barcode) WHERE deleted = FALSE OR deleted IS FALSE;
216 CREATE INDEX unit_cn_idx ON serial.unit (call_number);
217 CREATE INDEX unit_avail_cn_idx ON serial.unit (call_number);
218 CREATE INDEX unit_creator_idx  ON serial.unit ( creator );
219 CREATE INDEX unit_editor_idx   ON serial.unit ( editor );
220
221 -- must create this rule explicitly; it is not inherited from asset.copy
222 CREATE RULE protect_serial_unit_delete AS ON DELETE TO serial.unit DO INSTEAD UPDATE serial.unit SET deleted = TRUE WHERE OLD.id = serial.unit.id;
223
224 -- must create this trigger explicitly; it is not inherited from asset.copy
225 CREATE TRIGGER autogenerate_placeholder_barcode
226    BEFORE INSERT OR UPDATE ON serial.unit 
227    FOR EACH ROW EXECUTE PROCEDURE asset.autogenerate_placeholder_barcode()
228 ;
229
230 -- must create this trigger explicitly; it is not inherited from asset.copy
231 CREATE TRIGGER sunit_status_changed_trig
232     BEFORE UPDATE ON serial.unit
233     FOR EACH ROW EXECUTE PROCEDURE asset.acp_status_changed();
234
235 -- ditto
236 CREATE TRIGGER sunit_created_trig
237     BEFORE INSERT ON serial.unit
238     FOR EACH ROW EXECUTE PROCEDURE asset.acp_created();
239
240 CREATE TABLE serial.item (
241         id              SERIAL  PRIMARY KEY,
242         creator         INT     NOT NULL
243                                 REFERENCES actor.usr (id)
244                                 DEFERRABLE INITIALLY DEFERRED,
245         editor          INT     NOT NULL
246                                 REFERENCES actor.usr (id)
247                                 DEFERRABLE INITIALLY DEFERRED,
248         create_date     TIMESTAMP WITH TIME ZONE        NOT NULL DEFAULT now(),
249         edit_date       TIMESTAMP WITH TIME ZONE        NOT NULL DEFAULT now(),
250         issuance        INT     NOT NULL
251                                 REFERENCES serial.issuance (id)
252                                 ON DELETE CASCADE
253                                 DEFERRABLE INITIALLY DEFERRED,
254         stream          INT     NOT NULL
255                                 REFERENCES serial.stream (id)
256                                 ON DELETE CASCADE
257                                 DEFERRABLE INITIALLY DEFERRED,
258         unit            INT     REFERENCES serial.unit (id)
259                                 ON DELETE SET NULL
260                                 DEFERRABLE INITIALLY DEFERRED,
261         uri             INT     REFERENCES asset.uri (id)
262                                 ON DELETE SET NULL
263                                 DEFERRABLE INITIALLY DEFERRED,
264         date_expected   TIMESTAMP WITH TIME ZONE,
265         date_received   TIMESTAMP WITH TIME ZONE,
266         status          TEXT    CONSTRAINT valid_status CHECK
267                                 (
268                                     status IN ('Bindery', 'Bound', 'Claimed', 'Discarded', 'Expected', 'Not Held', 'Not Published', 'Received')
269                                 ) DEFAULT 'Expected',
270         shadowed        BOOL    NOT NULL DEFAULT FALSE -- ignore when generating summaries/labels
271 );
272 CREATE INDEX serial_item_stream_idx ON serial.item (stream);
273 CREATE INDEX serial_item_issuance_idx ON serial.item (issuance);
274 CREATE INDEX serial_item_unit_idx ON serial.item (unit);
275 CREATE INDEX serial_item_uri_idx ON serial.item (uri);
276 CREATE INDEX serial_item_date_received_idx ON serial.item (date_received);
277 CREATE INDEX serial_item_status_idx ON serial.item (status);
278
279 CREATE TABLE serial.item_note (
280         id          SERIAL  PRIMARY KEY,
281         item        INT     NOT NULL
282                             REFERENCES serial.item (id)
283                             ON DELETE CASCADE
284                             DEFERRABLE INITIALLY DEFERRED,
285         creator     INT     NOT NULL
286                             REFERENCES actor.usr (id)
287                             DEFERRABLE INITIALLY DEFERRED,
288         create_date TIMESTAMP WITH TIME ZONE    DEFAULT NOW(),
289         pub         BOOL    NOT NULL    DEFAULT FALSE,
290         title       TEXT    NOT NULL,
291         value       TEXT    NOT NULL
292 );
293 CREATE INDEX serial_item_note_item_idx ON serial.item_note (item);
294
295 CREATE TABLE serial.basic_summary (
296         id                  SERIAL  PRIMARY KEY,
297         distribution        INT     NOT NULL
298                                     REFERENCES serial.distribution (id)
299                                     ON DELETE CASCADE
300                                     DEFERRABLE INITIALLY DEFERRED,
301         generated_coverage  TEXT    NOT NULL,
302         textual_holdings    TEXT,
303         show_generated      BOOL    NOT NULL DEFAULT TRUE
304 );
305 CREATE INDEX serial_basic_summary_dist_idx ON serial.basic_summary (distribution);
306
307 CREATE TABLE serial.supplement_summary (
308         id                  SERIAL  PRIMARY KEY,
309         distribution        INT     NOT NULL
310                                     REFERENCES serial.distribution (id)
311                                     ON DELETE CASCADE
312                                     DEFERRABLE INITIALLY DEFERRED,
313         generated_coverage  TEXT    NOT NULL,
314         textual_holdings    TEXT,
315         show_generated      BOOL    NOT NULL DEFAULT TRUE
316 );
317 CREATE INDEX serial_supplement_summary_dist_idx ON serial.supplement_summary (distribution);
318
319 CREATE TABLE serial.index_summary (
320         id                  SERIAL  PRIMARY KEY,
321         distribution        INT     NOT NULL
322                                     REFERENCES serial.distribution (id)
323                                     ON DELETE CASCADE
324                                     DEFERRABLE INITIALLY DEFERRED,
325         generated_coverage  TEXT    NOT NULL,
326         textual_holdings    TEXT,
327         show_generated      BOOL    NOT NULL DEFAULT TRUE
328 );
329 CREATE INDEX serial_index_summary_dist_idx ON serial.index_summary (distribution);
330
331 CREATE VIEW serial.any_summary AS
332     SELECT
333         'basic' AS summary_type, id, distribution,
334         generated_coverage, textual_holdings, show_generated
335     FROM serial.basic_summary
336     UNION
337     SELECT
338         'index' AS summary_type, id, distribution,
339         generated_coverage, textual_holdings, show_generated
340     FROM serial.index_summary
341     UNION
342     SELECT
343         'supplement' AS summary_type, id, distribution,
344         generated_coverage, textual_holdings, show_generated
345     FROM serial.supplement_summary ;
346
347
348 CREATE TABLE serial.materialized_holding_code (
349     id BIGSERIAL PRIMARY KEY,
350     issuance INTEGER NOT NULL REFERENCES serial.issuance (id) ON DELETE CASCADE,
351     holding_type TEXT NOT NULL,
352     ind1 TEXT,
353     ind2 TEXT,
354     subfield CHAR,
355     value TEXT
356 );
357
358 CREATE OR REPLACE FUNCTION serial.materialize_holding_code() RETURNS TRIGGER
359 AS $func$ 
360 use strict;
361
362 use MARC::Field;
363 use JSON::XS;
364
365 # Do nothing if holding_code has not changed...
366
367 if ($_TD->{new}{holding_code} eq $_TD->{old}{holding_code}) {
368     # ... unless the following internal flag is set.
369
370     my $flag_rv = spi_exec_query(q{
371         SELECT * FROM config.internal_flag
372         WHERE name = 'serial.rematerialize_on_same_holding_code' AND enabled
373     }, 1);
374     return unless $flag_rv->{processed};
375 }
376
377
378 my $holding_code = (new JSON::XS)->decode($_TD->{new}{holding_code});
379
380 my $field = new MARC::Field('999', @$holding_code); # tag doesnt matter
381
382 my $dstmt = spi_prepare(
383     'DELETE FROM serial.materialized_holding_code WHERE issuance = $1',
384     'INT'
385 );
386 spi_exec_prepared($dstmt, $_TD->{new}{id});
387
388 my $istmt = spi_prepare(
389     q{
390         INSERT INTO serial.materialized_holding_code (
391             issuance, holding_type, ind1, ind2, subfield, value
392         ) VALUES ($1, $2, $3, $4, $5, $6)
393     }, qw{INT TEXT TEXT TEXT CHAR TEXT}
394 );
395
396 foreach ($field->subfields) {
397     spi_exec_prepared(
398         $istmt,
399         $_TD->{new}{id},
400         $_TD->{new}{holding_type},
401         $field->indicator(1),
402         $field->indicator(2),
403         $_->[0],
404         $_->[1]
405     );
406 }
407
408 return;
409
410 $func$ LANGUAGE 'plperlu';
411
412 CREATE INDEX assist_holdings_display
413     ON serial.materialized_holding_code (issuance, subfield);
414
415 CREATE TRIGGER materialize_holding_code
416     AFTER INSERT OR UPDATE ON serial.issuance
417     FOR EACH ROW EXECUTE PROCEDURE serial.materialize_holding_code() ;
418 COMMIT;
419