From cf831c4602ac52bf7ecfb939385f41dc13b5d8e3 Mon Sep 17 00:00:00 2001 From: JamilatulMuyasaroh Date: Wed, 13 May 2026 16:34:54 +0700 Subject: [PATCH 1/2] feat(hospitalportal): add provider and request log schema --- app/Models/Provider.php | 39 +++++++ app/Models/RequestLog.php | 106 ++++++++++++++++++ app/Models/RequestLogBenefit.php | 33 ++++++ ...26_05_13_150000_create_providers_table.php | 48 ++++++++ ...05_13_150100_create_request_logs_table.php | 93 +++++++++++++++ ...0200_create_request_log_benefits_table.php | 54 +++++++++ 6 files changed, 373 insertions(+) create mode 100644 app/Models/Provider.php create mode 100644 app/Models/RequestLog.php create mode 100644 app/Models/RequestLogBenefit.php create mode 100644 database/migrations/2026_05_13_150000_create_providers_table.php create mode 100644 database/migrations/2026_05_13_150100_create_request_logs_table.php create mode 100644 database/migrations/2026_05_13_150200_create_request_log_benefits_table.php diff --git a/app/Models/Provider.php b/app/Models/Provider.php new file mode 100644 index 00000000..7d91d6be --- /dev/null +++ b/app/Models/Provider.php @@ -0,0 +1,39 @@ +belongsTo(Organization::class, 'organization_id'); + } +} + diff --git a/app/Models/RequestLog.php b/app/Models/RequestLog.php new file mode 100644 index 00000000..e9d7ddee --- /dev/null +++ b/app/Models/RequestLog.php @@ -0,0 +1,106 @@ + 'boolean', + 'admission_date' => 'datetime', + 'discharge_date' => 'datetime', + ]; + + protected static function boot() + { + parent::boot(); + + static::creating(function (self $model) { + if (empty($model->uuid)) { + $model->uuid = (string) Str::orderedUuid(); + } + + if (empty($model->code)) { + $model->code = self::getNextCode(); + } + }); + } + + public static function getNextCode(): string + { + $lastCode = (string) self::withTrashed()->max('code'); + preg_match('/(\d+)$/', $lastCode, $matches); + $nextNumber = isset($matches[1]) ? ((int) $matches[1] + 1) : (self::withTrashed()->count() + 1); + + return self::makeCode($nextNumber); + } + + public static function makeCode(int $nextNumber): string + { + return self::$codePrefix . '-' . str_pad((string) $nextNumber, 5, '0', STR_PAD_LEFT); + } + + public function organization() + { + return $this->belongsTo(Organization::class, 'organization_id'); + } + + public function member() + { + return $this->belongsTo(Member::class, 'member_id'); + } + + public function plan() + { + return $this->belongsTo(Plan::class, 'plan_id'); + } + + public function requestLogBenefits() + { + return $this->hasMany(RequestLogBenefit::class, 'request_log_id'); + } +} diff --git a/app/Models/RequestLogBenefit.php b/app/Models/RequestLogBenefit.php new file mode 100644 index 00000000..80bbeed2 --- /dev/null +++ b/app/Models/RequestLogBenefit.php @@ -0,0 +1,33 @@ +belongsTo(RequestLog::class, 'request_log_id'); + } + + public function benefit() + { + return $this->belongsTo(Benefit::class, 'benefit_id'); + } +} diff --git a/database/migrations/2026_05_13_150000_create_providers_table.php b/database/migrations/2026_05_13_150000_create_providers_table.php new file mode 100644 index 00000000..fb5d37fe --- /dev/null +++ b/database/migrations/2026_05_13_150000_create_providers_table.php @@ -0,0 +1,48 @@ +id(); + $table->foreignId('organization_id')->nullable()->index(); + $table->string('username')->index(); + $table->string('password'); + $table->string('code')->index(); + $table->string('status')->default('active'); + $table->text('header_token')->nullable(); + $table->text('token')->nullable(); + + $table->timestamps(); + $table->softDeletes(); + + $table->unsignedBigInteger('created_by')->nullable()->index(); + $table->unsignedBigInteger('updated_by')->nullable()->index(); + $table->unsignedBigInteger('deleted_by')->nullable()->index(); + + $table->unique(['organization_id', 'username']); + $table->unique(['organization_id', 'code']); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('providers'); + } +}; + diff --git a/database/migrations/2026_05_13_150100_create_request_logs_table.php b/database/migrations/2026_05_13_150100_create_request_logs_table.php new file mode 100644 index 00000000..94e57552 --- /dev/null +++ b/database/migrations/2026_05_13_150100_create_request_logs_table.php @@ -0,0 +1,93 @@ +id(); + $table->uuid('uuid'); + $table->string('code')->index(); + $table->foreignId('organization_id')->nullable()->index(); + $table->foreignId('member_id')->nullable()->index(); + $table->foreignId('plan_id')->nullable()->index(); + + $table->string('service_code')->nullable()->comment('IP / OP'); + $table->string('status')->nullable()->default('approved'); + $table->boolean('final_log')->default(false); + $table->string('status_final_log')->nullable(); + $table->string('source')->nullable()->default('api'); + + $table->text('keterangan')->nullable(); + $table->string('penempatan_kamar')->nullable(); + $table->decimal('total_cob', 18, 2)->nullable(); + + $table->string('nomor_sep')->nullable(); + $table->string('inacbgs_code')->nullable(); + $table->decimal('inacbgs_amount', 18, 2)->nullable(); + $table->string('no_transaksi_provider')->nullable(); + + $table->dateTime('admission_date')->nullable(); + $table->dateTime('discharge_date')->nullable(); + $table->string('diagnosis')->nullable(); + $table->string('nomor_rujukan')->nullable(); + $table->string('status_rujukan')->nullable(); + + $table->timestamps(); + $table->softDeletes(); + + $table->unsignedBigInteger('created_by')->nullable()->index(); + $table->unsignedBigInteger('updated_by')->nullable()->index(); + $table->unsignedBigInteger('deleted_by')->nullable()->index(); + }); + return; + } + + Schema::table('request_logs', function (Blueprint $table) { + if (!Schema::hasColumn('request_logs', 'plan_id')) { + $table->foreignId('plan_id')->nullable()->index()->after('member_id'); + } + if (!Schema::hasColumn('request_logs', 'nomor_sep')) { + $table->string('nomor_sep')->nullable()->after('penempatan_kamar'); + } + if (!Schema::hasColumn('request_logs', 'inacbgs_code')) { + $table->string('inacbgs_code')->nullable()->after('nomor_sep'); + } + if (!Schema::hasColumn('request_logs', 'inacbgs_amount')) { + $table->decimal('inacbgs_amount', 18, 2)->nullable()->after('inacbgs_code'); + } + if (!Schema::hasColumn('request_logs', 'no_transaksi_provider')) { + $table->string('no_transaksi_provider')->nullable()->after('inacbgs_amount'); + } + if (!Schema::hasColumn('request_logs', 'admission_date')) { + $table->dateTime('admission_date')->nullable()->after('submission_date'); + } + if (!Schema::hasColumn('request_logs', 'nomor_rujukan')) { + $table->string('nomor_rujukan')->nullable()->after('nomor_sep'); + } + if (!Schema::hasColumn('request_logs', 'status_rujukan')) { + $table->string('status_rujukan')->nullable()->after('nomor_rujukan'); + } + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('request_logs'); + } +}; diff --git a/database/migrations/2026_05_13_150200_create_request_log_benefits_table.php b/database/migrations/2026_05_13_150200_create_request_log_benefits_table.php new file mode 100644 index 00000000..84487ab8 --- /dev/null +++ b/database/migrations/2026_05_13_150200_create_request_log_benefits_table.php @@ -0,0 +1,54 @@ +id(); + $table->foreignId('request_log_id')->index(); + $table->foreignId('benefit_id')->index(); + $table->decimal('amount_incurred', 18, 2)->nullable()->default(0); + $table->decimal('amount_approved', 18, 2)->nullable()->default(0); + $table->decimal('excess_paid', 18, 2)->nullable()->default(0); + $table->string('keterangan')->nullable(); + + $table->timestamps(); + $table->softDeletes(); + + $table->unsignedBigInteger('created_by')->nullable()->index(); + $table->unsignedBigInteger('updated_by')->nullable()->index(); + $table->unsignedBigInteger('deleted_by')->nullable()->index(); + + $table->unique(['request_log_id', 'benefit_id']); + }); + return; + } + + Schema::table('request_log_benefits', function (Blueprint $table) { + if (!Schema::hasColumn('request_log_benefits', 'keterangan')) { + $table->string('keterangan')->nullable()->after('excess_paid'); + } + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('request_log_benefits'); + } +}; -- 2.49.1 From a08cdd56c80d6e1b2fa18a0f3d3ab77dbb6acce8 Mon Sep 17 00:00:00 2001 From: JamilatulMuyasaroh Date: Wed, 13 May 2026 16:35:01 +0700 Subject: [PATCH 2/2] feat(hospitalportal): implement ProviderOnline bridging endpoints --- .../Api/ProviderOnlineController.php | 565 ++++++++++++++++++ Modules/HospitalPortal/Routes/api.php | 11 + 2 files changed, 576 insertions(+) create mode 100644 Modules/HospitalPortal/Http/Controllers/Api/ProviderOnlineController.php diff --git a/Modules/HospitalPortal/Http/Controllers/Api/ProviderOnlineController.php b/Modules/HospitalPortal/Http/Controllers/Api/ProviderOnlineController.php new file mode 100644 index 00000000..2c96a4ae --- /dev/null +++ b/Modules/HospitalPortal/Http/Controllers/Api/ProviderOnlineController.php @@ -0,0 +1,565 @@ +validate([ + 'username' => 'required|string', + 'password' => 'required|string', + 'kodeprovider' => 'required|string', + ]); + + $organization = Organization::query()->where('code', $request->kodeprovider)->first(); + if (!$organization) { + return $this->headerError('Kode provider tidak ditemukan'); + } + + $provider = Provider::query()->firstOrNew([ + 'organization_id' => $organization->id, + 'username' => $request->username, + ]); + + if ($provider->exists) { + $isPasswordValid = Hash::check($request->password, $provider->password) || $provider->password === $request->password; + if (!$isPasswordValid) { + return $this->headerError('Username atau password tidak valid'); + } + } else { + $provider->password = Hash::make($request->password); + } + + $provider->code = $request->kodeprovider; + $provider->status = 'active'; + $provider->header_token = Str::random(64); + $provider->token = Str::random(64); + $provider->save(); + + return response()->json([ + 'header-token' => $provider->header_token, + 'userid' => $provider->id, + 'usertoken' => $provider->token, + 'kodeprovider' => $organization->code, + 'namaprovider' => $organization->name, + 'errornumber' => 0, + 'messagestring' => 'Success', + ]); + } + + public function checkEligibilitasPeserta(Request $request) + { + $request->validate([ + 'nokartu' => 'required|string', + 'kodeprovider' => 'required|string', + 'p_user_no' => 'required', + 'p_token' => 'required|string', + ]); + + [$provider, $organization, $authError] = $this->resolveProvider($request->kodeprovider, $request->p_user_no, $request->p_token); + if ($authError) { + return $authError; + } + + $member = Member::query() + ->with(['person', 'currentCorporate', 'currentPolicy', 'memberPlans.plan']) + ->where('member_id', $request->nokartu) + ->first(); + + if (!$member) { + return $this->statusError('Peserta tidak ditemukan'); + } + + $benefits = $member->memberPlans + ->map(function (MemberPlan $memberPlan) { + $plan = $memberPlan->plan; + if (!$plan) { + return null; + } + + return [ + 'kodebenefit' => $plan->code, + 'namabenefit' => $plan->corporate_plan_id, + 'planid' => $plan->code, + ]; + }) + ->filter() + ->values(); + + return response()->json([ + 'Status' => $this->okStatus(), + 'Data' => [ + 'nokartu' => $member->member_id, + 'memberid' => (string) $member->id, + 'namapeserta' => $member->full_name, + 'nomorbpjs' => $member->bpjs_id, + 'jeniskelamin' => $member->gender_code, + 'tanggallahir' => $this->isoDate($member->birth_date), + 'hubungankeluarga' => $member->relation_with_principal, + 'namaperusahaan' => optional($member->currentCorporate)->name, + 'pesertavip' => 'N', + 'namapenjamin' => optional($organization)->name, + 'nomorpolis' => optional($member->currentPolicy)->code, + 'tglmulaipolis' => $this->isoDate(optional($member->currentPolicy)->start), + 'tglberakhirpolis' => $this->isoDate(optional($member->currentPolicy)->end), + 'phone' => optional($member->person)->phone, + 'email' => $member->email, + ], + 'Benefit' => $benefits, + ]); + } + + public function createPendaftaran(Request $request) + { + $request->validate([ + 'kodeprovider' => 'required|string', + 'kodebenefit' => 'required|string', + 'statusrujukan' => 'nullable|string', + 'nomorrujukan' => 'nullable|string', + 'keterangan' => 'nullable|string', + 'nomorsep' => 'nullable|string', + 'nokartu' => 'required|string', + 'kelaskamar' => 'nullable|string', + 'cobbpjs' => 'nullable|numeric', + 'notransaksiprovider' => 'nullable|string', + 'inacbgscode' => 'nullable|string', + 'inacbgsamount' => 'nullable|numeric', + 'p_user_no' => 'required', + 'p_token' => 'required|string', + ]); + + [$provider, $organization, $authError] = $this->resolveProvider($request->kodeprovider, $request->p_user_no, $request->p_token); + if ($authError) { + return $authError; + } + + $member = Member::query() + ->with(['person', 'currentCorporate', 'currentPolicy']) + ->where('member_id', $request->nokartu) + ->first(); + if (!$member) { + return $this->statusError('Peserta tidak ditemukan'); + } + + $plan = $this->resolvePlan($member, $request->kodebenefit); + + $requestLog = RequestLog::query()->create([ + 'organization_id' => $organization->id, + 'member_id' => $member->id, + 'plan_id' => optional($plan)->id, + 'policy_id' => optional($member->currentPolicy)->id ?? 0, + 'payment_type' => 'cashless', + 'service_code' => $request->kodebenefit, + 'type_of_member' => 'member', + 'status' => 'approved', + 'source' => 'api', + 'keterangan' => $request->keterangan, + 'hak_kamar_pasien' => $request->kelaskamar ?? '', + 'penempatan_kamar' => $request->kelaskamar, + 'total_cob' => $request->cobbpjs, + 'nominal' => 0, + 'import_system' => 0, + 'nomor_sep' => $request->nomorsep, + 'inacbgs_code' => $request->inacbgscode, + 'inacbgs_amount' => $request->inacbgsamount, + 'no_transaksi_provider' => $request->notransaksiprovider, + 'diagnosis' => '', + 'reason' => '', + 'reason_final' => '', + 'catatan' => '', + 'nomor_rujukan' => $request->nomorrujukan, + 'status_rujukan' => $request->statusrujukan, + 'submission_date' => now(), + 'admission_date' => now(), + ]); + + $limitSubBenefit = collect(); + if ($plan) { + $limitSubBenefit = CorporateBenefit::query() + ->with('benefit') + ->where('plan_id', $plan->id) + ->get() + ->map(function (CorporateBenefit $corporateBenefit) { + return [ + 'kodesubbenefit' => optional($corporateBenefit->benefit)->code, + 'namasubbenefit' => optional($corporateBenefit->benefit)->description, + 'batasan' => (string) ($corporateBenefit->limit_amount ?? 0), + ]; + }); + } + + return response()->json([ + 'Status' => $this->okStatus(), + 'Data' => [[ + 'noklaim' => $requestLog->code, + 'namapeserta' => $member->full_name, + 'tanggallahir' => $this->isoDate($member->birth_date), + 'nokartu' => $member->member_id, + 'nopolis' => optional($member->currentPolicy)->code, + 'nobpjs' => $member->bpjs_id, + 'nosep' => $requestLog->nomor_sep, + 'nomorrujukan' => $requestLog->nomor_rujukan, + 'planid' => optional($plan)->code, + 'masapolis' => optional($member->currentPolicy)->end ? Carbon::parse($member->currentPolicy->end)->format('d/m/Y') : null, + 'namaperusahaan' => optional($member->currentCorporate)->name, + 'namapenjamin' => $organization->name, + 'tanggalmasuk' => $this->isoDate($requestLog->admission_date), + 'tanggalkeluar' => $this->isoDate($requestLog->discharge_date), + 'hakkamar' => $requestLog->penempatan_kamar, + 'hakicu' => null, + 'nosuratjaminan' => $requestLog->code, + 'namapegawai' => null, + 'namabenefit' => optional($plan)->corporate_plan_id, + 'kodediagnosa' => $requestLog->diagnosis, + 'keterangan' => $requestLog->keterangan, + 'catatanTC1' => null, + 'catatanTC2' => null, + 'catatanTC3' => null, + 'catatanTC4' => null, + 'catatanTC5' => null, + 'catatanTC6' => null, + 'catatanTC7' => null, + 'catatanTC8' => null, + 'catatanTC9' => null, + 'catatanTC10' => null, + 'statusrujukan' => $requestLog->status_rujukan, + 'statusklaim' => 0, + 'notransaksiprovider' => $requestLog->no_transaksi_provider, + 'inacbgscode' => $requestLog->inacbgs_code, + 'inacbgsamount' => (float) ($requestLog->inacbgs_amount ?? 0), + ]], + 'LimitSubBenefit' => $limitSubBenefit->values(), + ]); + } + + public function createPengesahan(Request $request) + { + $request->validate([ + 'noklaim' => 'required|string', + 'kodeprovider' => 'required|string', + 'tanggalkeluar' => 'nullable|date', + 'kodediagnosa' => 'nullable|string', + 'inacbgscode' => 'nullable|string', + 'inacbgsamount' => 'nullable|numeric', + 'daftarbiaya' => 'nullable|array', + 'daftarbiaya.*.kodesubbenefit' => 'required_with:daftarbiaya|string', + 'daftarbiaya.*.biayaaju' => 'required_with:daftarbiaya|numeric', + 'p_user_no' => 'required', + 'p_token' => 'required|string', + ]); + + [$provider, $organization, $authError] = $this->resolveProvider($request->kodeprovider, $request->p_user_no, $request->p_token); + if ($authError) { + return $authError; + } + + $requestLog = RequestLog::query() + ->with(['member.person', 'member.currentCorporate', 'member.currentPolicy', 'plan']) + ->where('code', $request->noklaim) + ->where('organization_id', $organization->id) + ->first(); + if (!$requestLog) { + return $this->statusError('Nomor klaim tidak ditemukan'); + } + + $requestLog->update([ + 'status_final_log' => 'approve', + 'final_log' => true, + 'discharge_date' => $request->tanggalkeluar, + 'diagnosis' => $request->kodediagnosa, + 'inacbgs_code' => $request->inacbgscode ?? $requestLog->inacbgs_code, + 'inacbgs_amount' => $request->inacbgsamount ?? $requestLog->inacbgs_amount, + ]); + + foreach (($request->daftarbiaya ?? []) as $biaya) { + $benefit = Benefit::query()->where('code', $biaya['kodesubbenefit'])->first(); + if (!$benefit) { + continue; + } + + RequestLogBenefit::query()->updateOrCreate( + [ + 'request_log_id' => $requestLog->id, + 'benefit_id' => $benefit->id, + ], + [ + 'amount_incurred' => $biaya['biayaaju'], + 'amount_approved' => 0, + 'amount_not_approved' => 0, + 'excess_paid' => 0, + 'keterangan' => null, + ] + ); + } + + $requestLog->load(['requestLogBenefits.benefit']); + + $biayaResponse = $requestLog->requestLogBenefits->map(function (RequestLogBenefit $requestLogBenefit) use ($requestLog) { + return [ + 'noklaim' => $requestLog->code, + 'kodesubbenefit' => optional($requestLogBenefit->benefit)->code, + 'namasubbenefit' => optional($requestLogBenefit->benefit)->description, + 'kodebenefit' => optional($requestLog->plan)->code, + 'namabenefit' => optional($requestLog->plan)->corporate_plan_id, + 'biayaaju' => (float) ($requestLogBenefit->amount_incurred ?? 0), + 'jaminanasuransi' => (float) ($requestLogBenefit->amount_approved ?? 0), + 'jaminanpeserta' => (float) ($requestLogBenefit->excess_paid ?? 0), + 'keterangan' => $requestLogBenefit->keterangan, + ]; + })->values(); + + return response()->json([ + 'Status' => $this->okStatus(), + 'Data' => [[ + 'noklaim' => $requestLog->code, + 'namapeserta' => optional($requestLog->member)->full_name, + 'tanggallahir' => $this->isoDate(optional($requestLog->member)->birth_date), + 'nokartu' => optional($requestLog->member)->member_id, + 'nopolis' => optional(optional($requestLog->member)->currentPolicy)->code, + 'nobpjs' => optional($requestLog->member)->bpjs_id, + 'nosep' => $requestLog->nomor_sep, + 'nomorrujukan' => $requestLog->nomor_rujukan, + 'planid' => optional($requestLog->plan)->code, + 'masapolis' => optional(optional($requestLog->member)->currentPolicy)->end ? Carbon::parse($requestLog->member->currentPolicy->end)->format('d/m/Y') : null, + 'namaperusahaan' => optional(optional($requestLog->member)->currentCorporate)->name, + 'namapenjamin' => $organization->name, + 'tanggalmasuk' => $this->isoDate($requestLog->admission_date), + 'tanggalkeluar' => $this->isoDate($requestLog->discharge_date), + 'hakkamar' => $requestLog->penempatan_kamar, + 'hakicu' => null, + 'nosuratjaminan' => $requestLog->code, + 'namapegawai' => null, + 'namabenefit' => optional($requestLog->plan)->corporate_plan_id, + 'kodediagnosa' => $requestLog->diagnosis, + 'keterangan' => $requestLog->keterangan, + 'catatanTC1' => null, + 'catatanTC2' => null, + 'catatanTC3' => null, + 'catatanTC4' => null, + 'catatanTC5' => null, + 'catatanTC6' => null, + 'catatanTC7' => null, + 'catatanTC8' => null, + 'catatanTC9' => null, + 'catatanTC10' => null, + 'statusrujukan' => $requestLog->status_rujukan, + 'statusklaim' => 0, + 'notransaksiprovider' => $requestLog->no_transaksi_provider, + 'inacbgscode' => $requestLog->inacbgs_code, + 'inacbgsamount' => (float) ($requestLog->inacbgs_amount ?? 0), + ]], + 'Biaya' => $biayaResponse, + ]); + } + + public function getRincianBiayaKlaim(Request $request) + { + $request->validate([ + 'noklaim' => 'required|string', + 'kodeprovider' => 'required|string', + 'p_user_no' => 'required', + 'p_token' => 'required|string', + ]); + + [$provider, $organization, $authError] = $this->resolveProvider($request->kodeprovider, $request->p_user_no, $request->p_token); + if ($authError) { + return $authError; + } + + $requestLog = RequestLog::query() + ->with(['plan', 'requestLogBenefits.benefit']) + ->where('code', $request->noklaim) + ->where('organization_id', $organization->id) + ->first(); + if (!$requestLog) { + return $this->statusError('Nomor klaim tidak ditemukan'); + } + + $biaya = $requestLog->requestLogBenefits->map(function (RequestLogBenefit $requestLogBenefit) use ($requestLog) { + return [ + 'noklaim' => $requestLog->code, + 'kodesubbenefit' => optional($requestLogBenefit->benefit)->code, + 'namasubbenefit' => optional($requestLogBenefit->benefit)->description, + 'kodebenefit' => optional($requestLog->plan)->code, + 'namabenefit' => optional($requestLog->plan)->corporate_plan_id, + 'biayaaju' => (float) ($requestLogBenefit->amount_incurred ?? 0), + 'jaminanasuransi' => (float) ($requestLogBenefit->amount_approved ?? 0), + 'jaminanpeserta' => (float) ($requestLogBenefit->excess_paid ?? 0), + 'keterangan' => $requestLogBenefit->keterangan, + ]; + })->values(); + + return response()->json([ + 'Status' => $this->okStatus(), + 'Data' => [ + 'noklaim' => $requestLog->code, + 'kodeprovider' => $organization->code, + 'nosep' => $requestLog->nomor_sep, + 'keterangan' => $requestLog->keterangan, + 'statusklaim' => $requestLog->status, + ], + 'Biaya' => $biaya, + ]); + } + + public function downloadStrukPendaftaran(Request $request) + { + $request->validate([ + 'noklaim' => 'required|string', + 'kodeprovider' => 'required|string', + 'p_user_no' => 'required', + 'p_token' => 'required|string', + ]); + + [$provider, $organization, $authError] = $this->resolveProvider($request->kodeprovider, $request->p_user_no, $request->p_token); + if ($authError) { + return $authError; + } + + $requestLog = RequestLog::query()->where('code', $request->noklaim)->where('organization_id', $organization->id)->first(); + if (!$requestLog) { + return $this->statusError('Nomor klaim tidak ditemukan'); + } + + $member = Member::findOrFail($requestLog->member_id) + ->load(['currentPlan', 'currentPolicy', 'currentPlan.corporateBenefits', 'currentPlan.corporateBenefits.benefit']); + $dateOfAdmission = $requestLog->admission_date ? Carbon::parse($requestLog->admission_date) : now(); + + try { + $pdf = PDF::loadView('pdf.guaranted_leter', compact('member', 'dateOfAdmission')); + return $pdf->download('Struk-Pendaftaran-' . $requestLog->code . '.pdf'); + } catch (Throwable $e) { + return $this->statusError('Gagal generate PDF struk pendaftaran: ' . $e->getMessage(), 500); + } + } + + public function downloadStrukPengesahan(Request $request) + { + $request->validate([ + 'noklaim' => 'required|string', + 'kodeprovider' => 'required|string', + 'p_user_no' => 'required', + 'p_token' => 'required|string', + ]); + + [$provider, $organization, $authError] = $this->resolveProvider($request->kodeprovider, $request->p_user_no, $request->p_token); + if ($authError) { + return $authError; + } + + $requestLog = RequestLog::query()->where('code', $request->noklaim)->where('organization_id', $organization->id)->first(); + if (!$requestLog) { + return $this->statusError('Nomor klaim tidak ditemukan'); + } + + $member = Member::findOrFail($requestLog->member_id) + ->load(['currentPlan', 'currentPolicy', 'currentPlan.corporateBenefits', 'currentPlan.corporateBenefits.benefit']); + $dateOfAdmission = $requestLog->discharge_date ? Carbon::parse($requestLog->discharge_date) : now(); + + try { + $pdf = PDF::loadView('pdf.guaranted_leter', compact('member', 'dateOfAdmission')); + return $pdf->download('Struk-Pengesahan-' . $requestLog->code . '.pdf'); + } catch (Throwable $e) { + return $this->statusError('Gagal generate PDF struk pengesahan: ' . $e->getMessage(), 500); + } + } + + private function resolveProvider(string $kodeProvider, $userId, string $token): array + { + $organization = Organization::query()->where('code', $kodeProvider)->first(); + if (!$organization) { + return [null, null, $this->statusError('Kode provider tidak ditemukan')]; + } + + $provider = Provider::query() + ->where('id', $userId) + ->where('organization_id', $organization->id) + ->where('code', $kodeProvider) + ->where('status', 'active') + ->first(); + if (!$provider) { + return [null, null, $this->statusError('User provider tidak ditemukan')]; + } + + if ((string) $provider->token !== (string) $token) { + return [null, null, $this->statusError('Token tidak valid')]; + } + + return [$provider, $organization, null]; + } + + private function resolvePlan(Member $member, string $serviceCode) + { + $memberPlan = $member->memberPlans()->with('plan') + ->where('status', 'active') + ->orderByDesc('id') + ->get() + ->first(function (MemberPlan $item) use ($serviceCode) { + return optional($item->plan)->service_code === $serviceCode; + }); + + if ($memberPlan && $memberPlan->plan) { + return $memberPlan->plan; + } + + return optional($member->memberPlans()->with('plan')->orderByDesc('id')->first())->plan; + } + + private function okStatus(): array + { + return [ + 'errornumber' => 0, + 'messagestring' => 'Success', + ]; + } + + private function statusError(string $message, int $statusCode = 400) + { + return response()->json([ + 'Status' => [ + 'errornumber' => 1, + 'messagestring' => $message, + ], + 'Data' => null, + ], $statusCode); + } + + private function headerError(string $message, int $statusCode = 400) + { + return response()->json([ + 'header-token' => null, + 'userid' => 0, + 'usertoken' => null, + 'kodeprovider' => null, + 'namaprovider' => null, + 'errornumber' => 1, + 'messagestring' => $message, + ], $statusCode); + } + + private function isoDate($date): ?string + { + if (empty($date)) { + return null; + } + + return Carbon::parse($date)->toISOString(); + } +} diff --git a/Modules/HospitalPortal/Routes/api.php b/Modules/HospitalPortal/Routes/api.php index b3599848..e5655442 100644 --- a/Modules/HospitalPortal/Routes/api.php +++ b/Modules/HospitalPortal/Routes/api.php @@ -4,6 +4,7 @@ use Illuminate\Http\Request; use Modules\HospitalPortal\Http\Controllers\Api\AuthController; use Modules\HospitalPortal\Http\Controllers\Api\ClaimRequestController; use Modules\HospitalPortal\Http\Controllers\Api\MemberController; +use Modules\HospitalPortal\Http\Controllers\Api\ProviderOnlineController; use Modules\HospitalPortal\Http\Controllers\ClaimController; /* @@ -42,3 +43,13 @@ Route::prefix('hospitalportal')->group(function () { Route::get('claim-requests/{id}', [ClaimRequestController::class, 'show'])->name('claim-requests.show'); }); }); + +Route::prefix('v1/bridging-service/ProviderOnline')->group(function () { + Route::post('HeaderKey', [ProviderOnlineController::class, 'getHeaderKey']); + Route::post('EligibilitasPeserta', [ProviderOnlineController::class, 'checkEligibilitasPeserta']); + Route::post('Pendaftaran', [ProviderOnlineController::class, 'createPendaftaran']); + Route::post('Pengesahan', [ProviderOnlineController::class, 'createPengesahan']); + Route::post('RincianBiayaKlaim', [ProviderOnlineController::class, 'getRincianBiayaKlaim']); + Route::post('StrukPendaftaran', [ProviderOnlineController::class, 'downloadStrukPendaftaran']); + Route::post('StrukPengesahan', [ProviderOnlineController::class, 'downloadStrukPengesahan']); +}); -- 2.49.1