refactor(api): parsing out of runtime — pure-mirror sync, explicit organize, auto aggregate recompute
解析去运行时化(三层架构,plans/refactor/organize-script-refactor.md): - 同步 = 纯镜像:upsertOriginGood 不再写解析列、不再自动挂族;详情同步仍触发重算 - 整理 = 显式人工动作(OrganizeService):解析列回填 → 派生标签(人工接管永不 覆盖)→ auto-group 建族 → 全量重算;入口 CLI(pnpm --filter @inkreach/api organize)+ POST /product-families/organize + 后台「整理」按钮 - 重算 = 纯结构化聚合:不再按名称重派生标签(防上游改名倒灌,回归测试覆盖); 矩阵维度只认标签/CUSTOM 显式标签,未整理成员不进矩阵;工艺=不打印时 印花数量以单面占位(纯结构化规则);「恢复自动」走整理的单链接派生 - 派生默认补齐(脚本层假设):名称无单/双面且工艺非不打印 → 印花数量单面印花 - goods 服务建品/更新后仅镜像标签+重算(不派生);含商品名入库规范化 (normalizeGoodName,管理员输入边界质检) - organize.service.spec 由 tag-sync spec 迁移 + 防倒灌回归;sync/recompute/ public/families spec 全部适配;API 173/173,admin typecheck+22/22
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { OriginGoodsService } from './origin-goods.service';
|
||||
import { FamilyRecomputeService } from '../product-families/family-recompute.service';
|
||||
import { FamilyRecomputeService } from '../product-families/family-recompute.service';
|
||||
import { ProductFamiliesService } from '../product-families/product-families.service';
|
||||
import { OrganizeService } from '../product-families/organize.service';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
|
||||
describe('OriginGoodsService', () => {
|
||||
@@ -11,7 +13,7 @@ describe('OriginGoodsService', () => {
|
||||
|
||||
beforeAll(async () => {
|
||||
const moduleRef = await Test.createTestingModule({
|
||||
providers: [OriginGoodsService, FamilyRecomputeService, PrismaService],
|
||||
providers: [OriginGoodsService, FamilyRecomputeService, ProductFamiliesService, OrganizeService, PrismaService],
|
||||
}).compile();
|
||||
service = moduleRef.get(OriginGoodsService);
|
||||
prisma = moduleRef.get(PrismaService);
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { FamilyRecomputeService } from '../product-families/family-recompute.service';
|
||||
import { OrganizeService } from '../product-families/organize.service';
|
||||
import { QueryOriginGoodDto } from './dto/query-origin-good.dto';
|
||||
|
||||
/** 链接标签(origin_good_tags 行,含人工/派生标记) */
|
||||
@@ -89,6 +90,7 @@ export class OriginGoodsService {
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly familyRecompute: FamilyRecomputeService,
|
||||
private readonly organize: OrganizeService,
|
||||
) {}
|
||||
|
||||
/** 链接当前标签(含 manual 标记) */
|
||||
@@ -152,10 +154,16 @@ export class OriginGoodsService {
|
||||
this.prisma.originGood.update({ where: { id }, data: { tagsManual: true } }),
|
||||
]);
|
||||
await this.familyRecompute.mirrorLinkTagsToGoods(id);
|
||||
// 人工改标签 → 归因维度可能变化,自动重算族矩阵(有族才重算)
|
||||
const ogFull = await this.prisma.originGood.findUnique({
|
||||
where: { id },
|
||||
select: { familyId: true },
|
||||
});
|
||||
if (ogFull?.familyId) await this.familyRecompute.recomputeFamily(ogFull.familyId);
|
||||
return this.getTags(id);
|
||||
}
|
||||
|
||||
/** 恢复自动:清掉全部标签行(含人工行),回到按链接名称派生 */
|
||||
/** 恢复自动:清掉全部标签行(含人工行),按链接名称重新派生(显式人工动作) */
|
||||
async resetTags(id: bigint): Promise<OriginGoodTagsResult> {
|
||||
const og = await this.prisma.originGood.findUnique({
|
||||
where: { id },
|
||||
@@ -166,12 +174,9 @@ export class OriginGoodsService {
|
||||
this.prisma.originGoodTag.deleteMany({ where: { originGoodId: id } }),
|
||||
this.prisma.originGood.update({ where: { id }, data: { tagsManual: false } }),
|
||||
]);
|
||||
if (og.familyId) {
|
||||
// 族内链接:整族重派生 + 商品镜像
|
||||
await this.familyRecompute.syncFamilyTags(og.familyId);
|
||||
} else {
|
||||
await this.familyRecompute.refreshLinkTags(id);
|
||||
}
|
||||
// 派生集中在整理服务(解析去运行时化);「恢复自动」本身是显式人工动作
|
||||
await this.organize.deriveTagsForOg(id);
|
||||
if (og.familyId) await this.familyRecompute.recomputeFamily(og.familyId);
|
||||
return this.getTags(id);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user