feat(finance): 补齐自动发货与接单平台成本和对账
自动发货:价格导入支持 --effective-from,把首次基线版本回填到历史起点;41,676 个订单项全部归一并生成采购成本快照,缺失 0。\n\n接单平台:新增按工单 product_rule_id 回填商品的接口与按钮,长尾项按 provider+shop_id+sku_code+normalized_sku_name 补建 wo: 商品和 sku_code_name 渠道映射;118,053 个订单项全部归一。\n\n成本:已验收工单按 reward_amount 写 actual;未验收但已确定报酬的工单写 estimated,验收后升级。全量 95,870 actual + 21,217 estimated,actual 与 reward 0 差异。\n\n剩余 966 条取消/零报酬工单保留在成本异常队列,不自动记 0;人工块未改动。\n\n实测自动发货与接单平台未归一收入均为 0;整体未归一 79.67% 降至 57.54%,全部来自人工块。
This commit is contained in:
@@ -43,6 +43,7 @@ import {
|
||||
backfillAdminAffiliateDashSkus,
|
||||
backfillAdminNormalizedQuantities,
|
||||
backfillAdminProductMappings,
|
||||
backfillAdminWorkOrderProductSkus,
|
||||
createAdminChannelProductMapping,
|
||||
createAdminCostItem,
|
||||
createAdminCostSnapshot,
|
||||
@@ -368,6 +369,7 @@ export default function AdminCostCenterPage() {
|
||||
const [bootstrapApplying, setBootstrapApplying] = useState(false)
|
||||
const [syncingAffiliate, setSyncingAffiliate] = useState(false)
|
||||
const [backfillingAffiliateSkus, setBackfillingAffiliateSkus] = useState(false)
|
||||
const [backfillingWorkOrderSkus, setBackfillingWorkOrderSkus] = useState(false)
|
||||
const versionScopeType = Form.useWatch('scopeType', versionForm)
|
||||
const versionCostItemId = Form.useWatch('costItemId', versionForm)
|
||||
|
||||
@@ -694,6 +696,33 @@ export default function AdminCostCenterPage() {
|
||||
}
|
||||
}
|
||||
|
||||
async function backfillWorkOrderProducts() {
|
||||
setBackfillingWorkOrderSkus(true)
|
||||
try {
|
||||
const response = await backfillAdminWorkOrderProductSkus()
|
||||
const result = response.data
|
||||
const factsText = result.factsRebuild
|
||||
? `;已重算 ${result.factsRebuild.fromDate} ~ ${result.factsRebuild.toDate} 的销售事实`
|
||||
: ''
|
||||
const remainingText =
|
||||
result.remainingCount > 0
|
||||
? `;仍有 ${result.remainingCount} 个订单项没有可用的工单模板`
|
||||
: ''
|
||||
const tailText =
|
||||
result.tailUpdatedCount > 0
|
||||
? `,其中长尾商品 ${result.tailUpdatedCount} 个(新建商品 ${result.tailProductCount}、映射 ${result.tailMappingCount})`
|
||||
: ''
|
||||
message.success(
|
||||
`已按工单模板回填 ${result.updatedCount} 个订单项${tailText},${result.skippedCount} 个已一致${factsText}${remainingText}`,
|
||||
)
|
||||
refreshAll()
|
||||
} catch (error) {
|
||||
message.error(error instanceof Error ? error.message : '回填接单平台商品失败')
|
||||
} finally {
|
||||
setBackfillingWorkOrderSkus(false)
|
||||
}
|
||||
}
|
||||
|
||||
function openEditProduct(item: ProductCatalogItem) {
|
||||
setEditingProduct(item)
|
||||
productForm.setFieldsValue({
|
||||
@@ -1731,13 +1760,22 @@ export default function AdminCostCenterPage() {
|
||||
{canConfig ? (
|
||||
<>
|
||||
{activeCarrier === 'all' || activeCarrier === 'work_order' ? (
|
||||
<Button
|
||||
icon={<SyncOutlined />}
|
||||
loading={bootstrapPreviewing || bootstrapApplying}
|
||||
onClick={runTemplateBootstrap}
|
||||
>
|
||||
从接单模板初始化
|
||||
</Button>
|
||||
<>
|
||||
<Button
|
||||
icon={<SyncOutlined />}
|
||||
loading={bootstrapPreviewing || bootstrapApplying}
|
||||
onClick={runTemplateBootstrap}
|
||||
>
|
||||
从接单模板初始化
|
||||
</Button>
|
||||
<Button
|
||||
icon={<SyncOutlined />}
|
||||
loading={backfillingWorkOrderSkus}
|
||||
onClick={() => void backfillWorkOrderProducts()}
|
||||
>
|
||||
按工单回填商品
|
||||
</Button>
|
||||
</>
|
||||
) : null}
|
||||
{activeCarrier === 'all' || activeCarrier === 'affiliate_dash' ? (
|
||||
<Button
|
||||
|
||||
@@ -38,6 +38,27 @@ export function applyAdminTemplateProductBootstrap() {
|
||||
)
|
||||
}
|
||||
|
||||
export function backfillAdminWorkOrderProductSkus() {
|
||||
return apiPost<{
|
||||
updatedCount: number
|
||||
skippedCount: number
|
||||
remainingCount: number
|
||||
workOrderItemCount: number
|
||||
matchedCount: number
|
||||
ruleMatchedCount: number
|
||||
tailUpdatedCount: number
|
||||
tailProductCount: number
|
||||
tailMappingCount: number
|
||||
factsRebuild: {
|
||||
fromDate: string
|
||||
toDate: string
|
||||
deletedCount: number
|
||||
insertedCount: number
|
||||
batchCount: number
|
||||
} | null
|
||||
}>('/api/v1/admin/cost-center/work-order-products/backfill')
|
||||
}
|
||||
|
||||
export function fetchAdminProductCatalog(params?: Record<string, unknown>) {
|
||||
return apiGet<ProductCatalogListResult>('/api/v1/admin/cost-center/products', params)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user