diff --git a/Modules/Internal/Http/Controllers/Api/PrimayanMedicareController.php b/Modules/Internal/Http/Controllers/Api/PrimayanMedicareController.php
new file mode 100644
index 00000000..89048047
--- /dev/null
+++ b/Modules/Internal/Http/Controllers/Api/PrimayanMedicareController.php
@@ -0,0 +1,502 @@
+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),
+ ]);
+ }
+}
diff --git a/Modules/Internal/Routes/api.php b/Modules/Internal/Routes/api.php
index 48d8f406..509c540e 100755
--- a/Modules/Internal/Routes/api.php
+++ b/Modules/Internal/Routes/api.php
@@ -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();
diff --git a/database/seeders/NavigationSeeder.php b/database/seeders/NavigationSeeder.php
index 55cb5d42..6f7e7b42 100644
--- a/database/seeders/NavigationSeeder.php
+++ b/database/seeders/NavigationSeeder.php
@@ -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
]);
}
}
diff --git a/database/seeders/PermissionTableSeeder.php b/database/seeders/PermissionTableSeeder.php
index 75da78fd..4f317935 100644
--- a/database/seeders/PermissionTableSeeder.php
+++ b/database/seeders/PermissionTableSeeder.php
@@ -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',
diff --git a/frontend/dashboard/src/layouts/dashboard/navbar/NavConfig.tsx b/frontend/dashboard/src/layouts/dashboard/navbar/NavConfig.tsx
index 5add5536..1dae1e2f 100644
--- a/frontend/dashboard/src/layouts/dashboard/navbar/NavConfig.tsx
+++ b/frontend/dashboard/src/layouts/dashboard/navbar/NavConfig.tsx
@@ -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' },
],
},
diff --git a/frontend/dashboard/src/pages/Report/PrimayanMedicare/Index.tsx b/frontend/dashboard/src/pages/Report/PrimayanMedicare/Index.tsx
new file mode 100644
index 00000000..c888da30
--- /dev/null
+++ b/frontend/dashboard/src/pages/Report/PrimayanMedicare/Index.tsx
@@ -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 (
+
+
+
+
+
+
+
+ );
+}
diff --git a/frontend/dashboard/src/pages/Report/PrimayanMedicare/List.tsx b/frontend/dashboard/src/pages/Report/PrimayanMedicare/List.tsx
new file mode 100644
index 00000000..c9123d47
--- /dev/null
+++ b/frontend/dashboard/src/pages/Report/PrimayanMedicare/List.tsx
@@ -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 = {
+ draft: 'default',
+ requested: 'info',
+ received: 'primary',
+ approved: 'success',
+ postpone: 'warning',
+ paid: 'success',
+ declined: 'error',
+};
+
+const logTypeMap: Record = {
+ reference: 'Rujukan',
+ prescription: 'Resep',
+ consultation: 'Konsultasi',
+};
+
+const logTypeColors: Record = {
+ reference: 'secondary',
+ prescription: 'warning',
+ consultation: 'info',
+};
+
+export default function List() {
+ const [searchParams, setSearchParams] = useSearchParams();
+ const [providers, setProviders] = useState([]);
+
+ function Filter() {
+ const searchInput = useRef(null);
+ const [searchText, setSearchText] = useState('');
+ const [exportLoading, setExportLoading] = useState(false);
+ const [anchorEl, setAnchorEl] = React.useState(null);
+ const exportMenuOpen = Boolean(anchorEl);
+
+ const handleExportClick = (event: React.MouseEvent) => {
+ 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 (
+
+ );
+ }
+
+ function FilterForm() {
+ return (
+
+
+
+
+
+ );
+ }
+
+ function Row(props: { row: any }) {
+ const { row } = props;
+
+ return (
+
+
+ {(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 ?? '-'}
+
+ {row.member_name ?? '-'}
+ {row.member_number ?? '-'}
+ {row.service_code ?? '-'}
+
+ {row.log_type ? (
+
+ ) : (
+ '-'
+ )}
+
+ {row.provider_name ?? '-'}
+ {row.request_date ?? '-'}
+ {fNumber(parseInt(row.amount_incurred ?? 0))}
+ {fNumber(parseInt(row.amount_approved ?? 0))}
+ {fNumber(parseInt(row.excess_paid ?? 0))}
+
+
+
+
+ );
+ }
+
+ const headStyle = {
+ fontWeight: 'bold',
+ };
+
+ const [dataTableIsLoading, setDataTableLoading] = useState(true);
+ const [dataTableData, setDataTableData] = useState({
+ 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 (
+
+
+
+
+
+
+
+
+ Code Claim / Code LOG
+ Nama Member
+ Member ID
+ Service
+ Tipe LOG
+ Provider
+ Tanggal Request
+ Amount Incurred
+ Amount Approved
+ Excess Paid
+ Status
+
+
+ {dataTableIsLoading ? (
+
+
+
+ Loading
+
+
+
+ ) : dataTableData.data.length === 0 ? (
+
+
+
+ No Data
+
+
+
+ ) : (
+
+ {dataTableData.data.map((row, index) => (
+
+ ))}
+
+ )}
+
+
+
+
+
+
+ );
+}
diff --git a/frontend/dashboard/src/routes/index.tsx b/frontend/dashboard/src/routes/index.tsx
index 9082b104..fa0b42e6 100644
--- a/frontend/dashboard/src/routes/index.tsx
+++ b/frontend/dashboard/src/routes/index.tsx
@@ -471,6 +471,10 @@ export default function Router() {
path: 'report/linksehat-payments',
element: ,
},
+ {
+ path: 'report/primayan-medicare',
+ element: ,
+ },
{
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')));