121 lines
5.4 KiB
MySQL
121 lines
5.4 KiB
MySQL
|
|
-- 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.';
|