168 lines
4.4 KiB
PL/PgSQL
168 lines
4.4 KiB
PL/PgSQL
-- Add an atomic usage-record deletion path. The operation restores the
|
|
-- entitlement period and reflows stored balance snapshots for later rows.
|
|
|
|
CREATE FUNCTION condon.delete_usage_record(
|
|
p_usage_record_id uuid
|
|
)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
VOLATILE
|
|
SECURITY INVOKER
|
|
SET search_path = pg_catalog
|
|
AS $function$
|
|
DECLARE
|
|
v_usage condon.usage_records%ROWTYPE;
|
|
v_period condon.entitlement_periods%ROWTYPE;
|
|
v_initial_balance integer;
|
|
v_now timestamptz := pg_catalog.clock_timestamp();
|
|
BEGIN
|
|
IF p_usage_record_id IS NULL THEN
|
|
RAISE EXCEPTION USING
|
|
ERRCODE = '22023',
|
|
MESSAGE = 'CONDON_USAGE_RECORD_ID_REQUIRED';
|
|
END IF;
|
|
|
|
SELECT *
|
|
INTO v_usage
|
|
FROM condon.usage_records
|
|
WHERE id = p_usage_record_id
|
|
FOR UPDATE;
|
|
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION USING
|
|
ERRCODE = 'P0002',
|
|
MESSAGE = 'CONDON_USAGE_RECORD_NOT_FOUND';
|
|
END IF;
|
|
|
|
SELECT *
|
|
INTO v_period
|
|
FROM condon.entitlement_periods
|
|
WHERE id = v_usage.entitlement_period_id
|
|
FOR UPDATE;
|
|
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION USING
|
|
ERRCODE = 'P0002',
|
|
MESSAGE = 'CONDON_ENTITLEMENT_PERIOD_NOT_FOUND';
|
|
END IF;
|
|
|
|
DELETE FROM condon.entitlement_ledger
|
|
WHERE usage_record_id = v_usage.id;
|
|
|
|
DELETE FROM condon.usage_records
|
|
WHERE id = v_usage.id;
|
|
|
|
v_initial_balance := v_period.annual_grant + v_period.carry_forward;
|
|
|
|
WITH ordered AS (
|
|
SELECT
|
|
ur.id,
|
|
(
|
|
v_initial_balance
|
|
- COALESCE(
|
|
SUM(ur.use_nights) OVER (
|
|
ORDER BY
|
|
CASE WHEN ur.source_sheet IS NULL THEN 1 ELSE 0 END,
|
|
ur.source_sheet NULLS LAST,
|
|
ur.source_sequence NULLS LAST,
|
|
ur.source_row NULLS LAST,
|
|
ur.created_at ASC,
|
|
ur.id ASC
|
|
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
|
|
),
|
|
0
|
|
)
|
|
)::integer AS balance_before,
|
|
(
|
|
v_initial_balance
|
|
- SUM(ur.use_nights) OVER (
|
|
ORDER BY
|
|
CASE WHEN ur.source_sheet IS NULL THEN 1 ELSE 0 END,
|
|
ur.source_sheet NULLS LAST,
|
|
ur.source_sequence NULLS LAST,
|
|
ur.source_row NULLS LAST,
|
|
ur.created_at ASC,
|
|
ur.id ASC
|
|
)
|
|
)::integer AS balance_after
|
|
FROM condon.usage_records AS ur
|
|
WHERE ur.entitlement_period_id = v_period.id
|
|
)
|
|
UPDATE condon.usage_records AS ur
|
|
SET
|
|
balance_before = ordered.balance_before,
|
|
balance_after = ordered.balance_after
|
|
FROM ordered
|
|
WHERE ur.id = ordered.id;
|
|
|
|
WITH ordered AS (
|
|
SELECT
|
|
ur.id,
|
|
(
|
|
v_initial_balance
|
|
- COALESCE(
|
|
SUM(ur.use_nights) OVER (
|
|
ORDER BY
|
|
CASE WHEN ur.source_sheet IS NULL THEN 1 ELSE 0 END,
|
|
ur.source_sheet NULLS LAST,
|
|
ur.source_sequence NULLS LAST,
|
|
ur.source_row NULLS LAST,
|
|
ur.created_at ASC,
|
|
ur.id ASC
|
|
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
|
|
),
|
|
0
|
|
)
|
|
)::integer AS balance_before,
|
|
(
|
|
v_initial_balance
|
|
- SUM(ur.use_nights) OVER (
|
|
ORDER BY
|
|
CASE WHEN ur.source_sheet IS NULL THEN 1 ELSE 0 END,
|
|
ur.source_sheet NULLS LAST,
|
|
ur.source_sequence NULLS LAST,
|
|
ur.source_row NULLS LAST,
|
|
ur.created_at ASC,
|
|
ur.id ASC
|
|
)
|
|
)::integer AS balance_after
|
|
FROM condon.usage_records AS ur
|
|
WHERE ur.entitlement_period_id = v_period.id
|
|
)
|
|
UPDATE condon.entitlement_ledger AS ledger
|
|
SET
|
|
balance_before = ordered.balance_before,
|
|
balance_after = ordered.balance_after
|
|
FROM ordered
|
|
WHERE ledger.usage_record_id = ordered.id
|
|
AND ledger.entry_type = 'usage';
|
|
|
|
UPDATE condon.entitlement_periods
|
|
SET
|
|
current_balance = (
|
|
v_initial_balance
|
|
- COALESCE(
|
|
(
|
|
SELECT SUM(ur.use_nights)
|
|
FROM condon.usage_records AS ur
|
|
WHERE ur.entitlement_period_id = v_period.id
|
|
),
|
|
0
|
|
)
|
|
)::integer,
|
|
row_version = row_version + 1,
|
|
updated_at = v_now
|
|
WHERE id = v_period.id;
|
|
|
|
DELETE FROM condon.bookings AS booking
|
|
WHERE booking.confirmation_no = v_usage.confirmation_no
|
|
AND NOT EXISTS (
|
|
SELECT 1
|
|
FROM condon.usage_records AS ur
|
|
WHERE ur.confirmation_no = booking.confirmation_no
|
|
);
|
|
END;
|
|
$function$;
|
|
|
|
REVOKE ALL ON FUNCTION condon.delete_usage_record(uuid) FROM PUBLIC;
|