feat(product-archive): 全量档案第二个成本价列改为结算价(模块化 ×0.9)
- 列与变更记录标签:成本价(新品)→ 结算价 / 结算价(新品),表头与导出同步生效 - 结算价在查询映射层实时计算:非模块化沿用成本价原样,模块化按 0.9 折 (先取整到分再打折、四舍五入保留两位);模块化以商品标签含「模块化」判断,不落库 - 修复列设置合并时 localStorage 旧 label 覆盖默认列名的问题:内置列名 一律以当前默认定义为准,改名对已保存列设置的用户才能生效
This commit is contained in:
parent
67834358d2
commit
46ca3bf786
@ -93,7 +93,7 @@ export const ARCHIVE_COLUMNS: ArchiveColumnGroup[] = [
|
||||
{ prop: 'priceType', label: '价格类型', width: 100 },
|
||||
{ prop: 'purchasePrice', label: '采购价', width: 90 },
|
||||
{ prop: 'costPrice', label: '成本价', width: 90 },
|
||||
{ prop: 'costPriceSecondary', label: '成本价', width: 90 },
|
||||
{ prop: 'costPriceSecondary', label: '结算价', width: 90 },
|
||||
{ prop: 'shipAmount', label: '发货金额', width: 100 },
|
||||
{ prop: 'returnAmount', label: '退货金额', width: 100 },
|
||||
{ prop: 'salesAmount', label: '销售金额', width: 100 },
|
||||
|
||||
@ -195,7 +195,8 @@ function loadSettings(): ColumnSetting[] {
|
||||
return dc
|
||||
? {
|
||||
...dc,
|
||||
label: typeof sc.label === 'string' && sc.label.trim() ? sc.label.trim() : dc.label,
|
||||
// 内置列的 label 以当前默认定义为准:列名是字典口径不是用户偏好,
|
||||
// 否则改名(如「成本价」→「结算价」)会被 localStorage 里的旧值盖住。
|
||||
width: Number.isFinite(sc.width) && sc.width > 0 ? sc.width : dc.width,
|
||||
visible: sc.visible !== false,
|
||||
}
|
||||
|
||||
@ -59,7 +59,7 @@ export const PRODUCT_ARCHIVE_CHANGE_FIELDS = [
|
||||
{ key: 'stockFactory', label: '工厂库存' },
|
||||
{ key: 'purchasePrice', label: '采购价' },
|
||||
{ key: 'costPrice', label: '成本价(聚水潭)' },
|
||||
{ key: 'costPriceSecondary', label: '成本价(新品)' },
|
||||
{ key: 'costPriceSecondary', label: '结算价(新品)' },
|
||||
] as const
|
||||
|
||||
export type ProductArchiveChangeFieldKey =
|
||||
|
||||
@ -2,6 +2,7 @@ import {
|
||||
resolveProductArchiveWarehouseFields,
|
||||
SupplyChainProductArchiveService,
|
||||
} from '../supply-chain-product-archive.service'
|
||||
import { settlementPriceText } from '../supply-chain-product-archive.mapper'
|
||||
import { calculateJstPublicAvailableStock } from '@/lib/supply-chain-product-archive-inventory'
|
||||
import {
|
||||
calculateProductArchiveVolume,
|
||||
@ -197,9 +198,21 @@ describe('supply-chain product archive field mapping', () => {
|
||||
stockJianshang: '60',
|
||||
purchasePrice: '88.50',
|
||||
costPrice: '76.20',
|
||||
costPriceSecondary: '72.30',
|
||||
costPriceSecondary: '76.20',
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('derives the settlement price from the cost price and modular product tag', () => {
|
||||
expect(settlementPriceText('76.20', '模块化成品,预估尺寸')).toBe('68.58')
|
||||
expect(settlementPriceText('76.20', '模块化部件,简尚-崔桥工厂半成品包装项目仓')).toBe('68.58')
|
||||
expect(settlementPriceText('123.45', '模块化成品')).toBe('111.11')
|
||||
expect(settlementPriceText('85', '模块化部件')).toBe('76.50')
|
||||
expect(settlementPriceText('76.20', '1688一件代发,已匹配')).toBe('76.20')
|
||||
expect(settlementPriceText('76.20', '')).toBe('76.20')
|
||||
expect(settlementPriceText('', '模块化成品')).toBe('')
|
||||
expect(settlementPriceText(null, '模块化成品')).toBe('')
|
||||
expect(settlementPriceText('abc', '模块化成品')).toBe('')
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
@ -37,6 +37,26 @@ function percentageText(
|
||||
return value ? `${value.mul(100).toFixed(2)}%` : ''
|
||||
}
|
||||
|
||||
// 结算价展示口径(2026-10-14 用户确认):结算价 = 成本价 × 系数,非模块化 ×1
|
||||
// 原样展示,模块化 ×0.9(四舍五入保留两位)。模块化以产品标签含「模块化」为
|
||||
// 准(聚水潭标签里的“模块化成品/模块化部件”)。查询映射层实时计算,不落库。
|
||||
const SETTLEMENT_MODULAR_TAG = '模块化'
|
||||
const SETTLEMENT_MODULAR_FACTOR = 0.9
|
||||
|
||||
export function settlementPriceText(
|
||||
costPrice: string | null | undefined,
|
||||
productTag: string | null | undefined,
|
||||
) {
|
||||
const cost = costPrice?.trim() ?? ''
|
||||
if (!cost) return ''
|
||||
if (!(productTag ?? '').includes(SETTLEMENT_MODULAR_TAG)) return cost
|
||||
const value = Number(cost)
|
||||
if (!Number.isFinite(value)) return ''
|
||||
// 先取整到分再打折,避免浮点误差让 123.45×0.9 这类半厘值四舍五入方向漂移。
|
||||
const settled = Math.round(Math.round(value * 100) * SETTLEMENT_MODULAR_FACTOR) / 100
|
||||
return settled.toFixed(2)
|
||||
}
|
||||
|
||||
export function normalizeSupplierName(value: string) {
|
||||
return value.trim().toLocaleLowerCase('zh-CN')
|
||||
}
|
||||
@ -120,7 +140,7 @@ export function mapProductArchiveRow({
|
||||
stockFactory: record.stockFactory,
|
||||
purchasePrice: record.purchasePrice,
|
||||
costPrice: record.costPrice,
|
||||
costPriceSecondary: record.costPriceSecondary,
|
||||
costPriceSecondary: settlementPriceText(record.costPrice, record.productTag),
|
||||
shipAmount: decimalText(record.salesPerformance?.shipAmount ?? null),
|
||||
returnAmount: decimalText(record.salesPerformance?.returnAmount ?? null),
|
||||
salesAmount: decimalText(record.salesPerformance?.salesAmount ?? null),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user