]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/sql/Pg/upgrade/xxxx.schema.emergency_closing_fines_fix.sql
f90a10f55614d539059899a5f6786fb903c3ff24
[Evergreen.git] / Open-ILS / src / sql / Pg / upgrade / xxxx.schema.emergency_closing_fines_fix.sql
1 BEGIN;
2
3 SELECT evergreen.upgrade_deps_block_check('xxxx', :eg_version);
4
5 CREATE OR REPLACE FUNCTION action.emergency_closing_stage_2_circ ( circ_closing_entry INT )
6     RETURNS BOOL AS $$
7 DECLARE
8     circ            action.circulation%ROWTYPE;
9     e_closing       action.emergency_closing%ROWTYPE;
10     e_c_circ        action.emergency_closing_circulation%ROWTYPE;
11     closing         actor.org_unit_closed%ROWTYPE;
12     adjacent        actor.org_unit_closed%ROWTYPE;
13     bill            money.billing%ROWTYPE;
14     last_bill       money.billing%ROWTYPE;
15     day_number      INT;
16     hoo_close       TIME WITHOUT TIME ZONE;
17     plus_days       INT;
18     avoid_negative  BOOL;
19     extend_grace    BOOL;
20     new_due_date    TEXT;
21 BEGIN
22     -- Gather objects involved
23     SELECT  * INTO e_c_circ
24       FROM  action.emergency_closing_circulation
25       WHERE id = circ_closing_entry;
26
27     IF e_c_circ.process_time IS NOT NULL THEN
28         -- Already processed ... moving on
29         RETURN FALSE;
30     END IF;
31
32     SELECT  * INTO e_closing
33       FROM  action.emergency_closing
34       WHERE id = e_c_circ.emergency_closing;
35
36     IF e_closing.process_start_time IS NULL THEN
37         -- Huh... that's odd. And wrong.
38         RETURN FALSE;
39     END IF;
40
41     SELECT  * INTO closing
42       FROM  actor.org_unit_closed
43       WHERE emergency_closing = e_closing.id;
44
45     SELECT  * INTO circ
46       FROM  action.circulation
47       WHERE id = e_c_circ.circulation;
48
49     -- Record the processing
50     UPDATE  action.emergency_closing_circulation
51       SET   original_due_date = circ.due_date,
52             process_time = NOW()
53       WHERE id = circ_closing_entry;
54
55     UPDATE  action.emergency_closing
56       SET   last_update_time = NOW()
57       WHERE id = e_closing.id;
58
59     SELECT value::BOOL INTO avoid_negative FROM actor.org_unit_ancestor_setting('bill.prohibit_negative_balance_on_overdues', circ.circ_lib);
60     SELECT value::BOOL INTO extend_grace FROM actor.org_unit_ancestor_setting('circ.grace.extend', circ.circ_lib);
61
62     new_due_date := evergreen.find_next_open_time( closing.org_unit, circ.due_date, EXTRACT(EPOCH FROM circ.duration)::INT % 86400 > 0 )::TEXT;
63     UPDATE action.circulation SET due_date = new_due_date::TIMESTAMPTZ WHERE id = circ.id;
64
65     -- Now, see if we need to get rid of some fines
66     SELECT  * INTO last_bill
67       FROM  money.billing b
68       WHERE b.xact = circ.id
69             AND NOT b.voided
70             AND b.btype = 1
71       ORDER BY billing_ts DESC
72       LIMIT 1;
73
74     FOR bill IN
75         SELECT  *
76           FROM  money.billing b
77           WHERE b.xact = circ.id
78                 AND b.btype = 1
79                 AND NOT b.voided
80                 AND (
81                     b.billing_ts BETWEEN closing.close_start AND new_due_date::TIMESTAMPTZ
82                     OR (extend_grace AND last_bill.billing_ts <= new_due_date::TIMESTAMPTZ + circ.grace_period)
83                 )
84                 AND NOT EXISTS (SELECT 1 FROM money.account_adjustment a WHERE a.billing = b.id)
85           ORDER BY billing_ts
86     LOOP
87         IF avoid_negative THEN
88             PERFORM FROM money.materialized_billable_xact_summary WHERE id = circ.id AND balance_owed < bill.amount;
89             EXIT WHEN FOUND; -- We can't go negative, and voiding this bill would do that...
90         END IF;
91
92         UPDATE  money.billing
93           SET   voided = TRUE,
94                 void_time = NOW(),
95                 note = COALESCE(note,'') || ' :: Voided by emergency closing handler'
96           WHERE id = bill.id;
97     END LOOP;
98     
99     RETURN TRUE;
100 END;
101 $$ LANGUAGE PLPGSQL;
102
103 CREATE OR REPLACE FUNCTION action.emergency_closing_stage_2_reservation ( res_closing_entry INT )
104     RETURNS BOOL AS $$
105 DECLARE
106     res             booking.reservation%ROWTYPE;
107     e_closing       action.emergency_closing%ROWTYPE;
108     e_c_res         action.emergency_closing_reservation%ROWTYPE;
109     closing         actor.org_unit_closed%ROWTYPE;
110     adjacent        actor.org_unit_closed%ROWTYPE;
111     bill            money.billing%ROWTYPE;
112     day_number      INT;
113     hoo_close       TIME WITHOUT TIME ZONE;
114     plus_days       INT;
115     avoid_negative  BOOL;
116     new_due_date    TEXT;
117 BEGIN
118     -- Gather objects involved
119     SELECT  * INTO e_c_res
120       FROM  action.emergency_closing_reservation
121       WHERE id = res_closing_entry;
122
123     IF e_c_res.process_time IS NOT NULL THEN
124         -- Already processed ... moving on
125         RETURN FALSE;
126     END IF;
127
128     SELECT  * INTO e_closing
129       FROM  action.emergency_closing
130       WHERE id = e_c_res.emergency_closing;
131
132     IF e_closing.process_start_time IS NULL THEN
133         -- Huh... that's odd. And wrong.
134         RETURN FALSE;
135     END IF;
136
137     SELECT  * INTO closing
138       FROM  actor.org_unit_closed
139       WHERE emergency_closing = e_closing.id;
140
141     SELECT  * INTO res
142       FROM  booking.reservation
143       WHERE id = e_c_res.reservation;
144
145     IF res.pickup_lib IS NULL THEN -- Need to be far enough along to have a pickup lib
146         RETURN FALSE;
147     END IF;
148
149     -- Record the processing
150     UPDATE  action.emergency_closing_reservation
151       SET   original_end_time = res.end_time,
152             process_time = NOW()
153       WHERE id = res_closing_entry;
154
155     UPDATE  action.emergency_closing
156       SET   last_update_time = NOW()
157       WHERE id = e_closing.id;
158
159     SELECT value::BOOL INTO avoid_negative FROM actor.org_unit_ancestor_setting('bill.prohibit_negative_balance_on_overdues', res.pickup_lib);
160
161     new_due_date := evergreen.find_next_open_time( closing.org_unit, res.end_time, EXTRACT(EPOCH FROM res.booking_interval)::INT % 86400 > 0 )::TEXT;
162     UPDATE booking.reservation SET end_time = new_due_date::TIMESTAMPTZ WHERE id = res.id;
163
164     -- Now, see if we need to get rid of some fines
165     FOR bill IN
166         SELECT  *
167           FROM  money.billing b
168           WHERE b.xact = res.id
169                 AND b.btype = 1
170                 AND NOT b.voided
171                 AND b.billing_ts BETWEEN closing.close_start AND new_due_date::TIMESTAMPTZ
172                 AND NOT EXISTS (SELECT 1 FROM money.account_adjustment a WHERE a.billing = b.id)
173     LOOP
174         IF avoid_negative THEN
175             PERFORM FROM money.materialized_billable_xact_summary WHERE id = res.id AND balance_owed < bill.amount;
176             EXIT WHEN FOUND; -- We can't go negative, and voiding this bill would do that...
177         END IF;
178
179         UPDATE  money.billing
180           SET   voided = TRUE,
181                 void_time = NOW(),
182                 note = COALESCE(note,'') || ' :: Voided by emergency closing handler'
183           WHERE id = bill.id;
184     END LOOP;
185     
186     RETURN TRUE;
187 END;
188 $$ LANGUAGE PLPGSQL;
189
190 COMMIT;
191