diff --git a/.env.docker b/.env.docker index ea8375c..7cee720 100644 --- a/.env.docker +++ b/.env.docker @@ -64,5 +64,8 @@ DB_PASSWORD_7=root TENNANT_MASTER_DB=master_erahn TENNANT_KAUNTER_DB=kaunter_erahn +KAUNTER_URL=http://host.docker.internal:8081 +INTERNAL_NOTIFICATION_SECRET=erahn-local-notification-secret + CACHE_DRIVER=file QUEUE_CONNECTION=sync \ No newline at end of file diff --git a/.env.example b/.env.example index 2013ec2..8a444f0 100644 --- a/.env.example +++ b/.env.example @@ -262,3 +262,7 @@ ONEWAYSMS_AUTH_PASS=APIUK330HDAFOUK330 ADMIN_PHONE_NUMBER=60193450165 ACTIVE_JOB_SERVER=false + +# Kaunter inbox (PC modal request → operasi bell). Same secret as kaunter INTERNAL_NOTIFICATION_SECRET. +KAUNTER_URL=http://host.docker.internal:8081 +INTERNAL_NOTIFICATION_SECRET= diff --git a/app/Services/PembiayaanOnline/ModalOnlineService.php b/app/Services/PembiayaanOnline/ModalOnlineService.php index 6579b6d..b27a230 100644 --- a/app/Services/PembiayaanOnline/ModalOnlineService.php +++ b/app/Services/PembiayaanOnline/ModalOnlineService.php @@ -6,6 +6,7 @@ use App\Cawangan; use App\Feature; use App\ModalOnline; use App\RequestModalOnline; +use App\Services\StaffNotificationClient; use Carbon\Carbon; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; @@ -362,6 +363,8 @@ class ModalOnlineService 'nota' => $nota, ]); + $this->notifyOperasiModalRequest($kodcaw, $request, $jenis); + return [ 'ok' => true, 'status' => 201, @@ -373,6 +376,54 @@ class ModalOnlineService ]; } + /** + * Inbox for all operasi staff. Failures must not block the request. + * + * @param string $kodcaw + * @param \App\RequestModalOnline $request + * @param string $jenis + * @return void + */ + protected function notifyOperasiModalRequest($kodcaw, $request, $jenis) + { + try { + app(StaffNotificationClient::class)->notify([ + 'type' => 'modal_online.pending_operasi', + 'cawangan' => $kodcaw, + 'audience' => ['role' => 'operasi'], + 'data' => [ + 'request_id' => $request->id, + 'amaun' => (float) $request->amaun, + 'dimohon_oleh' => $request->dimohon_oleh, + 'jenis' => $jenis, + 'nota' => $request->nota, + 'cawangan_nama' => $this->cawanganNama($kodcaw), + ], + ]); + } catch (\Throwable $e) { + Log::warning('Operasi modal-online notification failed: '.$e->getMessage(), [ + 'kodcaw' => $kodcaw, + 'request_id' => $request->id, + ]); + } + } + + /** + * @param string $kodcaw + * @return string + */ + protected function cawanganNama($kodcaw) + { + $cawangan = Cawangan::on('mysql7')->where('kodcaw', '=', $kodcaw)->first(); + if (!$cawangan) { + return $kodcaw; + } + + $nama = trim((string) $cawangan->nama_cawangan); + + return $nama !== '' ? $nama : $kodcaw; + } + /** * List top-up requests. * For PC: pass kodcaw. For Operasi: omit kodcaw (all branches). diff --git a/app/Services/PembiayaanOnline/PembiayaanOnlineService.php b/app/Services/PembiayaanOnline/PembiayaanOnlineService.php index c8ed689..c760288 100644 --- a/app/Services/PembiayaanOnline/PembiayaanOnlineService.php +++ b/app/Services/PembiayaanOnline/PembiayaanOnlineService.php @@ -11,6 +11,7 @@ use App\Feature; use App\Gadai; use App\Jobs\WhatsappPembiayaanOnlinePaid; use App\PembiayaanOnline; +use App\Services\StaffNotificationClient; use App\Services\Whatsapp\WhatsappCloudClient; use Carbon\Carbon; use Illuminate\Support\Facades\DB; @@ -749,7 +750,7 @@ class PembiayaanOnlineService $tarikh = $now->toDateString(); try { - return DB::connection($mysql)->transaction(function () use ( + $result = DB::connection($mysql)->transaction(function () use ( $mysql, $kodcaw, $ids, @@ -857,6 +858,127 @@ class PembiayaanOnlineService 'payload' => ['message' => 'Gagal hantar batch pembiayaan online'], ]; } + + if (!empty($result['ok'])) { + $this->notifyOperasiBatchSubmitted($kodcaw, $ids, $pcBy, $result['payload']); + } + + return $result; + } + + /** + * Inbox for all operasi staff after PC submit. Failures must not block the batch. + * + * @param string $kodcaw + * @param array $ids + * @param string $pcBy + * @param array $payload + * @return void + */ + protected function notifyOperasiBatchSubmitted($kodcaw, array $ids, $pcBy, array $payload) + { + $batch = isset($payload['batch']) ? $payload['batch'] : null; + if (!$batch) { + return; + } + + $batchId = is_array($batch) ? ($batch['id'] ?? null) : $batch->id; + $batchNo = is_array($batch) ? ($batch['batch_no'] ?? '') : $batch->batch_no; + $slot = is_array($batch) ? ($batch['slot'] ?? '') : $batch->slot; + $bilangan = is_array($batch) ? ($batch['bilangan'] ?? 0) : $batch->bilangan; + $jumlah = is_array($batch) ? ($batch['jumlah_keseluruhan'] ?? 0) : $batch->jumlah_keseluruhan; + + if (!$batchId) { + return; + } + + try { + app(StaffNotificationClient::class)->notify([ + 'type' => 'pembiayaan_online.batch_operasi', + 'cawangan' => $kodcaw, + 'audience' => ['role' => 'operasi'], + 'data' => [ + 'batch_id' => $batchId, + 'batch_no' => $batchNo, + 'slot' => $slot, + 'appended' => !empty($payload['appended']), + 'submitted_count' => count($ids), + 'bilangan' => $bilangan, + 'jumlah_keseluruhan' => (float) $jumlah, + 'pc_submitted_by' => $pcBy, + 'cawangan_nama' => $this->cawanganNama($kodcaw), + ], + ]); + } catch (\Throwable $e) { + Log::warning('Operasi batch notification failed: '.$e->getMessage(), [ + 'kodcaw' => $kodcaw, + 'batch_id' => $batchId, + ]); + } + } + + /** + * @param string $kodcaw + * @return string + */ + protected function cawanganNama($kodcaw) + { + $cawangan = Cawangan::on('mysql7')->where('kodcaw', '=', $kodcaw)->first(); + if (!$cawangan) { + return $kodcaw; + } + + $nama = trim((string) $cawangan->nama_cawangan); + + return $nama !== '' ? $nama : $kodcaw; + } + + /** + * Inbox for PC at this branch. Failures must not block the operasi action. + * + * @param string $kodcaw + * @param string $type + * @param array $data + * @return void + */ + protected function notifyPcPembiayaanOnline($kodcaw, $type, array $data) + { + try { + app(StaffNotificationClient::class)->notify([ + 'type' => $type, + 'cawangan' => $kodcaw, + 'audience' => ['role' => 'pc'], + 'data' => array_merge($data, [ + 'cawangan_nama' => $this->cawanganNama($kodcaw), + ]), + ]); + } catch (\Throwable $e) { + Log::warning('PC pembiayaan-online notification failed: '.$e->getMessage(), [ + 'kodcaw' => $kodcaw, + 'type' => $type, + ]); + } + } + + /** + * @param mixed $line + * @return array + */ + protected function lineNotifyFields($line) + { + if (!$line) { + return []; + } + + $isArr = is_array($line); + + return [ + 'norujukan' => $isArr ? ($line['norujukan'] ?? '') : $line->norujukan, + 'nama_pelanggan' => $isArr ? ($line['nama_pelanggan'] ?? '') : $line->nama_pelanggan, + 'pinjaman' => $isArr ? ($line['pinjaman'] ?? 0) : $line->pinjaman, + 'ops_by' => $isArr ? ($line['ops_by'] ?? '') : $line->ops_by, + 'reject_reason' => $isArr ? ($line['reject_reason'] ?? '') : $line->reject_reason, + ]; } /** @@ -1031,7 +1153,7 @@ class PembiayaanOnlineService $now = Carbon::now(); try { - return DB::connection($mysql)->transaction(function () use ($mysql, $kodcaw, $id, $opsBy, $reason, $now) { + $result = DB::connection($mysql)->transaction(function () use ($mysql, $kodcaw, $id, $opsBy, $reason, $now) { $line = PembiayaanOnline::on($mysql) ->where('kodcaw', $kodcaw) ->where('id', $id) @@ -1102,6 +1224,18 @@ class PembiayaanOnlineService 'payload' => ['message' => 'Gagal tolak pembiayaan online'], ]; } + + if (!empty($result['ok'])) { + $this->notifyPcPembiayaanOnline($kodcaw, 'pembiayaan_online.rejected_pc', array_merge( + $this->lineNotifyFields(isset($result['payload']['pembiayaan_online']) ? $result['payload']['pembiayaan_online'] : null), + [ + 'ops_by' => $opsBy, + 'reject_reason' => $reason, + ] + )); + } + + return $result; } /** @@ -1222,7 +1356,7 @@ class PembiayaanOnlineService } try { - return DB::connection($mysql)->transaction(function () use ( + $result = DB::connection($mysql)->transaction(function () use ( $mysql, $kodcaw, $id, @@ -1321,6 +1455,18 @@ class PembiayaanOnlineService 'payload' => ['message' => 'Gagal tanda PAID / muat naik bukti'], ]; } + + if (!empty($result['ok'])) { + $this->notifyPcPembiayaanOnline($kodcaw, 'pembiayaan_online.paid_pc', array_merge( + $this->lineNotifyFields(isset($result['payload']['pembiayaan_online']) ? $result['payload']['pembiayaan_online'] : null), + [ + 'paid_count' => 1, + 'ops_by' => $opsBy, + ] + )); + } + + return $result; } /** @@ -1366,7 +1512,7 @@ class PembiayaanOnlineService } try { - return DB::connection($mysql)->transaction(function () use ( + $result = DB::connection($mysql)->transaction(function () use ( $mysql, $kodcaw, $batchId, @@ -1458,6 +1604,19 @@ class PembiayaanOnlineService 'payload' => ['message' => 'Gagal tanda PAID batch'], ]; } + + if (!empty($result['ok'])) { + $batch = isset($result['payload']['batch']) ? $result['payload']['batch'] : null; + $this->notifyPcPembiayaanOnline($kodcaw, 'pembiayaan_online.paid_pc', [ + 'paid_count' => isset($result['payload']['dibayar']) ? (int) $result['payload']['dibayar'] : 0, + 'batch_id' => $batch ? (is_array($batch) ? ($batch['id'] ?? null) : $batch->id) : $batchId, + 'batch_no' => $batch ? (is_array($batch) ? ($batch['batch_no'] ?? '') : $batch->batch_no) : '', + 'jumlah_keseluruhan' => $batch ? (is_array($batch) ? ($batch['jumlah_keseluruhan'] ?? 0) : $batch->jumlah_keseluruhan) : 0, + 'ops_by' => $opsBy, + ]); + } + + return $result; } /** diff --git a/app/Services/StaffNotificationClient.php b/app/Services/StaffNotificationClient.php new file mode 100644 index 0000000..6977808 --- /dev/null +++ b/app/Services/StaffNotificationClient.php @@ -0,0 +1,53 @@ +withHeaders([ + 'X-Internal-Token' => $secret, + 'Accept' => 'application/json', + ]) + ->asJson() + ->post($base . '/internal/notifications', $payload); + + if (!$response->successful()) { + Log::warning('Staff notification to kaunter failed', [ + 'status' => $response->status(), + 'body' => $response->body(), + 'type' => isset($payload['type']) ? $payload['type'] : null, + ]); + } + } catch (\Throwable $e) { + Log::warning('Staff notification to kaunter errored: '.$e->getMessage(), [ + 'type' => isset($payload['type']) ? $payload['type'] : null, + ]); + } + } +} diff --git a/bootstrap/app.php b/bootstrap/app.php index b487d31..6b99bbe 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -94,6 +94,7 @@ $app->configure('report'); $app->configure('app_parameter'); $app->configure('parameter'); $app->configure('whatsapp'); +$app->configure('kaunter'); /* |-------------------------------------------------------------------------- | Register Middleware diff --git a/config/kaunter.php b/config/kaunter.php new file mode 100644 index 0000000..5ba78cc --- /dev/null +++ b/config/kaunter.php @@ -0,0 +1,7 @@ + env('KAUNTER_URL', ''), + 'notification_secret' => env('INTERNAL_NOTIFICATION_SECRET', ''), + 'notification_timeout' => (int) env('KAUNTER_NOTIFICATION_TIMEOUT', 3), +];