R111/A1,A2 建立发票治理计划和海音达设计基线
这个提交包含在:
@@ -0,0 +1,109 @@
|
||||
require("dotenv/config");
|
||||
|
||||
const { createPrismaClient } = require("../prismaClient");
|
||||
|
||||
function printGroup(title, rows, keyFields) {
|
||||
process.stdout.write(`\n## ${title}\n`);
|
||||
if (!rows.length) {
|
||||
process.stdout.write("无重复记录\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (const row of rows) {
|
||||
const key = keyFields.map((field) => row[field]).join(" / ");
|
||||
process.stdout.write(`\n- ${key}:${row.count} 条\n`);
|
||||
for (const item of row.items) {
|
||||
process.stdout.write(
|
||||
` - ${item.id} status=${item.status} owner=${item.ownerName ?? "-"} form=${item.formNumber ?? "-"} file=${item.originalName ?? "-"} created=${item.createdAt ?? "-"}\n`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function loadDuplicateGroups(prisma, { byInvoiceNumber = false } = {}) {
|
||||
const groups = byInvoiceNumber
|
||||
? await prisma.$queryRaw`
|
||||
SELECT invoice_code, invoice_number, COUNT(*)::int AS count
|
||||
FROM "invoice_pool"
|
||||
WHERE invoice_code IS NOT NULL AND invoice_number IS NOT NULL
|
||||
GROUP BY invoice_code, invoice_number
|
||||
HAVING COUNT(*) > 1
|
||||
ORDER BY COUNT(*) DESC, invoice_code ASC, invoice_number ASC
|
||||
LIMIT 100
|
||||
`
|
||||
: await prisma.$queryRaw`
|
||||
SELECT file_sha256, COUNT(*)::int AS count
|
||||
FROM "invoice_pool"
|
||||
GROUP BY file_sha256
|
||||
HAVING COUNT(*) > 1
|
||||
ORDER BY COUNT(*) DESC, file_sha256 ASC
|
||||
LIMIT 100
|
||||
`;
|
||||
|
||||
const rows = [];
|
||||
for (const group of groups) {
|
||||
const where = byInvoiceNumber
|
||||
? {
|
||||
invoice_code: group.invoice_code,
|
||||
invoice_number: group.invoice_number,
|
||||
}
|
||||
: { file_sha256: group.file_sha256 };
|
||||
|
||||
const items = await prisma.invoicePool.findMany({
|
||||
where,
|
||||
orderBy: [{ created_at: "asc" }, { id: "asc" }],
|
||||
select: {
|
||||
id: true,
|
||||
status: true,
|
||||
original_name: true,
|
||||
created_at: true,
|
||||
owner_employee: { select: { name: true } },
|
||||
linked_reimbursement: { select: { form_number: true } },
|
||||
},
|
||||
});
|
||||
|
||||
rows.push({
|
||||
...group,
|
||||
items: items.map((item) => ({
|
||||
id: item.id,
|
||||
status: item.status,
|
||||
ownerName: item.owner_employee?.name ?? null,
|
||||
formNumber: item.linked_reimbursement?.form_number ?? null,
|
||||
originalName: item.original_name ?? null,
|
||||
createdAt: item.created_at?.toISOString?.() ?? null,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
(async () => {
|
||||
const { prisma, pool } = createPrismaClient();
|
||||
await prisma.$connect();
|
||||
try {
|
||||
const statusRows = await prisma.invoicePool.groupBy({
|
||||
by: ["status"],
|
||||
_count: { _all: true },
|
||||
orderBy: { status: "asc" },
|
||||
});
|
||||
process.stdout.write("# 发票池重复审计\n\n## 状态分布\n");
|
||||
for (const row of statusRows) {
|
||||
process.stdout.write(`- ${row.status}: ${row._count._all}\n`);
|
||||
}
|
||||
|
||||
const [fileGroups, numberGroups] = await Promise.all([
|
||||
loadDuplicateGroups(prisma),
|
||||
loadDuplicateGroups(prisma, { byInvoiceNumber: true }),
|
||||
]);
|
||||
|
||||
printGroup("按文件 SHA256 重复", fileGroups, ["file_sha256"]);
|
||||
printGroup("按发票代码/号码重复", numberGroups, ["invoice_code", "invoice_number"]);
|
||||
} finally {
|
||||
await prisma.$disconnect();
|
||||
await pool.end();
|
||||
}
|
||||
})().catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
在新工单中引用
屏蔽一个用户