import { PrismaClient } from '@prisma/client'; import * as fs from 'fs'; const prisma = new PrismaClient(); const DUMP = '/opt/import/prod/oa_clean.json'; type Row = Record; function str(v: unknown) { if (v == null) return ''; return String(v).trim(); } const CANON = [ { name: '江苏风影随行科技有限公司', shortName: '随行科技', aliases: ['江苏风影随行科技有限公司', '江苏风影随行', '随行科技'] }, { name: '江苏风影软件有限公司', shortName: '风影软件', aliases: ['江苏风影软件有限公司', '风影软件'] }, { name: '江苏风影工程科技有限公司', shortName: '风影工程', aliases: ['江苏风影工程科技有限公司', '风影工程'] }, { name: '山东鲁兵', shortName: '山东鲁兵', aliases: ['山东鲁兵', '鲁兵'] }, { name: '隆创', shortName: '隆创', aliases: ['隆创'] }, ] as const; function canonOf(raw: string) { const s = str(raw); if (!s) return null; if (/软件/.test(s) && /风影/.test(s)) return CANON[1]; if (/工程/.test(s) && /风影/.test(s)) return CANON[2]; if (/随行/.test(s) || s === '江苏风影' || (s.includes('风影') && !/软件|工程/.test(s))) return CANON[0]; if (s.includes('鲁兵')) return CANON[3]; if (s.includes('隆创')) return CANON[4]; for (const c of CANON) { if (c.aliases.some((a) => s === a || s.includes(a))) return c; } return null; } async function main() { const ids = new Map(); for (const c of CANON) { let row = (await prisma.legalEntity.findFirst({ where: { tenantId: '1', name: c.name } })) || (await prisma.legalEntity.findFirst({ where: { tenantId: '1', OR: c.aliases.map((a) => ({ name: a })) }, })); if (row) { row = await prisma.legalEntity.update({ where: { id: row.id }, data: { name: c.name, shortName: c.shortName, isDefault: c.name === '江苏风影随行科技有限公司' }, }); } else { row = await prisma.legalEntity.create({ data: { name: c.name, shortName: c.shortName, isDefault: c.name === '江苏风影随行科技有限公司', }, }); } ids.set(c.name, row.id); } const all = await prisma.legalEntity.findMany({ where: { tenantId: '1' } }); const keep = new Set(ids.values()); let merged = 0; for (const extra of all) { if (keep.has(extra.id)) continue; const hit = canonOf(extra.name) || canonOf(extra.shortName); const target = hit ? ids.get(hit.name) : ids.get('江苏风影随行科技有限公司'); if (!target || target === extra.id) continue; const n = await prisma.bidCase.updateMany({ where: { legalEntityId: extra.id }, data: { legalEntityId: target } }); await prisma.contract.updateMany({ where: { legalEntityId: extra.id }, data: { legalEntityId: target } }).catch(() => null); await prisma.sealItem.updateMany({ where: { legalEntityId: extra.id }, data: { legalEntityId: target } }).catch(() => null); await prisma.registeredAsset.updateMany({ where: { legalEntityId: extra.id }, data: { legalEntityId: target } }).catch(() => null); await prisma.legalEntity.delete({ where: { id: extra.id } }).catch(() => null); merged += 1; console.log('merged', extra.name, '->', hit?.name, 'bids', n.count); } await prisma.legalEntity.updateMany({ where: { name: { not: '江苏风影随行科技有限公司' } }, data: { isDefault: false }, }); await prisma.legalEntity.updateMany({ where: { name: '江苏风影随行科技有限公司' }, data: { isDefault: true }, }); let remapped = 0; if (fs.existsSync(DUMP)) { const raw = JSON.parse(fs.readFileSync(DUMP, 'utf8')) as Record; const tenders = raw.oa_tender || []; const bids = await prisma.bidCase.findMany({ select: { id: true, name: true, bidNo: true, externalNo: true } }); for (const t of tenders) { const name = str(t.project_name); const sys = str(t.system_number); const official = str(t.project_number); const row = bids.find((b) => b.name === name) || bids.find((b) => b.bidNo === sys || b.externalNo === official || b.bidNo === official); const hit = canonOf(str(t.participating_unit)); const legalEntityId = hit ? ids.get(hit.name) : undefined; const winner = str(t.winning_unit); const amtRaw = str(t.winning_amount); const status = str(t.winning_status); if (!row) continue; const data: { legalEntityId?: string; winnerName?: string; winnerAmount?: number } = {}; if (legalEntityId) data.legalEntityId = legalEntityId; if (winner && status && !/中标/.test(status)) { data.winnerName = winner; if (amtRaw && !Number.isNaN(Number(amtRaw))) data.winnerAmount = Number(amtRaw); } if (!Object.keys(data).length) continue; await prisma.bidCase.update({ where: { id: row.id }, data }); remapped += 1; } } const leftover = await prisma.legalEntity.findMany({ where: { tenantId: '1' }, orderBy: { name: 'asc' } }); const grouped = await prisma.bidCase.groupBy({ by: ['legalEntityId'], _count: true }); console.log( JSON.stringify( { entities: leftover.map((e) => ({ name: e.name, shortName: e.shortName, isDefault: e.isDefault })), bids: grouped.map((g) => ({ id: g.legalEntityId, count: g._count, name: leftover.find((e) => e.id === g.legalEntityId)?.name || '(空)', })), merged, remapped, }, null, 2, ), ); } main() .catch((e) => { console.error(e); process.exit(1); }) .finally(() => prisma.$disconnect());