]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/sql/Pg/upgrade/0479.schema.matrix_weights.sql
LP1893463: Follow-up to address de-duplication and adding release notes.
[Evergreen.git] / Open-ILS / src / sql / Pg / upgrade / 0479.schema.matrix_weights.sql
1 BEGIN;
2
3 INSERT INTO config.upgrade_log (version) VALUES ('0479');
4
5 CREATE OR REPLACE FUNCTION permission.grp_ancestors_distance( INT ) RETURNS TABLE (id INT, distance INT) AS $$
6     WITH RECURSIVE grp_ancestors_distance(id, distance) AS (
7             SELECT $1, 0
8         UNION
9             SELECT pgt.parent, gad.distance+1
10             FROM permission.grp_tree pgt JOIN grp_ancestors_distance gad ON pgt.id = gad.id
11             WHERE pgt.parent IS NOT NULL
12     )
13     SELECT * FROM grp_ancestors_distance;
14 $$ LANGUAGE SQL STABLE;
15
16 CREATE OR REPLACE FUNCTION permission.grp_descendants_distance( INT ) RETURNS TABLE (id INT, distance INT) AS $$
17     WITH RECURSIVE grp_descendants_distance(id, distance) AS (
18             SELECT $1, 0
19         UNION
20             SELECT pgt.id, gdd.distance+1
21             FROM permission.grp_tree pgt JOIN grp_descendants_distance gdd ON pgt.parent = gdd.id
22     )
23     SELECT * FROM grp_descendants_distance;
24 $$ LANGUAGE SQL STABLE;
25
26 CREATE OR REPLACE FUNCTION actor.org_unit_ancestors_distance( INT ) RETURNS TABLE (id INT, distance INT) AS $$
27     WITH RECURSIVE org_unit_ancestors_distance(id, distance) AS (
28             SELECT $1, 0
29         UNION
30             SELECT ou.parent_ou, ouad.distance+1
31             FROM actor.org_unit ou JOIN org_unit_ancestors_distance ouad ON ou.id = ouad.id
32             WHERE ou.parent_ou IS NOT NULL
33     )
34     SELECT * FROM org_unit_ancestors_distance;
35 $$ LANGUAGE SQL STABLE;
36
37 CREATE OR REPLACE FUNCTION actor.org_unit_descendants_distance( INT ) RETURNS TABLE (id INT, distance INT) AS $$
38     WITH RECURSIVE org_unit_descendants_distance(id, distance) AS (
39             SELECT $1, 0
40         UNION
41             SELECT ou.id, oudd.distance+1
42             FROM actor.org_unit ou JOIN org_unit_descendants_distance oudd ON ou.parent_ou = oudd.id
43     )
44     SELECT * FROM org_unit_descendants_distance;
45 $$ LANGUAGE SQL STABLE;
46
47 ALTER TABLE config.circ_matrix_matchpoint
48     ADD COLUMN user_home_ou         INT     REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED;
49
50 CREATE TABLE config.circ_matrix_weights (
51     id                      SERIAL  PRIMARY KEY,
52     name                    TEXT    NOT NULL UNIQUE,
53     org_unit                NUMERIC(6,2)   NOT NULL,
54     grp                     NUMERIC(6,2)   NOT NULL,
55     circ_modifier           NUMERIC(6,2)   NOT NULL,
56     marc_type               NUMERIC(6,2)   NOT NULL,
57     marc_form               NUMERIC(6,2)   NOT NULL,
58     marc_vr_format          NUMERIC(6,2)   NOT NULL,
59     copy_circ_lib           NUMERIC(6,2)   NOT NULL,
60     copy_owning_lib         NUMERIC(6,2)   NOT NULL,
61     user_home_ou            NUMERIC(6,2)   NOT NULL,
62     ref_flag                NUMERIC(6,2)   NOT NULL,
63     juvenile_flag           NUMERIC(6,2)   NOT NULL,
64     is_renewal              NUMERIC(6,2)   NOT NULL,
65     usr_age_lower_bound     NUMERIC(6,2)   NOT NULL,
66     usr_age_upper_bound     NUMERIC(6,2)   NOT NULL
67 );
68
69 CREATE TABLE config.hold_matrix_weights (
70     id                      SERIAL  PRIMARY KEY,
71     name                    TEXT    NOT NULL UNIQUE,
72     user_home_ou            NUMERIC(6,2)   NOT NULL,
73     request_ou              NUMERIC(6,2)   NOT NULL,
74     pickup_ou               NUMERIC(6,2)   NOT NULL,
75     item_owning_ou          NUMERIC(6,2)   NOT NULL,
76     item_circ_ou            NUMERIC(6,2)   NOT NULL,
77     usr_grp                 NUMERIC(6,2)   NOT NULL,
78     requestor_grp           NUMERIC(6,2)   NOT NULL,
79     circ_modifier           NUMERIC(6,2)   NOT NULL,
80     marc_type               NUMERIC(6,2)   NOT NULL,
81     marc_form               NUMERIC(6,2)   NOT NULL,
82     marc_vr_format          NUMERIC(6,2)   NOT NULL,
83     juvenile_flag           NUMERIC(6,2)   NOT NULL,
84     ref_flag                NUMERIC(6,2)   NOT NULL
85 );
86
87 CREATE TABLE config.weight_assoc (
88     id                      SERIAL  PRIMARY KEY,
89     active                  BOOL    NOT NULL,
90     org_unit                INT     NOT NULL REFERENCES actor.org_unit (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
91     circ_weights            INT     REFERENCES config.circ_matrix_weights (id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
92     hold_weights            INT     REFERENCES config.hold_matrix_weights (id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED
93 );
94 CREATE UNIQUE INDEX cwa_one_active_per_ou ON config.weight_assoc (org_unit) WHERE active;
95
96 CREATE OR REPLACE FUNCTION action.find_circ_matrix_matchpoint( context_ou INT, match_item BIGINT, match_user INT, renewal BOOL ) RETURNS config.circ_matrix_matchpoint AS $func$
97 DECLARE
98     user_object     actor.usr%ROWTYPE;
99     item_object     asset.copy%ROWTYPE;
100     cn_object       asset.call_number%ROWTYPE;
101     rec_descriptor  metabib.rec_descriptor%ROWTYPE;
102     matchpoint      config.circ_matrix_matchpoint%ROWTYPE;
103     weights         config.circ_matrix_weights%ROWTYPE;
104     user_age        INTERVAL;
105     denominator     INT;
106 BEGIN
107     SELECT INTO user_object     * FROM actor.usr                WHERE id = match_user;
108     SELECT INTO item_object     * FROM asset.copy               WHERE id = match_item;
109     SELECT INTO cn_object       * FROM asset.call_number        WHERE id = item_object.call_number;
110     SELECT INTO rec_descriptor  * FROM metabib.rec_descriptor   WHERE record = cn_object.record;
111
112     -- Pre-generate this so we only calc it once
113     IF user_object.dob IS NOT NULL THEN
114         SELECT INTO user_age age(user_object.dob);
115     END IF;
116
117     -- Grab the closest set circ weight setting.
118     SELECT INTO weights cw.*
119       FROM config.weight_assoc wa
120            JOIN config.circ_matrix_weights cw ON (cw.id = wa.circ_weights)
121            JOIN actor.org_unit_ancestors_distance( context_ou ) d ON (wa.org_unit = d.id)
122       WHERE active
123       ORDER BY d.distance
124       LIMIT 1;
125
126     -- No weights? Bad admin! Defaults to handle that anyway.
127     IF weights.id IS NULL THEN
128         weights.grp                 := 11;
129         weights.org_unit            := 10;
130         weights.circ_modifier       := 5;
131         weights.marc_type           := 4;
132         weights.marc_form           := 3;
133         weights.marc_vr_format      := 2;
134         weights.copy_circ_lib       := 8;
135         weights.copy_owning_lib     := 8;
136         weights.user_home_ou        := 8;
137         weights.ref_flag            := 1;
138         weights.juvenile_flag       := 6;
139         weights.is_renewal          := 7;
140         weights.usr_age_lower_bound := 0;
141         weights.usr_age_upper_bound := 0;
142     END IF;
143
144     -- Determine the max (expected) depth (+1) of the org tree and max depth of the permisson tree
145     -- If you break your org tree with funky parenting this may be wrong
146     -- Note: This CTE is duplicated in the find_hold_matrix_matchpoint function, and it may be a good idea to split it off to a function
147     -- We use one denominator for all tree-based checks for when permission groups and org units have the same weighting
148     WITH all_distance(distance) AS (
149             SELECT depth AS distance FROM actor.org_unit_type
150         UNION
151             SELECT distance AS distance FROM permission.grp_ancestors_distance((SELECT id FROM permission.grp_tree WHERE parent IS NULL))
152         )
153     SELECT INTO denominator MAX(distance) + 1 FROM all_distance;
154
155     -- Select the winning matchpoint into the matchpoint variable for returning
156     SELECT INTO matchpoint m.*
157       FROM  config.circ_matrix_matchpoint m
158             /*LEFT*/ JOIN permission.grp_ancestors_distance( user_object.profile ) upgad ON m.grp = upgad.id
159             /*LEFT*/ JOIN actor.org_unit_ancestors_distance( context_ou ) ctoua ON m.org_unit = ctoua.id
160             LEFT JOIN actor.org_unit_ancestors_distance( cn_object.owning_lib ) cnoua ON m.copy_owning_lib = cnoua.id
161             LEFT JOIN actor.org_unit_ancestors_distance( item_object.circ_lib ) iooua ON m.copy_circ_lib = iooua.id
162             LEFT JOIN actor.org_unit_ancestors_distance( user_object.home_ou  ) uhoua ON m.user_home_ou = uhoua.id
163       WHERE m.active
164             -- Permission Groups
165          -- AND (m.grp                      IS NULL OR upgad.id IS NOT NULL) -- Optional Permission Group?
166             -- Org Units
167          -- AND (m.org_unit                 IS NULL OR ctoua.id IS NOT NULL) -- Optional Org Unit?
168             AND (m.copy_owning_lib          IS NULL OR cnoua.id IS NOT NULL)
169             AND (m.copy_circ_lib            IS NULL OR iooua.id IS NOT NULL)
170             AND (m.user_home_ou             IS NULL OR uhoua.id IS NOT NULL)
171             -- Circ Type
172             AND (m.is_renewal               IS NULL OR m.is_renewal = renewal)
173             -- Static User Checks
174             AND (m.juvenile_flag            IS NULL OR m.juvenile_flag = user_object.juvenile)
175             AND (m.usr_age_lower_bound      IS NULL OR (user_age IS NOT NULL AND m.usr_age_lower_bound < user_age))
176             AND (m.usr_age_upper_bound      IS NULL OR (user_age IS NOT NULL AND m.usr_age_upper_bound > user_age))
177             -- Static Item Checks
178             AND (m.circ_modifier            IS NULL OR m.circ_modifier = item_object.circ_modifier)
179             AND (m.marc_type                IS NULL OR m.marc_type = COALESCE(item_object.circ_as_type, rec_descriptor.item_type))
180             AND (m.marc_form                IS NULL OR m.marc_form = rec_descriptor.item_form)
181             AND (m.marc_vr_format           IS NULL OR m.marc_vr_format = rec_descriptor.vr_format)
182             AND (m.ref_flag                 IS NULL OR m.ref_flag = item_object.ref)
183       ORDER BY
184             -- Permission Groups
185             CASE WHEN upgad.distance        IS NOT NULL THEN 2^(2*weights.grp - (upgad.distance/denominator)) ELSE 0 END +
186             -- Org Units
187             CASE WHEN ctoua.distance        IS NOT NULL THEN 2^(2*weights.org_unit - (ctoua.distance/denominator)) ELSE 0 END +
188             CASE WHEN cnoua.distance        IS NOT NULL THEN 2^(2*weights.copy_owning_lib - (cnoua.distance/denominator)) ELSE 0 END +
189             CASE WHEN iooua.distance        IS NOT NULL THEN 2^(2*weights.copy_circ_lib - (iooua.distance/denominator)) ELSE 0 END +
190             CASE WHEN uhoua.distance        IS NOT NULL THEN 2^(2*weights.user_home_ou - (uhoua.distance/denominator)) ELSE 0 END +
191             -- Circ Type                    -- Note: 4^x is equiv to 2^(2*x)
192             CASE WHEN m.is_renewal          IS NOT NULL THEN 4^weights.is_renewal ELSE 0 END +
193             -- Static User Checks
194             CASE WHEN m.juvenile_flag       IS NOT NULL THEN 4^weights.juvenile_flag ELSE 0 END +
195             CASE WHEN m.usr_age_lower_bound IS NOT NULL THEN 4^weights.usr_age_lower_bound ELSE 0 END +
196             CASE WHEN m.usr_age_upper_bound IS NOT NULL THEN 4^weights.usr_age_upper_bound ELSE 0 END +
197             -- Static Item Checks
198             CASE WHEN m.circ_modifier       IS NOT NULL THEN 4^weights.circ_modifier ELSE 0 END +
199             CASE WHEN m.marc_type           IS NOT NULL THEN 4^weights.marc_type ELSE 0 END +
200             CASE WHEN m.marc_form           IS NOT NULL THEN 4^weights.marc_form ELSE 0 END +
201             CASE WHEN m.marc_vr_format      IS NOT NULL THEN 4^weights.marc_vr_format ELSE 0 END +
202             CASE WHEN m.ref_flag            IS NOT NULL THEN 4^weights.ref_flag ELSE 0 END DESC,
203             -- Final sort on id, so that if two rules have the same sorting in the previous sort they have a defined order
204             -- This prevents "we changed the table order by updating a rule, and we started getting different results"
205             m.id;
206
207     -- Return the entire matchpoint
208     RETURN matchpoint;
209 END;
210 $func$ LANGUAGE plpgsql;
211
212 CREATE OR REPLACE FUNCTION action.find_hold_matrix_matchpoint(pickup_ou integer, request_ou integer, match_item bigint, match_user integer, match_requestor integer)
213   RETURNS integer AS
214 $func$
215 DECLARE
216     requestor_object    actor.usr%ROWTYPE;
217     user_object         actor.usr%ROWTYPE;
218     item_object         asset.copy%ROWTYPE;
219     item_cn_object      asset.call_number%ROWTYPE;
220     rec_descriptor      metabib.rec_descriptor%ROWTYPE;
221     matchpoint          config.hold_matrix_matchpoint%ROWTYPE;
222     weights             config.hold_matrix_weights%ROWTYPE;
223     denominator         INT;
224 BEGIN
225     SELECT INTO user_object         * FROM actor.usr                WHERE id = match_user;
226     SELECT INTO requestor_object    * FROM actor.usr                WHERE id = match_requestor;
227     SELECT INTO item_object         * FROM asset.copy               WHERE id = match_item;
228     SELECT INTO item_cn_object      * FROM asset.call_number        WHERE id = item_object.call_number;
229     SELECT INTO rec_descriptor      * FROM metabib.rec_descriptor   WHERE record = item_cn_object.record;
230
231     -- The item's owner should probably be the one determining if the item is holdable
232     -- How to decide that is debatable. Decided to default to the circ library (where the item lives)
233     -- This flag will allow for setting it to the owning library (where the call number "lives")
234     PERFORM * FROM config.internal_flag WHERE name = 'circ.holds.weight_owner_not_circ' AND enabled;
235
236     -- Grab the closest set circ weight setting.
237     IF NOT FOUND THEN
238         -- Default to circ library
239         SELECT INTO weights hw.*
240           FROM config.weight_assoc wa
241                JOIN config.hold_matrix_weights hw ON (hw.id = wa.hold_weights)
242                JOIN actor.org_unit_ancestors_distance( item_object.circ_lib ) d ON (wa.org_unit = d.id)
243           WHERE active
244           ORDER BY d.distance
245           LIMIT 1;
246     ELSE
247         -- Flag is set, use owning library
248         SELECT INTO weights hw.*
249           FROM config.weight_assoc wa
250                JOIN config.hold_matrix_weights hw ON (hw.id = wa.hold_weights)
251                JOIN actor.org_unit_ancestors_distance( cn_object.owning_lib ) d ON (wa.org_unit = d.id)
252           WHERE active
253           ORDER BY d.distance
254           LIMIT 1;
255     END IF;
256
257     -- No weights? Bad admin! Defaults to handle that anyway.
258     IF weights.id IS NULL THEN
259         weights.user_home_ou    := 5;
260         weights.request_ou      := 5;
261         weights.pickup_ou       := 5;
262         weights.item_owning_ou  := 5;
263         weights.item_circ_ou    := 5;
264         weights.usr_grp         := 7;
265         weights.requestor_grp   := 8;
266         weights.circ_modifier   := 4;
267         weights.marc_type       := 3;
268         weights.marc_form       := 2;
269         weights.marc_vr_format  := 1;
270         weights.juvenile_flag   := 4;
271         weights.ref_flag        := 0;
272     END IF;
273
274     -- Determine the max (expected) depth (+1) of the org tree and max depth of the permisson tree
275     -- If you break your org tree with funky parenting this may be wrong
276     -- Note: This CTE is duplicated in the find_circ_matrix_matchpoint function, and it may be a good idea to split it off to a function
277     -- We use one denominator for all tree-based checks for when permission groups and org units have the same weighting
278     WITH all_distance(distance) AS (
279             SELECT depth AS distance FROM actor.org_unit_type
280         UNION
281             SELECT distance AS distance FROM permission.grp_ancestors_distance((SELECT id FROM permission.grp_tree WHERE parent IS NULL))
282         )
283     SELECT INTO denominator MAX(distance) + 1 FROM all_distance;
284
285     -- To ATTEMPT to make this work like it used to, make it reverse the user/requestor profile ids.
286     -- This may be better implemented as part of the upgrade script?
287     -- Set usr_grp = requestor_grp, requestor_grp = 1 or something when this flag is already set
288     -- Then remove this flag, of course.
289     PERFORM * FROM config.internal_flag WHERE name = 'circ.holds.usr_not_requestor' AND enabled;
290
291     IF FOUND THEN
292         -- Note: This, to me, is REALLY hacky. I put it in anyway.
293         -- If you can't tell, this is a single call swap on two variables.
294         SELECT INTO user_object.profile, requestor_object.profile
295                     requestor_object.profile, user_object.profile;
296     END IF;
297
298     -- Select the winning matchpoint into the matchpoint variable for returning
299     SELECT INTO matchpoint m.*
300       FROM  config.hold_matrix_matchpoint m
301             /*LEFT*/ JOIN permission.grp_ancestors_distance( requestor_object.profile ) rpgad ON m.requestor_grp = rpgad.id
302             LEFT JOIN permission.grp_ancestors_distance( user_object.profile ) upgad ON m.usr_grp = upgad.id
303             LEFT JOIN actor.org_unit_ancestors_distance( pickup_ou ) puoua ON m.pickup_ou = puoua.id
304             LEFT JOIN actor.org_unit_ancestors_distance( request_ou ) rqoua ON m.request_ou = rqoua.id
305             LEFT JOIN actor.org_unit_ancestors_distance( item_cn_object.owning_lib ) cnoua ON m.item_owning_ou = cnoua.id
306             LEFT JOIN actor.org_unit_ancestors_distance( item_object.circ_lib ) iooua ON m.item_circ_ou = iooua.id
307             LEFT JOIN actor.org_unit_ancestors_distance( user_object.home_ou  ) uhoua ON m.user_home_ou = uhoua.id
308       WHERE m.active
309             -- Permission Groups
310          -- AND (m.requestor_grp        IS NULL OR upgad.id IS NOT NULL) -- Optional Requestor Group?
311             AND (m.usr_grp              IS NULL OR upgad.id IS NOT NULL)
312             -- Org Units
313             AND (m.pickup_ou            IS NULL OR (puoua.id IS NOT NULL AND (puoua.distance = 0 OR NOT m.strict_ou_match)))
314             AND (m.request_ou           IS NULL OR (rqoua.id IS NOT NULL AND (rqoua.distance = 0 OR NOT m.strict_ou_match)))
315             AND (m.item_owning_ou       IS NULL OR (cnoua.id IS NOT NULL AND (cnoua.distance = 0 OR NOT m.strict_ou_match)))
316             AND (m.item_circ_ou         IS NULL OR (iooua.id IS NOT NULL AND (iooua.distance = 0 OR NOT m.strict_ou_match)))
317             AND (m.user_home_ou         IS NULL OR (uhoua.id IS NOT NULL AND (uhoua.distance = 0 OR NOT m.strict_ou_match)))
318             -- Static User Checks
319             AND (m.juvenile_flag        IS NULL OR m.juvenile_flag = user_object.juvenile)
320             -- Static Item Checks
321             AND (m.circ_modifier        IS NULL OR m.circ_modifier = item_object.circ_modifier)
322             AND (m.marc_type            IS NULL OR m.marc_type = COALESCE(item_object.circ_as_type, rec_descriptor.item_type))
323             AND (m.marc_form            IS NULL OR m.marc_form = rec_descriptor.item_form)
324             AND (m.marc_vr_format       IS NULL OR m.marc_vr_format = rec_descriptor.vr_format)
325             AND (m.ref_flag             IS NULL OR m.ref_flag = item_object.ref)
326       ORDER BY
327             -- Permission Groups
328             CASE WHEN rpgad.distance    IS NOT NULL THEN 2^(2*weights.requestor_grp - (rpgad.distance/denominator)) ELSE 0 END +
329             CASE WHEN upgad.distance    IS NOT NULL THEN 2^(2*weights.usr_grp - (upgad.distance/denominator)) ELSE 0 END +
330             -- Org Units
331             CASE WHEN puoua.distance    IS NOT NULL THEN 2^(2*weights.pickup_ou - (puoua.distance/denominator)) ELSE 0 END +
332             CASE WHEN rqoua.distance    IS NOT NULL THEN 2^(2*weights.request_ou - (rqoua.distance/denominator)) ELSE 0 END +
333             CASE WHEN cnoua.distance    IS NOT NULL THEN 2^(2*weights.item_owning_ou - (cnoua.distance/denominator)) ELSE 0 END +
334             CASE WHEN iooua.distance    IS NOT NULL THEN 2^(2*weights.item_circ_ou - (iooua.distance/denominator)) ELSE 0 END +
335             CASE WHEN uhoua.distance    IS NOT NULL THEN 2^(2*weights.user_home_ou - (uhoua.distance/denominator)) ELSE 0 END +
336             -- Static User Checks       -- Note: 4^x is equiv to 2^(2*x)
337             CASE WHEN m.juvenile_flag   IS NOT NULL THEN 4^weights.juvenile_flag ELSE 0 END +
338             -- Static Item Checks
339             CASE WHEN m.circ_modifier   IS NOT NULL THEN 4^weights.circ_modifier ELSE 0 END +
340             CASE WHEN m.marc_type       IS NOT NULL THEN 4^weights.marc_type ELSE 0 END +
341             CASE WHEN m.marc_form       IS NOT NULL THEN 4^weights.marc_form ELSE 0 END +
342             CASE WHEN m.marc_vr_format  IS NOT NULL THEN 4^weights.marc_vr_format ELSE 0 END +
343             CASE WHEN m.ref_flag        IS NOT NULL THEN 4^weights.ref_flag ELSE 0 END DESC,
344             -- Final sort on id, so that if two rules have the same sorting in the previous sort they have a defined order
345             -- This prevents "we changed the table order by updating a rule, and we started getting different results"
346             m.id;
347
348     -- Return just the ID for now
349     RETURN matchpoint.id;
350 END;
351 $func$ LANGUAGE 'plpgsql';
352
353 INSERT INTO config.circ_matrix_weights(name, org_unit, grp, circ_modifier, marc_type, marc_form, 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 
354     ('Default', 10.0, 11.0, 5.0, 4.0, 3.0, 2.0, 8.0, 8.0, 8.0, 1.0, 6.0, 7.0, 0.0, 0.0),
355     ('Org_Unit_First', 11.0, 10.0, 5.0, 4.0, 3.0, 2.0, 8.0, 8.0, 8.0, 1.0, 6.0, 7.0, 0.0, 0.0),
356     ('Item_Owner_First', 8.0, 8.0, 5.0, 4.0, 3.0, 2.0, 10.0, 11.0, 8.0, 1.0, 6.0, 7.0, 0.0, 0.0),
357     ('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);
358
359 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_vr_format, juvenile_flag, ref_flag) VALUES
360     ('Default', 5.0, 5.0, 5.0, 5.0, 5.0, 7.0, 8.0, 4.0, 3.0, 2.0, 1.0, 4.0, 0.0),
361     ('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, 4.0, 0.0),
362     ('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, 4.0, 0.0),
363     ('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);
364
365 INSERT INTO config.weight_assoc(active, org_unit, circ_weights, hold_weights) VALUES
366     (true, 1, 1, 1);
367
368 COMMIT;