Merge remote-tracking branch 'origin/staging' into origin/production

This commit is contained in:
Linksehat Staging Server
2024-01-12 10:36:02 +07:00
5 changed files with 401 additions and 49 deletions

View File

@@ -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) {

View File

@@ -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()
@@ -391,7 +397,6 @@ class RequestLogController extends Controller
}
public function updateStatus($id)
{
$requestLog = RequestLog::findOrFail($id);
@@ -448,37 +453,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);
@@ -486,39 +489,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($requestLog));
$writer->addRow($singleRow);
// } catch (\Exception $e) {
$failed_member_data[] = ['row_number' => $index, 'error' => $e->getMessage(), 'data' => $requestLog];
// }
} 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,
@@ -752,7 +774,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)

View File

@@ -0,0 +1,272 @@
<?php
namespace Modules\Internal\Services;
use App\Exceptions\ImportRowException;
use App\Models\Member;
use App\Models\Benefit;
use App\Models\RequestLog;
use App\Models\RequestLogBenefit;
use App\Models\Corporate;
use App\Models\Service;
use App\Models\Plan;
use Box\Spout\Writer\Common\Creator\WriterEntityFactory;
use Box\Spout\Common\Entity\Row;
use Carbon\Carbon;
use DateTime;
use DB;
class RequestLogService
{
private static $code_prefix = 'LOG';
public $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",
"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);
}
}

View File

@@ -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 = [

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('request_logs', function (Blueprint $table) {
$table->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');
});
}
};