import { Migration } from '@mikro-orm/migrations'; export class Migration20260626140000 extends Migration { override async up(): Promise { this.addSql(` CREATE OR REPLACE FUNCTION recalc_invoice_totals() RETURNS TRIGGER AS $$ DECLARE v_invoice_id char(26); v_subtotal int; v_discount int; v_tax int; v_total int; v_paid int; v_enable_tax boolean; v_status text; BEGIN v_invoice_id := COALESCE(NEW.invoice_id, OLD.invoice_id); SELECT COALESCE(SUM(sub_total),0), COALESCE(SUM(discount),0) INTO v_subtotal, v_discount FROM invoice_items WHERE invoice_id = v_invoice_id AND deleted_at IS NULL AND confirmed_at IS NOT NULL; SELECT enable_tax INTO v_enable_tax FROM invoices WHERE id = v_invoice_id; IF v_enable_tax THEN v_tax := (v_subtotal - v_discount) * 0.10; ELSE v_tax := 0; END IF; v_total := (v_subtotal - v_discount) + v_tax; SELECT COALESCE(SUM(amount),0)::int INTO v_paid FROM payments WHERE invoice_id = v_invoice_id AND status = 'paid' AND deleted_at IS NULL; SELECT CASE WHEN NOT EXISTS ( SELECT 1 FROM invoice_items WHERE invoice_id = v_invoice_id AND deleted_at IS NULL AND confirmed_at IS NOT NULL ) THEN 'pending' WHEN NOT EXISTS ( SELECT 1 FROM invoice_items WHERE invoice_id = v_invoice_id AND deleted_at IS NULL AND confirmed_at IS NULL ) THEN 'confirmed' ELSE 'partially_confirmed' END INTO v_status; UPDATE invoices SET sub_total = v_subtotal, discount = v_discount, tax_amount = v_tax, total = v_total, paid_amount = v_paid, balance = v_total - v_paid, status = v_status WHERE id = v_invoice_id AND status <> 'archived'; RETURN NULL; END; $$ LANGUAGE plpgsql; `); this.addSql(` CREATE OR REPLACE FUNCTION recalc_invoice_payments() RETURNS TRIGGER AS $$ DECLARE v_invoice_id char(26); v_paid int; v_total int; BEGIN v_invoice_id := COALESCE(NEW.invoice_id, OLD.invoice_id); SELECT COALESCE(SUM(amount),0)::int INTO v_paid FROM payments WHERE invoice_id = v_invoice_id AND status = 'paid' AND deleted_at IS NULL; SELECT total INTO v_total FROM invoices WHERE id = v_invoice_id; UPDATE invoices SET paid_amount = v_paid, balance = v_total - v_paid WHERE id = v_invoice_id; RETURN NULL; END; $$ LANGUAGE plpgsql; `); this.addSql(`DROP TRIGGER IF EXISTS trg_invoice_items_recalc ON invoice_items;`); this.addSql(` CREATE TRIGGER trg_invoice_items_recalc AFTER INSERT OR UPDATE OR DELETE ON invoice_items FOR EACH ROW EXECUTE FUNCTION recalc_invoice_totals(); `); this.addSql(`DROP TRIGGER IF EXISTS trg_payments_recalc ON payments;`); this.addSql(` CREATE TRIGGER trg_payments_recalc AFTER INSERT OR UPDATE OR DELETE ON payments FOR EACH ROW EXECUTE FUNCTION recalc_invoice_payments(); `); this.addSql(` UPDATE invoice_items SET quantity = quantity WHERE deleted_at IS NULL; `); } override async down(): Promise { this.addSql(`DROP TRIGGER IF EXISTS trg_invoice_items_recalc ON invoice_items;`); this.addSql(`DROP TRIGGER IF EXISTS trg_payments_recalc ON payments;`); this.addSql(`DROP FUNCTION IF EXISTS recalc_invoice_totals();`); this.addSql(`DROP FUNCTION IF EXISTS recalc_invoice_payments();`); } }