fix(admin): 恢复接单模板计价配置并统一成本价格链路

This commit is contained in:
yml2213
2026-11-02 17:57:49 +08:00
parent d871b93fde
commit a7bac9c1d8
27 changed files with 304 additions and 83 deletions
@@ -108,6 +108,7 @@ function buildWorkOrderPlan(
skuQuantity,
unitPriceFen,
fixedRewardAmount: Number(rule.reward_amount || 0),
pricingMode: rule.pricing_mode,
sharingEnabled: rule.sharing_enabled === true,
sharingAutoFromOrder: rule.sharing_auto_from_order === true,
sharingTotalQuantity: Number(rule.sharing_total_quantity || 1),
@@ -120,7 +121,7 @@ function buildWorkOrderPlan(
return {
skuQuantity,
unitPriceFen,
pricingMode: unitPriceFen > 0 ? 'unit' : 'fixed',
pricingMode: rule.pricing_mode === 'unit' ? 'unit' : 'fixed',
rewardAmount: pricing.rewardAmount,
sharingEnabled,
sharingTotalQuantity: sharingEnabled ? pricing.sharingTotalQuantity : 1,
@@ -27,7 +27,7 @@ import {
upsertWorkProductRule,
} from '../../repositories/worker-platform/work-product-rule-repo.js'
import type { WorkOrderRow, WorkProductRuleRow } from '../../repositories/worker-platform/types.js'
import { withTransaction } from '../../db/client.js'
import { query, withTransaction } from '../../db/client.js'
import {
archiveDeletedWorkOrderTemplateProduct,
assertWorkOrderTemplateCanEnable,
@@ -394,6 +394,34 @@ export async function saveAdminWorkProductRule(payload: JsonObject = {}) {
const incomingUnitPriceFen = normalizeAmountFen(payload.unitPrice ?? payload.unitPriceYuan, 0)
const existingRewardAmount = Number(existingRule?.reward_amount || 0)
const existingUnitPriceFen = Number(existingRule?.unit_price_fen || 0)
const rawPricingMode = String(payload.pricingMode ?? payload.pricing_mode ?? '').trim()
if (rawPricingMode && rawPricingMode !== 'fixed' && rawPricingMode !== 'unit') {
throw createHttpError('接单模板计价方式无效', {
statusCode: 400,
errorCode: 'work_product_rule_pricing_mode_invalid',
})
}
const existingPricingMode = existingRule?.pricing_mode === 'unit' ? 'unit' : 'fixed'
const pricingMode: 'fixed' | 'unit' =
rawPricingMode === 'unit' ? 'unit' : rawPricingMode === 'fixed' ? 'fixed' : existingPricingMode
let carriedPricingAmount =
existingPricingMode === 'unit' ? existingUnitPriceFen : existingRewardAmount
if (existingRule && pricingMode !== existingPricingMode) {
const activeCostResult = await query<{ amount_fen: number }>(
`SELECT amount_fen
FROM cost_versions
WHERE work_product_rule_id = $1
AND scope_type = 'rule'
AND status = 'active'
AND effective_from <= NOW()
AND (effective_to IS NULL OR effective_to > NOW())
ORDER BY effective_from DESC, id DESC
LIMIT 1`,
[existingRule.id],
)
const activeCostAmount = Number(activeCostResult.rows[0]?.amount_fen || 0)
if (activeCostAmount > 0) carriedPricingAmount = activeCostAmount
}
// 模板保存只维护业务配置。价格只能由商品与成本中心的统一命令写入。
if (
@@ -409,8 +437,18 @@ export async function saveAdminWorkProductRule(payload: JsonObject = {}) {
},
)
}
const rewardAmount = existingRewardAmount
const unitPriceFen = existingUnitPriceFen
const rewardAmount =
pricingMode !== existingPricingMode || !existingRule
? pricingMode === 'fixed'
? carriedPricingAmount
: 0
: existingRewardAmount
const unitPriceFen =
pricingMode !== existingPricingMode || !existingRule
? pricingMode === 'unit'
? carriedPricingAmount
: 0
: existingUnitPriceFen
const sharingEnabled = hasOwnPayload(payload, 'sharingEnabled')
? normalizeBoolean(payload.sharingEnabled, false)
: hasOwnPayload(payload, 'sharing_enabled')
@@ -431,12 +469,14 @@ export async function saveAdminWorkProductRule(payload: JsonObject = {}) {
hasConfiguredSharingValue(payload.sharingTotalQuantity ?? payload.sharing_total_quantity) ||
hasConfiguredSharingValue(payload.sharingUnitReward ?? payload.sharingUnitRewardYuan) ||
hasConfiguredSharingValue(payload.sharingTotalAmount ?? payload.sharingTotalAmountYuan)
const sharingAutoFromOrder = hasOwnPayload(payload, 'sharingAutoFromOrder')
const requestedSharingAutoFromOrder = hasOwnPayload(payload, 'sharingAutoFromOrder')
? normalizeBoolean(payload.sharingAutoFromOrder, false)
: hasOwnPayload(payload, 'sharing_auto_from_order')
? normalizeBoolean(payload.sharing_auto_from_order, false)
: (existingRule?.sharing_auto_from_order === true && !hasManualSharingConfig) ||
(!existingRule && sharingEnabled && unitPriceFen > 0 && !hasManualSharingConfig)
(!existingRule && sharingEnabled && pricingMode === 'unit' && !hasManualSharingConfig)
const sharingAutoFromOrder =
pricingMode === 'unit' && requestedSharingAutoFromOrder && !hasManualSharingConfig
const hasManualSharingQuantity = hasConfiguredSharingValue(
payload.sharingTotalQuantity ?? payload.sharing_total_quantity,
)
@@ -445,7 +485,7 @@ export async function saveAdminWorkProductRule(payload: JsonObject = {}) {
)
if (
sharingEnabled &&
unitPriceFen > 0 &&
pricingMode === 'unit' &&
!sharingAutoFromOrder &&
hasManualSharingQuantity !== hasManualSharingUnitReward
) {
@@ -525,6 +565,7 @@ export async function saveAdminWorkProductRule(payload: JsonObject = {}) {
autoCreate: normalizeBoolean(payload.autoCreate ?? payload.auto_create, true),
rewardAmount: finalRewardAmount,
unitPriceFen,
pricingMode,
// 商品规则不配置押金;工单创建后由运营按需手工填写。
requiredDepositAmount: 0,
depositThresholdAmount: 0,
@@ -585,6 +626,7 @@ export function resolveWorkOrderTemplateSyncPrice(input: {
skuQuantity,
unitPriceFen: Number(input.rule.unit_price_fen || 0),
fixedRewardAmount: Number(input.rule.reward_amount || 0),
pricingMode: input.rule.pricing_mode,
sharingEnabled: input.rule.sharing_enabled === true,
sharingAutoFromOrder: input.rule.sharing_auto_from_order === true,
sharingTotalQuantity: Number(input.rule.sharing_total_quantity || 1),
@@ -16,6 +16,7 @@ function rule(
sort_order: input.sort_order ?? 100,
unit_price_fen: input.unit_price_fen ?? 0,
reward_amount: input.reward_amount ?? 0,
pricing_mode: input.pricing_mode ?? 'fixed',
sharing_enabled: input.sharing_enabled ?? false,
sharing_total_quantity: input.sharing_total_quantity ?? 1,
sharing_unit_reward: input.sharing_unit_reward ?? 0,
@@ -231,6 +231,7 @@ export async function syncWorkerOrdersForSourceOrder(
skuQuantity,
unitPriceFen: Number(rule.unit_price_fen || 0),
fixedRewardAmount: Number(rule.reward_amount || 0),
pricingMode: rule.pricing_mode,
sharingEnabled: rule.sharing_enabled === true,
sharingAutoFromOrder: rule.sharing_auto_from_order === true,
sharingTotalQuantity: Number(rule.sharing_total_quantity || 1),
@@ -64,6 +64,7 @@ export function mapWorkProductRule(rule: WorkProductRuleRow | null | undefined)
autoCreate: Boolean(rule.auto_create),
rewardAmount: Number(rule.reward_amount || 0),
unitPriceFen: Number(rule.unit_price_fen || 0),
pricingMode: rule.pricing_mode === 'unit' ? 'unit' : 'fixed',
sharing: {
enabled: rule.sharing_enabled === true,
totalQuantity: Number(rule.sharing_total_quantity || 1),
@@ -745,6 +745,7 @@ function buildProductRule(overrides: Partial<WorkProductRuleRow> = {}): WorkProd
auto_create: true,
reward_amount: 2500,
unit_price_fen: 0,
pricing_mode: 'fixed',
required_deposit_amount: 0,
deposit_threshold_amount: 20000,
sharing_enabled: false,
@@ -1624,6 +1625,7 @@ test('按件拼单未手动覆盖时,使用匹配数量与模板单价', () =>
skuQuantity: 10,
unitPriceFen: 20,
fixedRewardAmount: 0,
pricingMode: 'unit',
sharingEnabled: true,
sharingAutoFromOrder: true,
sharingTotalQuantity: 1,
@@ -1642,6 +1644,7 @@ test('按件拼单手动覆盖数量和单价时,保留手工配置', () => {
skuQuantity: 10,
unitPriceFen: 20,
fixedRewardAmount: 0,
pricingMode: 'unit',
sharingEnabled: true,
sharingAutoFromOrder: false,
sharingTotalQuantity: 3,
@@ -1657,7 +1660,7 @@ test('按件拼单手动覆盖数量和单价时,保留手工配置', () => {
test('模板同步价格按工单来源规格重新计算普通按件单', () => {
const price = resolveWorkOrderTemplateSyncPrice({
rule: buildProductRule({ unit_price_fen: 200 }),
rule: buildProductRule({ unit_price_fen: 200, pricing_mode: 'unit' }),
workOrder: buildWorkOrderRow({
product_name: '指挥官秘钥15个',
material_json: { source: { skuQuantity: 8 } },
@@ -1667,10 +1670,39 @@ test('模板同步价格按工单来源规格重新计算普通按件单', () =>
assert.deepEqual(price, { rewardAmount: 1600 })
})
test('模板同步价格以显式计价方式为准,不按两个金额字段反推', () => {
const workOrder = buildWorkOrderRow({ product_name: '指挥官秘钥15个' })
assert.deepEqual(
resolveWorkOrderTemplateSyncPrice({
rule: buildProductRule({
reward_amount: 2500,
unit_price_fen: 200,
pricing_mode: 'fixed',
}),
workOrder,
}),
{ rewardAmount: 2500 },
)
assert.deepEqual(
resolveWorkOrderTemplateSyncPrice({
rule: buildProductRule({
reward_amount: 2500,
unit_price_fen: 200,
pricing_mode: 'unit',
}),
workOrder,
}),
{ rewardAmount: 3000 },
)
})
test('模板同步价格为拼单返回新的份额单价', () => {
const price = resolveWorkOrderTemplateSyncPrice({
rule: buildProductRule({
unit_price_fen: 200,
pricing_mode: 'unit',
sharing_enabled: true,
sharing_auto_from_order: true,
}),