diff --git a/Modules/Client/Http/Controllers/Api/ClaimController.php b/Modules/Client/Http/Controllers/Api/ClaimController.php index 34f8d092..c42555b0 100644 --- a/Modules/Client/Http/Controllers/Api/ClaimController.php +++ b/Modules/Client/Http/Controllers/Api/ClaimController.php @@ -316,8 +316,8 @@ class ClaimController extends Controller // ->where('request_logs.status_final_log', '=', 'approved') ->where('request_logs.deleted_at', '=', null) ->when($start != 'all' && $end != 'all', function ($query) use ($start, $end) { - $query->where('request_logs.submission_date', '>=', $start) - ->where('request_logs.submission_date', '<=', Carbon::parse($end)->addDay()); + $query->where('request_logs.submission_date', '>=',Carbon::parse($start)->subDay()) + ->where('request_logs.submission_date', '<=',Carbon::parse($end)->addDay()); }) ->select( DB::raw('1 AS no'), diff --git a/Modules/Client/Http/Controllers/Api/ClaimRequestController.php b/Modules/Client/Http/Controllers/Api/ClaimRequestController.php index bd5bcc49..4c38a420 100644 --- a/Modules/Client/Http/Controllers/Api/ClaimRequestController.php +++ b/Modules/Client/Http/Controllers/Api/ClaimRequestController.php @@ -19,7 +19,7 @@ class ClaimRequestController extends Controller * Display a listing of the resource. * @return Renderable */ - private static $code_prefix = 'CP'; + private static $code_prefix = 'CLAIM'; public function index() { return view('client::index'); @@ -224,10 +224,6 @@ class ClaimRequestController extends Controller public static function getNextCode() { - // $last_number = ClaimRequest::max('code'); - // $next_number = empty($last_number) ? 1 : ((int) explode('-', $last_number)[2] + 1); - // return self::makeCode($next_number); - $last_numeric_code = ClaimRequest::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'); @@ -247,8 +243,14 @@ class ClaimRequestController extends Controller { // Pastikan $next_number adalah integer positif $next_number = max(1, (int) $next_number); - + $requestLogData = RequestLog::where('id', $request_log_id)->first(); + $organization = Organization::where(['id' => $requestLogData->organization_id, 'type' => 'hospital'])->first('code'); + $provideCode = $organization ? $organization->code : ''; + $member = Member::with('currentCorporate')->where(['id' => $requestLogData->member_id])->first(); + $sparator = '.'; + $date = date('ymd'); // Menghasilkan kode dengan format yang diinginkan - return self::$code_prefix . '-' . str_pad($next_number, 5, '0', STR_PAD_LEFT); + return self::$code_prefix . $sparator. 'H' . $sparator. $provideCode . $sparator. $date. $sparator . $member->currentPolicy->code . $sparator. $member->member_id . $sparator. str_pad($next_number, 6, '0', STR_PAD_LEFT); + } } diff --git a/Modules/Client/Http/Controllers/Api/CorporateMemberController.php b/Modules/Client/Http/Controllers/Api/CorporateMemberController.php index b113a246..ceb75d10 100644 --- a/Modules/Client/Http/Controllers/Api/CorporateMemberController.php +++ b/Modules/Client/Http/Controllers/Api/CorporateMemberController.php @@ -229,7 +229,7 @@ class CorporateMemberController extends Controller 'service:code,name', 'files', ]) - ->find($request_log_id, ['id', 'submission_date', 'discharge_date', 'member_id', 'service_code', 'organization_id', 'diagnosis']); + ->find($request_log_id, ['id', 'submission_date', 'discharge_date', 'member_id', 'service_code', 'organization_id', 'diagnosis', 'keterangan', 'catatan']); $dataBenefit = []; if (count($data->requestLogBenefits) > 0) { diff --git a/Modules/Client/Transformers/AlarmCenter/DataServiceMonitoring.php b/Modules/Client/Transformers/AlarmCenter/DataServiceMonitoring.php index 9ae4657d..849e1f91 100644 --- a/Modules/Client/Transformers/AlarmCenter/DataServiceMonitoring.php +++ b/Modules/Client/Transformers/AlarmCenter/DataServiceMonitoring.php @@ -105,6 +105,8 @@ class DataServiceMonitoring extends JsonResource 'name' => $requestLogBenefit->benefit->description, ]; })->all() ?? null, + 'keterangan' => $this->keterangan ?? null, + 'catatan' => $this->catatan ?? null, 'benefitTotal' => $this->benefitTotal ?? null, 'hospital' => $this->organization->name ?? null, 'admissionDate' => $this->submission_date ?? null, diff --git a/Modules/HospitalPortal/Http/Controllers/Api/ClaimRequestController.php b/Modules/HospitalPortal/Http/Controllers/Api/ClaimRequestController.php index 3d27eb3a..09b93693 100644 --- a/Modules/HospitalPortal/Http/Controllers/Api/ClaimRequestController.php +++ b/Modules/HospitalPortal/Http/Controllers/Api/ClaimRequestController.php @@ -133,10 +133,21 @@ class ClaimRequestController extends Controller if ($request->hasFile('additional_files')) { foreach ($request->additional_files as $file) { - $pathFile = File::storeFile('additional-files', $newClaimRequest->id, $file); - $newClaimRequest->files()->updateOrCreate([ + $pathFile = File::storeFile('additional-files', $request->request_logs_id, $file); + // $newClaimRequest->files()->updateOrCreate([ + // 'type' => 'additional-files', + // 'name' => File::getFileName('additional-files', $newClaimRequest->id, $file), + // 'original_name' => $file->getClientOriginalName(), + // 'extension' => $file->getClientOriginalExtension(), + // 'path' => $pathFile, + // 'created_by' => auth()->user()->id, + // 'updated_by' => auth()->user()->id, + // ]); + File::updateOrCreate([ + 'fileable_type' => 'App\Models\RequestLog', + 'fileable_id' => $request->request_logs_id, 'type' => 'additional-files', - 'name' => File::getFileName('additional-files', $newClaimRequest->id, $file), + 'name' => File::getFileName('additional-files', $request->request_logs_id, $file), 'original_name' => $file->getClientOriginalName(), 'extension' => $file->getClientOriginalExtension(), 'path' => $pathFile, @@ -265,7 +276,6 @@ class ClaimRequestController extends Controller $date = date('ymd'); // Menghasilkan kode dengan format yang diinginkan return self::$code_prefix . $sparator. 'H' . $sparator. $provideCode . $sparator. $date. $sparator . $member->currentPolicy->code . $sparator. $member->member_id . $sparator. str_pad($next_number, 5, '0', STR_PAD_LEFT); - return self::$code_prefix . '.' . str_pad($next_number, 6, '0', STR_PAD_LEFT); } public function get_claim_requests(Request $request) diff --git a/Modules/HospitalPortal/Http/Controllers/Api/RequestLogController.php b/Modules/HospitalPortal/Http/Controllers/Api/RequestLogController.php index 982a6ce0..1d1a60fa 100644 --- a/Modules/HospitalPortal/Http/Controllers/Api/RequestLogController.php +++ b/Modules/HospitalPortal/Http/Controllers/Api/RequestLogController.php @@ -13,6 +13,11 @@ use App\Models\File; use Dompdf\Dompdf; use Dompdf\Options; use Illuminate\Support\Facades\View; +use App\Models\Member; +use App\Models\RequestLog; +use App\Models\Organization; +use App\Services\ClaimRequestService; +use App\Models\ClaimRequest; class RequestLogController extends Controller { @@ -20,6 +25,7 @@ class RequestLogController extends Controller * Display a listing of the resource. * @return Renderable */ + private static $code_prefix = 'CLAIM'; public function requestLog(Request $request) { $data = [ @@ -244,6 +250,7 @@ class RequestLogController extends Controller $results = DB::table('request_logs') ->leftJoin('members', 'request_logs.member_id', '=', 'members.id') + ->where('request_logs.deleted_at', null) ->when($request->input('search'), function ($query, $search) { $query->where(function ($query) use ($search) { $query->orWhere('request_logs.code', 'like', "%" . $search . "%") @@ -820,4 +827,110 @@ class RequestLogController extends Controller return response($pdf->output(), 200, $headers); } + + public function submitClaims(Request $request) + { + $data = [ + 'selectedRows' => $request->selectedRows, + ]; + $validator = Validator::make($request->all(), [ + 'selectedRows' => 'required' + ], [ + 'selectedRows.required' => trans('Validation.required',['attribute' => 'Request Logs ID']), + ]); + if ($validator->fails()) + { + return ApiResponse::apiResponse('Bad Request', $data, $validator->errors(), 400); + } + else + { + foreach ($request->selectedRows as $request_logs_id) { + $data_req_logs = DB::table('request_logs') + ->where('id', '=', $request_logs_id) + ->select('id', 'member_id', 'service_code') + ->first(); + + $check_claim_requests = DB::table('claim_requests') + ->where('claim_requests.request_log_id', '=', $request_logs_id) + ->first(); + if(!$check_claim_requests) { + try { + DB::beginTransaction(); + $code = $this->getNextCode($request_logs_id); + $member = Member::find($data_req_logs->member_id); + $requestLogData = RequestLog::where('id',$request_logs_id)->first(); + $organization = Organization::where(['id' => $requestLogData->organization_id, 'type' => 'hospital'])->first('code'); + $provideCode = $organization ? $organization->code : ''; + + $newClaimRequest = ClaimRequestService::storeClaimRequest( + row: [], + code: $code, + member: $member, + paymentType: 'cashless', + serviceCode: $data_req_logs->service_code, + requestLogID: $request_logs_id, + organization_code: $provideCode, + ); + // Log History + $newClaimRequest->histories()->create([ + 'title' => 'New Claim Requested', + 'description' => "Claim Requested for Member : {$member->member_id} - ({$member->full_name})", + 'type' => 'info', + 'system_origin' => 'hospital-portal' + ]); + + // Claim Log + DB::table('claim_logs') + ->insert([ + 'claim_request_id' => $newClaimRequest->id, + 'status' => 'requested', + 'date' => date('Y-m-d H:i:s'), + 'description' => "Claim Requested for Member : {$member->member_id} - ({$member->full_name})", + 'system_origin' => 'hospital-portal', + 'created_by' => auth()->user()->id, + 'created_at' => date('Y-m-d H:i:s'), + 'updated_at'=> date('Y-m-d H:i:s'), + ]); + DB::commit(); + } catch (\Exception $e) { + DB::rollback(); + return ApiResponse::apiResponse("Error", $data, $e->getMessage(), 500); + } + } + } + return ApiResponse::apiResponse('Success', $data, trans('Message.success'), 200); + } + } + + public static function getNextCode($request_log_id = 0) + { + $last_numeric_code = ClaimRequest::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'); + // $next_number = 1; + if ($last_numeric_code) { + // // Jika ada kode sebelumnya, pecah kode dan tambahkan 1 ke angka terakhir + // $parts = explode('-', $last_code); + // $last_number = (int) end($parts); + $next_number = $last_numeric_code + 1; + } else { + $next_number = 1; + } + return self::makeCode($next_number, $request_log_id); + } + + public static function makeCode($next_number, $request_log_id) + { + // Pastikan $next_number adalah integer positif + $next_number = max(1, (int) $next_number); + $requestLogData = RequestLog::where('id', $request_log_id)->first(); + $organization = Organization::where(['id' => $requestLogData->organization_id, 'type' => 'hospital'])->first('code'); + $provideCode = $organization ? $organization->code : ''; + $member = Member::with('currentCorporate')->where(['id' => $requestLogData->member_id])->first(); + $sparator = '.'; + $date = date('ymd'); + // Menghasilkan kode dengan format yang diinginkan + return self::$code_prefix . $sparator. 'H' . $sparator. $provideCode . $sparator. $date. $sparator . $member->currentPolicy->code . $sparator. $member->member_id . $sparator. str_pad($next_number, 5, '0', STR_PAD_LEFT); + return self::$code_prefix . '.' . str_pad($next_number, 6, '0', STR_PAD_LEFT); + } } diff --git a/Modules/HospitalPortal/Routes/api.php b/Modules/HospitalPortal/Routes/api.php index 17fdec66..3b73f731 100644 --- a/Modules/HospitalPortal/Routes/api.php +++ b/Modules/HospitalPortal/Routes/api.php @@ -56,6 +56,7 @@ Route::prefix('v1')->group(function() { Route::post('request-final-log', 'requestFinalLog'); Route::get('download-log/{request_log_id}', 'downlodLog'); Route::get('download-final-log/{request_log_id}', 'downlodFinalLog'); + Route::post('submit-claims', 'submitClaims'); }); //Notification Route::controller(NotificationController::class)->group(function() { diff --git a/Modules/Internal/Http/Controllers/Api/ClaimController.php b/Modules/Internal/Http/Controllers/Api/ClaimController.php index f120b1d4..832cddc3 100644 --- a/Modules/Internal/Http/Controllers/Api/ClaimController.php +++ b/Modules/Internal/Http/Controllers/Api/ClaimController.php @@ -21,8 +21,18 @@ use Modules\Internal\Transformers\ClaimEditResource; use Modules\Internal\Transformers\ClaimHistoryCareResource; use Box\Spout\Reader\Common\Creator\ReaderEntityFactory; use Box\Spout\Writer\Common\Creator\WriterEntityFactory; + +use Box\Spout\Writer\Common\Creator\Style\StyleBuilder; +use Box\Spout\Common\Entity\Style\CellAlignment; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\View; +use Maatwebsite\Excel\Facades\Excel; +use Illuminate\Support\Facades\Storage; +use App\Exports\FailedRowsExport; // Import class export Excel + +use Modules\Internal\Transformers\RequestLogResource; + +use App\Models\RequestLog; use PDF; @@ -34,41 +44,436 @@ class ClaimController extends Controller */ public function index(Request $request) { - // $serviceCode = 'IP'; - $claims = Claim::with([ - 'member', - 'member.currentCorporate', - 'member.currentCorporate.currentPolicy', - // 'member.currentPlan' => function($memberPlan) use ($serviceCode) { - // $memberPlan->where('plans.service_code', $serviceCode); - // }, - 'member.currentPlan' => function($memberPlan) { - $memberPlan->join('claim_requests', 'claim_requests.service_code', '=', 'plans.service_code'); - }, - 'diagnoses' => function ($diagnosis) { - $diagnosis->where('type', 'primary'); - }, - 'diagnoses.icd', - 'benefit', - 'claimRequest', - 'claimRequest.service', - ]) - ->when($request->search, function ($q, $search) { - $q->where(function ($subQuery) use ($search) { - $subQuery->whereHas('claimRequest', function ($claimRequest) use ($search) { - $claimRequest->where('code', 'LIKE', "%" . $search . "%"); - }) - ->orWhereHas('member', function ($member) use ($search) { - $member->where('name', 'LIKE', "%" . $search . "%"); - }); + $limit = $request->has('per_page') ? $request->input('per_page') : 10; + $results = DB::table('claim_requests') + ->leftJoin('request_logs', 'claim_requests.request_log_id','=', 'request_logs.id') + ->leftJoin('members', 'request_logs.member_id', '=', 'members.id') + // ->leftJoin('member_plans', 'member_plans.member_id', '=', 'members.id') + ->when($request->input('search'), function ($query, $search) { + $query->where(function ($query) use ($search) { + $query->orWhere('members.name', 'like', "%" . $search . "%"); + $query->orWhere('claim_requests.code', 'like', "%" . $search . "%"); + $query->orWhere('members.member_id', 'like', "%" . $search . "%"); }); }) - ->where('status', '!=', 'requested') // Penjagaan agar approve baru masuk ke claim management - ->latest() - ->paginate(10); + ->when($request->has('orderBy'), function ($query) use ($request) { + $orderBy = $request->orderBy; + $direction = $request->order ?? 'asc'; + + $query->orderBy($orderBy, $direction); + }) + ->when($request->input('start_date') , function ($query, $start_date) { + $query->where(function ($query) use ($start_date) { + $query->where('claim_requests.created_at', '>=', $start_date); + }); + }) + ->when($request->input('end_date') , function ($query, $end_date) { + $query->where(function ($query) use ($end_date) { + $query->where('claim_requests.created_at', '<=', $end_date); + }); + }) + ->when($request->input('provider') , function ($query, $provider) { + $query->where(function ($query) use ($provider) { + $query->where('request_logs.organization_id', '=', $provider); + }); + }) + ->where('claim_management', '=', 1) + ->select( + 'claim_requests.id', + 'request_logs.id AS id_log', + 'claim_requests.code as code', + 'members.name', + DB::raw(' + (SELECT members.member_id FROM members WHERE members.id = claim_requests.member_id LIMIT 1) AS member_id + '), + 'claim_requests.created_at', + // DB::raw(' + // (SELECT plans.code FROM plans WHERE plans.id = member_plans.plan_id LIMIT 1) AS plan_code + // '), + DB::raw(' + (SELECT plans.code + FROM plans + WHERE plans.id IN ( + SELECT member_plans.plan_id + FROM member_plans + WHERE member_plans.member_id = claim_requests.member_id + ) + AND plans.service_code = claim_requests.service_code) AS plan_code + '), + DB::raw(' + (SELECT services.description FROM services WHERE services.code = claim_requests.service_code LIMIT 1) AS service_code + '), + DB::raw(' + (SELECT corporate_policies.code FROM corporate_policies WHERE corporate_policies.id = claim_requests.policy_id LIMIT 1) AS corporate_policies + '), + DB::raw(' + (SELECT organizations.name FROM organizations WHERE organizations.id = request_logs.organization_id LIMIT 1) AS provider + '), + DB::raw(' + (Select SUM(request_log_benefits.amount_approved) as tot_bill FROM request_log_benefits + WHERE request_log_benefits.request_log_id = request_logs.id LIMIT 1) AS tot_bill + '), + 'claim_requests.status_claim_management as status', + ) + ->paginate($limit); + - return response()->json($claims); + return response()->json(Helper::paginateResources($results)); + } + + public function downloadTemplate() + { + return Helper::responseJson([ + 'file_name' => "Template - Claim - Management.xlsx", + "file_url" => url('files/Template - Claim - Management.xlsx') + ]); + } + + public function import(Request $request) + { + if ($request->hasFile('file')) { + $file = $request->file('file'); + $data = Excel::toArray([], $file); + + $processedData = $this->processCategoryNames($data); + + $importedRows = 0; + $failedRows = []; + + foreach ($processedData as $row) { + try { + $affectedRows = DB::table('claim_requests') + ->where('code','=', $row['code']) + ->where('claim_management','=', 1) + ->update([ + 'status_claim_management' => $row['qc'] == 'Y' ? 'approved' : 'declined', + 'reason_decline' => $row['reason'] ? $row['reason'] : null, + 'approval_by_claim_management' => auth()->user()->id, + 'approval_date_claim_management' => date('Y-m-d H:i:s'), + ]); + + if ($affectedRows === 0) { + $failedRows[] = $row; + } else { + $importedRows += $affectedRows; + } + } catch (\Exception $e) { + $failedRows[] = $row; + } + } + + $response = [ + 'message' => 'File uploaded and data saved to database', + 'data' => [ + 'total_success_row' => $importedRows, + 'total_failed_row' => count($failedRows), + 'failed_rows' => $failedRows, + ], + ]; + + return response()->json($response); + } + + return response()->json(['error' => 'No file uploaded.']); + } + + private function processCategoryNames($data) + { + $header = []; + $row = []; + for ($i = 1; $i < count($data[0]); $i++) { + $row[] = $data[0][$i]; + $header[] = $data[0][0]; + } + + $filed = []; + foreach ($header[0] as $value) + { + $modelColumn = strtolower(preg_replace('/\s+/', '_', trim($value))); + $modelColumn = str_replace(['*', ' '], '', $modelColumn); + if($modelColumn) + { + $filed[] = $modelColumn; + } + } + + $result = []; + foreach ($row as $subarray) { + $trimmedSubarray = []; + for ($i = 0; $i < count($filed); $i++) { + $trimmedSubarray[$filed[$i]] = $subarray[$i] ? $subarray[$i] : null; + } + + $result[] = $trimmedSubarray; + } + return $result; + } + + public function exportClaimManagement(Request $request) + { + $start_date = $request->input('start_date') ? $request->input('start_date') : 'all'; + $end_date = $request->input('end_date') ? $request->input('end_date') : 'all'; + $writer = WriterEntityFactory::createXLSXWriter(); + $writer->openToFile(public_path('files/Report-Data-Claim-Management-'.$start_date.'-'.$end_date.'.xlsx')); + $header = [ + 'No', + 'Code', + 'Name', + 'Member ID', + 'Date Submission', + 'Plan ID', + 'Service', + 'Policy Number', + 'Provider', + 'Total Billing', + ]; + $style = (new StyleBuilder()) + ->setFontBold() + // ->setFontSize(15) + // ->setFontColor(Color::BLUE) + // ->setShouldWrapText() + ->setCellAlignment(CellAlignment::LEFT) + // ->setBackgroundColor(Color::YELLOW) + ->build(); + + $headerRow = WriterEntityFactory::createRowFromArray($header, $style); + $writer->addRow($headerRow); + // ============================ + $results = DB::table('claim_requests') + ->leftJoin('request_logs', 'claim_requests.request_log_id','=', 'request_logs.id') + ->leftJoin('members', 'request_logs.member_id', '=', 'members.id') + // ->leftJoin('member_plans', 'member_plans.member_id', '=', 'members.id') + ->when($request->input('search'), function ($query, $search) { + $query->where(function ($query) use ($search) { + $query->orWhere('members.name', 'like', "%" . $search . "%"); + $query->orWhere('claim_requests.code', 'like', "%" . $search . "%"); + $query->orWhere('members.member_id', 'like', "%" . $search . "%"); + }); + }) + ->when($request->has('orderBy'), function ($query) use ($request) { + $orderBy = $request->orderBy; + $direction = $request->order ?? 'asc'; + + $query->orderBy($orderBy, $direction); + }) + ->when($request->input('start_date') , function ($query, $start_date) { + $query->where(function ($query) use ($start_date) { + $query->where('claim_requests.created_at', '>=', $start_date); + }); + }) + ->when($request->input('end_date') , function ($query, $end_date) { + $query->where(function ($query) use ($end_date) { + $query->where('claim_requests.created_at', '<=', $end_date); + }); + }) + ->when($request->input('provider') , function ($query, $provider) { + $query->where(function ($query) use ($provider) { + $query->where('request_logs.organization_id', '=', $provider); + }); + }) + ->where('claim_management', '=', 1) + ->select( + 'claim_requests.id', + 'request_logs.id AS id_log', + 'claim_requests.code as code', + 'members.name', + DB::raw(' + (SELECT members.member_id FROM members WHERE members.id = claim_requests.member_id LIMIT 1) AS member_id + '), + 'claim_requests.created_at', + DB::raw(' + (SELECT plans.code + FROM plans + WHERE plans.id IN ( + SELECT member_plans.plan_id + FROM member_plans + WHERE member_plans.member_id = claim_requests.member_id + ) + AND plans.service_code = claim_requests.service_code) AS plan_code + '), + // DB::raw(' + // (SELECT plans.code FROM plans WHERE plans.id = member_plans.plan_id LIMIT 1) AS plan_code + // '), + DB::raw(' + (SELECT services.description FROM services WHERE services.code = claim_requests.service_code LIMIT 1) AS service_code + '), + DB::raw(' + (SELECT corporate_policies.code FROM corporate_policies WHERE corporate_policies.id = claim_requests.policy_id LIMIT 1) AS corporate_policies + '), + DB::raw(' + (SELECT organizations.name FROM organizations WHERE organizations.id = request_logs.organization_id LIMIT 1) AS provider + '), + DB::raw(' + (Select SUM(request_log_benefits.amount_approved) as tot_bill FROM request_log_benefits + WHERE request_log_benefits.request_log_id = request_logs.id LIMIT 1) AS tot_bill + '), + 'claim_requests.status_claim_management as status', + ) + ->get(); + $no=0; + $gr_total = 0; + foreach($results as $item) + { + $gr_total += $item->tot_bill; + $no++; + $rowData = [ + $no, + $item->code, + $item->name, + $item->member_id, + $item->created_at, + $item->plan_code, + $item->service_code, + $item->corporate_policies, + $item->provider, + $item->tot_bill ? $item->tot_bill : 0 + ]; + $style = (new StyleBuilder()) + //->setFontBold() + // ->setFontSize(15) + // ->setFontColor(Color::BLUE) + // ->setShouldWrapText() + ->setCellAlignment(CellAlignment::LEFT) + // ->setBackgroundColor(Color::YELLOW) + ->build(); + $row = WriterEntityFactory::createRowFromArray($rowData, $style); + $writer->addRow($row); + } + $footer = [ + 'Grand Total', + '', + '', + '', + '', + '', + '', + '', + '', + $gr_total, + ]; + $style = (new StyleBuilder()) + ->setFontBold() + // ->setFontSize(15) + // ->setFontColor(Color::BLUE) + // ->setShouldWrapText() + ->setCellAlignment(CellAlignment::LEFT) + // ->setBackgroundColor(Color::YELLOW) + ->build(); + + $footerRow = WriterEntityFactory::createRowFromArray($footer, $style); + $writer->addRow($footerRow); + + $writer->close(); + + return Helper::responseJson([ + 'file_name' => 'Report-Data-Claim-Management-'. $start_date.'-'.$end_date, + "file_url" => url('files/Report-Data-Claim-Management-'. $start_date.'-'.$end_date.'.xlsx') + ]); + } + + public function exportFiled(Request $request) + { + $writer = WriterEntityFactory::createXLSXWriter(); + $writer->openToFile(public_path('files/Report-Data-Filed-Import.xlsx')); + $header = [ + 'Code*', + 'QC*', + 'Reason' + ]; + $style = (new StyleBuilder()) + ->setFontBold() + // ->setFontSize(15) + // ->setFontColor(Color::BLUE) + // ->setShouldWrapText() + ->setCellAlignment(CellAlignment::LEFT) + // ->setBackgroundColor(Color::YELLOW) + ->build(); + + $headerRow = WriterEntityFactory::createRowFromArray($header, $style); + $writer->addRow($headerRow); + // ============================ + + foreach($request->params as $item) + { + + $rowData = [ + $item['code'], + $item['qc'], + $item['reason'] + ]; + $style = (new StyleBuilder()) + //->setFontBold() + // ->setFontSize(15) + // ->setFontColor(Color::BLUE) + // ->setShouldWrapText() + ->setCellAlignment(CellAlignment::LEFT) + // ->setBackgroundColor(Color::YELLOW) + ->build(); + $row = WriterEntityFactory::createRowFromArray($rowData, $style); + $writer->addRow($row); + } + $footer = [ + '', + '', + '', + ]; + $style = (new StyleBuilder()) + ->setFontBold() + // ->setFontSize(15) + // ->setFontColor(Color::BLUE) + // ->setShouldWrapText() + ->setCellAlignment(CellAlignment::LEFT) + // ->setBackgroundColor(Color::YELLOW) + ->build(); + + $footerRow = WriterEntityFactory::createRowFromArray($footer, $style); + $writer->addRow($footerRow); + + $writer->close(); + + return Helper::responseJson([ + 'file_name' => 'Report-Data-Filed-Import', + "file_url" => url('files/Report-Data-Filed-Import.xlsx') + ]); + } + public function getProvider(Request $request) + { + $providers = DB::table('organizations') + ->where('organizations.type', '=', 'hospital') + ->where('organizations.status', '=', 'active') + ->select( + 'organizations.id', + 'organizations.name' + ) + ->orderBy('name', 'asc') + ->get(); + + return response()->json($providers); + } + + public function cekStatus($id) + { + $cek = DB::table('claim_requests') + ->where('claim_requests.id', '=', $id) + ->select('claim_requests.status_claim_management as status') + ->first(); + + $data['cek'] = $cek; + + $member = DB::table('claim_requests') + ->join('request_logs', 'claim_requests.request_log_id','=', 'request_logs.id') + ->join('members', 'request_logs.member_id', '=', 'members.id') + ->where('claim_requests.id', '=', $id) + ->select('claim_requests.code','members.name','claim_requests.created_at', DB::raw(' + (SELECT services.name FROM services WHERE services.code = request_logs.service_code LIMIT 1) AS service_type + '),) + ->first(); + + $data['member'] = $member; + + return response()->json($data); + } /** @@ -334,21 +739,18 @@ class ClaimController extends Controller return Helper::responseJson([], message: "Diagnosis berhasil di update"); } - public function decline($id) + public function decline(Request $request, $id) { - //Get claim request id - $data_claim_requests = DB::table('claim_requests') - ->leftJoin('claims', 'claim_requests.id', '=', 'claims.claim_request_id') - ->where('claims.id', $id) - ->select('claim_requests.id') - ->first(); - $id = $data_claim_requests->id; - DB::table('claims') - ->where('claim_request_id', $id) + DB::table('claim_requests') + ->where('claim_requests.id', $id) ->update( [ - 'status' => 'declined' + 'status' => 'declined', + 'status_claim_management' => 'declined', + 'reason_decline' => $request->reasonDecline ? $request->reasonDecline : '', + 'approval_date_claim_management' => date('Y-m-d H:i:s'), + 'approval_by_claim_management' => auth()->user()->id ] ); @@ -370,19 +772,14 @@ class ClaimController extends Controller public function approve($id) { - //Get claim request id - $data_claim_requests = DB::table('claim_requests') - ->leftJoin('claims', 'claim_requests.id', '=', 'claims.claim_request_id') - ->where('claims.id', $id) - ->select('claim_requests.id') - ->first(); - $id = $data_claim_requests->id; - - DB::table('claims') - ->where('claim_request_id', $id) + DB::table('claim_requests') + ->where('claim_requests.id', $id) ->update( [ - 'status' => 'approved' + 'status' => 'approved', + 'status_claim_management' => 'approved', + 'approval_date_claim_management' => date('Y-m-d H:i:s'), + 'approval_by_claim_management' => auth()->user()->id ] ); diff --git a/Modules/Internal/Http/Controllers/Api/ClaimRequestController.php b/Modules/Internal/Http/Controllers/Api/ClaimRequestController.php index b74a79be..eec5be19 100644 --- a/Modules/Internal/Http/Controllers/Api/ClaimRequestController.php +++ b/Modules/Internal/Http/Controllers/Api/ClaimRequestController.php @@ -17,15 +17,23 @@ use App\Services\ClaimRequestService; use App\Exceptions\ImportRowException; use App\Events\ClaimRequested; +use Box\Spout\Reader\Common\Creator\ReaderEntityFactory; +use Box\Spout\Writer\Common\Creator\WriterEntityFactory; +use Box\Spout\Writer\Common\Creator\Style\StyleBuilder; +use Box\Spout\Common\Entity\Style\CellAlignment; use App\Models\File; use App\Models\FilesMcu; use Illuminate\Support\Facades\DB; use App\Models\Member; +use App\Models\MemberPlan; +use App\Models\Plan; +use App\Models\RequestLogBenefit; +use Carbon\Carbon; class ClaimRequestController extends Controller { - private static $code_prefix = 'CRQ-C'; + private static $code_prefix = 'CLAIM'; /** * Display a listing of the resource. @@ -41,11 +49,17 @@ class ClaimRequestController extends Controller }); }) ->when($request->start_date, function ($q, $startDate) { - $q->where('submission_date', '>', $startDate); + $q->where('submission_date', '>', Carbon::parse($startDate)->subDay()); }) - ->when($request->end_date, function ($q, $endDate) { - $q->where('submission_date', '<', $endDate); + ->when($request->end_date, function ($q, $endDate) use ($request) { + // Jika tanggal akhir diberikan dan tidak sama dengan tanggal mulai + if ($request->start_date != $request->end_date) { + $q->where('submission_date', '<', Carbon::parse($endDate)->addDay()); + } else { + $q->where('submission_date', '<', Carbon::parse($endDate)->addDay()); + } }) + ->when($request->service_code, function ($q, $serviceCode) { $q->whereIn('service_code', $serviceCode); }) @@ -62,7 +76,7 @@ class ClaimRequestController extends Controller }) ->with(['member', 'files', 'service', 'member.currentPolicy']) ->paginate(); - + return Helper::paginateResources(ClaimRequestResource::collection($claimRequests)); } @@ -429,6 +443,7 @@ class ClaimRequestController extends Controller $import = new ImportService(); $import->read($fileRead); $import->write($fileWrite, 'xsls'); + foreach ($import->sheetsIterator() as $sheetIndex => $sheet) { if ($sheetIndex == 1) { // Rename First Sheet to Writer $firstWriterSheet = $import->writer->getCurrentSheet(); @@ -445,6 +460,9 @@ class ClaimRequestController extends Controller $result_headers = array_merge($result_headers, ['Ingest Code', 'Ingest Note']); $import->addArrayToRow($result_headers); + $imported_claim_data = 0; + $failed_claim_data = []; + $doc_headers_indexes = []; foreach ($sheet->getRowIterator() as $index => $row) { if ($index == 1) { // First Row Must be Header @@ -465,25 +483,28 @@ class ClaimRequestController extends Controller } try { // Process the Row Data $claimRequestService = new ClaimRequestService(); - $claimRequestService->handleClaimRequestRow($row_data); - // Write Success Result to File // $import->read($fileRead); // $import->write($fileWrite, 'xsls'); $result_headers = array_merge($row_data, ['Ingest Code' =>200, 'Ingest Note' => 'Success']); - + // Mengambil tanggal dari objek DateTime + $dateSubmission = Helper::dateParser($result_headers['date_submission']); // Format tanggal sesuai kebutuhan + // Mengubah nilai date_submission menjadi string tanggal + $result_headers['date_submission'] = $dateSubmission; + // dd($result_headers); $import->addArrayToRow($result_headers, $sheet->getName()); - + $imported_claim_data++; } catch (ImportRowException $e) { // Write Data Validation Error to File // $import->read($fileRead); // $import->write($fileWrite, 'xsls'); - - $import->addArrayToRow(array_merge($row_data, [ + $new_claim_data = $import->addArrayToRow(array_merge($row_data, [ 'Ingest Code' => $e->getCode(), 'Ingest Note' => $e->getMessage(), ]), $sheet->getName()); + + $failed_claim_data[] = ['row_number' => $index, 'error' => $e->getMessage(),'data' => $new_claim_data]; } // catch (\Exception $e) { // // throw new \Exception($e); @@ -502,104 +523,20 @@ class ClaimRequestController extends Controller $import->reader->close(); Storage::delete('temp/' . $file_name); $import->writer->close(); - return [ - // 'total_successed_row' => $imported_plan_data, - // 'total_failed_row' => count($failed_plan_data), - // 'failed_row' => $failed_plan_data, + 'result_file' => [ 'url' => Storage::disk('public')->url('temp/result-' . $file_name), 'name' => 'result-' . $file_name, + 'total_success_row' => $imported_claim_data, + 'total_failed_row' => count($failed_claim_data), + 'failed_row' => $failed_claim_data, ] ]; } public function claimRequestDetail($claimRequestId) { - // $status = DB::table('claim_requests') - // ->leftJoin('claims', 'claim_requests.id', '=', 'claims.claim_request_id') - // ->leftJoin('members', 'claim_requests.member_id', '=', 'members.id') - // ->leftJoin('corporate_employees', 'members.id', '=', 'corporate_employees.member_id') - // ->leftJoin('corporate_divisions', 'corporate_employees.division_id', '=', 'corporate_divisions.id') - // ->where('claim_requests.id', '=', $claimRequestId) - // ->select( - // 'claim_requests.submission_date', - // 'claim_requests.code', - // DB::raw(' - // CASE - // WHEN claim_requests.status = "requested" THEN "requested" - // WHEN claim_requests.status = "approved" AND claims.status = "approved" THEN "approved" - // WHEN claim_requests.status = "approved" AND claims.status = "declined" THEN "declined" - // WHEN claim_requests.status = "approved" AND claims.status = "disbrusmented" THEN "disbrusmented" - // /*WHEN claim_requests.status = "approved" AND claims.status = "received" THEN "pending"*/ - // WHEN claim_requests.status = "approved" AND claims.status = "received" THEN "reviewed" - // ELSE "" - // END AS status - // ') - // ) - // ->first(); - // $results['status'] = $status; - // $timeline = DB::table('claim_logs') - // ->where('claim_logs.claim_request_id', '=', $claimRequestId) - // ->select( - // DB::raw(' - // CASE - // WHEN claim_logs.status = "requested" THEN "Request" - // WHEN claim_logs.status = "reviewed" THEN "Review" - // WHEN claim_logs.status = "approved" THEN "Approval" - // WHEN claim_logs.status = "declined" THEN "Decline" - // ELSE "-" - // END AS txt_status - // '), - // DB::raw(' - // CASE - // WHEN claim_logs.status = "requested" THEN "#159C9C" - // WHEN claim_logs.status = "reviewed" THEN "#0C53B7" - // WHEN claim_logs.status = "approved" THEN "#229A16" - // WHEN claim_logs.status = "declined" THEN "#FF4842" - // ELSE "-" - // END AS txt_status_color - // '), - // DB::raw(' - // CASE - // WHEN claim_logs.status = "requested" THEN "#00AB5529" - // WHEN claim_logs.status = "reviewed" THEN "#1890FF29" - // WHEN claim_logs.status = "approved" THEN "#54D62C29" - // WHEN claim_logs.status = "declined" THEN "#FF48427A" - // ELSE "-" - // END AS txt_status_backgroundColor - // '), - // 'claim_logs.date', - // 'claim_logs.description', - // 'claim_logs.status' - // ) - // ->orderBy('claim_logs.id', 'desc') - // ->get(); - // $results['timeline'] = $timeline; - // $request_files = DB::table('claim_request_files') - // ->where('claim_request_files.claim_request_id', '=', $claimRequestId) - // ->select( - // 'claim_request_files.*', - // DB::raw('(SELECT files.fileable_id FROM files WHERE files.fileable_id = claim_request_files.claim_request_id AND files.type = claim_request_files.type LIMIT 1) AS check_files'), - // ) - // ->get(); - // $results['request_files'] = $request_files; - // $documents = DB::table('files') - // ->where('fileable_type', 'App\Models\ClaimRequest') - // ->where('fileable_id', $claimRequestId) - // ->select('original_name', \DB::raw("CONCAT('" . env('APP_URL') . "/storage/', path) as path"), 'type') - // ->orderBy('id', 'desc') - // ->get(); - // $results['documents'] = $documents; - // $dialog_submits = DB::table('claim_requests') - // ->leftJoin('members', 'claim_requests.member_id','=', 'members.id') - // ->where('claim_requests.id', $claimRequestId) - // ->select('claim_requests.code', 'members.name', 'claim_requests.submission_date', 'claim_requests.service_code','claim_requests.status') - // ->first(); - // $results['dialog_submits'] = $dialog_submits; - - // return Helper::responseJson($results); - $claimRequest = ClaimRequest::findOrFail($claimRequestId); $claimRequest->load([ 'requestLog', @@ -704,10 +641,6 @@ class ClaimRequestController extends Controller public static function getNextCode() { - // $last_number = ClaimRequest::max('code'); - // $next_number = empty($last_number) ? 1 : ((int) explode('-', $last_number)[2] + 1); - // return self::makeCode($next_number); - $last_numeric_code = ClaimRequest::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'); @@ -725,11 +658,17 @@ class ClaimRequestController extends Controller public static function makeCode($next_number) { - // Pastikan $next_number adalah integer positif - $next_number = max(1, (int) $next_number); - - // Menghasilkan kode dengan format yang diinginkan - return self::$code_prefix . '-' . str_pad($next_number, 5, '0', STR_PAD_LEFT); + // Pastikan $next_number adalah integer positif + $next_number = max(1, (int) $next_number); + $requestLogData = RequestLog::where('id', $request_log_id)->first(); + $organization = Organization::where(['id' => $requestLogData->organization_id, 'type' => 'hospital'])->first('code'); + $provideCode = $organization ? $organization->code : ''; + $member = Member::with('currentCorporate')->where(['id' => $requestLogData->member_id])->first(); + $sparator = '.'; + $date = date('ymd'); + // Menghasilkan kode dengan format yang diinginkan + return self::$code_prefix . $sparator. 'H' . $sparator. $provideCode . $sparator. $date. $sparator . $member->currentPolicy->code . $sparator. $member->member_id . $sparator. str_pad($next_number, 6, '0', STR_PAD_LEFT); + } public function requestFiles(Request $request, $claim_id) @@ -788,4 +727,309 @@ class ClaimRequestController extends Controller return Helper::responseJson(data: $request->toArray(), message: 'Invoice Success Uploaded'); } + + public function exportClaimRequest(Request $request) + { + $claimRequests = ClaimRequest::query() + ->when($request->search, function ($q, $search) { + $q->where('code', 'LIKE', "%".$search."%"); + $q->orWhereHas('member', function ($subQuery) use ($search) { + $subQuery->where('name', 'LIKE', "%".$search."%"); + }); + }) + ->when($request->start_date, function ($q, $startDate) { + $q->where('submission_date', '>', Carbon::parse($startDate)->subDay()); + }) + ->when($request->end_date, function ($q, $endDate) use ($request) { + // Jika tanggal akhir diberikan dan tidak sama dengan tanggal mulai + if ($request->start_date != $request->end_date) { + $q->where('submission_date', '<', Carbon::parse($endDate)->addDay()); + } else { + $q->where('submission_date', '<=', Carbon::parse($endDate)); + } + }) + ->when($request->service_code, function ($q, $serviceCode) { + $q->whereIn('service_code', $serviceCode); + }) + ->when($request->orderBy, function ($q, $orderBy) use ($request) { + if (in_array($orderBy, ['submission_date', 'code'])) { + $q->orderBy($orderBy, $request->order); + } + }) + ->when(empty($request->orderBy), function ($q) { + $q->orderBy('created_at', 'desc'); + }) + ->when($request->status, function($q, $status) { + $q->where('status', $status); + }) + ->with(['member', 'member.currentCorporate', 'files', 'service', 'member.currentPolicy', 'requestLog', 'requestLog.organization',]) + ->addSelect([ + 'tot_billing' => function ($query) { + $query->select(DB::raw('SUM(request_log_benefits.amount_approved)')) + ->from('request_log_benefits') + ->whereColumn('request_log_benefits.request_log_id', 'claim_requests.request_log_id') + ->limit(1); + } + ]) + ->get(); + $writer = WriterEntityFactory::createXLSXWriter(); + $writer->openToFile(public_path('files/Report-Data-Claim-Request.xlsx')); + $header = [ + 'No', + 'Code Claim', + 'Date Claim Submission', + 'Code LOG', + 'Date Submission', + 'Date Admission', + 'Date Discharge', + 'Provider', + 'Member ID (BN)', + 'Member Name', + 'Member Name Principal', + 'Plan Code', + 'Payor ID', + 'Corporate name', + 'Policy Number', + 'Total Billing', + 'Benefit Code', + 'Benefit Desc', + 'Amt Incurred', + 'Amt Approved', + 'Amt Not Approved', + 'Excess Paid', + // 'Reason', + 'Diagnosis', + 'Keterangan', + 'Catatan', + 'Status', + 'QC' + ]; + $style = (new StyleBuilder()) + ->setFontBold() + // ->setFontSize(15) + // ->setFontColor(Color::BLUE) + // ->setShouldWrapText() + ->setCellAlignment(CellAlignment::LEFT) + // ->setBackgroundColor(Color::YELLOW) + ->build(); + + $headerRow = WriterEntityFactory::createRowFromArray($header, $style); + $writer->addRow($headerRow); + + $results = $claimRequests; + $no=0; + $gr_total = 0; + $rowData=[]; + foreach($results as $item) + { + // $gr_total += $item->tot_bill; + // $requestLogData = RequestLogBenefit::selectRaw('*, + // (SELECT code FROM benefits WHERE benefits.id = request_log_benefits.benefit_id) AS benefit_code, + // (SELECT description FROM benefits WHERE benefits.id = request_log_benefits.benefit_id) AS benefit_description, + // sum(amount_incurred) AS total_incurred' + // ) + // ->where(['request_log_id' => $item->request_log_id, 'deleted_at' => null]) + // ->get()->toArray(); + + //Data Benefit + $requestLogData = DB::table('request_log_benefits') + ->where('request_log_benefits.request_log_id', '=', $item->request_log_id) + ->select( + '*', + // DB::raw('SUM(request_log_benefits.amount_incurred) AS total_incurred'), + + DB::raw(' + (Select benefits.description FROM benefits + WHERE benefits.id = request_log_benefits.benefit_id LIMIT 1) AS benefit_description + '), + DB::raw(' + (Select benefits.code FROM benefits + WHERE benefits.id = request_log_benefits.benefit_id LIMIT 1) AS benefit_code + ') + ) + ->get(); + if ($item->member){ + $member = Member::where('member_id', $item->member->principal_id)->first(); + $memberPrincipal = $member->name; + $memberPlan = MemberPlan::where('member_id', $item->member->id)->get('plan_id')->toArray(); + $plan= Plan::whereIn('id', $memberPlan)->where('service_code', $item->requestLog->service_code)->first(); + $planCode = $plan->code; + if ($item->member->currentCorporate->id == $item->requestLog->organization->corporate_id_partner){ + $payor = $item->member->currentCorporate->name; + } else { + $payor = 'LinkSehat'; + } + } else { + $memberPrincipal = '-'; + $planCode = '-'; + $payor = '-'; + } + + if (!$requestLogData->isEmpty()){ + foreach($requestLogData as $key => $data){ + $no++; + if ($key == 0){ + $gr_total += $item->tot_billing; + } + $rowItem = [ + $no, + $item->code, + $item->submission_date ? $item->submission_date : '', + $item->requestLog ? $item->requestLog->code : '-', + $item->requestLog ? Helper::dateParser($item->requestLog->created_at) : '-', // submission = created_at + $item->requestLog ? $item->requestLog->submission_date : '-', + $item->requestLog ? $item->requestLog->discharge_date : '-', + $item->requestLog ? $item->requestLog->organization->name : '-', + $item->member ? $item->member->member_id : '-', + $item->member ? $item->member->name : '-', + $memberPrincipal, + $key == 0 ? $planCode : '', + $payor, + $item->member ? $item->member->currentCorporate->name : '-', + $item->member ? $item->member->currentPolicy->code : '-', + $key == 0 ? $item->tot_billing : '', + $data->benefit_code, + $data->benefit_description, + $data->amount_incurred ? $data->amount_incurred : '' , + $data->amount_approved ? $data->amount_approved : '', + $data->amount_not_approved ? $data->amount_not_approved : '', + $data->excess_paid ? $data->excess_paid : '', + // $data->reason ? $data->reason : '', + $item->requestLog ? $item->requestLog->diagnosis : '-', + $item->requestLog ? $item->requestLog->keterangan : '-', + $item->requestLog ? $item->requestLog->catatan : '-', + $item->status ? $item->status : '-' + ]; + array_push($rowData,$rowItem); + } + } else { + $no++; + if ($item->member){ + $member = Member::where('member_id', $item->member->principal_id)->first(); + $memberPrincipal = $member->name; + $memberPlan = MemberPlan::where('member_id', $item->member->id)->get('plan_id')->toArray(); + $plan= Plan::whereIn('id', $memberPlan)->where('service_code', $item->requestLog->service_code)->first(); + $planCode = $plan->code; + if ($item->member->currentCorporate->id == $item->requestLog->organization->corporate_id_partner){ + $payor = $item->member->currentCorporate->name; + } else { + $payor = 'LinkSehat'; + } + } else { + $memberPrincipal = '-'; + $planCode = '-'; + $payor = '-'; + } + $rowItem = [ + $no, + $item->code, + $item->submission_date ? Helper::dateParser($item->submission_date) : '', + $item->requestLog ? $item->requestLog->code : '-', + $item->requestLog ? Helper::dateParser($item->requestLog->created_at) : '-', // submission = created_at + $item->requestLog ? $item->requestLog->submission_date : '-', + $item->requestLog ? $item->requestLog->discharge_date : '-', + $item->requestLog ? $item->requestLog->organization->name : '-', + $item->member ? $item->member->member_id : '-', + $item->member ? $item->member->name : '-', + $memberPrincipal, + $planCode, + $payor, + $item->member ? $item->member->currentCorporate->name : '-', + $item->member ? $item->member->currentPolicy->code : '-', + '', + '', + '', + '', + '', + '', + '', + // '', + $item->requestLog ? $item->requestLog->diagnosis : '-', + $item->requestLog ? $item->requestLog->keterangan : '-', + $item->requestLog ? $item->requestLog->catatan : '-', + $item->status ? $item->status : '-' + ]; + array_push($rowData,$rowItem); + } + + } + $style = (new StyleBuilder()) + //->setFontBold() + // ->setFontSize(15) + // ->setFontColor(Color::BLUE) + // ->setShouldWrapText() + ->setCellAlignment(CellAlignment::LEFT) + // ->setBackgroundColor(Color::YELLOW) + ->build(); + foreach ($rowData as $rowItem) { + // if (is_numeric($rowItem[13])) { + // // Jumlahkan nilai angka ke total + // $grand_total_billing += $rowItem[13]; + // } + $row = WriterEntityFactory::createRowFromArray($rowItem, $style); + $writer->addRow($row); + } + + //Footer + $footer = [ + 'Total', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + $gr_total, + '', + '', + '', + '', + '', + '', + '' + ]; + $style = (new StyleBuilder()) + ->setFontBold() + // ->setFontSize(15) + // ->setFontColor(Color::BLUE) + // ->setShouldWrapText() + ->setCellAlignment(CellAlignment::LEFT) + // ->setBackgroundColor(Color::YELLOW) + ->build(); + $grand_total_billing = 0; + $footerRow = WriterEntityFactory::createRowFromArray($footer, $style); + $writer->addRow($footerRow); + + $writer->close(); + return Helper::responseJson([ + 'file_name' => 'Report-Data-Claim-Request', + "file_url" => url('files/Report-Data-Claim-Request.xlsx') + ]); + } + + public function submition($id){ + $claimRequest = ClaimRequest::findOrFail($id); + $claimRequest->status = 'submission'; + $claimRequest->claim_management = 1; + $claimRequest->status_claim_management = 'received'; + $claimRequest->submission_date_claim_management = date('Y-m-d H:i:s'); + $claimRequest->submission_by_claim_management = auth()->user()->id; + + $claimRequest->save(); + + return response()->json([ + 'error' => false, + 'message' => 'Update succses', + 'data' => $claimRequest], + 200); + + } } diff --git a/Modules/Internal/Http/Controllers/Api/CorporateController.php b/Modules/Internal/Http/Controllers/Api/CorporateController.php index be80d40c..bbb4c9d2 100644 --- a/Modules/Internal/Http/Controllers/Api/CorporateController.php +++ b/Modules/Internal/Http/Controllers/Api/CorporateController.php @@ -559,8 +559,8 @@ class CorporateController extends Controller break; case 'claim-request': return Helper::responseJson([ - 'file_name' => "Template Format Claim.xlsx", - "file_url" => url('files/Template Format Claim.xlsx') + 'file_name' => "Template Claim Request.xlsx", + "file_url" => url('files/Template Claim Request.xlsx') ]); break; case 'request-log': diff --git a/Modules/Internal/Routes/api.php b/Modules/Internal/Routes/api.php index effbf550..8a24d18b 100644 --- a/Modules/Internal/Routes/api.php +++ b/Modules/Internal/Routes/api.php @@ -235,6 +235,11 @@ Route::prefix('internal')->group(function () { Route::post('claims/{claim_id}/set-final-encounter', [ClaimEncounterController::class, 'setFinalEncounter']); Route::get('claims', [ClaimController::class, 'index']); + Route::get('claims/download-template', [ClaimController::class, 'downloadTemplate']); + Route::post('claims/import', [ClaimController::class, 'import']); + Route::post('claims/exportFiled/', [ClaimController::class, 'exportFiled']); + Route::get('claims/export-claim-management', [ClaimController::class, 'exportClaimManagement']); + Route::get('claims/get-provider', [ClaimController::class, 'getProvider']); Route::post('claims/{id}/update-items', [ClaimController::class, 'updateItems'])->name('claim.update-items'); Route::post('claims/{id}/update-diagnosis', [ClaimController::class, 'updateDiagnosis'])->name('claim.update-diagnosis'); Route::post('claims/{id}/decline', [ClaimController::class, 'decline'])->name('claim.decline'); @@ -248,6 +253,7 @@ Route::prefix('internal')->group(function () { Route::post('claims', [ClaimController::class, 'store']); Route::get('claims/{id}', [ClaimController::class, 'show']); + Route::get('claims/cek_status/{id}', [ClaimController::class, 'cekStatus']); Route::put('claims/{id}', [ClaimController::class, 'update']); Route::get('claims/{id}/edit', [ClaimController::class, 'edit']); Route::post('check-limit', [ClaimController::class, 'checkLimit']); @@ -311,13 +317,15 @@ Route::prefix('internal')->group(function () { Route::get('claim-requests', [ClaimRequestController::class, 'index'])->name('claim-requests.index'); Route::get('claim-requests/list-member', [ClaimRequestController::class, 'getClaimMemberInfiniteScroll']); // Bagaskoro, BSD 31 Oktober 2023 Route::post('claim-requests/{id}/approve', [ClaimRequestController::class, 'approve'])->name('claim-requests.approve'); - Route::get('claim-requests/{id}', [ClaimRequestController::class, 'show'])->name('claim-requests.show'); + Route::post('claim-requests/{id}/submition', [ClaimRequestController::class, 'submition'])->name('claim-requests.submition'); + Route::get('claim-requests/{id}/show', [ClaimRequestController::class, 'show'])->name('claim-requests.show'); Route::post('claim-requests', [ClaimRequestController::class, 'createNew']); // Bagaskoro, BSD 2 November 2023 Route::post('claim-requests/{id}/update', [ClaimRequestController::class, 'update']); Route::post('claim-requests/import', [ClaimRequestController::class, 'importClaim'])->name('claim-requests.importClaim'); Route::get('claim-requests/detail/{id}', [ClaimRequestController::class, 'claimRequestDetail']); Route::post('claim-requests/{id}/invoice-files', [ClaimRequestController::class, 'invoiceFiles']); Route::post('claim-requests/{id}/request-files', [ClaimRequestController::class, 'requestFiles']); + Route::get('claim-requests/export', [ClaimRequestController::class, 'exportClaimRequest']); Route::get('claim-requests/service/{id}', [ClaimRequestController::class, 'getServiceMember']); diff --git a/Modules/Internal/Transformers/ClaimRequestShowResource.php b/Modules/Internal/Transformers/ClaimRequestShowResource.php index 39923a97..d56bbd75 100644 --- a/Modules/Internal/Transformers/ClaimRequestShowResource.php +++ b/Modules/Internal/Transformers/ClaimRequestShowResource.php @@ -71,10 +71,22 @@ class ClaimRequestShowResource extends JsonResource 'total_excess_paid' => $total_excess_paid, ]; + $isReversal = false; + $isRole = auth()->user()->role_id; + if ($data['request_log']['status'] == 'approved' && + $data['request_log']['status_final_log'] == 'approved' && + $data['status'] == 'approved' && + $data['status_claim_management'] == 'approved' && + $isRole != 1 // is admin + ){ + $isReversal = true; + } + $response = [ 'id' => $data['id'], 'code' => $data['code'], + 'status' => $data['status'], 'request_log_id' => $data['request_log_id'], 'request_log' => $requestLogData, 'provider' => $data['request_log']['organization']['name'], @@ -98,7 +110,9 @@ class ClaimRequestShowResource extends JsonResource 'service_type' => Helper::serviceName( $data['request_log']['service_code']), 'claim_method' => $data['request_log']['payment_type'], 'files' => $data['request_log']['files'], + 'reason_decline' => $data['reason_decline'], // 'benefit_data' => $benefitDetailLog, + 'is_reversal' => $isReversal, // untuk penjagaan, jika true tidak bisa di edit/hapus lagi ]; diff --git a/Modules/Internal/Transformers/RequestLogShowResource.php b/Modules/Internal/Transformers/RequestLogShowResource.php index ebb5aa43..1591701a 100644 --- a/Modules/Internal/Transformers/RequestLogShowResource.php +++ b/Modules/Internal/Transformers/RequestLogShowResource.php @@ -10,6 +10,7 @@ use App\Models\RequestLogBenefit; use App\Models\RequestLogMedicine; use App\Models\Organization; use App\Models\Exclusion; +use App\Models\ClaimRequest; use App\Models\Icd; use App\Helpers\Helper; use App\Models\CorporatePolicy; @@ -36,6 +37,23 @@ class RequestLogShowResource extends JsonResource $benefitDetailLog = RequestLogBenefit::with('benefit')->where('request_log_id', $requestLog['id'])->get()->toArray(); $medicineDetailLog = RequestLogMedicine::where('request_log_id', $requestLog['id'])->get()->toArray(); $provider = Organization::where('id', $requestLog['organization_id'])->first(); + $claimRequest = ClaimRequest::where('request_log_id', $requestLog['id'])->first(); + if ($claimRequest) { + $claimCode = $claimRequest->code; + $isReversal = false; + $isRole = auth()->user()->role_id; + if ($requestLog['status'] == 'approved' && + $requestLog['status_final_log'] == 'approved' && + $claimRequest->status == 'approved' && + $claimRequest->status_claim_management == 'approved' && + $isRole != 1 + ){ + $isReversal = true; + } + } else { + $claimCode = '-'; + $isReversal = false; + } if ($provider){ $providerName = $provider->name; @@ -90,11 +108,12 @@ class RequestLogShowResource extends JsonResource ->whereIn('code', $diagnosis) ->select('code', 'name') ->get(); - } + } $data = [ 'id' => $requestLog['id'], 'code' => $requestLog['code'], + 'code_claim' => $claimCode, 'member_id' => $requestLog['member']['member_id'], 'corporate_id' => $corporateId, 'policy_number' =>$policyNumber->code ? $policyNumber->code : '-', @@ -128,6 +147,7 @@ class RequestLogShowResource extends JsonResource 'catatan' => $requestLog['catatan'], 'reason' => $requestLog['reason'], 'diagnosis' => $icd, + 'is_reversal' => $isReversal, // untuk penjagaan, jika true tidak bisa di edit/hapus lagi ]; diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index 5f7a1f4e..b188b9dc 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -11,6 +11,7 @@ use Illuminate\Support\Facades\DB; use App\Models\Member; use App\Models\User; use App\Models\Service; +use DateTime; class Helper { @@ -426,4 +427,20 @@ class Helper ini_set('memory_limit', '256M'); } + public static function dateParser($date_from_row) { + if ($date_from_row instanceof DateTime) { + return $date_from_row->format('Y-m-d'); + } else if ($date_from_row != null) { + if (strtotime($date_from_row)){ + return date('Y-m-d', strtotime($date_from_row)); + } else { + // throw new ImportRowException(__('Format Date Invalid'), 0, null, $date_from_row); + return null; + } + } else { + // throw new ImportRowException(__('Format Date Invalid'), 0, null, $date_from_row); + return null; + } + } + } diff --git a/app/Models/ClaimRequest.php b/app/Models/ClaimRequest.php index cfed961a..61b7fcf3 100644 --- a/app/Models/ClaimRequest.php +++ b/app/Models/ClaimRequest.php @@ -26,6 +26,15 @@ class ClaimRequest extends Model 'service_code', 'policy_id', 'status', + // New field for claim management + 'claim_management', + 'status_claim_management', + 'submission_date_claim_management', + 'submission_by_claim_management', + 'approval_date_claim_management', + 'approval_by_claim_management', + 'reason_decline', + // 'claim_id', 'organization_id', 'code', @@ -43,69 +52,29 @@ class ClaimRequest extends Model ]; public static $doc_headers_to_field_map = [ - "PAYOR ID" => "payor_id", - "CORPORATE ID" => "corporate_id", - "POLICY NUMBER" => "policy_number", - "MEMBER ID" => "member_id", - "MEMBER NAME" => "member_name", - "RECORD TYPE (P/D)" => "record_type", - "BENEFIT CODE" => "benefit_code", - "BENEFIT DESC" => "benefit_desc", - "CLAIM TYPE" => "claim_type", - "CLAIM PROCESS STATUS" => "status", - "CLIENT CLAIM ID" => "client_claim_id", - "REFERENCE NO" => "reference_no", - "ADMEDIKA CLAIM ID" => "admika_claim_id", - "PROVIDER CODE" => "provider_code", - "ADMISSION DATE" => "admission_date", - "DISCUTRGE DATE" => "discutrge_date", - "DURATION DAYS" => "duration_days", - "COVERAGE TYPE" => "coverage_type", - "PLAN ID" => "plan_id", - "DIAGNOSIS CODE" => "diagnosis_code", - "DIAGNOSIS DESC" => "diagnosis_desc", - "TOT AMT INCURRED" => "tot_amt_insurred", - "TOT AMT APPROVED" => "tot_amt_approved", - "TOT AMT NOT APPROVED" => "tot_amt_not_approved", - "TOT EXCESS PAID" => "tot_excess_paid", - "REMARKS" => "remarks", - "SECONDARY DIAGNOSIS CODE" => "secondary_diagnosis", - "APPROVED DATE" => "approved_date", - "APPROVED BY" => "approved_by", - "DATE RECEIVED" => "data_received", - "HOSPITAL INVOICE DATE" => "hospital_invoice_date", + "Code LOG" => "code", + "Date Claim Submission" => "date_submission", + "Total Billing" => "total_billing", + "Benefit Code" => "benefit_code", + "Amt Incurred" => "amount_incurred", + "Amt Approved" => "amount_apporve", + "Amt Not Approved" => "amount_not_apporve", + "Excess Paid" => "excess_paid", + "Reason" => "reason", + "QC" => "qc", ]; public static $listing_doc_headers = [ - "PAYOR ID", - "CORPORATE ID", - "POLICY NUMBER", - "MEMBER ID", - "MEMBER NAME", - "RECORD TYPE (P/D)", - "CLAIM TYPE", - "CLAIM PROCESS STATUS", - "CLIENT CLAIM ID", - "REFERENCE NO", - "ADMEDIKA CLAIM ID", - "PROVIDER CODE", - "ADMISSION DATE", - "DISCUTRGE DATE", - "DURATION DAYS", - "COVERAGE TYPE", - "PLAN ID", - "DIAGNOSIS CODE", - "DIAGNOSIS DESC", - "TOT AMT INCURRED", - "TOT AMT APPROVED", - "TOT AMT NOT APPROVED", - "TOT EXCESS PAID", - "REMARKS", - "SECONDARY DIAGNOSIS CODE", - "APPROVED DATE", - "APPROVED BY", - "DATE RECEIVED", - "HOSPITAL INVOICE DATE", + "Code LOG", + "Date Claim Submission", + "Total Billing", + "Benefit Code", + "Amt Incurred", + "Amt Approved", + "Amt Not Approved", + "Excess Paid", + // "Reason", + "QC", ]; diff --git a/app/Services/ClaimRequestService.php b/app/Services/ClaimRequestService.php index 3ecac549..7d1a7e88 100644 --- a/app/Services/ClaimRequestService.php +++ b/app/Services/ClaimRequestService.php @@ -6,6 +6,9 @@ use App\Events\ClaimApproved; use App\Events\ClaimRequested; use App\Models\Claim; use App\Models\ClaimRequest; +use App\Models\RequestLog; +use App\Models\Benefit; +use App\Models\RequestLogBenefit; use App\Models\Organization; use App\Helpers\Helper; use App\Models\Icd; @@ -20,6 +23,7 @@ use Str; class ClaimRequestService{ + private static $code_prefix = 'CLAIM'; public static function storeClaimRequest($row = null, $code, $member, $paymentType, $serviceCode, $requestLogID = null, $submissionDate = null, $status = 'requested', $organization_code = null) { // try { @@ -32,24 +36,74 @@ class ClaimRequestService{ 'code' => $row['provider_code'] ]), 403, null, $row); } - }; + } DB::beginTransaction(); - $claimRequestData = [ - 'code' => $code, - 'request_log_id' => $requestLogID ?? 0, - 'member_id' => $member->id, - 'submission_date' => $submissionDate ?? now(), - 'status' => $status, - 'payment_type' => $paymentType, - 'service_code' => $serviceCode, - 'policy_id' => $member->currentPolicy->id ?? null, - 'organization_id' => $organization ? $organization->id : 0, - ]; - - $claimRequest = ClaimRequest::create($claimRequestData); + if ($status == 'submission'){ + $claimManagement = 1; + $submissionDateClaimManagement = $submissionDate; + $submissionByClaimManagement = auth()->user()->id; + $statusClaim = 'received'; + } else { + $claimManagement = 0; + $submissionDateClaimManagement = null; + $submissionByClaimManagement = null; + $statusClaim = null; + } + if (count($row)>0){ + if($row['total_billing']) { + $data = [ + 'code' => $code, + 'request_log_id' => $requestLogID ?? 0, + 'member_id' => $member->id, + 'submission_date' => $submissionDate ?? now(), + 'status' => $status, + 'claim_management' => $claimManagement, + 'status_claim_management' => $statusClaim, + 'submission_date_claim_management' => $submissionDateClaimManagement, + 'submission_by_claim_management' => $submissionByClaimManagement, + 'payment_type' => $paymentType, + 'service_code' => $serviceCode, + 'policy_id' => $member->currentPolicy->id ?? null, + 'organization_id' => $organization ? $organization->id : 0, + ]; + } else { + $data = []; + } + $claimRequest = ClaimRequest::updateOrCreate(['request_log_id' => $requestLogID],$data); + $benefitData = Benefit::where('code', $row['benefit_code'])->first(); + $requestLogData = RequestLogBenefit::updateOrCreate( + [ + 'request_log_id' => $requestLogID, + 'benefit_id' => $benefitData->id, + ],[ + 'request_log_id' => $requestLogID, + 'benefit_id' => $benefitData->id, + 'amount_incurred' => $row['amount_incurred'], + 'amount_approved' => $row['amount_apporve'], + 'amount_not_approved' => $row['amount_not_apporve'], + 'excess_paid' => $row['excess_paid'], + ]); + } else { // input from hospital portal + $data = [ + 'code' => $code, + 'request_log_id' => $requestLogID ?? 0, + 'member_id' => $member->id, + 'submission_date' => $submissionDate ?? now(), + 'status' => $status, + 'claim_management' => $claimManagement, + 'status_claim_management' => $statusClaim, + 'submission_date_claim_management' => $submissionDateClaimManagement, + 'submission_by_claim_management' => $submissionByClaimManagement, + 'payment_type' => $paymentType, + 'service_code' => $serviceCode, + 'policy_id' => $member->currentPolicy->id ?? null, + 'organization_id' => $organization ? $organization->id : 0, + ]; + $claimRequest = ClaimRequest::updateOrCreate(['request_log_id' => $requestLogID],$data); + } DB::commit(); return $claimRequest; @@ -60,8 +114,6 @@ class ClaimRequestService{ // } } - - public static function storeClaimManagement($row, $member, $claim_request_id){ try { $organization = 0; @@ -130,53 +182,58 @@ class ClaimRequestService{ } } - protected function validatePlanRow($row) - { - if (empty($row['member_id'])) { - throw new ImportRowException(__('Member ID Required'), 0, null, $row); - } - } - public function handleClaimRequestRow($row) { try { - $member = Member::where('member_id', $row['member_id'])->with(['currentPlan'])->first(); - if(!$member){ - throw new ImportRowException(__('Member Tidak ditemukan'), 0, null, $row); + $requestLog = RequestLog::where('code', $row['code'])->first(); + if(!$requestLog){ + throw new ImportRowException(__('LOG Tidak ditemukan'), 0, null, $row); }; - $code = $row['client_claim_id']; - $organization_id = $row['provider_code']; - $submissionDate = Helper::formatDateDB($row['admission_date']); - $paymentType = $row['claim_type']; - $status = $row['status']; - $serviceCode = $row['coverage_type']; + if ($requestLog->status != 'approved' && $requestLog != 'approved'){ + throw new ImportRowException(__('Request LOG / Final LOG Belum di Approved'), 0, null, $row); + } + $organization = Organization::where('id', $requestLog->organization_id)->first(); + + // Create Code + $last_numeric_code = ClaimRequest::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'); + // $next_number = 1; + if ($last_numeric_code) { + // // Jika ada kode sebelumnya, pecah kode dan tambahkan 1 ke angka terakhir + // $parts = explode('-', $last_code); + // $last_number = (int) end($parts); + $next_number = $last_numeric_code + 1; + } else { + $next_number = 1; + } + // make code + $member = Member::with('currentCorporate')->where(['id' => $requestLog->member_id])->first(); + $sparator = '.'; + $date = date('ymd'); + // Menghasilkan kode dengan format yang diinginkan + $code = 'CLAIM' . $sparator. 'I' . $sparator. $organization->code . $sparator. $date. $sparator . $member->currentPolicy->code . $sparator. $member->member_id . $sparator. str_pad($next_number, 5, '0', STR_PAD_LEFT); + $submissionDate = Helper::dateParser($row['date_submission']); + $paymentType = $requestLog->payment_type; + if ($row['qc'] == 'Y'){ + $status = 'submission'; + } else { + $status = 'requested'; + } + $serviceCode = $requestLog->service_code; $newClaimRequest = $this->storeClaimRequest( row: $row, code: $code, member: $member, paymentType: $paymentType, serviceCode: $serviceCode, + requestLogID: $requestLog->id, submissionDate: $submissionDate, status: $status, - organization_code: $organization_id + organization_code: $organization->code ); - $newlyCreatedID = $newClaimRequest->id; - - $newClaimManangement = $this->storeClaimManagement($row, $member, $newlyCreatedID); - ClaimRequested::dispatch($newClaimRequest); - // Log History - $newClaimRequest->histories()->create([ - 'title' => 'New Claim Requested', - 'description' => "Claim Requested for Member : {$member->member_id} - ({$member->full_name})", - 'type' => 'info', - 'system_origin' => 'import-internal-aso' - ]); - - $claim_request_data = $row; - $this->validatePlanRow($claim_request_data); - return $newClaimRequest; } catch (\Exception $e) { throw $e; diff --git a/database/migrations/2024_02_23_091725_add_coloumn_to_claim_request_table.php b/database/migrations/2024_02_23_091725_add_coloumn_to_claim_request_table.php new file mode 100644 index 00000000..09501950 --- /dev/null +++ b/database/migrations/2024_02_23_091725_add_coloumn_to_claim_request_table.php @@ -0,0 +1,47 @@ +integer('claim_management') + ->default(0) + ->after('status') + ->comment('0=claim request, 1=claim management'); + $table->string('status_claim_management')->after('claim_management')->nullable(); + $table->dateTime('submission_date_claim_management')->after('status_claim_management')->nullable(); + $table->string('submission_by_claim_management')->after('submission_date_claim_management')->nullable(); + $table->dateTime('approval_date_claim_management')->after('submission_by_claim_management')->nullable(); + $table->string('approval_by_claim_management')->after('approval_date_claim_management')->nullable(); + $table->string('reason_decline')->after('approval_by_claim_management')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('claim_requests', function (Blueprint $table) { + $table->dropColumn('claim_management'); + $table->dropColumn('status_claim_management'); + $table->dropColumn('submission_date_claim_management'); + $table->dropColumn('submission_by_claim_management'); + $table->dropColumn('approval_date_claim_management'); + $table->dropColumn('approval_by_claim_management'); + $table->dropColumn('reason_decline'); + }); + } +}; diff --git a/frontend/client-portal/src/pages/AlarmCenter/ServiceMonitoring.tsx b/frontend/client-portal/src/pages/AlarmCenter/ServiceMonitoring.tsx index edecc2e8..82b75065 100644 --- a/frontend/client-portal/src/pages/AlarmCenter/ServiceMonitoring.tsx +++ b/frontend/client-portal/src/pages/AlarmCenter/ServiceMonitoring.tsx @@ -203,6 +203,8 @@ type ServiceMonitoringProps = { }[]; }> >; + keterangan: string; + catatan: string; }; export default function ServiceMonitoring() { @@ -591,6 +593,44 @@ export default function ServiceMonitoring() { )} */} + {/* Keterangan */} + + + + {loading ? : 'Keterangan'} + + + + + {loading ? ( + + ) : data && data.keterangan ? ( + data.keterangan + ) : ( + '-' + )} + + + + {/* Catatan */} + + + + {loading ? : 'Catatan'} + + + + + {loading ? ( + + ) : data && data.catatan ? ( + data.catatan + ) : ( + '-' + )} + + + diff --git a/frontend/dashboard/src/pages/ClaimRequests/Components/DialogConfirmation.tsx b/frontend/dashboard/src/pages/ClaimRequests/Components/DialogConfirmation.tsx index ce78fa0b..259ffed7 100644 --- a/frontend/dashboard/src/pages/ClaimRequests/Components/DialogConfirmation.tsx +++ b/frontend/dashboard/src/pages/ClaimRequests/Components/DialogConfirmation.tsx @@ -1,35 +1,30 @@ import MuiDialog from "@/components/MuiDialog"; -import { Autocomplete, Button, Card, Checkbox, DialogActions, Grid, TextField, Typography } from "@mui/material"; +import { Button, Card, Checkbox, DialogActions, Grid, TextField, TextareaAutosize, Typography } from "@mui/material"; import { Paper } from "@mui/material"; import { Stack } from '@mui/material'; import React, { useEffect, useState } from 'react'; -import { ClaimRequest, Files } from '@/@types/claims'; -import { fDateOnly, fDateTimesecond, toTitleCase } from "@/utils/formatTime"; +import { DetailClaimRequest } from "../Model/Types"; +import { fDateTimesecond, toTitleCase } from "@/utils/formatTime"; import axios from "@/utils/axios"; -import { enqueueSnackbar, useSnackbar } from "notistack"; +import { enqueueSnackbar } from "notistack"; import { useNavigate } from "react-router"; -import * as Yup from 'yup'; -import { yupResolver } from '@hookform/resolvers/yup'; +import { RHFTextField } from "@/components/hook-form"; + type DialogConfirmationType = { openDialog: boolean; setOpenDialog: any; onSubmit?: void; approve: string; - claimRequest: ClaimRequest|undefined; + requestLog: DetailClaimRequest|undefined; } -export default function DialogConfirmation({claimRequest, setOpenDialog, openDialog, approve, onSubmit} : DialogConfirmationType ) { - +export default function DialogConfirmation({requestLog, setOpenDialog, openDialog, approve, onSubmit} : DialogConfirmationType ) { const navigate = useNavigate(); - const { enqueueSnackbar } = useSnackbar(); - + const [formData, setFormData] = useState({ - date: claimRequest?.date, - id: claimRequest?.id, - reason: claimRequest?.reason + }); - const handleChange = (field, value) => { setFormData((prevData) => ({ ...prevData, @@ -38,24 +33,28 @@ export default function DialogConfirmation({claimRequest, setOpenDialog, openDia }; + const handleApprove = () => { + setFormData((prevData) => ({ + ...prevData, + status: approve, + })); + handleSubmit(); + }; + + const handleSubmit = () => { axios - .post(`customer-service/request/final-log`, formData) + .post(`claim-requests/${requestLog?.id}/submition`, formData) .then((response) => { - enqueueSnackbar('Verification Request LOG Success', { variant: 'success' }); + enqueueSnackbar('Submition Claim Request Success', { variant: 'success' }); setOpenDialog(false); - if (requestLog?.service_type == 'Inpatient'){ - navigate('/case_management/inpatient_monitoring'); - } else { - navigate('/custormer-service/final-log'); - } + navigate('/claim-requests') }) .catch(({ response }) => { enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' }); }); } - const style1 = { color: '#919EAB', width: '30%' @@ -66,34 +65,57 @@ export default function DialogConfirmation({claimRequest, setOpenDialog, openDia const marginBottom1 = { marginBottom: 1, } + const marginBottom2 = { marginBottom: 2, } + + const resetForm = () => { + setFormData({ + status: approve, + no_identitas: requestLog?.no_identitas ?? '', + keterangan: '', + hak_kamar_pasien: '', + penempatan_kamar: '', + }); + }; + const handleCloseDialog = () => { setOpenDialog(false); + resetForm(); } - + const handleNumericInput = (input: any) => { + const numericInput = input.replace(/\D/g, ''); + return numericInput; + }; + const handleKeyPress = (e:any) => { + if (e.key === 'Enter' && !e.shiftKey) { + // Menghentikan default "Enter" (tidak membuat baris baru) + e.preventDefault(); + + // Menambahkan karakter baris baru + handleChange('keterangan', `${formData.keterangan}\n`); + } + }; + + console.log(approve, 'test') const getContent = () => ( - Are you sure to {approve == 'approved' ? 'approve' : 'deciline'} this final log ? + Are you sure to submit this claim ? - Member ID - {requestLog?.member_id} - - - Policy Number - {requestLog?.policy_number} + Code + {requestLog?.code} Name {requestLog?.name} - Submission Date + Date Submission {requestLog?.submission_date ? fDateTimesecond(requestLog?.submission_date) : '-'} @@ -105,58 +127,10 @@ export default function DialogConfirmation({claimRequest, setOpenDialog, openDia {requestLog?.service_type} - - - - Discharge Date - handleChange('discharge_date', e.target.value)} - /> - - - Catatan - handleChange('catatan', e.target.value)} - /> - - - Diagnosis ICD - X - option.label} - fullWidth - value={icdOptions.filter((icd) => formData.icdCodes.includes(icd.value))} - onChange={(e, newValues) => handleChange('icdCodes', newValues.map((value) => value.value))} - renderInput={(params) => ( - - )} - /> - - Cancel - - {approve == 'approved' ? ( - handleApprove()}>Approve - ) : ( - handleApprove()}>Decline - ) } - + handleApprove()}>Submit ); @@ -168,7 +142,7 @@ export default function DialogConfirmation({claimRequest, setOpenDialog, openDia openDialog={openDialog} setOpenDialog={setOpenDialog} content={getContent()} - maxWidth="xl" + maxWidth="md" /> ); } \ No newline at end of file diff --git a/frontend/dashboard/src/pages/ClaimRequests/Components/FormEdit.tsx b/frontend/dashboard/src/pages/ClaimRequests/Components/FormEdit.tsx index 80811203..256aaea9 100644 --- a/frontend/dashboard/src/pages/ClaimRequests/Components/FormEdit.tsx +++ b/frontend/dashboard/src/pages/ClaimRequests/Components/FormEdit.tsx @@ -78,15 +78,13 @@ export default function FormEdit({ isEdit, currentClaim }: Props) { ); - const [date, setDate] = useState(currentClaim?.submission_date) + const [date, setDate] = useState(currentClaim?.submission_date ? fDateTimesecond(currentClaim?.submission_date) : null) const id = currentClaim?.id useEffect(() => { setDate(currentClaim?.submission_date) }, [currentClaim]); - console.log(date); - useEffect(() => { if (isEdit && currentClaim) { reset(defaultValues); @@ -254,7 +252,6 @@ export default function FormEdit({ isEdit, currentClaim }: Props) { ) - return ( @@ -310,10 +307,14 @@ export default function FormEdit({ isEdit, currentClaim }: Props) { setDate(field.value)} + value={field.value} + onChange={() => + setDate(field.value) + } + dateFormat='dd MMM yyyy HH:mm:ss' /> )} + /> diff --git a/frontend/dashboard/src/pages/ClaimRequests/CreateUpdate.tsx b/frontend/dashboard/src/pages/ClaimRequests/CreateUpdate.tsx index c1e6307d..1d956a40 100644 --- a/frontend/dashboard/src/pages/ClaimRequests/CreateUpdate.tsx +++ b/frontend/dashboard/src/pages/ClaimRequests/CreateUpdate.tsx @@ -32,7 +32,7 @@ export default function ClaimsCreateUpdate() { useEffect(() => { if (isEdit) { - axios.get('/claim-requests/' + id).then((res) => { + axios.get('/claim-requests/' + id + '/show').then((res) => { setCurrentClaim(res.data.data); }); diff --git a/frontend/dashboard/src/pages/ClaimRequests/Detail.tsx b/frontend/dashboard/src/pages/ClaimRequests/Detail.tsx index a4d31d16..647f632c 100644 --- a/frontend/dashboard/src/pages/ClaimRequests/Detail.tsx +++ b/frontend/dashboard/src/pages/ClaimRequests/Detail.tsx @@ -38,6 +38,8 @@ import DialogDeleteFileLog from './Components/DialogDeleteFileLog'; import DialogBenefit from '../CustomerService/FinalLog/Components/DialogBenefit'; import DialogDeleteBenefit from '../CustomerService/FinalLog/Components/DialogDeleteBenefit'; import DialogEditBenefit from '../CustomerService/FinalLog/Components/DialogEditBenefit'; +import DialogConfirmation from './Components/DialogConfirmation'; + // ---------------------------------------------------------------------- @@ -49,6 +51,8 @@ export default function Detail() { const navigate = useNavigate(); const { themeStretch } = useSettings(); const [claimRequests, setClaimRequest] = useState(); + const [openDialogSubmit, setOpenDialogSubmit] = useState(false); + const [isReversal, setIsReversal] = useState(false); const { id } = useParams(); @@ -57,6 +61,7 @@ export default function Detail() { .get('claim-requests/detail/'+id) .then((response) => { setClaimRequest(response.data.data) + setIsReversal(response.data.data.is_reversal) }) .catch((error) => { console.error(error); @@ -223,13 +228,18 @@ export default function Detail() { Document - - } sx={{marginLeft: 'auto'}} onClick={() => { - setDialogUploadFileLog(true) - }} > - File - - + { + !isReversal ? ( + + } sx={{marginLeft: 'auto'}} onClick={() => { + setDialogUploadFileLog(true) + }} > + File + + + ) : null + } + {claimRequests?.files?.map((documentType, index) => ( @@ -250,14 +260,19 @@ export default function Detail() { {documentType.original_name ? documentType.original_name : '-'} - - { - setDialogDeleteFileLog(true) - setPathFile(documentType.path) - }} aria-label="delete" size="small" sx={{ marginLeft: 'auto' }}> - - - + { + !isReversal ? ( + + { + setDialogDeleteFileLog(true) + setPathFile(documentType.path) + }} aria-label="delete" size="small" sx={{ marginLeft: 'auto' }}> + + + + ) : null + } + ))} @@ -281,11 +296,15 @@ export default function Detail() { Benefit - } sx={{marginLeft: 'auto'}} onClick={() => { - setDialogBenefit(true); - }} > - Benefit - + { + !isReversal ? ( + } sx={{marginLeft: 'auto'}} onClick={() => { + setDialogBenefit(true); + }} > + Benefit + + ) : null + } @@ -298,29 +317,34 @@ export default function Detail() { {item.benefit?.description} - - - { - setDialogEditBenefit(true) - setIdBenefitData(item.id) - setBenefitConfigurationData(item) - }} - > - - Edit - - { - setIdBenefitData(item.id) - setDialogDeleteBenefit(true) - }} - > - - Delete - - > - } /> - + { + !isReversal ? ( + + + { + setDialogEditBenefit(true) + setIdBenefitData(item.id) + setBenefitConfigurationData(item) + }} + > + + Edit + + { + setIdBenefitData(item.id) + setDialogDeleteBenefit(true) + }} + > + + Delete + + > + } /> + + ) : null + } + @@ -421,7 +445,7 @@ export default function Detail() { - + Total Benefit @@ -436,12 +460,12 @@ export default function Detail() { - + Amount Incurred - + {totalAmountIncurred ? fNumber(totalAmountIncurred) : '0'} @@ -452,12 +476,12 @@ export default function Detail() { - + Amount Approved - + {totalAmountApproved ? fNumber(totalAmountApproved) : '0'} @@ -468,12 +492,12 @@ export default function Detail() { - + Amount Not Approved - + {totalAmountNotApproved ? fNumber(totalAmountNotApproved) : 0} @@ -484,12 +508,12 @@ export default function Detail() { - + Excess Paid - + {totalExcessPaid ? fNumber(totalExcessPaid) : 0} @@ -497,6 +521,23 @@ export default function Detail() { + + + + Biaya disetujui + + + + + {totalAmountApproved ? fNumber(totalAmountApproved) : '0'} + + + + + Nominal diatas 1 juta akan menunggu persetujuan senior analyst + + + @@ -504,9 +545,25 @@ export default function Detail() { : ( null )} + + + { claimRequests?.status === 'declined' ? ( + + + Reason + + + + Reason Decline + {claimRequests?.reason_decline} + + + + ) : null } + {/* PR Buat pindahin ke componen */} {/* */} + + {(claimRequests?.status === 'requested') || (claimRequests?.status === 'declined') ? ( + + + {/* Perubahan sintaksis disini */} + { + navigate('/claim-requests') + }} + > + Cancel + + + + { + setOpenDialogSubmit(true); + setApprove('approved'); + }} + > + Submit + + + + + + + ) : null} diff --git a/frontend/dashboard/src/pages/ClaimRequests/List.tsx b/frontend/dashboard/src/pages/ClaimRequests/List.tsx index c2df449c..20437328 100644 --- a/frontend/dashboard/src/pages/ClaimRequests/List.tsx +++ b/frontend/dashboard/src/pages/ClaimRequests/List.tsx @@ -123,6 +123,11 @@ export default function List() { variant="outlined" fullWidth onChange={handleSearchChange} + onKeyDown={(event) => { + if (event.key === 'Enter') { + handleSearchSubmit(event); + } + }} value={searchText} placeholder='Search Code or Name...' /> @@ -152,7 +157,7 @@ export default function List() { { try { @@ -274,7 +279,7 @@ export default function List() { } const handleGetData = (type :string) => { - axios.get(`corporates/${corporate_id}/data-plan-benefit`) + axios.get(`claim-requests/export`) .then((response) => { const link = document.createElement('a'); link.href = response.data.data.file_url; @@ -361,14 +366,32 @@ export default function List() { )} {importResult && ( + // + // + // Last Import Result Report :{' '} + // + // {importResult.result_file?.name ?? '-'} + // + // + // + - Last Import Result Report :{' '} + Last Import Result :{' '} + + {importResult.result_file?.total_success_row ?? 0} + {' '} + Row Processed,{' '} + + {importResult.result_file?.total_failed_row} + {' '} + Failed, Report :{' '} {importResult.result_file?.name ?? '-'} + )} ); @@ -393,7 +416,7 @@ export default function List() { setDataTableLoading(true); const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]); const response = await axios.get('/claim-requests', { params: filter }); - console.log(response.data); + setDataTableLoading(false); @@ -468,8 +491,12 @@ export default function List() { {row.service_name} {row.payment_type_name} - { row.status == "requested" ? + { row.status == "requested" ? ({capitalizeFirstLetter(row.status)}) : + row.status == "submission" ? + ( {capitalizeFirstLetter(row.status)}) : + row.status == "declined" ? + ( {capitalizeFirstLetter(row.status)}) : ( {capitalizeFirstLetter(row.status)}) } diff --git a/frontend/dashboard/src/pages/ClaimRequests/Model/Types.tsx b/frontend/dashboard/src/pages/ClaimRequests/Model/Types.tsx index e62ad097..782bc315 100644 --- a/frontend/dashboard/src/pages/ClaimRequests/Model/Types.tsx +++ b/frontend/dashboard/src/pages/ClaimRequests/Model/Types.tsx @@ -51,6 +51,7 @@ export type DetailClaimRequest = { benefit_data : BenefitData[], diagnosis : Diagnosis[], request_log : RequestLogType | undefined, + reason_decline : string, } export type RequestLogType = { diff --git a/frontend/dashboard/src/pages/Claims/Detail.tsx b/frontend/dashboard/src/pages/Claims/Detail.tsx index 28cf2c47..c1d62748 100644 --- a/frontend/dashboard/src/pages/Claims/Detail.tsx +++ b/frontend/dashboard/src/pages/Claims/Detail.tsx @@ -1,637 +1,102 @@ -import * as Yup from 'yup'; -// mui import { Container, Grid, Stack, Typography, Card, - TextField, - Divider, - ButtonBase, - Box, + TableRow, + Tab, + TableCell, + Collapse, + AccordionSummary, + AccordionDetails, IconButton, - Autocomplete, - FormControl, - InputLabel, - Select, - FormHelperText, - MenuItem } from '@mui/material'; + TextField + } from '@mui/material'; // components -import Page from '../../components/Page'; +import Page from '@/components/Page'; // utils -import useSettings from '../../hooks/useSettings'; +import useSettings from '@/hooks/useSettings'; // react import { useNavigate, useParams, useLocation } from 'react-router-dom'; import { useEffect, useState, useRef, useMemo } from 'react'; -import axios from '../../utils/axios'; +import axios from '@/utils/axios'; // pages -import { format } from 'date-fns'; import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos'; -import Button from '@mui/material/Button'; -import AddIcon from '@mui/icons-material/Add'; -import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile'; -import { Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material'; -import CloseIcon from '@mui/icons-material/Close'; -import FormGroup from '@mui/material/FormGroup'; -import FormControlLabel from '@mui/material/FormControlLabel'; -import Checkbox from '@mui/material/Checkbox'; -import { DatePicker, LocalizationProvider } from '@mui/x-date-pickers'; -import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; -import { fPostFormat } from '@/utils/formatTime'; -import { fDate, fDateTime } from '../../utils/formatTime'; -import ListItemText from '@mui/material/ListItemText'; -import EditOutlinedIcon from '@mui/icons-material/EditOutlined'; -import TableMoreMenu from '@/components/table/TableMoreMenu'; - -import { enqueueSnackbar } from 'notistack'; -import BenefitConfigurationList from './components/BenefitConfigurationList'; -import { map } from 'lodash'; - - -import { FormProvider, RHFDatepicker, RHFSelect, RHFTextField } from '@/components/hook-form'; -import { useFieldArray, useForm } from 'react-hook-form'; -import { ClaimHistoryCare } from '@/@types/claims'; -import { yupResolver } from '@hookform/resolvers/yup'; -import { LoadingButton } from '@mui/lab'; -import { Delete, Edit, EditOffOutlined, EditTwoTone, LoopOutlined, RefreshOutlined } from '@mui/icons-material'; -import { fDateOnly, fDateTimeSuffix } from '@/utils/formatTime'; +import { fDate, fDateTimesecond, fDateTime } from '@/utils/formatTime'; +import { Button } from '@mui/material'; import Label from '@/components/Label'; -import RHFAutocomplete from '../../components/hook-form/RHFAutocompleteV2'; +import { Box } from '@mui/system'; +import { Accordion } from '@mui/material'; +import { Delete, EditOutlined, ExpandMore } from '@mui/icons-material'; +import AddIcon from '@mui/icons-material/Add'; + +import MoreMenu from '@/components/MoreMenu'; +import { MenuItem } from '@mui/material'; +import { fNumber } from '@/utils/formatNumber'; +import palette from '@/theme/palette'; + +import CloseIcon from '@mui/icons-material/Close'; +import { enqueueSnackbar } from 'notistack'; +import { Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material'; + + // ---------------------------------------------------------------------- export default function Detail() { const location = useLocation(); const queryParams = new URLSearchParams(location.search); - const code = queryParams.get('code'); const navigate = useNavigate(); const { themeStretch } = useSettings(); - const [customerData, setCustomerData] = useState(null); - const [documentData, setDocumentData] = useState(null); - const [requestDocumentData, setRequestDocumentData] = useState(null); - const [serviceData, setServiceData] = useState(null); - const [serviceBenefitData, setServiceBenefitData] = useState(null); - const [dataDialog, setDataDialog] = useState(null); + const [requestLog, setRequestLog] = useState(); + const [statusClaim, setStatusClaim] = useState(''); + const [dataMember, setDataMember] = useState(''); + const { id } = useParams(); + const {id_claim} = useParams(); useEffect(() => { axios - .get('/claims/detail/'+id) + .get('customer-service/request/'+id) .then((response) => { - setCustomerData(response.data.data.customer_data); - setDocumentData(response.data.data.documents); - setRequestDocumentData(response.data.data.request_documents); - setServiceData(response.data.data.claim_services); - setServiceBenefitData(response.data.data.claim_service_benefits); - setDataDialog(response.data.data.dialog_submits); + setRequestLog(response.data.data) }) .catch((error) => { console.error(error); }); - getService(); + axios + .get('claims/cek_status/'+id_claim) + .then((response) => { + setStatusClaim(response.data.cek.status); + setDataMember(response.data.member); - }, []); - - function toTitleCase(str: string | null) { - return str.replace(/\w\S*/g, function(txt) { - return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); - }); - } + }) + .catch((error) => { + console.error(error); + }) + }, [id, id_claim]); const style1 = { color: '#919EAB', width: '30%' } + const style3 = { + color: '#919EAB', + width: '35%' + } const style2 = { width: '70%' } const marginBottom1 = { marginBottom: 1, } - - //Request - const [openDialogRequest, setOpenDialogRequest] = useState(false); - const handleCloseDialogRequest = () => { - setOpenDialogRequest(false); + const marginBottom2 = { + marginBottom: 2, } - const [conditionChecked, setConditionChecked] = useState(true); - const [diagnosisChecked, setDiagnosisChecked] = useState(false); - const [supportingResultChecked, setSupportingResultChecked] = useState(false); - - const handleConditionChange = (event) => { - setConditionChecked(event.target.checked); - }; - - const handleDiagnosisChange = (event) => { - setDiagnosisChecked(event.target.checked); - }; - - const handleSupportingResultChange = (event) => { - setSupportingResultChecked(event.target.checked); - }; - - const [noteField, setNoteField] = useState(''); - const [noteFieldError, setNoteFieldError] = useState(''); - const isRequiredFieldsFilled = () => { - return noteField.trim() !== ''; - }; - - const handelRequestDocument = () => { - const dataForm = { - claim_id: id, - condition: conditionChecked, - diagnosis: diagnosisChecked, - result: supportingResultChecked, - note: noteField, - } - axios - .post('/claims/request-documents', dataForm) - .then((response) => { - enqueueSnackbar('Success Request Document', { variant: 'success' }); - setOpenDialogRequest(false); - window.location.reload(); - }) - .catch((error) => { - enqueueSnackbar('Something Went Wrong', { variant: 'error' }); - }) - } - - /*---------------------- Handle History Hospital Care ----------------------------*/ - - interface FormValuesProps extends Partial { - taxes: boolean; - inStock: boolean; - } - - - /**------------- Handle History Hospital Care ---------------------*/ - const [currentClaimHistoryCare, setCurrentClaimHistoryCare] = useState(null); - const [organization, setOrganization] = useState([]); // Untuk Hospital - const [doctor, setDoctor] = useState([]); // Untuk Docter - const [corporate_id, setCorporateId] = useState(null); // Untuk Corporate - const [main_diagnosis, setMainDiagnosis] = useState([]); // Untuk Main diagnosis - const [claimHistoryId,setClaimHistoryId] = useState(null); // Untuk edit Claim History - - const [carehistory, setCarehistory] = useState(null); - const [isEdit,setEdit] = useState(false); - const [service_code, setServiceType] = useState(); - const handleCloseDialogUpdate = () => { - setOpenDialogRequest(false); - reset() - } - - useEffect( () => { - axios - .get('claims/'+id) - .then((response) => { - setCorporateId(response.data.data.corporate_id) - setCurrentClaimHistoryCare(response.data.data.history_hospital_care) - setServiceType(response.data.data.service_code) - - }) - }, [id]) - - useEffect( () => { - // setMainDiagnosis - axios - .get(`corporates/${corporate_id}/diagnosis`) - .then((response) => { - setMainDiagnosis(response.data.data) - }) - - // setOrganization atau hospital atau location - axios - .get(`corporates/${corporate_id}/hospitals`) - .then((response) => { - setOrganization(response.data.data) - }) - - }, [corporate_id]) - - useEffect( () => { - // setCarehistory - if (claimHistoryId != null) { - axios - .get('/claims/carehistory/'+claimHistoryId) - .then((response) => { - reset({ - service_code: response.data.data.service_code, - admission_date: response.data.data.admission_date, - discharge_date: response.data.data.discharge_date, - organization_id: response.data.data.organization_id, - practitioner_id: response.data.data.practitioner_id, - medical_record_number: response.data.data.medical_record_number, - symptoms: response.data.data.symptoms, - sign: response.data.data.sign, - main_diagnosis_id: response.data.data.main_diagnosis_id, - secondary_diagnosis_id: response.data.data.secondary_diagnosis.map((row: any) => ({ - value: { - id: row.id, - name: row.icd.name - } - })) - }); - - setCarehistory(response.data.data); - }) - .catch((error) => { - console.error(error); - }); - // setDoctor atau practioner - axios - .get('/doctors?search=&organization_id='+values.organization_id) - .then((response) => { - setDoctor(response.data.data); - - }) - .catch((error) => { - console.error(error); - }); - - // setMainDiagnosis - axios - .get(`corporates/${corporate_id}/diagnosis`) - .then((response) => { - setMainDiagnosis(response.data.data) - }) - - // setOrganization atau hospital atau location - axios - .get(`corporates/${corporate_id}/hospitals`) - .then((response) => { - setOrganization(response.data.data) - }) - } - - }, [claimHistoryId]) - - useEffect( () => { - reset(defaultValues); - }, [isEdit]) - - - const [openDialogHospitalCare, setOpenHospitalCare] = useState(false); - - const handleCloseDialogHospitalCare = () => { - setEdit(false) - setOpenHospitalCare(false); - setClaimHistoryId(null) - reset(); - } - - const [openDialogApproval, setOpenDialogApproval] = useState(false); - - const handleCloseDialogApprove = () => { - setOpenDialogApproval(false); - setEdit(false) - setClaimHistoryId(null); - reset(); - } - - /* Handle For Approve Claim */ - const handleApproveClaim = (id: number|null, claim_id: number|null) =>{ - // let data = { - // status: 1 - // } - // axios.post(`/claims/carehistory/${id}/approval`, data); - // setOpenDialogApproval(false) - // enqueueSnackbar( - // 'Claim Approve Successfully!', - // { variant: 'success' } - // ); - // window.location.reload(); - - const dataForm = { - status: 1, - claim_id: id - } - axios - .post(`/claims/carehistory/approval`, dataForm) - .then((response) => { - enqueueSnackbar('Claim Approve Successfully!', { variant: 'success' }); - setOpenDialogApproval(false); - window.location.reload(); - }) - .catch((error) => { - enqueueSnackbar('Something Went Wrong', { variant: 'error' }); - }) - - } - - // Handle Location Change - const handleLocationChange = (organization_id:number) => { - // if (newValue) { - const selectedValue = organization_id; - setValue('organization_id', selectedValue); - // let data = { - // ...values, - // practitioner_id: 0 - // } - // reset(data) - - axios - .get('/doctors?search=&organization_id=' + selectedValue) - .then((response) => { - setDoctor(response.data.data); - }) - .catch((error) => { - console.error(error); - }); - // } - } - - const handleDoctorChange = (event, newValue) => { - if (newValue) { - const selectedValue = newValue.id; - setValue('practitioner_id', selectedValue); - } - } - - const handleMainDiagnosisChange = (event, newValue) => { - if (newValue) { - const selectedValue = newValue.id; - setValue('main_diagnosis_id', selectedValue); - } - } - - const defaultValues = useMemo( - () => ({ - service_code: service_code, - secondary_diagnosis_id: [{ - value: { - name: "", - value: 0 - } - }], - admission_date: isEdit ? carehistory?.admission_date : '', - discharge_date: isEdit ? carehistory?.discharge_date : '', - organization_id: isEdit ? carehistory?.organization_id : '', - practitioner_id: isEdit ? carehistory?.practitioner_id : '', - medical_record_number: isEdit ? carehistory?.medical_record_number : '', - symptoms: isEdit ? carehistory?.symptoms : '', - sign: isEdit ? carehistory?.sign : '', - main_diagnosis_id: isEdit ? carehistory?.main_diagnosis_id : 0, - }), - [service_code] - ) - - let NewClaimHistoryCareSchema = Yup.object().shape({ - service_code: Yup.string().required('Name is required'), - // admission_date: Yup.date().required('Admisision Date is required'), - // discharge_date: Yup.date().required('Discharge Date is required'), - // organization_id: Yup.number().required('Location is required'), - // practitioner_id: Yup.number().required('Doctor is required'), - // medical_record_number: Yup.string().required('Medical Record is required'), - // symptoms: Yup.string().required('Symptoms is required'), - // sign: Yup.string().required('Sign is required'), - // main_diagnosis_id: Yup.number().required('Main Diagnosis is required'), - }); - - const methods = useForm({ - resolver: yupResolver(NewClaimHistoryCareSchema), - defaultValues, - }); - - const { - reset, - watch, - control, - setValue, - getValues, - setError, - handleSubmit, - resetField, - formState: { isSubmitting }, - } = methods; - - const values = watch(); - const valueOfLocation = organization.find((row) => row.organization_id === values.organization_id) - - const {fields, append, remove} = useFieldArray({name: "secondary_diagnosis_id", control}) - - const onSubmit = async (data: FormValuesProps) => { - if (isEdit){ - let newData = { - service_code: data.service_code, - admission_date: data.admission_date ? fDateOnly(data.admission_date) : null, - discharge_date: data.discharge_date ? fDateOnly(data.discharge_date) : null, - organization_id: data.organization_id, - practitioner_id: data.practitioner_id, - medical_record_number: data.medical_record_number, - symptoms: data.symptoms, - sign: data.sign, - secondary_diagnosis_id: data.secondary_diagnosis_id ? data.secondary_diagnosis_id.map((row) => row.value.id) : null, - main_diagnosis_id: data.main_diagnosis_id, - } - - const response:any = await axios.post(`/claims/carehistory/${claimHistoryId}/update`, newData); - // if (response.status == 'success'){ - setOpenHospitalCare(false) - enqueueSnackbar( - 'Claim Update Successfully!', - { variant: 'success' } - ); - navigate('/claims/detail/'+id); - window.location.reload(); - - // } - } else { - let newData = { - service_code: data.service_code, - admission_date: data.admission_date ? fDateOnly(data.admission_date) : null, - discharge_date: data.discharge_date ? fDateOnly(data.discharge_date) : null, - organization_id: data.organization_id, - practitioner_id: data.practitioner_id, - medical_record_number: data.medical_record_number, - symptoms: data.symptoms, - sign: data.sign, - secondary_diagnosis_id: data.secondary_diagnosis_id ? data.secondary_diagnosis_id.map((row) => row.value.id) : null, - main_diagnosis_id: data.main_diagnosis_id, - - } - - - const response:any = await axios.post(`/claims/${id}/carehistory`, newData); - // if (response.status == 'success'){ - setOpenHospitalCare(false) - enqueueSnackbar( - 'Claim Insert Successfully!', - { variant: 'success' } - ); - navigate('/claims/detail/'+id); - window.location.reload(); - // } - - } - - reset(); - } - - function secondaryDiagnosisOption() { - return fields.map((item, index) => { - return ( - - {`#${index+1}`} - - - opt.name} - isOptionEqualToValue={(opt, val) => opt.name === val.name} - label='Comparative Diagnosis (ICD-X)' - /> - - remove(index)}> - - - - - ) - }) - } - - function handleNewHospitalCare() { - setEdit(false); - setOpenHospitalCare(true); - reset(defaultValues); - } - - function handleEditHospitalCare(id: number) { - setClaimHistoryId(id); - setEdit(true); - setOpenHospitalCare(true); - reset(defaultValues); - } - - function handleUpdateHospitalCare(id: number) { - setOpenHospitalCare(false); - setClaimHistoryId(id); - setEdit(false); - setOpenDialogApproval(true); - } - - //Service - const [openDialogService, setOpenDialogService] = useState(false); - const handleCloseDialogService = () => { - setOpenDialogService(false); - } - const handleConditionChangeService = (event) => { - const selectedItem = event.target.value; - - if (valBenefitNames.includes(selectedItem)) { - // Item is already selected, remove it - setValBenefitNames(valBenefitNames.filter(item => item !== selectedItem)); - } else { - // Item is not selected, add it - setValBenefitNames([...valBenefitNames, selectedItem]); - } - }; - - //Data - const [serviceTypeData, setServiceTypeData] = useState(null); - const [benefitNameData, setBenefitNameData] = useState(null); - const [hospitalData, setHospitalData] = useState(null); - //Field - const currentDate = new Date(); - const formattedCurrentDate = format(currentDate, 'dd MMM yyyy'); - //Date Addmissions - const [dateAd, setDateAd] = useState(currentDate); - //Date Discharge - const [dateDis, setDateDis] = useState(currentDate); - //Service Type - const [valServiceType, setValServiceType] = useState(''); - const [valServiceTypeError, setValServiceTypeError] = useState(''); - //Benefit Name - const [valBenefitNames, setValBenefitNames] = useState([]); - const [valBenefitNameError, setValBenefitNameError] = useState(''); - //Hospital - const [valHospital, setValHospital] = useState(''); - const [valHospitalError, setValHospitalError] = useState(''); - //txt name - const [txtName, setTxtName] = useState('Add Service'); - //flag add or edit service - const [flagAddService, setFlagAddService] = useState('add'); - //id claim_services - const [idService, setIdService] = useState(null); - - - const isRequiredFieldsServiceType = () => { - return dateAd !== '' && dateDis !== '' && valServiceType !== '' && valBenefitNames.length > 0 && valHospital !== ''; - }; - - const getService = async () => { - try { - const response = await axios.get('/claims/get-services/' + id); - setServiceTypeData(response.data.data.service_type); - setValServiceType(response.data.data.service_type[0].id); - setBenefitNameData(response.data.data.benefit_name); - setHospitalData(response.data.data.hospital); - await Promise.all([ - setServiceTypeData(response.data.data.service_type), - setBenefitNameData(response.data.data.benefit_name), - setHospitalData(response.data.data.hospital), - ]); - - } catch (error) { - } - } - - - const handleAddService = async () => { - setTxtName('Add Service'); - setFlagAddService('add'); - setOpenDialogService(true); - } - - const handleEditService = async () => { - setDateAd(serviceData.addmission_date); - setDateDis(serviceData.discharge_date); - setIdService(serviceData.id); - - setOpenDialogService(true); - setTxtName('Edit Service'); - setFlagAddService('edit'); - - if (serviceTypeData) { - setValServiceType(serviceData.service_id); - setValHospital(serviceData.hospital_id); - setValBenefitNames(serviceBenefitData.benefit_id); - } - } - - const handelSaveServiceType = () => { - const dateAdd = dateAd ? fPostFormat(dateAd, 'yyyy-MM-dd') : null; - const dateDisc = dateDis ? fPostFormat(dateDis, 'yyyy-MM-dd') : null; - const data = { - flagAddService : flagAddService, - idService: idService, - claim_request_id: id, - dateAdd : dateAdd, - dateDisc : dateDisc, - serviceType : valServiceType, - benefitName : valBenefitNames, - hospital : valHospital - }; - axios - .post('/claims/save-services', data) - .then((response) => { - enqueueSnackbar('Success '+(flagAddService == 'add' ? 'Add' : 'Edit')+' Service', { variant: 'success' }); - handleCloseDialogService(); - window.location.reload(); - }) - .catch((error) => { - enqueueSnackbar('Something Went Wrong', { variant: 'error' }); - }) - } - - const [openDialogSubmit, setOpenDialogSubmit] = useState(false); const handleCloseDialogSubmit = () => { setOpenDialogSubmit(false); } @@ -640,12 +105,17 @@ export default function Detail() { const handleSubmitData = () => { //approve or decline + if(!reasonDecline && approve == 'decline') + { + enqueueSnackbar('Mohon isi alasan', { variant: 'warning' }); + return false; + } axios - .post('claims/'+id+'/'+decline) + .post('claims/'+id_claim+'/'+approve, {reasonDecline:reasonDecline}) .then((response) => { - enqueueSnackbar('Success '+toTitleCase(decline)+' Claim Request', { variant: 'success' }); + enqueueSnackbar('Success '+toTitleCase(approve)+' Claim Request', { variant: 'success' }); setOpenDialogSubmit(false); - window.location.reload(); + // window.location.reload(); }) .catch(({ response }) => { @@ -659,911 +129,590 @@ export default function Detail() { }; - const handelDownloadLog = () => { - axios - .get(`final-log/${id}`, { - responseType: 'blob', - }) - .then((response) => { - window.open(URL.createObjectURL(response.data)); - }) - .catch((response) => { - enqueueSnackbar(response.message, { variant: 'error' }); + function toTitleCase(str: string | null) { + return str.replace(/\w\S*/g, function(txt) { + return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); }); } + const [reasonDecline, setReasonDecline] = useState(''); + + const handleReasonDeclineChange = (event) => { + setReasonDecline(event.target.value); + // Tambahkan logika yang diperlukan di sini + }; + + const [openDialogSubmit, setOpenDialogSubmit] = useState(false); + const [openDialogEditDetail, setDialogDEditDetail] = useState(false); + const [openDialogBenefit, setDialogBenefit] = useState(false); + const [openDialogMedicine, setDialogMedicine] = useState(false); + + // Handel Delete Detail Benefit + const [idBenefitData, setIdBenefitData] = useState(); + const [openDialogDeleteBenefit, setDialogDeleteBenefit] = useState(false) + + const [idMedicineData, setIdMedicineData] = useState(); + const [openDialogDeleteMedicine, setDialogDeleteMedicine] = useState(false) + + const [approve, setApprove] = useState('') + + // Handle Edit Detail Benefit + const [openDialogEditBenefit, setDialogEditBenefit] = useState(false) + const [BenefitConfigurationData, setBenefitConfigurationData] = useState(); + + // Buat total data + const totalAmountIncurred = (requestLog?.benefit_data || []).reduce((accumulator, item) => { + return accumulator + (item.amount_incurred || 0); + }, 0); + const totalAmountApprove = (requestLog?.benefit_data || []).reduce((accumulator, item) => { + return accumulator + (item.amount_approved || 0); + }, 0); + const totalAmountNotApprove = (requestLog?.benefit_data || []).reduce((accumulator, item) => { + return accumulator + (item.amount_not_approved || 0); + }, 0); + const totalExcessPaid = (requestLog?.benefit_data || []).reduce((accumulator, item) => { + return accumulator + (item.excess_paid || 0); + }, 0); + + // Handle Delete File LOG + const [pathFile, setPathFile] = useState('') + const [dialogDeleteFIleLog, setDialogDeleteFileLog] = useState(false) + + // Handle Upload File LOG + const [dialogUploadFileLog, setDialogUploadFileLog] = useState(false) + return ( navigate(-1)} sx={{cursor:'pointer'}}/> - {(customerData && customerData.code ? customerData.code : '')} - {customerData ? ( - - - Status - {(customerData && customerData.status) ? toTitleCase(customerData.status) : ''} - - - Submission Date - {(customerData && customerData.submission_date) ? format(new Date(customerData.submission_date), "d MMM yyyy") : ''} - - - ) : ''} + {(requestLog && requestLog.code_claim ? requestLog.code_claim : '')} - {customerData ? ( + {/* Detail */} - - Summary of Customer Data - - Full Name - {customerData.name} - - - Policy Number - {customerData.payor_id} - - - Member ID - {customerData.member_id} - - - Claim Type - {toTitleCase(customerData.payment_type)} - - - Corporate Name - {toTitleCase(customerData.coporate_name)} - - - - ) : ''} - {documentData ? ( - - - {customerData?.status === 'received' ? ( - - Additional Documents - } sx={{marginLeft: 'auto'}} onClick={() => setOpenDialogRequest(true)}> - Request Document - - - ) : ''} - - {documentData?.map((documentType, index) => ( - - - {documentType.type === 'claim-diagnosis' ? - 'Diagnosis' - : documentType.type === 'claim-kondisi' ? - 'Condition' - : documentType.type === 'claim-result' ? - 'Supporting Result' - : documentType.type === 'claim-invoice' ? - 'Invoice' - : ''} - - - - - {documentType.original_name ? documentType.original_name : '-'} - - - - ))} - - {requestDocumentData && requestDocumentData.length > 0 ? ( - Request Documents - ) : ''} - - {requestDocumentData?.map((documentType, index) => ( - - - - - - {documentType.type === 'claim-diagnosis' ? - 'Diagnosis' - : documentType.type === 'claim-kondisi' ? - 'Condition' - : documentType.type === 'claim-result' ? - 'Supporting Result' - : documentType.type === 'claim-invoice' ? - 'Invoice' - : ''} - - - - ))} - - {/* Dialog Request Documents */} - - - - - Request Document - - - - - - - - - - } - label="Condition Document" - /> - } - label="Diagnosis Document" - /> - } - label="Supporting Result Document" - /> - - - Notes* + + + + + Detail - { - setNoteField(e.target.value); - setNoteFieldError(e.target.value.trim() === '' ? 'This field is required' : ''); - }} - fullWidth - inputProps={{ maxLength: 50 }} - error={!!noteFieldError} - helperText={noteFieldError} - /> - - - - Cancel - handelRequestDocument()}>Request - - - - - ): ''} - - - - - History of Hospital Care - {customerData?.status === 'received' ? ( - } sx={{marginLeft: 'auto'}} onClick={handleNewHospitalCare}> - History - - ) : ''} - - - - {currentClaimHistoryCare?.map((claimHistoryCare, index) => - claimHistoryCare.status === 0 ? ( - {/* Tambahkan key untuk setiap elemen dalam loop */} - - {customerData?.status === 'received' ? ( - - - {claimHistoryCare.service_code = 'OP' ? 'Outpatient' : 'Inpatient'} - - - handleEditHospitalCare(claimHistoryCare.id)}> - Edit - - handleUpdateHospitalCare(claimHistoryCare.id)}> - Update Status - - > - }/> - - ) : ''} - - Admission Date : - { fDate(claimHistoryCare.admission_date)} {/* Perbaikan typo di 'admission_date' */} - - - Discharge Date : - { fDate(claimHistoryCare.discharge_date)} - - - Location : - {toTitleCase(claimHistoryCare.organization?.name)} - - - Doctor : - {toTitleCase(claimHistoryCare.practitioner?.code)} - {claimHistoryCare.person?.name} - - - Status : - {claimHistoryCare.status == 0 ? 'Pending' : 'Approv'} - - - Diagnosis : - #{index+1} {claimHistoryCare.icd?.code} - {claimHistoryCare.icd?.name} - - - - ) : null - )} - - - {/* Dialog for input and update */} - - - - - {isEdit ? 'Update' : 'Add'} History of Hospital Care - - - - - - - - - - - - Service Code - - - Inpatient - Outpatient - - - - Admission Date* - - - - Discharge Date* - - - {/* Location */} - - Location* - { - return option.name ?? false - }} - isOptionEqualToValue={(option, value) =>{ - return option.organization_id == value.organization_id - }} - - onChange={(e, selectedOption) => { - if (selectedOption) { - const selectedOrganizationId = selectedOption.organization_id; - handleLocationChange(selectedOrganizationId); - } - }} - // value={organization.find(row => row.organization_id == values.organization_id)} - value={valueOfLocation ?? null} - - renderInput={(params) => ( - - )} - /> - - - {/* Dokter */} - - Doctor* - { - return option.name ?? false - }} - isOptionEqualToValue={(option, value) =>{ - return option.id === value.id - }} - - value={doctor.find(row => row.id == values.practitioner_id) ?? null} - - onChange={handleDoctorChange} - renderInput={(params) => ( - - )} - /> - - - - - Medical Record Number* - - - - Symptoms* - - - - Sign* - - - - Diagnosis* - - - {/* } sx={{marginLeft: 'auto'}} onClick={() => handleAddSecondaryDiagnosis()}> */} - } sx={{marginLeft: 'auto'}} onClick={() => append({value: {name: "", value: 0}})}> - Diagnosis - - - {/* Main Diagnosis */} - - { - return option.name ?? false - }} - isOptionEqualToValue={(option, value) =>{ - return option.id == value.main_diagnosis_id - }} - value={main_diagnosis.find(row => row.id == values.main_diagnosis_id) ?? null} - onChange={handleMainDiagnosisChange} - renderInput={(params) => ( - - )} - /> - - - - {secondaryDiagnosisOption()} - - - - - - - Cancel - - {isEdit ? 'Update' : 'Save'} - - - - - - - - - - - - {/* Dialog for approval */} - - - - - Add History of Hospital Care - - - - - - - - - - Are you sure to approve this hospital care ? - - - - - Admission Date - { carehistory ? fDate(carehistory?.admission_date) : '-'} - - - Discharge Date - {carehistory ? fDate(carehistory.discharge_date) : '-'} - - - Location - { carehistory ? carehistory.organization_name : '-'} - - - Doctor - {carehistory ? carehistory.practitioner_name : '-'} - - - Diagnosis - {carehistory ? carehistory?.main_diagnosis_name : '-'} - - - - - - Cancel - handleApproveClaim(carehistory?.id, carehistory?.claim_id)} > - Approve - - - - - - - - - - - - - - - - - - Diagnostic History - - - {currentClaimHistoryCare?.map((claimHistoryCare, index) => - claimHistoryCare.status === 1 ? ( - {/* Tambahkan key untuk setiap elemen dalam loop */} - - - - {claimHistoryCare.service_code = 'OP' ? 'Outpatient' : 'Inpatient'} - - - - Admission Date : - { fDate(claimHistoryCare.admission_date)} {/* Perbaikan typo di 'admission_date' */} - - - Discharge Date : - { fDate(claimHistoryCare.discharge_date)} - - - Location : - {toTitleCase(claimHistoryCare.organization?.name)} - - - Doctor : - {toTitleCase(claimHistoryCare.practitioner?.code)} - {claimHistoryCare.person?.name} - - - Status : - {claimHistoryCare.status == 0 ? 'Pending' : 'Approv'} - - - Diagnosis : - #{index+1} {claimHistoryCare.icd?.code} - {claimHistoryCare.icd?.name} - - - - ) : null - )} - - - - - - - Diagnosis Summary - - - {currentClaimHistoryCare?.map((claimHistoryCare, index) => - claimHistoryCare.status === 1 ? ( - {/* Tambahkan key untuk setiap elemen dalam loop */} - - - Symtomps : - { claimHistoryCare.symptoms} {/* Perbaikan typo di 'admission_date' */} - - - Sign : - { claimHistoryCare.sign} - - - Main Diagnosis : - {claimHistoryCare.icd?.name} {claimHistoryCare.icd?.code} - - - {/* {claimHistoryCare.comparative_diagnosis?.map((comparativeDiagnosis, i) => - ( - - {i == 0 ? 'Comparative Diagnosis :' : ''} - {comparativeDiagnosis.icd?.name} {comparativeDiagnosis.icd?.code} - - ) - )} */} - - {claimHistoryCare.comparative_diagnosis && claimHistoryCare.comparative_diagnosis.length > 0 && ( - claimHistoryCare.comparative_diagnosis.map((comparativeDiagnosis, i) => ( - - - {i === 0 ? 'Comparative Diagnosis :' : ''} - - - {comparativeDiagnosis.icd?.name} {comparativeDiagnosis.icd?.code} - - - )) - )} - - - - - ) : null - )} - - - - - - - Service - {!serviceData && customerData?.status === 'received' ? ( - } sx={{marginLeft: 'auto'}} onClick={() => handleAddService()}> - Service - - ) : ( - - {customerData?.status === 'received' ? ( - - handleEditService()}> - - Edit - - > - } - /> - ) : ''} - - )} - - {serviceData ? ( - <> - - Admission Date - {serviceData && serviceData.addmission_date ? fDateTime(serviceData.addmission_date) : ''} - - - Discharge Date - {serviceData && serviceData.discharge_date ? fDateTime(serviceData.discharge_date) : ''} - - - Serice Type - {serviceData && serviceData.name_services ? serviceData.name_services : ''} - - - Benefit Name - {serviceBenefitData && serviceBenefitData.name_benefits ? serviceBenefitData.name_benefits : ''} - - - Hospital - {serviceData && serviceData.name_hospitals ? serviceData.name_hospitals : ''} - - > - ): ''} - - {/* Dialog Service */} - - - - - {txtName} - - - - - - - - - - - - Admission Date* - - - { - setDateAd(newValue); - }} - inputFormat="dd MMM yyyy" - renderInput={(params) => } - /> - - - - - Discharge Date* - - - { - setDateDis(newValue); - }} - inputFormat="dd MMM yyyy" - renderInput={(params) => } - /> - - - - - - Service Type* - - - Service Type - - { - setValServiceType(e.target.value); - setValServiceTypeError(e.target.value === '' ? 'This field is required' : ''); - }} - disabled - - > - {serviceTypeData?.map((item, index) => ( - {item.name} - ))} - - {valServiceTypeError} - - - - - - Benefit Name* - - - Benefit Name - - { - setValBenefitNameError(!valBenefitNames ? 'At least one item must be selected' : ''); - }} - renderValue={(selected) => selected.map(value => { - const selectedOption = benefitNameData.find(option => String(option.id) === value); - return selectedOption ? selectedOption.description : ''; - }).join(', ')} - > - {benefitNameData?.map((item, index) => ( - - - } - label={item.description} - /> - - ))} - - {valBenefitNameError} - - - - - - Hospital* - - - Hospital - - { - setValHospital(e.target.value); - setValHospitalError(e.target.value === '' ? 'This field is required' : ''); - }} - - > - {hospitalData?.map((item, index) => ( - {item.name} - ))} - - {valHospitalError} - - - - - - - Cancel - handelSaveServiceType()}>Save - - - - - - - - {/* title */} - - Client Benefit Configuration - - {/* no benefit selected */} - { - false - ? - ( - - Tidak ada benefit yang dipilih - - ) - : - ( - - - - ) - } + {/* {requestLog?.status_final_log != 'requested' ? ( + + + { + setDialogDEditDetail(true) + }}> + + Edit + + > + } + /> + ) : null } */} + + + Provider + {requestLog?.provider} + + + Member ID + {requestLog?.member_id} + + + Policy Number + {requestLog?.policy_number} + + + Name + {requestLog?.name} + + + Date Of Birth + {requestLog?.date_of_birth ? fDate(requestLog?.date_of_birth) : '-'} + + + Marital Status + {requestLog?.marital_status} + + + Submission Date + {requestLog?.submission_date ? fDateTimesecond(requestLog?.submission_date) : '-'} + + + Admission Date + {requestLog?.admission_date ? fDateTimesecond(requestLog?.admission_date) : '-'} + + + + Discharge Date + {requestLog?.discharge_date ? fDateTimesecond(requestLog?.discharge_date) : '-'} + + + + No KTP + {requestLog?.no_identitas ? requestLog?.no_identitas : '-'} + + + Keterangan + {requestLog?.keterangan ? requestLog?.keterangan : '-'} + + + Hak Kamar Pasien + {requestLog?.hak_kamar_pasien ? requestLog?.hak_kamar_pasien : '-'} + + + Penempatan Kamar + {requestLog?.penempatan_kamar ? requestLog?.penempatan_kamar : '-'} + + + Catatan + {requestLog?.catatan ? requestLog?.catatan : '-'} + + + Diagnosis + + {requestLog?.diagnosis?.length > 0 ? ( + + {requestLog.diagnosis.map((diagnosisItem, index) => ( + {diagnosisItem.code} - {diagnosisItem.name} + // Replace 'name' with the property you want to display + ))} + + ) : ( + No diagnosis available. + )} + + + {/* */} - - - <> - {(customerData && customerData.status === 'received') ? ( - <> - { - setOpenDialogSubmit(true); - setDeclaine('decline'); - }} - > - Decline - - { - setOpenDialogSubmit(true); - setDeclaine('approve'); - }} - > - Approve - - > - ) : ( - <> - - - Download Final LOG - - { - setOpenDialogSubmit(true); - setDeclaine('re-open'); - }} - > - Re-Open - - - > - ) } - > - {/* Dialog Submits */} - - - - - Confirmation - - - - - - - - {dataDialog ? ( - - Are you sure to {toTitleCase(decline)} this claim ? - - - Code - {dataDialog.code} - - - Name - {dataDialog.name} - - - Date Submission - {fDateTime(dataDialog.submission_date)} - - - Claim Method - Service Type - - - Service Type - - {dataDialog.service_code === 'IP' ? 'Inpatient' : 'Outpatient'} - - - - - ) : ''} - - - Cancel - {(decline === "decline" ? 'Decline' : (decline === "approve" ? 'Approve' : 'Re-Open'))} - - - + {/* Service */} + + {/* + */} + + {/* Exclusion */} + + {/* + */} + + + {/* Benefit */} + + + + Benefit + + + + {requestLog?.benefit_data?.map((item, index) => ( + + + + + + + {item.benefit?.description} + + + {/* + + { + setDialogEditBenefit(true) + setIdBenefitData(item.id) + setBenefitConfigurationData(item) + }} + > + + Edit + + { + setIdBenefitData(item.id) + setDialogDeleteBenefit(true) + }} + > + + Delete + + > + } /> + */} + + + + + + + {/* Amount Incurred */} + + + + + Amount Incurred + + + + + {fNumber(item.amount_incurred)} + + + + + + {/* Amount Approved */} + + + + + Amount Approved + + + + + {fNumber(item.amount_approved)} + + + + + + {/* Amount Not Approved */} + + + + + Amount Not Approved + + + + + {fNumber(item.amount_not_approved)} + + + + + + {/* Excess Paid* */} + + + + + Excess Paid* + + + + + {fNumber(item.excess_paid)} + + + + + + {/* Keterangan* */} + + + + + Keterangan* + + + + + {item.keterangan} + + + + + + + + + + + + ))} + + + {requestLog?.benefit_data && requestLog.benefit_data.length > 0 ? ( + + + + + + + Total Benefit + + + + + + + + + + {/* Amount Incurred */} + + + + + Amount Incurred + + + + + {fNumber(totalAmountIncurred)} + + + + + + {/* Amount Approved */} + + + + + Amount Approved + + + + + {fNumber(totalAmountApprove)} + + + + + + {/* Amount Not Approved */} + + + + + Amount Not Approved + + + + + {fNumber(totalAmountNotApprove)} + + + + + + {/* Excess Paid* */} + + + + + Excess Paid + + + + + {fNumber(totalExcessPaid)} + + + + + + + + + + + ) + : ( + null + )} + + + {/* PR Buat pindahin ke componen */} + {/* + + */} + + + + {/* Medicine */} + + + + Medicine + + + + {requestLog?.medicine.map((item, index) => ( + + {item.medicine} + Rp. {fNumber(item.price)} + { + setIdMedicineData(item.id) + setDialogDeleteMedicine(true) + }}> + + + + + ))} + + + + + + {/* File */} + + + + + Files + + + + + + {requestLog?.files?.map((documentType, index) => ( + + + + {documentType.original_name ? documentType.original_name : '-'} + + + + + + + ))} + + + + + + {statusClaim == 'received' ? ( + + + + <> + + { + setOpenDialogSubmit(true); + setApprove('decline'); + }} + > + Decline + + + + { + setOpenDialogSubmit(true); + setApprove('approve'); + }} + > + Approve + + + > + + + {/* Dialog Submits */} + + + + + Confirmation + + + + + + + + + + Are you sure to {toTitleCase(approve)} this claim ? + + + Code + {dataMember?.code} + + + Name + {dataMember?.name} + + + Date Submission + {dataMember?.created_at ? fDateTime(dataMember?.created_at) : ''} + + + Claim Method + Service Type + + + Service Type + + {dataMember?.service_type} + + + {approve == "decline" ? ( + + + + ): ''} + + + + + Cancel + {(approve === "decline" ? 'Decline' : 'Approve')} + + + + + ) : null} + ); -} +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/Claims/Index.tsx b/frontend/dashboard/src/pages/Claims/Index.tsx index 5fc6d983..78214d1e 100644 --- a/frontend/dashboard/src/pages/Claims/Index.tsx +++ b/frontend/dashboard/src/pages/Claims/Index.tsx @@ -7,7 +7,7 @@ import List from "./List"; export default function Claims() { - const pageTitle = 'Claim'; + const pageTitle = 'Claim Management'; return ( @@ -16,7 +16,7 @@ export default function Claims() { links={[ { name: 'Dashboard', href: '/dashboard' }, { - name: 'Claim', + name: 'Claim Management', href: '/claims', }, ]} diff --git a/frontend/dashboard/src/pages/Claims/List.tsx b/frontend/dashboard/src/pages/Claims/List.tsx index 5e1d01fd..5de5511c 100644 --- a/frontend/dashboard/src/pages/Claims/List.tsx +++ b/frontend/dashboard/src/pages/Claims/List.tsx @@ -1,6 +1,7 @@ // @mui import { Box, + Grid, Button, Card, Collapse, @@ -17,12 +18,24 @@ import { ButtonGroup, Tooltip, TableHead, + Checkbox, + InputAdornment, + TableSortLabel, + FormControl } from '@mui/material'; +import { visuallyHidden } from '@mui/utils'; + +import { DesktopDatePicker, LocalizationProvider } from '@mui/x-date-pickers'; +import { fDateOnly } from '@/utils/formatTime'; + +import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; import FindInPageOutlinedIcon from '@mui/icons-material/FindInPageOutlined'; import AssessmentIcon from '@mui/icons-material/Assessment'; // hooks import React, { ChangeEvent, useEffect, useRef, useState } from 'react'; import { Link, Navigate, useNavigate, useSearchParams } from 'react-router-dom'; + +import { LoadingButton } from '@mui/lab'; // components import axios from '../../utils/axios'; import { LaravelPaginatedData, LaravelPaginatedDataDefault } from '../../@types/paginated-data'; @@ -32,23 +45,146 @@ import EditRoundedIcon from '@mui/icons-material/EditRounded'; import { Chip } from '@mui/material'; import Iconify from '@/components/Iconify'; import { enqueueSnackbar } from 'notistack'; -import { fDate } from '../../utils/formatTime'; +import { fDate, fDateTime } from '../../utils/formatTime'; import { Claims } from '@/@types/claims'; import Label from '@/components/Label'; import { capitalizeFirstLetter } from '@/utils/formatString'; import TableMoreMenu from '@/components/table/TableMoreMenu'; import Edit from '@mui/icons-material/Edit'; import { Download } from '@mui/icons-material'; +import { Add, Search } from '@mui/icons-material'; +import Autocomplete from '@mui/material/Autocomplete'; + +import DownloadIcon from '@mui/icons-material/Download'; + +import UploadIcon from '@mui/icons-material/Upload'; +import CancelIcon from '@mui/icons-material/Cancel'; +import CheckCircleIcon from '@mui/icons-material/CheckCircle'; + +import { Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material'; +import CloseIcon from '@mui/icons-material/Close'; + export default function List() { + const [selectAll, setSelectAll] = useState(false); + const [selectedRows, setSelectedRows] = useState([]); + const [providers, setProviders] = useState(null); + // const [searchText, setSearchText] = useState(''); + const [order, setOrder] = useState('desc'); + const [orderBy, setOrderBy] = useState('created_at'); + const [perPage, setPerPage] = useState(0); + + const handleChange = (event, newValue) => { + // Jika newValue tidak undefined, atur nilai dataProvider + if (newValue !== undefined) { + setDataProvider(newValue.service_code); + } else { + // Jika tidak ada yang dipilih, set dataProvider menjadi string kosong + setDataProvider(null); + } + }; + // Dummy data +const dummyServices = [ + { service_code: '1', name: 'Service 1' }, + { service_code: '2', name: 'Service 2' }, + { service_code: '3', name: 'Service 3' }, + // tambahkan data lain sesuai kebutuhan +]; + + + + const handleSelectAll = () => { + setSelectAll(!selectAll); + if (!selectAll) { + const requestedIds = dataTableData.data + .filter(row => row.status === 'received') // Memfilter baris dengan status 'requested' + .map(row => row.id); // Mengambil hanya ID dari baris-baris yang memenuhi kondisi + setSelectedRows(requestedIds); + } else { + setSelectedRows([]); + } + }; + + const handleRowSelect = (id) => { + if (selectedRows.includes(id)) { + setSelectedRows(selectedRows.filter(rowId => rowId !== id)); + } else { + setSelectedRows([...selectedRows, id]); + } + }; + const [searchParams, setSearchParams] = useSearchParams(); - const [importResult, setImportResult] = useState(null); + const [startDate, setStartDate] = useState(null); + const [searchText, setSearchText] = useState(''); + const [endDate, setEndDate] = useState(null); const navigate = useNavigate(); + const [dataProvider, setDataProvider] = useState(null); + + useEffect(() => { + if (startDate !== null || endDate !== null || dataProvider !== null + || order !== null || orderBy !== null || perPage !== 0) { + loadDataTableData(); + getProvider(); + } + }, [startDate, endDate, dataProvider, order, orderBy, perPage]); + + const [isLoading, setIsLoading] = useState(false); + const [isLoadingImport, setIsLoadingImport] = useState(false); + const handleExportReport = async () => { + + + const year = startDate?.getFullYear(); + const month = (startDate?.getMonth() + 1).toString().padStart(2, '0'); // Tambahkan 1 karena bulan dimulai dari 0, dan padStart untuk memastikan 2 digit + const day = startDate?.getDate().toString().padStart(2, '0'); // padStart untuk memastikan 2 digit + + const formattedDate = year && month && day ? `${year}-${month}-${day}` : ''; + + const year1 = endDate?.getFullYear(); + const month1 = (endDate?.getMonth() + 1).toString().padStart(2, '0'); // Tambahkan 1 karena bulan dimulai dari 0, dan padStart untuk memastikan 2 digit + const day1 = endDate?.getDate().toString().padStart(2, '0'); // padStart untuk memastikan 2 digit + + const formattedDate1 = year1 && month1 && day1 ? `${year1}-${month1}-${day1}` : ''; + + + + var filter = Object.fromEntries([...searchParams.entries()]); + setIsLoading(true) + await axios + .get('/claims/export-claim-management',{ + params: { + search: searchText, + start_date: formattedDate ? formattedDate : null, + end_date:formattedDate1, + provider: dataProvider, + order: order, + orderBy: orderBy, + page: perPage, + } + }) + .then((res) => { + enqueueSnackbar('Data berhasil di Export', { + variant: 'success', + anchorOrigin: { horizontal: 'right', vertical: 'top' }, + }); + setIsLoading(false) + + document.location.href = res.data.data.file_url; + }) + .catch((err) => + enqueueSnackbar('Data Gagal di Export', { + variant: 'error', + anchorOrigin: { horizontal: 'right', vertical: 'top' }, + }) + + ); + }; + function SearchInput(props: any) { // SEARCH const searchInput = useRef(null); - const [searchText, setSearchText] = useState(''); + + const handleSearchChange = (event: any) => { const newSearchText = event.target.value ?? ''; @@ -73,7 +209,7 @@ export default function List() { useEffect(() => { // Trigger First Search - setSearchText(searchParams.get('search') ?? ''); + // setSearchText(searchParams.get('search') ?? ''); }, []); return ( @@ -126,41 +262,331 @@ export default function List() { ); } + const searchInput = useRef(null); + + + //handle search + const handleSearchChange = (event: any) => { + const newSearchText = event.target.value ?? ''; + setSearchText(newSearchText); + }; + + const handleSearchSubmit = (event: any) => { + event.preventDefault(); + loadDataTableData(); + }; + + + + useEffect(() => { + // Trigger First Search + //setSearchText(searchText); + }, []); + + const item = [ + { + id: '', + value: '', + name: 'Semua', + }, + ]; + + // const handleClick = () => { + + // } + + + // Dummy Default Data const [dataTableIsLoading, setDataTableLoading] = useState(true); const [dataTableData, setDataTableData] = useState( LaravelPaginatedDataDefault ); + + const loadDataTableData = async (appliedFilter: any | null = null) => { setDataTableLoading(true); + const year = startDate?.getFullYear(); + const month = (startDate?.getMonth() + 1).toString().padStart(2, '0'); // Tambahkan 1 karena bulan dimulai dari 0, dan padStart untuk memastikan 2 digit + const day = startDate?.getDate().toString().padStart(2, '0'); // padStart untuk memastikan 2 digit + + const formattedDate = year && month && day ? `${year}-${month}-${day}` : ''; + + const year1 = endDate?.getFullYear(); + const month1 = (endDate?.getMonth() + 1).toString().padStart(2, '0'); // Tambahkan 1 karena bulan dimulai dari 0, dan padStart untuk memastikan 2 digit + const day1 = endDate?.getDate().toString().padStart(2, '0'); // padStart untuk memastikan 2 digit + + const formattedDate1 = year1 && month1 && day1 ? `${year1}-${month1}-${day1}` : ''; + const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]); - const response = await axios.get('/claims', { params: filter }); - // console.log(response.data); + const response = await axios.get('/claims', { + params: { + search: searchText, + start_date: formattedDate ? formattedDate : null, + end_date:formattedDate1, + provider: dataProvider, + order: order, + orderBy: orderBy, + page: perPage, + } + }); + setDataTableLoading(false); setDataTableData(response.data); }; + const getProvider = async () => { + const response = await axios.get('/claims/get-provider'); + setProviders(response.data) + } + const applyFilter = async (searchFilter: { search: string }) => { await loadDataTableData(searchFilter); setSearchParams(searchFilter); }; - + const handlePageChange = (event: ChangeEvent, value: number): void => { - const filter = Object.fromEntries([...searchParams.entries(), ['page', value]]); - loadDataTableData(filter); - setSearchParams(filter); + setPerPage(value); }; - useEffect(() => { - loadDataTableData(); - }, []); + const [openDialogSubmit, setOpenDialogSubmit] = useState(false); + const handleCloseDialogSubmit = () => { + setOpenDialogSubmit(false); + } + + function toTitleCase(str: string | null) { + return str.replace(/\w\S*/g, function(txt) { + return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); + }); + } + + const [approve, setApprove] = useState(''); + + const [reasonDecline, setReasonDecline] = useState(''); + + const handleReasonDeclineChange = (event) => { + setReasonDecline(event.target.value); + // Tambahkan logika yang diperlukan di sini + }; + + const handleSubmitData = () => { + //approve or decline + if (!reasonDecline && approve == 'decline') { + enqueueSnackbar('Mohon isi alasan', { variant: 'warning' }); + return false; + } + Promise.all(selectedRows.map(send_bulk)) + .then(() => { + enqueueSnackbar('All requests processed successfully', { variant: 'success' }); + setOpenDialogSubmit(false); + setTimeout(() => { + window.location.reload(); + }, 5000); // Reload the page after 5 seconds + }) + .catch((error) => { + enqueueSnackbar(error.response?.data?.message ?? 'Something went wrong!', { variant: 'error' }); + }); + }; + + function send_bulk(id) { + return axios.post(`claims/${id}/${approve}`, { reasonDecline: reasonDecline }); + } + + + const [anchorEl, setAnchorEl] = React.useState(null); + const createMenu = Boolean(anchorEl); + const importHospital = useRef(null); + const [currentImportFileName, setCurrentImportFileName] = useState(null); + const [importLoading, setImportLoading] = useState(false); + const [importResult, setImportResult] = useState(null); + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + const handleClose = () => { + setAnchorEl(null); + }; + const handleImportButton = () => { + if (importHospital?.current) { + handleClose(); + importHospital.current ? importHospital.current.click() : console.log('No File selected'); + } else { + alert('No file selected'); + } + }; + const handleCancelImportButton = () => { + if(importHospital.current) + { + importHospital.current.value = ''; + importHospital.current.dispatchEvent(new Event('change', { bubbles: true })); + } +}; + const handleImportChange = (event: any) => { + if (event.target.files[0]) { + setCurrentImportFileName(event.target.files[0].name); + } else { + setCurrentImportFileName(null); + } + }; + const handleUpload = () => { + if(importHospital.current && importHospital.current.files) + { + if (importHospital.current?.files.length) { + const formData = new FormData(); + formData.append('file', importHospital.current?.files[0]); + setImportLoading(true); + axios + .post('claims/import', formData) + .then((response) => { + handleCancelImportButton(); + loadDataTableData(); + setImportResult(response.data); + setImportLoading(false); + enqueueSnackbar('Success Import Hospitals', { variant: 'success' }); + }) + .catch((response) => { + enqueueSnackbar( + 'Looks like something went wrong. Please check your data and try again. ' + + response.message, + { variant: 'error' } + ); + setImportLoading(false); + }); + } else { + enqueueSnackbar('No File Selected', { variant: 'warning' }); + } + } +}; + const handleGetTemplate = () => { + axios.get('claims/download-template').then((response) => { + const link = document.createElement('a'); + link.href = response.data.data.file_url; + link.setAttribute('download', response.data.data.file_name); + document.body.appendChild(link); + link.click(); + handleClose(); + }); + + +}; + +const handleExportReportFiled = async () => { + + await axios + .post('claims/exportFiled', { params: importResult?.data.failed_rows }) + .then((res) => { + enqueueSnackbar('Data berhasil di Export', { + variant: 'success', + anchorOrigin: { horizontal: 'right', vertical: 'top' }, + }); + setIsLoading(false) + + document.location.href = res.data.data.file_url; + }) + .catch((err) => + enqueueSnackbar('Data Gagal di Export', { + variant: 'error', + anchorOrigin: { horizontal: 'right', vertical: 'top' }, + }) + + ); +}; + + + // useEffect(() => { + // loadDataTableData(); + // getProvider(); + // }, []); const headStyle = { fontWeight: 'bold', }; + const headCells = [ + { + id: 'code', + align: 'left', + label: 'Code', + isSort: true, + }, + { + id: 'name', + align: 'left', + label: 'Name', + isSort: false, + }, + { + id: 'member_id', + align: 'left', + label: 'Member ID', + isSort: false, + }, + { + id: 'created_at', + align: 'left', + label: 'Date Submission', + isSort: true, + }, + { + id: 'plan_code', + align: 'left', + label: 'Plan ID', + isSort: true, + }, + { + id: 'service_code', + align: 'left', + label: 'Service', + isSort: false, + }, + { + id: 'corporate_policies', + align: 'left', + label: 'Policy Number', + isSort: true, + }, + { + id: 'provider', + align: 'left', + label: 'Provider', + isSort: false, + }, + { + id: 'tot_bill', + align: 'left', + label: 'Total Billing', + isSort: false, + }, + { + id: 'status', + align: 'left', + label: 'Status', + isSort: false, + }, + { + id: 'action', + align: 'left', + label: '', + isSort: false, + }, + ]; + + const orders = { + order: order, + setOrder: setOrder, + orderBy: orderBy, + setOrderBy: setOrderBy, + }; + const createSortHandler = (property: string) => (event: React.MouseEvent) => { + handleRequestSort(event, property); + }; + const handleRequestSort = async (event: React.MouseEvent, property: string) => { + const isAsc = orders?.orderBy === property && orders?.order === 'asc'; + + orders?.setOrder(isAsc ? 'desc' : 'asc'); + orders?.setOrderBy(property); + }; // Called on every row to map the data to the columns function createData(data: Claims): Claims { return { @@ -171,10 +597,18 @@ export default function List() { { /* ------------------ TABLE ROW ------------------ */ } - function Row(props: { row: ReturnType }) { - const { row } = props; + function Row(props: { row: ReturnType, isSelected: boolean, onSelect: (id: string) => void }) { + const { row, isSelected, onSelect } = props; + // Memperbaiki destrukturisasi props + + const handleRowCheckboxChange = () => { + onSelect(row.id); // Panggil fungsi onSelect dari komponen induk dengan id baris saat checkbox di baris diklik + }; + const [open, setOpen] = React.useState(false); + const test = 1000; + return ( *': { borderBottom: 'unset' } }}> @@ -183,16 +617,22 @@ export default function List() { {open ? : } */} - {row.claim_request?.code} + + {row?.status == 'received' ? ( + + ):''} + + {row?.code} {/* {row.code} */} - {row.member?.current_plan?.code} - {row.member?.current_corporate?.payor_id} - {row.member?.current_corporate?.code} - {row.member?.current_corporate?.current_policy?.code} - {row.member?.member_id} - {row.benefit_desc} - - + {row?.name} + {row?.member_id} + {row?.created_at ? fDateTime(row?.created_at) : ''} + {row?.plan_code} + {row?.service_code} + {row?.corporate_policies} + {row?.provider} + Rp. {row?.tot_bill?.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".")} + {row.status == 'draft' && ({capitalizeFirstLetter(row.status)})} {row.status == 'requested' && ({capitalizeFirstLetter(row.status)})} {row.status == 'received' && ({capitalizeFirstLetter(row.status)})} @@ -202,18 +642,17 @@ export default function List() { {row.status == 'declined' && ({capitalizeFirstLetter(row.status)})} - - navigate(`/claims/edit/${row.id}`) }> - - Edit - - navigate('/claims/detail/'+row.id+'') }> - - Detail - - > - } /> + + + navigate('/claims/detail/'+row.id_log+'/'+row.id+'') }> + + Detail + + > + } /> + + @@ -236,40 +675,77 @@ export default function List() { /* ------------------ END TABLE ROW ------------------ */ } + + function TableContent() { return ( {/* ------------------ TABLE HEADER ------------------ */} - {/* */} - - Code - - - Plan ID - - - Payor ID - - - Corporate ID - - - Policy Number - - - Member ID - - - Benefit Desc - - - Status - - - - + {selectedRows.length > 0 ? ( + <> + + + + {selectedRows.length > 0 ? selectedRows.length : '0'} Selected + + + + + + + } onClick={() => {setOpenDialogSubmit(true); + setApprove('decline');}}> + Decline + + + + } onClick={() => {setOpenDialogSubmit(true); + setApprove('approve');}}> + Approve + + + + > + ) : ( + <> + + + + {headCells && + headCells.map((headCell, index) => ( + + {headCell.isSort ? ( + + {headCell.label} + {orders?.orderBy === headCell.id ? ( + + {orders.order === 'desc' ? 'sorted descending' : 'sorted ascending'} + + ) : null} + + ) : ( + headCell.label + )} + + ))} + > + + )} + + {/* ------------------ END TABLE HEADER ------------------ */} @@ -278,7 +754,7 @@ export default function List() { {dataTableIsLoading ? ( - + Loading @@ -286,7 +762,7 @@ export default function List() { ) : dataTableData.data.length === 0 ? ( - + No Data @@ -294,7 +770,7 @@ export default function List() { ) : ( {dataTableData.data.map((row) => ( - + ))} )} @@ -305,7 +781,212 @@ export default function List() { return ( - + + + + + + {!currentImportFileName && ( + <> + + { + if (event.key === 'Enter') { + handleSearchSubmit(event); + } + }} + InputProps={{ + startAdornment: ( + + + + ), + placeholder: 'Search Code or Name', + }} + /> + + + + { + + // loadDataTableData(); + setStartDate(value); + }} + renderInput={(params) => } + /> + + + + { + setEndDate(value); + }} + renderInput={(params) => ( + + )} + /> + + + + { + providers && ( + option.name || ''} + value={providers.find((item) => item.id === dataProvider) || null} + onChange={(event, value) => { + if (value) { + setDataProvider(value.id); + } else { + setDataProvider(null); + } + }} + renderInput={(params) => ( + + )} + /> + ) + } + + + + } + sx={{ p: 1.8 }} + loading={isLoadingImport} + onClick={handleClick} + > + + Import + + + + + Import + + { + handleGetTemplate(); + }} + > + Download Template + + + + + } + sx={{ p: 1.8 }} + onClick={handleExportReport} + loading={isLoading} + > + + Export + + + + + > + )} + {currentImportFileName && ( + + + + + {currentImportFileName ?? 'No File Selected'} + + + + + + + } + sx={{ p: 1.8 }} + onClick={handleUpload} + loading={importLoading} + > + Upload + + + + )} + {importResult && ( + + + Last Import Result :{' '} + + {importResult.data.total_success_row ?? 0} + {' '} + Row Processed,{' '} + + {importResult.data.total_failed_row} + {' '} + Failed + {/* {importResult.data.failed_rows.map((row, index) => ( + [Code={row.code ? row.code : 'Required'}] + ))} */} + Download Data Filed + + + )} + + + + } /> + + + + + Confirmation + + + + + + + + + + Are you sure to {toTitleCase(approve)} this claim ? + {approve == "decline" ? ( + + + + ): ''} + + + + Cancel + {(approve === "decline" ? 'Decline' : 'Approve')} + + ); } diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogBenefit.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogBenefit.tsx index c2e82765..b7855726 100644 --- a/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogBenefit.tsx +++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogBenefit.tsx @@ -145,51 +145,62 @@ export default function DialogBenefit({requestLog, setOpenDialog, openDialog, cl const methods = useForm({ resolver: yupResolver(validationSchema), - defaultValues + defaultValues, + reValidateMode: "onChange" }); let width = claimInput ? 2 : 2.36; - const {fields, append, remove} = useFieldArray({name: 'benefit_data',control: methods.control}); - const { handleSubmit, reset, watch, setValue, formState: { isDirty, isSubmitting, errors } } = methods - - // Buat total data - let totalAmountIncurred = (requestLog?.benefit_data || []).reduce((accumulator, item) => { - return accumulator + (item.amount_incurred || 0); - }, 0); - let totalAmountApproved = (requestLog?.benefit_data || []).reduce((accumulator, item) => { - return accumulator + (item.amount_approved || 0); - }, 0); - let totalAmountNotApproved = (requestLog?.benefit_data || []).reduce((accumulator, item) => { - return accumulator + (item.amount_not_approved || 0); - }, 0); - let totalExcessPaid = (requestLog?.benefit_data || []).reduce((accumulator, item) => { - return accumulator + (item.excess_paid || 0); - }, 0); + const {fields, append, remove} = useFieldArray({name: 'benefit_data',control: methods.control,}); + const { handleSubmit, reset, watch, setValue, setError, clearErrors, formState: { isDirty, isSubmitting, errors,isValid } } = methods + + const errorsExist = errors ? Object.keys(errors).length > 0 : false; + // Calculate const benefitData = watch('benefit_data'); - const [isDisableSave, setDisableSave] = useState(false) - - benefitData?.map((item, index) => { - totalAmountIncurred += parseFloat(item.amount_incurred); - totalAmountApproved += parseFloat(item.amount_approved); - totalAmountNotApproved += parseFloat(item.amount_not_approved); - totalExcessPaid += parseFloat(item.excess_paid); + const totalAll = () => { + let totalAmountIncurred = (requestLog?.benefit_data || []).reduce((accumulator, item) => { + return accumulator + (item.amount_incurred || 0); + }, 0); + let totalAmountApproved = (requestLog?.benefit_data || []).reduce((accumulator, item) => { + return accumulator + (item.amount_approved || 0); + }, 0); + let totalAmountNotApproved = (requestLog?.benefit_data || []).reduce((accumulator, item) => { + return accumulator + (item.amount_not_approved || 0); + }, 0); + let totalExcessPaid = (requestLog?.benefit_data || []).reduce((accumulator, item) => { + return accumulator + (item.excess_paid || 0); + }, 0); - if (totalAmountApproved != 0 && totalAmountIncurred != 0) { - if (totalAmountApproved > totalAmountIncurred){ - setValue(`benefit_data.${index}.amount_approved`, 0) - alert('Total Amount Approved tidak boleh lebih dari Total Incurred') - } - } + benefitData?.map((item, index) => { + totalAmountIncurred += parseFloat(item.amount_incurred); + totalAmountApproved += parseFloat(item.amount_approved); + totalAmountNotApproved += parseFloat(item.amount_not_approved); + totalExcessPaid += parseFloat(item.excess_paid); + }); + + return { + totalAmountIncurred, + totalAmountApproved, + totalAmountNotApproved, + totalExcessPaid + } + } + + const handleOnChangeNominal = (key) => { + if (totalAll().totalAmountApproved > totalAll().totalAmountIncurred){ + // setValue(`benefit_data.${key}.amount_approved`, 0); + setError(`benefit_data.${key}.amount_approved`, {message: 'Amount Approve tidak boleh lebih dari Amount Incurred'}); + } else { + clearErrors(`benefit_data.${key}.amount_approved`); + } + } - }); - // Submit Form // ===================================== const submitHandler = async (data: BenefitConfigurationListType) => { const mapData = data.benefit_data.map((item) => ({ ...item, - reason: item.reason.value + reason: item.reason ? item.reason.value : null })); const newData = { @@ -206,8 +217,6 @@ export default function DialogBenefit({requestLog, setOpenDialog, openDialog, cl } } - // Calculate - const getContent = () => !addBenefit ? ( @@ -281,6 +290,10 @@ export default function DialogBenefit({requestLog, setOpenDialog, openDialog, cl name={`benefit_data.${index}.amount_incurred`} placeholder='Amount Incurred' required + onChange={(event) => { + setValue(`benefit_data.${index}.amount_incurred`, event.target.value) + handleOnChangeNominal(index)} + } /> @@ -301,6 +314,10 @@ export default function DialogBenefit({requestLog, setOpenDialog, openDialog, cl name={`benefit_data.${index}.amount_approved`} placeholder='Amount Approved' required + onChange={(event) => { + setValue(`benefit_data.${index}.amount_approved`, event.target.value) + handleOnChangeNominal(index)} + } /> @@ -434,7 +451,7 @@ export default function DialogBenefit({requestLog, setOpenDialog, openDialog, cl - {fNumber(totalAmountIncurred)} + {fNumber(totalAll().totalAmountIncurred)} @@ -450,7 +467,7 @@ export default function DialogBenefit({requestLog, setOpenDialog, openDialog, cl - {fNumber(totalAmountApproved)} + {fNumber(totalAll().totalAmountApproved)} @@ -466,7 +483,7 @@ export default function DialogBenefit({requestLog, setOpenDialog, openDialog, cl - {fNumber(totalAmountNotApproved)} + {fNumber(totalAll().totalAmountNotApproved)} @@ -482,7 +499,7 @@ export default function DialogBenefit({requestLog, setOpenDialog, openDialog, cl - {fNumber(totalExcessPaid)} + {fNumber(totalAll().totalExcessPaid)} @@ -499,7 +516,7 @@ export default function DialogBenefit({requestLog, setOpenDialog, openDialog, cl Cancel - + Save diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogEditBenefit.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogEditBenefit.tsx index bbd99c7f..11f0b03f 100644 --- a/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogEditBenefit.tsx +++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogEditBenefit.tsx @@ -62,23 +62,36 @@ export default function DialogEditBenefit({id, data, setOpenDialog, openDialog, defaultValues }); - const { handleSubmit, reset, watch, setValue, formState: { isDirty, isSubmitting, errors } } = methods; + const { handleSubmit, reset, watch, setValue, setError, clearErrors, formState: { isDirty, isSubmitting, errors } } = methods; + const errorsExist = errors ? Object.keys(errors).length > 0 : false; + const totalAll = () => { + // Ambil nilai dari form menggunakan watch + const amountIncurred = parseFloat(watch('amount_incurred')); + const amountApproved = parseFloat(watch('amount_approved')); + const amountNotApproved = parseFloat(watch('amount_not_approved')); + const excessPaid = parseFloat(watch('excess_paid')); + + // Hitung total baru + const totalAmountIncurred = total.totalAmountIncurred - data?.amount_incurred + amountIncurred; + const totalAmountApproved = total.totalAmountApproved - data?.amount_approved + amountApproved; + const totalAmountNotApproved = total.totalAmountNotApproved - data?.amount_not_approved + amountNotApproved; + const totalExcessPaid = total.totalExcessPaid - data?.excess_paid + excessPaid; - // Ambil nilai dari form menggunakan watch - const amountIncurred = parseFloat(watch('amount_incurred')); - const amountApproved = parseFloat(watch('amount_approved')); - const amountNotApproved = parseFloat(watch('amount_not_approved')); - const excessPaid = parseFloat(watch('excess_paid')); + return { + totalAmountIncurred, + totalAmountApproved, + totalAmountNotApproved, + totalExcessPaid + } + } - // Hitung total baru - const totalAmountIncurred = total.totalAmountIncurred - data?.amount_incurred + amountIncurred; - const totalAmountApproved = total.totalAmountApproved - data?.amount_approved + amountApproved; - const totalAmountNotApproved = total.totalAmountNotApproved - data?.amount_not_approved + amountNotApproved; - const totalExcessPaid = total.totalExcessPaid - data?.excess_paid + excessPaid; - - if (totalAmountApproved > totalAmountIncurred) { - alert('Total Approve tidak boleh melebihi Total Incurred') - setValue('amount_approved', data?.amount_approved) + const handleOnChangeNominal = (key) => { + if (totalAll().totalAmountApproved > totalAll().totalAmountIncurred){ + // setValue(`benefit_data.${key}.amount_approved`, 0); + setError(`amount_approved`, {message: 'Amount Approve tidak boleh lebih dari Amount Incurred'}); + } else { + clearErrors(`amount_approved`); + } } // if (totalAmountIncurred !== (totalAmountApproved+totalAmountNotApproved)){ @@ -142,6 +155,10 @@ export default function DialogEditBenefit({id, data, setOpenDialog, openDialog, name={`amount_incurred`} placeholder='Amount Incurred' required + onChange={(event) => { + setValue(`amount_incurred`, event.target.value) + handleOnChangeNominal(id)} + } /> @@ -162,6 +179,10 @@ export default function DialogEditBenefit({id, data, setOpenDialog, openDialog, name={`amount_approved`} placeholder='Amount Approved' required + onChange={(event) => { + setValue(`amount_approved`, event.target.value) + handleOnChangeNominal(id)} + } /> @@ -275,7 +296,7 @@ export default function DialogEditBenefit({id, data, setOpenDialog, openDialog, - {totalAmountIncurred ? fNumber(totalAmountIncurred) : 0} + {totalAll().totalAmountIncurred ? fNumber(totalAll().totalAmountIncurred) : 0} @@ -291,7 +312,7 @@ export default function DialogEditBenefit({id, data, setOpenDialog, openDialog, - {fNumber(totalAmountApproved)} + {totalAll().totalAmountApproved ? fNumber(totalAll().totalAmountApproved) : 0} @@ -307,7 +328,7 @@ export default function DialogEditBenefit({id, data, setOpenDialog, openDialog, - {fNumber(totalAmountNotApproved)} + {totalAll().totalAmountNotApproved ? fNumber(totalAll().totalAmountNotApproved) : 0} @@ -323,7 +344,7 @@ export default function DialogEditBenefit({id, data, setOpenDialog, openDialog, - {fNumber(totalExcessPaid)} + {totalAll().totalExcessPaid ? fNumber(totalAll().totalExcessPaid) : 0} @@ -337,7 +358,7 @@ export default function DialogEditBenefit({id, data, setOpenDialog, openDialog, Cancel - + Save diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/Detail.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/Detail.tsx index 7ad82656..6a4471ed 100644 --- a/frontend/dashboard/src/pages/CustomerService/FinalLog/Detail.tsx +++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/Detail.tsx @@ -68,6 +68,7 @@ export default function Detail() { const navigate = useNavigate(); const { themeStretch } = useSettings(); const [requestLog, setRequestLog] = useState(); + const [isReversal, setIsReversal] = useState(false); const { id } = useParams(); @@ -77,6 +78,7 @@ export default function Detail() { .get('customer-service/request/'+id) .then((response) => { setRequestLog(response.data.data) + setIsReversal(response.data.data.is_reversal) }) .catch((error) => { console.error(error); @@ -304,11 +306,15 @@ export default function Detail() { Benefit - } sx={{marginLeft: 'auto'}} onClick={() => { - setDialogBenefit(true); - }} > - Benefit - + { + !isReversal ? ( + } sx={{marginLeft: 'auto'}} onClick={() => { + setDialogBenefit(true); + }} > + Benefit + + ) : null + } {requestLog?.benefit_data?.map((item, index) => ( @@ -321,29 +327,33 @@ export default function Detail() { {item.benefit?.description} - - - { - setDialogEditBenefit(true) - setIdBenefitData(item.id) - setBenefitConfigurationData(item) - }} - > - - Edit - - { - setIdBenefitData(item.id) - setDialogDeleteBenefit(true) - }} - > - - Delete - - > - } /> - + { + !isReversal ? ( + + + { + setDialogEditBenefit(true) + setIdBenefitData(item.id) + setBenefitConfigurationData(item) + }} + > + + Edit + + { + setIdBenefitData(item.id) + setDialogDeleteBenefit(true) + }} + > + + Delete + + > + } /> + + ) : null + } @@ -619,13 +629,16 @@ export default function Detail() { Files - - } sx={{marginLeft: 'auto'}} onClick={() => { - setDialogUploadFileLog(true) - }} > - Files - - + { !isReversal ? ( + + } sx={{marginLeft: 'auto'}} onClick={() => { + setDialogUploadFileLog(true) + }} > + Files + + + ) : null } + {requestLog?.files?.map((documentType, index) => ( @@ -638,14 +651,17 @@ export default function Detail() { {documentType.original_name ? documentType.original_name : '-'} - - { - setDialogDeleteFileLog(true) - setPathFile(documentType.path) - }} aria-label="delete" size="small" sx={{ marginLeft: 'auto' }}> - - - + { !isReversal ? ( + + { + setDialogDeleteFileLog(true) + setPathFile(documentType.path) + }} aria-label="delete" size="small" sx={{ marginLeft: 'auto' }}> + + + + ) : null } + ))} diff --git a/frontend/dashboard/src/routes/index.tsx b/frontend/dashboard/src/routes/index.tsx index 0859ba78..23c0a50c 100644 --- a/frontend/dashboard/src/routes/index.tsx +++ b/frontend/dashboard/src/routes/index.tsx @@ -456,7 +456,7 @@ export default function Router() { element: , }, { - path: 'claims/detail/:id', + path: 'claims/detail/:id/:id_claim', element: , }, { diff --git a/frontend/hospital-portal/public/lang/en-US.json b/frontend/hospital-portal/public/lang/en-US.json index 8791f8a0..e11ef130 100644 --- a/frontend/hospital-portal/public/lang/en-US.json +++ b/frontend/hospital-portal/public/lang/en-US.json @@ -50,5 +50,14 @@ "txtNew" : "New", "txtBeforeThat" : "Before that", "txtDischargeDate" : "Discharge Date", - "txtPatner" : "Patner" + "txtPatner" : "Patner", + "txtSelected": "Selected", + "txtConfirmation": "Confirmation", + "txtReason": "Reason Decline", + "txtCancel": "Cancel", + "txtDecline": "Decline", + "txtApprove": "Approve", + "txtDialogConfirmation": "Are you sure you want to proceed with this action?", + "txtStartDate": "Start Date", + "txtEndDate": "End Date" } diff --git a/frontend/hospital-portal/public/lang/id-ID.json b/frontend/hospital-portal/public/lang/id-ID.json index 6f85bbb5..d3f59306 100644 --- a/frontend/hospital-portal/public/lang/id-ID.json +++ b/frontend/hospital-portal/public/lang/id-ID.json @@ -50,5 +50,14 @@ "txtNew" : "Baru", "txtBeforeThat" : "Sebelum", "txtDischargeDate" : "Tanggal Keluar", - "txtPatner" : "Rekanan" + "txtPatner" : "Rekanan", + "txtSelected": "Terpilih", + "txtConfirmation": "Konfirmasi", + "txtReason": "Alasan Penolakan", + "txtCancel": "Batal", + "txtDecline": "Tolak", + "txtApprove": "Terima", + "txtDialogConfirmation": "Apakah Anda yakin ingin melanjutkan tindakan ini?", + "txtStartDate": "Tanggal Mulai", + "txtEndDate": "Tanggal Akhir" } diff --git a/frontend/hospital-portal/src/components/Table.tsx b/frontend/hospital-portal/src/components/Table.tsx index a60bc862..7334e85b 100644 --- a/frontend/hospital-portal/src/components/Table.tsx +++ b/frontend/hospital-portal/src/components/Table.tsx @@ -13,6 +13,7 @@ import { TableSortLabel, Box, Card, + Checkbox, Grid, FormControl, InputLabel, @@ -25,6 +26,10 @@ import { linearProgressClasses, } from '@mui/material'; import { visuallyHidden } from '@mui/utils'; + +import { DatePicker, LocalizationProvider, MobileDatePicker } from '@mui/x-date-pickers'; + +import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; /* ---------------------------------- axios --------------------------------- */ import axios from '../utils/axios'; /* ---------------------------------- react --------------------------------- */ @@ -43,6 +48,8 @@ import { DivisionDataProps, Order, PaginationTableProps, TableListProps } from ' import { InputAdornment } from '@mui/material'; import GetAppIcon from '@mui/icons-material/GetApp'; import { LanguageContext } from '@/contexts/LanguageContext'; +import CancelIcon from '@mui/icons-material/Cancel'; +import CheckCircleIcon from '@mui/icons-material/CheckCircle'; /* --------------------------------- styled --------------------------------- */ const BorderLinearProgress = styled(LinearProgress)(({ theme }) => ({ @@ -71,6 +78,7 @@ export default function Table({ filterEndDate, searchs, exportReport, + selected, }: TableListProps) { /* ------------------------------- handle sort ------------------------------ */ const handleRequestSort = async (event: React.MouseEvent, property: string) => { @@ -98,34 +106,73 @@ export default function Table({ return ( - {headCells && - headCells.map((headCell, index) => ( - - {headCell.isSort ? ( - - {headCell.label} - {orders?.orderBy === headCell.id ? ( - - {orders.order === 'desc' ? 'sorted descending' : 'sorted ascending'} - - ) : null} - - ) : ( - headCell.label - )} + {selected.useSelected && selected.selectedRows.length > 0 ? ( + <> + + + + + + + {selected.selectedRows.length > 0 ? selected.selectedRows.length : '0'} {localeData.txtSelected} + + + + + + {selected.useDecline ? ( + } onClick={() => {selected.setOpenDialogSubmit(true);selected.setValDialog('decline');}}> + {selected.txtDecline} + + ):''} + } onClick={() => {selected.setOpenDialogSubmit(true);selected.setValDialog('approve');}}> + {selected.txtApprove} + + + + - ))} + > + ):( + <> + {selected.useSelected ? ( + + + + ):''} + {headCells && + headCells.map((headCell, index) => ( + + {headCell.isSort ? ( + + {headCell.label} + {orders?.orderBy === headCell.id ? ( + + {orders.order === 'desc' ? 'sorted descending' : 'sorted ascending'} + + ) : null} + + ) : ( + headCell.label + )} + + ))} + > + + )} + + ); @@ -162,7 +209,6 @@ export default function Table({ params.setAppliedParams(parameters); }; /* -------------------------------------------------------------------------- */ - return ( // @@ -255,7 +301,7 @@ export default function Table({ {/* Start date */} {filterStartDate && filterStartDate.useFilter ? ( - filterStartDate.handleStartDateChange(event)}> + {/* filterStartDate.handleStartDateChange(event)}> ({ shrink: true, }} /> - + */} + + { + filterStartDate.setStartDate( (newValue)); + }} + inputFormat="dd-MM-yyyy" + renderInput={(params) => } + /> + ) : null } @@ -275,7 +332,7 @@ export default function Table({ {filterEndDate && filterEndDate.useFilter ? ( - filterEndDate.handleEndDateChange(event)}> + {/* filterEndDate.handleEndDateChange(event)}> ({ shrink: true, }} /> - + */} + + { + filterEndDate.setEndDate( (newValue)); + }} + inputFormat="dd-MM-yyyy" + renderInput={(params) => } + /> + ) : null } @@ -349,6 +417,20 @@ export default function Table({ ) : rows && rows.length >= 1 ? ( rows.map((row, rowIndex) => ( + {!selected.useSelected ? ( + '' + ): (selected.useSelected && row.check_status === 'approved' && !row.check_claim ? ( + + selected.handleCheckboxChange(row.id)} + /> + + ):( + + + + ))} {headCells && //@ts-ignore headCells.map((head, headIndex) => ( diff --git a/frontend/hospital-portal/src/sections/claim/TableList.tsx b/frontend/hospital-portal/src/sections/claim/TableList.tsx index 61badfaf..17dcf2c4 100644 --- a/frontend/hospital-portal/src/sections/claim/TableList.tsx +++ b/frontend/hospital-portal/src/sections/claim/TableList.tsx @@ -118,6 +118,58 @@ export default function TableList() { /* -------------------------------------------------------------------------- */ + // ----------------------------------------- handle selected --------------------- + const [selectAll, setSelectAll] = useState(false); + const [selectedRows, setSelectedRows] = useState([]); + const [dataTableData, setDataTableData] = useState(); + const handleSelectAll = () => { + setSelectAll(!selectAll); + if (!selectAll) { + const requestedIds = dataTableData?.data + .filter((row: { status: string, check_claim:any }) => row.status === 'approved' && !row.check_claim) + .map((row: { id: any }) => row.id); + setSelectedRows(requestedIds); + } else { + setSelectedRows([]); + } + }; + + const handleCheckboxChange = (id: any) => { + setSelectedRows(prevSelectedRows => { + const isSelected = prevSelectedRows.includes(id); + if (isSelected) { + return prevSelectedRows.filter(rowId => rowId !== id); + } else { + return [...prevSelectedRows, id]; + } + }); + }; + + const [openDialogSubmit, setOpenDialogSubmit] = useState(false); + const handleCloseDialogSubmit = () => { + setOpenDialogSubmit(false); + } + const [valDialog, setValDialog] = useState(''); + const [reasonDecline, setReasonDecline] = useState(''); + const handleReasonDeclineChange = (event: { target: { value: SetStateAction; }; }) => { + setReasonDecline(event.target.value); +}; + + const selected = { + useSelected: false, + selectAll: selectAll, + handleSelectAll: handleSelectAll, + selectedRows: selectedRows, + handleCheckboxChange : handleCheckboxChange, + totRows: 9, + useDecline: false, + txtDecline: 'Decline', + useApprove:true, + txtApprove: 'Submit Claim', + setOpenDialogSubmit: setOpenDialogSubmit, + setValDialog: setValDialog + }; + /* ------------------------------ handle search ----------------------------- */ const [searchText, setSearchText] = useState(''); @@ -252,12 +304,12 @@ export default function TableList() { label: localeData.txtStatus, isSort: true, }, - { - id: 'action', - align: 'right', - label: '', - isSort: false, - }, + // { + // id: 'action', + // align: 'right', + // label: '', + // isSort: false, + // }, ]; @@ -280,6 +332,7 @@ export default function TableList() { const response = await axios.get(`/get-claim-requests`, { params: { ...parameters, type: 'final-log' }, }); + setDataTableData(response.data); setData( response.data.data.map((obj: any) => ({ ...obj, @@ -310,15 +363,15 @@ export default function TableList() { {obj.submission_date ? fDateSuffix(obj.submission_date) : ''} , - action: - - navigate ('/claim/detail/'+obj.claim_request_id)}> - - View - - > - } /> + // action: + // + // navigate ('/claim/detail/'+obj.claim_request_id)}> + // + // View + // + // > + // } /> })) ); @@ -357,6 +410,7 @@ export default function TableList() { params={params} searchs={searchs} filterStatus={filterStatus} + selected={selected} // filterStartDate={filterStartDate} // filterEndDate={filterEndDate} /> diff --git a/frontend/hospital-portal/src/sections/dashboard/DialogClaimSubmit.tsx b/frontend/hospital-portal/src/sections/dashboard/DialogClaimSubmit.tsx index 914fa652..538aeb81 100644 --- a/frontend/hospital-portal/src/sections/dashboard/DialogClaimSubmit.tsx +++ b/frontend/hospital-portal/src/sections/dashboard/DialogClaimSubmit.tsx @@ -76,7 +76,7 @@ export default function DialogClaimSubmit({ member, getData, onClose, handleSubm @@ -143,7 +143,7 @@ export default function DialogClaimSubmit({ member, getData, onClose, handleSubm style={{ display: 'none' }} multiple onChange={handleKondisiInputChange} - accept="application/pdf" + accept="application/pdf, image/*" /> diff --git a/frontend/hospital-portal/src/sections/dashboard/TableListFinalLog.tsx b/frontend/hospital-portal/src/sections/dashboard/TableListFinalLog.tsx index 010662dc..4473836f 100644 --- a/frontend/hospital-portal/src/sections/dashboard/TableListFinalLog.tsx +++ b/frontend/hospital-portal/src/sections/dashboard/TableListFinalLog.tsx @@ -1,11 +1,11 @@ /* ---------------------------------- @mui ---------------------------------- */ -import { Stack, Button, MenuItem, SelectChangeEvent, Tab, Tabs, Card, Box } from '@mui/material'; +import { Stack, Button, Checkbox, MenuItem, SelectChangeEvent, Tab, Tabs, Card, Box, IconButton, TextField } from '@mui/material'; /* ---------------------------------- axios --------------------------------- */ // import axios from 'axios'; import axios from '../../utils/axios'; import { styled } from '@mui/material/styles'; /* ---------------------------------- react --------------------------------- */ -import { useContext, useEffect, useState } from 'react'; +import { SetStateAction, useContext, useEffect, useState } from 'react'; /* -------------------------------- component ------------------------------- */ import Iconify from '../../components/Iconify'; @@ -30,6 +30,8 @@ import MuiDialog from '@/components/MuiDialog'; import DialogMember from './DialogMember'; import DialogClaimSubmit from './DialogClaimSubmit'; import { fPostFormat } from '@/utils/formatTime'; +import { Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material'; +import CloseIcon from '@mui/icons-material/Close'; export default function TableListFinalLog() { const navigate = useNavigate(); @@ -68,6 +70,7 @@ export default function TableListFinalLog() { return `${day}${month}${year}`; } + /* -------------------------------------------------------------------------- */ /* setting up for the table */ /* -------------------------------------------------------------------------- */ @@ -128,6 +131,85 @@ export default function TableListFinalLog() { /* -------------------------------------------------------------------------- */ + // ----------------------------------------- handle selected --------------------- + const [selectAll, setSelectAll] = useState(false); + const [selectedRows, setSelectedRows] = useState([]); + const [dataTableData, setDataTableData] = useState(); + const handleSelectAll = () => { + setSelectAll(!selectAll); + if (!selectAll) { + const requestedIds = dataTableData?.data + .filter((row: { status: string, check_claim:any }) => row.status === 'approved' && !row.check_claim) + .map((row: { id: any }) => row.id); + setSelectedRows(requestedIds); + } else { + setSelectedRows([]); + } + }; + + const handleCheckboxChange = (id: any) => { + setSelectedRows(prevSelectedRows => { + const isSelected = prevSelectedRows.includes(id); + if (isSelected) { + return prevSelectedRows.filter(rowId => rowId !== id); + } else { + return [...prevSelectedRows, id]; + } + }); + }; + + const [openDialogSubmit, setOpenDialogSubmit] = useState(false); + const handleCloseDialogSubmit = () => { + setOpenDialogSubmit(false); + } + const [valDialog, setValDialog] = useState(''); + const [reasonDecline, setReasonDecline] = useState(''); + const handleReasonDeclineChange = (event: { target: { value: SetStateAction; }; }) => { + setReasonDecline(event.target.value); +}; + + const selected = { + useSelected: true, + selectAll: selectAll, + handleSelectAll: handleSelectAll, + selectedRows: selectedRows, + handleCheckboxChange : handleCheckboxChange, + totRows: 9, + useDecline: false, + txtDecline: 'Decline', + useApprove:true, + txtApprove: 'Submit Claim', + setOpenDialogSubmit: setOpenDialogSubmit, + setValDialog: setValDialog + }; + const handleSubmitData = () => { + //approve or decline + // if (!reasonDecline && valDialog == 'decline') { + // enqueueSnackbar('Mohon isi alasan', { variant: 'warning' }); + // return false; + // } + axios.post('/submit-claims', { + selectedRows: selectedRows + }) + .then((response) => { + if(response.data.meta.code === 200) + { + setOpenDialogSubmit(false); + enqueueSnackbar(response.data.meta.message, {variant : "success"}); + } + else{ + setOpenDialogSubmit(false); + enqueueSnackbar(response.data.meta.message, {variant : "error"}); + } + getData(); + setSelectedRows([]); + }) + .catch(({response}) => { + enqueueSnackbar(response.data.errors ? response.data.errors[0] : (response.data ? response.data.meta.message : 'Opps, Something went Wrong!'), {variant : "error"}) + }) + .then(() => { + }); + }; /* ------------------------------ handle search ----------------------------- */ const [searchText, setSearchText] = useState(''); @@ -335,11 +417,14 @@ export default function TableListFinalLog() { params: { ...parameters, search:searchText, order: order, orderBy: orderBy, status:statusValue, type: 'final-log' }, }); + setDataTableData(response.data); setData( - response.data.data.map((obj: any) => ({ - ...obj, + response.data.data.map((obj: any) => ({ + ...obj, provider:formatTitleCase(obj.provider), full_name:formatTitleCase(obj.full_name), + check_status: obj.status, + check_claim: obj.check_claim, status: obj.status === 'requested' ? ( @@ -445,6 +530,7 @@ export default function TableListFinalLog() { params={params} searchs={searchs} filterStatus={filterStatus} + selected={selected} // filterStartDate={filterStartDate} // filterEndDate={filterEndDate} /> @@ -466,7 +552,6 @@ export default function TableListFinalLog() { member={dataViewClaimSubmit} getData={getData} onClose={(data:any, getData:any) => { - console.log('Data returned:', data); getData(); setOpenDialogClaimSubmit(false); }} @@ -475,7 +560,43 @@ export default function TableListFinalLog() { /> } maxWidth="sm" - /> + /> + + + + + {localeData.txtConfirmation} + + + + + + + + + + {localeData.txtDialogConfirmation} + {valDialog == "decline" ? ( + + + + ): ''} + + + + {localeData.txtCancel} + {(valDialog === "decline" ? localeData.txtDeclaine : 'Submit')} + + > ); } \ No newline at end of file diff --git a/frontend/hospital-portal/src/sections/dashboard/TableListReqLog.tsx b/frontend/hospital-portal/src/sections/dashboard/TableListReqLog.tsx index 17ce8ace..7fe20e82 100644 --- a/frontend/hospital-portal/src/sections/dashboard/TableListReqLog.tsx +++ b/frontend/hospital-portal/src/sections/dashboard/TableListReqLog.tsx @@ -5,7 +5,7 @@ import { Stack, Button, MenuItem, SelectChangeEvent, Tab, Tabs, Card, Box } from import axios from '../../utils/axios'; import { styled } from '@mui/material/styles'; /* ---------------------------------- react --------------------------------- */ -import { useContext, useEffect, useState } from 'react'; +import { useContext, useEffect, useState, SetStateAction } from 'react'; /* -------------------------------- component ------------------------------- */ import Iconify from '../../components/Iconify'; @@ -132,6 +132,58 @@ export default function TableList() { /* -------------------------------------------------------------------------- */ + // ----------------------------------------- handle selected --------------------- + const [selectAll, setSelectAll] = useState(false); + const [selectedRows, setSelectedRows] = useState([]); + const [dataTableData, setDataTableData] = useState(); + const handleSelectAll = () => { + setSelectAll(!selectAll); + if (!selectAll) { + const requestedIds = dataTableData?.data + .filter((row: { status: string, check_claim:any }) => row.status === 'approved' && !row.check_claim) + .map((row: { id: any }) => row.id); + setSelectedRows(requestedIds); + } else { + setSelectedRows([]); + } + }; + + const handleCheckboxChange = (id: any) => { + setSelectedRows(prevSelectedRows => { + const isSelected = prevSelectedRows.includes(id); + if (isSelected) { + return prevSelectedRows.filter(rowId => rowId !== id); + } else { + return [...prevSelectedRows, id]; + } + }); + }; + + const [openDialogSubmit, setOpenDialogSubmit] = useState(false); + const handleCloseDialogSubmit = () => { + setOpenDialogSubmit(false); + } + const [valDialog, setValDialog] = useState(''); + const [reasonDecline, setReasonDecline] = useState(''); + const handleReasonDeclineChange = (event: { target: { value: SetStateAction; }; }) => { + setReasonDecline(event.target.value); +}; + + const selected = { + useSelected: false, + selectAll: selectAll, + handleSelectAll: handleSelectAll, + selectedRows: selectedRows, + handleCheckboxChange : handleCheckboxChange, + totRows: 9, + useDecline: false, + txtDecline: 'Decline', + useApprove:true, + txtApprove: 'Submit Claim', + setOpenDialogSubmit: setOpenDialogSubmit, + setValDialog: setValDialog + }; + /* ------------------------------ handle search ----------------------------- */ const [searchText, setSearchText] = useState(''); @@ -187,7 +239,7 @@ export default function TableList() { }; // handle start date - const [startDateValue, setStartDateValue] = useState(''); + const [startDateValue, setStartDateValue] = useState(null); const handleStartDateChanges = async (event: React.FormEvent) => { event.preventDefault(); @@ -211,7 +263,7 @@ export default function TableList() { }; // handle end date - const [endDateValue, setEndDateValue] = useState(''); + const [endDateValue, setEndDateValue] = useState(null); const handleEndDateChanges = async (event: React.FormEvent) => { event.preventDefault(); @@ -328,6 +380,7 @@ export default function TableList() { params: { ...parameters, search:searchText, order: order, orderBy: orderBy, status:statusValue, type: 'request-log' }, }); + setDataTableData(response.data); setData( response.data.data.map((obj: any) => ({ ...obj, @@ -440,8 +493,9 @@ export default function TableList() { params={params} searchs={searchs} filterStatus={filterStatus} - // filterStartDate={filterStartDate} - // filterEndDate={filterEndDate} + selected={selected} + //filterStartDate={filterStartDate} + //filterEndDate={filterEndDate} />
No diagnosis available.