Files
simrsx-fe/ENCOUNTER_API_REFERENCE.md

348 lines
9.5 KiB
Markdown

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