134 lines
4.9 KiB
TypeScript
134 lines
4.9 KiB
TypeScript
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<string[]> {
|
||
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;
|
||
}
|