This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
import { Migration } from '@mikro-orm/migrations';
|
||||
|
||||
/**
|
||||
* Adds paid_amount, balance, refunded_amount on orders.
|
||||
* Values are maintained by PostgreSQL functions + triggers from payments / order.total.
|
||||
*
|
||||
* Definitions:
|
||||
* - paid_amount = SUM(payments.amount) WHERE status = 'paid' AND deleted_at IS NULL
|
||||
* - refunded_amount = SUM(payments.amount) WHERE status = 'refunded' AND deleted_at IS NULL
|
||||
* - balance = total - paid_amount (remaining amount due)
|
||||
*/
|
||||
export class Migration20260718093000_addOrderPaymentAmounts extends Migration {
|
||||
override async up(): Promise<void> {
|
||||
this.addSql(`
|
||||
alter table "orders"
|
||||
add column "paid_amount" numeric(10,0) not null default 0,
|
||||
add column "balance" numeric(10,0) not null default 0,
|
||||
add column "refunded_amount" numeric(10,0) not null default 0;
|
||||
`);
|
||||
|
||||
this.addSql(`
|
||||
create or replace function recalculate_order_payment_amounts(p_order_id char(26))
|
||||
returns void
|
||||
language plpgsql
|
||||
as $$
|
||||
declare
|
||||
v_paid numeric(10,0);
|
||||
v_refunded numeric(10,0);
|
||||
begin
|
||||
if p_order_id is null then
|
||||
return;
|
||||
end if;
|
||||
|
||||
select
|
||||
coalesce(sum(p.amount) filter (where p.status = 'paid'), 0),
|
||||
coalesce(sum(p.amount) filter (where p.status = 'refunded'), 0)
|
||||
into v_paid, v_refunded
|
||||
from payments p
|
||||
where p.order_id = p_order_id
|
||||
and p.deleted_at is null;
|
||||
|
||||
update orders o
|
||||
set
|
||||
paid_amount = v_paid,
|
||||
refunded_amount = v_refunded,
|
||||
balance = o.total - v_paid
|
||||
where o.id = p_order_id;
|
||||
end;
|
||||
$$;
|
||||
`);
|
||||
|
||||
this.addSql(`
|
||||
create or replace function trg_payments_recalculate_order_payment_amounts()
|
||||
returns trigger
|
||||
language plpgsql
|
||||
as $$
|
||||
begin
|
||||
if tg_op = 'DELETE' then
|
||||
perform recalculate_order_payment_amounts(old.order_id);
|
||||
return old;
|
||||
end if;
|
||||
|
||||
perform recalculate_order_payment_amounts(new.order_id);
|
||||
|
||||
if tg_op = 'UPDATE' and old.order_id is distinct from new.order_id then
|
||||
perform recalculate_order_payment_amounts(old.order_id);
|
||||
end if;
|
||||
|
||||
return new;
|
||||
end;
|
||||
$$;
|
||||
`);
|
||||
|
||||
this.addSql(`
|
||||
create trigger payments_recalculate_order_payment_amounts
|
||||
after insert or update of amount, status, order_id, deleted_at or delete
|
||||
on payments
|
||||
for each row
|
||||
execute procedure trg_payments_recalculate_order_payment_amounts();
|
||||
`);
|
||||
|
||||
this.addSql(`
|
||||
create or replace function trg_orders_sync_balance()
|
||||
returns trigger
|
||||
language plpgsql
|
||||
as $$
|
||||
begin
|
||||
new.balance := coalesce(new.total, 0) - coalesce(new.paid_amount, 0);
|
||||
return new;
|
||||
end;
|
||||
$$;
|
||||
`);
|
||||
|
||||
this.addSql(`
|
||||
create trigger orders_sync_balance
|
||||
before insert or update of total, paid_amount
|
||||
on orders
|
||||
for each row
|
||||
execute procedure trg_orders_sync_balance();
|
||||
`);
|
||||
|
||||
// Backfill existing rows: set balance from total, then recalc from payments
|
||||
this.addSql(`
|
||||
update orders
|
||||
set balance = total - paid_amount;
|
||||
`);
|
||||
|
||||
this.addSql(`
|
||||
do $$
|
||||
declare
|
||||
r record;
|
||||
begin
|
||||
for r in
|
||||
select distinct order_id
|
||||
from payments
|
||||
where deleted_at is null
|
||||
and status in ('paid', 'refunded')
|
||||
loop
|
||||
perform recalculate_order_payment_amounts(r.order_id);
|
||||
end loop;
|
||||
end;
|
||||
$$;
|
||||
`);
|
||||
}
|
||||
|
||||
override async down(): Promise<void> {
|
||||
this.addSql(`drop trigger if exists orders_sync_balance on orders;`);
|
||||
this.addSql(`drop trigger if exists payments_recalculate_order_payment_amounts on payments;`);
|
||||
this.addSql(`drop function if exists trg_orders_sync_balance();`);
|
||||
this.addSql(`drop function if exists trg_payments_recalculate_order_payment_amounts();`);
|
||||
this.addSql(`drop function if exists recalculate_order_payment_amounts(char(26));`);
|
||||
this.addSql(`
|
||||
alter table "orders"
|
||||
drop column "paid_amount",
|
||||
drop column "balance",
|
||||
drop column "refunded_amount";
|
||||
`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user