fix(finance): 重写履约路由迁移与统一渠道配置
重写 120/121 迁移,统一内部 SKU、渠道 id、config_json 和旧规则转换。 后台渠道配置改读统一渠道表,卡券与人工配置不再写旧规则。 增加安全渠道切换,并排除已关闭、失败或过期的历史任务载体。 按生产 119 基线重跑迁移、完整履约财务链路和严格预检。
This commit is contained in:
@@ -58,11 +58,7 @@ const CHANNEL_COLOR: Record<string, string> = {
|
||||
manual: 'orange',
|
||||
}
|
||||
|
||||
const MATCH_KEY_OPTIONS = [
|
||||
{ value: 'sku_code', label: '平台 SKU' },
|
||||
{ value: 'internal_sku', label: '内部 SKU' },
|
||||
{ value: 'sku_name', label: 'SKU 名称' },
|
||||
]
|
||||
const MATCH_KEY_OPTIONS = [{ value: 'internal_sku', label: '内部 SKU' }]
|
||||
|
||||
export default function AdminFulfillmentChannelPage() {
|
||||
return (
|
||||
@@ -214,7 +210,7 @@ function PendingPanel() {
|
||||
type="info"
|
||||
showIcon
|
||||
style={{ marginBottom: 12 }}
|
||||
message="待分类订单的收入已经计入「未分类」桶,不会丢失;指定渠道后会自动进入商品归一与成本核算。"
|
||||
message="指定渠道会写入该内部 SKU 的全局配置,并影响所有平台和店铺;系统会先确认载体创建成功,再进入商品归一与成本核算。"
|
||||
/>
|
||||
<PercentTable
|
||||
rowKey={(row) => rowKey(row)}
|
||||
@@ -259,8 +255,7 @@ function RulesPanel() {
|
||||
})
|
||||
|
||||
const columns = [
|
||||
{ title: '来源', dataIndex: 'provider', width: 120, render: (v: string) => v || '不限' },
|
||||
{ title: '店铺', dataIndex: 'shop_id', width: 140, render: (v: string) => v || '不限' },
|
||||
{ title: '作用范围', width: 110, render: () => <Tag color="blue">全局</Tag> },
|
||||
{
|
||||
title: '匹配键',
|
||||
dataIndex: 'match_key_type',
|
||||
@@ -303,7 +298,7 @@ function RulesPanel() {
|
||||
|
||||
return (
|
||||
<Card
|
||||
title={`渠道规则(${query.data?.data?.length ?? 0})`}
|
||||
title={`统一渠道配置(${query.data?.data?.length ?? 0})`}
|
||||
extra={
|
||||
<Space>
|
||||
<Button icon={<ReloadOutlined />} onClick={() => void query.refetch()}>
|
||||
@@ -316,8 +311,8 @@ function RulesPanel() {
|
||||
}
|
||||
>
|
||||
<Typography.Paragraph type="secondary">
|
||||
接单平台由接单模板匹配决定,不在此表维护;这里负责自动发货、人工、第三方卡券三个渠道与运营强制覆盖。
|
||||
同优先级命中多个渠道时订单保持待分类并进「配置冲突」。
|
||||
配置按内部 SKU 全局生效,会同时影响所有平台和店铺。每条内部 SKU 只能有一个主渠道;
|
||||
其他渠道请设置 90 以上优先级作为兜底。接单平台的具体模板由统一配置中的 workRuleKey 控制。
|
||||
</Typography.Paragraph>
|
||||
<PercentTable
|
||||
rowKey="id"
|
||||
@@ -329,7 +324,7 @@ function RulesPanel() {
|
||||
/>
|
||||
|
||||
<Modal
|
||||
title="新增渠道规则"
|
||||
title="新增统一渠道配置"
|
||||
open={open}
|
||||
onCancel={() => setOpen(false)}
|
||||
onOk={() => form.submit()}
|
||||
@@ -338,15 +333,13 @@ function RulesPanel() {
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
initialValues={{ matchKeyType: 'sku_code', channel: 'third_party_voucher', priority: 10 }}
|
||||
initialValues={{
|
||||
matchKeyType: 'internal_sku',
|
||||
channel: 'third_party_voucher',
|
||||
priority: 10,
|
||||
}}
|
||||
onFinish={(values) => saveMutation.mutate(values)}
|
||||
>
|
||||
<Form.Item name="provider" label="来源(留空=不限)">
|
||||
<Input placeholder="91kaquan / pdd / douyin_mashida" />
|
||||
</Form.Item>
|
||||
<Form.Item name="shopId" label="店铺(留空=不限)">
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item name="matchKeyType" label="匹配键" rules={[{ required: true }]}>
|
||||
<Select options={MATCH_KEY_OPTIONS} />
|
||||
</Form.Item>
|
||||
|
||||
@@ -24,9 +24,7 @@ export type PendingChannelGroupListResult = {
|
||||
/** 渠道规则(L1)。 */
|
||||
export type ChannelRule = {
|
||||
id: number
|
||||
provider: string
|
||||
shop_id: string
|
||||
match_key_type: 'sku_code' | 'internal_sku' | 'sku_name'
|
||||
match_key_type: 'internal_sku'
|
||||
match_key: string
|
||||
channel: 'work_order' | 'affiliate_dash' | 'third_party_voucher' | 'manual'
|
||||
priority: number
|
||||
@@ -117,14 +115,24 @@ export function assignChannelToItems(payload: {
|
||||
)
|
||||
}
|
||||
|
||||
export function switchChannelForItems(payload: {
|
||||
orderItemIds: number[]
|
||||
channel: string
|
||||
note?: string
|
||||
}) {
|
||||
return apiPost<{
|
||||
switched: number
|
||||
failed: number
|
||||
errors: Array<{ orderItemId: number; reason: string }>
|
||||
}>('/api/v1/admin/fulfillment/switch', payload)
|
||||
}
|
||||
|
||||
export function fetchChannelRules(params: { channel?: string } = {}) {
|
||||
return apiGet<ChannelRule[]>('/api/v1/admin/fulfillment/rules', params)
|
||||
}
|
||||
|
||||
export function saveChannelRule(payload: {
|
||||
id?: number
|
||||
provider?: string
|
||||
shopId?: string
|
||||
matchKeyType: string
|
||||
matchKey: string
|
||||
channel: string
|
||||
|
||||
Reference in New Issue
Block a user