]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/sql/Pg/upgrade/0579.schema.fix_checkout_overrides.sql
LP#1759238: stamping upgrade script
[Evergreen.git] / Open-ILS / src / sql / Pg / upgrade / 0579.schema.fix_checkout_overrides.sql
1 -- Evergreen DB patch 0579.schema.fix_checkout_overrides.sql
2 --
3 --
4 BEGIN;
5
6
7 -- check whether patch can be applied
8 SELECT evergreen.upgrade_deps_block_check('0579', :eg_version);
9
10 CREATE OR REPLACE FUNCTION action.item_user_circ_test( circ_ou INT, match_item BIGINT, match_user INT, renewal BOOL ) RETURNS SETOF action.circ_matrix_test_result AS $func$
11 DECLARE
12     user_object             actor.usr%ROWTYPE;
13     standing_penalty        config.standing_penalty%ROWTYPE;
14     item_object             asset.copy%ROWTYPE;
15     item_status_object      config.copy_status%ROWTYPE;
16     item_location_object    asset.copy_location%ROWTYPE;
17     result                  action.circ_matrix_test_result;
18     circ_test               action.found_circ_matrix_matchpoint;
19     circ_matchpoint         config.circ_matrix_matchpoint%ROWTYPE;
20     out_by_circ_mod         config.circ_matrix_circ_mod_test%ROWTYPE;
21     circ_mod_map            config.circ_matrix_circ_mod_test_map%ROWTYPE;
22     hold_ratio              action.hold_stats%ROWTYPE;
23     penalty_type            TEXT;
24     items_out               INT;
25     context_org_list        INT[];
26     done                    BOOL := FALSE;
27 BEGIN
28     -- Assume success unless we hit a failure condition
29     result.success := TRUE;
30
31     -- Need user info to look up matchpoints
32     SELECT INTO user_object * FROM actor.usr WHERE id = match_user AND NOT deleted;
33
34     -- (Insta)Fail if we couldn't find the user
35     IF user_object.id IS NULL THEN
36         result.fail_part := 'no_user';
37         result.success := FALSE;
38         done := TRUE;
39         RETURN NEXT result;
40         RETURN;
41     END IF;
42
43     -- Need item info to look up matchpoints
44     SELECT INTO item_object * FROM asset.copy WHERE id = match_item AND NOT deleted;
45
46     -- (Insta)Fail if we couldn't find the item 
47     IF item_object.id IS NULL THEN
48         result.fail_part := 'no_item';
49         result.success := FALSE;
50         done := TRUE;
51         RETURN NEXT result;
52         RETURN;
53     END IF;
54
55     SELECT INTO circ_test * FROM action.find_circ_matrix_matchpoint(circ_ou, item_object, user_object, renewal);
56
57     circ_matchpoint             := circ_test.matchpoint;
58     result.matchpoint           := circ_matchpoint.id;
59     result.circulate            := circ_matchpoint.circulate;
60     result.duration_rule        := circ_matchpoint.duration_rule;
61     result.recurring_fine_rule  := circ_matchpoint.recurring_fine_rule;
62     result.max_fine_rule        := circ_matchpoint.max_fine_rule;
63     result.hard_due_date        := circ_matchpoint.hard_due_date;
64     result.renewals             := circ_matchpoint.renewals;
65     result.grace_period         := circ_matchpoint.grace_period;
66     result.buildrows            := circ_test.buildrows;
67
68     -- (Insta)Fail if we couldn't find a matchpoint
69     IF circ_test.success = false THEN
70         result.fail_part := 'no_matchpoint';
71         result.success := FALSE;
72         done := TRUE;
73         RETURN NEXT result;
74         RETURN;
75     END IF;
76
77     -- All failures before this point are non-recoverable
78     -- Below this point are possibly overridable failures
79
80     -- Fail if the user is barred
81     IF user_object.barred IS TRUE THEN
82         result.fail_part := 'actor.usr.barred';
83         result.success := FALSE;
84         done := TRUE;
85         RETURN NEXT result;
86     END IF;
87
88     -- Fail if the item can't circulate
89     IF item_object.circulate IS FALSE THEN
90         result.fail_part := 'asset.copy.circulate';
91         result.success := FALSE;
92         done := TRUE;
93         RETURN NEXT result;
94     END IF;
95
96     -- Fail if the item isn't in a circulateable status on a non-renewal
97     IF NOT renewal AND item_object.status NOT IN ( 0, 7, 8 ) THEN 
98         result.fail_part := 'asset.copy.status';
99         result.success := FALSE;
100         done := TRUE;
101         RETURN NEXT result;
102     -- Alternately, fail if the item isn't checked out on a renewal
103     ELSIF renewal AND item_object.status <> 1 THEN
104         result.fail_part := 'asset.copy.status';
105         result.success := FALSE;
106         done := TRUE;
107         RETURN NEXT result;
108     END IF;
109
110     -- Fail if the item can't circulate because of the shelving location
111     SELECT INTO item_location_object * FROM asset.copy_location WHERE id = item_object.location;
112     IF item_location_object.circulate IS FALSE THEN
113         result.fail_part := 'asset.copy_location.circulate';
114         result.success := FALSE;
115         done := TRUE;
116         RETURN NEXT result;
117     END IF;
118
119     -- Apparently....use the circ matchpoint org unit to determine what org units are valid.
120     SELECT INTO context_org_list ARRAY_ACCUM(id) FROM actor.org_unit_full_path( circ_matchpoint.org_unit );
121
122     IF renewal THEN
123         penalty_type = '%RENEW%';
124     ELSE
125         penalty_type = '%CIRC%';
126     END IF;
127
128     FOR standing_penalty IN
129         SELECT  DISTINCT csp.*
130           FROM  actor.usr_standing_penalty usp
131                 JOIN config.standing_penalty csp ON (csp.id = usp.standing_penalty)
132           WHERE usr = match_user
133                 AND usp.org_unit IN ( SELECT * FROM unnest(context_org_list) )
134                 AND (usp.stop_date IS NULL or usp.stop_date > NOW())
135                 AND csp.block_list LIKE penalty_type LOOP
136
137         result.fail_part := standing_penalty.name;
138         result.success := FALSE;
139         done := TRUE;
140         RETURN NEXT result;
141     END LOOP;
142
143     -- Fail if the test is set to hard non-circulating
144     IF circ_matchpoint.circulate IS FALSE THEN
145         result.fail_part := 'config.circ_matrix_test.circulate';
146         result.success := FALSE;
147         done := TRUE;
148         RETURN NEXT result;
149     END IF;
150
151     -- Fail if the total copy-hold ratio is too low
152     IF circ_matchpoint.total_copy_hold_ratio IS NOT NULL THEN
153         SELECT INTO hold_ratio * FROM action.copy_related_hold_stats(match_item);
154         IF hold_ratio.total_copy_ratio IS NOT NULL AND hold_ratio.total_copy_ratio < circ_matchpoint.total_copy_hold_ratio THEN
155             result.fail_part := 'config.circ_matrix_test.total_copy_hold_ratio';
156             result.success := FALSE;
157             done := TRUE;
158             RETURN NEXT result;
159         END IF;
160     END IF;
161
162     -- Fail if the available copy-hold ratio is too low
163     IF circ_matchpoint.available_copy_hold_ratio IS NOT NULL THEN
164         IF hold_ratio.hold_count IS NULL THEN
165             SELECT INTO hold_ratio * FROM action.copy_related_hold_stats(match_item);
166         END IF;
167         IF hold_ratio.available_copy_ratio IS NOT NULL AND hold_ratio.available_copy_ratio < circ_matchpoint.available_copy_hold_ratio THEN
168             result.fail_part := 'config.circ_matrix_test.available_copy_hold_ratio';
169             result.success := FALSE;
170             done := TRUE;
171             RETURN NEXT result;
172         END IF;
173     END IF;
174
175     -- Fail if the user has too many items with specific circ_modifiers checked out
176     FOR out_by_circ_mod IN SELECT * FROM config.circ_matrix_circ_mod_test WHERE matchpoint = circ_matchpoint.id LOOP
177         SELECT  INTO items_out COUNT(*)
178           FROM  action.circulation circ
179             JOIN asset.copy cp ON (cp.id = circ.target_copy)
180           WHERE circ.usr = match_user
181                AND circ.circ_lib IN ( SELECT * FROM unnest(context_org_list) )
182             AND circ.checkin_time IS NULL
183             AND (circ.stop_fines IN ('MAXFINES','LONGOVERDUE') OR circ.stop_fines IS NULL)
184             AND cp.circ_modifier IN (SELECT circ_mod FROM config.circ_matrix_circ_mod_test_map WHERE circ_mod_test = out_by_circ_mod.id);
185         IF items_out >= out_by_circ_mod.items_out THEN
186             result.fail_part := 'config.circ_matrix_circ_mod_test';
187             result.success := FALSE;
188             done := TRUE;
189             RETURN NEXT result;
190         END IF;
191     END LOOP;
192
193     -- If we passed everything, return the successful matchpoint
194     IF NOT done THEN
195         RETURN NEXT result;
196     END IF;
197
198     RETURN;
199 END;
200 $func$ LANGUAGE plpgsql;
201
202
203 COMMIT;