feat(intake): open sample measurement and pricing template access with spec name column

measurement and pricing nodes now default downloads for pricing/purchase/merchandiser subjects so non-admin owners see the export/import template buttons; both workbook exports add a spec name reference column after the barcode (imports stay barcode-keyed and ignore it); the pricing node also grants merchandiser download parity with purchase owners.
This commit is contained in:
WuYongJie 2026-09-07 11:47:40 +08:00
parent 8ea6a54eaa
commit f8ba4f1e25
7 changed files with 32 additions and 10 deletions

View File

@ -176,6 +176,7 @@ export function buildProductPricingWorkbookRows(
return rows.map((row) => ({
image: row.image.trim(),
barcode: row.barcode.trim(),
specName: row.specName.trim(),
costPrice: row.costPrice.trim(),
}));
}

View File

@ -104,6 +104,7 @@ export function buildSampleMeasurementWorkbookRows(
return rows.map((row) => ({
image: row.image.trim(),
barcode: row.barcode.trim(),
specName: row.specName.trim(),
lengthCm: row.lengthCm.trim(),
widthCm: row.widthCm.trim(),
heightCm: row.heightCm.trim(),

View File

@ -623,6 +623,11 @@ export const PRODUCT_DEVELOPMENT_PERMISSION_TARGETS: IntakeNodePermissionTarget[
pricing: "edit",
externalIntake: "edit",
},
downloads: {
merchandiser: true,
pricing: true,
purchase: true,
},
},
{
key: "finishedSampleShipment",
@ -645,6 +650,11 @@ export const PRODUCT_DEVELOPMENT_PERMISSION_TARGETS: IntakeNodePermissionTarget[
pricing: "edit",
externalIntake: "edit",
},
downloads: {
merchandiser: true,
pricing: true,
purchase: true,
},
},
{
key: "limit",

View File

@ -27,6 +27,7 @@ describe('non-integrated-product-pricing-workbook', () => {
{
image: PRODUCT_PRICING_TEST_IMAGE,
barcode: 'GBGJ-XJ009601N1280V01',
specName: '款式一 45/45/50 胡桃色',
costPrice: '88',
},
])
@ -40,9 +41,11 @@ describe('non-integrated-product-pricing-workbook', () => {
expect(worksheet?.name).toBe('产品核价')
expect(worksheet?.getCell(1, 1).value).toBe('产品图片')
expect(worksheet?.getCell(1, 2).value).toBe('条码')
expect(worksheet?.getCell(1, 3).value).toBe('成本价')
expect(worksheet?.getCell(1, 3).value).toBe('条码规格名称')
expect(worksheet?.getCell(1, 4).value).toBe('成本价')
expect(worksheet?.getCell(2, 2).value).toBe('GBGJ-XJ009601N1280V01')
expect(worksheet?.getCell(2, 3).value).toBe(88)
expect(worksheet?.getCell(2, 3).value).toBe('款式一 45/45/50 胡桃色')
expect(worksheet?.getCell(2, 4).value).toBe(88)
const media = (workbook as import('exceljs').Workbook & {
model?: { media?: unknown[] }

View File

@ -1,6 +1,7 @@
export type NonIntegratedProductPricingWorkbookRow = {
image: string
barcode: string
specName: string
costPrice: string
}
@ -20,7 +21,7 @@ type ProductPricingWorkbookImageExtension = 'jpeg' | 'png' | 'gif'
type ProductPricingWorkbookExportColumn =
| {
key: 'barcode'
key: 'barcode' | 'specName'
label: string
width: number
kind: 'text'
@ -42,6 +43,7 @@ const NON_INTEGRATED_PRODUCT_PRICING_EXPORT_COLUMNS: ProductPricingWorkbookExpor
[
{ key: 'image', label: '产品图片', width: 14, kind: 'image' },
{ key: 'barcode', label: '条码', width: 24, kind: 'text' },
{ key: 'specName', label: '条码规格名称', width: 24, kind: 'text' },
{ key: 'costPrice', label: '成本价', width: 12, kind: 'number' },
]

View File

@ -27,6 +27,7 @@ describe('non-integrated-sample-measurement-workbook', () => {
{
image: SAMPLE_MEASUREMENT_TEST_IMAGE,
barcode: 'XJ010101N3576V01',
specName: '款式一 1/1/1 黑色',
lengthCm: '30',
widthCm: '40',
heightCm: '60',
@ -43,13 +44,15 @@ describe('non-integrated-sample-measurement-workbook', () => {
expect(worksheet?.name).toBe('样包测量')
expect(worksheet?.getCell(1, 1).value).toBe('产品图片')
expect(worksheet?.getCell(1, 2).value).toBe('条码')
expect(worksheet?.getCell(1, 3).value).toBe('长(CM)')
expect(worksheet?.getCell(1, 4).value).toBe('宽(CM)')
expect(worksheet?.getCell(1, 5).value).toBe('高(CM)')
expect(worksheet?.getCell(1, 6).value).toBe('重量(KG)')
expect(worksheet?.getCell(1, 3).value).toBe('条码规格名称')
expect(worksheet?.getCell(1, 4).value).toBe('长(CM)')
expect(worksheet?.getCell(1, 5).value).toBe('宽(CM)')
expect(worksheet?.getCell(1, 6).value).toBe('高(CM)')
expect(worksheet?.getCell(1, 7).value).toBe('重量(KG)')
expect(worksheet?.getCell(2, 2).value).toBe('XJ010101N3576V01')
expect(worksheet?.getCell(2, 3).value).toBe(30)
expect(worksheet?.getCell(2, 6).value ?? '').toBe('')
expect(worksheet?.getCell(2, 3).value).toBe('款式一 1/1/1 黑色')
expect(worksheet?.getCell(2, 4).value).toBe(30)
expect(worksheet?.getCell(2, 7).value ?? '').toBe('')
const media = (workbook as import('exceljs').Workbook & {
model?: { media?: unknown[] }

View File

@ -1,6 +1,7 @@
export type NonIntegratedSampleMeasurementWorkbookRow = {
image: string
barcode: string
specName: string
lengthCm: string
widthCm: string
heightCm: string
@ -26,7 +27,7 @@ type SampleMeasurementWorkbookImageExtension = 'jpeg' | 'png' | 'gif'
type SampleMeasurementWorkbookExportColumn =
| {
key: 'barcode'
key: 'barcode' | 'specName'
label: string
width: number
kind: 'text'
@ -48,6 +49,7 @@ const NON_INTEGRATED_SAMPLE_MEASUREMENT_EXPORT_COLUMNS: SampleMeasurementWorkboo
[
{ key: 'image', label: '产品图片', width: 14, kind: 'image' },
{ key: 'barcode', label: '条码', width: 24, kind: 'text' },
{ key: 'specName', label: '条码规格名称', width: 24, kind: 'text' },
{ key: 'lengthCm', label: '长(CM)', width: 12, kind: 'number' },
{ key: 'widthCm', label: '宽(CM)', width: 12, kind: 'number' },
{ key: 'heightCm', label: '高(CM)', width: 12, kind: 'number' },