feat(finance): P1 人工商品归一,按内部 SKU 生成 man 商品并回填

- 新服务 manual-product-normalization-service:skuNick → outSkuSn → sku_code 兜底,按内部 SKU 生成 man:<sku> 商品
- 订单项按 id 分批(2 万/批)回填,避免 15s 语句超时;同步补齐人工成本快照的商品维度
- 新增 POST /cost-center/manual-products/normalize(支持 dryRun/日期窗口),成本中心「标准商品」加「归一人工商品」按钮
- 每日 cost_finance_sync 接入最近 N 天的增量归一
- 渠道映射未归一队列增加人工单提示:人工单不能用平台 sku_code 建映射
- 文档同步:P1 标记完成,补充归一接口契约与销售事实重算结果
This commit is contained in:
yml2213
2026-10-24 16:54:55 +08:00
parent e5122d116a
commit a78cc1f984
8 changed files with 425 additions and 7 deletions
@@ -3,11 +3,12 @@ import {
syncActualWorkOrderCostSnapshots,
syncEstimatedOrderItemCostSnapshots,
} from '../cost-center/cost-snapshot-sync-service.js'
import { normalizeManualProducts } from '../cost-center/manual-product-normalization-service.js'
import { rebuildSalesDailyFacts } from '../finance/sales-facts-service.js'
import { reconcilePendingFulfillmentModes } from '../fulfillment/fulfillment-mode-service.js'
/**
* 财务闭环同步:履约方式兜底 -> 预估成本快照 -> 工单实际快照 -> 销售事实重算。
* 财务闭环同步:履约方式兜底 -> 人工商品归一 -> 预估成本快照 -> 工单实际快照 -> 销售事实重算。
* 只处理最近 N 天,避免定时任务扫全量历史。
*/
export async function runCostFinanceSyncJob(job: JsonObject = {}) {
@@ -19,6 +20,12 @@ export async function runCostFinanceSyncJob(job: JsonObject = {}) {
maxBatches: 10,
reason: 'cost_finance_sync',
})
// 人工单按内部 SKU 归一;异常收口交给预估同步统一处理,这里只补商品维度。
const manualProducts = await normalizeManualProducts({
dateFrom: shiftDays(-(days - 1)),
dateTo: today(),
resolveExceptions: false,
})
const estimated = await syncEstimatedOrderItemCostSnapshots({
dateFrom: shiftDays(-(days - 1)),
@@ -37,12 +44,15 @@ export async function runCostFinanceSyncJob(job: JsonObject = {}) {
status: 'ok',
message:
`履约方式 ${fulfillment.updatedCount} 项 / ` +
`人工商品 ${manualProducts.updatedItemCount} 项 / ` +
`成本快照 ${estimated.createdCount} 商品预估 / ` +
`${actual.directRewardCount + actual.upgradedCount} 工单实际 / ` +
`${actual.estimatedRewardCount} 工单在途,销售事实 ${facts.insertedCount} 行`,
days,
fulfillmentModeUpdated: fulfillment.updatedCount,
fulfillmentModeRemaining: fulfillment.remainingCount,
manualItemsNormalized: manualProducts.updatedItemCount,
manualProductsCreated: manualProducts.createdProductCount,
estimatedCreated: estimated.createdCount,
actualCreated: actual.directRewardCount + actual.upgradedCount,
estimatedRewardCreated: actual.estimatedRewardCount,