import { prismaClient } from '@/lib/prisma'; import dayjs from 'dayjs' /** * 根据开票日期获取对应的项目号 * @param kai_piao_ri_qi 开票日期,格式为 YYYY-MM-DD * @returns 匹配的项目号数组 */ /** * 根据开票日期或日期范围获取对应的项目号 * 支持: * - 单个日期字符串:'YYYY-MM-DD' * - JSON数组字符串:'["2025-09-01","2025-09-30",""]' * - 直接数组:['2025-09-01','2025-09-30'] */ export async function getProjectIdsByInvoiceDate(kai_piao_ri_qi: unknown): Promise { const dateRegex = /^\d{4}-\d{2}-\d{2}$/; const normalizeDate = (input: unknown): string | undefined => { if (input === null || input === undefined) return undefined; if (typeof input === 'number' && Number.isFinite(input)) { const parsed = dayjs(input); return parsed.isValid() ? parsed.format('YYYY-MM-DD') : undefined; } const s = String(input).trim(); if (!s) return undefined; if (dateRegex.test(s)) return s; const parsed = dayjs(s); if (parsed.isValid()) return parsed.format('YYYY-MM-DD'); return undefined; }; let start: string | undefined; let end: string | undefined; if (Array.isArray(kai_piao_ri_qi)) { start = normalizeDate(kai_piao_ri_qi[0]); end = normalizeDate(kai_piao_ri_qi[1]); } else if (kai_piao_ri_qi && typeof kai_piao_ri_qi === 'object') { const obj = kai_piao_ri_qi as any; start = normalizeDate(obj?.start ?? obj?.startTime ?? obj?.begin ?? obj?.beginTime ?? obj?.[0]); end = normalizeDate(obj?.end ?? obj?.endTime ?? obj?.finish ?? obj?.finishTime ?? obj?.[1]); } else if (typeof kai_piao_ri_qi === 'string') { const raw = kai_piao_ri_qi.trim(); if (dateRegex.test(raw)) { start = normalizeDate(raw); } else if (raw.startsWith('[')) { // 尝试解析 JSON 数组字符串,例如 '["2025-09-03","2025-09-05",""]' try { const arr = JSON.parse(raw); if (Array.isArray(arr)) { start = normalizeDate(arr[0]); end = normalizeDate(arr[1]); } } catch { // 非法 JSON,后续会走错误提示 } } else { const parts = raw.split(/[,,、\s]+/).map(s => s.trim()).filter(Boolean); if (parts.length >= 2) { start = normalizeDate(parts[0]); end = normalizeDate(parts[1]); } } } // 组装 where 条件:区间或单点 // 由于数据库中日期可能以 YYYY-MM-DD 或 YYYY/MM/DD 存储,需要同时支持两种格式 let whereClause: any; if (start && end) { const startDash = start.replace(/\//g, '-'); const endExclusiveDash = dayjs(end).add(1, 'day').format('YYYY-MM-DD'); const startSlash = start.replace(/-/g, '/'); const endExclusiveSlash = dayjs(end).add(1, 'day').format('YYYY/MM/DD'); whereClause = { OR: [ { kai_piao_ri_qi: { gte: startDash, lt: endExclusiveDash } }, { kai_piao_ri_qi: { gte: startSlash, lt: endExclusiveSlash } } ] }; } else if (start) { const startDash = start.replace(/\//g, '-'); const startSlash = start.replace(/-/g, '/'); whereClause = { OR: [ { kai_piao_ri_qi: { startsWith: startDash } }, { kai_piao_ri_qi: { startsWith: startSlash } } ] }; } else { throw new Error('开票日期格式不正确,应为 YYYY-MM-DD 或 ["YYYY-MM-DD","YYYY-MM-DD",""]'); } const voidRecords = await prismaClient.dingding_oa_invoice_application.findMany({ where: { remark: { in: ['发票作废', '作废'] } }, select: { dataId: true } }); const voidIds = voidRecords.map(r => r.dataId).filter(Boolean); const invoiceRows = await prismaClient.invoice_data.findMany({ where: { ...whereClause }, select: { dataid: true } }); const dataIdsRaw = Array.from(new Set(invoiceRows.map(r => String(r.dataid ?? '').trim()).filter(Boolean))); const voidIdSet = new Set(voidIds.map(id => String(id).trim()).filter(Boolean)); const dataIds = voidIdSet.size > 0 ? dataIdsRaw.filter(id => !voidIdSet.has(id)) : dataIdsRaw; if (dataIds.length === 0) return []; const apps = await prismaClient.dingding_oa_invoice_application.findMany({ where: { dataId: { in: dataIds } }, select: { projectNumber: true } }); const projectIds = Array.from(new Set( apps.flatMap(item => ((item.projectNumber || '') as string) .split(/[,,、\s]+/) .filter(Boolean)) )); return projectIds; }