forked from Yara724/api
YARA-1246
This commit is contained in:
@@ -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: {
|
||||
|
||||
Reference in New Issue
Block a user