Update Hospitals Corporate Bisa Import

This commit is contained in:
ivan-sim
2023-11-09 11:36:10 +07:00
parent a9929ad7a2
commit 7cd4f2c929
6 changed files with 282 additions and 23 deletions

View File

@@ -145,7 +145,7 @@ class DrugController extends Controller
}
$response = [
'message' => 'File uploaded and data saved to database!',
'message' => 'File uploaded and data saved to database',
'data' => [
'total_success_row' => $importedRows,
'total_failed_row' => count($failedRows),

View File

@@ -8,6 +8,8 @@ use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\DB;
use App\Helpers\Helper;
use Maatwebsite\Excel\Facades\Excel;
class HospitalController extends Controller
{
@@ -150,4 +152,93 @@ class HospitalController extends Controller
{
//
}
public function downloadTemplate()
{
return Helper::responseJson([
'file_name' => "Template - Hospitals.xlsx",
"file_url" => url('files/Template - Hospitals.xlsx')
]);
}
public function import(Request $request, $corporate_id)
{
if ($request->hasFile('file')) {
$file = $request->file('file');
$data = Excel::toArray([], $file);
$processedData = $this->processCategoryNames($data);
$importedRows = 0;
$failedRows = [];
foreach ($processedData as $row) {
$q = DB::table('organizations')
->where('code', '=', $row['code'])
->where('type', '=', 'hospital')
->where('status', '=', 'active')
->select('id', 'code', 'name')
->limit(1)
->first();
try {
CorporateHospital::create(
[
'corporate_id' => $corporate_id,
'code' => $q->code,
'name' => $q->name,
'organization_id' => $q->id,
'description' => $request->description ? $request->description : null,
]
);
$importedRows++;
} catch (\Exception $e) {
$failedRows[] = $row;
}
}
$response = [
'message' => 'File uploaded and data saved to database',
'data' => [
'total_success_row' => $importedRows,
'total_failed_row' => count($failedRows),
'failed_rows' => $failedRows,
],
];
return response()->json($response);
}
return response()->json(['error' => 'No file uploaded.']);
}
private function processCategoryNames($data)
{
$header = [];
$row = [];
for ($i = 1; $i < count($data[0]); $i++) {
$row[] = $data[0][$i];
$header[] = $data[0][0];
}
$filed = [];
foreach ($header[0] as $value)
{
$modelColumn = strtolower(preg_replace('/\s+/', '_', trim($value)));
$modelColumn = str_replace(['*', ' '], '', $modelColumn);
if($modelColumn)
{
$filed[] = $modelColumn;
}
}
$result = [];
foreach ($row as $subarray) {
$trimmedSubarray = [];
for ($i = 0; $i < count($filed); $i++) {
$trimmedSubarray[$filed[$i]] = $subarray[$i] ? $subarray[$i] : null;
}
$result[] = $trimmedSubarray;
}
return $result;
}
}

View File

@@ -109,6 +109,8 @@ Route::prefix('internal')->group(function () {
Route::get('corporates/{corporate_id}/hospitals/data', [HospitalController::class, 'dataHospital']);
Route::post('corporates/{corporate_id}/hospitals/save', [HospitalController::class, 'store']);
Route::put('corporates/{corporate_id}/hospitals/{id}/edit', [HospitalController::class, 'update']);
Route::get('corporates/hospitals/download-template', [HospitalController::class, 'downloadTemplate']);
Route::post('corporates/{corporate_id}/hospitals/import', [HospitalController::class, 'import']);
Route::get('corporates/{corporate_id}/members', [CorporateMemberController::class, 'index']);

View File

@@ -20,6 +20,8 @@ import {
InputLabel,
Select,
FormHelperText,
Menu,
ButtonGroup
} from '@mui/material';
import AddIcon from '@mui/icons-material/Add';
// hooks
@@ -39,6 +41,10 @@ import { Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material
import CloseIcon from '@mui/icons-material/Close';
import { enqueueSnackbar } from 'notistack';
import Label from '../../../components/Label';
import DownloadIcon from '@mui/icons-material/Download';
import { LoadingButton } from '@mui/lab';
import CancelIcon from '@mui/icons-material/Cancel';
import UploadIcon from '@mui/icons-material/Upload';
export default function HospitalList() {
const { corporate_id } = useParams();
@@ -267,22 +273,182 @@ export default function HospitalList() {
}
// End dialog for update status devisions
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const createMenu = Boolean(anchorEl);
const importHospital = useRef<HTMLInputElement>(null);
const [currentImportFileName, setCurrentImportFileName] = useState(null);
const [importLoading, setImportLoading] = useState(false);
const [importResult, setImportResult] = useState(null);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const handleImportButton = () => {
if (importHospital?.current) {
handleClose();
importHospital.current ? importHospital.current.click() : console.log('No File selected');
} else {
alert('No file selected');
}
};
const handleCancelImportButton = () => {
if(importHospital.current)
{
importHospital.current.value = '';
importHospital.current.dispatchEvent(new Event('change', { bubbles: true }));
}
};
const handleImportChange = (event: any) => {
if (event.target.files[0]) {
setCurrentImportFileName(event.target.files[0].name);
} else {
setCurrentImportFileName(null);
}
};
const handleUpload = () => {
if(importHospital.current && importHospital.current.files)
{
if (importHospital.current?.files.length) {
const formData = new FormData();
formData.append('file', importHospital.current?.files[0]);
setImportLoading(true);
axios
.post('corporates/'+corporate_id+'/hospitals/import', formData)
.then((response) => {
handleCancelImportButton();
loadDataTableData();
setImportResult(response.data);
setImportLoading(false);
enqueueSnackbar('Success Import Hospitals', { variant: 'success' });
})
.catch((response) => {
enqueueSnackbar(
'Looks like something went wrong. Please check your data and try again. ' +
response.message,
{ variant: 'error' }
);
setImportLoading(false);
});
} else {
enqueueSnackbar('No File Selected', { variant: 'warning' });
}
}
};
const handleGetTemplate = () => {
axios.get('corporates/hospitals/download-template').then((response) => {
const link = document.createElement('a');
link.href = response.data.data.file_url;
link.setAttribute('download', response.data.data.file_name);
document.body.appendChild(link);
link.click();
handleClose();
});
};
return (
<Stack>
<Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
<SearchInput onSearch={applyFilter} />
<Button
component="button"
id="upload-button"
startIcon={<AddIcon />}
sx={{ p: 1.8, color: '#FFFFFF', backgroundColor: '#19BBBB', width: '125px', height: '48px' }}
onClick={handleAddData}
>
Create
</Button>
</Stack>
<input
type="file"
id="file"
ref={importHospital}
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} />
<Button
id="import-button"
startIcon={<DownloadIcon />}
sx={{ p: 1.8, color: '#FFFFFF', backgroundColor: '#19BBBB', width: '125px', height: '48px' }}
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={handleAddData}>
<Typography variant='body2'>Create</Typography>
</MenuItem>
<MenuItem onClick={handleImportButton}>
<Typography variant='body2'>Import</Typography>
</MenuItem>
<MenuItem
onClick={() => {
handleGetTemplate();
}}
>
<Typography variant='body2'> Download Template</Typography>
</MenuItem>
{/* <MenuItem onClick={handleICDList}>
<Typography variant='body2'>Download ICD</Typography>
</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>
<LoadingButton
id="upload-button"
variant="outlined"
startIcon={<UploadIcon />}
sx={{ p: 1.8 }}
onClick={handleUpload}
loading={importLoading}
>
Upload
</LoadingButton>
</Stack>
)}
{importResult && (
<Stack direction={'row'} sx={{ px: 2, pb: 2 }}>
<Box sx={{ color: 'text.secondary' }}>
Last Import Result :{' '}
<Box sx={{ color: 'success.main', display: 'inline' }}>
{importResult.data.total_success_row ?? 0}
</Box>{' '}
Row Processed,{' '}
<Box sx={{ color: 'error.main', display: 'inline' }}>
{importResult.data.total_failed_row}
</Box>{' '}
Failed
{importResult.data.failed_rows.map((row, index) => (
<Typography variant='body' key={index} color="error"> [Code={row.code ? row.code : 'Required'},Name={row.name ? row.name : 'Required'}]</Typography>
))}
</Box>
</Stack>
)}
<Card>
{/* The Main Table */}
<TableContainer component={Paper}>

View File

@@ -98,7 +98,7 @@ import {
// Create Button Menu
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const createMenu = Boolean(anchorEl);
const importPlan = useRef<HTMLInputElement>(null);
const importDrug = useRef<HTMLInputElement>(null);
const [currentImportFileName, setCurrentImportFileName] = useState(null);
const [importLoading, setImportLoading] = useState(false);
@@ -111,19 +111,19 @@ import {
};
const handleImportButton = () => {
if (importPlan?.current) {
if (importDrug?.current) {
handleClose();
importPlan.current ? importPlan.current.click() : console.log('No File selected');
importDrug.current ? importDrug.current.click() : console.log('No File selected');
} else {
alert('No file selected');
}
};
const handleCancelImportButton = () => {
if(importPlan.current)
if(importDrug.current)
{
importPlan.current.value = '';
importPlan.current.dispatchEvent(new Event('change', { bubbles: true }));
importDrug.current.value = '';
importDrug.current.dispatchEvent(new Event('change', { bubbles: true }));
}
};
@@ -136,11 +136,11 @@ import {
};
const handleUpload = () => {
if(importPlan.current && importPlan.current.files)
if(importDrug.current && importDrug.current.files)
{
if (importPlan.current?.files.length) {
if (importDrug.current?.files.length) {
const formData = new FormData();
formData.append('file', importPlan.current?.files[0]);
formData.append('file', importDrug.current?.files[0]);
setImportLoading(true);
axios
.post(`master/drugs/import`, formData)
@@ -181,7 +181,7 @@ import {
<input
type="file"
id="file"
ref={importPlan}
ref={importDrug}
style={{ display: 'none' }}
onChange={handleImportChange}
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain"

Binary file not shown.