feat(api): expose recurrence in schedule detail

This commit is contained in:
avicenan
2026-03-25 11:37:40 +07:00
parent c3f77f4c69
commit ab14a0b670
3 changed files with 55 additions and 2 deletions

View File

@ -197,7 +197,11 @@ export class ScheduleController {
code: 200, code: 200,
message: 'success', message: 'success',
data: { data: {
series: { id: 'uuid-string', title: 'Practice Schedule' }, series: {
id: 'uuid-string',
title: 'Practice Schedule',
recurrence: { $ref: '#/components/schemas/scheduleRecurrence' }
},
exceptions: [{ id: 'uuid-string', occurrence_date: '2026-03-24' }] exceptions: [{ id: 'uuid-string', occurrence_date: '2026-03-24' }]
} }
} }

View File

@ -237,7 +237,16 @@ export class ScheduleModel {
.orderBy("ScheduleException.occurrence_date", "ASC") .orderBy("ScheduleException.occurrence_date", "ASC")
.getMany(); .getMany();
return { series, exceptions }; const recurrenceRule = series.recurrence_rule;
const { recurrence_rule: _omitRule, ...seriesRest } = series as ScheduleSeries & { recurrence_rule?: string | null };
return {
series: {
...seriesRest,
recurrence: ScheduleModel.rRuleToRecurrence(recurrenceRule),
},
exceptions,
};
} }
static async createSeries(payload: ScheduleSeriesPayload, actor: string): Promise<ScheduleSeries> { static async createSeries(payload: ScheduleSeriesPayload, actor: string): Promise<ScheduleSeries> {
@ -466,6 +475,30 @@ export class ScheduleModel {
throw new Error("Unsupported recurrence type"); throw new Error("Unsupported recurrence type");
} }
private static rRuleToRecurrence(recurrence_rule: string | null): RecurrenceInput | null {
if (!recurrence_rule || !String(recurrence_rule).trim()) return null;
const parsed = ScheduleModel.parseRRule(recurrence_rule);
if (!parsed.freq) return null;
const interval = parsed.interval && parsed.interval > 0 ? parsed.interval : 1;
const freq = parsed.freq.toUpperCase();
if (freq === "DAILY") {
return { type: "daily", interval };
}
if (freq === "WEEKLY") {
const out: RecurrenceInput = { type: "weekly", interval };
if (parsed.byDay && parsed.byDay.length > 0) {
out.daysOfWeek = parsed.byDay;
}
return out;
}
if (freq === "MONTHLY") {
return { type: "monthly", interval };
}
return null;
}
private static async getDailyUsedQuotaMap(seriesIds: string[], rangeStart: Date, rangeEnd: Date): Promise<Map<string, number>> { private static async getDailyUsedQuotaMap(seriesIds: string[], rangeStart: Date, rangeEnd: Date): Promise<Map<string, number>> {
const usedQuotaMap = new Map<string, number>(); const usedQuotaMap = new Map<string, number>();
if (seriesIds.length === 0) return usedQuotaMap; if (seriesIds.length === 0) return usedQuotaMap;

View File

@ -385,6 +385,22 @@ const doc = {
$endTimeLocal: "13:00:00", $endTimeLocal: "13:00:00",
$recurrence: { $ref: "#/components/schemas/scheduleRecurrence" } $recurrence: { $ref: "#/components/schemas/scheduleRecurrence" }
}, },
scheduleSeriesDetail: {
$id: "uuid-string",
$room_id: "uuid-string",
$doctor_id: "uuid-string",
$title: "Practice Schedule",
$timezone: "Asia/Jakarta",
$quota: 20,
$start_date: "2026-03-20",
$until_date: "2026-06-30",
$start_time_local: "09:00:00",
$end_time_local: "12:00:00",
$recurrence: { $ref: "#/components/schemas/scheduleRecurrence" },
$status: "Active",
$room: { id: "uuid-string", room: "Room 1" },
$doctor: { id: "uuid-string", name: "Dr A" }
},
scheduleExceptionCreate: { scheduleExceptionCreate: {
$occurrenceDate: "2026-03-24", $occurrenceDate: "2026-03-24",
$isCancelled: false, $isCancelled: false,