fix(admin): 恢复接单模板计价配置并统一成本价格链路
This commit is contained in:
@@ -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,
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user