fix: align stock and refill semantics

Squash merge PR #474
This commit is contained in:
Daniel Volz
2026-03-25 06:49:34 +01:00
committed by GitHub
parent 37fc2b8e66
commit 7059c25f1c
18 changed files with 1063 additions and 463 deletions
@@ -921,6 +921,39 @@ describe("MedDetailModal stock overflow warning", () => {
});
});
describe("MedDetailModal amount-based stock display", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("shows current liquid stock against configured structural capacity", () => {
const liquidMed: Medication = {
...mockMedication,
id: 20,
name: "Liquid Multi",
packageType: "liquid_container",
packCount: 4,
packageAmountValue: 150,
packageAmountUnit: "ml",
totalPills: 450,
looseTablets: 450,
};
const liquidCoverage: Coverage = {
name: "Liquid Multi",
medsLeft: 450,
daysLeft: 45,
depletionDate: "2024-04-01",
depletionTime: Date.now() + 45 * 86400000,
nextDose: null,
};
render(<MedDetailModal {...defaultProps} selectedMed={liquidMed} coverage={{ all: [liquidCoverage] }} />);
expect(screen.getByText("450 / 600 form.packageAmountUnitMl")).toBeInTheDocument();
expect(screen.queryByText("450 / 450 form.packageAmountUnitMl")).not.toBeInTheDocument();
});
});
describe("MedDetailModal bottle package type", () => {
const bottleMed: Medication = {
id: 2,
@@ -113,6 +113,56 @@ describe("ReportModal", () => {
expect(onClose).toHaveBeenCalledTimes(1);
});
it("exports bottle current stock separately from configured capacity", async () => {
const onClose = vi.fn();
(global.fetch as ReturnType<typeof vi.fn>).mockResolvedValue({
ok: true,
json: async () => ({
1: {
dosesTaken: 0,
automaticDosesTaken: 0,
dosesDismissed: 0,
firstDoseAt: null,
lastDoseAt: null,
refills: [],
},
}),
});
render(
<ReportModal
isOpen={true}
onClose={onClose}
medications={[
createMedication({
packageType: "bottle",
packCount: 0,
blistersPerPack: 1,
pillsPerBlister: 1,
totalPills: 100,
looseTablets: 20,
stockAdjustment: 50,
}),
]}
/>
);
fireEvent.click(screen.getByRole("radio", { name: /report\.formatTxt/i }));
fireEvent.click(screen.getByRole("button", { name: /report\.generate/i }));
await waitFor(() => {
expect(URL.createObjectURL).toHaveBeenCalled();
});
const [blob] = (URL.createObjectURL as ReturnType<typeof vi.fn>).mock.calls.at(-1) ?? [];
const content = await (blob as Blob).text();
expect(content).toContain("report.docTotalCapacity: 100");
expect(content).toContain("report.docCurrentStock: 70 common.pills");
expect(content).not.toContain("report.docCurrentStock: 100 common.pills");
expect(onClose).toHaveBeenCalledTimes(1);
});
it("generates printable report when PDF format is selected", async () => {
const onClose = vi.fn();
const mockWrite = vi.fn();
@@ -344,6 +344,58 @@ describe("UserFilterModal", () => {
expect(screen.queryByText(/600\/600 .*common\.pills/)).not.toBeInTheDocument();
});
it("shows liquid stock against configured multi-container capacity", () => {
const onClose = vi.fn();
const onOpenMedDetail = vi.fn();
const liquidMedication: Medication = {
...mockMedication,
id: 13,
name: "Liquid Multi",
genericName: "Liquid Generic",
packageType: "liquid_container",
packCount: 4,
packageAmountValue: 150,
packageAmountUnit: "ml",
totalPills: 450,
looseTablets: 450,
intakes: [
{
usage: 2,
every: 1,
start: "2024-01-01T09:32:00",
intakeUnit: "ml",
takenBy: "John",
intakeRemindersEnabled: true,
},
],
};
const liquidCoverage: Coverage = {
name: "Liquid Multi",
medsLeft: 450,
daysLeft: 30,
depletionDate: null,
depletionTime: null,
nextDose: null,
};
render(
<UserFilterModal
selectedUser="John"
meds={[liquidMedication]}
coverage={{ all: [liquidCoverage] }}
settings={defaultSettings}
onClose={onClose}
onClearUser={vi.fn()}
onOpenMedDetail={onOpenMedDetail}
/>
);
expect(screen.getByText("450/600 form.packageAmountUnitMl")).toBeInTheDocument();
expect(screen.queryByText("450/450 form.packageAmountUnitMl")).not.toBeInTheDocument();
});
it("renders liquid container intakes and stock in ml", () => {
const onClose = vi.fn();
const onOpenMedDetail = vi.fn();