Add Diagnosis Exclusion
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Internal\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Icd;
|
||||
use Illuminate\Contracts\Support\Renderable;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
|
||||
class DiagnosisController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
* @return Renderable
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$diagnosis = Icd::withTrashed()->filter($request->toArray())->paginate();
|
||||
|
||||
return $diagnosis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
* @return Renderable
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('internal::create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
* @param Request $request
|
||||
* @return Renderable
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the specified resource.
|
||||
* @param int $id
|
||||
* @return Renderable
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
return view('internal::show');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
* @param int $id
|
||||
* @return Renderable
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
return view('internal::edit');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
* @param Request $request
|
||||
* @param int $id
|
||||
* @return Renderable
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
* @param int $id
|
||||
* @return Renderable
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Internal\Http\Controllers\Api;
|
||||
|
||||
use App\Exceptions\ImportRowException;
|
||||
use App\Models\Corporate;
|
||||
use App\Models\Exclusion;
|
||||
use App\Models\Icd;
|
||||
use App\Models\ImportLog;
|
||||
use App\Services\ImportService;
|
||||
use Illuminate\Contracts\Support\Renderable;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Modules\Internal\Services\ExclusionService;
|
||||
use Modules\Internal\Transformers\DiagnosisExclusionResource;
|
||||
|
||||
class DiagnosisExclusionController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
* @return Renderable
|
||||
*/
|
||||
public function index(Request $request, $corporate_id)
|
||||
{
|
||||
$exclusions = Exclusion::query()
|
||||
->where('corporate_id', $corporate_id)
|
||||
->with(['exclusionable', 'rules'])
|
||||
->filter($request->toArray())
|
||||
->paginate();
|
||||
|
||||
return response()->json(DiagnosisExclusionResource::collection($exclusions)->response()->getData(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
* @return Renderable
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('internal::create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
* @param Request $request
|
||||
* @return Renderable
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the specified resource.
|
||||
* @param int $id
|
||||
* @return Renderable
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
return view('internal::show');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
* @param int $id
|
||||
* @return Renderable
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
return view('internal::edit');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
* @param Request $request
|
||||
* @param int $id
|
||||
* @return Renderable
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
* @param int $id
|
||||
* @return Renderable
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public function import(Request $request, $corporate_id)
|
||||
{
|
||||
$request->validate([
|
||||
'file' => 'required|file|mimes:xls,xlsx,csv,txt',
|
||||
]);
|
||||
// dd($request->toArray());
|
||||
$file_name = now()->getPreciseTimestamp(3).'-'.$request->file('file')->getClientOriginalName();
|
||||
$file = $request->file('file')->storeAs('temp', $file_name);
|
||||
$corporate = Corporate::findOrFail($corporate_id);
|
||||
|
||||
$importLog = $corporate->importLogs()->create([
|
||||
'type' => 'diagnosis-exclusions',
|
||||
'file_path' => $file,
|
||||
'status' => 'pending',
|
||||
'progress' => 0,
|
||||
]);
|
||||
|
||||
$import = new ImportService();
|
||||
$import->read(Storage::path('temp/'.$file_name));
|
||||
$import->write(Storage::disk('public')->path('temp/result-'.$file_name), 'xsls');
|
||||
|
||||
foreach ($import->sheetsIterator() as $sheetIndex => $sheet) {
|
||||
$doc_headers_indexes = [];
|
||||
foreach ($sheet->getRowIterator() as $index => $row) {
|
||||
if ($index == 1) { // First Row Must be Header
|
||||
foreach ($row->getCells() as $index => $cell) {
|
||||
$title = $cell->getValue();
|
||||
$title = preg_replace( "/\r|\n/", " ", $title );
|
||||
$title = preg_replace('/\xc2\xa0/', " ", $title );
|
||||
$title = rtrim($title);
|
||||
$title = ltrim($title);
|
||||
$doc_headers_indexes[$index] = $title;
|
||||
}
|
||||
|
||||
// Write Header to File
|
||||
$result_headers = array_merge($doc_headers_indexes, ['Ingest Code', 'Ingest Note']);
|
||||
$import->addArrayToRow($result_headers);
|
||||
|
||||
// TODO Validate if First Row not Header
|
||||
} else { // Next Row Should be Data
|
||||
$row_data = [];
|
||||
$row_map = [
|
||||
0 => 'code',
|
||||
1 => 'description',
|
||||
2 => 'ip_exclusion',
|
||||
3 => 'op_exclusion',
|
||||
4 => 'de_exclusion',
|
||||
5 => 'ma_exclusion',
|
||||
6 => 'sp_exclusion',
|
||||
7 => 'pre_exist_exclusion',
|
||||
8 => 'op_de_exclusion',
|
||||
9 => 'keterangan',
|
||||
10 => 'maternity_waiting'
|
||||
];
|
||||
|
||||
foreach ($row->getCells() as $header_index => $cell) {
|
||||
if (isset($row_map[$header_index])) {
|
||||
$value = $cell->getValue();
|
||||
$value = preg_replace( "/\r|\n/", " ", $value );
|
||||
$value = preg_replace('/\xc2\xa0/', " ", $value );
|
||||
$value = rtrim($value);
|
||||
$value = ltrim($value);
|
||||
$row_data[$row_map[$header_index]] = $cell->getValue();
|
||||
}
|
||||
}
|
||||
|
||||
try { // Process the Row Data
|
||||
if (
|
||||
// empty($row_data['code']) &&
|
||||
// empty($row_data['description']) &&
|
||||
empty($row_data['ip_exclusion']) &&
|
||||
empty($row_data['op_exclusion']) &&
|
||||
empty($row_data['de_exclusion']) &&
|
||||
empty($row_data['ma_exclusion']) &&
|
||||
empty($row_data['sp_exclusion']) &&
|
||||
empty($row_data['pre_exis_exclusion']) &&
|
||||
empty($row_data['op_de_exclusion']) &&
|
||||
empty($row_data['maternity_waiting'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Save the Row
|
||||
$exclusionService = new ExclusionService();
|
||||
$exclusionService->handleDiagnosisExclusionRow($corporate, $row_data);
|
||||
|
||||
// Write Success Result to File
|
||||
$import->addArrayToRow(array_merge($row_data, [
|
||||
'Ingest Code' => 200,
|
||||
'Ingest Note' => 'Success',
|
||||
]), $sheet->getName());
|
||||
|
||||
} catch (ImportRowException $e) {
|
||||
// Write Data Validation Error to File
|
||||
$import->addArrayToRow(array_merge($row_data, [
|
||||
'Ingest Code' => $e->getCode(),
|
||||
'Ingest Note' => $e->getMessage(),
|
||||
]), $sheet->getName());
|
||||
} catch (\Exception $e) {
|
||||
throw new \Exception($e);
|
||||
// Write Server Error to File
|
||||
$import->addArrayToRow(array_merge($row_data, [
|
||||
'Ingest Code' => 500,
|
||||
'Ingest Note' => env('APP_DEBUG') ? $e->getMessage() : 'Server Error',
|
||||
]), $sheet->getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break; // Only Read First Row
|
||||
}
|
||||
$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,
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ use Modules\Internal\Http\Controllers\Api\BenefitController;
|
||||
use Modules\Internal\Http\Controllers\Api\CorporateBenefitController;
|
||||
use Modules\Internal\Http\Controllers\Api\CorporateController;
|
||||
use Modules\Internal\Http\Controllers\Api\CorporatePlanController;
|
||||
use Modules\Internal\Http\Controllers\Api\DiagnosisController;
|
||||
use Modules\Internal\Http\Controllers\Api\DiagnosisExclusionController;
|
||||
use Modules\Internal\Http\Controllers\Api\DivisionController;
|
||||
use Modules\Internal\Http\Controllers\Api\MemberController;
|
||||
use Modules\Internal\Http\Controllers\Api\PlanController;
|
||||
@@ -63,5 +65,16 @@ Route::prefix('internal')->group(function () {
|
||||
Route::get('corporates/{corporate_id}/members', [MemberController::class, 'index']);
|
||||
Route::post('corporates/{corporate_id}/members/import', [MemberController::class, 'import']);
|
||||
|
||||
Route::get('corporates/{corporate_id}/diagnosis-exclusions', [DiagnosisExclusionController::class, 'index']);
|
||||
Route::post('corporates/{corporate_id}/diagnosis-exclusions/import', [DiagnosisExclusionController::class, 'import']);
|
||||
|
||||
// Route::get('corporates/{corporate_id}/diagnosis-exclusions', [DiagnosisExclusionController::class, 'index']);
|
||||
// Route::get('corporates/{corporate_id}/diagnosis-exclusions/import', [DiagnosisExclusionController::class, 'import']);
|
||||
|
||||
Route::get('master/diagnosis', [DiagnosisController::class, 'index']);
|
||||
|
||||
|
||||
});
|
||||
|
||||
// Route::get('something', [DiagnosisExclusionController::class, 'index']);
|
||||
});
|
||||
|
||||
220
Modules/Internal/Services/ExclusionService.php
Normal file
220
Modules/Internal/Services/ExclusionService.php
Normal file
@@ -0,0 +1,220 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Internal\Services;
|
||||
|
||||
use App\Exceptions\ImportRowException;
|
||||
use App\Models\Benefit;
|
||||
use App\Models\Corporate;
|
||||
use App\Models\Icd;
|
||||
use App\Models\Plan;
|
||||
use Box\Spout\Writer\Common\Creator\WriterEntityFactory;
|
||||
|
||||
class ExclusionService
|
||||
{
|
||||
protected function validateDiagnosisExclusionRow($row)
|
||||
{
|
||||
// if (empty($row['service_code'])) {
|
||||
// throw new ImportRowException(__('plan.RECORD_TYPE_REQUIRED'), 0, null, $row);
|
||||
// }
|
||||
}
|
||||
|
||||
public function handleDiagnosisExclusionRow(Corporate $corporate, $row)
|
||||
{
|
||||
try {
|
||||
$this->validateDiagnosisExclusionRow($row);
|
||||
|
||||
if (!empty($row['ip_exclusion'])) {
|
||||
$excl_array = explode('|', $row['ip_exclusion']);
|
||||
if ($excl_array[0] == '3') {
|
||||
$icd = Icd::where('code', $row['code'])->first();
|
||||
$exclusion = $icd->exclusions()->create([
|
||||
'corporate_id' => $corporate->id,
|
||||
'service_code' => 'OP',
|
||||
'type' => 'diagnosis'
|
||||
]);
|
||||
|
||||
if (!empty($excl_array[1])) { //msc
|
||||
$msc = explode(',', $excl_array[1]);
|
||||
collect($msc)->each(function($m) use ($exclusion) {
|
||||
$exclusion->rules()->create([
|
||||
'name' => 'msc',
|
||||
'values' => $m
|
||||
]);
|
||||
});
|
||||
}
|
||||
if (!empty($excl_array[2])) { //genders
|
||||
$genders = explode(',', $excl_array[2]);
|
||||
collect($genders)->each(function($gender) use ($exclusion) {
|
||||
$exclusion->rules()->create([
|
||||
'name' => 'gender',
|
||||
'values' => $gender
|
||||
]);
|
||||
});
|
||||
}
|
||||
if (!empty($excl_array[3])) { //min_age
|
||||
$exclusion->rules()->create([
|
||||
'name' => 'min_age',
|
||||
'values' => $excl_array[3]
|
||||
]);
|
||||
}
|
||||
if (!empty($excl_array[4])) { //max_age
|
||||
$exclusion->rules()->create([
|
||||
'name' => 'max_age',
|
||||
'values' => $excl_array[4]
|
||||
]);
|
||||
}
|
||||
if (!empty($excl_array[5])) { //plans
|
||||
$exclusion->rules()->create([
|
||||
'name' => 'plan',
|
||||
'values' => $excl_array[5]
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($row['op_exclusion'])) {
|
||||
$excl_array = explode('|', $row['op_exclusion']);
|
||||
if ($excl_array[0] == '3') {
|
||||
$icd = Icd::where('code', $row['code'])->first();
|
||||
if (!$icd) {
|
||||
throw new ImportRowException(__('icd.NOT_FOUND'), 0, NULL, $row);
|
||||
}
|
||||
$exclusion = $icd->exclusions()->create([
|
||||
'corporate_id' => $corporate->id,
|
||||
'service_code' => 'OP',
|
||||
'type' => 'diagnosis'
|
||||
]);
|
||||
|
||||
if (!empty($excl_array[1])) { //msc
|
||||
$msc = explode(',', $excl_array[1]);
|
||||
collect($msc)->each(function($m) use ($exclusion) {
|
||||
$exclusion->rules()->create([
|
||||
'name' => 'msc',
|
||||
'values' => $m
|
||||
]);
|
||||
});
|
||||
}
|
||||
if (!empty($excl_array[2])) { //genders
|
||||
$genders = explode(',', $excl_array[2]);
|
||||
collect($genders)->each(function($gender) use ($exclusion) {
|
||||
$exclusion->rules()->create([
|
||||
'name' => 'gender',
|
||||
'values' => $gender
|
||||
]);
|
||||
});
|
||||
}
|
||||
if (!empty($excl_array[3])) { //min_age
|
||||
$exclusion->rules()->create([
|
||||
'name' => 'min_age',
|
||||
'values' => $excl_array[3]
|
||||
]);
|
||||
}
|
||||
if (!empty($excl_array[4])) { //max_age
|
||||
$exclusion->rules()->create([
|
||||
'name' => 'max_age',
|
||||
'values' => $excl_array[4]
|
||||
]);
|
||||
}
|
||||
if (!empty($excl_array[5])) { //plans
|
||||
$exclusion->rules()->create([
|
||||
'name' => 'plan',
|
||||
'values' => $excl_array[5]
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($row['de_exclusion'])) {
|
||||
$excl_array = explode('|', $row['de_exclusion']);
|
||||
if ($excl_array[0] == '3') {
|
||||
$icd = Icd::where('code', $row['code'])->first();
|
||||
$exclusion = $icd->exclusions()->create([
|
||||
'corporate_id' => $corporate->id,
|
||||
'service_code' => 'OP',
|
||||
'type' => 'diagnosis'
|
||||
]);
|
||||
|
||||
if (!empty($excl_array[1])) { //msc
|
||||
$msc = explode(',', $excl_array[1]);
|
||||
collect($msc)->each(function($m) use ($exclusion) {
|
||||
$exclusion->rules()->create([
|
||||
'name' => 'msc',
|
||||
'values' => $m
|
||||
]);
|
||||
});
|
||||
}
|
||||
if (!empty($excl_array[2])) { //genders
|
||||
$genders = explode(',', $excl_array[2]);
|
||||
collect($genders)->each(function($gender) use ($exclusion) {
|
||||
$exclusion->rules()->create([
|
||||
'name' => 'gender',
|
||||
'values' => $gender
|
||||
]);
|
||||
});
|
||||
}
|
||||
if (!empty($excl_array[3])) { //min_age
|
||||
$exclusion->rules()->create([
|
||||
'name' => 'min_age',
|
||||
'values' => $excl_array[3]
|
||||
]);
|
||||
}
|
||||
if (!empty($excl_array[4])) { //max_age
|
||||
$exclusion->rules()->create([
|
||||
'name' => 'max_age',
|
||||
'values' => $excl_array[4]
|
||||
]);
|
||||
}
|
||||
if (!empty($excl_array[5])) { //plans
|
||||
$exclusion->rules()->create([
|
||||
'name' => 'plan',
|
||||
'values' => $excl_array[5]
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($row['ma_exclusion'])) {
|
||||
$excl_array = explode('|', $row['ma_exclusion']);
|
||||
dd($excl_array);
|
||||
if ($excl_array[0]) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($row['sp_exclusion'])) {
|
||||
$excl_array = explode('|', $row['sp_exclusion']);
|
||||
dd($excl_array);
|
||||
if ($excl_array[0]) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($row['pre_exist_exclusion'])) {
|
||||
$excl_array = explode('|', $row['pre_exist_exclusion']);
|
||||
dd($excl_array);
|
||||
if ($excl_array[0]) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($row['op_de_exclusion'])) {
|
||||
$excl_array = explode('|', $row['op_de_exclusion']);
|
||||
dd($excl_array);
|
||||
if ($excl_array[0]) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($row['maternity_waiting'])) {
|
||||
$excl_array = explode('|', $row['maternity_waiting']);
|
||||
dd($excl_array);
|
||||
if ($excl_array[0]) {
|
||||
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
29
Modules/Internal/Transformers/DiagnosisExclusionResource.php
Normal file
29
Modules/Internal/Transformers/DiagnosisExclusionResource.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Internal\Transformers;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class DiagnosisExclusionResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'code' => $this->exclusionable->code,
|
||||
'name' => $this->exclusionable->name,
|
||||
'diagnosis_type' => $this->exclusionable->type,
|
||||
'service_code' => $this->service_code,
|
||||
'type' => $this->type,
|
||||
'rules' => $this->rules->mapToGroups(function ($item, $key) {
|
||||
return [$item['name'] => $item['values']];
|
||||
})
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -62,4 +62,9 @@ class Corporate extends Model
|
||||
{
|
||||
return $this->hasMany(CorporateDivision::class, 'corporate_id');
|
||||
}
|
||||
|
||||
public function importLogs()
|
||||
{
|
||||
return $this->morphMany(ImportLog::class, 'importable');
|
||||
}
|
||||
}
|
||||
|
||||
43
app/Models/Exclusion.php
Normal file
43
app/Models/Exclusion.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Traits\Blameable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Exclusion extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes, Blameable;
|
||||
|
||||
protected $fillable = [
|
||||
'corporate_id',
|
||||
'service_code',
|
||||
'type',
|
||||
'exclusionable_id',
|
||||
'exclusionable_type',
|
||||
];
|
||||
|
||||
public function rules()
|
||||
{
|
||||
return $this->hasMany(ExclusionRules::class, 'exclusion_id');
|
||||
}
|
||||
|
||||
public function exclusionable()
|
||||
{
|
||||
return $this->morphTo();
|
||||
}
|
||||
|
||||
public function scopeFilter($query, Array $filters)
|
||||
{
|
||||
$query->when($filters['search'] ?? false, function ($query, $search) {
|
||||
return $query
|
||||
->whereHasMorph('exclusionable', [Icd::class], function ($query) use ($search) {
|
||||
$query->where('code', 'like', "%" . $search . "%")
|
||||
->orWhere('name', 'like', "%" . $search . "%");
|
||||
})
|
||||
;
|
||||
});
|
||||
}
|
||||
}
|
||||
24
app/Models/ExclusionRules.php
Normal file
24
app/Models/ExclusionRules.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Traits\Blameable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class ExclusionRules extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes, Blameable;
|
||||
|
||||
protected $fillable = [
|
||||
'exclusion_id',
|
||||
'name',
|
||||
'values',
|
||||
];
|
||||
|
||||
public function exclusion()
|
||||
{
|
||||
return $this->belongsTo(Exclusion::class, 'exclusion_id');
|
||||
}
|
||||
}
|
||||
65
app/Models/Icd.php
Normal file
65
app/Models/Icd.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Traits\Blameable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Icd extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes, Blameable;
|
||||
|
||||
protected $table = 'icd';
|
||||
|
||||
protected $fillable = [
|
||||
'rev',
|
||||
'version',
|
||||
'code',
|
||||
'name',
|
||||
'description',
|
||||
'parent_code',
|
||||
];
|
||||
|
||||
public $appends = [
|
||||
'type',
|
||||
'active'
|
||||
];
|
||||
|
||||
public function getTypeAttribute()
|
||||
{
|
||||
return 'ICD-'.$this->rev;
|
||||
}
|
||||
|
||||
public function getActiveAttribute()
|
||||
{
|
||||
return empty($this->deleted_at);
|
||||
}
|
||||
|
||||
public function subCategories()
|
||||
{
|
||||
return $this->hasMany(Icd::class, 'parent_code', 'code');
|
||||
}
|
||||
|
||||
public function category()
|
||||
{
|
||||
return $this->belongsTo(Icd::class, 'parent_code', 'code');
|
||||
}
|
||||
|
||||
public function exclusions()
|
||||
{
|
||||
return $this->morphMany(Exclusion::class, 'exclusionable');
|
||||
}
|
||||
|
||||
public function scopeFilter($query, Array $filters)
|
||||
{
|
||||
$query->when($filters['search'] ?? false, function ($query, $search) {
|
||||
return $query
|
||||
->where('code', 'like', "%" . $search . "%")
|
||||
->orWhere('name', 'like', "%" . $search . "%")
|
||||
;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,12 +2,28 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Traits\Blameable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ImportLog extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use HasFactory, SoftDeletes, Blameable;
|
||||
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::creating(function ($model) {
|
||||
try {
|
||||
$model->uuid = (string) Str::orderedUuid(); // generate uuid
|
||||
} catch (\Exception $e) {
|
||||
abort(500, $e->getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected $fillable = [
|
||||
'importable_type',
|
||||
|
||||
@@ -14,7 +14,7 @@ return new class extends Migration
|
||||
public function up()
|
||||
{
|
||||
Schema::create('import_logs', function (Blueprint $table) {
|
||||
$table->uuid();
|
||||
$table->uuid()->primary();
|
||||
$table->morphs('importable');
|
||||
$table->string('type')->nullable();
|
||||
$table->string('file_path')->nullable();
|
||||
|
||||
43
database/migrations/2022_07_28_032235_create_icd_table.php
Normal file
43
database/migrations/2022_07_28_032235_create_icd_table.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?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::create('icd', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('rev');
|
||||
$table->string('version')->nullable();
|
||||
$table->string('code');
|
||||
$table->string('name');
|
||||
$table->text('description')->nullable();
|
||||
$table->string('parent_code')->nullable()->index();
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->unsignedBigInteger('created_by')->nullable();
|
||||
$table->unsignedBigInteger('updated_by')->nullable();
|
||||
$table->unsignedBigInteger('deleted_by')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('icd_x');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
<?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::create('exclusions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('corporate_id');
|
||||
$table->string('service_code')->index();
|
||||
$table->string('type');
|
||||
$table->morphs('exclusionable');
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->unsignedBigInteger('created_by')->nullable();
|
||||
$table->unsignedBigInteger('updated_by')->nullable();
|
||||
$table->unsignedBigInteger('deleted_by')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('exclusions');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
<?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::create('exclusion_rules', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('exclusion_id');
|
||||
$table->string('name');
|
||||
$table->text('values');
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->unsignedBigInteger('created_by')->nullable();
|
||||
$table->unsignedBigInteger('updated_by')->nullable();
|
||||
$table->unsignedBigInteger('deleted_by')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('exclusion_rules');
|
||||
}
|
||||
};
|
||||
64
database/seeders/IcdSeeder.php
Normal file
64
database/seeders/IcdSeeder.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Icd;
|
||||
use Box\Spout\Reader\Common\Creator\ReaderEntityFactory;
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class IcdSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$file_path = resource_path('files/ICD-X-Halodoc.csv');
|
||||
$reader = ReaderEntityFactory::createReaderFromFile($file_path);
|
||||
$reader->open($file_path);
|
||||
|
||||
Icd::truncate();
|
||||
|
||||
$chunks = [];
|
||||
$time = now();
|
||||
foreach ($reader->getSheetIterator() as $sheet) {
|
||||
foreach ($sheet->getRowIterator() as $index => $row) {
|
||||
if ($index != 1) {
|
||||
$row_data = [
|
||||
'rev' => 'X',
|
||||
'version' => 'Halodoc',
|
||||
'created_at' => $time,
|
||||
];
|
||||
foreach ($row->getCells() as $cell_index => $cell) {
|
||||
if ($cell_index == 0) {
|
||||
$row_data['code'] = $cell->getValue();
|
||||
} else if ($cell_index == 1) {
|
||||
$row_data['name'] = $cell->getValue();
|
||||
}
|
||||
}
|
||||
|
||||
$exploded_code = explode('.', $row_data['code']);
|
||||
if (count($exploded_code) > 1) {
|
||||
$row_data['parent_code'] = $exploded_code[0];
|
||||
} else {
|
||||
$row_data['parent_code'] = NULL;
|
||||
}
|
||||
|
||||
$chunks[] = $row_data;
|
||||
}
|
||||
|
||||
if ($chunks && count($chunks) == 1000) {
|
||||
Icd::insert($chunks);
|
||||
$chunks = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($chunks && count($chunks) > 0) {
|
||||
Icd::insert($chunks);
|
||||
$chunks = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
11
frontend/dashboard/src/@types/diagnosis.ts
Normal file
11
frontend/dashboard/src/@types/diagnosis.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export type Icd = {
|
||||
id: number;
|
||||
type: string;
|
||||
rev: string;
|
||||
version?: string;
|
||||
code: string;
|
||||
name: string;
|
||||
description?: any;
|
||||
childs?: Icd[];
|
||||
status: string;
|
||||
};
|
||||
17
frontend/dashboard/src/components/BasePagination.tsx
Normal file
17
frontend/dashboard/src/components/BasePagination.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Pagination } from "@mui/material";
|
||||
import { Box } from "@mui/system";
|
||||
import { LaravelPaginatedData } from "../@types/paginated-data";
|
||||
|
||||
|
||||
export interface Props {
|
||||
paginationData?: LaravelPaginatedData;
|
||||
onPageChange: any;
|
||||
}
|
||||
|
||||
export default function BasePagination({ paginationData, onPageChange }: Props) {
|
||||
return (
|
||||
<Box sx={{ m: 2 }} display="flex" justifyContent="flex-end">
|
||||
<Pagination count={paginationData?.last_page} page={paginationData?.current_page} variant="outlined" shape="rounded" onChange={onPageChange}/>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
@@ -43,6 +43,10 @@ export default function CorporateTabNavigations({ position }: Props) {
|
||||
'path' : 'members',
|
||||
'label': 'Member List',
|
||||
},
|
||||
{
|
||||
'path' : 'diagnosis-exclusions',
|
||||
'label': 'Exclusion',
|
||||
},
|
||||
{
|
||||
'path' : 'hospitals',
|
||||
'label': 'Hospital',
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
import * as Yup from 'yup';
|
||||
import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import { Card, Collapse, Divider, Grid, Stack, Typography } from "@mui/material";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { useParams } from "react-router-dom";
|
||||
import HeaderBreadcrumbs from "../../../components/HeaderBreadcrumbs";
|
||||
import { FormProvider, RHFCheckbox, RHFSelect, RHFTextField } from "../../../components/hook-form";
|
||||
import Page from "../../../components/Page";
|
||||
import useSettings from "../../../hooks/useSettings";
|
||||
import CorporateTabNavigations from "../CorporateTabNavigations";
|
||||
import DivisionsList from "./List";
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
|
||||
|
||||
export default function Divisions() {
|
||||
const { themeStretch } = useSettings();
|
||||
|
||||
const { corporate_id } = useParams();
|
||||
|
||||
const NewDivisionSchema = Yup.object().shape({
|
||||
name: Yup.string().required('Name is required'),
|
||||
code: Yup.string().required('Corporate Code is required'),
|
||||
active: Yup.boolean().required('Corporate Status is required'),
|
||||
});
|
||||
|
||||
const defaultValues = useMemo(
|
||||
() => ({
|
||||
code: '',
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
const methods = useForm({
|
||||
resolver: yupResolver(NewDivisionSchema),
|
||||
defaultValues,
|
||||
});
|
||||
|
||||
const {
|
||||
reset,
|
||||
watch,
|
||||
control,
|
||||
setValue,
|
||||
getValues,
|
||||
setError,
|
||||
handleSubmit,
|
||||
formState: { isSubmitting },
|
||||
} = methods;
|
||||
|
||||
const onSubmit = async (data: any) => {
|
||||
console.log(data);
|
||||
};
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const benefits = [
|
||||
{
|
||||
'category' : 'General Practitioner',
|
||||
'childs' : [
|
||||
{
|
||||
'name' : 'External Doctor Online',
|
||||
'code' : 'gp-external-doctor-online'
|
||||
},
|
||||
{
|
||||
'name' : 'External Doctor Offline',
|
||||
'code' : 'gp-external-doctor-offline'
|
||||
},
|
||||
{
|
||||
'name' : 'Internal Doctor Online',
|
||||
'code' : 'gp-internal-doctor-online'
|
||||
},
|
||||
{
|
||||
'name' : 'Internal Doctor Offline',
|
||||
'code' : 'gp-internal-doctor-offline'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
'category' : 'Specialist',
|
||||
'childs' : [
|
||||
{
|
||||
'name' : 'External Doctor Online',
|
||||
'code' : 'sp-external-doctor-online'
|
||||
},
|
||||
{
|
||||
'name' : 'External Doctor Offline',
|
||||
'code' : 'sp-external-doctor-offline'
|
||||
},
|
||||
{
|
||||
'name' : 'Internal Doctor Online',
|
||||
'code' : 'sp-internal-doctor-online'
|
||||
},
|
||||
{
|
||||
'name' : 'Internal Doctor Offline',
|
||||
'code' : 'sp-internal-doctor-offline'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
'category' : 'Medicines',
|
||||
'childs' : [
|
||||
{
|
||||
'name' : 'Vitamins',
|
||||
'code' : 'medicines-vitamins'
|
||||
},
|
||||
{
|
||||
'name' : 'Delivery Fee',
|
||||
'code' : 'medicines-delivery-fee'
|
||||
},
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
const products = [
|
||||
{
|
||||
'name' : 'Inpatient',
|
||||
'code' : 'IP',
|
||||
},
|
||||
{
|
||||
'name' : 'Outpatient',
|
||||
'code' : 'OP',
|
||||
},
|
||||
{
|
||||
'name' : 'Dental',
|
||||
'code' : 'DT',
|
||||
},
|
||||
{
|
||||
'name' : 'Dental',
|
||||
'code' : 'DTL',
|
||||
},
|
||||
{
|
||||
'name' : 'Matternity',
|
||||
'code' : 'MT',
|
||||
},
|
||||
{
|
||||
'name' : 'Special Benefit',
|
||||
'code' : 'SB',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Page title="Create Benefit">
|
||||
|
||||
<HeaderBreadcrumbs
|
||||
heading={'Create Benefit'}
|
||||
links={[
|
||||
{ name: 'Dashboard', href: '/dashboard' },
|
||||
{
|
||||
name: 'Corporates',
|
||||
href: '/corporates',
|
||||
},
|
||||
{
|
||||
name: 'Corporate Name',
|
||||
href: '/corporates/'+id,
|
||||
},
|
||||
{
|
||||
name: 'Benefits',
|
||||
href: '/corporates/'+id+'/benefits',
|
||||
},
|
||||
{
|
||||
name: 'Create',
|
||||
href: '/corporates/'+id+'/benefits/create',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Card sx={{ p: 2 }}>
|
||||
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||
<Stack spacing={3}>
|
||||
|
||||
<Typography variant="h6">Benefit Detail</Typography>
|
||||
|
||||
<RHFTextField name="name" label="Benefit Name" />
|
||||
|
||||
<RHFTextField name="code" label="Benefit Code" />
|
||||
|
||||
<Typography variant="h6">Benefit Configuration</Typography>
|
||||
|
||||
<Divider orientation="horizontal" flexItem />
|
||||
<Stack spacing={3} divider={<Divider orientation="horizontal" flexItem />}>
|
||||
<Stack spacing={2}>
|
||||
<RHFCheckbox name="a" label='Outpatient'/>
|
||||
{benefits.map(row => (
|
||||
<Collapse in={true} timeout="auto" unmountOnExit >
|
||||
<Typography>{row.category}</Typography>
|
||||
<Grid container>
|
||||
{row.childs.map(benefit => (
|
||||
<Grid item xs={6}>
|
||||
<RHFCheckbox name={benefit.code} label={benefit.name}/>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</Collapse>
|
||||
))}
|
||||
<Typography>Admin Fee</Typography>
|
||||
<Grid container>
|
||||
{benefits.map(row => (
|
||||
<Grid item xs={4}>
|
||||
<RHFCheckbox name="cat" label={row.category}/>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</Stack>
|
||||
|
||||
|
||||
<Stack spacing={2}>
|
||||
<RHFCheckbox name="a" label='Inpatient'/>
|
||||
{benefits.map(row => (
|
||||
<Collapse in={true} timeout="auto" unmountOnExit >
|
||||
<Typography>{row.category}</Typography>
|
||||
<Grid container>
|
||||
{row.childs.map(benefit => (
|
||||
<Grid item xs={6}>
|
||||
<RHFCheckbox name={benefit.code} label={benefit.name}/>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</Collapse>
|
||||
))}
|
||||
<Typography>Admin Fee</Typography>
|
||||
<Grid container>
|
||||
{benefits.map(row => (
|
||||
<Grid item xs={4}>
|
||||
<RHFCheckbox name="cat" label={row.category}/>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
</Stack>
|
||||
</FormProvider>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { Card, Grid } from "@mui/material";
|
||||
import { useParams } from "react-router-dom";
|
||||
import HeaderBreadcrumbs from "../../../components/HeaderBreadcrumbs";
|
||||
import Page from "../../../components/Page";
|
||||
import useSettings from "../../../hooks/useSettings";
|
||||
import CorporateTabNavigations from "../CorporateTabNavigations";
|
||||
import List from "./List";
|
||||
|
||||
|
||||
|
||||
export default function Divisions() {
|
||||
const { themeStretch } = useSettings();
|
||||
|
||||
const { corporate_id } = useParams();
|
||||
|
||||
const pageTitle = 'Diagnosis Exclusion';
|
||||
return (
|
||||
<Page title={ pageTitle }>
|
||||
|
||||
<HeaderBreadcrumbs
|
||||
heading={ pageTitle }
|
||||
links={[
|
||||
{
|
||||
name: 'Corporates',
|
||||
href: '/corporates',
|
||||
},
|
||||
{
|
||||
name: 'Corporate Name',
|
||||
href: '/corporates/'+corporate_id,
|
||||
},
|
||||
{
|
||||
name: 'Diagnosis Exclusion',
|
||||
href: '/corporates/'+corporate_id+'/diagnosis-exclusions',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<CorporateTabNavigations position={'diagnosis-exclusions'} />
|
||||
|
||||
<Card>
|
||||
<List />
|
||||
</Card>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
// @mui
|
||||
import { Box, Button, Card, Collapse, IconButton, InputLabel, MenuItem, OutlinedInput, Paper, Select, SelectChangeEvent, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TextField, Typography, Badge, Tab, Tabs, CardHeader, Stack, Menu, ButtonGroup } from '@mui/material';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import UploadIcon from '@mui/icons-material/Upload';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
// hooks
|
||||
import React, { Component, useEffect, useRef, useState } from 'react';
|
||||
import useSettings from '../../../hooks/useSettings';
|
||||
import { useParams, useSearchParams } from 'react-router-dom';
|
||||
// components
|
||||
import axios from '../../../utils/axios';
|
||||
import { LaravelPaginatedData } from '../../../@types/paginated-data';
|
||||
import { Icd } from '../../../@types/diagnosis';
|
||||
|
||||
export default function List() {
|
||||
const { themeStretch } = useSettings();
|
||||
const { corporate_id } = useParams();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [importResult, setImportResult] = useState(null);
|
||||
|
||||
function SearchInput(props: any) {
|
||||
// SEARCH
|
||||
const searchInput = useRef<HTMLInputElement>(null);
|
||||
const [searchText, setSearchText] = useState("");
|
||||
|
||||
const handleSearchChange = (event: any) => {
|
||||
const newSearchText = event.target.value ?? ''
|
||||
setSearchText(newSearchText);
|
||||
}
|
||||
|
||||
const handleSearchSubmit = (event: any) => {
|
||||
event.preventDefault();
|
||||
props.onSearch(searchText); // Trigger to Parent
|
||||
}
|
||||
|
||||
useEffect(() => { // Trigger First Search
|
||||
setSearchText(searchParams.get('search') ?? '');
|
||||
}, [searchParams])
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSearchSubmit} style={{ width: '100%' }}>
|
||||
<TextField id="search-input" ref={searchInput} label="Search" variant="outlined" fullWidth onChange={handleSearchChange} value={searchText}/>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
function ImportForm(props: any) {
|
||||
// IMPORT
|
||||
// Create Button Menu
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
const createMenu = Boolean(anchorEl);
|
||||
const importForm = useRef<HTMLInputElement>(null)
|
||||
const [currentImportFileName, setCurrentImportFileName] = useState(null)
|
||||
|
||||
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const handleImportButton = () => {
|
||||
if (importForm?.current) {
|
||||
handleClose();
|
||||
importForm.current ? importForm.current.click() : console.log('No File selected');
|
||||
} else {
|
||||
alert('No file selected')
|
||||
}
|
||||
}
|
||||
|
||||
const handleCancelImportButton = () => {
|
||||
importForm.current.value = "";
|
||||
importForm.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 (importForm.current?.files.length) {
|
||||
const formData = new FormData();
|
||||
formData.append("file", importForm.current?.files[0])
|
||||
axios.post(`corporates/${corporate_id}/diagnosis-exclusions/import`, formData )
|
||||
.then(response => {
|
||||
handleCancelImportButton();
|
||||
loadDataTableData();
|
||||
setImportResult(response.data)
|
||||
// alert('Succesfully read '+ response.data.total_successed_row + ' with ' + response.data.total_failed_row + ' failed rows');
|
||||
})
|
||||
.catch(response => {
|
||||
alert('Looks like something went wrong. Please check your data and try again. ' + response.message)
|
||||
})
|
||||
} else {
|
||||
alert('No File Selected')
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<input type='file' id='file' ref={importForm} style={{ display: 'none' }} onChange={handleImportChange} accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain" />
|
||||
{( !currentImportFileName && <Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||
<SearchInput onSearch={applyFilter}/>
|
||||
{/* <h1>kjasndkjandskjasndkjansdkjansd</h1> */}
|
||||
<Button
|
||||
id="import-button"
|
||||
variant='outlined'
|
||||
startIcon={<AddIcon />} sx={{ p: 1.8 }}
|
||||
aria-controls={createMenu ? 'basic-menu' : undefined}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={createMenu ? 'true' : undefined}
|
||||
onClick={handleClick}
|
||||
>
|
||||
Import
|
||||
</Button>
|
||||
<Menu
|
||||
id="import-button"
|
||||
anchorEl={anchorEl}
|
||||
open={createMenu}
|
||||
onClose={handleClose}
|
||||
MenuListProps={{
|
||||
'aria-labelledby': 'basic-button',
|
||||
}}
|
||||
>
|
||||
<MenuItem onClick={handleImportButton}>Import</MenuItem>
|
||||
<MenuItem onClick={handleClose}>Download Template</MenuItem>
|
||||
</Menu>
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
{( currentImportFileName && <Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||
<ButtonGroup variant="outlined" aria-label="outlined button group" fullWidth>
|
||||
<Button onClick={handleImportButton} fullWidth>{currentImportFileName ?? "No File Selected"}</Button>
|
||||
<Button onClick={handleCancelImportButton} size="small" fullWidth={false} sx={{ p: 1.8 }}><CancelIcon color="error"/></Button>
|
||||
</ButtonGroup>
|
||||
|
||||
<Button
|
||||
id="upload-button"
|
||||
variant='outlined'
|
||||
startIcon={<UploadIcon />} sx={{ p: 1.8 }}
|
||||
onClick={handleUpload}
|
||||
>
|
||||
Upload
|
||||
</Button>
|
||||
</Stack>
|
||||
)}
|
||||
{( importResult &&
|
||||
<Stack direction={'row'} sx={{ px: 2, pb: 2 }}>
|
||||
<Box sx={{ color: "text.secondary" }}>Last Import Result Report : <a href={importResult.result_file?.url ?? "#"}>{importResult.result_file?.name ?? "-"}</a></Box>
|
||||
</Stack>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Called on every row to map the data to the columns
|
||||
function createData( icd: Icd ): Icd {
|
||||
return {
|
||||
...icd,
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the every row of the table
|
||||
function Row(props: { row: ReturnType<typeof createData> }) {
|
||||
const { row } = props;
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
|
||||
<TableCell>
|
||||
<IconButton
|
||||
aria-label="expand row"
|
||||
size="small"
|
||||
onClick={() => setOpen(!open)}
|
||||
>
|
||||
{open ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
<TableCell align="left">{row.service_code}</TableCell>
|
||||
<TableCell align="left">{row.code}</TableCell>
|
||||
<TableCell align="left">{row.name}</TableCell>
|
||||
<TableCell align="left">{Object.keys(row.rules).length ? 'With Rules' : 'All'}</TableCell>
|
||||
|
||||
<TableCell align="right"><Button variant="outlined" color="success" size="small">Active</Button></TableCell>
|
||||
<TableCell align="right"><Button variant="outlined" color="error" size="small">Disable</Button></TableCell>
|
||||
</TableRow>
|
||||
{/* COLLAPSIBLE ROW */}
|
||||
<TableRow>
|
||||
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={99}>
|
||||
<Collapse in={open} timeout="auto" unmountOnExit>
|
||||
<Box sx={{ borderBottom: 1 }}>
|
||||
{ Object.keys(row.rules).length ? (
|
||||
<div>
|
||||
<Typography variant="body" sx={{ fontWeight: 'bold' }}>
|
||||
Excluded Only for :
|
||||
</Typography>
|
||||
{ row.rules.msc && (<Typography variant="body" component="div">
|
||||
MSC : {row.rules.msc.join(', ') ?? "-"}
|
||||
</Typography> )}
|
||||
{ row.rules.gender && (<Typography variant="body" component="div">
|
||||
Gender : {row.rules.gender.join(', ') ?? "-"}
|
||||
</Typography> )}
|
||||
{ (row.rules.min_age || row.rules.max_age) && (<Typography variant="body" component="div">
|
||||
Age : {row.rules.min_age ?? "-"} - {row.rules.max_age ?? "-"}
|
||||
</Typography> )}
|
||||
{ row.rules.plan && (<Typography variant="body" component="div">
|
||||
Plan : {row.rules.plan.join(', ') ?? "-"}
|
||||
</Typography> )}
|
||||
</div>
|
||||
) : (
|
||||
<Typography variant="body2" gutterBottom component="div">
|
||||
Excluded for All
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</Collapse>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
// Dummy Default Data
|
||||
const [dataTableIsLoading, setDataTableLoading] = useState(true);
|
||||
const [dataTableLastRequest, setDataTableLastRequest] = useState(0);
|
||||
const [dataTableResponseState, setDataTableResponseState] = useState('idle');
|
||||
const [dataTableData, setDataTableData] = useState<LaravelPaginatedData>({
|
||||
current_page: 1,
|
||||
data: [],
|
||||
path: "",
|
||||
first_page_url: "",
|
||||
last_page: 1,
|
||||
last_page_url: "",
|
||||
next_page_url: "",
|
||||
prev_page_url: "",
|
||||
per_page: 10,
|
||||
from: 0,
|
||||
to: 0,
|
||||
total: 0
|
||||
});
|
||||
|
||||
const loadDataTableData = async (appliedFilter : any | null = null) => {
|
||||
setDataTableLoading(true);
|
||||
const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]);
|
||||
const response = await axios.get('/corporates/'+corporate_id+'/diagnosis-exclusions', { params: filter });
|
||||
setDataTableLoading(false);
|
||||
|
||||
setDataTableData(response.data);
|
||||
}
|
||||
|
||||
const headStyle = {
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
|
||||
const applyFilter = async (searchFilter: any) => {
|
||||
await loadDataTableData({ "search" : searchFilter });
|
||||
setSearchParams({ "search" : searchFilter });
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
loadDataTableData();
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<ImportForm />
|
||||
|
||||
<Card>
|
||||
{/* The Main Table */}
|
||||
<TableContainer component={Paper}>
|
||||
<Table aria-label="collapsible table">
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left" />
|
||||
<TableCell style={headStyle} align="left">Service</TableCell>
|
||||
<TableCell style={headStyle} align="left">Code</TableCell>
|
||||
<TableCell style={headStyle} align="left">Name</TableCell>
|
||||
<TableCell style={headStyle} align="left">Rules</TableCell>
|
||||
<TableCell style={headStyle} align="right">Status</TableCell>
|
||||
<TableCell style={headStyle} align="right">Action</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
{dataTableIsLoading ?
|
||||
(
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={8} align="center">Loading</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
dataTableData.data.length == 0 ?
|
||||
(
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={8} align="center">No Data</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
<TableBody>
|
||||
{dataTableData.data.map(row => (
|
||||
<Row key={row.id} row={row} />
|
||||
))}
|
||||
</TableBody>
|
||||
)
|
||||
)}
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Card>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
241
frontend/dashboard/src/pages/Master/Diagnosis/Create.tsx
Normal file
241
frontend/dashboard/src/pages/Master/Diagnosis/Create.tsx
Normal file
@@ -0,0 +1,241 @@
|
||||
import * as Yup from 'yup';
|
||||
import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import { Card, Collapse, Divider, Grid, Stack, Typography } from "@mui/material";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { useParams } from "react-router-dom";
|
||||
import HeaderBreadcrumbs from "../../../components/HeaderBreadcrumbs";
|
||||
import { FormProvider, RHFCheckbox, RHFSelect, RHFTextField } from "../../../components/hook-form";
|
||||
import Page from "../../../components/Page";
|
||||
import useSettings from "../../../hooks/useSettings";
|
||||
import CorporateTabNavigations from "../CorporateTabNavigations";
|
||||
import DivisionsList from "./List";
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
|
||||
|
||||
export default function Divisions() {
|
||||
const { themeStretch } = useSettings();
|
||||
|
||||
const { corporate_id } = useParams();
|
||||
|
||||
const NewDivisionSchema = Yup.object().shape({
|
||||
name: Yup.string().required('Name is required'),
|
||||
code: Yup.string().required('Corporate Code is required'),
|
||||
active: Yup.boolean().required('Corporate Status is required'),
|
||||
});
|
||||
|
||||
const defaultValues = useMemo(
|
||||
() => ({
|
||||
code: '',
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
const methods = useForm({
|
||||
resolver: yupResolver(NewDivisionSchema),
|
||||
defaultValues,
|
||||
});
|
||||
|
||||
const {
|
||||
reset,
|
||||
watch,
|
||||
control,
|
||||
setValue,
|
||||
getValues,
|
||||
setError,
|
||||
handleSubmit,
|
||||
formState: { isSubmitting },
|
||||
} = methods;
|
||||
|
||||
const onSubmit = async (data: any) => {
|
||||
console.log(data);
|
||||
};
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const benefits = [
|
||||
{
|
||||
'category' : 'General Practitioner',
|
||||
'childs' : [
|
||||
{
|
||||
'name' : 'External Doctor Online',
|
||||
'code' : 'gp-external-doctor-online'
|
||||
},
|
||||
{
|
||||
'name' : 'External Doctor Offline',
|
||||
'code' : 'gp-external-doctor-offline'
|
||||
},
|
||||
{
|
||||
'name' : 'Internal Doctor Online',
|
||||
'code' : 'gp-internal-doctor-online'
|
||||
},
|
||||
{
|
||||
'name' : 'Internal Doctor Offline',
|
||||
'code' : 'gp-internal-doctor-offline'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
'category' : 'Specialist',
|
||||
'childs' : [
|
||||
{
|
||||
'name' : 'External Doctor Online',
|
||||
'code' : 'sp-external-doctor-online'
|
||||
},
|
||||
{
|
||||
'name' : 'External Doctor Offline',
|
||||
'code' : 'sp-external-doctor-offline'
|
||||
},
|
||||
{
|
||||
'name' : 'Internal Doctor Online',
|
||||
'code' : 'sp-internal-doctor-online'
|
||||
},
|
||||
{
|
||||
'name' : 'Internal Doctor Offline',
|
||||
'code' : 'sp-internal-doctor-offline'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
'category' : 'Medicines',
|
||||
'childs' : [
|
||||
{
|
||||
'name' : 'Vitamins',
|
||||
'code' : 'medicines-vitamins'
|
||||
},
|
||||
{
|
||||
'name' : 'Delivery Fee',
|
||||
'code' : 'medicines-delivery-fee'
|
||||
},
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
const products = [
|
||||
{
|
||||
'name' : 'Inpatient',
|
||||
'code' : 'IP',
|
||||
},
|
||||
{
|
||||
'name' : 'Outpatient',
|
||||
'code' : 'OP',
|
||||
},
|
||||
{
|
||||
'name' : 'Dental',
|
||||
'code' : 'DT',
|
||||
},
|
||||
{
|
||||
'name' : 'Dental',
|
||||
'code' : 'DTL',
|
||||
},
|
||||
{
|
||||
'name' : 'Matternity',
|
||||
'code' : 'MT',
|
||||
},
|
||||
{
|
||||
'name' : 'Special Benefit',
|
||||
'code' : 'SB',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Page title="Create Benefit">
|
||||
|
||||
<HeaderBreadcrumbs
|
||||
heading={'Create Benefit'}
|
||||
links={[
|
||||
{ name: 'Dashboard', href: '/dashboard' },
|
||||
{
|
||||
name: 'Corporates',
|
||||
href: '/corporates',
|
||||
},
|
||||
{
|
||||
name: 'Corporate Name',
|
||||
href: '/corporates/'+id,
|
||||
},
|
||||
{
|
||||
name: 'Benefits',
|
||||
href: '/corporates/'+id+'/benefits',
|
||||
},
|
||||
{
|
||||
name: 'Create',
|
||||
href: '/corporates/'+id+'/benefits/create',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Card sx={{ p: 2 }}>
|
||||
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||
<Stack spacing={3}>
|
||||
|
||||
<Typography variant="h6">Benefit Detail</Typography>
|
||||
|
||||
<RHFTextField name="name" label="Benefit Name" />
|
||||
|
||||
<RHFTextField name="code" label="Benefit Code" />
|
||||
|
||||
<Typography variant="h6">Benefit Configuration</Typography>
|
||||
|
||||
<Divider orientation="horizontal" flexItem />
|
||||
<Stack spacing={3} divider={<Divider orientation="horizontal" flexItem />}>
|
||||
<Stack spacing={2}>
|
||||
<RHFCheckbox name="a" label='Outpatient'/>
|
||||
{benefits.map(row => (
|
||||
<Collapse in={true} timeout="auto" unmountOnExit >
|
||||
<Typography>{row.category}</Typography>
|
||||
<Grid container>
|
||||
{row.childs.map(benefit => (
|
||||
<Grid item xs={6}>
|
||||
<RHFCheckbox name={benefit.code} label={benefit.name}/>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</Collapse>
|
||||
))}
|
||||
<Typography>Admin Fee</Typography>
|
||||
<Grid container>
|
||||
{benefits.map(row => (
|
||||
<Grid item xs={4}>
|
||||
<RHFCheckbox name="cat" label={row.category}/>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</Stack>
|
||||
|
||||
|
||||
<Stack spacing={2}>
|
||||
<RHFCheckbox name="a" label='Inpatient'/>
|
||||
{benefits.map(row => (
|
||||
<Collapse in={true} timeout="auto" unmountOnExit >
|
||||
<Typography>{row.category}</Typography>
|
||||
<Grid container>
|
||||
{row.childs.map(benefit => (
|
||||
<Grid item xs={6}>
|
||||
<RHFCheckbox name={benefit.code} label={benefit.name}/>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</Collapse>
|
||||
))}
|
||||
<Typography>Admin Fee</Typography>
|
||||
<Grid container>
|
||||
{benefits.map(row => (
|
||||
<Grid item xs={4}>
|
||||
<RHFCheckbox name="cat" label={row.category}/>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
</Stack>
|
||||
</FormProvider>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
38
frontend/dashboard/src/pages/Master/Diagnosis/Index.tsx
Normal file
38
frontend/dashboard/src/pages/Master/Diagnosis/Index.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
import { Card, Grid } from "@mui/material";
|
||||
import { useParams } from "react-router-dom";
|
||||
import HeaderBreadcrumbs from "../../../components/HeaderBreadcrumbs";
|
||||
import Page from "../../../components/Page";
|
||||
import useSettings from "../../../hooks/useSettings";
|
||||
import List from "./List";
|
||||
|
||||
|
||||
|
||||
export default function Divisions() {
|
||||
const { themeStretch } = useSettings();
|
||||
|
||||
const { corporate_id } = useParams();
|
||||
|
||||
const pageTitle = 'Benefit';
|
||||
return (
|
||||
<Page title={ pageTitle }>
|
||||
|
||||
<HeaderBreadcrumbs
|
||||
heading={ pageTitle }
|
||||
links={[
|
||||
{
|
||||
name: 'Master',
|
||||
href: '/master',
|
||||
},
|
||||
{
|
||||
name: 'Diagnosis',
|
||||
href: '/master/diagnosis',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<Card>
|
||||
<List />
|
||||
</Card>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
310
frontend/dashboard/src/pages/Master/Diagnosis/List.tsx
Normal file
310
frontend/dashboard/src/pages/Master/Diagnosis/List.tsx
Normal file
@@ -0,0 +1,310 @@
|
||||
// @mui
|
||||
import { Box, Button, Card, Collapse, IconButton, InputLabel, MenuItem, OutlinedInput, Paper, Select, SelectChangeEvent, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TextField, Typography, Badge, Tab, Tabs, CardHeader, Stack, Menu, ButtonGroup, Pagination } from '@mui/material';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import UploadIcon from '@mui/icons-material/Upload';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
// hooks
|
||||
import React, { ChangeEvent, Component, useEffect, useRef, useState } from 'react';
|
||||
import useSettings from '../../../hooks/useSettings';
|
||||
import { useParams, useSearchParams } from 'react-router-dom';
|
||||
// components
|
||||
import axios from '../../../utils/axios';
|
||||
import { LaravelPaginatedData } from '../../../@types/paginated-data';
|
||||
import { Icd } from '../../../@types/diagnosis';
|
||||
import BasePagination from '../../../components/BasePagination';
|
||||
|
||||
export default function List() {
|
||||
const { themeStretch } = useSettings();
|
||||
const { corporate_id } = useParams();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [importResult, setImportResult] = useState(null);
|
||||
|
||||
function SearchInput(props: any) {
|
||||
// SEARCH
|
||||
const searchInput = useRef<HTMLInputElement>(null);
|
||||
const [searchText, setSearchText] = useState("");
|
||||
|
||||
const handleSearchChange = (event: any) => {
|
||||
const newSearchText = event.target.value ?? ''
|
||||
setSearchText(newSearchText);
|
||||
}
|
||||
|
||||
const handleSearchSubmit = (event: any) => {
|
||||
event.preventDefault();
|
||||
props.onSearch(searchText); // Trigger to Parent
|
||||
}
|
||||
|
||||
useEffect(() => { // Trigger First Search
|
||||
setSearchText(searchParams.get('search') ?? '');
|
||||
}, [searchParams])
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSearchSubmit} style={{ width: '100%' }}>
|
||||
<TextField id="search-input" ref={searchInput} label="Search" variant="outlined" fullWidth onChange={handleSearchChange} value={searchText}/>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
function ImportForm(props: any) {
|
||||
// IMPORT
|
||||
// Create Button Menu
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
const createMenu = Boolean(anchorEl);
|
||||
const importForm = useRef<HTMLInputElement>(null)
|
||||
const [currentImportFileName, setCurrentImportFileName] = useState(null)
|
||||
|
||||
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const handleImportButton = () => {
|
||||
if (importForm?.current) {
|
||||
handleClose();
|
||||
importForm.current ? importForm.current.click() : console.log('No File selected');
|
||||
} else {
|
||||
alert('No file selected')
|
||||
}
|
||||
}
|
||||
|
||||
const handleCancelImportButton = () => {
|
||||
importForm.current.value = "";
|
||||
importForm.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 (importForm.current?.files.length) {
|
||||
const formData = new FormData();
|
||||
formData.append("file", importForm.current?.files[0])
|
||||
axios.post(`corporates/${corporate_id}/import-plan-benefit`, formData )
|
||||
.then(response => {
|
||||
handleCancelImportButton();
|
||||
loadDataTableData();
|
||||
setImportResult(response.data)
|
||||
// alert('Succesfully read '+ response.data.total_successed_row + ' with ' + response.data.total_failed_row + ' failed rows');
|
||||
})
|
||||
.catch(response => {
|
||||
alert('Looks like something went wrong. Please check your data and try again. ' + response.message)
|
||||
})
|
||||
} else {
|
||||
alert('No File Selected')
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<input type='file' id='file' ref={importForm} style={{ display: 'none' }} onChange={handleImportChange} accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain" />
|
||||
{( !currentImportFileName && <Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||
<SearchInput onSearch={applyFilter}/>
|
||||
{/* <h1>kjasndkjandskjasndkjansdkjansd</h1> */}
|
||||
<Button
|
||||
id="import-button"
|
||||
variant='outlined'
|
||||
startIcon={<AddIcon />} sx={{ p: 1.8 }}
|
||||
aria-controls={createMenu ? 'basic-menu' : undefined}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={createMenu ? 'true' : undefined}
|
||||
onClick={handleClick}
|
||||
>
|
||||
Import
|
||||
</Button>
|
||||
<Menu
|
||||
id="import-button"
|
||||
anchorEl={anchorEl}
|
||||
open={createMenu}
|
||||
onClose={handleClose}
|
||||
MenuListProps={{
|
||||
'aria-labelledby': 'basic-button',
|
||||
}}
|
||||
>
|
||||
<MenuItem onClick={handleImportButton}>Import</MenuItem>
|
||||
<MenuItem onClick={handleClose}>Download Template</MenuItem>
|
||||
</Menu>
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
{( currentImportFileName && <Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||
<ButtonGroup variant="outlined" aria-label="outlined button group" fullWidth>
|
||||
<Button onClick={handleImportButton} fullWidth>{currentImportFileName ?? "No File Selected"}</Button>
|
||||
<Button onClick={handleCancelImportButton} size="small" fullWidth={false} sx={{ p: 1.8 }}><CancelIcon color="error"/></Button>
|
||||
</ButtonGroup>
|
||||
|
||||
<Button
|
||||
id="upload-button"
|
||||
variant='outlined'
|
||||
startIcon={<UploadIcon />} sx={{ p: 1.8 }}
|
||||
onClick={handleUpload}
|
||||
>
|
||||
Upload
|
||||
</Button>
|
||||
</Stack>
|
||||
)}
|
||||
{( importResult &&
|
||||
<Stack direction={'row'} sx={{ px: 2, pb: 2 }}>
|
||||
<Box sx={{ color: "text.secondary" }}>Last Import Result Report : <a href={importResult.result_file?.url ?? "#"}>{importResult.result_file?.name ?? "-"}</a></Box>
|
||||
</Stack>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Called on every row to map the data to the columns
|
||||
function createData( icd: Icd ): Icd {
|
||||
return {
|
||||
...icd,
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the every row of the table
|
||||
function Row(props: { row: ReturnType<typeof createData> }) {
|
||||
const { row } = props;
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
|
||||
<TableCell>
|
||||
<IconButton
|
||||
aria-label="expand row"
|
||||
size="small"
|
||||
onClick={() => setOpen(!open)}
|
||||
>
|
||||
{open ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
<TableCell align="left">{row.type}</TableCell>
|
||||
<TableCell align="left">{row.code}</TableCell>
|
||||
<TableCell align="left">{row.name}</TableCell>
|
||||
<TableCell align="left">{row.version}</TableCell>
|
||||
|
||||
<TableCell align="right"><Button variant="outlined" color="success" size="small">Active</Button></TableCell>
|
||||
<TableCell align="right"><Button variant="outlined" color="error" size="small">Disable</Button></TableCell>
|
||||
</TableRow>
|
||||
{/* COLLAPSIBLE ROW */}
|
||||
<TableRow>
|
||||
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={99}>
|
||||
<Collapse in={open} timeout="auto" unmountOnExit>
|
||||
<Box sx={{ borderBottom: 1 }}>
|
||||
<Typography variant="body2" gutterBottom component="div">
|
||||
Description : {row.description}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Collapse>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
// Dummy Default Data
|
||||
const [dataTableIsLoading, setDataTableLoading] = useState(true);
|
||||
const [dataTableLastRequest, setDataTableLastRequest] = useState(0);
|
||||
const [dataTableResponseState, setDataTableResponseState] = useState('idle');
|
||||
const [dataTableData, setDataTableData] = useState<LaravelPaginatedData>({
|
||||
current_page: 1,
|
||||
data: [],
|
||||
path: "",
|
||||
first_page_url: "",
|
||||
last_page: 1,
|
||||
last_page_url: "",
|
||||
next_page_url: "",
|
||||
prev_page_url: "",
|
||||
per_page: 10,
|
||||
from: 0,
|
||||
to: 0,
|
||||
total: 0
|
||||
});
|
||||
const [dataTablePage, setDataTablePage] = useState(5);
|
||||
|
||||
const loadDataTableData = async (appliedFilter : any | null = null) => {
|
||||
setDataTableLoading(true);
|
||||
const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]);
|
||||
const response = await axios.get('/master/diagnosis', { params: filter });
|
||||
// console.log(response.data);
|
||||
setDataTableLoading(false);
|
||||
|
||||
setDataTableData(response.data);
|
||||
}
|
||||
|
||||
const headStyle = {
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
|
||||
const applyFilter = async (searchFilter: any) => {
|
||||
await loadDataTableData({ "search" : searchFilter });
|
||||
setSearchParams({ "search" : searchFilter });
|
||||
}
|
||||
|
||||
const handlePageChange = (event : ChangeEvent, value: number) => {
|
||||
const filter = Object.fromEntries([...searchParams.entries(), ["page", value]]);
|
||||
loadDataTableData(filter);
|
||||
setSearchParams(filter);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
loadDataTableData();
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<ImportForm />
|
||||
|
||||
<Card>
|
||||
{/* The Main Table */}
|
||||
<TableContainer component={Paper}>
|
||||
<Table aria-label="collapsible table">
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left" />
|
||||
<TableCell style={headStyle} align="left">Type</TableCell>
|
||||
<TableCell style={headStyle} align="left">Code</TableCell>
|
||||
<TableCell style={headStyle} align="left">Name</TableCell>
|
||||
<TableCell style={headStyle} align="left">Version</TableCell>
|
||||
<TableCell style={headStyle} align="right">Status</TableCell>
|
||||
<TableCell style={headStyle} align="right">Action</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
{dataTableIsLoading ?
|
||||
(
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={8} align="center">Loading</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
dataTableData.data.length == 0 ?
|
||||
(
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={8} align="center">No Data</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
<TableBody>
|
||||
{dataTableData.data.map(row => (
|
||||
<Row key={row.id} row={row} />
|
||||
))}
|
||||
</TableBody>
|
||||
)
|
||||
)}
|
||||
</Table>
|
||||
</TableContainer>
|
||||
|
||||
<BasePagination paginationData={dataTableData} onPageChange={handlePageChange}/>
|
||||
</Card>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -95,6 +95,7 @@ export default function Router() {
|
||||
path: 'corporates/:corporate_id/edit',
|
||||
element: <CorporateCreate />,
|
||||
},
|
||||
|
||||
{
|
||||
path: 'corporates/:corporate_id/divisions',
|
||||
element: <CorporateDivisions />,
|
||||
@@ -107,10 +108,12 @@ export default function Router() {
|
||||
path: 'corporates/:corporate_id/divisions/:id/edit',
|
||||
element: <CorporateDivisionsCreate />,
|
||||
},
|
||||
|
||||
{
|
||||
path: 'corporates/:corporate_id/members',
|
||||
element: <CorporateMembers />,
|
||||
},
|
||||
|
||||
{
|
||||
path: 'corporates/:corporate_id/plans/create',
|
||||
element: <PlanCreate />,
|
||||
@@ -119,6 +122,7 @@ export default function Router() {
|
||||
path: 'corporates/:corporate_id/plans',
|
||||
element: <Plans />,
|
||||
},
|
||||
|
||||
{
|
||||
path: 'corporates/:corporate_id/corporate-plans/create',
|
||||
element: <CorporatePlanCreate />,
|
||||
@@ -131,6 +135,7 @@ export default function Router() {
|
||||
path: 'corporates/:corporate_id/corporate-plans',
|
||||
element: <CorporatePlans />,
|
||||
},
|
||||
|
||||
{
|
||||
path: 'corporates/:corporate_id/benefits/create',
|
||||
element: <BenefitCreate />,
|
||||
@@ -139,6 +144,7 @@ export default function Router() {
|
||||
path: 'corporates/:corporate_id/benefits',
|
||||
element: <Benefits />,
|
||||
},
|
||||
|
||||
{
|
||||
path: 'corporates/:corporate_id/corporate-benefits/create',
|
||||
element: <CorporateBenefitsCreate />,
|
||||
@@ -151,6 +157,16 @@ export default function Router() {
|
||||
path: 'corporates/:corporate_id/corporate-benefits/:id/edit',
|
||||
element: <CorporateBenefitsCreate />,
|
||||
},
|
||||
|
||||
{
|
||||
path: 'corporates/:corporate_id/diagnosis-exclusions',
|
||||
element: <DiagnosisExclusions />,
|
||||
},
|
||||
|
||||
{
|
||||
path: 'master/diagnosis',
|
||||
element: <MasterDiagnosis />,
|
||||
},
|
||||
]
|
||||
},
|
||||
// {
|
||||
@@ -216,3 +232,7 @@ const CorporatePlans = Loadable(lazy(() => import('../pages/Corporates/Corporate
|
||||
|
||||
const PlanCreate = Loadable(lazy(() => import('../pages/Corporates/Plan/Create')));
|
||||
const Plans = Loadable(lazy(() => import('../pages/Corporates/Plan/Index')));
|
||||
|
||||
const DiagnosisExclusions = Loadable(lazy(() => import('../pages/Corporates/DiagnosisExclusion/Index')));
|
||||
|
||||
const MasterDiagnosis = Loadable(lazy(() => import('../pages/Master/Diagnosis/Index')));
|
||||
|
||||
18555
resources/files/ICD-X-Halodoc.csv
Normal file
18555
resources/files/ICD-X-Halodoc.csv
Normal file
File diff suppressed because it is too large
Load Diff
@@ -15,4 +15,3 @@ use Illuminate\Support\Facades\Route;
|
||||
| is assigned the "api" middleware group. Enjoy building your API!
|
||||
|
|
||||
*/
|
||||
|
||||
|
||||
Reference in New Issue
Block a user