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(); } function when(v: unknown) { const s = str(v); if (!s || s.startsWith('0000')) return null; const d = new Date(s.includes('T') ? s : s.replace(' ', 'T')); return Number.isNaN(d.getTime()) ? null : d; } function entityKey(raw: unknown) { const s = str(raw); if (!s) return ''; if (s.includes('鲁兵')) return '山东鲁兵'; if (s.includes('隆创')) return '隆创'; if (s.includes('风影')) return '江苏风影随行科技有限公司'; return s; } const ENTITIES: { key: string; name: string; shortName: string }[] = [ { key: '江苏风影随行科技有限公司', name: '江苏风影随行科技有限公司', shortName: '江苏风影' }, { key: '山东鲁兵', name: '山东鲁兵', shortName: '山东鲁兵' }, { key: '隆创', name: '隆创', shortName: '隆创' }, ]; async function main() { const raw = JSON.parse(fs.readFileSync(DUMP, 'utf8')) as Record; const tenders = raw.oa_tender || []; const entityIds = new Map(); for (const e of ENTITIES) { const existing = await prisma.legalEntity.findFirst({ where: { tenantId: '1', OR: [{ name: e.name }, { shortName: e.shortName }] }, }); if (existing) { await prisma.legalEntity.update({ where: { id: existing.id }, data: { name: e.name, shortName: e.shortName } }); entityIds.set(e.key, existing.id); } else { const created = await prisma.legalEntity.create({ data: { name: e.name, shortName: e.shortName, isDefault: e.shortName === '江苏风影' }, }); entityIds.set(e.key, created.id); } } await prisma.legalEntity.updateMany({ where: { name: { not: '江苏风影随行科技有限公司' } }, data: { isDefault: false }, }); await prisma.legalEntity.updateMany({ where: { name: '江苏风影随行科技有限公司' }, data: { isDefault: true }, }); const users = await prisma.user.findMany(); const userByName = new Map(users.map((u) => [u.displayName, u])); const bids = await prisma.bidCase.findMany(); const usedNos = new Set(); const matched: { rowId: string; t: Row }[] = []; 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); if (!row) continue; matched.push({ rowId: row.id, t }); } for (const m of matched) { await prisma.bidCase.update({ where: { id: m.rowId }, data: { bidNo: `TMP-${m.rowId.replace(/-/g, '').slice(0, 20)}` }, }); } for (const { rowId, t } of matched) { const row = bids.find((b) => b.id === rowId)!; const official = str(t.project_number); const key = entityKey(t.participating_unit); let bidNo = official || row.externalNo || row.bidNo; if (usedNos.has(bidNo)) bidNo = `${bidNo}-${row.id.slice(0, 4)}`; usedNos.add(bidNo); const preparer = str(t.bid_prepare_person); const creator = userByName.get(preparer === '张靖妍' ? '张婧妍' : preparer); await prisma.bidCase.update({ where: { id: row.id }, data: { bidNo, externalNo: official || row.externalNo, legalEntityId: key ? entityIds.get(key) || null : null, openAt: when(t.bid_open_date) || row.openAt, applyEndAt: when(t.file_apply_deadline) || row.applyEndAt, applyStartAt: when(t.create_time) || row.applyStartAt, createdById: creator?.id || row.createdById, createdAt: when(t.create_time) || row.createdAt, }, }); } const patched = matched.length; const loan = await prisma.loanRecord.findFirst({ where: { purpose: { contains: '重庆投标' } } }); const chongqing = await prisma.bidCase.findFirst({ where: { name: { contains: '门诊特病' } } }); if (loan && chongqing) { await prisma.loanRecord.update({ where: { id: loan.id }, data: { bidCaseId: chongqing.id, costType: 'BID' }, }); } console.log(JSON.stringify({ patchedBids: patched, entities: ENTITIES.map((e) => e.shortName), linkedChongqingLoan: Boolean(loan && chongqing) })); } main() .catch((e) => { console.error(e); process.exit(1); }) .finally(() => prisma.$disconnect());