diff --git a/openapi_first/templates/vet_app/data.py b/openapi_first/templates/vet_app/data.py index c67e98a..3b1f47f 100644 --- a/openapi_first/templates/vet_app/data.py +++ b/openapi_first/templates/vet_app/data.py @@ -22,7 +22,9 @@ from models import ( Parent, ParentCreate, Vet, VetCreate, Treatment, TreatmentCreate, - Procedure, ProcedureNotes, + Procedure, + BasicNote, HeartRateNote, DentalNote, + VaccineNote, PreOpNote, SurgeryNote, Pet, PetCreate, Appointment, AppointmentCreate, ) @@ -339,16 +341,29 @@ def _seed_data(): _pets_next_id = 6 _appointments[1] = Appointment(id=1, date=datetime(2026, 6, 18, 9, 0, tzinfo=timezone.utc), notes="Annual checkup", - procedures=[Procedure(name="Physical Exam", cost=50.0), Procedure(name="Heart Rate", notes=ProcedureNotes(summary="Normal rhythm"))], + procedures=[ + Procedure(name="Physical Exam", cost=50.0, notes=BasicNote(summary="Normal findings", details="Heart rate and temperature within normal range")), + Procedure(name="Heart Rate", notes=HeartRateNote(summary="Normal rhythm", bpm=65)), + ], pet=_pets[1], vet=_vets[1], treatment=_treatments[1], metadata=meta) _appointments[2] = Appointment(id=2, date=datetime(2026, 6, 18, 10, 30, tzinfo=timezone.utc), notes="Dental cleaning", - procedures=[Procedure(name="Scaling", cost=80.0), Procedure(name="Polishing", cost=40.0, notes=ProcedureNotes(summary="High-speed polish"))], + procedures=[ + Procedure(name="Scaling", cost=80.0, notes=DentalNote(summary="Moderate tartar removed", procedureType="scaling", teeth="all")), + Procedure(name="Polishing", cost=40.0, notes=DentalNote(summary="High-speed polish applied", procedureType="polishing", teeth="all")), + ], pet=_pets[2], vet=_vets[2], treatment=_treatments[3], metadata=meta) _appointments[3] = Appointment(id=3, date=datetime(2026, 6, 19, 11, 0, tzinfo=timezone.utc), notes="Vaccination booster", - procedures=[Procedure(name="DHPP Vaccine", cost=35.0), Procedure(name="Rabies Vaccine", cost=45.0)], + procedures=[ + Procedure(name="Vaccine", cost=35.0, notes=VaccineNote(summary="Administered", medicine="DHPP", leg="hind_left")), + Procedure(name="Vaccine", cost=45.0, notes=VaccineNote(summary="Administered", medicine="Rabies", leg="hind_right")), + ], pet=_pets[3], vet=_vets[3], treatment=_treatments[2], metadata=meta) _appointments[4] = Appointment(id=4, date=datetime(2026, 6, 20, 14, 0, tzinfo=timezone.utc), notes="Follow-up after surgery", - procedures=[Procedure(name="Pre-op Exam", cost=30.0), Procedure(name="Surgery", cost=200.0), Procedure(name="Post-op Care", cost=50.0)], + procedures=[ + Procedure(name="PreOp", cost=30.0, notes=PreOpNote(summary="Pre-op clearance", heartRate=80, temperature=38.5)), + Procedure(name="Neuter", cost=200.0, notes=SurgeryNote(summary="Surgery completed", surgeryType="neuter", complications="None")), + Procedure(name="PostOp", cost=50.0, notes=BasicNote(summary="Recovering well", details="Eating and drinking normally")), + ], pet=_pets[5], vet=_vets[1], treatment=_treatments[4], metadata=meta) _appointments_next_id = 5 diff --git a/openapi_first/templates/vet_app/models.py b/openapi_first/templates/vet_app/models.py index 898dac8..fe98dd0 100644 --- a/openapi_first/templates/vet_app/models.py +++ b/openapi_first/templates/vet_app/models.py @@ -1,5 +1,6 @@ from datetime import date, datetime -from pydantic import BaseModel +from typing import Annotated, Literal +from pydantic import BaseModel, Field class Metadata(BaseModel): @@ -38,11 +39,50 @@ class Vet(VetBase): id: int -class ProcedureNotes(BaseModel): +class ProcedureNoteBase(BaseModel): summary: str | None = None details: str | None = None +class BasicNote(ProcedureNoteBase): + noteType: Literal["basic"] = "basic" + + +class HeartRateNote(ProcedureNoteBase): + noteType: Literal["heart_rate"] = "heart_rate" + bpm: int + + +class DentalNote(ProcedureNoteBase): + noteType: Literal["dental"] = "dental" + procedureType: Literal["scaling", "polishing"] + teeth: str | None = None + + +class VaccineNote(ProcedureNoteBase): + noteType: Literal["vaccine"] = "vaccine" + medicine: Literal["Rabies", "DHPP", "Tricat", "Deworming"] + leg: Literal["front_left", "front_right", "hind_left", "hind_right"] + + +class PreOpNote(ProcedureNoteBase): + noteType: Literal["preop"] = "preop" + heartRate: int + temperature: float + + +class SurgeryNote(ProcedureNoteBase): + noteType: Literal["surgery"] = "surgery" + surgeryType: Literal["neuter", "spay"] + complications: str | None = None + + +ProcedureNotes = Annotated[ + BasicNote | HeartRateNote | DentalNote | VaccineNote | PreOpNote | SurgeryNote, + Field(discriminator="noteType"), +] + + class Procedure(BaseModel): name: str | None = None description: str | None = None diff --git a/openapi_first/templates/vet_app/openapi.yaml b/openapi_first/templates/vet_app/openapi.yaml index 7888d29..494ceec 100644 --- a/openapi_first/templates/vet_app/openapi.yaml +++ b/openapi_first/templates/vet_app/openapi.yaml @@ -45,9 +45,8 @@ components: x-order: 4 x-label: "Notes" - ProcedureNotes: + ProcedureNoteBase: type: object - x-display-format: "{summary}" properties: summary: type: string @@ -58,6 +57,139 @@ components: x-order: 2 x-label: "Details" + ProcedureNotes: + x-display-format: "{summary}" + oneOf: + - $ref: '#/components/schemas/BasicNote' + - $ref: '#/components/schemas/HeartRateNote' + - $ref: '#/components/schemas/DentalNote' + - $ref: '#/components/schemas/VaccineNote' + - $ref: '#/components/schemas/PreOpNote' + - $ref: '#/components/schemas/SurgeryNote' + discriminator: + propertyName: noteType + mapping: + basic: BasicNote + heart_rate: HeartRateNote + dental: DentalNote + vaccine: VaccineNote + preop: PreOpNote + surgery: SurgeryNote + + BasicNote: + allOf: + - $ref: '#/components/schemas/ProcedureNoteBase' + - type: object + properties: + noteType: + type: string + enum: [basic] + x-order: 0 + x-label: "Type" + required: [noteType] + + HeartRateNote: + allOf: + - $ref: '#/components/schemas/ProcedureNoteBase' + - type: object + properties: + noteType: + type: string + enum: [heart_rate] + x-order: 0 + x-label: "Type" + bpm: + type: integer + x-order: 3 + x-label: "Heart Rate (bpm)" + required: [noteType, bpm] + + DentalNote: + allOf: + - $ref: '#/components/schemas/ProcedureNoteBase' + - type: object + properties: + noteType: + type: string + enum: [dental] + x-order: 0 + x-label: "Type" + procedureType: + type: string + enum: [scaling, polishing] + x-order: 3 + x-label: "Procedure" + teeth: + type: string + enum: [all, upper_only, lower_only] + x-order: 4 + x-label: "Teeth" + required: [noteType, procedureType] + + VaccineNote: + allOf: + - $ref: '#/components/schemas/ProcedureNoteBase' + - type: object + properties: + noteType: + type: string + enum: [vaccine] + x-order: 0 + x-label: "Type" + medicine: + type: string + enum: [Rabies, DHPP, Tricat, Deworming] + x-order: 3 + x-label: "Medicine" + leg: + type: string + enum: [front_left, front_right, hind_left, hind_right] + x-order: 4 + x-label: "Injection Leg" + required: [noteType, medicine, leg] + + PreOpNote: + allOf: + - $ref: '#/components/schemas/ProcedureNoteBase' + - type: object + properties: + noteType: + type: string + enum: [preop] + x-order: 0 + x-label: "Type" + heartRate: + type: integer + x-order: 3 + x-label: "Heart Rate (bpm)" + temperature: + type: number + format: float + x-order: 4 + x-label: "Temperature (°C)" + required: [noteType, heartRate, temperature] + + SurgeryNote: + allOf: + - $ref: '#/components/schemas/ProcedureNoteBase' + - type: object + properties: + noteType: + type: string + enum: [surgery] + x-order: 0 + x-label: "Type" + surgeryType: + type: string + enum: [neuter, spay] + x-order: 3 + x-label: "Surgery Type" + complications: + type: string + x-order: 4 + x-label: "Complications" + required: [noteType, surgeryType] + Call: type: object x-primary-key: _received_at