feat(api): product families backfill script
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* 产品族回填脚本(一次性 / 幂等):
|
||||
* 1. 全量 OriginGood 回填四个链接名解析列;
|
||||
* 2. auto-group 全量建族并挂成员(每族建立即重算);
|
||||
* 3. 输出统计与不可解析清单。
|
||||
*
|
||||
* 运行:pnpm --filter @inkreach/api backfill:product-families
|
||||
* 幂等性:重复执行时步骤 1 数据不变、步骤 2 候选为空(familyId=null 过滤)。
|
||||
*/
|
||||
import { PrismaService } from '../src/prisma/prisma.service';
|
||||
import { FamilyRecomputeService } from '../src/product-families/family-recompute.service';
|
||||
import { ProductFamiliesService } from '../src/product-families/product-families.service';
|
||||
import { parseOriginName } from '../src/product-families/origin-name.parser';
|
||||
|
||||
async function main() {
|
||||
const prisma = new PrismaService();
|
||||
await prisma.onModuleInit();
|
||||
const recompute = new FamilyRecomputeService(prisma);
|
||||
const families = new ProductFamiliesService(prisma, recompute);
|
||||
|
||||
// ---- 1. 解析列回填(分批) ----
|
||||
const BATCH = 100;
|
||||
let parsed = 0;
|
||||
const unparsable: string[] = [];
|
||||
for (;;) {
|
||||
const batch = await prisma.originGood.findMany({
|
||||
orderBy: { id: 'asc' },
|
||||
take: BATCH,
|
||||
skip: parsed,
|
||||
select: { id: true, goodName: true },
|
||||
});
|
||||
if (batch.length === 0) break;
|
||||
for (const og of batch) {
|
||||
const p = parseOriginName(og.goodName);
|
||||
if (!p.skuCode && !p.craftLabel) unparsable.push(`#${og.id} ${og.goodName ?? ''}`);
|
||||
await prisma.originGood.update({
|
||||
where: { id: og.id },
|
||||
data: {
|
||||
skuCode: p.skuCode,
|
||||
logisticsLabel: p.logisticsLabel,
|
||||
craftLabel: p.craftLabel,
|
||||
warehouseLabel: p.warehouseLabel,
|
||||
},
|
||||
});
|
||||
}
|
||||
parsed += batch.length;
|
||||
}
|
||||
console.log(`[1/2] parsed ${parsed} origin goods (${unparsable.length} without sku/craft)`);
|
||||
|
||||
// ---- 2. 自动建族(含逐族重算) ----
|
||||
const result = await families.autoGroup(true);
|
||||
console.log(`[2/2] created ${result.applied} families`);
|
||||
|
||||
// ---- 统计 ----
|
||||
const total = await prisma.productFamily.count();
|
||||
const withMatrix = await prisma.productFamily.count({ where: { priceMatrix: { not: null } } });
|
||||
const members = await prisma.originGood.count({ where: { familyId: { not: null } } });
|
||||
const stale = await prisma.productFamily.count({ where: { stale: true } });
|
||||
console.log(`stats: families=${total}, materialized=${withMatrix}, members=${members}, stale=${stale}`);
|
||||
if (unparsable.length) {
|
||||
console.log('unparsable names:');
|
||||
for (const line of unparsable) console.log(` - ${line}`);
|
||||
}
|
||||
|
||||
await prisma.$disconnect();
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user