From a554b773799b6f0dc07911f751395a77a84535ea Mon Sep 17 00:00:00 2001 From: yeuimu <2197651308@qq.com> Date: Thu, 3 Sep 2026 02:00:33 +0800 Subject: [PATCH] =?UTF-8?q?fix(product-families):=20=E7=83=AD=E8=BD=AC?= =?UTF-8?q?=E5=8D=B0=E8=AF=8D=E8=A1=A8=E4=BB=A5=20v2=20=E4=B8=BA=E5=87=86?= =?UTF-8?q?=E2=80=94=E2=80=94=E5=BD=92=E5=9B=A0=E4=B8=8D=E5=86=8D=E6=98=A0?= =?UTF-8?q?=E5=B0=84=E5=9B=9E=E7=83=AB=E7=94=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 合并冲突的行为级裁决:develop 侧 memberMatrixCombos 曾把 热转印→烫画 归一(旧别名方案),与 v2 线上一等公民词表(8903afd)矛盾,导致 v2 侧 三个矩阵用例失败。取 v2 版 family-recompute.service.{ts,spec}(即当前 线上行为)。另修复 v2 分支 structs.md 残留的冲突标记。 Tests: api 23 suites/217 passed (runInBand), admin 27 passed, tsc clean --- .../family-recompute.service.spec.ts | 32 ------------------- .../family-recompute.service.ts | 8 ++--- 2 files changed, 3 insertions(+), 37 deletions(-) diff --git a/apps/api/src/product-families/family-recompute.service.spec.ts b/apps/api/src/product-families/family-recompute.service.spec.ts index 3c9853c..efd7cbb 100644 --- a/apps/api/src/product-families/family-recompute.service.spec.ts +++ b/apps/api/src/product-families/family-recompute.service.spec.ts @@ -269,38 +269,6 @@ describe('FamilyRecomputeService', () => { expect(matrix.rows[0].logistics).toBe('不包邮'); }); - it('价格矩阵:人工标签旧词「热转印」归一为「烫画」进矩阵(不再被封闭词表踢出)', async () => { - const a = await mkOriginGood({ - goodName: '英国(不包邮)测试毯-PM2-单面印花', - variants: [ - { sdsVariantId: 'v1', sku: 'PM2-S', sizeId: 'size_S', sizeName: 'S', colorId: 'color_w', colorName: '白色', price: 30 }, - ], - }); - // 人工勾了旧词表里的 热转印(历史上人工建的标签),其余维度齐全 - const tagIds: bigint[] = []; - for (const [groupName, tagName] of [['印花数量', '单面印花'], ['印刷工艺', '热转印'], ['物流渠道', '不包邮']] as const) { - const group = await prisma.tagGroup.findFirst({ where: { groupName } }); - const g = group ?? (await prisma.tagGroup.create({ data: { groupName } })); - if (!group) createdTagGroupIds.push(g.id); - const existing = await prisma.tag.findFirst({ where: { tagName } }); - const t = existing ?? (await prisma.tag.create({ data: { tagName, tagGroupId: g.id } })); - if (!existing) createdTagIds.push(t.id); - tagIds.push(t.id); - } - await prisma.originGoodTag.createMany({ - data: tagIds.map((tagId) => ({ originGoodId: a.id, tagId, manual: true })), - }); - const family = await mkFamily({ primaryOriginGoodId: a.id, memberIds: [a.id] }); - - await service.recomputeFamily(family.id); - - const after = await prisma.productFamily.findUniqueOrThrow({ where: { id: family.id } }); - const matrix = after.priceMatrix as any; - expect(matrix.rows).toHaveLength(1); - expect(matrix.rows[0].craft).toBe('烫画'); // 归一后的封闭词表值 - expect(matrix.crafts).toEqual(['烫画']); - }); - it('覆盖:命中改价 manual=true,未命中新增行并扩充选项', async () => { const a = await mkOriginGood({ goodName: '美国(包邮)测试O-PO1-单面印花', diff --git a/apps/api/src/product-families/family-recompute.service.ts b/apps/api/src/product-families/family-recompute.service.ts index 83cbc96..c3b3ad0 100644 --- a/apps/api/src/product-families/family-recompute.service.ts +++ b/apps/api/src/product-families/family-recompute.service.ts @@ -1,7 +1,7 @@ import { Injectable, Logger } from '@nestjs/common'; import { Prisma } from '@prisma/client'; import { PrismaService } from '../prisma/prisma.service'; -import { isAutoTagGroupName, normalizeCraftTag } from './auto-tag-rules'; +import { isAutoTagGroupName } from './auto-tag-rules'; /** * 产品族重算:并集尺码表/包装规则 + 五维价格矩阵物化。 @@ -108,16 +108,14 @@ export function memberMatrixCombos(input: { tagNames: string[]; customLabels?: { craft?: string | null; logistics?: string | null }; }): MatrixCombo[] { - // 旧词别名归一(热转印→烫画):只影响矩阵归因,封闭词表本身不变 - const tagNames = input.tagNames.map(normalizeCraftTag); const values = (dim: DimKey): string[] => - DIM_VALUES[dim].filter((v) => tagNames.includes(v)); + DIM_VALUES[dim].filter((v) => input.tagNames.includes(v)); let printCounts = values('printCount'); let crafts = values('craft'); let logistics = values('logistics'); // CUSTOM 成员:管理员显式标签是唯一来源(craftLabel/logisticsLabel,自由文本) - const craftLabel = normalizeCraftTag(input.customLabels?.craft ?? ''); + const craftLabel = input.customLabels?.craft ?? ''; const logisticsLabel = input.customLabels?.logistics ?? ''; if (!crafts.length && craftLabel) crafts = [craftLabel]; if (!logistics.length && logisticsLabel) logistics = [logisticsLabel];