Files
simrsx-fe/ENCOUNTER_API_REFERENCE.md

9.5 KiB

ENCOUNTER API REFERENCE

Endpoints

GET Encounter Detail

GET /api/v1/encounter/{id}
Query Parameters: includes=patient,patient-person,specialist,subspecialist

Response Structure:

{
  "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:

{
  "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:

{
  "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:

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

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

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:

// 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)