You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

60 lines
1.8 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { QUOTE_ID_PREFIX } from "@/lib/constants/quote";
import { prisma } from "@/lib/prisma";
import { writeAudit } from "@/modules/audit/service";
import { QuoteIdConflictError } from "@/modules/quote/types";
function formatDatePart(date: Date): string {
const y = date.getFullYear();
const m = String(date.getMonth() + 1).padStart(2, "0");
const d = String(date.getDate()).padStart(2, "0");
return `${y}${m}${d}`;
}
/** QTE_YYYYMMDD_NNNN 格式DB 序号保证唯一性 */
export async function generateQuoteId(): Promise<string> {
const datePart = formatDatePart(new Date());
const prefix = `${QUOTE_ID_PREFIX}_${datePart}_`;
const latest = await prisma.quoteRecord.findFirst({
where: { quoteId: { startsWith: prefix } },
orderBy: { quoteId: "desc" },
select: { quoteId: true },
});
let seq = 1;
if (latest?.quoteId) {
const suffix = latest.quoteId.slice(prefix.length);
const parsed = Number.parseInt(suffix, 10);
if (!Number.isNaN(parsed)) {
seq = parsed + 1;
}
}
return `${prefix}${String(seq).padStart(4, "0")}`;
}
/** task-109quote_id 唯一冲突 → 写 audit + 抛 INTERNAL_ERROR */
export async function handleQuoteIdConflict(
quoteId: string,
actorId: string,
): Promise<never> {
await writeAudit("QUOTE_ID_CONFLICT", actorId, quoteId, {
quoteId,
message: "quote_id 唯一键冲突",
});
throw new QuoteIdConflictError("系统繁忙,请稍后重试");
}
/** 检测 Prisma P2002 是否为 quote_id 冲突 */
export function isQuoteIdUniqueConflict(error: unknown): boolean {
const prismaError = error as { code?: string; meta?: { target?: string[] } };
if (prismaError.code !== "P2002") {
return false;
}
const target = prismaError.meta?.target;
return (
Array.isArray(target) &&
(target.includes("quote_id") || target.includes("quoteId"))
);
}