# ENCOUNTER API REFERENCE ## Endpoints ### GET Encounter Detail ``` GET /api/v1/encounter/{id} Query Parameters: includes=patient,patient-person,specialist,subspecialist ``` **Response Structure:** ```json { "success": true, "message": "OK", "data": { "id": 123, "patient_id": 456, "patient": { "id": 456, "number": "RM-2025-001", "person": { "id": 789, "name": "John Doe", "residentIdentityNumber": "1234567890123456" } }, "appointment_doctor_id": 5, "responsible_doctor_id": 5, "specialist_id": 10, "subspecialist_id": 15, "specialist": { "id": 10, "code": "CARDIO", "name": "Cardiology" }, "subspecialist": { "id": 15, "code": "CARDIO_ADULT", "name": "Cardiology Adult" }, "registeredAt": "2025-12-02T10:30:00Z", "visitDate": "2025-12-02T10:30:00Z", "member_number": "0000123456789", "ref_number": "0301P123456789", "sep_type": "1", "participant_group_code": "1", "paymentMethod_code": "insurance", "vclaimReference": { "noSep": "0301P123456789", "tglRujukan": "2025-12-02T00:00:00Z", "ppkDirujuk": "rssa", "jnsPelayanan": "2", "catatan": "Rujukan BPJS" }, "class_code": "ambulatory", "subClass_code": "reg", "unit_code": "UNIT001", "created_at": "2025-12-01T08:00:00Z", "updated_at": "2025-12-02T10:30:00Z" } } ``` ### PATCH Encounter ``` PATCH /api/v1/encounter/{id} Content-Type: application/json ``` **Request Payload:** ```json { "patient_id": 456, "appointment_doctor_code": "5", "class_code": "ambulatory", "subClass_code": "reg", "unit_code": "UNIT001", "refSource_name": "RSSA", "refTypeCode": "bpjs", "vclaimReference": { "noSep": "0301P123456789", "tglRujukan": "2025-12-02T00:00:00Z", "ppkDirujuk": "rssa", "jnsPelayanan": "2" }, "paymentType": "jkn", "paymentMethod_code": "insurance", "specialist_id": 10, "subspecialist_id": 15, "member_number": "0000123456789", "registeredAt": "2025-12-02T10:30:00.000Z", "visitDate": "2025-12-02T10:30:00.000Z" } ``` **Response:** ```json { "success": true, "message": "Encounter updated successfully", "data": { "id": 123, "patient_id": 456, "updated_at": "2025-12-02T15:45:00Z" } } ``` --- ## Handler Methods ### getFetchEncounterDetail() **Purpose:** Load encounter data and map to form **Trigger:** Automatically on page mount if `props.id > 0` **Logic:** 1. GET `/api/v1/encounter/{id}?includes=patient,patient-person,specialist,subspecialist` 2. Call `mapEncounterToForm()` to transform data 3. Update `formObjects.value` with transformed data 4. Fetch doctors for selected specialist **Logs:** ``` 📥 [EDIT MODE] Loading encounter detail: {id: 123} 📥 [EDIT MODE] API Response: {success: true, data: {...}} 📋 [EDIT MODE] Mapped encounter to form: {...} ✅ [EDIT MODE] Encounter detail loaded and form mapped successfully ``` ### mapEncounterToForm(encounter) **Purpose:** Transform API response to form values **Input:** Encounter object from GET response **Output:** `formObjects.value` with mapped fields **Mapping:** ```typescript formData = { patientName: encounter.patient.person.name, nationalIdentity: encounter.patient.person.residentIdentityNumber, medicalRecordNumber: encounter.patient.number, doctorId: String(encounter.appointment_doctor_id), subSpecialistId: specialist.code (resolved from ID), registerDate: "YYYY-MM-DD" (from registeredAt or visitDate), paymentType: "jkn|spm|pks|jkmm" (mapped from paymentMethod_code), cardNumber: encounter.member_number, sepNumber: encounter.ref_number, sepType: encounter.sep_type, patientCategory: encounter.participant_group_code, sepReference: encounter.vclaimReference?.noSep } ``` ### handleSaveEncounter(formValues) **Purpose:** Save encounter (create or update) **Input:** Form values from validation schema **Output:** POST/PATCH API call and navigation **Logic:** 1. Validate patient selected 2. Build payload with transformations: - Convert doctorId to string - Convert specialist code to ID - Map paymentType to paymentMethod_code - Format dates to ISO 3. If `isEditMode`: PATCH `/api/v1/encounter/{id}` 4. Else: POST `/api/v1/encounter` 5. Success: Toast + redirect to list 6. Error: Toast with error message **Logs:** ``` 💾 [EDIT MODE] Sending PATCH request: {id: 123, payload: {...}} 💾 [ADD MODE] Sending POST request: {payload: {...}} 📤 [SAVE] API Response: {success: true, message: "OK"} ✅ [SAVE] Success - Redirecting to list page ``` --- ## Data Type Mapping ### Payment Type Mapping | Form Value | API Value | Description | |-----------|-----------|-------------| | jkn | insurance | BPJS (Insurance) | | jkmm | insurance | BPJS Mandiri | | spm | cash | Out of pocket | | pks | membership | Partnership/Membership | ### Specialist Type Mapping | Field | Type | Example | |-------|------|---------| | specialist_id | number | 10 | | specialist.code | string | "CARDIO" | | subspecialist_id | number | 15 | | subspecialist.code | string | "CARDIO_ADULT" | ### Date Format Mapping | Format | Usage | Example | |--------|-------|---------| | YYYY-MM-DD | Form display | "2025-12-02" | | ISO 8601 with Z | API send | "2025-12-02T10:30:00.000Z" | | ISO 8601 | API response | "2025-12-02T10:30:00Z" | --- ## Error Codes & Handling | HTTP Status | Error | Handler Response | |-------------|-------|-----------------| | 200 | Success | Navigate to list, show success toast | | 400 | Validation error | Show error message from API | | 401 | Unauthorized | Redirect to login (middleware) | | 403 | Forbidden | RBAC middleware blocks, show error page | | 404 | Not found | Show error toast, redirect to list | | 422 | Unprocessable | Show field-specific validation errors | | 500 | Server error | Show generic error toast, allow retry | --- ## Testing Curl Commands ### Get Encounter Detail ```bash curl -X GET "http://localhost:3000/api/v1/encounter/123?includes=patient,patient-person,specialist,subspecialist" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" ``` ### Update Encounter ```bash curl -X PATCH "http://localhost:3000/api/v1/encounter/123" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "patient_id": 456, "appointment_doctor_code": "5", "class_code": "ambulatory", "subClass_code": "reg", "unit_code": "UNIT001", "paymentType": "jkn", "paymentMethod_code": "insurance", "specialist_id": 10, "subspecialist_id": 15, "member_number": "0000123456789", "registeredAt": "2025-12-02T10:30:00.000Z", "visitDate": "2025-12-02T10:30:00.000Z" }' ``` --- ## Handler Flow Diagram ``` ┌─────────────────────────────────────────────────────────────────┐ │ ENCOUNTER EDIT MODE │ └─────────────────────────────────────────────────────────────────┘ 1. PAGE MOUNT (props.id > 0 = Edit Mode) │ ├─→ handleInit() │ ├─ Load specialists │ ├─ Load doctors │ └─ Load payment types │ ├─→ getFetchEncounterDetail() │ ├─ GET /api/v1/encounter/{id} │ ├─ await mapEncounterToForm() │ │ └─ formObjects.value = { ...mapped data } │ └─ await handleFetchDoctors() │ └─→ Entry form watches props.objects └─ Updates form UI with formObjects data 2. USER EDITS FORM │ └─→ Form state updates reactively └─ Validation runs on change 3. USER CLICKS SAVE │ └─→ handleSaveEncounter(formValues) ├─ Build payload │ └─ Convert types, dates, payment method ├─ if isEditMode: │ └─ PATCH /api/v1/encounter/{id} ├─ else: │ └─ POST /api/v1/encounter ├─ Success: │ ├─ Show success toast │ └─ Navigate to list page └─ Error: ├─ Show error toast └─ Stay on page (allow retry) ``` --- ## Common Issues & Solutions ### Issue: Form not populated after page load **Check:** 1. Console shows `✅ [EDIT MODE] Encounter detail loaded` ✓ 2. formObjects.value has data (check in Vue DevTools) 3. Form watches props.objects properly **Solution:** ```typescript // In entry.vue, ensure watch is set up: watch( () => props.objects, (objects) => { // Auto-populate form fields from props.objects }, { deep: true, immediate: true } ) ``` ### Issue: PATCH request failing with 422 **Check:** 1. Console shows full payload being sent 2. Required fields are present 3. Data types match API expectations (string IDs, ISO dates) **Solution:** Look for payload fields and compare with expected structure in ENCOUNTER_API_REFERENCE.md ### Issue: Specialist not loading after edit **Check:** 1. `subSpecialistId` is correctly set in form 2. `handleFetchDoctors(subSpecialistId)` called after mapEncounterToForm **Solution:** Verify specialist code to ID resolution in `getSpecialistIdsFromCode()` --- ## Performance Notes - GET includes relationships: `patient,patient-person,specialist,subspecialist` - No N+1 queries expected (relationships included) - Form mapping happens once on page load - Doctor list fetched only if specialist selected - Debounced search if SEP number changed (500ms)