diff --git a/src/lib/wallet-transfer-actions.ts b/src/lib/wallet-transfer-actions.ts index 6df1ee8..cf3a756 100644 --- a/src/lib/wallet-transfer-actions.ts +++ b/src/lib/wallet-transfer-actions.ts @@ -11,7 +11,7 @@ export type TransferOrderActionRow = { }; export function canReverseTransferOrder(row: TransferOrderActionRow, canWriteWallet: boolean): boolean { - return canWriteWallet && (row.can_reverse ?? row.status === "pending_reconcile"); + return canWriteWallet && row.can_reverse === true; } export function canCompleteTransferInCredit(row: TransferOrderActionRow, canWriteWallet: boolean): boolean { diff --git a/src/modules/settlement/agent-bill-detail.tsx b/src/modules/settlement/agent-bill-detail.tsx index 488f97f..afb86b0 100644 --- a/src/modules/settlement/agent-bill-detail.tsx +++ b/src/modules/settlement/agent-bill-detail.tsx @@ -67,8 +67,23 @@ export function AgentBillDetail({ const [advancedOpen, setAdvancedOpen] = useState(false); const confirmRef = useRef(null); const paymentRef = useRef(null); + const paymentIdempotencyKeyRef = useRef(null); + const adjustmentIdempotencyKeyRef = useRef(null); const { request: requestConfirm, ConfirmDialog, busy: confirmBusy } = useConfirmAction(); + const createIdempotencyKey = useCallback((prefix: string): string => { + const random = + typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" + ? crypto.randomUUID() + : Math.random().toString(36).slice(2, 10); + return `${prefix}-${billId}-${Date.now()}-${random}`; + }, [billId]); + + useEffect(() => { + paymentIdempotencyKeyRef.current = null; + adjustmentIdempotencyKeyRef.current = null; + }, [billId]); + const load = useCallback(async () => { setLoading(true); setLoadErr(null); @@ -202,7 +217,10 @@ export function AgentBillDetail({ return; } - const idempotencyKey = `pay-${billId}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`; + if (!paymentIdempotencyKeyRef.current) { + paymentIdempotencyKeyRef.current = createIdempotencyKey("pay"); + } + const idempotencyKey = paymentIdempotencyKeyRef.current; requestConfirm({ title: t("settlementBills.paymentConfirmTitle", { defaultValue: "确认登记收付?" }), description: t("settlementBills.paymentConfirmDescription", { @@ -218,6 +236,7 @@ export function AgentBillDetail({ proof: payProof.trim() || undefined, idempotency_key: idempotencyKey, }); + paymentIdempotencyKeyRef.current = null; await load(); await onUpdated?.(); toast.success(t("settlementBills.paid", { defaultValue: "已登记收付" })); @@ -273,7 +292,10 @@ export function AgentBillDetail({ return; } - const idempotencyKey = `adj-${billId}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`; + if (!adjustmentIdempotencyKeyRef.current) { + adjustmentIdempotencyKeyRef.current = createIdempotencyKey("adj"); + } + const idempotencyKey = adjustmentIdempotencyKeyRef.current; requestConfirm({ title: t("settlementBills.adjustmentConfirmTitle", { defaultValue: "确认创建补差/冲正单?" }), description: t("settlementBills.adjustmentConfirmDescription", { @@ -289,6 +311,7 @@ export function AgentBillDetail({ reason, idempotency_key: idempotencyKey, }); + adjustmentIdempotencyKeyRef.current = null; setAdjustAmount(""); setAdjustReason(""); toast.success(t("settlementBills.adjustmentCreated", { defaultValue: "已创建补差单" }));