bmc_hub/migrations/1043_prepaid_card_usage_alerts.sql

121 lines
5.4 KiB
MySQL
Raw Normal View History

-- Migration 1043: Idempotent accounting follow-up when prepaid cards reach 80% and 100% usage.
-- Existing card balances and transactions are left untouched.
CREATE TABLE IF NOT EXISTS tticket_prepaid_card_alerts (
id SERIAL PRIMARY KEY,
-- Keep the audit trail if an old card is later deleted.
card_id INTEGER NOT NULL,
alert_type VARCHAR(24) NOT NULL CHECK (alert_type IN ('usage_80_percent', 'usage_100_percent')),
case_id INTEGER REFERENCES sag_sager(id) ON DELETE SET NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE (card_id, alert_type)
);
CREATE INDEX IF NOT EXISTS idx_prepaid_card_alerts_case
ON tticket_prepaid_card_alerts(case_id) WHERE case_id IS NOT NULL;
CREATE OR REPLACE FUNCTION notify_prepaid_card_usage_threshold()
RETURNS TRIGGER AS $$
DECLARE
v_alert_id INTEGER;
v_case_id INTEGER;
v_group_id INTEGER;
v_customer_name TEXT;
BEGIN
IF COALESCE(NEW.purchased_hours, 0) <= 0 THEN
RETURN NEW;
END IF;
IF NEW.used_hours >= NEW.purchased_hours * 0.80 THEN
INSERT INTO tticket_prepaid_card_alerts (card_id, alert_type)
VALUES (NEW.id, 'usage_80_percent')
ON CONFLICT (card_id, alert_type) DO NOTHING
RETURNING id INTO v_alert_id;
IF v_alert_id IS NOT NULL THEN
SELECT id INTO v_group_id
FROM groups
WHERE LOWER(TRIM(name)) IN ('bogholderi', 'økonomi', 'okonomi', 'accounting')
ORDER BY CASE WHEN LOWER(TRIM(name)) = 'bogholderi' THEN 0 ELSE 1 END, id
LIMIT 1;
SELECT name INTO v_customer_name FROM customers WHERE id = NEW.customer_id;
INSERT INTO sag_sager (
titel, beskrivelse, type, template_key, status, customer_id,
assigned_group_id, created_by_user_id
) VALUES (
'Klippekort ' || NEW.card_number || ' har nået 80 %',
format('Klippekort %s for %s har brugt %.2f af %.2f timer (%.1f%%). Vurder om kunden skal tilbydes et nyt klippekort. Der er ikke oprettet en ordre eller et nyt klippekort automatisk.',
NEW.card_number, COALESCE(v_customer_name, 'kunden'), NEW.used_hours,
NEW.purchased_hours, NEW.used_hours / NEW.purchased_hours * 100),
'bogholderi', 'bogholderi', 'åben', NEW.customer_id,
v_group_id, (SELECT user_id FROM users ORDER BY user_id LIMIT 1)
) RETURNING id INTO v_case_id;
UPDATE tticket_prepaid_card_alerts SET case_id = v_case_id WHERE id = v_alert_id;
END IF;
END IF;
IF NEW.used_hours >= NEW.purchased_hours THEN
SELECT case_id INTO v_case_id
FROM tticket_prepaid_card_alerts
WHERE card_id = NEW.id AND alert_type = 'usage_80_percent';
IF v_case_id IS NULL THEN
-- Covers cards that were already above 80% when this migration was installed.
INSERT INTO tticket_prepaid_card_alerts (card_id, alert_type)
VALUES (NEW.id, 'usage_80_percent')
ON CONFLICT (card_id, alert_type) DO NOTHING
RETURNING id INTO v_alert_id;
IF v_alert_id IS NOT NULL THEN
SELECT id INTO v_group_id
FROM groups
WHERE LOWER(TRIM(name)) IN ('bogholderi', 'økonomi', 'okonomi', 'accounting')
ORDER BY CASE WHEN LOWER(TRIM(name)) = 'bogholderi' THEN 0 ELSE 1 END, id
LIMIT 1;
SELECT name INTO v_customer_name FROM customers WHERE id = NEW.customer_id;
INSERT INTO sag_sager (
titel, beskrivelse, type, template_key, status, customer_id,
assigned_group_id, created_by_user_id
) VALUES (
'Klippekort ' || NEW.card_number || ' har nået 80 %',
format('Klippekort %s for %s har nået fuldt forbrug. Vurder eventuelt nyt klippekort.',
NEW.card_number, COALESCE(v_customer_name, 'kunden')),
'bogholderi', 'bogholderi', 'åben', NEW.customer_id, v_group_id,
(SELECT user_id FROM users ORDER BY user_id LIMIT 1)
) RETURNING id INTO v_case_id;
UPDATE tticket_prepaid_card_alerts SET case_id = v_case_id WHERE id = v_alert_id;
END IF;
END IF;
INSERT INTO tticket_prepaid_card_alerts (card_id, alert_type, case_id)
VALUES (NEW.id, 'usage_100_percent', v_case_id)
ON CONFLICT (card_id, alert_type) DO NOTHING
RETURNING id INTO v_alert_id;
IF v_alert_id IS NOT NULL AND v_case_id IS NOT NULL THEN
INSERT INTO sag_kommentarer (sag_id, forfatter, indhold, er_system_besked)
VALUES (v_case_id, 'System',
format('Klippekort %s er nu fuldt brugt og er lukket for nyt forbrug.', NEW.card_number), TRUE);
END IF;
UPDATE tticket_prepaid_cards SET status = 'depleted', updated_at = CURRENT_TIMESTAMP
WHERE id = NEW.id AND status = 'active';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS trg_prepaid_card_usage_thresholds ON tticket_prepaid_cards;
CREATE TRIGGER trg_prepaid_card_usage_thresholds
AFTER UPDATE OF used_hours ON tticket_prepaid_cards
FOR EACH ROW
WHEN (NEW.used_hours IS DISTINCT FROM OLD.used_hours)
EXECUTE FUNCTION notify_prepaid_card_usage_threshold();
COMMENT ON TABLE tticket_prepaid_card_alerts IS
'One-time bookkeeping follow-up case references for prepaid card usage thresholds.';