YARA-1246

This commit is contained in:
SepehrYahyaee
2026-08-25 16:50:06 +03:30
parent dc3748ae94
commit 6566b5f112
5 changed files with 978 additions and 395 deletions

View File

@@ -58,6 +58,89 @@ export class ReportsService {
return { fromDate, toDate };
}
private startOfDay(date: Date): Date {
return new Date(
date.getFullYear(),
date.getMonth(),
date.getDate(),
0,
0,
0,
0,
);
}
private endOfDay(date: Date): Date {
return new Date(
date.getFullYear(),
date.getMonth(),
date.getDate(),
23,
59,
59,
999,
);
}
private parseReportPeriodDays(value?: string | number): 30 | 60 | 90 {
const parsed = Number(value ?? 30);
if (parsed === 30 || parsed === 60 || parsed === 90) return parsed;
throw new BadRequestException("periodDays must be one of 30, 60, or 90");
}
private resolveReportDateRange(opts: {
from?: string;
to?: string;
periodDays?: string | number;
} = {}) {
const hasFrom = typeof opts.from === "string" && opts.from.trim().length > 0;
const hasTo = typeof opts.to === "string" && opts.to.trim().length > 0;
const periodDays = this.parseReportPeriodDays(opts.periodDays);
const now = new Date();
if (!hasFrom && !hasTo) {
const toDate = this.endOfDay(now);
const fromBase = new Date(toDate);
fromBase.setDate(fromBase.getDate() - (periodDays - 1));
const fromDate = this.startOfDay(fromBase);
return { mode: "preset" as const, fromDate, toDate, periodDays };
}
let { fromDate, toDate } = this.parseDateRange(opts.from, opts.to);
if (!fromDate && toDate) {
const fromBase = new Date(toDate);
fromBase.setDate(fromBase.getDate() - (periodDays - 1));
fromDate = this.startOfDay(fromBase);
}
if (fromDate && !toDate) {
toDate = this.endOfDay(now);
}
if (!fromDate || !toDate) {
throw new BadRequestException("Could not resolve reporting date range");
}
if (fromDate > toDate) {
throw new BadRequestException("'from' must be before or equal to 'to'");
}
return { mode: "custom" as const, fromDate, toDate, periodDays };
}
private serializeReportRange(range: {
mode: "preset" | "custom";
fromDate: Date;
toDate: Date;
periodDays?: 30 | 60 | 90;
}) {
return {
mode: range.mode,
from: range.fromDate.toISOString(),
to: range.toDate.toISOString(),
...(range.periodDays ? { periodDays: range.periodDays } : {}),
};
}
private isInDateRange(
value: unknown,
fromDate?: Date,
@@ -442,41 +525,40 @@ export class ReportsService {
expertKind?: "all" | "expert" | "damage_expert";
from?: string;
to?: string;
periodDays?: string | number;
page?: number;
limit?: number;
} = {},
): Promise<{ experts: InsurerExpertWorkLogEntryDtoRs[]; total: number }> {
): Promise<{
range: { mode: "preset" | "custom"; from: string; to: string; periodDays?: 30 | 60 | 90 };
experts: InsurerExpertWorkLogEntryDtoRs[];
total: number;
}> {
const clientKey = requireActorClientKey(actor);
const { events, expertRows } =
await this.loadTenantExpertsAndActivities(clientKey);
// expertKind filter
const filteredRows =
!opts.expertKind || opts.expertKind === "all"
? expertRows
: expertRows.filter((r) => r.kind === opts.expertKind);
const now = new Date();
// When from/to supplied, distinctFilesCheckedInPeriod is restricted to that window;
// totalHandled and currentlyChecking are snapshot-at-'to' (or now when to is absent).
const { fromDate, toDate } = this.parseDateRange(opts.from, opts.to);
const cutoff = toDate ?? now;
const checkedFrom = fromDate ?? new Date(0);
const checkedTo = toDate ?? now;
const entries = this.buildWorkLogEntries(filteredRows, events, cutoff, {
from: checkedFrom,
to: checkedTo,
const range = this.resolveReportDateRange(opts);
const entries = this.buildWorkLogEntries(filteredRows, events, range.toDate, {
from: range.fromDate,
to: range.toDate,
});
// Optional pagination
const page = Number(opts.page) > 0 ? Number(opts.page) : 1;
const limit = Number(opts.limit) > 0 ? Number(opts.limit) : entries.length;
const start = (page - 1) * limit;
const paged = entries.slice(start, start + limit);
return { experts: paged, total: entries.length };
return {
range: this.serializeReportRange(range),
experts: paged,
total: entries.length,
};
}
async getInsurerExpertWorkLogPerMonth(actor: {