/** * 将存量商品 / SKU 的 sku_code 全部改成 DK + 6 位数字。 * 已是 DK 数字码的保持不变;其余先写临时码再分配,避免唯一约束冲突。 * * 用法:cd server/dukang-api && npx ts-node prisma/rewrite-sku-codes-dk.ts */ import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient(); const PREFIX = 'DK'; const PAD = 6; const RE = /^DK(\d+)$/; function isDk(code: string) { return RE.test(code); } function formatCode(seq: number) { return `${PREFIX}${String(seq).padStart(PAD, '0')}`; } async function maxExistingSeq(): Promise { const [items, skus] = await Promise.all([ prisma.commonProductItem.findMany({ where: { skuCode: { startsWith: PREFIX } }, select: { skuCode: true }, }), prisma.commonProductSku.findMany({ where: { skuCode: { startsWith: PREFIX } }, select: { skuCode: true }, }), ]); let maxSeq = 0; for (const row of [...items, ...skus]) { const m = RE.exec(row.skuCode); if (!m) continue; const n = Number(m[1]); if (Number.isFinite(n) && n > maxSeq) maxSeq = n; } return maxSeq; } async function main() { const skus = await prisma.commonProductSku.findMany({ orderBy: [{ productId: 'asc' }, { id: 'asc' }], select: { id: true, productId: true, skuCode: true, isDefault: true }, }); const products = await prisma.commonProductItem.findMany({ select: { id: true, skuCode: true }, }); const skuNeed = skus.filter((s) => !isDk(s.skuCode)); const productNeed = products.filter((p) => !isDk(p.skuCode)); console.log(`sku total=${skus.length} rewrite=${skuNeed.length}`); console.log(`product total=${products.length} rewrite=${productNeed.length}`); await prisma.$transaction(async (tx) => { for (const s of skuNeed) { await tx.commonProductSku.update({ where: { id: s.id }, data: { skuCode: `TMP${s.id.toString()}` }, }); } for (const p of productNeed) { await tx.commonProductItem.update({ where: { id: p.id }, data: { skuCode: `TMPP${p.id.toString()}` }, }); } const seqStart = await (async () => { const [items, skuRows] = await Promise.all([ tx.commonProductItem.findMany({ where: { skuCode: { startsWith: PREFIX } }, select: { skuCode: true }, }), tx.commonProductSku.findMany({ where: { skuCode: { startsWith: PREFIX } }, select: { skuCode: true }, }), ]); let maxSeq = 0; for (const row of [...items, ...skuRows]) { const m = RE.exec(row.skuCode); if (!m) continue; const n = Number(m[1]); if (Number.isFinite(n) && n > maxSeq) maxSeq = n; } return maxSeq; })(); let seq = seqStart; const defaultSkuCodeByProduct = new Map(); for (const s of skuNeed) { seq += 1; const code = formatCode(seq); await tx.commonProductSku.update({ where: { id: s.id }, data: { skuCode: code }, }); if (s.isDefault) defaultSkuCodeByProduct.set(s.productId.toString(), code); console.log(`sku ${s.id} ${s.skuCode} -> ${code}`); } for (const p of productNeed) { const fromDefault = defaultSkuCodeByProduct.get(p.id.toString()); let code = fromDefault; if (!code) { seq += 1; code = formatCode(seq); } await tx.commonProductItem.update({ where: { id: p.id }, data: { skuCode: code }, }); console.log(`product ${p.id} ${p.skuCode} -> ${code}`); } const stillDefault = await tx.commonProductSku.findMany({ where: { isDefault: true }, select: { productId: true, skuCode: true }, }); for (const s of stillDefault) { if (!isDk(s.skuCode)) continue; await tx.commonProductItem.updateMany({ where: { id: s.productId, NOT: { skuCode: s.skuCode } }, data: { skuCode: s.skuCode }, }); } }); const leftoverSku = await prisma.commonProductSku.count({ where: { NOT: { skuCode: { startsWith: PREFIX } } }, }); const leftoverProduct = await prisma.commonProductItem.count({ where: { NOT: { skuCode: { startsWith: PREFIX } } }, }); console.log(`done leftoverSku=${leftoverSku} leftoverProduct=${leftoverProduct} maxWas=${await maxExistingSeq()}`); } main() .catch((e) => { console.error(e); process.exit(1); }) .finally(() => prisma.$disconnect());