Merge branch 'feature/report-primayan'
This commit is contained in:
@@ -0,0 +1,502 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Internal\Http\Controllers\Api;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Corporate;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Alignment;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Border;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Fill;
|
||||
|
||||
class PrimayanMedicareController extends Controller
|
||||
{
|
||||
/**
|
||||
* List transactions for Primayan Medicare (corporate code: PRAY)
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$limit = $request->has('per_page') ? $request->input('per_page') : 10;
|
||||
|
||||
$corporate = Corporate::where('code', 'PRAY')->first();
|
||||
|
||||
if (!$corporate) {
|
||||
return response()->json([
|
||||
'message' => 'Corporate Primayan Medicare (PRAY) not found',
|
||||
'data' => []
|
||||
], 404);
|
||||
}
|
||||
|
||||
// Subquery to aggregate amounts from request_log_benefits
|
||||
$subQueryAmount = DB::table('request_log_benefits')
|
||||
->select('request_log_id',
|
||||
DB::raw('SUM(amount_incurred) as total_incurred'),
|
||||
DB::raw('SUM(amount_approved) as total_approved'),
|
||||
DB::raw('SUM(excess_paid) as total_excess'))
|
||||
->whereNull('deleted_at')
|
||||
->groupBy('request_log_id');
|
||||
|
||||
$query = DB::table('claim_requests')
|
||||
->join('members', 'claim_requests.member_id', '=', 'members.id')
|
||||
->join('corporate_employees', 'corporate_employees.member_id', '=', 'members.id')
|
||||
->leftJoin('organizations', 'claim_requests.organization_id', '=', 'organizations.id')
|
||||
->leftJoin('claims', 'claim_requests.claim_id', '=', 'claims.id')
|
||||
->leftJoin('request_logs', 'claim_requests.request_log_id', '=', 'request_logs.id')
|
||||
->leftJoinSub($subQueryAmount, 'log_amounts', function ($join) {
|
||||
$join->on('request_logs.id', '=', 'log_amounts.request_log_id');
|
||||
})
|
||||
->leftJoin('plans', 'claims.plan_id', '=', 'plans.id')
|
||||
->leftJoin('benefits', 'claims.benefit_id', '=', 'benefits.id')
|
||||
->where('corporate_employees.corporate_id', $corporate->id)
|
||||
->whereNull('corporate_employees.deleted_at')
|
||||
->whereNull('claim_requests.deleted_at')
|
||||
->when($request->input('search'), function ($query, $search) {
|
||||
$query->where(function ($query) use ($search) {
|
||||
$query->orWhere('members.name', 'like', "%" . $search . "%")
|
||||
->orWhere('members.member_id', 'like', "%" . $search . "%")
|
||||
->orWhere('claim_requests.code', 'like', "%" . $search . "%")
|
||||
->orWhere('request_logs.code', 'like', "%" . $search . "%")
|
||||
->orWhere('claims.code', 'like', "%" . $search . "%")
|
||||
->orWhere('corporate_employees.nik', 'like', "%" . $search . "%");
|
||||
});
|
||||
})
|
||||
->when($request->input('start_date'), function ($query, $start_date) {
|
||||
$query->where('claim_requests.created_at', '>=', $start_date);
|
||||
})
|
||||
->when($request->input('end_date'), function ($query, $end_date) {
|
||||
$query->where('claim_requests.created_at', '<=', $end_date . ' 23:59:59');
|
||||
})
|
||||
->when($request->input('status'), function ($query, $status) {
|
||||
if ($status !== 'all') {
|
||||
$query->where('claim_requests.status', $status);
|
||||
}
|
||||
})
|
||||
->when($request->input('provider_id'), function ($query, $provider_id) {
|
||||
if ($provider_id !== 'all') {
|
||||
$query->where('claim_requests.organization_id', $provider_id);
|
||||
}
|
||||
})
|
||||
->select(
|
||||
'claim_requests.id',
|
||||
'claim_requests.code as request_code',
|
||||
'claim_requests.status',
|
||||
'claim_requests.created_at as request_date',
|
||||
'claim_requests.service_code',
|
||||
'request_logs.log_type',
|
||||
'claims.code as claim_code',
|
||||
'request_logs.code as log_code',
|
||||
DB::raw('COALESCE(log_amounts.total_incurred, claims.amount_incurred, 0) as amount_incurred'),
|
||||
DB::raw('COALESCE(log_amounts.total_approved, claims.amount_approved, 0) as amount_approved'),
|
||||
DB::raw('COALESCE(claims.amount_not_approved, 0) as amount_not_approved'),
|
||||
DB::raw('COALESCE(log_amounts.total_excess, claims.excess_paid, 0) as excess_paid'),
|
||||
'claims.benefit_code',
|
||||
'claims.benefit_desc',
|
||||
'members.name as member_name',
|
||||
'members.member_id as member_number',
|
||||
'members.birth_date',
|
||||
'members.gender',
|
||||
'corporate_employees.nik',
|
||||
'corporate_employees.branch_code',
|
||||
'organizations.name as provider_name',
|
||||
'plans.code as plan_code',
|
||||
'benefits.code as benefit_code_ref'
|
||||
)
|
||||
->orderBy('claim_requests.created_at', 'desc');
|
||||
|
||||
$results = $query->paginate($limit)->appends($request->all());
|
||||
|
||||
// Get Providers for filter
|
||||
$providers = DB::table('claim_requests')
|
||||
->join('members', 'claim_requests.member_id', '=', 'members.id')
|
||||
->join('corporate_employees', 'corporate_employees.member_id', '=', 'members.id')
|
||||
->join('organizations', 'claim_requests.organization_id', '=', 'organizations.id')
|
||||
->where('corporate_employees.corporate_id', $corporate->id)
|
||||
->whereNull('claim_requests.deleted_at')
|
||||
->select('organizations.id', 'organizations.name')
|
||||
->groupBy('organizations.id', 'organizations.name')
|
||||
->get();
|
||||
|
||||
return Helper::responseJson([
|
||||
'results' => Helper::paginateResources($results),
|
||||
'providers' => $providers,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Export transactions to Excel
|
||||
*/
|
||||
public function export(Request $request)
|
||||
{
|
||||
$corporate = Corporate::where('code', 'PRAY')->first();
|
||||
|
||||
if (!$corporate) {
|
||||
return response()->json([
|
||||
'message' => 'Corporate Primayan Medicare (PRAY) not found',
|
||||
], 404);
|
||||
}
|
||||
|
||||
$exportType = $request->input('export_type', 'list');
|
||||
|
||||
if ($exportType === 'summary') {
|
||||
return $this->exportSummary($corporate);
|
||||
}
|
||||
|
||||
// Subquery to aggregate amounts from request_log_benefits
|
||||
$subQueryAmount = DB::table('request_log_benefits')
|
||||
->select('request_log_id',
|
||||
DB::raw('SUM(amount_incurred) as total_incurred'),
|
||||
DB::raw('SUM(amount_approved) as total_approved'),
|
||||
DB::raw('SUM(excess_paid) as total_excess'))
|
||||
->whereNull('deleted_at')
|
||||
->groupBy('request_log_id');
|
||||
|
||||
$results = DB::table('claim_requests')
|
||||
->join('members', 'claim_requests.member_id', '=', 'members.id')
|
||||
->join('corporate_employees', 'corporate_employees.member_id', '=', 'members.id')
|
||||
->leftJoin('organizations', 'claim_requests.organization_id', '=', 'organizations.id')
|
||||
->leftJoin('claims', 'claim_requests.claim_id', '=', 'claims.id')
|
||||
->leftJoin('request_logs', 'claim_requests.request_log_id', '=', 'request_logs.id')
|
||||
->leftJoinSub($subQueryAmount, 'log_amounts', function ($join) {
|
||||
$join->on('request_logs.id', '=', 'log_amounts.request_log_id');
|
||||
})
|
||||
->leftJoin('plans', 'claims.plan_id', '=', 'plans.id')
|
||||
->leftJoin('benefits', 'claims.benefit_id', '=', 'benefits.id')
|
||||
->where('corporate_employees.corporate_id', $corporate->id)
|
||||
->whereNull('corporate_employees.deleted_at')
|
||||
->whereNull('claim_requests.deleted_at')
|
||||
->when($request->input('search'), function ($query, $search) {
|
||||
$query->where(function ($query) use ($search) {
|
||||
$query->orWhere('members.name', 'like', "%" . $search . "%")
|
||||
->orWhere('members.member_id', 'like', "%" . $search . "%")
|
||||
->orWhere('claim_requests.code', 'like', "%" . $search . "%")
|
||||
->orWhere('request_logs.code', 'like', "%" . $search . "%")
|
||||
->orWhere('claims.code', 'like', "%" . $search . "%")
|
||||
->orWhere('corporate_employees.nik', 'like', "%" . $search . "%");
|
||||
});
|
||||
})
|
||||
->when($request->input('start_date'), function ($query, $start_date) {
|
||||
$query->where('claim_requests.created_at', '>=', $start_date);
|
||||
})
|
||||
->when($request->input('end_date'), function ($query, $end_date) {
|
||||
$query->where('claim_requests.created_at', '<=', $end_date . ' 23:59:59');
|
||||
})
|
||||
->when($request->input('status'), function ($query, $status) {
|
||||
if ($status !== 'all') {
|
||||
$query->where('claim_requests.status', $status);
|
||||
}
|
||||
})
|
||||
->when($request->input('provider_id'), function ($query, $provider_id) {
|
||||
if ($provider_id !== 'all') {
|
||||
$query->where('claim_requests.organization_id', $provider_id);
|
||||
}
|
||||
})
|
||||
->select(
|
||||
'claim_requests.id',
|
||||
'claim_requests.code as request_code',
|
||||
'claim_requests.status',
|
||||
'claim_requests.created_at as request_date',
|
||||
'claim_requests.service_code',
|
||||
'request_logs.log_type',
|
||||
'claims.code as claim_code',
|
||||
'request_logs.code as log_code',
|
||||
DB::raw('COALESCE(log_amounts.total_incurred, claims.amount_incurred, 0) as amount_incurred'),
|
||||
DB::raw('COALESCE(log_amounts.total_approved, claims.amount_approved, 0) as amount_approved'),
|
||||
DB::raw('COALESCE(claims.amount_not_approved, 0) as amount_not_approved'),
|
||||
DB::raw('COALESCE(log_amounts.total_excess, claims.excess_paid, 0) as excess_paid'),
|
||||
'claims.benefit_code',
|
||||
'claims.benefit_desc',
|
||||
'members.name as member_name',
|
||||
'members.member_id as member_number',
|
||||
'members.birth_date',
|
||||
'members.gender',
|
||||
'corporate_employees.nik',
|
||||
'corporate_employees.branch_code',
|
||||
'organizations.name as provider_name',
|
||||
'plans.code as plan_code',
|
||||
'benefits.code as benefit_code_ref'
|
||||
)
|
||||
->orderBy('claim_requests.created_at', 'desc')
|
||||
->get();
|
||||
|
||||
$fileName = 'PrimayanMedicare-List-' . now()->format('Y-m-d_H-i-s') . '.xlsx';
|
||||
$filePath = storage_path('app/public/temp/' . $fileName);
|
||||
|
||||
if (!is_dir(storage_path('app/public/temp'))) {
|
||||
mkdir(storage_path('app/public/temp'), 0755, true);
|
||||
}
|
||||
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
|
||||
$serviceCodeMap = [
|
||||
'OP' => 'Outpatient',
|
||||
'IP' => 'Inpatient',
|
||||
'DE' => 'Dental',
|
||||
'MA' => 'Maternal',
|
||||
'GL' => 'Optical',
|
||||
'MCU' => 'Medical Check Up',
|
||||
'MEDIVAC' => 'Medical Emergency Evacuation',
|
||||
];
|
||||
|
||||
$headers = [
|
||||
'No',
|
||||
'Code Claim / Code LOG',
|
||||
'Member Name',
|
||||
'Member Number',
|
||||
'NIK',
|
||||
'Birth Date',
|
||||
'Gender',
|
||||
'Plan',
|
||||
'Benefit',
|
||||
'Service',
|
||||
'Tipe LOG',
|
||||
'Provider',
|
||||
'Request Date',
|
||||
'Amount Incurred',
|
||||
'Amount Approved',
|
||||
'Amount Not Approved',
|
||||
'Excess Paid',
|
||||
'Status',
|
||||
];
|
||||
|
||||
$sheet->fromArray($headers, null, 'A1');
|
||||
$sheet->getStyle('A1:R1')->applyFromArray([
|
||||
'font' => [
|
||||
'bold' => true,
|
||||
],
|
||||
'alignment' => [
|
||||
'horizontal' => Alignment::HORIZONTAL_CENTER,
|
||||
]
|
||||
]);
|
||||
|
||||
$rowIndex = 2;
|
||||
$no = 1;
|
||||
|
||||
$logTypeMap = [
|
||||
'reference' => 'Rujukan',
|
||||
'prescription' => 'Resep',
|
||||
'consultation' => 'Konsultasi',
|
||||
];
|
||||
|
||||
foreach ($results as $item) {
|
||||
$logTypeName = $logTypeMap[$item->log_type] ?? $item->log_type ?? '-';
|
||||
|
||||
$rowData = [
|
||||
$no++,
|
||||
($item->claim_code && $item->log_code)
|
||||
? $item->claim_code . ' / ' . $item->log_code
|
||||
: ($item->claim_code ?? $item->log_code ?? $item->request_code ?? '-'),
|
||||
$item->member_name ?? '-',
|
||||
$item->member_number ?? '-',
|
||||
$item->nik ?? '-',
|
||||
$item->birth_date ?? '-',
|
||||
$item->gender ?? '-',
|
||||
$item->plan_code ?? '-',
|
||||
$item->benefit_name ?? $item->benefit_desc ?? '-',
|
||||
$item->service_code ?? '-',
|
||||
$logTypeName,
|
||||
$item->provider_name ?? '-',
|
||||
$item->request_date ?? '-',
|
||||
(int)($item->amount_incurred ?? 0),
|
||||
(int)($item->amount_approved ?? 0),
|
||||
(int)($item->amount_not_approved ?? 0),
|
||||
(int)($item->excess_paid ?? 0),
|
||||
$item->status ?? '-',
|
||||
];
|
||||
|
||||
$sheet->fromArray($rowData, null, 'A' . $rowIndex);
|
||||
$rowIndex++;
|
||||
}
|
||||
|
||||
foreach (range('A', 'R') as $col) {
|
||||
$sheet->getColumnDimension($col)->setAutoSize(true);
|
||||
}
|
||||
|
||||
$writer = new Xlsx($spreadsheet);
|
||||
$writer->save($filePath);
|
||||
|
||||
return Helper::responseJson([
|
||||
'file_name' => 'Primayan Medicare List ' . now()->format('Y-m-d H:i:s'),
|
||||
'file_url' => Storage::disk('public')->url('temp/' . $fileName),
|
||||
]);
|
||||
}
|
||||
|
||||
private function exportSummary($corporate)
|
||||
{
|
||||
// Get all branch codes
|
||||
$branches = DB::table('corporate_employees')
|
||||
->where('corporate_id', $corporate->id)
|
||||
->whereNull('deleted_at')
|
||||
->select('branch_code')
|
||||
->groupBy('branch_code')
|
||||
->get();
|
||||
|
||||
$fileName = 'PrimayanMedicare-Summary-' . now()->format('Y-m-d_H-i-s') . '.xlsx';
|
||||
$filePath = storage_path('app/public/temp/' . $fileName);
|
||||
|
||||
if (!is_dir(storage_path('app/public/temp'))) {
|
||||
mkdir(storage_path('app/public/temp'), 0755, true);
|
||||
}
|
||||
|
||||
$codeRSMap = [
|
||||
'AI' => 'ABI', 'BB' => 'PHBB', 'BT' => 'PHBT', 'BU' => 'PHBU',
|
||||
'BW' => 'PHBW', 'CI' => 'PHPC', 'CO' => 'FABS', 'DE' => 'PHDE',
|
||||
'EV' => 'PHEV', 'HE' => 'PHHE', 'KG' => 'PHKG', 'KI' => 'KMI',
|
||||
'KR' => 'PHKA', 'KV' => 'KAVA', 'LM' => 'LMS', 'LY' => 'LYNAS',
|
||||
'MK' => 'PHMA', 'MS' => 'EYEQU', 'PF' => 'FMC', 'PS' => 'PHPK',
|
||||
'PY' => 'PHBP', 'RA' => 'PHRA', 'SB' => 'PHSB', 'SF' => 'SFI',
|
||||
'SG' => 'PHSM', 'SM' => 'SIM', 'SO' => 'PHSW', 'SS' => 'SAS',
|
||||
'TG' => 'PHTA', 'UP' => 'UKRIDA', 'WS' => 'WEST'
|
||||
];
|
||||
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
|
||||
// Header Date Range (Row 1)
|
||||
$dateRange = now()->startOfMonth()->format('j F') . ' - ' . now()->format('j F Y');
|
||||
$sheet->setCellValue('A1', strtoupper($dateRange));
|
||||
$sheet->mergeCells('A1:B1');
|
||||
$sheet->getStyle('A1')->applyFromArray([
|
||||
'font' => [
|
||||
'bold' => true,
|
||||
],
|
||||
'alignment' => [
|
||||
'horizontal' => Alignment::HORIZONTAL_CENTER,
|
||||
]
|
||||
]);
|
||||
|
||||
// Table Headers (Row 3)
|
||||
$headers = ['Code RS', 'Branch Code', 'Total Benefit', 'Deposit 10%', 'Pemakaian Benefit Obat & Rujukan', 'Pemakaian Telekonsultasi', 'Sisa Deposit'];
|
||||
$sheet->fromArray($headers, null, 'A3');
|
||||
$sheet->getStyle('A3:G3')->applyFromArray([
|
||||
'font' => [
|
||||
'bold' => true,
|
||||
],
|
||||
'fill' => [
|
||||
'fillType' => Fill::FILL_SOLID,
|
||||
'startColor' => [
|
||||
'rgb' => 'C6E0B4'
|
||||
]
|
||||
],
|
||||
'borders' => [
|
||||
'allBorders' => [
|
||||
'borderStyle' => Border::BORDER_THIN,
|
||||
]
|
||||
],
|
||||
'alignment' => [
|
||||
'horizontal' => Alignment::HORIZONTAL_CENTER,
|
||||
]
|
||||
]);
|
||||
|
||||
$row = 4;
|
||||
foreach ($branches as $branch) {
|
||||
$branchCode = $branch->branch_code ?? '-';
|
||||
$codeRS = $codeRSMap[$branchCode] ?? '-';
|
||||
|
||||
$totalDeposit = DB::table('corporate_employees')
|
||||
->join('member_plans', 'corporate_employees.member_id', '=', 'member_plans.member_id')
|
||||
->join('plans', 'member_plans.plan_id', '=', 'plans.id')
|
||||
->where('corporate_employees.corporate_id', $corporate->id)
|
||||
->where(function($query) use ($branchCode) {
|
||||
if ($branchCode === '-') {
|
||||
$query->whereNull('corporate_employees.branch_code')->orWhere('corporate_employees.branch_code', '');
|
||||
} else {
|
||||
$query->where('corporate_employees.branch_code', $branchCode);
|
||||
}
|
||||
})
|
||||
->whereNull('corporate_employees.deleted_at')
|
||||
->whereNull('member_plans.deleted_at')
|
||||
->sum(DB::raw('CAST(plans.limit_rules as UNSIGNED)'));
|
||||
|
||||
$deposit10 = $totalDeposit * 0.1;
|
||||
|
||||
$usageMedicines = DB::table('request_log_medicines')
|
||||
->join('request_logs', 'request_log_medicines.request_log_id', '=', 'request_logs.id')
|
||||
->join('corporate_employees', 'request_logs.member_id', '=', 'corporate_employees.member_id')
|
||||
->where('corporate_employees.corporate_id', $corporate->id)
|
||||
->where(function($query) use ($branchCode) {
|
||||
if ($branchCode === '-') {
|
||||
$query->whereNull('corporate_employees.branch_code')->orWhere('corporate_employees.branch_code', '');
|
||||
} else {
|
||||
$query->where('corporate_employees.branch_code', $branchCode);
|
||||
}
|
||||
})
|
||||
->whereIn('request_logs.log_type', ['prescription', 'reference'])
|
||||
->sum('request_log_medicines.price');
|
||||
|
||||
$consultationCount = DB::table('request_logs')
|
||||
->join('corporate_employees', 'request_logs.member_id', '=', 'corporate_employees.member_id')
|
||||
->where('corporate_employees.corporate_id', $corporate->id)
|
||||
->where(function($query) use ($branchCode) {
|
||||
if ($branchCode === '-') {
|
||||
$query->whereNull('corporate_employees.branch_code')
|
||||
->orWhere('corporate_employees.branch_code', '');
|
||||
} else {
|
||||
$query->where('corporate_employees.branch_code', $branchCode);
|
||||
}
|
||||
})
|
||||
->where('request_logs.log_type', 'consultation')
|
||||
->count();
|
||||
|
||||
$usageConsultation = $consultationCount * 11100;
|
||||
$remainingDeposit = $deposit10 - $usageMedicines - $usageConsultation;
|
||||
|
||||
$sheet->setCellValue('A' . $row, $codeRS);
|
||||
$sheet->setCellValue('B' . $row, $branchCode);
|
||||
$sheet->setCellValue('C' . $row, $totalDeposit);
|
||||
$sheet->setCellValue('D' . $row, $deposit10);
|
||||
$sheet->setCellValue('E' . $row, $usageMedicines);
|
||||
$sheet->setCellValue('F' . $row, $usageConsultation);
|
||||
$sheet->setCellValue('G' . $row, $remainingDeposit);
|
||||
|
||||
// Number format with thousand separator
|
||||
$sheet->getStyle('C' . $row . ':G' . $row)->getNumberFormat()->setFormatCode('#,##0');
|
||||
|
||||
$row++;
|
||||
}
|
||||
|
||||
$lastRow = $row - 1;
|
||||
foreach (range('A', 'G') as $col) {
|
||||
$sheet->getColumnDimension($col)->setAutoSize(true);
|
||||
}
|
||||
|
||||
$sheet->getStyle('A3:G' . $lastRow)->applyFromArray([
|
||||
'borders' => [
|
||||
'allBorders' => [
|
||||
'borderStyle' => Border::BORDER_THIN,
|
||||
'color' => ['rgb' => '000000']
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$sheet->freezePane('A4');
|
||||
|
||||
$sheet->setCellValue('E1', '=SUM(E4:E' . $lastRow . ')');
|
||||
$sheet->setCellValue('F1', '=SUM(F4:F' . $lastRow . ')');
|
||||
$sheet->getStyle('E1:F1')
|
||||
->getNumberFormat()
|
||||
->setFormatCode('#,##0');
|
||||
$sheet->getStyle('E1:F1')->applyFromArray([
|
||||
'font' => [
|
||||
'bold' => true,
|
||||
'size' => 12,
|
||||
],
|
||||
'alignment' => [
|
||||
'horizontal' => Alignment::HORIZONTAL_CENTER,
|
||||
]
|
||||
]);
|
||||
|
||||
$writer = new Xlsx($spreadsheet);
|
||||
$writer->save($filePath);
|
||||
|
||||
return Helper::responseJson([
|
||||
'file_name' => $fileName,
|
||||
'file_url' => Storage::disk('public')->url('temp/' . $fileName),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -62,6 +62,7 @@ use Modules\Primaya\Http\Controllers\Api\MasterController;
|
||||
|
||||
// Report
|
||||
use Modules\Internal\Http\Controllers\Api\ReportLogController;
|
||||
use Modules\Internal\Http\Controllers\Api\PrimayanMedicareController;
|
||||
|
||||
|
||||
/*
|
||||
@@ -112,6 +113,10 @@ Route::prefix('internal')->group(function () {
|
||||
Route::get('linksehat/rujukan', [RujukanController::class, 'index']);
|
||||
Route::get('linksehat/rujukan/generate-excel', [RujukanController::class, 'generateExcel']);
|
||||
|
||||
// Report Primayan Medicare
|
||||
Route::get('primayan-medicare', [PrimayanMedicareController::class, 'index']);
|
||||
Route::get('primayan-medicare/export', [PrimayanMedicareController::class, 'export']);
|
||||
|
||||
Route::post('logout', [AuthController::class, 'logout'])->name('logout');
|
||||
Route::get('/user', function (Request $request) {
|
||||
return $request->user();
|
||||
|
||||
@@ -16,9 +16,10 @@ class NavigationSeeder extends Seeder
|
||||
public function run()
|
||||
{
|
||||
$menuItems = [
|
||||
// DOCTORS & HOSPITALS
|
||||
// Dashboard
|
||||
[
|
||||
'title' => 'Dashboard',
|
||||
'urutan' => 1,
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'Dashboard',
|
||||
@@ -31,6 +32,7 @@ class NavigationSeeder extends Seeder
|
||||
// DOCTORS & HOSPITALS
|
||||
[
|
||||
'title' => 'DOCTORS & HOSPITALS',
|
||||
'urutan' => 2,
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'Doctors',
|
||||
@@ -48,6 +50,7 @@ class NavigationSeeder extends Seeder
|
||||
// PHARMACY & DELIVERY MANAGEMENT
|
||||
[
|
||||
'title' => 'PHARMACY & DELIVERY MANAGEMENT',
|
||||
'urutan' => 3,
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'Drug',
|
||||
@@ -70,6 +73,7 @@ class NavigationSeeder extends Seeder
|
||||
// STATION BENEFIT & MEMBERSHIP
|
||||
[
|
||||
'title' => 'STATION BENEFIT & MEMBERSHIP',
|
||||
'urutan' => 4,
|
||||
'openWhen' => ['/corporates', '/formularium', '/diagnosis', '/hospitals'],
|
||||
'children' => [
|
||||
[
|
||||
@@ -77,7 +81,6 @@ class NavigationSeeder extends Seeder
|
||||
'path' => '/corporates',
|
||||
'permission' => 'corporate-list',
|
||||
],
|
||||
// ['title' => 'Corporate Create', 'path' => '/corporates/create'],
|
||||
[
|
||||
'title' => 'Formularium',
|
||||
'path' => '/master/formularium-template-v2',
|
||||
@@ -96,28 +99,33 @@ class NavigationSeeder extends Seeder
|
||||
],
|
||||
'permission' => null
|
||||
],
|
||||
// CLAIM REQUEST
|
||||
// MASTER
|
||||
[
|
||||
'title' => 'CLAIM REQUEST',
|
||||
'path' => '/claim-requests',
|
||||
'title' => 'MASTER',
|
||||
'urutan' => 5,
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'CLAIM REQUEST',
|
||||
'path' => '/claim-requests',
|
||||
'permission' => 'claim-request-list'
|
||||
'title' => 'Diagnosis',
|
||||
'path' => '/master/diagnosis',
|
||||
'permission' => 'diagnosis-list'
|
||||
],
|
||||
],
|
||||
'permission' => null
|
||||
],
|
||||
// CLAIM MANAGEMENT
|
||||
// CUSTOMER SERVICES
|
||||
[
|
||||
'title' => 'CLAIM MANAGEMENT',
|
||||
'path' => '/claims',
|
||||
'title' => 'CUSTOMER SERVICES',
|
||||
'urutan' => 6,
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'CLAIM MANAGEMENT',
|
||||
'path' => '/claims',
|
||||
'permission' => 'claim-management-list'
|
||||
'title' => 'Request',
|
||||
'path' => '/custormer-service/request',
|
||||
'permission' => 'request-log-list'
|
||||
],
|
||||
[
|
||||
'title' => 'Final LOG',
|
||||
'path' => '/custormer-service/final-log',
|
||||
'permission' => 'final-log-list'
|
||||
],
|
||||
],
|
||||
'permission' => null
|
||||
@@ -125,13 +133,13 @@ class NavigationSeeder extends Seeder
|
||||
// CASE MANAGEMENT
|
||||
[
|
||||
'title' => 'CASE MANAGEMENT',
|
||||
'urutan' => 7,
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'Daily Monitoring',
|
||||
'path' => '/case_management/daily_monitoring',
|
||||
'permission' => 'daily-monitoring-list'
|
||||
],
|
||||
// ['title' => 'Laboratorium Result', 'path' => '/case_management/laboratorium_result'],
|
||||
[
|
||||
'title' => 'Inpatient Monitoring',
|
||||
'path' => '/case_management/inpatient_monitoring',
|
||||
@@ -145,9 +153,56 @@ class NavigationSeeder extends Seeder
|
||||
],
|
||||
'permission' => null
|
||||
],
|
||||
// Invoice
|
||||
// CLAIM REQUEST
|
||||
[
|
||||
'title' => 'CLAIM REQUEST',
|
||||
'urutan' => 8,
|
||||
'path' => '/claim-requests',
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'CLAIM REQUEST',
|
||||
'path' => '/claim-requests',
|
||||
'permission' => 'claim-request-list'
|
||||
],
|
||||
],
|
||||
'permission' => null
|
||||
],
|
||||
// CLAIM MANAGEMENT
|
||||
[
|
||||
'title' => 'CLAIM MANAGEMENT',
|
||||
'urutan' => 9,
|
||||
'path' => '/claims',
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'CLAIM MANAGEMENT',
|
||||
'path' => '/claims',
|
||||
'permission' => 'claim-management-list'
|
||||
],
|
||||
],
|
||||
'permission' => null
|
||||
],
|
||||
// USER MANAGEMENT
|
||||
[
|
||||
'title' => 'USER MANAGEMENT',
|
||||
'urutan' => 10,
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'User Role',
|
||||
'path' => '/user-role',
|
||||
'permission' => 'user-role-list'
|
||||
],
|
||||
[
|
||||
'title' => 'User Access',
|
||||
'path' => '/user-access',
|
||||
'permission' => 'user-access-list'
|
||||
],
|
||||
],
|
||||
'permission' => null
|
||||
],
|
||||
// INVOICE
|
||||
[
|
||||
'title' => 'INVOICE',
|
||||
'urutan' => 11,
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'Invoice',
|
||||
@@ -157,79 +212,78 @@ class NavigationSeeder extends Seeder
|
||||
],
|
||||
'permission' => null
|
||||
],
|
||||
// CUSTOMER SERVICES
|
||||
[
|
||||
'title' => 'CUSTOMER SERVICES',
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'Request',
|
||||
'path' => '/custormer-service/request',
|
||||
'permission' => 'request-log-list'
|
||||
],
|
||||
// ['title' => 'Membership', 'path' => '/cs-membership'],
|
||||
[
|
||||
'title' => 'Final LOG',
|
||||
'path' => '/custormer-service/final-log',
|
||||
'permission' => 'final-log-list'
|
||||
],
|
||||
],
|
||||
'permission' => null
|
||||
],
|
||||
// REPORT
|
||||
[
|
||||
'title' => 'REPORT',
|
||||
'urutan' => 12,
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'Files Provider',
|
||||
'path' => 'report/files-provider',
|
||||
'permission' => 'report-files-provider-list'
|
||||
'permission' => 'report-files-provider-list',
|
||||
'urutan' => 1,
|
||||
],
|
||||
[
|
||||
'title' => 'Letter of Guarantee',
|
||||
'path' => '/report/logs',
|
||||
'permission' => 'report-log-list'
|
||||
'permission' => 'report-log-list',
|
||||
'urutan' => 2,
|
||||
],
|
||||
[
|
||||
'title' => 'Appointment',
|
||||
'path' => '/report/appointments',
|
||||
'permission' => 'report-appointment-list'
|
||||
'permission' => 'report-appointment-list',
|
||||
'urutan' => 3,
|
||||
],
|
||||
[
|
||||
'title' => 'Live Chat',
|
||||
'path' => '/report/live-chat',
|
||||
'permission' => 'report-livechat-list'
|
||||
'permission' => 'report-livechat-list',
|
||||
'urutan' => 4,
|
||||
],
|
||||
[
|
||||
'title' => 'Linksehat Payment',
|
||||
'path' => '/report/linksehat-payments',
|
||||
'permission' => 'report-livechat-payment'
|
||||
'permission' => 'report-livechat-payment',
|
||||
'urutan' => 5,
|
||||
],
|
||||
[
|
||||
'title' => 'Prescription',
|
||||
'path' => '/report/prescription',
|
||||
'permission' => 'report-prescription'
|
||||
'permission' => 'report-prescription',
|
||||
'urutan' => 6,
|
||||
],
|
||||
[
|
||||
'title' => 'Doctor Rating',
|
||||
'path' => '/report/doctor-rating',
|
||||
'permission' => 'report-doctor-rating'
|
||||
'permission' => 'report-doctor-rating',
|
||||
'urutan' => 7,
|
||||
],
|
||||
[
|
||||
'title' => 'Doctor Online',
|
||||
'path' => '/report/doctor-online',
|
||||
'permission' => 'report-doctor-online'
|
||||
'permission' => 'report-doctor-online',
|
||||
'urutan' => 8,
|
||||
],
|
||||
[
|
||||
'title' => 'Katalog Dokter',
|
||||
'path' => '/report/katalog-dokter',
|
||||
'permission' => 'report-katalog-dokter'
|
||||
]
|
||||
'permission' => 'report-katalog-dokter',
|
||||
'urutan' => 9,
|
||||
],
|
||||
[
|
||||
'title' => 'Primayan Medicare',
|
||||
'path' => '/report/primayan-medicare',
|
||||
'permission' => 'report-primayan-medicare',
|
||||
'urutan' => 10,
|
||||
],
|
||||
],
|
||||
'permission' => null
|
||||
],
|
||||
// MASTER
|
||||
[
|
||||
'title' => 'MASTER',
|
||||
'urutan' => 11,
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'Diagnosis',
|
||||
@@ -242,6 +296,7 @@ class NavigationSeeder extends Seeder
|
||||
// USER MANAGEMENT
|
||||
[
|
||||
'title' => 'USER MANAGEMENT',
|
||||
'urutan' => 9,
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'User Role',
|
||||
@@ -259,12 +314,14 @@ class NavigationSeeder extends Seeder
|
||||
// LINKING TOOLS
|
||||
[
|
||||
'title' => 'LINKING TOOLS',
|
||||
'urutan' => 13,
|
||||
'path' => '/linking',
|
||||
'permission' => 'linkking-list'
|
||||
],
|
||||
// E-PRESCRIPTION
|
||||
[
|
||||
'title' => 'E-PRESCRIPTION',
|
||||
'urutan' => 14,
|
||||
'path' => '/e-prescription/live-chat',
|
||||
'permission' => 'prescription-list'
|
||||
],
|
||||
@@ -370,7 +427,8 @@ class NavigationSeeder extends Seeder
|
||||
'title' => $menuItemData['title'],
|
||||
'path' => $menuItemData['path'] ?? null,
|
||||
'icon' => $menuItemData['icon'] ?? null,
|
||||
'permission' => $menuItemData['permission'] ?? null
|
||||
'permission' => $menuItemData['permission'] ?? null,
|
||||
'urutan' => $menuItemData['urutan'] ?? null
|
||||
]);
|
||||
|
||||
if (isset($menuItemData['children'])) {
|
||||
@@ -384,7 +442,8 @@ class NavigationSeeder extends Seeder
|
||||
'path' => $childData['path'] ?? null,
|
||||
'icon' => $childData['icon'] ?? null,
|
||||
'parent_id' => $menuItem->id,
|
||||
'permission' => $childData['permission'] ?? null
|
||||
'permission' => $childData['permission'] ?? null,
|
||||
'urutan' => $childData['urutan'] ?? null
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ class PermissionTableSeeder extends Seeder
|
||||
'report-livechat-list',
|
||||
'report-livechat-payment',
|
||||
'report-doctor-rating',
|
||||
'report-primayan-medicare',
|
||||
'report-doctor-online',
|
||||
'report-prescription',
|
||||
'user-role-list',
|
||||
|
||||
@@ -106,6 +106,7 @@ const navConfig = [
|
||||
{ title: 'Linksehat Payment', path: '/report/linksehat-payments' },
|
||||
// { title: 'Prescription', path: '/report/prescription' },
|
||||
{ title: 'Doctor Rating', path: '/report/doctor-rating' },
|
||||
{ title: 'Primayan Medicare', path: '/report/primayan-medicare' },
|
||||
|
||||
],
|
||||
},
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import { Container } from '@mui/material';
|
||||
import HeaderBreadcrumbs from '../../../components/HeaderBreadcrumbs';
|
||||
import Page from '../../../components/Page';
|
||||
import useSettings from '../../../hooks/useSettings';
|
||||
import List from './List';
|
||||
|
||||
export default function PrimayanMedicare() {
|
||||
const { themeStretch } = useSettings();
|
||||
|
||||
const pageTitle = 'Primayan Medicare';
|
||||
return (
|
||||
<Page title={pageTitle}>
|
||||
<Container maxWidth={themeStretch ? false : 'xl'}>
|
||||
<HeaderBreadcrumbs
|
||||
heading={pageTitle}
|
||||
links={[
|
||||
{
|
||||
name: 'Report',
|
||||
href: '/report',
|
||||
},
|
||||
{
|
||||
name: 'Primayan Medicare',
|
||||
href: '/report/primayan-medicare',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<List />
|
||||
</Container>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
415
frontend/dashboard/src/pages/Report/PrimayanMedicare/List.tsx
Normal file
415
frontend/dashboard/src/pages/Report/PrimayanMedicare/List.tsx
Normal file
@@ -0,0 +1,415 @@
|
||||
import {
|
||||
Card,
|
||||
Grid,
|
||||
Paper,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableRow,
|
||||
TextField,
|
||||
Stack,
|
||||
Chip,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
Select,
|
||||
MenuItem,
|
||||
Menu,
|
||||
} from '@mui/material';
|
||||
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import React, { ChangeEvent, useEffect, useRef, useState } from 'react';
|
||||
import axios from '../../../utils/axios';
|
||||
import { LaravelPaginatedData } from '../../../@types/paginated-data';
|
||||
import BasePagination from '../../../components/BasePagination';
|
||||
import { fNumber } from '@/utils/formatNumber';
|
||||
import { fDateOnly } from '@/utils/formatTime';
|
||||
import { DesktopDatePicker, LocalizationProvider } from '@mui/x-date-pickers';
|
||||
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import UploadIcon from '@mui/icons-material/Upload';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const statusColors: Record<string, 'default' | 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning'> = {
|
||||
draft: 'default',
|
||||
requested: 'info',
|
||||
received: 'primary',
|
||||
approved: 'success',
|
||||
postpone: 'warning',
|
||||
paid: 'success',
|
||||
declined: 'error',
|
||||
};
|
||||
|
||||
const logTypeMap: Record<string, string> = {
|
||||
reference: 'Rujukan',
|
||||
prescription: 'Resep',
|
||||
consultation: 'Konsultasi',
|
||||
};
|
||||
|
||||
const logTypeColors: Record<string, 'default' | 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning'> = {
|
||||
reference: 'secondary',
|
||||
prescription: 'warning',
|
||||
consultation: 'info',
|
||||
};
|
||||
|
||||
export default function List() {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [providers, setProviders] = useState<any[]>([]);
|
||||
|
||||
function Filter() {
|
||||
const searchInput = useRef<HTMLInputElement>(null);
|
||||
const [searchText, setSearchText] = useState('');
|
||||
const [exportLoading, setExportLoading] = useState(false);
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
const exportMenuOpen = Boolean(anchorEl);
|
||||
|
||||
const handleExportClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
const handleExportClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const handleExport = (exportType: string) => {
|
||||
const parameters = Object.fromEntries([...searchParams.entries()]);
|
||||
setExportLoading(true);
|
||||
axios
|
||||
.get('/primayan-medicare/export', {
|
||||
params: { ...parameters, export_type: exportType },
|
||||
})
|
||||
.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();
|
||||
handleExportClose();
|
||||
setExportLoading(false);
|
||||
})
|
||||
.catch(() => {
|
||||
setExportLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
const handleSearchChange = (event: any) => {
|
||||
setSearchText(event.target.value ?? '');
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setSearchText(searchParams.get('search') ?? '');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<form style={{ width: '100%' }}>
|
||||
<Grid container spacing={2} sx={{ alignItems: 'center' }}>
|
||||
<Grid item xs={12} md={2.4}>
|
||||
<TextField
|
||||
id="search-input"
|
||||
ref={searchInput}
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
onChange={handleSearchChange}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
const filter = Object.fromEntries([
|
||||
...searchParams.entries(),
|
||||
['search', searchText],
|
||||
['page', '1'],
|
||||
]);
|
||||
setSearchParams(filter);
|
||||
loadDataTableData(filter);
|
||||
}
|
||||
}}
|
||||
label="Search"
|
||||
value={searchText}
|
||||
InputProps={{
|
||||
placeholder: 'Nama, Member ID',
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} md={2}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel>Status</InputLabel>
|
||||
<Select
|
||||
value={searchParams.get('status') ?? 'all'}
|
||||
label="Status"
|
||||
onChange={(el) => {
|
||||
const filter = Object.fromEntries([
|
||||
...searchParams.entries(),
|
||||
['status', el.target.value],
|
||||
['page', '1'],
|
||||
]);
|
||||
setSearchParams(filter);
|
||||
loadDataTableData(filter);
|
||||
}}
|
||||
>
|
||||
<MenuItem value={'all'}>Semua</MenuItem>
|
||||
<MenuItem value={'draft'}>Draft</MenuItem>
|
||||
<MenuItem value={'requested'}>Requested</MenuItem>
|
||||
<MenuItem value={'received'}>Received</MenuItem>
|
||||
<MenuItem value={'approved'}>Approved</MenuItem>
|
||||
<MenuItem value={'postpone'}>Postpone</MenuItem>
|
||||
<MenuItem value={'paid'}>Paid</MenuItem>
|
||||
<MenuItem value={'declined'}>Declined</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} md={2}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel>Provider</InputLabel>
|
||||
<Select
|
||||
value={searchParams.get('provider_id') ?? 'all'}
|
||||
label="Provider"
|
||||
onChange={(el) => {
|
||||
const filter = Object.fromEntries([
|
||||
...searchParams.entries(),
|
||||
['provider_id', el.target.value],
|
||||
['page', '1'],
|
||||
]);
|
||||
setSearchParams(filter);
|
||||
loadDataTableData(filter);
|
||||
}}
|
||||
>
|
||||
<MenuItem value={'all'}>Semua</MenuItem>
|
||||
{providers.map((provider) => (
|
||||
<MenuItem key={provider.id} value={provider.id}>
|
||||
{provider.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} md={2}>
|
||||
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
||||
<DesktopDatePicker
|
||||
value={searchParams.get('start_date') || null}
|
||||
inputFormat="dd/MM/yyyy"
|
||||
onChange={(value) => {
|
||||
try {
|
||||
if (value && !!Date.parse(value)) {
|
||||
const date = fDateOnly(value);
|
||||
let entries = [...searchParams.entries(), ['start_date', date ?? '']];
|
||||
if (!searchParams.get('end_date')) {
|
||||
entries = [...entries, ['end_date', date ?? '']];
|
||||
}
|
||||
const filter = Object.fromEntries([...entries, ['page', '1']]);
|
||||
setSearchParams(filter);
|
||||
loadDataTableData(filter);
|
||||
}
|
||||
} catch (e) {}
|
||||
}}
|
||||
renderInput={(params) => <TextField {...params} fullWidth label="Start Date" />}
|
||||
/>
|
||||
</LocalizationProvider>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} md={2}>
|
||||
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
||||
<DesktopDatePicker
|
||||
value={searchParams.get('end_date') || null}
|
||||
inputFormat="dd/MM/yyyy"
|
||||
onChange={(value) => {
|
||||
try {
|
||||
if (value && !!Date.parse(value)) {
|
||||
const date = fDateOnly(value);
|
||||
let entries = [...searchParams.entries(), ['end_date', date ?? '']];
|
||||
if (!searchParams.get('start_date')) {
|
||||
entries = [...entries, ['start_date', date ?? '']];
|
||||
}
|
||||
const filter = Object.fromEntries([...entries, ['page', '1']]);
|
||||
setSearchParams(filter);
|
||||
loadDataTableData(filter);
|
||||
}
|
||||
} catch (e) {}
|
||||
}}
|
||||
renderInput={(params) => <TextField {...params} fullWidth label="End Date" />}
|
||||
/>
|
||||
</LocalizationProvider>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} md={1.6}>
|
||||
<LoadingButton
|
||||
variant="outlined"
|
||||
startIcon={<UploadIcon />}
|
||||
fullWidth
|
||||
sx={{ height: '56px' }}
|
||||
onClick={handleExportClick}
|
||||
loading={exportLoading}
|
||||
>
|
||||
Export
|
||||
</LoadingButton>
|
||||
<Menu
|
||||
id="export-menu"
|
||||
anchorEl={anchorEl}
|
||||
open={exportMenuOpen}
|
||||
onClose={handleExportClose}
|
||||
MenuListProps={{
|
||||
'aria-labelledby': 'export-button',
|
||||
}}
|
||||
>
|
||||
<MenuItem onClick={() => handleExport('list')}>Download List Excel</MenuItem>
|
||||
<MenuItem onClick={() => handleExport('summary')}>Download Summary Excel</MenuItem>
|
||||
</Menu>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
function FilterForm() {
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
spacing={2}
|
||||
sx={{ p: 2, justifyContent: 'space-between', alignItems: 'center' }}
|
||||
>
|
||||
<Grid item xs={12} md={12} lg={12}>
|
||||
<Filter />
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
function Row(props: { row: any }) {
|
||||
const { row } = props;
|
||||
|
||||
return (
|
||||
<TableRow>
|
||||
<TableCell align="left">
|
||||
{(row.claim_code || row.request_code) && row.log_code
|
||||
? `${row.claim_code ?? row.request_code} / ${row.log_code}`
|
||||
: row.claim_code ?? row.request_code ?? row.log_code ?? '-'}
|
||||
</TableCell>
|
||||
<TableCell align="left">{row.member_name ?? '-'}</TableCell>
|
||||
<TableCell align="left">{row.member_number ?? '-'}</TableCell>
|
||||
<TableCell align="left">{row.service_code ?? '-'}</TableCell>
|
||||
<TableCell align="left">
|
||||
{row.log_type ? (
|
||||
<Chip
|
||||
label={logTypeMap[row.log_type] ?? row.log_type}
|
||||
color={logTypeColors[row.log_type] ?? 'default'}
|
||||
size="small"
|
||||
/>
|
||||
) : (
|
||||
'-'
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell align="left">{row.provider_name ?? '-'}</TableCell>
|
||||
<TableCell align="left">{row.request_date ?? '-'}</TableCell>
|
||||
<TableCell align="right">{fNumber(parseInt(row.amount_incurred ?? 0))}</TableCell>
|
||||
<TableCell align="right">{fNumber(parseInt(row.amount_approved ?? 0))}</TableCell>
|
||||
<TableCell align="right">{fNumber(parseInt(row.excess_paid ?? 0))}</TableCell>
|
||||
<TableCell align="center">
|
||||
<Chip
|
||||
label={row.status ?? '-'}
|
||||
color={statusColors[row.status] ?? 'default'}
|
||||
size="small"
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
|
||||
const headStyle = {
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
|
||||
const [dataTableIsLoading, setDataTableLoading] = useState(true);
|
||||
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()]);
|
||||
try {
|
||||
const response = await axios.get('/primayan-medicare', {
|
||||
params: filter,
|
||||
});
|
||||
setDataTableData(response.data.data.results);
|
||||
setProviders(response.data.data.providers);
|
||||
} catch (error) {
|
||||
console.error('Failed to load Primayan Medicare data:', error);
|
||||
}
|
||||
setDataTableLoading(false);
|
||||
};
|
||||
|
||||
const handlePageChange = (event: ChangeEvent, value: number) => {
|
||||
const filter = Object.fromEntries([...searchParams.entries(), ['page', value]]);
|
||||
loadDataTableData(filter);
|
||||
setSearchParams(filter);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadDataTableData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<Card sx={{ marginTop: '30px' }}>
|
||||
<FilterForm />
|
||||
|
||||
<TableContainer component={Paper}>
|
||||
<Table>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">Code Claim / Code LOG</TableCell>
|
||||
<TableCell style={headStyle} align="left">Nama Member</TableCell>
|
||||
<TableCell style={headStyle} align="left">Member ID</TableCell>
|
||||
<TableCell style={headStyle} align="left">Service</TableCell>
|
||||
<TableCell style={headStyle} align="left">Tipe LOG</TableCell>
|
||||
<TableCell style={headStyle} align="left">Provider</TableCell>
|
||||
<TableCell style={headStyle} align="left">Tanggal Request</TableCell>
|
||||
<TableCell style={headStyle} align="right">Amount Incurred</TableCell>
|
||||
<TableCell style={headStyle} align="right">Amount Approved</TableCell>
|
||||
<TableCell style={headStyle} align="right">Excess Paid</TableCell>
|
||||
<TableCell style={headStyle} align="center">Status</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
{dataTableIsLoading ? (
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={11} align="center">
|
||||
Loading
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : dataTableData.data.length === 0 ? (
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={11} align="center">
|
||||
No Data
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
<TableBody>
|
||||
{dataTableData.data.map((row, index) => (
|
||||
<Row key={row.id ?? index} row={row} />
|
||||
))}
|
||||
</TableBody>
|
||||
)}
|
||||
</Table>
|
||||
</TableContainer>
|
||||
|
||||
<BasePagination paginationData={dataTableData} onPageChange={handlePageChange} />
|
||||
</Card>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -471,6 +471,10 @@ export default function Router() {
|
||||
path: 'report/linksehat-payments',
|
||||
element: <LinksehatPayment />,
|
||||
},
|
||||
{
|
||||
path: 'report/primayan-medicare',
|
||||
element: <PrimayanMedicare />,
|
||||
},
|
||||
|
||||
{
|
||||
path: 'report/phr',
|
||||
@@ -770,6 +774,8 @@ const EPrescriptionShow = Loadable(lazy(() => import('../pages/EPrescription/Liv
|
||||
|
||||
const LinksehatPayment = Loadable(lazy(() => import('../pages/Report/LinksehatPayments/Index')));
|
||||
|
||||
const PrimayanMedicare = Loadable(lazy(() => import('../pages/Report/PrimayanMedicare/Index')));
|
||||
|
||||
const RiwayatMedisPeserta = Loadable(lazy(() => import('../pages/Report/RiwayatMedisPeserta/Index')));
|
||||
const RujukanPasien = Loadable(lazy(() => import('../pages/Report/Rujukan/Index')));
|
||||
const Prescription = Loadable(lazy(() => import('../pages/Report/Prescription/Index')));
|
||||
|
||||
Reference in New Issue
Block a user