diff --git a/Modules/Internal/Http/Controllers/Api/CorporateMemberController.php b/Modules/Internal/Http/Controllers/Api/CorporateMemberController.php index 2668e0ac..817a27ef 100644 --- a/Modules/Internal/Http/Controllers/Api/CorporateMemberController.php +++ b/Modules/Internal/Http/Controllers/Api/CorporateMemberController.php @@ -185,6 +185,7 @@ class CorporateMemberController extends Controller $imported_member_data = 0; $failed_member_data = []; + foreach ($reader->getSheetIterator() as $sheet) { $doc_headers_indexes = []; foreach ($sheet->getRowIterator() as $index => $row) { diff --git a/Modules/Internal/Http/Controllers/Api/RequestLogController.php b/Modules/Internal/Http/Controllers/Api/RequestLogController.php index 32cc6645..5e6591ed 100644 --- a/Modules/Internal/Http/Controllers/Api/RequestLogController.php +++ b/Modules/Internal/Http/Controllers/Api/RequestLogController.php @@ -13,7 +13,6 @@ use Illuminate\Routing\Controller; use Modules\Internal\Transformers\RequestLogResource; use Modules\Internal\Transformers\RequestLogShowResource; use Illuminate\Support\Facades\Storage; -use App\Services\RequestLogService; use App\Exceptions\ImportRowException; use App\Events\RequestLoged; use Carbon\Carbon; @@ -32,6 +31,7 @@ use App\Models\File; use App\Models\FilesMcu; use Illuminate\Support\Facades\DB; use App\Models\Member; +use Modules\Internal\Services\RequestLogService; class RequestLogController extends Controller { @@ -41,6 +41,12 @@ class RequestLogController extends Controller * Display a listing of the resource. * @return Renderable */ + + public function __construct(RequestLogService $requestLogService) + { + $this->requestLogService = $requestLogService; + } + public function index(Request $request) { $requestLog = RequestLog::query() @@ -386,7 +392,6 @@ class RequestLogController extends Controller } - public function updateStatus($id) { $requestLog = RequestLog::findOrFail($id); @@ -443,37 +448,35 @@ class RequestLogController extends Controller public function importRequestLog(Request $request) { - $request->validate([ 'file' => 'required|file|mimes:xls,xlsx,csv,txt', ]); + $file_name = now()->getPreciseTimestamp(3) . '-' . $request->file('file')->getClientOriginalName(); $file = $request->file('file')->storeAs('temp', $file_name); - $fileWrite = Storage::disk('public')->path('temp/result-' . $file_name); - $fileRead = Storage::path('temp/' . $file_name); - $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(); - $firstWriterSheet->setName($sheet->getName()); - } else { // Add New Sheet to Writer - $nextWriterSheet = $import->writer->addNewSheetAndMakeItCurrent(); - $nextWriterSheet->setName($sheet->getName()); - } + + $reader = ReaderEntityFactory::createXLSXReader(Storage::path('temp/' . $file_name)); + $reader->open(Storage::path('temp/' . $file_name)); - $headers_map_to_table_fields = RequestLog::$doc_headers_to_field_map; + $writer = WriterEntityFactory::createXLSXWriter(); + $writer->openToFile(Storage::disk('public')->path('temp/result-' . $file_name)); - // Write Header to File - $result_headers = array_keys($headers_map_to_table_fields); - $result_headers = array_merge($result_headers, ['Ingest Code', 'Ingest Note']); + $headers_map_to_table_fields = $this->requestLogService->doc_headers_to_field_map; - $import->addArrayToRow($result_headers); + // Write Header to File with certain Format from MemberEnrollmentService::$result_doc_headers + $result_headers = $this->requestLogService->listing_doc_headers; + $singleRow = WriterEntityFactory::createRow($this->requestLogService->makeResultRow($result_headers)); + $writer->addRow($singleRow); + + $imported_member_data = 0; + $failed_member_data = []; + + foreach ($reader->getSheetIterator() as $sheet) { $doc_headers_indexes = []; foreach ($sheet->getRowIterator() as $index => $row) { if ($index == 1) { // First Row Must be Header foreach ($row->getCells() as $index => $cell) { + // Clear up the string and remove all spaces $title = $cell->getValue(); $title = preg_replace("/\r|\n/", " ", $title); $title = preg_replace('/\xc2\xa0/', " ", $title); @@ -481,39 +484,58 @@ class RequestLogController extends Controller $title = ltrim($title); $doc_headers_indexes[$index] = $title; } - // TODO Validate if First Row not Header } else { // Next Row Should be Data - $row_data = []; + // Collecting Values from table rows and map it to correct fields + $requestLog = []; foreach ($row->getCells() as $header_index => $cell) { - if (isset($headers_map_to_table_fields[$doc_headers_indexes[$header_index]])) - $row_data[$headers_map_to_table_fields[$doc_headers_indexes[$header_index]]] = $cell->getValue(); + if (isset($headers_map_to_table_fields[$doc_headers_indexes[$header_index]])) { + $requestLog[$headers_map_to_table_fields[$doc_headers_indexes[$header_index]]] = $cell->getValue(); + } } - try { // Process the Row Data - $requestLog = new RequestLogService(); - $requestLog->handleRequestLogRow($row_data); - - $result_headers = array_merge($row_data, ['Ingest Code' =>200, 'Ingest Note' => 'Success']); - - $import->addArrayToRow($result_headers, $sheet->getName()); + try { + $rowResponse = $this->requestLogService->handleImportRow($requestLog); + // Write Success Result to File + $singleRow = WriterEntityFactory::createRow($this->requestLogService->makeResultRowWithResultFormat($rowResponse)); + $writer->addRow($singleRow); + $imported_member_data++; } catch (ImportRowException $e) { - $import->addArrayToRow(array_merge($row_data, [ - 'Ingest Code' => $e->getCode(), - 'Ingest Note' => $e->getMessage(), - ]), $sheet->getName()); + // Write Data Validation Error to File + $requestLog = array_merge($requestLog, [ + 'ingestion_code' => $e->getCode(), + 'ingestion_status' => $e->getMessage(), + ]); + // try { + $singleRow = WriterEntityFactory::createRow($this->requestLogService->makeResultRowWithResultFormat($new_member_data)); + $writer->addRow($singleRow); + // } catch (\Exception $e) { + $failed_member_data[] = ['row_number' => $index, 'error' => $e->getMessage(), 'data' => $new_member_data]; + // } + } catch (\Exception $e) { + // Write Server Error to File + $requestLog = array_merge($requestLog, [ + 'ingestion_code' => $e->getCode(), + 'ingestion_status' => $e->getMessage(), + ]); + $singleRow = WriterEntityFactory::createRow($this->requestLogService->makeResultRowWithResultFormat($requestLog)); + $writer->addRow($singleRow); + $failed_member_data[] = ['row_number' => $index, 'error' => $e->getMessage()]; } } } - } - $import->reader->close(); - Storage::delete('temp/' . $file_name); - $import->writer->close(); + break; //only read first sheet + } + + $reader->close(); + $writer->close(); + Storage::delete('temp/' . $file_name); + // throw(404); return [ - // 'total_successed_row' => $imported_plan_data, - // 'total_failed_row' => count($failed_plan_data), - // 'failed_row' => $failed_plan_data, + 'total_success_row' => $imported_member_data, + 'total_failed_row' => count($failed_member_data), + 'failed_row' => $failed_member_data, 'result_file' => [ 'url' => Storage::disk('public')->url('temp/result-' . $file_name), 'name' => 'result-' . $file_name, @@ -747,7 +769,7 @@ class RequestLogController extends Controller // Pastikan $next_number adalah integer positif $next_number = max(1, (int) $next_number); // Menghasilkan kode dengan format yang diinginkan - return self::$code_prefix . $sparator. $data['source'] . $sparator. $data['provideCode'] . $sparator. $data['date'] . $sparator . $data['policy'] . $sparator. $data['member_code'] . $sparator. str_pad($next_number, 3, '0', STR_PAD_LEFT); + return self::$code_prefix . $sparator. $data['source'] . $sparator. $data['provideCode'] . $sparator. $data['date'] . $sparator . $data['policy'] . $sparator. $data['member_code'] . $sparator. str_pad($next_number, 5, '0', STR_PAD_LEFT); } public function requestFiles(Request $request, $claim_id) diff --git a/Modules/Internal/Services/RequestLogService.php b/Modules/Internal/Services/RequestLogService.php new file mode 100644 index 00000000..6bf78138 --- /dev/null +++ b/Modules/Internal/Services/RequestLogService.php @@ -0,0 +1,272 @@ + "submission_date", + "Date Addmission" => "submission_date", + "Member ID Peserta" => "member_id", + "Type of patient" => "service", + "Provider Name" => "organization_id", + "End Of Claim Numbers" => "code", + "Remarks" => "keterangan", + "Diagnosis" => "catatan", + "Tgl Billing dari RS" => "approved_final_log_at", + "Benefit Item" => "benefit_id", + "Total Billing" => "total_billing", + "Amount Approval" => "amount_approval", + "Amount Not Approval" => "amount_not_approval", + "QC 1" => "status_final_log", + "Ingestion Code" => "ingestion_code", // TODO I think this should not be here because if user uploading result then ingestion code and status will be filled + "Ingestion Status" => "ingestion_status", + + ]; + + public $field_to_doc_headers_map = [ + "submission_date" => "Date Of Request", + "submission_date" => "Date Addmission", + "member_id" => "Member ID Peserta", + "service" => "Type of patient", + "organization_id" => "Provider Name", + "code" => "End Of Claim Numbers", + "keterangan" => "Remarks", + "catatan" => "Diagnosis", + "approved_final_log_at" => "Tgl Billing dari RS", + "benefit_id" => "Benefit Item", + "total_billing" => "Total Billing", + "amount_approval" => "Amount Approval", + "amount_not_approval" => "Amount Not Approval", + "status_final_log" => "QC 1" , + "ingestion_code" => "Ingestion Code", + "ingestion_status" => "Ingestion Status", + ]; + + public $result_doc_headers = [ + "Date Of Request", + "Date Addmission", + "Member ID Peserta", + "Type of patient", + "Provider Name", + "End Of Claim Numbers", + "Remarks", + "Diagnosis", + "Tgl Billing dari RS", + "Benefit Item", + "Total Billing", + "Amount Approval", + "Amount Not Approval", + "QC 1", + "Ingestion Code", + "Ingestion Status", + ]; + + public $listing_doc_headers = [ + "Date Of Request", + "Date Addmission", + "Member ID Peserta", + "Type of patient", + "Provider Name", + "End Of Claim Numbers", + "Remarks", + "Diagnosis", + "Tgl Billing dari RS", + "Benefit Item", + "Total Billing", + "Amount Approval", + "Amount Not Approval", + "QC 1", + "Ingestion Code", + "Ingestion Status", + ]; + + public 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) { + return date('Y-m-d', strtotime($date_from_row)); + } else { + return null; + } + + } + + public function dateParserCode($date_from_row) { + + if ($date_from_row instanceof DateTime) { + return $date_from_row->format('ymd'); + } else if ($date_from_row != null) { + return date('ymd', strtotime($date_from_row)); + } else { + return null; + } + + } + + public function handleImportRow($row) + { + try { + // Memulai transaksi + DB::beginTransaction(); + $member = Member::with('currentCorporate')->where(['member_id' => $row['member_id']])->first(); + + // // Validate If Exist Member + if (!$member) { + throw new ImportRowException(__('MEMBER_NOT_FOUND', [ + 'member_id' => $row['member_id'], + ]), 0, null, $row); + } + // Membuat singkatan dari nama rumah sakit + $singkatan = ""; + $words = explode(' ', $row['organization_id']); + + foreach ($words as $word) { + $singkatan .= strtoupper(substr($word, 0, 1)); + } + + // Membuat kode organisasi + $kodeOrganisasi = "ORG000" . $singkatan; + // Insert data ke tabel organizations + $organization = DB::table('organizations')->where('code', $kodeOrganisasi)->first(); + // dd( $organization); + if ($organization) { + $organization_id = $organization->id; + } else { + $organization_id = DB::table('organizations') + ->insertGetId([ + 'name' => $row['organization_id'], + 'code' => $kodeOrganisasi, + 'type' => 'hospital', + 'created_at' => now(), + 'created_by' => auth()->user()->id + ]); + } + + $data = [ + 'source' => 'H', + 'provideCode' => $kodeOrganisasi , + 'date' => $this->dateParserCode($row['submission_date']), + 'policy' => $member->currentPolicy->code, + 'member_code' => $row['member_id'] + ]; + + $code = $this->makeCode($row['code'], $data); + $status = $row['status_final_log'] == 'Y' ? 'approved' : 'requested'; + $service = Service::where('name', $row['service'])->first(); + if ($service){ + $serviceCode = $service->code; + } else { + $serviceCode = 'Unk'; + } + + $benefit = Benefit::where('code', $row['benefit_id'])->first(); + + $requestLog = RequestLog::updateOrCreate( + [ + 'code' => $code + ], + [ + 'code' => $code, + 'member_id' => $member->id, + 'submission_date' => $row['submission_date'], + 'discharge_date' => $row['submission_date'], + 'payment_type' => 'cashless', + 'status' => $status, + 'status_final_log' => $status, + 'final_log' =>$row['status_final_log'] == 'Y' ? 1 : 0, + 'import_system' =>TRUE, + 'catatan' => $row['catatan'], + 'policy_id' => $member->currentPolicy->id ?? null, + 'organization_id' => $organization_id, + 'service_code' => $serviceCode, + 'approved_final_log_at' => $row['approved_final_log_at'], + ]); + + $requestLogBenefit = RequestLogBenefit::updateOrCreate( + [ + 'request_log_id' => $requestLog->id, + ], + [ + 'request_log_id' => $requestLog->id, + 'benefit_id' => $benefit->id, + 'amount_incurred' => $row['total_billing'], + 'amount_approved' => $row['amount_approval'], + 'amount_not_approved' => $row['amount_not_approval'], + 'excess_paid' => $row['amount_not_approval'], + 'created_by' => auth()->user()->id, + + ]); + + // Commit transaksi + DB::commit(); + } catch (\Exception $e) { + DB::rollback(); + throw new ImportRowException($e->getMessage(), $e->getCode(), $e, $row); + } + + $row['ingestion_code'] = "200"; + $row['ingestion_status'] = "SUCCESS"; + + return $row; + } + + // This returning row with format or order as it is + public function makeResultRow($row_data) + { + $cells = []; + foreach ($row_data as $cellValue) { + $cells[] = WriterEntityFactory::createCell($cellValue); + } + + return $cells; + } + + // This returning row with format or order following $result_doc_headers + public function makeResultRowWithResultFormat($row_data) + { + $cells = []; + foreach ($this->result_doc_headers as $header) { + $value = $row_data[$this->doc_headers_to_field_map[$header]] ?? null; + if (is_string($value)) { + $cells[] = WriterEntityFactory::createCell($value); + } + else if ($value instanceof DateTime) { + $cells[] = WriterEntityFactory::createCell(Carbon::parse($value)->format('Ymd')); + } + else { + $cells[] = WriterEntityFactory::createCell($value); + } + } + + return $cells; + } + + + public function makeCode($next_number, $data) + { + $sparator = '.'; + // Pastikan $next_number adalah integer positif + $next_number = max(1, (int) $next_number); + // Menghasilkan kode dengan format yang diinginkan + return self::$code_prefix . $sparator. $data['source'] . $sparator. $data['provideCode'] . $sparator. $data['date'] . $sparator . $data['policy'] . $sparator. $data['member_code'] . $sparator. str_pad($next_number, 5, '0', STR_PAD_LEFT); + } + +} diff --git a/app/Models/RequestLog.php b/app/Models/RequestLog.php index 0fac9e09..2683be21 100644 --- a/app/Models/RequestLog.php +++ b/app/Models/RequestLog.php @@ -34,6 +34,7 @@ class RequestLog extends Model 'hak_kamar_pasien', 'penempatan_kamar', 'catatan', + 'import_system', 'code', 'approved_by', 'approved_at', @@ -50,14 +51,38 @@ class RequestLog extends Model 'deleted_by', ]; - public static $doc_headers_to_field_map = [ - "ID REQUEST LOG" => "id", - "STATUS (approved, declined, requested)" => "status", + public static $doc_headers_to_field_map = [ + "Date Of Request" => "submission_date", + "Date Addmission" => "submission_date", + "Member ID Peserta" => "member_id", + "Type of patient" => "service", + "Provider Name" => "organization_id", + "End Of Claim Numbers" => "code", + "Remarks" => "keterangan", + "Diagnosis" => "catatan", + "Tgl Billing dari RS" => "approved_final_log_at", + "Benefit Item" => "benefit_id", + "Total Billing" => "total_billing", + "Amount Approval" => "amount_approval", + "Amount Not Approval" => "amount_not_approval", + "QC 1" => "status_final_log", ]; public static $listing_doc_headers = [ - "ID REQUEST LOG", - "STATUS (approved, declined, requested)", + "Date Of Request", + "Date Addmission", + "Member ID Peserta", + "Type of patient", + "Provider Name", + "End Of Claim Numbers", + "Remarks", + "Diagnosis", + "Tgl Billing dari RS", + "Benefit Item", + "Total Billing", + "Amount Approval", + "Amount Not Approval", + "QC 1", ]; public static $listing_data_doc_headers = [ diff --git a/database/migrations/2024_01_11_225714_add_column_to_request_log.php b/database/migrations/2024_01_11_225714_add_column_to_request_log.php new file mode 100644 index 00000000..7e964071 --- /dev/null +++ b/database/migrations/2024_01_11_225714_add_column_to_request_log.php @@ -0,0 +1,32 @@ +boolean('import_system')->after('organization_id')->default(false); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('request_logs', function (Blueprint $table) { + $table->dropColumn('import_system'); + }); + } +}; diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/List.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/List.tsx index d00eb098..15e45f95 100644 --- a/frontend/dashboard/src/pages/CustomerService/FinalLog/List.tsx +++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/List.tsx @@ -483,6 +483,9 @@ export default function List() { Code + + Provider + Name