feat(product-families): add heat-transfer (热转印) craft to matrix vocabularies
Append 热转印 to DIM_VALUES.craft so links manually tagged with the new tag enter the price matrix (previously the closed vocabulary filtered it out and the link's prices would silently disappear), and to OPTION_DISPLAY_ORDER.craft so the button group renders it after 不打印. No derivation rules changed: existing links are unaffected until an operator explicitly tags them.
This commit is contained in:
@@ -1,6 +1,10 @@
|
|||||||
import { Test } from '@nestjs/testing';
|
import { Test } from '@nestjs/testing';
|
||||||
import { Prisma } from '@prisma/client';
|
import { Prisma } from '@prisma/client';
|
||||||
import { FamilyRecomputeService, derivePriceMatrix } from './family-recompute.service';
|
import {
|
||||||
|
FamilyRecomputeService,
|
||||||
|
derivePriceMatrix,
|
||||||
|
memberMatrixCombos,
|
||||||
|
} from './family-recompute.service';
|
||||||
import { ProductFamiliesService } from './product-families.service';
|
import { ProductFamiliesService } from './product-families.service';
|
||||||
import { OrganizeService } from './organize.service';
|
import { OrganizeService } from './organize.service';
|
||||||
import { PrismaService } from '../prisma/prisma.service';
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
@@ -441,7 +445,7 @@ describe('derivePriceMatrix 选项组排序', () => {
|
|||||||
it('幂等:同输入多跑两遍输出全等(含顺序),与成员遍历顺序无关', () => {
|
it('幂等:同输入多跑两遍输出全等(含顺序),与成员遍历顺序无关', () => {
|
||||||
const members = [
|
const members = [
|
||||||
mkMember(1, { tags: ['直喷', '双面印花', '不包邮'] }),
|
mkMember(1, { tags: ['直喷', '双面印花', '不包邮'] }),
|
||||||
mkMember(2, { source: 'CUSTOM', craftLabel: '丝印', logisticsLabel: '海运' }),
|
mkMember(2, { source: 'CUSTOM', tags: ['双面印花'], craftLabel: '丝印', logisticsLabel: '海运' }),
|
||||||
mkMember(3, { tags: ['烫画', '单面印花', '包邮'] }),
|
mkMember(3, { tags: ['烫画', '单面印花', '包邮'] }),
|
||||||
];
|
];
|
||||||
const first = derivePriceMatrix(members, []);
|
const first = derivePriceMatrix(members, []);
|
||||||
@@ -451,3 +455,47 @@ describe('derivePriceMatrix 选项组排序', () => {
|
|||||||
expect(JSON.stringify(reversed)).toBe(JSON.stringify(first));
|
expect(JSON.stringify(reversed)).toBe(JSON.stringify(first));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 印刷工艺新增"热转印":矩阵维度词表放开准入 + 展示序追加末尾。
|
||||||
|
* 自动派生规则不改 —— SDS 链接只能人工打标;不打标的链接/族零影响。
|
||||||
|
*/
|
||||||
|
describe('热转印工艺', () => {
|
||||||
|
const mkMember = (
|
||||||
|
id: number,
|
||||||
|
over: { tags?: string[]; source?: 'SDS' | 'CUSTOM'; craftLabel?: string | null; logisticsLabel?: string | null },
|
||||||
|
) =>
|
||||||
|
({
|
||||||
|
id: BigInt(id),
|
||||||
|
source: over.source ?? 'SDS',
|
||||||
|
originGoodTags: (over.tags ?? []).map((t) => ({ tag: { tagName: t } })),
|
||||||
|
variants: [],
|
||||||
|
craftLabel: over.craftLabel ?? null,
|
||||||
|
logisticsLabel: over.logisticsLabel ?? null,
|
||||||
|
}) as any;
|
||||||
|
|
||||||
|
it('memberMatrixCombos:打标热转印的链接产出矩阵组合(此前被词表过滤为空)', () => {
|
||||||
|
const combos = memberMatrixCombos({ tagNames: ['单面印花', '热转印', '包邮'] });
|
||||||
|
expect(combos).toEqual([{ printCount: '单面印花', craft: '热转印', logistics: '包邮' }]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('derivePriceMatrix:crafts 展示序为 烫画→直喷→不打印→热转印(词表内,不再沉底)', () => {
|
||||||
|
const members = [
|
||||||
|
mkMember(1, { tags: ['热转印', '单面印花', '包邮'] }),
|
||||||
|
mkMember(2, { tags: ['烫画', '单面印花', '包邮'] }),
|
||||||
|
mkMember(3, { tags: ['直喷', '单面印花', '不包邮'] }),
|
||||||
|
mkMember(4, { tags: ['不打印', '单面印花', '包邮'] }),
|
||||||
|
];
|
||||||
|
const m = derivePriceMatrix(members, []);
|
||||||
|
expect(m.crafts).toEqual(['烫画', '直喷', '不打印', '热转印']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('词表外自由文本(丝印/水洗)仍然沉底,与热转印区分', () => {
|
||||||
|
const members = [
|
||||||
|
mkMember(1, { tags: ['热转印', '单面印花', '包邮'] }),
|
||||||
|
mkMember(2, { source: 'CUSTOM', tags: ['单面印花'], craftLabel: '丝印', logisticsLabel: '包邮' }),
|
||||||
|
];
|
||||||
|
const m = derivePriceMatrix(members, []);
|
||||||
|
expect(m.crafts).toEqual(['热转印', '丝印']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -66,20 +66,20 @@ type OverrideRow = Prisma.FamilyPriceOverrideGetPayload<{}>;
|
|||||||
/** 矩阵三个归因维度的合法取值(封闭集合,与派生标签组一致) */
|
/** 矩阵三个归因维度的合法取值(封闭集合,与派生标签组一致) */
|
||||||
const DIM_VALUES = {
|
const DIM_VALUES = {
|
||||||
printCount: ['单面印花', '双面印花'],
|
printCount: ['单面印花', '双面印花'],
|
||||||
craft: ['烫画', '直喷', '不打印'],
|
craft: ['烫画', '直喷', '不打印', '热转印'],
|
||||||
logistics: ['包邮', '不包邮'],
|
logistics: ['包邮', '不包邮'],
|
||||||
} as const satisfies Record<string, readonly string[]>;
|
} as const satisfies Record<string, readonly string[]>;
|
||||||
|
|
||||||
type DimKey = keyof typeof DIM_VALUES;
|
type DimKey = keyof typeof DIM_VALUES;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 选项组展示顺序(业务确认):printCount 单面→双面;craft 烫画→直喷→不打印;logistics 不包邮→包邮。
|
* 选项组展示顺序(业务确认):printCount 单面→双面;craft 烫画→直喷→不打印→热转印;logistics 不包邮→包邮。
|
||||||
* 与 DIM_VALUES 的"组合生成序"是两回事,物化前对聚合数组按此稳定排序;
|
* 与 DIM_VALUES 的"组合生成序"是两回事,物化前对聚合数组按此稳定排序;
|
||||||
* 词表外自由文本(CUSTOM 标签,如"海运")沉底,相互间保持首次遇到序。
|
* 词表外自由文本(CUSTOM 标签,如"海运")沉底,相互间保持首次遇到序。
|
||||||
*/
|
*/
|
||||||
const OPTION_DISPLAY_ORDER = {
|
const OPTION_DISPLAY_ORDER = {
|
||||||
printCount: ['单面印花', '双面印花'],
|
printCount: ['单面印花', '双面印花'],
|
||||||
craft: ['烫画', '直喷', '不打印'],
|
craft: ['烫画', '直喷', '不打印', '热转印'],
|
||||||
logistics: ['不包邮', '包邮'],
|
logistics: ['不包邮', '包邮'],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user