all(), [ 'kodeprovider' => 'required|string|exists:organizations,code', 'username' => 'required|string', 'password' => 'required|string', 'status' => 'nullable|in:active,inactive', 'header_token' => 'nullable|string', 'namaprovider' => 'nullable|string', ]); if ($validator->fails()) { return response()->json([ 'Status' => [ 'errornumber' => 1, 'messagestring' => $validator->errors()->first(), ], 'Data' => (object) [], ], 400); } $organization = Organization::query()->where('code', $request->kodeprovider)->first(); if (!$organization) { return response()->json([ 'Status' => [ 'errornumber' => 1, 'messagestring' => 'Organization dengan kodeprovider tidak ditemukan', ], 'Data' => (object) [], ], 404); } $provider = Provider::query()->updateOrCreate( ['organization_id' => $organization->id, 'code' => $request->kodeprovider], [ 'name' => $request->namaprovider ?: $organization->name, 'username' => $request->username, 'password' => $request->password, 'status' => $request->status ?? 'active', 'header_token' => $request->header_token ?: ('bearer_' . Str::lower(Str::random(24))), ] ); return response()->json([ 'Status' => [ 'errornumber' => 0, 'messagestring' => 'HeaderKey berhasil disimpan', ], 'Data' => [ 'provider_id' => (int) $provider->id, 'organization_id' => (int) $provider->organization_id, 'kodeprovider' => (string) $provider->code, 'namaprovider' => (string) ($provider->name ?? ''), 'username' => (string) $provider->username, 'status' => (string) $provider->status, 'header_token' => (string) ($provider->header_token ?? ''), ], ]); } public function getHeaderKey(Request $request): JsonResponse { $validator = Validator::make($request->all(), [ 'username' => 'required|string', 'password' => 'required|string', 'kodeprovider' => 'required|string|exists:organizations,code', ]); if ($validator->fails()) { return response()->json([ 'header-token' => '', 'userid' => 0, 'usertoken' => '', 'kodeprovider' => $request->input('kodeprovider', ''), 'namaprovider' => '', 'errornumber' => 1, 'messagestring' => $validator->errors()->first(), ], 400); } $provider = Provider::query() ->with('organization') ->where('code', $request->kodeprovider) ->where('username', $request->username) ->where('status', 'active') ->first(); if (!$provider || !hash_equals((string) $provider->password, (string) $request->password)) { return response()->json([ 'header-token' => '', 'userid' => 0, 'usertoken' => '', 'kodeprovider' => $request->kodeprovider, 'namaprovider' => '', 'errornumber' => 1, 'messagestring' => 'Username, password, atau kodeprovider tidak valid', ], 401); } if (empty($provider->header_token)) { $provider->header_token = 'bearer_' . Str::lower(Str::random(24)); } $provider->token = Str::lower(Str::random(40)); $provider->save(); return response()->json([ 'header-token' => $provider->header_token, 'userid' => (int) $provider->id, 'usertoken' => $provider->token, 'kodeprovider' => $provider->code, 'namaprovider' => optional($provider->organization)->name ?? $provider->name, 'errornumber' => 0, 'messagestring' => 'Success', ]); } public function checkEligibilitasPeserta(Request $request): JsonResponse { $validated = $this->validateProviderRequest($request, [ 'nokartu' => 'required|string', ]); if ($validated instanceof JsonResponse) { return $validated; } [$provider, $organization] = $validated; $member = Member::query()->where('member_id', $request->nokartu)->first(); if (!$member) { return $this->statusResponse(1, 'Data peserta tidak ditemukan', [ 'Data' => (object) [], 'Benefit' => [], ], 404); } return response()->json([ 'Status' => [ 'errornumber' => 0, 'messagestring' => 'Success', ], 'Data' => [ 'nokartu' => (string) $member->member_id, 'memberid' => (string) $member->id, 'namapeserta' => (string) $member->name, 'nomorbpjs' => (string) ($member->bpjs_no ?? ''), 'jeniskelamin' => (string) ($member->gender ?? ''), 'tanggallahir' => $this->toIsoDateTime($member->birth_date ?? null), 'hubungankeluarga' => (string) ($member->relationship ?? ''), 'namaperusahaan' => (string) optional($member->currentCorporate)->name, 'pesertavip' => (string) ($member->vip_status ?? ''), 'namapenjamin' => 'LinkSehat', 'nomorpolis' => (string) optional($member->currentPolicy)->code, 'tglmulaipolis' => $this->toIsoDateTime($member->members_effective_date ?? null), 'tglberakhirpolis' => $this->toIsoDateTime($member->members_expire_date ?? null), 'phone' => (string) ($member->telephone_mobile ?? ''), 'email' => (string) ($member->email ?? ''), ], 'Benefit' => $this->buildEligibilitasBenefit($member->id), ]); } public function createPendaftaran(Request $request): JsonResponse { $validated = $this->validateProviderRequest($request, [ 'kodebenefit' => 'required|string', 'nokartu' => 'required|string', 'keterangan' => 'nullable|string', 'kelaskamar' => 'nullable|string', 'nomorsep' => 'nullable|string', 'notransaksiprovider' => 'nullable|string', 'inacbgscode' => 'nullable|string', 'inacbgsamount' => 'nullable|numeric', 'cobbpjs' => 'nullable|numeric', ]); if ($validated instanceof JsonResponse) { return $validated; } [, $organization] = $validated; $member = Member::query()->where('member_id', $request->nokartu)->first(); if (!$member) { return $this->statusResponse(1, 'Data peserta tidak ditemukan', [ 'Data' => [], 'LimitSubBenefit' => [], ], 404); } $serviceCode = strtoupper((string) $request->kodebenefit); if (!in_array($serviceCode, ['OP', 'IP'], true)) { $serviceCode = $request->kodebenefit; } DB::beginTransaction(); try { $requestLog = RequestLog::query()->create([ 'submission_date' => now(), 'member_id' => $member->id, 'payment_type' => 'cashless', 'service_code' => $serviceCode, 'policy_id' => 0, 'status' => 'approved', 'source' => 'api', 'organization_id' => $organization->id, 'keterangan' => $request->keterangan, 'penempatan_kamar' => $request->kelaskamar, 'total_cob' => (int) ($request->cobbpjs ?? 0), 'nomor_sep' => $request->nomorsep, 'inacbgs_code' => $request->inacbgscode, 'inacbgs_amount' => (int) ($request->inacbgsamount ?? 0), 'invoice_no' => $request->notransaksiprovider, ]); $requestLog->code = $this->generateNoLogCode($requestLog); $requestLog->save(); DB::commit(); } catch (\Throwable $e) { DB::rollBack(); return $this->statusResponse(1, $e->getMessage(), [ 'Data' => [], 'LimitSubBenefit' => [], ], 500); } $limitSubBenefit = $this->buildLimitSubBenefit($member->id, $serviceCode); return response()->json([ 'Status' => [ 'errornumber' => 0, 'messagestring' => 'Success', ], 'Data' => [[ 'noklaim' => (string) $requestLog->code, 'namapeserta' => (string) $member->name, 'tanggallahir' => $this->toIsoDateTime($member->birth_date ?? null), 'nokartu' => (string) $member->member_id, 'nopolis' => (string) optional($member->currentPolicy)->code, 'nobpjs' => (string) ($member->bpjs_no ?? ''), 'nosep' => (string) ($requestLog->nomor_sep ?? ''), 'nomorrujukan' => (string) ($request->nomorrujukan ?? ''), 'planid' => '', 'masapolis' => '', 'namaperusahaan' => (string) optional($member->currentCorporate)->name, 'namapenjamin' => 'LinkSehat', 'tanggalmasuk' => $this->toIsoDateTime($requestLog->submission_date ?? null), 'tanggalkeluar' => $this->toIsoDateTime($requestLog->discharge_date ?? null), 'hakkamar' => (string) ($requestLog->hak_kamar_pasien ?? ''), 'hakicu' => '', 'nosuratjaminan' => '', 'namapegawai' => (string) $member->name, 'namabenefit' => (string) $request->kodebenefit, 'kodediagnosa' => (string) ($requestLog->diagnosis ?? ''), 'keterangan' => (string) ($requestLog->keterangan ?? ''), 'catatanTC1' => '', 'catatanTC2' => '', 'catatanTC3' => '', 'catatanTC4' => '', 'catatanTC5' => '', 'catatanTC6' => '', 'catatanTC7' => '', 'catatanTC8' => '', 'catatanTC9' => '', 'catatanTC10' => '', 'statusrujukan' => (string) ($request->statusrujukan ?? ''), 'statusklaim' => 0, 'notransaksiprovider' => (string) ($requestLog->invoice_no ?? ''), 'inacbgscode' => (string) ($requestLog->inacbgs_code ?? ''), 'inacbgsamount' => (int) ($requestLog->inacbgs_amount ?? 0), ]], 'LimitSubBenefit' => $limitSubBenefit, ]); } public function createPengesahan(Request $request): JsonResponse { $validated = $this->validateProviderRequest($request, [ 'noklaim' => 'required|string', 'tanggalkeluar' => 'required|date', 'kodediagnosa' => 'nullable|string', 'daftarbiaya' => 'nullable|array', 'daftarbiaya.*.kodesubbenefit' => 'required_with:daftarbiaya|string', 'daftarbiaya.*.biayaaju' => 'required_with:daftarbiaya|numeric', 'inacbgscode' => 'nullable|string', 'inacbgsamount' => 'nullable|numeric', ]); if ($validated instanceof JsonResponse) { return $validated; } [, $organization] = $validated; $requestLog = RequestLog::query() ->where('code', $request->noklaim) ->where('organization_id', $organization->id) ->first(); if (!$requestLog) { return $this->statusResponse(1, 'Data klaim tidak ditemukan', [ 'Data' => [], 'Biaya' => [], ], 404); } DB::beginTransaction(); try { $requestLog->update([ 'status_final_log' => 'approve', 'final_log' => 1, 'discharge_date' => $request->tanggalkeluar, 'diagnosis' => $request->kodediagnosa, 'inacbgs_code' => $request->inacbgscode, 'inacbgs_amount' => (int) ($request->inacbgsamount ?? $requestLog->inacbgs_amount ?? 0), ]); 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' => (int) $biaya['biayaaju'], 'amount_approved' => 0, 'amount_not_approved' => 0, 'excess_paid' => 0, 'keterangan' => '', ] ); } DB::commit(); } catch (\Throwable $e) { DB::rollBack(); return $this->statusResponse(1, $e->getMessage(), [ 'Data' => [], 'Biaya' => [], ], 500); } return $this->buildRincianBiayaResponse($requestLog, 'Success'); } public function getRincianBiayaKlaim(Request $request): JsonResponse { $validated = $this->validateProviderRequest($request, [ 'noklaim' => 'required|string', ]); if ($validated instanceof JsonResponse) { return $validated; } [, $organization] = $validated; $requestLog = RequestLog::query() ->where('code', $request->noklaim) ->where('organization_id', $organization->id) ->first(); if (!$requestLog) { return $this->statusResponse(1, 'Data klaim tidak ditemukan', [ 'Data' => [], 'Biaya' => [], ], 404); } return $this->buildRincianBiayaResponse($requestLog, 'Success'); } public function downloadStrukPendaftaran(Request $request) { $validated = $this->validateProviderRequest($request, [ 'noklaim' => 'required|string', ]); if ($validated instanceof JsonResponse) { return $validated; } [, $organization] = $validated; $requestLog = RequestLog::query() ->where('code', $request->noklaim) ->where('organization_id', $organization->id) ->first(); if (!$requestLog) { return $this->statusResponse(1, 'Data klaim tidak ditemukan', (object) [], 404); } return app(RequestLogController::class)->downlodLog($requestLog->id); } public function downloadStrukPengesahan(Request $request) { $validated = $this->validateProviderRequest($request, [ 'noklaim' => 'required|string', ]); if ($validated instanceof JsonResponse) { return $validated; } [, $organization] = $validated; $requestLog = RequestLog::query() ->where('code', $request->noklaim) ->where('organization_id', $organization->id) ->first(); if (!$requestLog) { return $this->statusResponse(1, 'Data klaim tidak ditemukan', (object) [], 404); } return app(RequestLogController::class)->downlodFinalLog($requestLog->id); } private function validateProviderRequest(Request $request, array $rules) { $baseRules = [ 'kodeprovider' => 'required|string|exists:organizations,code', 'p_user_no' => 'required|numeric', 'p_token' => 'required|string', ]; $validator = Validator::make($request->all(), array_merge($baseRules, $rules)); if ($validator->fails()) { return $this->statusResponse(1, $validator->errors()->first(), (object) [], 400); } $provider = Provider::query() ->where('code', $request->kodeprovider) ->where('status', 'active') ->first(); if (!$provider) { return $this->statusResponse(1, 'Provider tidak ditemukan', (object) [], 404); } $headerToken = $request->header('header-token'); if (!empty($provider->header_token) && $headerToken !== $provider->header_token) { return $this->statusResponse(1, 'Header token tidak valid', (object) [], 401); } if ((int) $request->p_user_no !== (int) $provider->id || (string) $request->p_token !== (string) $provider->token) { return $this->statusResponse(1, 'Token user tidak valid', (object) [], 401); } $organization = Organization::query()->where('id', $provider->organization_id)->first(); if (!$organization) { return $this->statusResponse(1, 'Organization provider tidak ditemukan', (object) [], 404); } return [$provider, $organization]; } private function statusResponse(int $errorNumber, string $message, $extra = [], int $statusCode = 200): JsonResponse { $payload = [ 'Status' => [ 'errornumber' => $errorNumber, 'messagestring' => $message, ], ]; if (is_array($extra)) { $payload = array_merge($payload, $extra); } return response()->json($payload, $statusCode); } private function buildRincianBiayaResponse(RequestLog $requestLog, string $message): JsonResponse { $member = Member::query()->find($requestLog->member_id); $benefits = RequestLogBenefit::query() ->with('benefit') ->where('request_log_id', $requestLog->id) ->get(); $plan = $this->resolvePlanByRequestLog($requestLog); return response()->json([ 'Status' => [ 'errornumber' => 0, 'messagestring' => $message, ], 'Data' => [[ 'noklaim' => (string) $requestLog->code, 'namapeserta' => (string) optional($member)->name, 'tanggallahir' => $this->toIsoDateTime(optional($member)->birth_date ?? null), 'nokartu' => (string) optional($member)->member_id, 'nopolis' => (string) optional(optional($member)->currentPolicy)->code, 'nobpjs' => (string) (optional($member)->bpjs_no ?? ''), 'nosep' => (string) ($requestLog->nomor_sep ?? ''), 'nomorrujukan' => '', 'planid' => '', 'masapolis' => '', 'namaperusahaan' => (string) optional(optional($member)->currentCorporate)->name, 'namapenjamin' => 'LinkSehat', 'tanggalmasuk' => $this->toIsoDateTime($requestLog->submission_date ?? null), 'tanggalkeluar' => $this->toIsoDateTime($requestLog->discharge_date ?? null), 'hakkamar' => (string) ($requestLog->hak_kamar_pasien ?? ''), 'hakicu' => '', 'nosuratjaminan' => '', 'namapegawai' => (string) optional($member)->name, 'namabenefit' => '', 'kodediagnosa' => (string) ($requestLog->diagnosis ?? ''), 'keterangan' => (string) ($requestLog->keterangan ?? ''), 'catatanTC1' => '', 'catatanTC2' => '', 'catatanTC3' => '', 'catatanTC4' => '', 'catatanTC5' => '', 'catatanTC6' => '', 'catatanTC7' => '', 'catatanTC8' => '', 'catatanTC9' => '', 'catatanTC10' => '', 'statusrujukan' => '', 'statusklaim' => 0, 'notransaksiprovider' => (string) ($requestLog->invoice_no ?? ''), 'inacbgscode' => (string) ($requestLog->inacbgs_code ?? ''), 'inacbgsamount' => (int) ($requestLog->inacbgs_amount ?? 0), ]], 'Biaya' => $benefits->map(function (RequestLogBenefit $item) use ($requestLog, $plan) { $planCode = ''; $planName = ''; if (!empty($plan)) { $planCode = (string) ($plan->code ?? ''); $planName = (string) ($plan->corporate_plan_id ?? $plan->code ?? ''); } return [ 'noklaim' => (string) $requestLog->code, 'kodesubbenefit' => (string) optional($item->benefit)->code, 'namasubbenefit' => (string) optional($item->benefit)->description, 'kodebenefit' => $planCode, 'namabenefit' => $planName, 'biayaaju' => (int) $item->amount_incurred, 'jaminanasuransi' => (int) $item->amount_approved, 'jaminanpeserta' => (int) $item->excess_paid, 'keterangan' => (string) ($item->keterangan ?? ''), ]; })->values(), ]); } private function toIsoDateTime($value): ?string { if (empty($value)) { return null; } try { return Carbon::parse($value)->format('Y-m-d\\TH:i:s.v\\Z'); } catch (\Throwable $e) { return null; } } private function generateNoLogCode(RequestLog $requestLog): string { $organizationCode = (string) optional($requestLog->organization)->code; $member = Member::query()->with('currentPolicy')->find($requestLog->member_id); $memberCode = (string) optional($member)->member_id; $policyCode = (string) optional(optional($member)->currentPolicy)->code; $dateCode = now()->format('ymd'); $lastNumericCode = RequestLog::query() ->select(DB::raw('MAX(CAST(SUBSTRING_INDEX(code, ".", -1) AS SIGNED)) as max_numeric_code')) ->whereRaw('SUBSTRING_INDEX(code, ".", -1) REGEXP "^[0-9]+$"') ->value('max_numeric_code'); $nextNumber = ((int) $lastNumericCode) + 1; if ($nextNumber <= 0) { $nextNumber = 1; } return 'LOG' . '.H.' . $organizationCode . '.' . $dateCode . '.' . $policyCode . '.' . $memberCode . '.' . str_pad((string) $nextNumber, 5, '0', STR_PAD_LEFT); } private function buildEligibilitasBenefit(int $memberDbId): array { $rows = MemberPlan::query() ->join('plans', 'plans.id', '=', 'member_plans.plan_id') ->where('member_plans.member_id', $memberDbId) ->whereNull('member_plans.deleted_at') ->whereNull('plans.deleted_at') ->select([ 'plans.code as plan_code', 'plans.corporate_plan_id as plan_name', ]) ->distinct() ->get(); return $rows->map(function ($row) { $planCode = (string) ($row->plan_code ?? ''); return [ 'kodebenefit' => $planCode, 'namabenefit' => (string) ($planCode ?? $row->plan_name), // tidak ada nama plan 'planid' => $planCode, ]; })->values()->all(); } private function buildLimitSubBenefit(int $memberDbId, string $serviceCode): array { $rows = MemberPlan::query() ->join('plans', 'plans.id', '=', 'member_plans.plan_id') ->join('corporate_benefits', 'corporate_benefits.plan_id', '=', 'plans.id') ->join('benefits', 'benefits.id', '=', 'corporate_benefits.benefit_id') ->where('member_plans.member_id', $memberDbId) ->whereNull('member_plans.deleted_at') ->whereNull('plans.deleted_at') ->whereNull('corporate_benefits.deleted_at') ->whereNull('benefits.deleted_at') ->when(!empty($serviceCode), function ($query) use ($serviceCode) { $query->where('plans.service_code', $serviceCode); }) ->select([ 'benefits.code as benefit_code', 'benefits.description as benefit_name', 'corporate_benefits.limit_amount as benefit_limit', ]) ->distinct() ->get(); return $rows->map(function ($row) { return [ 'kodesubbenefit' => (string) ($row->benefit_code ?? ''), 'namasubbenefit' => (string) ($row->benefit_name ?? ''), 'batasan' => (string) ($row->benefit_limit ?? ''), ]; })->values()->all(); } private function resolvePlanByRequestLog(RequestLog $requestLog): ?Plan { $plan = Plan::query() ->join('member_plans', 'member_plans.plan_id', '=', 'plans.id') ->where('member_plans.member_id', $requestLog->member_id) ->whereNull('member_plans.deleted_at') ->whereNull('plans.deleted_at') ->where('plans.service_code', $requestLog->service_code) ->orderByDesc('member_plans.id') ->select('plans.*') ->first(); if ($plan) { return $plan; } return Plan::query() ->join('member_plans', 'member_plans.plan_id', '=', 'plans.id') ->where('member_plans.member_id', $requestLog->member_id) ->whereNull('member_plans.deleted_at') ->whereNull('plans.deleted_at') ->orderByDesc('member_plans.id') ->select('plans.*') ->first(); } }