Files
cpone_midleware/README.md

254 lines
7.4 KiB
Markdown

# CPONE Middleware Go
Service Go untuk endpoint:
```text
GET /api/cpone/paket
GET /api/cpone/paket/{id}
Authorization: Bearer <your-secure-token>
GET /api/cpone/layanan?page=1
Authorization: Bearer <your-secure-token>
X-RS-Code: <kode-rs>
GET /api/cpone/perusahaan?search=&page=1
GET /api/cpone/perusahaan/{id}
GET /api/cpone/perusahaan/{id}/group-tarif?group_tarif_id=
Authorization: Bearer <your-secure-token>
X-RS-Code: <kode-rs>
GET /api/cpone/tarif-kerjasama?search=&perusahaan_id=&tarif_id=&page=1&per_page=15
Authorization: Bearer <your-secure-token>
GET /api/cpone/tarif-kerjasama/{id}?group_tarif_id=&active=N&effective_date=2026-08-22
Authorization: Bearer <your-secure-token>
GET /api/cpone/periode-tarif
Authorization: Bearer <your-secure-token>
X-RS-Code: <kode-rs>
Endpoint ini menampilkan seluruh periode tarif dari HIS dengan `NA = 'N'`.
GET /api/cpone/periode-tarif/{PeriodeTarifID}?search=&page=1
Authorization: Bearer <your-secure-token>
X-RS-Code: <kode-rs>
Endpoint ini mengambil detail seluruh tarif layanan dari tabel dinamis
`harga_layanan_{PeriodeTarifID}` beserta layanan, departemen, dan kelas tarif.
Parameter `search` mencari berdasarkan `LayananID` atau `NamaLayanan`; hasil
dipaginasi 20 data per halaman.
GET /api/cpone/layanan-mapping-harga?periodeTarifID=10&layananID=6413,6414,1309
Authorization: Bearer <your-secure-token>
POST /api/cpone/patients/lab-registration
Authorization: Bearer <your-secure-token>
Content-Type: application/json
POST /api/cpone/patients/lab-registration/{regId}/services
Authorization: Bearer <your-secure-token>
Content-Type: application/json
POST /api/cpone/patients/lab-registration/{regId}/packages
Authorization: Bearer <your-secure-token>
Content-Type: application/json
POST /api/cpone/patients/medrec
Authorization: Bearer <your-secure-token>
Content-Type: application/json
```
Format payload dan response dibuat mengikuti controller PHP CPONE terkait.
Contoh payload pembuatan pasien HIS:
```json
{
"rs": "PRIMAYA",
"nama": "BUDI SANTOS",
"jenis_kelamin": "L",
"tgl_lahir": "1990-01-15",
"jenis_nomer_sosial": "KTP",
"nomer_sosial": "3174011501900001",
"telepon": "081234567890",
"ponsel": "081234567890",
"email": "budi@example.com",
"tempat_lahir": "JAKARTA",
"alamat": "JL. CONTOH NO. 1",
"propinsi": "DKI JAKARTA",
"kabupaten": "JAKARTA",
"kecamatan": "KECAMATAN CONTOH",
"kelurahan": "KELURAHAN CONTOH",
"kode_pos": "12345",
"perusahaan_id": "PE260700001",
"nik_karyawan": "TSB2026002",
"dependant_id": "D001",
"nama_karyawan": "BUDI SANTOS",
"channel": "CPONE"
}
```
Endpoint mengembalikan `created`, `already_exists`, atau `possible_duplicate`
sesuai hasil pemeriksaan identitas dan kemiripan data pasien di HIS.
Contoh payload registrasi laboratorium:
```json
{
"medrec_id": "00001234",
"tanggal": "2026-08-18",
"departemen_id": "LAB",
"dokter_id": "DR01",
"dokter_pengirim_id": "DR02",
"perujuk": null,
"jenis_pasien_id": "0",
"periode_tarif_id": 10,
"kelas_id": "Default",
"shift_harian_id": null,
"diagnosa_kerja": "Pemeriksaan laboratorium",
"catatan": null,
"channel": "CPONE"
}
```
`dokter_pengirim_id` atau `perujuk` wajib diisi. Endpoint ini membuat
registrasi laboratorium tanpa layanan, sama seperti
`PatientController::registerLab`; layanan ditambahkan melalui endpoint terpisah.
Contoh payload penambahan layanan:
```json
{
"layanan": [
{
"layanan_id": "6413",
"jumlah": 1,
"cito": false,
"markup_cito": 0,
"catatan": null
}
],
"channel": "CPONE"
}
```
Harga, diskon publik, share, unit cost, layanan multiple, dan spesimen diambil
langsung dari master HIS. Layanan yang sudah ada akan dilewati dan dilaporkan
melalui `skipped_layanan_ids`.
Contoh payload penambahan Paket Dispenser HIS:
```json
{
"paket_id": "DISP-260800011",
"cito": false,
"markup_cito": 0,
"catatan": "",
"channel": "CPONE"
}
```
Paket harus aktif, disetujui, berlaku untuk rawat jalan, dan belum memiliki
layanan yang sama pada registrasi. Request ulang untuk paket yang sudah masuk
bersifat idempoten dan tidak membuat transaksi ganda.
## Config
Copy `.env.example` menjadi `.env`, lalu isi koneksi MySQL:
```text
APP_HOST=0.0.0.0
APP_PORT=8080
CPONE_DB_HOST=127.0.0.1
CPONE_DB_PORT=3306
CPONE_DB_DATABASE=cpone_middleware
CPONE_DB_USERNAME=root
CPONE_DB_PASSWORD=
CPONE_BEARER_TOKEN=replace-with-a-secure-token
CPONE_DATABASE_SETTINGS_TOKEN=replace-with-a-different-admin-token
CPONE_DATABASE_CREDENTIAL_KEY=replace-with-a-long-random-encryption-key
```
## Multi-database per kode RS
Tambahkan atau perbarui koneksi RS melalui API berikut. Koneksi akan dites
sebelum disimpan; bila `Ping` gagal, setting tidak disimpan.
```http
POST /api/cpone/database-settings
Authorization: Bearer <your-database-settings-token>
Content-Type: application/json
{
"kode_rs": "PRIMAYA_BEKASI_BARAT",
"nama": "Primaya Hospital Bekasi Barat",
"host": "10.10.10.20",
"port": "3306",
"database": "his_bekasi_barat",
"username": "cpone",
"password": "secret"
}
```
Endpoint pengelolaan yang tersedia:
```text
POST /api/cpone/database-settings
GET /api/cpone/database-settings
GET /api/cpone/database-settings/{kodeRs}
```
Daftar ringkas rumah sakit aktif dapat diambil tanpa memilih database HIS:
```http
GET /api/cpone/hospitals
Authorization: Bearer <your-secure-token>
```
Response hanya memuat `kode_rs`, `nama`, dan `status`; rumah sakit nonaktif tidak
ditampilkan.
Saat startup, service otomatis membuat database `CPONE_DB_DATABASE` beserta
tabel `hospitals` dan `hospital_databases`. Tidak ada database RS default; semua
koneksi HIS harus ditambahkan lewat API. Akun `CPONE_DB_USERNAME` harus memiliki
izin `CREATE DATABASE` pada bootstrap pertama; alternatifnya jalankan migration
di direktori `database/migrations` secara manual.
Response list/detail tidak pernah menampilkan password, hanya field
`has_password`. Password koneksi RS disimpan terenkripsi AES-GCM menggunakan
`CPONE_DATABASE_CREDENTIAL_KEY`. Jangan mengubah key tersebut setelah data mulai
disimpan karena password lama tidak akan bisa didekripsi. Jika key belum diisi,
service memakai `CPONE_DATABASE_SETTINGS_TOKEN`, lalu `CPONE_BEARER_TOKEN`
sebagai fallback; token fallback itu juga tidak boleh diubah tanpa rotasi
credential.
Endpoint pengelolaan memakai `CPONE_DATABASE_SETTINGS_TOKEN`. Jika variabel ini
belum diisi, service memakai `CPONE_BEARER_TOKEN` untuk kompatibilitas; gunakan
token admin yang berbeda di production.
Pilih database pada semua endpoint bisnis dengan header:
```http
X-RS-Code: PRIMAYA_BEKASI_BARAT
```
Sebagai alternatif dapat memakai query `?kode_rs=PRIMAYA_BEKASI_BARAT`.
Header memiliki prioritas lebih tinggi daripada query. Response juga memuat
header `X-RS-Code` agar koneksi yang terpilih mudah diaudit. Salah satu dari
header atau query tersebut wajib dikirim; jika tidak ada, API mengembalikan
status `422` dan tidak mengakses database HIS.
## Run
```bash
cd cpone-middleware
go mod tidy
go run ./cmd/server
```
## SQLC
File `sqlc.yaml`, `sqlc/schema.sql`, dan `sqlc/query.sql` sudah disiapkan.
Catatan penting: sqlc tidak bisa menerima nama tabel dinamis seperti `harga_layanan_{periodeTarifID}`. Implementasi runtime saat ini tetap memakai `database/sql` untuk menyusun nama tabel setelah `periodeTarifID` divalidasi angka, sama seperti PHP memakai `HargaLayanan::makeTableName()`. Kalau semua periode ingin digenerate oleh sqlc, buat query konkret per tabel periode, misalnya `harga_layanan_10`, `harga_layanan_11`, dan seterusnya.