bpjs-bridge 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +262 -12
- package/dist/__test__/pcare.service.test.js +14 -11
- package/dist/config/enpoints.d.ts +2 -2
- package/dist/config/enpoints.js +2 -2
- package/dist/core/configHelper.d.ts +3 -0
- package/dist/core/configHelper.js +3 -0
- package/dist/core/httpClient.js +75 -15
- package/dist/index.d.ts +9 -0
- package/dist/index.js +10 -0
- package/dist/services/antrean/fktpBPJS.service.d.ts +61 -0
- package/dist/services/antrean/fktpBPJS.service.js +80 -0
- package/dist/services/base.service.d.ts +46 -0
- package/dist/services/base.service.js +183 -0
- package/dist/services/fktp.service.d.ts +2 -1
- package/dist/services/fktp.service.js +5 -4
- package/dist/services/i-care/icare.service.d.ts +36 -0
- package/dist/services/i-care/icare.service.js +43 -0
- package/dist/services/pcare/module/alergi.module.d.ts +15 -0
- package/dist/services/pcare/module/alergi.module.js +20 -0
- package/dist/services/pcare/module/diagnosa.module.d.ts +8 -0
- package/dist/services/pcare/module/diagnosa.module.js +13 -0
- package/dist/services/pcare/module/dokter.module.d.ts +12 -0
- package/dist/services/pcare/module/dokter.module.js +22 -0
- package/dist/services/pcare/module/kesadaran.module.d.ts +14 -0
- package/dist/services/pcare/module/kesadaran.module.js +19 -0
- package/dist/services/pcare/module/komplok.module.d.ts +82 -0
- package/dist/services/pcare/module/komplok.module.js +114 -0
- package/dist/services/pcare/module/kunjungan.module.d.ts +58 -0
- package/dist/services/pcare/module/kunjungan.module.js +115 -0
- package/dist/services/pcare/module/mcu.module.d.ts +40 -0
- package/dist/services/pcare/module/mcu.module.js +59 -0
- package/dist/services/pcare/module/obat.module.d.ts +39 -0
- package/dist/services/pcare/module/obat.module.js +57 -0
- package/dist/services/pcare/module/pendafataran.module.d.ts +55 -0
- package/dist/services/pcare/module/pendafataran.module.js +77 -0
- package/dist/services/pcare/module/peserta.module.d.ts +23 -0
- package/dist/services/pcare/module/peserta.module.js +37 -0
- package/dist/services/pcare/module/poli.module.d.ts +16 -0
- package/dist/services/pcare/module/poli.module.js +24 -0
- package/dist/services/pcare/module/prognosa.module.d.ts +14 -0
- package/dist/services/pcare/module/prognosa.module.js +19 -0
- package/dist/services/pcare/module/provider.module.d.ts +16 -0
- package/dist/services/pcare/module/provider.module.js +24 -0
- package/dist/services/pcare/module/spesialis.module.d.ts +72 -0
- package/dist/services/pcare/module/spesialis.module.js +100 -0
- package/dist/services/pcare/module/statusPulang.module.d.ts +15 -0
- package/dist/services/pcare/module/statusPulang.module.js +22 -0
- package/dist/services/pcare/module/tindakan.module.d.ts +50 -0
- package/dist/services/pcare/module/tindakan.module.js +73 -0
- package/dist/services/pcare/pcare.service.d.ts +32 -60
- package/dist/services/pcare/pcare.service.js +32 -124
- package/dist/types/antreanFktp.d.ts +40 -0
- package/dist/types/antreanFktp.js +2 -0
- package/dist/types/global.d.ts +4 -0
- package/dist/types/globalErroModule.d.ts +22 -0
- package/dist/types/globalErroModule.js +50 -0
- package/dist/types/icare.d.ts +7 -0
- package/dist/types/icare.js +2 -0
- package/dist/types/kelompok.d.ts +109 -0
- package/dist/types/kelompok.js +2 -0
- package/dist/types/kunjungan.d.ts +225 -0
- package/dist/types/kunjungan.js +2 -0
- package/dist/types/pcare.d.ts +130 -0
- package/dist/types/pcare.js +1 -0
- package/dist/types/pendaftaran.d.ts +108 -0
- package/dist/types/pendaftaran.js +2 -0
- package/dist/types/peserta.d.ts +45 -0
- package/dist/types/peserta.js +2 -0
- package/dist/types/spesialis.d.ts +30 -0
- package/dist/types/spesialis.js +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://img.shields.io/badge/Newus%20BPJS%20Bridge-FKTP-blue?style=for-the-badge" />
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
+
<h1 align="center">BPJS Bridge FKTP Service</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
Integrasi BPJS PCare, Antrean FKTP, VClaim, dan iCare dengan dukungan Redis Cache, Logging, dan Modular Service Architecture.
|
|
9
|
+
<br />
|
|
10
|
+
Repository resmi: <a href="https://github.com/NewusTech/bpjs-bridge">NewusTech/bpjs-bridge</a>
|
|
11
|
+
</p>
|
|
5
12
|
|
|
6
13
|
## Installation
|
|
7
14
|
|
|
8
15
|
```bash
|
|
9
|
-
npm
|
|
16
|
+
npm i bpjs-bridge
|
|
10
17
|
```
|
|
11
18
|
|
|
12
19
|
## Usage
|
|
@@ -20,24 +27,267 @@ secretKey: "...",
|
|
|
20
27
|
userKey: "...",
|
|
21
28
|
username: "...",
|
|
22
29
|
password: "..."
|
|
23
|
-
});
|
|
30
|
+
},redist);
|
|
24
31
|
|
|
25
|
-
const dokter = await pcare.
|
|
32
|
+
const dokter = await pcare.dokter.get(0, 10);
|
|
26
33
|
console.log(dokter);
|
|
27
34
|
```
|
|
28
35
|
|
|
29
36
|
---
|
|
30
37
|
|
|
31
|
-
|
|
38
|
+
## 📌 **Fitur Utama**
|
|
39
|
+
|
|
40
|
+
- ⚡ **Redis Caching** untuk mempercepat response BPJS
|
|
41
|
+
- 🔐 Request signing otomatis (X-Signature, Authorization, Timestamp)
|
|
42
|
+
- 🧩 Arsitektur service modular (PcareService, FktpService, AntrolService)
|
|
43
|
+
- 📚 Auto-retry request & error handling kuat
|
|
44
|
+
- 🧵 Prefix Redis per fasilitas kesehatan
|
|
45
|
+
- 🧼 Pattern deletion & flush cache
|
|
46
|
+
- 📦 Endpoints BPJS terstruktur via config JSON
|
|
47
|
+
- 🚀 Support transaksi BPJS GET/POST/PUT/DELETE
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
# Dokumentasi Fitur Redis Cache pada `FktpService`
|
|
52
|
+
|
|
53
|
+
Dokumentasi ini menjelaskan cara kerja sistem caching Redis yang diimplementasikan pada class `FktpService`. Tujuannya adalah mempercepat respons API BPJS, mengurangi beban request berulang, serta meningkatkan performa aplikasi.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 🚀 1. Overview Arsitektur
|
|
58
|
+
|
|
59
|
+
Class **`FktpService`** berfungsi sebagai service utama untuk memanggil endpoint BPJS (PCare, Antrean, VClaim, iCare) dengan fitur tambahan berupa:
|
|
60
|
+
|
|
61
|
+
- Redis caching
|
|
62
|
+
- Prefix key dinamis per fasyankes/puskesmas
|
|
63
|
+
- Otomatis menyimpan dan mengambil cache berdasarkan parameter API
|
|
64
|
+
- TTL (kadaluarsa cache) otomatis
|
|
65
|
+
- Penghapusan berdasarkan pola (pattern deletion)
|
|
66
|
+
- Flush semua cache
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## 🧩 2. Cara Kerja Redis Cache
|
|
71
|
+
|
|
72
|
+
### **a. Inisialisasi Redis**
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
constructor(config, redisClient, chachePrefix) {
|
|
76
|
+
this.client = createBpjsClient(config);
|
|
77
|
+
|
|
78
|
+
if (redisClient) {
|
|
79
|
+
this.redisClient = redisClient;
|
|
80
|
+
|
|
81
|
+
this.redisClient.on("connect", () => console.info("Redis connected"));
|
|
82
|
+
this.redisClient.on("error", err => console.error("Redis error:", err));
|
|
83
|
+
|
|
84
|
+
if (chachePrefix) {
|
|
85
|
+
this.defaultRedisKeyPrefix =
|
|
86
|
+
this.defaultRedisKeyPrefix + "_" + chachePrefix + ":";
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Fitur ini memungkinkan:
|
|
93
|
+
|
|
94
|
+
- Menggunakan Redis secara opsional
|
|
95
|
+
- Menghasilkan prefix unik untuk setiap instansi faskes
|
|
96
|
+
- Mempermudah isolasi cache antar puskesmas
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## 📦 3. Menyimpan Data ke Redis (`set`)
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
private async set(key, value, expInSecond = 3600)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Fungsi ini:
|
|
107
|
+
|
|
108
|
+
- Menerima key dan value
|
|
109
|
+
- Mengubah value menjadi JSON string
|
|
110
|
+
- Menyimpan ke Redis dengan TTL default **3600 detik** (1 jam)
|
|
111
|
+
|
|
112
|
+
Flow:
|
|
113
|
+
|
|
114
|
+
1. Serialize → JSON.stringify
|
|
115
|
+
2. Redis SET key with **EXPIRE**
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## 🔍 4. Mengambil Data dari Redis (`get`)
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
private async get(key)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Fungsi:
|
|
126
|
+
|
|
127
|
+
- Mencari key di Redis
|
|
128
|
+
- Mengembalikan string JSON atau `null` jika tidak ada
|
|
129
|
+
- Logging otomatis jika cache ditemukan
|
|
130
|
+
|
|
131
|
+
Jika data ditemukan:
|
|
132
|
+
|
|
133
|
+
- System **tidak memanggil API BPJS**
|
|
134
|
+
- Mengembalikan data sebagai **fake AxiosResponse**
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 🗑️ 5. Menghapus Cache (`del`)
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
private async del(key)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Menghapus satu cache berdasarkan key lengkap.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## 🧹 6. Hapus Banyak Key Berdasarkan Pola (`deleteKeysByPattern`)
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
private async deleteKeysByPattern(pattern)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Contoh:
|
|
155
|
+
|
|
156
|
+
- Menghapus semua cache endpoint PCare:
|
|
157
|
+
`deleteKeysByPattern("pcare_*")`
|
|
158
|
+
|
|
159
|
+
Fitur ini sangat berguna ketika:
|
|
160
|
+
|
|
161
|
+
- Fasyankes update mapping
|
|
162
|
+
- Data referensi berubah
|
|
163
|
+
- Harus invalidasi cache massal
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## 💣 7. Flush Semua Cache
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
private async flushAll()
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Membersihkan seluruh isi Redis.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## 🔥 8. Mekanisme utama caching di `callEndpoint`
|
|
178
|
+
|
|
179
|
+
### **Langkah-langkah lengkap:**
|
|
180
|
+
|
|
181
|
+
#### 1️⃣ Generate cacheKey
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
const cacheKey = `${name}:${JSON.stringify(params)}`;
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
#### 2️⃣ Cek apakah data sudah ada di Redis
|
|
32
188
|
|
|
33
|
-
|
|
189
|
+
```ts
|
|
190
|
+
const cachedData = await this.get(cacheKey);
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Jika ada → langsung return:
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
return {
|
|
197
|
+
data: parsed,
|
|
198
|
+
status: 200,
|
|
199
|
+
statusText: "OK",
|
|
200
|
+
headers: {},
|
|
201
|
+
config: client.defaults,
|
|
202
|
+
};
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Tanpa memanggil API BPJS!
|
|
206
|
+
|
|
207
|
+
#### 3️⃣ Jika tidak ada cache → BPJS request dijalankan
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
const res = await this.client({ url: endpoint, method: "GET" });
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
#### 4️⃣ Data response yang bukan string disimpan ke Redis
|
|
34
214
|
|
|
35
|
-
|
|
215
|
+
```ts
|
|
216
|
+
await this.set(cacheKey, res.data);
|
|
217
|
+
```
|
|
36
218
|
|
|
37
|
-
|
|
219
|
+
---
|
|
38
220
|
|
|
39
|
-
|
|
221
|
+
## 📘 9. Keuntungan Implementasi Cache
|
|
40
222
|
|
|
41
|
-
|
|
223
|
+
| Fitur | Manfaat |
|
|
224
|
+
| -------------------- | ------------------------------------------------- |
|
|
225
|
+
| Redis TTL | Otomatis invalidasi cache usang |
|
|
226
|
+
| Prefix per puskesmas | Cache tidak saling tercampur |
|
|
227
|
+
| Fake AxiosResponse | Kompatibel dengan semua service yang expect Axios |
|
|
228
|
+
| Pattern deletion | Mudah invalidasi cache masal |
|
|
229
|
+
| Response lebih cepat | Hemat request ke BPJS |
|
|
42
230
|
|
|
43
231
|
---
|
|
232
|
+
|
|
233
|
+
## 📝 10. Contoh Struktur Key Redis
|
|
234
|
+
|
|
235
|
+
```
|
|
236
|
+
bpjs_bridge_fktp_puskesmasA:pcare_diagnosa:{"kode":"A00"}
|
|
237
|
+
bpjs_bridge_fktp_puskesmasA:pcare_obat:{"kdObat":"40102"}
|
|
238
|
+
bpjs_bridge_fktp_puskesmasB:vclaim_peserta:{"nokartu":"000123"}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Prefix → per instansi
|
|
242
|
+
Suffix → berdasarkan endpoint + parameter
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## 🧪 11. Cara Menggunakan dalam Service PCare / Antrean
|
|
247
|
+
|
|
248
|
+
```ts
|
|
249
|
+
const res = await fktpService.callEndpoint("pcare_diagnosa", { kode: "A00" });
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Jika sudah pernah dipanggil → langsung ambil dari Redis.
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## 📄 12. Catatan Penting
|
|
257
|
+
|
|
258
|
+
- Cache **hanya berjalan untuk request GET**, sesuai pola:
|
|
259
|
+
```ts
|
|
260
|
+
if (method === "GET") save to Redis
|
|
261
|
+
```
|
|
262
|
+
- Untuk POST/PUT/DELETE → tidak disimpan agar tidak membuat konflik data.
|
|
263
|
+
- TTL default bisa diganti sesuai kebutuhan.
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
#### ✅ Penutup
|
|
268
|
+
|
|
269
|
+
Dokumentasi ini menjelaskan seluruh mekanisme internal caching Redis yang digunakan pada sistem BPJS Bridge.
|
|
270
|
+
Implementasi ini membuat aplikasi lebih cepat, efisien, dan hemat pemanggilan API.
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
🧑💻 Kontributor
|
|
275
|
+
|
|
276
|
+
Terima kasih kepada semua kontributor yang telah membantu pengembangan project ini 🙏
|
|
277
|
+
|
|
278
|
+
<br> <!-- Contrib rocks --> <p align="center"> <img src="https://contrib.rocks/image?repo=NewusTech/bpjs-bridge" /> </p>
|
|
279
|
+
|
|
280
|
+
<!-- readme: contributors -start -->
|
|
281
|
+
<!-- readme: contributors -end -->
|
|
282
|
+
|
|
283
|
+
📄 Lisensi
|
|
284
|
+
|
|
285
|
+
## MIT License © Newus Teknologi
|
|
286
|
+
|
|
287
|
+
❤️ Dukungan
|
|
288
|
+
|
|
289
|
+
Jika project ini bermanfaat, jangan lupa:
|
|
290
|
+
|
|
291
|
+
⭐ Star repository
|
|
292
|
+
🍴 Fork bila ingin modifikasi
|
|
293
|
+
🐛 Open issue untuk bug/fitur baru
|
|
@@ -4,14 +4,17 @@ const redis_1 = require("../lib/redis");
|
|
|
4
4
|
const pcare_service_1 = require("../services/pcare/pcare.service");
|
|
5
5
|
const config_1 = require("./config");
|
|
6
6
|
// Setup PcareService
|
|
7
|
-
const pcareService = new pcare_service_1.PcareService(config_1.PcareConfig, redis_1.redis);
|
|
7
|
+
const pcareService = new pcare_service_1.PcareService(config_1.PcareConfig, redis_1.redis, "redis_prefix_test");
|
|
8
8
|
describe("PcareService", () => {
|
|
9
|
+
afterAll(() => {
|
|
10
|
+
redis_1.redis.disconnect();
|
|
11
|
+
});
|
|
9
12
|
it("should load environment variables", () => {
|
|
10
13
|
console.log(config_1.PcareConfig);
|
|
11
14
|
expect(config_1.PcareConfig).toBeDefined();
|
|
12
15
|
});
|
|
13
16
|
it("should fetch diagnosa data", async () => {
|
|
14
|
-
const response = await pcareService.
|
|
17
|
+
const response = await pcareService.diagnosa.get("r51", 0, 10);
|
|
15
18
|
expect(response).toEqual(expect.objectContaining({
|
|
16
19
|
count: expect.any(Number), // count harus berupa number
|
|
17
20
|
list: expect.arrayContaining([
|
|
@@ -25,7 +28,7 @@ describe("PcareService", () => {
|
|
|
25
28
|
}));
|
|
26
29
|
});
|
|
27
30
|
it("should fetch getAlergiJenis 01", async () => {
|
|
28
|
-
const response = await pcareService.
|
|
31
|
+
const response = await pcareService.alergi.get("01");
|
|
29
32
|
expect(response).toEqual(expect.objectContaining({
|
|
30
33
|
list: expect.arrayContaining([
|
|
31
34
|
// list harus berupa array
|
|
@@ -37,7 +40,7 @@ describe("PcareService", () => {
|
|
|
37
40
|
}));
|
|
38
41
|
});
|
|
39
42
|
it("should fetch getDokter", async () => {
|
|
40
|
-
const response = await pcareService.
|
|
43
|
+
const response = await pcareService.dokter.get(0, 1);
|
|
41
44
|
expect(response).toEqual(expect.objectContaining({
|
|
42
45
|
count: expect.any(Number),
|
|
43
46
|
list: expect.arrayContaining([
|
|
@@ -49,7 +52,7 @@ describe("PcareService", () => {
|
|
|
49
52
|
}));
|
|
50
53
|
});
|
|
51
54
|
it("should fetch getKesadaran", async () => {
|
|
52
|
-
const response = await pcareService.
|
|
55
|
+
const response = await pcareService.kesadaran.get();
|
|
53
56
|
expect(response).toEqual(expect.objectContaining({
|
|
54
57
|
count: expect.any(Number),
|
|
55
58
|
list: expect.arrayContaining([
|
|
@@ -61,7 +64,7 @@ describe("PcareService", () => {
|
|
|
61
64
|
}));
|
|
62
65
|
});
|
|
63
66
|
it("should fetch getDPHO", async () => {
|
|
64
|
-
const response = await pcareService.getDPHO("a", 0, 1);
|
|
67
|
+
const response = await pcareService.obat.getDPHO("a", 0, 1);
|
|
65
68
|
expect(response).toEqual(expect.objectContaining({
|
|
66
69
|
count: expect.any(Number),
|
|
67
70
|
list: expect.arrayContaining([
|
|
@@ -74,7 +77,7 @@ describe("PcareService", () => {
|
|
|
74
77
|
}));
|
|
75
78
|
});
|
|
76
79
|
it("should fetch Poli FKTP", async () => {
|
|
77
|
-
const response = await pcareService.
|
|
80
|
+
const response = await pcareService.poli.get(0, 1);
|
|
78
81
|
expect(response).toEqual(expect.objectContaining({
|
|
79
82
|
count: expect.any(Number),
|
|
80
83
|
list: expect.arrayContaining([
|
|
@@ -87,7 +90,7 @@ describe("PcareService", () => {
|
|
|
87
90
|
}));
|
|
88
91
|
});
|
|
89
92
|
it("should fetch Provider Rayonisasi", async () => {
|
|
90
|
-
const response = await pcareService.
|
|
93
|
+
const response = await pcareService.provider.get(0, 1);
|
|
91
94
|
expect(response).toEqual(expect.objectContaining({
|
|
92
95
|
count: expect.any(Number),
|
|
93
96
|
list: expect.arrayContaining([
|
|
@@ -99,7 +102,7 @@ describe("PcareService", () => {
|
|
|
99
102
|
}));
|
|
100
103
|
});
|
|
101
104
|
it("should fetch Status Pulang", async () => {
|
|
102
|
-
const response = await pcareService.
|
|
105
|
+
const response = await pcareService.statusPulang.get(false);
|
|
103
106
|
expect(response).toEqual(expect.objectContaining({
|
|
104
107
|
count: expect.any(Number),
|
|
105
108
|
list: expect.arrayContaining([
|
|
@@ -111,7 +114,7 @@ describe("PcareService", () => {
|
|
|
111
114
|
}));
|
|
112
115
|
});
|
|
113
116
|
it("should fetch Referensi Tindakan", async () => {
|
|
114
|
-
const response = await pcareService.
|
|
117
|
+
const response = await pcareService.tindakan.getReferensi("10", 0, 1);
|
|
115
118
|
expect(response).toEqual(expect.objectContaining({
|
|
116
119
|
count: expect.any(Number),
|
|
117
120
|
list: expect.arrayContaining([
|
|
@@ -125,7 +128,7 @@ describe("PcareService", () => {
|
|
|
125
128
|
}));
|
|
126
129
|
});
|
|
127
130
|
it("should fetch Prognosa", async () => {
|
|
128
|
-
const response = await pcareService.
|
|
131
|
+
const response = await pcareService.prognosa.get();
|
|
129
132
|
expect(response).toEqual(expect.objectContaining({
|
|
130
133
|
list: expect.arrayContaining([
|
|
131
134
|
expect.objectContaining({
|
|
@@ -274,13 +274,13 @@ export declare const BaseUrl: {
|
|
|
274
274
|
url_pcare: string;
|
|
275
275
|
url_icare: string;
|
|
276
276
|
url_vclaim: string;
|
|
277
|
-
|
|
277
|
+
url_antrean_fktp: string;
|
|
278
278
|
};
|
|
279
279
|
prod: {
|
|
280
280
|
url_icare: string;
|
|
281
281
|
url_pcare: string;
|
|
282
282
|
url_vclaim: string;
|
|
283
|
-
|
|
283
|
+
url_antrean_fktp: string;
|
|
284
284
|
};
|
|
285
285
|
};
|
|
286
286
|
export type EndpointName = (typeof enpoints)[number]["name"];
|
package/dist/config/enpoints.js
CHANGED
|
@@ -332,12 +332,12 @@ exports.BaseUrl = {
|
|
|
332
332
|
url_pcare: "https://apijkn-dev.bpjs-kesehatan.go.id/pcare-rest-dev",
|
|
333
333
|
url_icare: "https://apijkn-dev.bpjs-kesehatan.go.id/ihs_dev",
|
|
334
334
|
url_vclaim: "https://apijkn-dev.bpjs-kesehatan.go.id/vclaim-rest-dev",
|
|
335
|
-
|
|
335
|
+
url_antrean_fktp: "https://apijkn-dev.bpjs-kesehatan.go.id/antreanfktp_dev",
|
|
336
336
|
},
|
|
337
337
|
prod: {
|
|
338
338
|
url_icare: "https://apijkn.bpjs-kesehatan.go.id/ihs",
|
|
339
339
|
url_pcare: "https://apijkn.bpjs-kesehatan.go.id/pcare-rest",
|
|
340
340
|
url_vclaim: "https://apijkn.bpjs-kesehatan.go.id/vclaim-rest",
|
|
341
|
-
|
|
341
|
+
url_antrean_fktp: "https://apijkn.bpjs-kesehatan.go.id/antreanfktp",
|
|
342
342
|
},
|
|
343
343
|
};
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.resolveConfig = resolveConfig;
|
|
4
4
|
// src/core/configHelper.ts
|
|
5
|
+
/**
|
|
6
|
+
* @deprecated
|
|
7
|
+
*/
|
|
5
8
|
function resolveConfig(globalCfg, serviceCfg) {
|
|
6
9
|
return {
|
|
7
10
|
consId: serviceCfg?.consId ?? globalCfg?.consId,
|
package/dist/core/httpClient.js
CHANGED
|
@@ -7,6 +7,7 @@ exports.createBpjsClient = void 0;
|
|
|
7
7
|
const axios_1 = __importDefault(require("axios"));
|
|
8
8
|
const decrypt_1 = require("./decrypt");
|
|
9
9
|
const security_1 = require("./security");
|
|
10
|
+
const globalErroModule_1 = require("../types/globalErroModule");
|
|
10
11
|
const createBpjsClient = (config) => {
|
|
11
12
|
const client = axios_1.default.create({
|
|
12
13
|
baseURL: config.baseUrl,
|
|
@@ -25,27 +26,86 @@ const createBpjsClient = (config) => {
|
|
|
25
26
|
return req;
|
|
26
27
|
});
|
|
27
28
|
client.interceptors.response.use(async (res) => {
|
|
29
|
+
const url = `${res.config.method?.toUpperCase()} ${res.config.baseURL}/${res.config.url}`;
|
|
28
30
|
const { response: encryptedData } = res.data;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
if (encryptedData) {
|
|
32
|
+
if (typeof encryptedData !== "string") {
|
|
33
|
+
throw new globalErroModule_1.BpjsDecryptionError(`[DECRYPTION ERROR] ${url} Format encrypted data tidak valid, expected string`, { type: typeof encryptedData, data: encryptedData });
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
const timestamp = String(headers["X-timestamp"]);
|
|
37
|
+
if (!timestamp) {
|
|
38
|
+
throw new Error("Timestamp tidak tersedia untuk decryption");
|
|
39
|
+
}
|
|
40
|
+
const decrypted = (0, decrypt_1.decryptBpjsResponse)(encryptedData, config.consId, config.secretKey, timestamp);
|
|
41
|
+
return {
|
|
42
|
+
...res,
|
|
43
|
+
data: decrypted,
|
|
44
|
+
headers: {
|
|
45
|
+
...res.headers,
|
|
46
|
+
"x-decrypted": "true",
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
catch (decryptError) {
|
|
51
|
+
throw new globalErroModule_1.BpjsDecryptionError(`[DECRYPTION ERROR] ${url} : ${decryptError.message}`, {
|
|
52
|
+
originalError: decryptError,
|
|
53
|
+
encryptedLength: encryptedData.length,
|
|
54
|
+
consId: config.consId,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
34
57
|
}
|
|
35
|
-
res.data = `[HTTP CLIENT ERROR => URL : ${res.config.baseURL}/${res.config.url} ] => ${
|
|
36
|
-
|
|
58
|
+
res.data = `[HTTP CLIENT ERROR => URL : ${res.config.baseURL}/${res.config.url} ] => ${"NO_CONTENT_IN_RESPONSE"}`;
|
|
59
|
+
res.status = 204;
|
|
60
|
+
res.statusText = "No Content";
|
|
61
|
+
const AxiosError = {
|
|
62
|
+
name: "BpjsResponseError",
|
|
63
|
+
code: "NO_CONTENT_IN_RESPONSE",
|
|
64
|
+
message: res.data,
|
|
65
|
+
status: res.status,
|
|
66
|
+
config: res.config,
|
|
67
|
+
isAxiosError: true,
|
|
68
|
+
response: {
|
|
69
|
+
data: res.data,
|
|
70
|
+
status: res.status,
|
|
71
|
+
statusText: res.statusText,
|
|
72
|
+
headers: res.headers,
|
|
73
|
+
config: res.config,
|
|
74
|
+
},
|
|
75
|
+
toJSON: () => ({}),
|
|
76
|
+
};
|
|
77
|
+
return Promise.reject(AxiosError);
|
|
37
78
|
}, (err) => {
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
data:
|
|
41
|
-
err.message ??
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
79
|
+
const url = `${err.config.method?.toUpperCase()} ${err.config.baseURL}/${err.config.url}`;
|
|
80
|
+
const fallBackResponse = {
|
|
81
|
+
data: {
|
|
82
|
+
message: `[HTTP CLIENT ERROR => URL : ${url} ] => ${err.response?.data?.metaData?.message ??
|
|
83
|
+
err.message ??
|
|
84
|
+
"unknown error"}`,
|
|
85
|
+
originalResponse: err.response?.data,
|
|
86
|
+
},
|
|
87
|
+
status: err.response?.data?.metaData?.code || err.status || 500,
|
|
88
|
+
statusText: err.response?.data?.metaData?.message ??
|
|
89
|
+
(err.message || "Internal Server Error"),
|
|
45
90
|
headers: {},
|
|
46
91
|
config: err.config || {},
|
|
47
92
|
};
|
|
48
|
-
|
|
93
|
+
const AxiosError = {
|
|
94
|
+
name: "BpjsResponseError",
|
|
95
|
+
message: fallBackResponse.data.message,
|
|
96
|
+
status: fallBackResponse.status,
|
|
97
|
+
config: fallBackResponse.config,
|
|
98
|
+
isAxiosError: true,
|
|
99
|
+
response: {
|
|
100
|
+
data: fallBackResponse.data,
|
|
101
|
+
status: fallBackResponse.status,
|
|
102
|
+
statusText: fallBackResponse.statusText,
|
|
103
|
+
headers: err.headers,
|
|
104
|
+
config: fallBackResponse.config,
|
|
105
|
+
},
|
|
106
|
+
toJSON: () => ({}),
|
|
107
|
+
};
|
|
108
|
+
return Promise.reject(AxiosError);
|
|
49
109
|
});
|
|
50
110
|
return client;
|
|
51
111
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
export * from "./core/httpClient";
|
|
2
2
|
export * from "./core/configHelper";
|
|
3
3
|
export * from "./services/pcare/pcare.service";
|
|
4
|
+
export * from "./services/antrean/fktpBPJS.service";
|
|
5
|
+
export * from "./services/i-care/icare.service";
|
|
4
6
|
export * from "./lib/redis";
|
|
5
7
|
export * from "./types/global";
|
|
6
8
|
export * from "./types/pcare";
|
|
9
|
+
export * from "./types/kunjungan";
|
|
10
|
+
export * from "./types/peserta";
|
|
11
|
+
export * from "./types/kunjungan";
|
|
12
|
+
export * from "./types/pendaftaran";
|
|
13
|
+
export * from "./types/spesialis";
|
|
14
|
+
export * from "./types/antreanFktp";
|
|
15
|
+
export * from "./types/icare";
|
package/dist/index.js
CHANGED
|
@@ -17,6 +17,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
__exportStar(require("./core/httpClient"), exports);
|
|
18
18
|
__exportStar(require("./core/configHelper"), exports);
|
|
19
19
|
__exportStar(require("./services/pcare/pcare.service"), exports);
|
|
20
|
+
__exportStar(require("./services/antrean/fktpBPJS.service"), exports);
|
|
21
|
+
__exportStar(require("./services/i-care/icare.service"), exports);
|
|
20
22
|
__exportStar(require("./lib/redis"), exports);
|
|
23
|
+
//
|
|
21
24
|
__exportStar(require("./types/global"), exports);
|
|
22
25
|
__exportStar(require("./types/pcare"), exports);
|
|
26
|
+
__exportStar(require("./types/kunjungan"), exports);
|
|
27
|
+
__exportStar(require("./types/peserta"), exports);
|
|
28
|
+
__exportStar(require("./types/kunjungan"), exports);
|
|
29
|
+
__exportStar(require("./types/pendaftaran"), exports);
|
|
30
|
+
__exportStar(require("./types/spesialis"), exports);
|
|
31
|
+
__exportStar(require("./types/antreanFktp"), exports);
|
|
32
|
+
__exportStar(require("./types/icare"), exports);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import Redis from "ioredis";
|
|
2
|
+
import { configType } from "../../core/configHelper";
|
|
3
|
+
import { DataArray } from "../../types/global";
|
|
4
|
+
import { AntreanFktpBatalPayload, AntreanFktpPayload, AntreanFktpReferensiDokterType, AntreanFktpReferensiPoliType, AntreanFktpStatusPayload } from "../../types/antreanFktp";
|
|
5
|
+
import { BaseService } from "../base.service";
|
|
6
|
+
/**
|
|
7
|
+
* Service untuk mengakses endpoint Antrean BPJS FKTP
|
|
8
|
+
*/
|
|
9
|
+
export declare class AntreanFktpService extends BaseService {
|
|
10
|
+
/**
|
|
11
|
+
* Constructor AntreanFktpService
|
|
12
|
+
* @param config konfigurasi BPJS
|
|
13
|
+
* @param redisClient instance Redis (opsional)
|
|
14
|
+
* @param chachePrefix prefix untuk cache Redis (opsional)
|
|
15
|
+
*/
|
|
16
|
+
constructor(config: configType, redisClient?: Redis, chachePrefix?: string);
|
|
17
|
+
/**
|
|
18
|
+
*
|
|
19
|
+
* @param tanggal
|
|
20
|
+
* @returns
|
|
21
|
+
* @description
|
|
22
|
+
* Melihat referensi poli pada layanan antrean (WS Antrol)
|
|
23
|
+
*/
|
|
24
|
+
getReferensiPoli(tanggal: string): Promise<DataArray<AntreanFktpReferensiPoliType>>;
|
|
25
|
+
/**
|
|
26
|
+
*
|
|
27
|
+
* @param kodepoli
|
|
28
|
+
* @param tanggal
|
|
29
|
+
* @returns
|
|
30
|
+
* @description
|
|
31
|
+
* Melihat daftar dokter berdasarkan poli dan tanggal
|
|
32
|
+
*/
|
|
33
|
+
getReferensiDokter(kodepoli: string, tanggal: string): Promise<DataArray<AntreanFktpReferensiDokterType>>;
|
|
34
|
+
/**
|
|
35
|
+
*
|
|
36
|
+
* @param body
|
|
37
|
+
* @returns
|
|
38
|
+
* @description
|
|
39
|
+
* Menambah data antrean pasien
|
|
40
|
+
*/
|
|
41
|
+
add(body: AntreanFktpPayload): Promise<null>;
|
|
42
|
+
/**
|
|
43
|
+
*
|
|
44
|
+
* @param body
|
|
45
|
+
* ### notes :
|
|
46
|
+
* - Status 1 = Hadir; Status 2 = Tidak Hadir
|
|
47
|
+
* - Waktu dalam bentuk timestamp milisecond
|
|
48
|
+
* @returns
|
|
49
|
+
* @description
|
|
50
|
+
* Update status antrean hadir/tidak hadir
|
|
51
|
+
*/
|
|
52
|
+
updateStatus(body: AntreanFktpStatusPayload): Promise<null>;
|
|
53
|
+
/**
|
|
54
|
+
*
|
|
55
|
+
* @param body
|
|
56
|
+
* @returns
|
|
57
|
+
* @description
|
|
58
|
+
* Membatalkan antrean pasien
|
|
59
|
+
*/
|
|
60
|
+
batal(body: AntreanFktpBatalPayload): Promise<null>;
|
|
61
|
+
}
|