-- Reserve each requested refund against its original, successful payment. -- A successful external refund can exceed the current wallet balance. alter table public.billing_wallets drop constraint if exists billing_wallets_balance_fen_check; alter table public.billing_ledger drop constraint if exists billing_ledger_balance_after_fen_check; alter table public.billing_ledger drop constraint if exists billing_ledger_kind_check; alter table public.billing_ledger add constraint billing_ledger_kind_check check (kind in ('recharge', 'charge', 'refund', 'adjustment', 'recharge_refund')); create table public.payment_refunds ( id text primary key check (length(id) between 1 and 32 and id ~ '^[A-Za-z0-9_-]+$'), order_id text not null references public.payment_orders(id) on delete restrict, organization_id text not null references public.platform_organizations(id) on delete restrict, operator_id text not null references public.platform_users(id) on delete restrict, request_key text not null check (length(request_key) between 1 and 64 and request_key ~ '^[A-Za-z0-9_-]+$'), mch_id text not null check (length(mch_id) between 1 and 64), transaction_id text not null check (length(transaction_id) > 0), provider_id text, amount_fen bigint not null check (amount_fen > 0), total_fen bigint not null check (total_fen > 0 and total_fen >= amount_fen), currency text not null check (currency = 'CNY'), reason text not null, status text not null default 'pending' check (status in ('pending', 'processing', 'success', 'closed', 'abnormal', 'rejected')), failure_reason text not null default '', created_at timestamptz not null default now(), updated_at timestamptz not null default now(), succeeded_at timestamptz, constraint payment_refunds_request_unique unique (order_id, request_key), constraint payment_refunds_success_check check ((status = 'success') = (succeeded_at is not null)) ); create unique index payment_refunds_provider_unique on public.payment_refunds(mch_id, provider_id) where provider_id is not null; create index payment_refunds_order_idx on public.payment_refunds(order_id, created_at desc, id desc); create index payment_refunds_pending_idx on public.payment_refunds(updated_at, created_at, id) where status in ('pending', 'processing', 'abnormal');