mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +00:00
fix(medications): size weekly-cadence supply runway correctly
`estimateDailyDoseCount` only special-cased FREQ=MONTHLY and FREQ=YEARLY. A modern FREQ=WEEKLY rrule (the encoding the create path stores, with an empty daysOfWeek) fell through to the legacy branch at seven days per week, so a once-weekly injection counted as one dose per day. The detail card's "lasts about N days" and the daily low-stock job — which share this math — fired reorder alerts roughly seven times too early (fourteen for bi-weekly). Parse FREQ=WEEKLY honouring INTERVAL and BYDAY count: perDay += (times * bydayCount) / (7 * interval).
This commit is contained in:
1 parent
d85ac3e555
commit
3405bb6fd3
2 files changed
+56
No files matched your search
@@ -68,6 +68,43 @@ describe("estimateDailyDoseCount", () => {
|
||||
).toBeCloseTo(1 / 30);
|
||||
});
|
||||
|
||||
it("treats a once-weekly RRULE as one dose per 7 days", () => {
|
||||
// FREQ=WEEKLY;BYDAY=MO is the modern once-weekly injection encoding;
|
||||
// it must NOT fall through to the daysPerWeek=7 legacy branch.
|
||||
expect(
|
||||
estimateDailyDoseCount([
|
||||
schedule({ timesOfDay: ["08:00"], rrule: "FREQ=WEEKLY;BYDAY=MO" }),
|
||||
]),
|
||||
).toBeCloseTo(1 / 7);
|
||||
});
|
||||
|
||||
it("halves a bi-weekly RRULE via INTERVAL=2 (one dose per 14 days)", () => {
|
||||
expect(
|
||||
estimateDailyDoseCount([
|
||||
schedule({
|
||||
timesOfDay: ["08:00"],
|
||||
rrule: "FREQ=WEEKLY;INTERVAL=2;BYDAY=MO",
|
||||
}),
|
||||
]),
|
||||
).toBeCloseTo(1 / 14);
|
||||
});
|
||||
|
||||
it("counts each BYDAY pick on a weekly RRULE (Mon+Thu → 2 per 7 days)", () => {
|
||||
expect(
|
||||
estimateDailyDoseCount([
|
||||
schedule({ timesOfDay: ["08:00"], rrule: "FREQ=WEEKLY;BYDAY=MO,TH" }),
|
||||
]),
|
||||
).toBeCloseTo(2 / 7);
|
||||
});
|
||||
|
||||
it("defaults a weekly RRULE with no BYDAY to one pick per week", () => {
|
||||
expect(
|
||||
estimateDailyDoseCount([
|
||||
schedule({ timesOfDay: ["08:00"], rrule: "FREQ=WEEKLY" }),
|
||||
]),
|
||||
).toBeCloseTo(1 / 7);
|
||||
});
|
||||
|
||||
it("sums across multiple schedules", () => {
|
||||
expect(
|
||||
estimateDailyDoseCount([
|
||||
|
||||
@@ -46,6 +46,25 @@ export function estimateDailyDoseCount(schedules: RunwaySchedule[]): number {
|
||||
perDay += times / 365;
|
||||
continue;
|
||||
}
|
||||
// FREQ=WEEKLY;BYDAY=…;INTERVAL=… is the modern weekly encoding (the
|
||||
// create path stores the cadence on the rrule and leaves daysOfWeek
|
||||
// empty). Honour the BYDAY pick count and the week INTERVAL: a
|
||||
// once-weekly injection is one dose per 7 days, a bi-weekly one per
|
||||
// 14. Without this branch a weekly rrule fell through to the legacy
|
||||
// daysOfWeek fallback below with daysPerWeek=7, over-estimating the
|
||||
// rate ~7× (≈14× bi-weekly) and firing low-stock alerts far too early.
|
||||
if (/FREQ=WEEKLY/.test(rrule)) {
|
||||
const byday = /BYDAY=([^;]+)/.exec(rrule);
|
||||
const bydayCount =
|
||||
byday && byday[1].length > 0 ? byday[1].split(",").length : 1;
|
||||
const intervalMatch = /INTERVAL=(\d+)/.exec(rrule);
|
||||
const interval =
|
||||
intervalMatch && Number(intervalMatch[1]) >= 1
|
||||
? Number(intervalMatch[1])
|
||||
: 1;
|
||||
perDay += (times * bydayCount) / (7 * interval);
|
||||
continue;
|
||||
}
|
||||
const { daysOfWeek, intervalWeeks } = parseScheduleRecurrence(s.daysOfWeek);
|
||||
const daysPerWeek = daysOfWeek.length > 0 ? daysOfWeek.length : 7;
|
||||
const weeks = intervalWeeks >= 1 ? intervalWeeks : 1;
|
||||
|
||||
Reference in new issue
Block a user