feat(finance): P2 手动退款登记与成本异常闭环

- 迁移 112:order_refunds(订单项级退款,整单拆多条共享 batch_no,source/external_ref 预留平台 API)+ cost_exceptions.resolution_note
- 新服务 order-refund-service:整单/指定商品退款、可退金额校验、撤销、全额退完同步 pay_status
- 销售事实改为按有效退款记录冲减;无记录时仍兼容 pay_status=refunded 的历史全额退款
- 订单详情新增退款登记与退款记录表,商品明细显示收入/已退/可退
- 全额退款自动关闭该订单项成本异常并写处理备注;成本异常处理改为带备注弹窗
- 财务事件 UNION 接入退款记录,文档同步 P2 状态与 API
This commit is contained in:
yml2213
2026-10-24 17:18:51 +08:00
parent a78cc1f984
commit faf56e567e
18 changed files with 1127 additions and 48 deletions
@@ -0,0 +1,36 @@
-- P2 退款冲减(手动录入先行,后续接平台退款 API)。
-- 一条记录 = 一个订单项的退款金额;整单退款会按订单项拆成多条,用 batch_no 归组。
CREATE TABLE IF NOT EXISTS order_refunds (
id bigserial PRIMARY KEY,
refund_no text NOT NULL UNIQUE,
batch_no text NOT NULL DEFAULT '',
order_id bigint NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
order_item_id bigint NOT NULL REFERENCES order_items(id) ON DELETE CASCADE,
amount_fen bigint NOT NULL CHECK (amount_fen > 0),
reason text NOT NULL DEFAULT '',
note text NOT NULL DEFAULT '',
source text NOT NULL DEFAULT 'manual' CHECK (source IN ('manual', 'api', 'platform', 'legacy')),
status text NOT NULL DEFAULT 'confirmed' CHECK (status IN ('confirmed', 'voided')),
refunded_at timestamp with time zone NOT NULL,
external_ref text NOT NULL DEFAULT '',
operator_admin_user_id bigint REFERENCES admin_users(id) ON DELETE SET NULL,
voided_at timestamp with time zone,
void_reason text NOT NULL DEFAULT '',
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_order_refunds_order
ON order_refunds (order_id, status);
CREATE INDEX IF NOT EXISTS idx_order_refunds_item
ON order_refunds (order_item_id, status);
CREATE INDEX IF NOT EXISTS idx_order_refunds_time
ON order_refunds (refunded_at DESC);
COMMENT ON TABLE order_refunds IS '订单退款记录:手动录入先行,后续平台退款 API 写 source=api/platform';
COMMENT ON COLUMN order_refunds.batch_no IS '同一次操作的分组号;整单退款会按订单项拆成多条';
-- 异常闭环备注:手动处理或退款自动关闭时记录原因。
ALTER TABLE cost_exceptions
ADD COLUMN IF NOT EXISTS resolution_note text NOT NULL DEFAULT '';