feat(api): support schedule quota tracking
This commit is contained in:
@ -14,6 +14,7 @@ type ScheduleSeriesPayload = {
|
||||
doctorId: string;
|
||||
title: string;
|
||||
timezone: string;
|
||||
quota?: number | null;
|
||||
startDate: string;
|
||||
untilDate?: string | null;
|
||||
startTimeLocal: string;
|
||||
@ -82,6 +83,7 @@ export class ScheduleModel {
|
||||
if (seriesList.length === 0) return { resources: [], events: [] };
|
||||
|
||||
const seriesIds = seriesList.map((series) => series.id);
|
||||
const usageMap = await ScheduleModel.getDailyUsedQuotaMap(seriesIds, rangeStart, rangeEnd);
|
||||
const exceptionRepo = OrmHelper.DB.getRepository(ScheduleException);
|
||||
const exceptions = await exceptionRepo
|
||||
.createQueryBuilder("ScheduleException")
|
||||
@ -132,6 +134,12 @@ export class ScheduleModel {
|
||||
title: eventTitle,
|
||||
startAt: eventStart.toISOString(),
|
||||
endAt: eventEnd.toISOString(),
|
||||
quota: series.quota ?? null,
|
||||
usedQuota: usageMap.get(`${series.id}:${occurrenceYmd}`) || 0,
|
||||
leftQuota:
|
||||
typeof series.quota === "number"
|
||||
? Math.max(0, series.quota - (usageMap.get(`${series.id}:${occurrenceYmd}`) || 0))
|
||||
: null,
|
||||
isRecurring: !!series.recurrence_rule,
|
||||
isException: !!exception,
|
||||
status: "confirmed",
|
||||
@ -246,6 +254,7 @@ export class ScheduleModel {
|
||||
series.doctor = doctor;
|
||||
series.title = payload.title;
|
||||
series.timezone = payload.timezone;
|
||||
series.quota = payload.quota ?? null;
|
||||
series.start_date = new Date(payload.startDate);
|
||||
series.until_date = payload.untilDate ? new Date(payload.untilDate) : null;
|
||||
series.start_time_local = payload.startTimeLocal;
|
||||
@ -278,6 +287,7 @@ export class ScheduleModel {
|
||||
series.doctor = doctor;
|
||||
series.title = payload.title;
|
||||
series.timezone = payload.timezone;
|
||||
series.quota = payload.quota ?? null;
|
||||
series.start_date = new Date(payload.startDate);
|
||||
series.until_date = payload.untilDate ? new Date(payload.untilDate) : null;
|
||||
series.start_time_local = payload.startTimeLocal;
|
||||
@ -455,4 +465,38 @@ export class ScheduleModel {
|
||||
}
|
||||
throw new Error("Unsupported recurrence type");
|
||||
}
|
||||
|
||||
private static async getDailyUsedQuotaMap(seriesIds: string[], rangeStart: Date, rangeEnd: Date): Promise<Map<string, number>> {
|
||||
const usedQuotaMap = new Map<string, number>();
|
||||
if (seriesIds.length === 0) return usedQuotaMap;
|
||||
|
||||
const placeholders = seriesIds.map((_, index) => `$${index + 1}`).join(", ");
|
||||
const startParamIndex = seriesIds.length + 1;
|
||||
const endParamIndex = seriesIds.length + 2;
|
||||
const params = [...seriesIds, ScheduleModel.formatYmd(rangeStart), ScheduleModel.formatYmd(rangeEnd)];
|
||||
|
||||
const query = `
|
||||
SELECT
|
||||
ro."scheduleSeriesId" AS series_id,
|
||||
DATE(ro.visit_date) AS visit_date,
|
||||
COUNT(ro.id) AS used_count
|
||||
FROM emr.emr_registration_outpatient ro
|
||||
WHERE ro."scheduleSeriesId" IN (${placeholders})
|
||||
AND DATE(ro.visit_date) BETWEEN $${startParamIndex} AND $${endParamIndex}
|
||||
AND ro.deleted_at IS NULL
|
||||
GROUP BY ro."scheduleSeriesId", DATE(ro.visit_date)
|
||||
`;
|
||||
|
||||
const rows: Array<{ series_id: string; visit_date: string | Date; used_count: string | number }> = await OrmHelper.DB.manager.query(
|
||||
query,
|
||||
params
|
||||
);
|
||||
|
||||
for (const row of rows) {
|
||||
const occurrenceYmd = ScheduleModel.formatYmd(new Date(row.visit_date));
|
||||
usedQuotaMap.set(`${row.series_id}:${occurrenceYmd}`, Number(row.used_count) || 0);
|
||||
}
|
||||
|
||||
return usedQuotaMap;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user