feat(consignment): 确认加好友后现货作废不回池,撤销履约押金可选并结算打手押金
现货口径(严):已确认加好友 = 买家好友已加上、货随时可能送出去,回池会被下一个工单 再次占用(等于二次出货)。收口在 releaseConsignmentInventoryBindingForWorkOrderWithClient: 解绑前读工单 acceptance_mode/friend_added_at,命中则 archived + allow_matching=FALSE + 留痕, 否则仍回池。所有解绑路径自动继承,发单系统接口未动。 撤销寄售履约(寄卖专属入口)支持两笔押金各自可选,默认按规则自动: - 打手履约押金:auto / refund / forfeit - 卖家发布押金:auto / keep_frozen / forfeit 策略抽成 domain/consignment-deposit-policy.ts 纯函数;覆盖时原因照旧必填,选项与金额写进 工单事件便于对账。 顺带修掉两个 bug: 1. 撤销寄售履约从不结算打手履约押金——只清 assigned_worker_id、只处理卖家押金, worker_deposit 单撤销后打手押金永久冻结。现按选项结算(退还/没收)。 2. detachConsignmentMaterialFromWorkOrderWithClient 里 $1 既作 $1::text(detachedAt) 又赋值给 updated_at,Postgres 整体推断成 text → 42804。凡解绑现货摘寄售标记的路径 (取消指派/撤单/退单/售后/撤销履约/人工回库)在真实库上必然 500,假 client 单测抓不到。 已显式 ::timestamptz,并补类级静态护栏扫同类写法。 验证:真实库(全回滚)——已确认加好友解绑 → archived/allow_matching=false; 未确认 → 仍 in_stock;打手押金冻结 3000 → 退还 3000(重复结算 0)→ 再冻 2500 → 没收 2500 (可用余额不变、冻结归零、流水 deposit_deduction)。后端 432 例(新增 5 例)全绿。
This commit is contained in:
@@ -315,12 +315,18 @@ export default function WorkOrdersPanel() {
|
||||
order: WorkOrder | null
|
||||
action: 'reopen' | 'cancel_order' | 'archive_inventory'
|
||||
reason: string
|
||||
/** 打手履约押金处置:默认按规则自动,覆盖后必须填原因 */
|
||||
workerDeposit: 'auto' | 'refund' | 'forfeit'
|
||||
/** 卖家发布押金处置:默认按规则自动 */
|
||||
consignmentDeposit: 'auto' | 'keep_frozen' | 'forfeit'
|
||||
submitting: boolean
|
||||
}>({
|
||||
open: false,
|
||||
order: null,
|
||||
action: 'reopen',
|
||||
reason: '',
|
||||
workerDeposit: 'auto',
|
||||
consignmentDeposit: 'auto',
|
||||
submitting: false,
|
||||
})
|
||||
|
||||
@@ -820,6 +826,8 @@ export default function WorkOrdersPanel() {
|
||||
order: row,
|
||||
action: 'reopen',
|
||||
reason: '',
|
||||
workerDeposit: 'auto',
|
||||
consignmentDeposit: 'auto',
|
||||
submitting: false,
|
||||
})
|
||||
}
|
||||
@@ -836,13 +844,17 @@ export default function WorkOrdersPanel() {
|
||||
workOrderId: revokeConsignmentModal.order.workOrderId,
|
||||
action: revokeConsignmentModal.action,
|
||||
reason: revokeConsignmentModal.reason,
|
||||
workerDeposit: revokeConsignmentModal.workerDeposit,
|
||||
consignmentDeposit: revokeConsignmentModal.consignmentDeposit,
|
||||
})
|
||||
message.success('寄售履约已撤销!物品已退单回库,工单已更新')
|
||||
message.success('寄售履约已撤销,现货与押金已按所选方式处理')
|
||||
setRevokeConsignmentModal({
|
||||
open: false,
|
||||
order: null,
|
||||
action: 'reopen',
|
||||
reason: '',
|
||||
workerDeposit: 'auto',
|
||||
consignmentDeposit: 'auto',
|
||||
submitting: false,
|
||||
})
|
||||
await refreshAll()
|
||||
@@ -3078,6 +3090,8 @@ export default function WorkOrdersPanel() {
|
||||
order: null,
|
||||
action: 'reopen',
|
||||
reason: '',
|
||||
workerDeposit: 'auto',
|
||||
consignmentDeposit: 'auto',
|
||||
submitting: false,
|
||||
})
|
||||
}}
|
||||
@@ -3090,8 +3104,16 @@ export default function WorkOrdersPanel() {
|
||||
<Alert
|
||||
showIcon
|
||||
type="warning"
|
||||
message="撤销后,关联寄售物品将退单回库;物品的【允许匹配】开关保持原设置不变"
|
||||
description="只适用于【进行中 / 待验收 / 问题单】。已验收订单无法撤销(现货已交付、押金已结清),买家退款或纠纷请走售后流程。"
|
||||
message={
|
||||
revokeConsignmentModal.order?.gift?.friendAddedAt
|
||||
? '该单已确认加好友:撤销时现货一律作废下架,不会退回在库池'
|
||||
: '撤销后,关联寄售物品将退单回库;物品的【允许匹配】开关保持原设置不变'
|
||||
}
|
||||
description={
|
||||
revokeConsignmentModal.order?.gift?.friendAddedAt
|
||||
? '买家好友已经加上,货随时可能送出去,回池会被下一个工单再次占用(等于二次出货)。押金默认按「已确认加好友不退」处理,可在下方按需覆盖。'
|
||||
: '只适用于【进行中 / 待验收 / 问题单】。已验收订单无法撤销(现货已交付、押金已结清),买家退款或纠纷请走售后流程。'
|
||||
}
|
||||
style={{ marginBottom: 16 }}
|
||||
/>
|
||||
|
||||
@@ -3132,6 +3154,59 @@ export default function WorkOrdersPanel() {
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="打手履约押金">
|
||||
<Radio.Group
|
||||
value={revokeConsignmentModal.workerDeposit}
|
||||
onChange={(e) =>
|
||||
setRevokeConsignmentModal((prev) => ({ ...prev, workerDeposit: e.target.value }))
|
||||
}
|
||||
>
|
||||
<Space direction="vertical">
|
||||
<Radio value="auto">
|
||||
按规则自动
|
||||
<span style={{ fontSize: 12, color: '#8c8c8c' }}>
|
||||
(已确认加好友则扣除,否则全额退还)
|
||||
</span>
|
||||
</Radio>
|
||||
<Radio value="refund">全额退还打手</Radio>
|
||||
<Radio value="forfeit">全额扣除(押金不退)</Radio>
|
||||
</Space>
|
||||
</Radio.Group>
|
||||
{!revokeConsignmentModal.order?.worker ? (
|
||||
<div style={{ fontSize: 12, color: '#8c8c8c', marginTop: 4 }}>
|
||||
内部现货单没有接单打手,无需处理履约押金。
|
||||
</div>
|
||||
) : null}
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="卖家发布押金">
|
||||
<Radio.Group
|
||||
value={revokeConsignmentModal.consignmentDeposit}
|
||||
onChange={(e) =>
|
||||
setRevokeConsignmentModal((prev) => ({
|
||||
...prev,
|
||||
consignmentDeposit: e.target.value,
|
||||
}))
|
||||
}
|
||||
>
|
||||
<Space direction="vertical">
|
||||
<Radio value="auto">
|
||||
按规则自动
|
||||
<span style={{ fontSize: 12, color: '#8c8c8c' }}>
|
||||
(已确认加好友则没收;否则作废退还、回库保持冻结)
|
||||
</span>
|
||||
</Radio>
|
||||
<Radio value="keep_frozen">
|
||||
保留冻结
|
||||
<span style={{ fontSize: 12, color: '#8c8c8c' }}>
|
||||
(不退还也不没收,钱一直冻着,留给后续人工处理)
|
||||
</span>
|
||||
</Radio>
|
||||
<Radio value="forfeit">扣除没收(卖家押金不退)</Radio>
|
||||
</Space>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="撤单原因说明" required>
|
||||
<Input.TextArea
|
||||
rows={3}
|
||||
|
||||
Reference in New Issue
Block a user