59 Commits

Author SHA1 Message Date
R
a5db01bd25 Fix Download LOG 2023-02-15 12:50:46 +07:00
R
5d4033a9ca Display Uploaded Files 2023-02-15 12:30:35 +07:00
R
27523b8cce [WIP] Fix Upload Document from Hospital Portal 2023-02-15 08:00:14 +07:00
R
f6117743ad Fix Filter 2023-02-14 16:32:38 +07:00
R
8c97df9fc4 Remove Dummy Notifications 2023-02-14 15:31:57 +07:00
R
4f2bb19d8a [Build] Dashboard & Hospital Portal 2023-02-14 13:48:59 +07:00
R
13764a3766 [Build] Staging - Hospital Portal 2023-02-14 13:31:49 +07:00
R
ed273fdafa Merge branch 'feature/hospital-portal' 2023-02-14 13:09:14 +07:00
R
d706bf0623 [WIP] Add Approve Button 2023-02-14 13:07:17 +07:00
R
13542cd3c0 [WIP] Add Claim Request 2023-02-14 12:39:51 +07:00
R
6491f4d3e3 Add corporate Manager soft delete 2023-02-04 08:48:52 +07:00
R
5028b2d82b Fix Division by Zero 2023-02-04 08:46:44 +07:00
R
5d56434aa2 [Build] Client Portal 2023-02-04 08:38:46 +07:00
R
8e05280b7d Fix Name & User Avatar 2023-02-04 08:36:59 +07:00
R
e3de0a3c04 Hide Burger 2023-02-04 08:14:51 +07:00
R
c3a425c93d Fix Error on opening Add Claim Modal 2023-02-04 08:12:53 +07:00
R
431070efc3 Fix OTP Client Portal to 4444 2023-02-04 08:05:03 +07:00
R
e8c3decf85 Change Title 2023-02-01 20:27:53 +07:00
R
99c488baf3 Update Guaranted Letter 2023-02-01 20:21:03 +07:00
R
0b50e4c980 Update Guaranted Letter Styling 2023-02-01 20:17:32 +07:00
R
ba310a21c1 [Build] Both 2023-02-01 19:39:33 +07:00
R
5a0136acf8 Fix Download Blob Pdf 2023-02-01 19:35:30 +07:00
R
75c9781a22 [Build] Staging 2023-02-01 19:20:09 +07:00
R
2a1f0c854a [Build] Production 2023-02-01 19:16:50 +07:00
R
f0c787fede Add Download LOG 2023-02-01 19:15:31 +07:00
pajri
a7e688a52c hospital portal 2023-02-01 16:22:03 +07:00
R
8d5f4bb0bd Fix Import Benefit selecting wrong plan from another corporate 2023-02-01 01:37:53 +07:00
R
248047006e [Build] Staging 2023-02-01 01:16:44 +07:00
R
2c535b4021 [Build] Production 2023-02-01 00:56:17 +07:00
R
59dd63a78f Add name,dob linking tools 2023-02-01 00:51:14 +07:00
R
21282be7b3 Merge remote-tracking branch 'origin/feature/prices' 2023-02-01 00:42:44 +07:00
pajri
8cbfb1929b update csv 2023-02-01 11:52:19 +07:00
R
b8152e6b3f Fix Date Time Write 2023-01-30 12:40:04 +07:00
R
cfbe108629 Remove error sting 2023-01-30 12:20:14 +07:00
R
a8821dfb3c Fix Seeder 2023-01-30 12:08:49 +07:00
pajri
1ce2655b65 update schedule dokter 2023-01-28 09:44:14 +07:00
pajri
335e24b17c add biaya admin 2023-01-27 13:26:42 +07:00
pajri
4776eb5b0a seeder prices jadwal dokter 2023-01-27 09:52:31 +07:00
R
17daf20167 Add MCU 2023-01-26 14:51:32 +07:00
R
18ace75fc7 Add OLDLMS .env.example 2023-01-26 07:35:08 +07:00
R
ad743de98d Fix Bug Member Import 2023-01-19 15:09:32 +07:00
R
96a40842bd [Build] Import Loading Button 2023-01-19 14:43:16 +07:00
R
137fd07a28 Add Loading Button when Import 2023-01-19 14:41:56 +07:00
R
21dc0b1fc1 [Build] Frontend Dashboard 2023-01-19 10:15:55 +07:00
R
f56361de62 [Build] Frontend Dashboard 2023-01-19 10:15:00 +07:00
R
85f319878a Fix Regex Kode Corporate 2023-01-19 10:09:53 +07:00
R
23436164c2 Fix Corporate Create & Update Validation remove allow spaces 2023-01-17 12:40:15 +07:00
R
b19e0876e5 Change Specialities Button 2023-01-15 12:19:31 +07:00
R
704c5ecc44 [Bug Fix] Update Validation : Is there laravel validation update ? 2023-01-15 12:07:44 +07:00
R
9087580138 Add File Import Example Download 2023-01-15 11:28:07 +07:00
R
7ff199a3c1 [Fix] Member Benefit Specific 2023-01-13 14:48:15 +07:00
R
08a2502fb1 Enable Claim Softdeletes 2023-01-13 12:19:00 +07:00
R
65c9153fee [Build] Frontend 2023-01-13 12:14:00 +07:00
R
775f471a07 [WIP] Update Postponed 2023-01-13 12:08:57 +07:00
R
f09eaef5ad [Fix] Display Claim Postponed 2023-01-13 11:50:31 +07:00
R
e116fb814a [WIP] Fix Medicine 2023-01-13 08:19:43 +07:00
R
2f10f913c0 [WIP] Change Check Coverage Appointment 2023-01-13 00:43:58 +07:00
R
3a2dd84500 Fix Breadcrumbs Links 2023-01-12 15:10:59 +07:00
R
7d1872ef1e [Build] Update 2023-01-11 14:49:16 +07:00
753 changed files with 57381 additions and 3641 deletions

View File

@@ -15,6 +15,13 @@ DB_DATABASE=laravel
DB_USERNAME=root DB_USERNAME=root
DB_PASSWORD= DB_PASSWORD=
OLDLMS_DB_CONNECTION=mysql
OLDLMS_DB_HOST=127.0.0.1
OLDLMS_DB_PORT=3306
OLDLMS_DB_DATABASE=linksehat
OLDLMS_DB_USERNAME=mysql
OLDLMS_DB_PASSWORD=password
BROADCAST_DRIVER=log BROADCAST_DRIVER=log
CACHE_DRIVER=file CACHE_DRIVER=file
FILESYSTEM_DISK=local FILESYSTEM_DISK=local

View File

@@ -35,13 +35,13 @@ class AuthController extends Controller
if (filter_var($request->phoneOrEmail, FILTER_VALIDATE_EMAIL)) { if (filter_var($request->phoneOrEmail, FILTER_VALIDATE_EMAIL)) {
User::query()->find($user->id)->update([ User::query()->find($user->id)->update([
'email' => $request->phoneOrEmail, 'email' => $request->phoneOrEmail,
'otp' => rand(1000, 9999), 'otp' => 4444, //rand(1000, 9999),
'otp_created_at' => now() 'otp_created_at' => now()
]); ]);
} else { } else {
User::query()->find($user->id)->update([ User::query()->find($user->id)->update([
'phone' => $request->phoneOrEmail, 'phone' => $request->phoneOrEmail,
'otp' => rand(1000, 9999), 'otp' => 4444,//rand(1000, 9999),
'otp_created_at' => now() 'otp_created_at' => now()
]); ]);
} }

View File

@@ -26,7 +26,7 @@ class DashboardResources extends JsonResource
'myLimit' => [ 'myLimit' => [
'balance' => $myLimitBalance, 'balance' => $myLimitBalance,
'total' => $myLimitTotal, 'total' => $myLimitTotal,
'percentage' => ($myLimitBalance / $myLimitTotal) * 100, 'percentage' => $myLimitTotal ? (($myLimitBalance / $myLimitTotal) * 100) : 0,
], ],
'lockLimit' => [ 'lockLimit' => [
'balance' => $lockBalance, 'balance' => $lockBalance,

View File

View File

@@ -0,0 +1,5 @@
<?php
return [
'name' => 'HospitalPortal'
];

View File

View File

@@ -0,0 +1,21 @@
<?php
namespace Modules\HospitalPortal\Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
class HospitalPortalDatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
Model::unguard();
// $this->call("OthersTableSeeder");
}
}

View File

View File

@@ -0,0 +1,128 @@
<?php
namespace Modules\HospitalPortal\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\User;
use Crypt;
use Error;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Mail;
use Modules\Internal\Emails\SendVerifyEmail;
use Modules\Internal\Events\ForgetPassword;
class AuthController extends Controller
{
public function login(Request $request)
{
$request->validate([
'email' => 'required|email',
'password' => 'required'
]);
$user = User::query()
->where('email', $request->email)
->first();
if (!$user) {
return response(['message' => 'User Tidak Ditemukan'], 404);
}
if (!Hash::check($request->password, $user->password)) {
return response(['message' => 'Password Salah'], 403);
}
return response([
'message' => 'Selamat Datang',
'user' => $user,
'token' => $user->createToken('app')->plainTextToken
]);
}
public function logout(Request $request)
{
$token = $request->bearerToken();
Auth::user()->tokens()->where('id', $token)->delete();
return response(['message' => 'Berhasil Logout.']);
}
public function resetPassword(Request $request)
{
$user = Auth::user();
$request->validate([
'old_password' => 'required',
'new_password' => 'required',
'confirm_new_password' => 'required'
]);
if (!Hash::check($request['old_password'], $user->password)) {
return response(['message' => 'Password Salah'], 403);
}
if ($request["new_password"] != $request["confirm_new_password"]) {
return response([
'message' => "Password Tidak Sama"
]);
}
$user->update([
'password' => Hash::make($request->confirm_new_password),
]);
return response()->json($user);
}
public function verifyEmail(Request $request)
{
$request->validate([
'email' => 'required|email',
]);
$user = User::query()
->where('email', $request->email)
->first();
if (!$user) {
return response(['message' => 'User Tidak Ditemukan'], 404);
}
Event(new ForgetPassword($user));
// Mail::to($user->email)->send(new SendVerifyEmail($user));
return response()->json($user);
}
public function forgetPassword(Request $request)
{
$request->validate([
'new_password' => 'required',
'confirm_new_password' => 'required'
]);
$token = Crypt::decryptString($request->token);
$email = explode('|', $token)[0];
$user = User::query()
->where('email', $email)
->first();
if (!$user) {
return response(['message' => 'User Tidak Ditemukan'], 404);
}
if ($request["new_password"] != $request["confirm_new_password"]) {
return response([
'message' => "Password Tidak Sama"
], 404);
}
$user->update([
'password' => Hash::make($request->confirm_new_password),
]);
return response()->json($user);
}
}

View File

@@ -0,0 +1,145 @@
<?php
namespace Modules\HospitalPortal\Http\Controllers\Api;
use App\Helpers\Helper;
use App\Models\ClaimRequest;
use App\Models\File;
use App\Models\Member;
use Exception;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use PDF;
class ClaimRequestController extends Controller
{
/**
* Display a listing of the resource.
* @return Renderable
*/
public function index(request $request)
{
$claimRequests = ClaimRequest::query()
->when($request->search, function ($q, $search) {
$q->where('code', 'LIKE', "%".$search."%");
})
->when($request->orderBy, function ($q, $orderBy) use ($request) {
if (in_array($orderBy, ['submission_date', 'code'])) {
$q->orderBy($orderBy, $request->order);
}
})
->when($request->status, function($q, $status) {
$q->where('status', $status);
})
->with(['member'])
->paginate();
return Helper::responseJson($claimRequests);
}
/**
* Show the form for creating a new resource.
* @return Renderable
*/
public function create()
{
return view('hospitalportal::create');
}
/**
* Store a newly created resource in storage.
* @param Request $request
* @return Renderable
*/
public function store(Request $request)
{
$request->validate([
// 'submission_date' => 'required',
'member_id' => 'required',
// 'files' => ''
]);
$newClaimRequest = ClaimRequest::create([
'member_id' => $request->member_id,
'submission_date' => now(),
'status' => 'requested'
]);
if ($request->hasFile('result_files')) {
foreach ($request->result_files as $file) {
$pathFile = File::storeFile('claim', $newClaimRequest->id, $file);
$newClaimRequest->files()->updateOrCreate([
'type' => 'result',
'name' => File::getFileName('claim', $newClaimRequest->id, $file),
'original_name' => $file->getClientOriginalName(),
'extension' => $file->getClientOriginalExtension(),
'path' => $pathFile,
'created_by' => auth()->user()->id,
'updated_by' => auth()->user()->id,
]);
}
}
return ($request->result_files[0]->getClientOriginalName());
return Helper::responseJson(data: $request->toArray(), message: 'Claim Request berhasil ajukan!');
}
/**
* Show the specified resource.
* @param int $id
* @return Renderable
*/
public function show($id)
{
return view('hospitalportal::show');
}
/**
* Show the form for editing the specified resource.
* @param int $id
* @return Renderable
*/
public function edit($id)
{
return view('hospitalportal::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 generateLog($claim_request_id)
{
$claimRequest = ClaimRequest::findOrFail($claim_request_id);
if ($claimRequest->status != 'approved') {
throw new Exception("Belum Teverifikasi", 1);
}
$member = Member::findOrFail($claimRequest->member_id)
->load(['currentPlan', 'currentPolicy', 'currentPlan.corporateBenefits', 'currentPlan.corporateBenefits.benefit']);
$pdf = PDF::loadView('pdf.guaranted_leter', compact('member', 'claimRequest'));
return $pdf->download('Guaranted Letter - '.$member->full_name.'.pdf');
return $claimRequest;
}
}

View File

@@ -0,0 +1,41 @@
<?php
namespace Modules\HospitalPortal\Http\Controllers\Api;
use App\Helpers\Helper;
use App\Models\Member;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
class MemberController extends Controller
{
/**
* Display a listing of the resource.
* @return Renderable
*/
public function search(Request $request)
{
$request->validate([
'no_polis' => 'required',
'birth_date' => 'required'
]);
$member = Member::query()
->where('member_id', $request->no_polis)
->where('birth_date', $request->birth_date)
->with(['person', 'currentCorporate',
// 'currentCorporate.corporateServices' => function ($corporateService) {
// $corporateService->where('status', 'active');
// },
// 'currentCorporate.corporateServices.service'
// 'currentPlan.benefits',
// 'currentPlan.corporateBenefit.plan',
'currentPlan.corporateBenefits.benefit'
])
->firstOrFail();
return Helper::responseJson($member);
}
}

View File

@@ -0,0 +1,83 @@
<?php
namespace Modules\HospitalPortal\Http\Controllers;
use App\Helpers\Helper;
use App\Models\Claim;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
class ClaimController extends Controller
{
/**
* Display a listing of the resource.
* @return Renderable
*/
public function index()
{
$claims = Claim::where('deleted_at', 'ASD')->paginate(5);
return Helper::responseJson($claims);
}
/**
* Show the form for creating a new resource.
* @return Renderable
*/
public function create()
{
return view('hospitalportal::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('hospitalportal::show');
}
/**
* Show the form for editing the specified resource.
* @param int $id
* @return Renderable
*/
public function edit($id)
{
return view('hospitalportal::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)
{
//
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace Modules\HospitalPortal\Http\Controllers;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
class HospitalPortalController extends Controller
{
/**
* Display a listing of the resource.
* @return Renderable
*/
public function index()
{
return view('hospitalportal::index');
}
/**
* Show the form for creating a new resource.
* @return Renderable
*/
public function create()
{
return view('hospitalportal::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('hospitalportal::show');
}
/**
* Show the form for editing the specified resource.
* @param int $id
* @return Renderable
*/
public function edit($id)
{
return view('hospitalportal::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)
{
//
}
}

View File

@@ -0,0 +1,112 @@
<?php
namespace Modules\HospitalPortal\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Database\Eloquent\Factory;
class HospitalPortalServiceProvider extends ServiceProvider
{
/**
* @var string $moduleName
*/
protected $moduleName = 'HospitalPortal';
/**
* @var string $moduleNameLower
*/
protected $moduleNameLower = 'hospitalportal';
/**
* Boot the application events.
*
* @return void
*/
public function boot()
{
$this->registerTranslations();
$this->registerConfig();
$this->registerViews();
$this->loadMigrationsFrom(module_path($this->moduleName, 'Database/Migrations'));
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->app->register(RouteServiceProvider::class);
}
/**
* Register config.
*
* @return void
*/
protected function registerConfig()
{
$this->publishes([
module_path($this->moduleName, 'Config/config.php') => config_path($this->moduleNameLower . '.php'),
], 'config');
$this->mergeConfigFrom(
module_path($this->moduleName, 'Config/config.php'), $this->moduleNameLower
);
}
/**
* Register views.
*
* @return void
*/
public function registerViews()
{
$viewPath = resource_path('views/modules/' . $this->moduleNameLower);
$sourcePath = module_path($this->moduleName, 'Resources/views');
$this->publishes([
$sourcePath => $viewPath
], ['views', $this->moduleNameLower . '-module-views']);
$this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), $this->moduleNameLower);
}
/**
* Register translations.
*
* @return void
*/
public function registerTranslations()
{
$langPath = resource_path('lang/modules/' . $this->moduleNameLower);
if (is_dir($langPath)) {
$this->loadTranslationsFrom($langPath, $this->moduleNameLower);
} else {
$this->loadTranslationsFrom(module_path($this->moduleName, 'Resources/lang'), $this->moduleNameLower);
}
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return [];
}
private function getPublishableViewPaths(): array
{
$paths = [];
foreach (\Config::get('view.paths') as $path) {
if (is_dir($path . '/modules/' . $this->moduleNameLower)) {
$paths[] = $path . '/modules/' . $this->moduleNameLower;
}
}
return $paths;
}
}

View File

@@ -0,0 +1,69 @@
<?php
namespace Modules\HospitalPortal\Providers;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class RouteServiceProvider extends ServiceProvider
{
/**
* The module namespace to assume when generating URLs to actions.
*
* @var string
*/
protected $moduleNamespace = 'Modules\HospitalPortal\Http\Controllers';
/**
* Called before routes are registered.
*
* Register any model bindings or pattern based filters.
*
* @return void
*/
public function boot()
{
parent::boot();
}
/**
* Define the routes for the application.
*
* @return void
*/
public function map()
{
$this->mapApiRoutes();
$this->mapWebRoutes();
}
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*
* @return void
*/
protected function mapWebRoutes()
{
Route::middleware('web')
->namespace($this->moduleNamespace)
->group(module_path('HospitalPortal', '/Routes/web.php'));
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*
* @return void
*/
protected function mapApiRoutes()
{
Route::prefix('api')
->middleware('api')
->namespace($this->moduleNamespace)
->group(module_path('HospitalPortal', '/Routes/api.php'));
}
}

View File

@@ -0,0 +1,9 @@
@extends('hospitalportal::layouts.master')
@section('content')
<h1>Hello World</h1>
<p>
This view is loaded from module: {!! config('hospitalportal.name') !!}
</p>
@endsection

View File

@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Module HospitalPortal</title>
{{-- Laravel Mix - CSS File --}}
{{-- <link rel="stylesheet" href="{{ mix('css/hospitalportal.css') }}"> --}}
</head>
<body>
@yield('content')
{{-- Laravel Mix - JS File --}}
{{-- <script src="{{ mix('js/hospitalportal.js') }}"></script> --}}
</body>
</html>

View File

View File

@@ -0,0 +1,43 @@
<?php
use Illuminate\Http\Request;
use Modules\HospitalPortal\Http\Controllers\Api\AuthController;
use Modules\HospitalPortal\Http\Controllers\Api\ClaimRequestController;
use Modules\HospitalPortal\Http\Controllers\Api\MemberController;
use Modules\HospitalPortal\Http\Controllers\ClaimController;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::prefix('hospitalportal')->group(function () {
Route::post('login', [AuthController::class, 'login'])->name('login');
Route::post('forget-password', [AuthController::class, 'forgetPassword'])->name('forget-password');
Route::post('verify-email', [AuthController::class, 'verifyEmail'])->name('verify-email');
Route::middleware('auth:sanctum')->group(function () {
Route::post('logout', [AuthController::class, 'logout'])->name('logout');
Route::get('/user', function (Request $request) {
return $request->user();
});
Route::put('reset-password', [AuthController::class, 'resetPassword'])->name('resetPassword');
Route::get('claims', [ClaimController::class, 'index']);
Route::post('search-member', [MemberController::class, 'search']);
Route::get('claim-requests', [ClaimRequestController::class, 'index'])->name('claim-requests.index');
Route::post('claim-requests', [ClaimRequestController::class, 'store'])->name('claim-requests.store');
Route::get('claim-requests/{claim_request_id}/log', [ClaimRequestController::class, 'generateLog'])->name('claim-requests.generate-log');
});
});

View File

@@ -0,0 +1,16 @@
<?php
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::prefix('hospitalportal')->group(function() {
Route::get('/', 'HospitalPortalController@index');
});

View File

@@ -0,0 +1,23 @@
{
"name": "nwidart/hospitalportal",
"description": "",
"authors": [
{
"name": "Nicolas Widart",
"email": "n.widart@gmail.com"
}
],
"extra": {
"laravel": {
"providers": [],
"aliases": {
}
}
},
"autoload": {
"psr-4": {
"Modules\\HospitalPortal\\": ""
}
}
}

View File

@@ -0,0 +1,13 @@
{
"name": "HospitalPortal",
"alias": "hospitalportal",
"description": "",
"keywords": [],
"priority": 0,
"providers": [
"Modules\\HospitalPortal\\Providers\\HospitalPortalServiceProvider"
],
"aliases": {},
"files": [],
"requires": []
}

View File

@@ -0,0 +1,21 @@
{
"private": true,
"scripts": {
"dev": "npm run development",
"development": "mix",
"watch": "mix watch",
"watch-poll": "mix watch -- --watch-options-poll=1000",
"hot": "mix watch --hot",
"prod": "npm run production",
"production": "mix --production"
},
"devDependencies": {
"axios": "^0.21.4",
"dotenv": "^10.0.0",
"dotenv-expand": "^5.1.0",
"laravel-mix": "^6.0.31",
"laravel-mix-merge-manifest": "^2.0.0",
"lodash": "^4.17.21",
"postcss": "^8.3.7"
}
}

View File

@@ -0,0 +1,14 @@
const dotenvExpand = require('dotenv-expand');
dotenvExpand(require('dotenv').config({ path: '../../.env'/*, debug: true*/}));
const mix = require('laravel-mix');
require('laravel-mix-merge-manifest');
mix.setPublicPath('../../public').mergeManifest();
mix.js(__dirname + '/Resources/assets/js/app.js', 'js/hospitalportal.js')
.sass( __dirname + '/Resources/assets/sass/app.scss', 'css/hospitalportal.css');
if (mix.inProduction()) {
mix.version();
}

View File

@@ -0,0 +1,113 @@
<?php
namespace Modules\Internal\Http\Controllers\Api;
use App\Helpers\Helper;
use App\Models\ClaimRequest;
use App\Models\Member;
use Exception;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Knp\Snappy\Pdf;
use Modules\Internal\Transformers\ClaimRequestResource;
class ClaimRequestController extends Controller
{
/**
* Display a listing of the resource.
* @return Renderable
*/
public function index(Request $request)
{
$claimRequests = ClaimRequest::query()
->when($request->search, function ($q, $search) {
$q->where('code', 'LIKE', "%".$search."%");
})
->when($request->orderBy, function ($q, $orderBy) use ($request) {
if (in_array($orderBy, ['submission_date', 'code'])) {
$q->orderBy($orderBy, $request->order);
}
})
->when(empty($request->orderBy), function ($q) {
$q->orderBy('created_at', 'desc');
})
->when($request->status, function($q, $status) {
$q->where('status', $status);
})
->with(['member', 'files'])
->paginate();
return Helper::paginateResources(ClaimRequestResource::collection($claimRequests));
}
/**
* 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 approve($id)
{
$claimRequest = ClaimRequest::findOrFail($id);
$claimRequest->status = 'approved';
$claimRequest->save();
return $claimRequest;
}
}

View File

@@ -3,6 +3,7 @@
namespace Modules\Internal\Http\Controllers\Api; namespace Modules\Internal\Http\Controllers\Api;
use App\Exceptions\ImportRowException; use App\Exceptions\ImportRowException;
use App\Helpers\Helper;
use App\Imports\PlansImport; use App\Imports\PlansImport;
use App\Models\Benefit; use App\Models\Benefit;
use App\Models\Claim; use App\Models\Claim;
@@ -19,7 +20,8 @@ use Illuminate\Routing\Controller;
use Maatwebsite\Excel\Facades\Excel; use Maatwebsite\Excel\Facades\Excel;
use Box\Spout\Reader\Common\Creator\ReaderEntityFactory; use Box\Spout\Reader\Common\Creator\ReaderEntityFactory;
use App\Models\File; use App\Models\File;
use Illuminate\Support\Facades\File as FacadesFile;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Modules\Internal\Services\CorporateService; use Modules\Internal\Services\CorporateService;
@@ -76,7 +78,7 @@ class CorporateController extends Controller
public function store(Request $request) public function store(Request $request)
{ {
$request->validate([ $request->validate([
'code' => 'required', 'code' => 'required|regex:/^[a-zA-Z0-9]+$/',
'name' => 'required', 'name' => 'required',
// 'logo' => 'required', // 'logo' => 'required',
'policy_code' => 'required_with:policy_id', 'policy_code' => 'required_with:policy_id',
@@ -144,6 +146,12 @@ class CorporateController extends Controller
'code' => 'OPT', 'code' => 'OPT',
'description' => 'Optical', 'description' => 'Optical',
], ],
[
'id' => 6,
'name' => 'Medical Check Up',
'code' => 'MCU',
'description' => 'Medical Check Up',
],
]; ];
foreach ($services as $service) { foreach ($services as $service) {
@@ -293,7 +301,7 @@ class CorporateController extends Controller
public function update(Request $request, $id) public function update(Request $request, $id)
{ {
$request->validate([ $request->validate([
'code' => 'required', 'code' => 'required|regex:/^[a-zA-Z0-9]+$/',
'name' => 'required', 'name' => 'required',
'policy_code' => 'required_with:policy_id', 'policy_code' => 'required_with:policy_id',
'policy_total_premi' => 'required_with:policy_code', 'policy_total_premi' => 'required_with:policy_code',
@@ -486,4 +494,31 @@ class CorporateController extends Controller
] ]
]; ];
} }
public function importDocumentExample($document_type)
{
switch ($document_type) {
case 'plan-benefit':
return Helper::responseJson([
'file_name' => "Corporate Plan & Benefit Import.xlsx",
"file_url" => url('files/Corporate Plan & Benefit Import.xlsx')
]);
break;
case 'member':
return Helper::responseJson([
'file_name' => "Corporate Membership Import.xlsx",
"file_url" => url('files/Corporate Membership Import.xlsx')
]);
break;
case 'diagnosis-exclusion':
return Helper::responseJson([
'file_name' => "Corporate Exclusion Import.xlsx",
"file_url" => url('files/Corporate Exclusion Import.xlsx')
]);
break;
default:
return Helper::responseJson([], 'error', 404);
break;
}
}
} }

View File

@@ -15,6 +15,7 @@ use Illuminate\Http\Request;
use Illuminate\Routing\Controller; use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Modules\Internal\Services\MemberEnrollmentService; use Modules\Internal\Services\MemberEnrollmentService;
use PDF;
class CorporateMemberController extends Controller class CorporateMemberController extends Controller
{ {
@@ -192,9 +193,12 @@ class CorporateMemberController extends Controller
'ingestion_code' => $e->getCode(), 'ingestion_code' => $e->getCode(),
'ingestion_status' => $e->getMessage(), 'ingestion_status' => $e->getMessage(),
]); ]);
$singleRow = WriterEntityFactory::createRow($this->memberEnrollmentService->makeResultRowWithResultFormat($new_member_data)); // try {
$writer->addRow($singleRow); $singleRow = WriterEntityFactory::createRow($this->memberEnrollmentService->makeResultRowWithResultFormat($new_member_data));
$failed_member_data[] = ['row_number' => $index, 'error' => $e->getMessage()]; $writer->addRow($singleRow);
// } catch (\Exception $e) {
$failed_member_data[] = ['row_number' => $index, 'error' => $e->getMessage(), 'data' => $new_member_data];
// }
} catch (\Exception $e) { } catch (\Exception $e) {
// Write Server Error to File // Write Server Error to File
$new_member_data = array_merge($new_member_data, [ $new_member_data = array_merge($new_member_data, [
@@ -225,4 +229,17 @@ class CorporateMemberController extends Controller
] ]
]; ];
} }
public function generateLog($member_id)
{
$member = Member::findOrFail($member_id)
->load(['currentPlan', 'currentPolicy', 'currentPlan.corporateBenefits', 'currentPlan.corporateBenefits.benefit']);
// dd($member->currentPlan->corporateBenefits->toArray());
// return view('pdf.guaranted_leter', compact('member'));
$pdf = PDF::loadView('pdf.guaranted_leter', compact('member'));
return $pdf->download('Guaranted Letter - '.$member->full_name.'.pdf');
}
} }

View File

@@ -5,6 +5,7 @@ use Modules\Internal\Http\Controllers\Api\AuthController;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Modules\Internal\Http\Controllers\Api\BenefitController; use Modules\Internal\Http\Controllers\Api\BenefitController;
use Modules\Internal\Http\Controllers\Api\ClaimController; use Modules\Internal\Http\Controllers\Api\ClaimController;
use Modules\Internal\Http\Controllers\Api\ClaimRequestController;
use Modules\Internal\Http\Controllers\Api\CorporateBenefitController; use Modules\Internal\Http\Controllers\Api\CorporateBenefitController;
use Modules\Internal\Http\Controllers\Api\CorporateController; use Modules\Internal\Http\Controllers\Api\CorporateController;
use Modules\Internal\Http\Controllers\Api\CorporateFormulariumController; use Modules\Internal\Http\Controllers\Api\CorporateFormulariumController;
@@ -51,6 +52,7 @@ Route::prefix('internal')->group(function () {
Route::resource('corporates', CorporateController::class); Route::resource('corporates', CorporateController::class);
Route::get('corporates/import-document-example/{document_type}', [CorporateController::class, 'importDocumentExample']);
Route::put('corporates/{corporate_id}/activation', [CorporateController::class, 'activation']); Route::put('corporates/{corporate_id}/activation', [CorporateController::class, 'activation']);
Route::post('corporates/{corporate_id}/import-plan-benefit', [CorporateController::class, 'importPlanBenefit']); Route::post('corporates/{corporate_id}/import-plan-benefit', [CorporateController::class, 'importPlanBenefit']);
@@ -119,6 +121,11 @@ Route::prefix('internal')->group(function () {
Route::get('search-specialities', [SpecialityController::class, 'searchSpeciality']); Route::get('search-specialities', [SpecialityController::class, 'searchSpeciality']);
Route::resource('organizations', OrganizationController::class); Route::resource('organizations', OrganizationController::class);
Route::resource('doctors', DoctorController::class); Route::resource('doctors', DoctorController::class);
Route::get('generate-log/{member_id}', [CorporateMemberController::class, 'generateLog']);
Route::get('claim-requests', [ClaimRequestController::class, 'index'])->name('claim-requests.index');
Route::post('claim-requests/{id}/approve', [ClaimRequestController::class, 'approve'])->name('claim-requests.approve');
}); });
// Route::resource('organizations', OrganizationController::class); // Route::resource('organizations', OrganizationController::class);

View File

@@ -11,6 +11,8 @@
| |
*/ */
use Modules\Internal\Http\Controllers\Api\CorporateMemberController;
Route::prefix('internal')->group(function() { Route::prefix('internal')->group(function() {
Route::get('/', 'InternalController@index'); Route::get('/', 'InternalController@index');
}); });

View File

@@ -42,10 +42,8 @@ class CorporateService
$this->validatePlanRow($plan_data); $this->validatePlanRow($plan_data);
$plan = Plan::updateOrCreate([ $plan = $corporate->plans()->updateOrCreate([
'service_code' => $plan_data['service_code'], 'service_code' => $plan_data['service_code'],
'corporate_id' => $corporate->id,
'code' => $plan_data['code'],
], $plan_data); ], $plan_data);
return $plan; return $plan;
@@ -91,7 +89,9 @@ class CorporateService
$this->validateBenefitRow($benefit_data); $this->validateBenefitRow($benefit_data);
$plan = Plan::where('corporate_plan_id', $benefit_data['plan_code'])->first(); $plan = $corporate->plans()
->where('corporate_plan_id', $benefit_data['plan_code'])
->first();
// $corporate->plans->where('corporate_plan_id', $benefit_data['plan_code'])->first(); // $corporate->plans->where('corporate_plan_id', $benefit_data['plan_code'])->first();
$benefit_data['plan_code'] = $plan->id; $benefit_data['plan_code'] = $plan->id;

View File

@@ -15,6 +15,7 @@ use App\Models\Plan;
use Box\Spout\Writer\Common\Creator\WriterEntityFactory; use Box\Spout\Writer\Common\Creator\WriterEntityFactory;
use Box\Spout\Common\Entity\Row; use Box\Spout\Common\Entity\Row;
use Carbon\Carbon; use Carbon\Carbon;
use DateTime;
use DB; use DB;
class MemberEnrollmentService class MemberEnrollmentService
@@ -45,6 +46,7 @@ class MemberEnrollmentService
"The Right Classes Room of BPJS Participants" => "bpjs_class", "The Right Classes Room of BPJS Participants" => "bpjs_class",
"Name of Faskes" => "faskes_name", "Name of Faskes" => "faskes_name",
"Rule_BPJSK ('Y' or 'N')" => "bpjsk", "Rule_BPJSK ('Y' or 'N')" => "bpjsk",
"Rule BPJSK" => "bpjsk",
"Agent Code / intermediary code" => "agent_code", "Agent Code / intermediary code" => "agent_code",
"Member Name" => "name", "Member Name" => "name",
"Address1" => "address1", "Address1" => "address1",
@@ -123,7 +125,7 @@ class MemberEnrollmentService
"faskes_fkrtl" => "Faskes FKRTL (Next Level Provider) or Individual group preferred provider", "faskes_fkrtl" => "Faskes FKRTL (Next Level Provider) or Individual group preferred provider",
"bpjs_class" => "The Right Classes Room of BPJS Participants", "bpjs_class" => "The Right Classes Room of BPJS Participants",
"faskes_name" => "Name of Faskes", "faskes_name" => "Name of Faskes",
"bpjsk" => "Rule_BPJSK ('Y' or 'N')", "bpjsk" => "Rule BPJSK",
"agent_code" => "Agent Code / intermediary code", "agent_code" => "Agent Code / intermediary code",
"name" => "Member Name", "name" => "Member Name",
"address1" => "Address1", "address1" => "Address1",
@@ -195,8 +197,8 @@ class MemberEnrollmentService
"Faskes FKRTL (Next Level Provider) or Individual group preferred provider", "Faskes FKRTL (Next Level Provider) or Individual group preferred provider",
"The Right Classes Room of BPJS Participants", "The Right Classes Room of BPJS Participants",
"Name of Faskes", "Name of Faskes",
"Rule_BPJSK ('Y' or 'N')", "Rule BPJSK",
"Agent Code / intermediary code", "Internal Use",
"Member Name", "Member Name",
"Address1", "Address1",
"Address 1", "Address 1",
@@ -247,6 +249,10 @@ class MemberEnrollmentService
$this->member = $member; $this->member = $member;
} }
public function dateParser($date_from_row) {
return is_string($date_from_row) ? Carbon::parse(strtotime($date_from_row)) : Carbon::parse($date_from_row);
}
protected function validateRow($row) protected function validateRow($row)
{ {
if (empty($row['record_type'])) { if (empty($row['record_type'])) {
@@ -360,7 +366,7 @@ class MemberEnrollmentService
"member_id" => $row['member_id'] ?? null, "member_id" => $row['member_id'] ?? null,
"payor_id" => $row['payor_id'] ?? null, "payor_id" => $row['payor_id'] ?? null,
"nik" => $row['nik'] ?? null, "nik" => $row['nik'] ?? null,
"birth_date" => Carbon::parse(strtotime($row['date_of_birth'])), "birth_date" => $this->dateParser($row['date_of_birth']),
"gender" => Helper::genderNormalization($row['sex']), "gender" => Helper::genderNormalization($row['sex']),
// "language" => $row['language'] ?? null, // "language" => $row['language'] ?? null,
// "race" => $row['race'] ?? null, // "race" => $row['race'] ?? null,
@@ -415,7 +421,7 @@ class MemberEnrollmentService
], ],
[ [
'name' => $row['name'] ?? null, 'name' => $row['name'] ?? null,
'birth_date' => Carbon::parse(strtotime($row['date_of_birth'])), 'birth_date' => $this->dateParser($row['date_of_birth']),
'gender' => Helper::genderPerson($row['sex']), 'gender' => Helper::genderPerson($row['sex']),
'language' => $row['language'] ?? null, 'language' => $row['language'] ?? null,
'race' => $row['race'] ?? null, 'race' => $row['race'] ?? null,
@@ -462,7 +468,7 @@ class MemberEnrollmentService
$person = Person::create([ $person = Person::create([
'name' => $row['name'], 'name' => $row['name'],
'birth_date' => Carbon::parse(strtotime($row['date_of_birth'])), 'birth_date' => $this->dateParser($row['date_of_birth']),
'gender' => Helper::genderPerson($row['sex']), 'gender' => Helper::genderPerson($row['sex']),
'language' => $row['language'] ?? null, 'language' => $row['language'] ?? null,
'race' => $row['race'] ?? null, 'race' => $row['race'] ?? null,
@@ -474,8 +480,8 @@ class MemberEnrollmentService
$memberPolicy->fill([ $memberPolicy->fill([
'member_id' => $member->member_id, 'member_id' => $member->member_id,
'policy_id' => $row['policy_number'], 'policy_id' => $row['policy_number'],
'start' => Carbon::parse(strtotime($row['member_effective_date'])), 'start' => $this->dateParser($row['member_effective_date']),
'end' => Carbon::parse(strtotime($row['member_expiry_date'])), 'end' => $this->dateParser($row['member_expiry_date']),
'status' => 'active' 'status' => 'active'
]); ]);
$memberPolicy->save(); $memberPolicy->save();
@@ -505,8 +511,8 @@ class MemberEnrollmentService
$member->memberPlans()->create([ $member->memberPlans()->create([
'plan_id' => $plan->id, 'plan_id' => $plan->id,
'status' => 'active', 'status' => 'active',
'start' => Carbon::parse(strtotime($row['member_effective_date'])), 'start' => $this->dateParser($row['member_effective_date']),
'end' => Carbon::parse(strtotime($row['member_expiry_date'])), 'end' => $this->dateParser($row['member_expiry_date']),
]); ]);
} }
DB::commit(); DB::commit();
@@ -620,13 +626,13 @@ class MemberEnrollmentService
} }
if (Carbon::parse(strtotime($row['member_effective_date'])) > Carbon::parse(strtotime($row['member_expiry_date']))) { if ($this->dateParser($row['member_effective_date']) > $this->dateParser($row['member_expiry_date'])) {
throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_INVALID'), 0, null, $row); throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_INVALID'), 0, null, $row);
} }
if ( if (
Carbon::parse($memberPolicy->end) > Carbon::parse(strtotime($row['member_expiry_date'])) Carbon::parse($memberPolicy->end) > $this->dateParser($row['member_expiry_date'])
|| $memberPolicy->end > Carbon::parse(strtotime($row['member_expiry_date'])) || $memberPolicy->end > $this->dateParser($row['member_expiry_date'])
) { ) {
throw new ImportRowException(__('enrollment.MEMBER_RENEWAL_STILL_ACTIVE'), 0, null, $row); throw new ImportRowException(__('enrollment.MEMBER_RENEWAL_STILL_ACTIVE'), 0, null, $row);
} }
@@ -663,13 +669,13 @@ class MemberEnrollmentService
]), 0, null, $row); ]), 0, null, $row);
} }
if (Carbon::parse(strtotime($row['member_effective_date'])) > Carbon::parse(strtotime($row['member_expiry_date']))) { if ($this->dateParser($row['member_effective_date']) > $this->dateParser($row['member_expiry_date'])) {
throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_INVALID'), 0, null, $row); throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_INVALID'), 0, null, $row);
} }
if ( if (
Carbon::parse($memberPolicy->end) > Carbon::parse(strtotime($row['member_expiry_date'])) Carbon::parse($memberPolicy->end) > $this->dateParser($row['member_expiry_date'])
|| $memberPolicy->end > Carbon::parse(strtotime($row['member_expiry_date'])) || $memberPolicy->end > $this->dateParser($row['member_expiry_date'])
) { ) {
throw new ImportRowException(__('enrollment.MEMBER_RENEWAL_STILL_ACTIVE'), 0, null, $row); throw new ImportRowException(__('enrollment.MEMBER_RENEWAL_STILL_ACTIVE'), 0, null, $row);
} }
@@ -850,11 +856,11 @@ class MemberEnrollmentService
]), 0, null, $row); ]), 0, null, $row);
} }
if (Carbon::parse(strtotime($row['member_effective_date'])) < now() || Carbon::parse(strtotime($row['member_expiry_date'])) < now()) { if ($this->dateParser($row['member_effective_date']) < now() || $this->dateParser($row['member_expiry_date']) < now()) {
throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_MUST_BE_AFTER_TODAY'), 0, null, $row); throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_MUST_BE_AFTER_TODAY'), 0, null, $row);
} }
if (Carbon::parse(strtotime($row['member_effective_date'])) > Carbon::parse(strtotime($row['member_expiry_date']))) { if ($this->dateParser($row['member_effective_date']) > $this->dateParser($row['member_expiry_date'])) {
throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_INVALID'), 0, null, $row); throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_INVALID'), 0, null, $row);
} }
@@ -889,8 +895,8 @@ class MemberEnrollmentService
$newMemberPolicy->fill([ $newMemberPolicy->fill([
'member_id' => $row['member_id'], 'member_id' => $row['member_id'],
'policy_id' => $row['policy_number'], 'policy_id' => $row['policy_number'],
'start' => Carbon::parse(strtotime($row['member_effective_date'])), 'start' => $this->dateParser($row['member_effective_date']),
'end' => Carbon::parse(strtotime($row['member_expiry_date'])), 'end' => $this->dateParser($row['member_expiry_date']),
'status' => 'active' 'status' => 'active'
]); ]);
$newMemberPolicy->save(); $newMemberPolicy->save();
@@ -931,7 +937,7 @@ class MemberEnrollmentService
throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_NO_CHANGE'), 0, null, $row); throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_NO_CHANGE'), 0, null, $row);
} }
if (Carbon::parse(strtotime($row['member_effective_date'])) > Carbon::parse(strtotime($row['member_expiry_date']))) { if ($this->dateParser($row['member_effective_date']) > $this->dateParser($row['member_expiry_date'])) {
throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_INVALID'), 0, null, $row); throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_INVALID'), 0, null, $row);
} }
@@ -1016,7 +1022,15 @@ class MemberEnrollmentService
$cells = []; $cells = [];
foreach ($this->result_doc_headers as $header) { foreach ($this->result_doc_headers as $header) {
$value = $row_data[$this->doc_headers_to_field_map[$header]] ?? null; $value = $row_data[$this->doc_headers_to_field_map[$header]] ?? null;
$cells[] = WriterEntityFactory::createCell($value); if (is_string($value)) {
$cells[] = WriterEntityFactory::createCell($value);
}
else if ($value instanceof DateTime) {
$cells[] = WriterEntityFactory::createCell(Carbon::parse($value)->format('Ymd'));
}
else {
$cells[] = WriterEntityFactory::createCell(null);
}
} }
return $cells; return $cells;

View File

@@ -0,0 +1,33 @@
<?php
namespace Modules\Internal\Transformers;
use Illuminate\Http\Resources\Json\JsonResource;
class ClaimRequestResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
{
$filesGroupByType = $this->files->mapToGroups(function($file) {
return [$file->type => $file];
});
$data = [
'id' => $this->id,
'code' => $this->code,
'submission_date' => $this->submission_date,
'member' => $this->member,
'status' => $this->status ?? 'unknown',
'service_type' => $this->service_type,
'files_by_type' => $filesGroupByType
];
return $data;
}
}

View File

@@ -20,8 +20,8 @@ class CorporateServiceConfigResource extends JsonResource
'corporate_id' => $this->corporate_id, 'corporate_id' => $this->corporate_id,
'service_code' => $this->service_code, 'service_code' => $this->service_code,
'status' => $this->status, 'status' => $this->status,
'name' => $this->service->name, 'name' => $this->service->name ?? '-',
'description' => $this->service->description, 'description' => $this->service->description ?? '-',
'configurations' => $this->configs->pluck('value', 'name'), 'configurations' => $this->configs->pluck('value', 'name'),
'selected_specialities' => $this->corporateServiceSpecialities->where('active', true)->pluck('speciality.name', 'speciality_id'), 'selected_specialities' => $this->corporateServiceSpecialities->where('active', true)->pluck('speciality.name', 'speciality_id'),
'exclusions' => $this->corporateServiceSpecialities->map(function ($speciality) { 'exclusions' => $this->corporateServiceSpecialities->map(function ($speciality) {

View File

@@ -6,8 +6,11 @@ use App\Helpers\Helper;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\Icd; use App\Models\Icd;
use App\Models\Member; use App\Models\Member;
use App\Models\Claim;
use App\Models\Speciality;
use App\Services\ClaimService; use App\Services\ClaimService;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class ClaimController extends Controller class ClaimController extends Controller
{ {
@@ -16,19 +19,23 @@ class ClaimController extends Controller
$request->validate([ $request->validate([
'member_id' => 'required', 'member_id' => 'required',
'user_id' => 'required', 'user_id' => 'required',
'type' => 'required|in:consultation-gp,consultation-specialist,medicine', 'type' => 'required|in:consultation,teleconsultation,medicine',
// 'speciality_code' => 'required',
'total_claim' => 'required', 'total_claim' => 'required',
'detail' => 'required', 'detail' => 'required',
]); ]);
$currentSpeciality = Speciality::where('code', $request->speciality_code)->first();
if ($request->type == 'consultation-gp') { $gpSpecialityName = config('aso.general_practitioner_speciality_name', 'Umum');
$benefitCode = 'OPCONS1'; $isGp = $gpSpecialityName == ($currentSpeciality ? $currentSpeciality->name : false);
}
if ($request->type == 'consultation-specialist') {
$benefitCode = 'OPCONS2';
}
if ($request->type == 'medicine') { if ($request->type == 'medicine') {
$benefitCode = 'OPMEDI1'; $benefitCode = 'OPMEDI1';
} else if ($isGp) {
$benefitCode = 'OPCONS1';
} else {
$benefitCode = 'OPCONS2';
} }
$member = Member::query() $member = Member::query()
@@ -38,8 +45,7 @@ class ClaimController extends Controller
]) ])
->firstOrFail(); ->firstOrFail();
$benefit = $member->currentPlan->benefits()->where('code', $benefitCode)->first(); $benefit = $member->currentPlan->benefits()->where('code', $benefitCode)->first();
// $diagnosis = Icd::first();
$claim = ClaimService::storeClaim($member, null, $request->total_claim, $benefit, 'requested'); $claim = ClaimService::storeClaim($member, null, $request->total_claim, $benefit, 'requested');
$claim->status = 'approved'; $claim->status = 'approved';
$claim->save(); $claim->save();
@@ -54,7 +60,29 @@ class ClaimController extends Controller
'icd_codes' => 'required' 'icd_codes' => 'required'
]); ]);
// dd($request->toArray()); $claim = Claim::where('code', $request->claim_code)->firstOrFail();
return $request->toArray();
try {
DB::beginTransaction();
$claim->fill(['status' => 'postpone'])->update();
$icds = Icd::whereIn('code', $request['icd_codes'])->get();
$icds = $icds->map(function($icd) use ($claim) {
return [
'claim_id' => $claim->id,
'type' => 'primary',
'diagnosis_id' => $icd->id,
'note' => 'HIS Summary',
'description'=> ''
];
})->toArray();
return $claim->diagnoses()->insert($icds);
DB::commit();
} catch (\Exception $e) {
DB::rollback();
return Helper::responseJson($e, 500);
};
} }
} }

View File

@@ -11,7 +11,7 @@ use Illuminate\Http\Request;
class MembershipController extends Controller class MembershipController extends Controller
{ {
// //
public function check(Request $request) public function check(Request $request)
{ {
$request->validate([ $request->validate([
'member_id' => 'required', 'member_id' => 'required',
@@ -25,7 +25,7 @@ class MembershipController extends Controller
} }
if (!$member->active) { if (!$member->active) {
return Helper::responseJson(statusCode: 406, message: 'The Member '.$request->member_id.' is Inactive.', status: 'error'); return Helper::responseJson(statusCode: 406, message: 'The Member ' . $request->member_id . ' is Inactive.', status: 'error');
} }
return Helper::responseJson(data: $member, message: 'Member Found'); return Helper::responseJson(data: $member, message: 'Member Found');
@@ -35,68 +35,30 @@ class MembershipController extends Controller
{ {
$request->validate([ $request->validate([
'member_id' => 'required', 'member_id' => 'required',
'type' => 'required|in:consultation-gp,consultation-specialist,medicine', 'type' => 'required|in:consultation,teleconsultation,medicine',
// 'speciality_code' => 'sometimes' // 'speciality_code' => 'sometimes'
]); ]);
if ($request->type == 'consultation-gp') { $member = Member::query()
$benefitCode = 'OPCONS1'; ->where('member_id', $request->member_id)
} ->with(['currentCorporate', 'currentPolicy', 'currentPlan', 'postponedClaims'])
if ($request->type == 'consultation-specialist') { ->first();
$benefitCode = 'OPCONS2';
}
if ($request->type == 'medicine') {
$benefitCode = 'OPMEDI1';
}
$member = Member::where('member_id', $request->member_id)->with(['currentCorporate', 'currentPolicy', 'currentPlan', 'postponedClaims'])->first(); $corporateService = $member->currentCorporate->corporateServices()
$limits = ClaimService::showMemberBenefitLimit($member, $benefitCode);
$limits['postponed_claims'] = $member->postponedClaims;
$limits['postponed_claims_payment_url'] = route('postpone-pay', $member->member_id);
$limits['postponed_claims_unpaid_total'] = $member->postponedClaims->sum('total_claim');
$corporateService = $member->currentCorporate
->corporateServices()
->active() ->active()
->where('service_code', 'OP') ->where('service_code', 'OP')
->with([ ->with([
'configs', 'configs',
'specialities' => function ($speciality) use ($request) { 'specialities' => function ($speciality) use ($request) {
$speciality->where('code', $request->speciality_code) $speciality->where('code', $request->speciality_code ?? null)
->wherePivot('active', 1); ->wherePivot('active', 1);
}]) }
])
->first(); ->first();
$configs = $corporateService->configs->mapWithKeys(function ($config) {
return [$config->name => $config];
});
$coverage = [ $currentSpeciality = $corporateService->specialities->first();
'benefit' => false,
'admin_fee' => false,
'medicine_benefit' => true, // TODO Make this into setting ?
'medicine_delivery_fee' => false
];
$coverage['medicine_delivery_fee'] = (($configs['delivery_fee']['value'] ?? 1) == 1);
$coverage['gp_benefit'] = (($configs['gp_internal_doctor_online']['value'] ?? 1) == 1);
$coverage['gp_admin_fee'] = (($configs['general_practitioner_fee']['value'] ?? 1) == 1);
$coverage['sp_benefit'] = (($configs['sp_internal_doctor_online']['value'] ?? 1) == 1);
$coverage['sp_admin_fee'] = (($configs['specialist_practitioner_fee']['value'] ?? 1) == 1);
if ($request->has('speciality_code') && !empty($request->speciality_code)) { if ($currentSpeciality) {
if (empty($corporateService) || empty($corporateService->specialities)) {
$coverage['benefit'] = false;
$coverage['admin_fee'] = false;
$limits['coverage'] = $coverage;
return Helper::responseJson(data: $limits);
}
$currentSpeciality = $corporateService->specialities->first();
// Load the Relation Data after speciality check is supported
$corporateService->load([ $corporateService->load([
'corporateServiceSpecialities' => function ($corporateServiceSpeciality) use ($currentSpeciality) { 'corporateServiceSpecialities' => function ($corporateServiceSpeciality) use ($currentSpeciality) {
$corporateServiceSpeciality->where('speciality_id', $currentSpeciality->id); $corporateServiceSpeciality->where('speciality_id', $currentSpeciality->id);
@@ -106,94 +68,105 @@ class MembershipController extends Controller
}, },
'corporateServiceSpecialities.exclusions.rules' 'corporateServiceSpecialities.exclusions.rules'
]); ]);
$serviceSpeciality = $corporateService->corporateServiceSpecialities->first() ?? null;
$serviceSpecialityRules = $serviceSpeciality->exclusions->first()->rules ?? collect([]);
$serviceSpecialityRules = $serviceSpecialityRules->mapWithKeys(function ($rule) {
return [$rule->name => $rule];
});
$gpSpecialityName = config('aso.general_practitioner_speciality_name', 'Umum');
if ($gpSpecialityName == $currentSpeciality->name) {
// To General Practitioner
if (($configs['gp_internal_doctor_online']['value'] ?? 1) == 1) {
$coverage['benefit'] = true;
}
if (($configs['general_practitioner_fee']['value'] ?? 1) == 1) {
$coverage['admin_fee'] = true;
}
if ($serviceSpeciality->active == 1) {
$coverage['benefit'] = true;
}
} else {
// To Specialist
if (($configs['sp_internal_doctor_online']['value'] ?? 1) == 1) {
$coverage['benefit'] = true;
}
// dd($configs['specialist_practitioner_fee']['value'], $configs['specialist_practitioner_fee']['value'] ?? 1, ($configs['specialist_practitioner_fee']['value'] ?? 1) == 1);
if (($configs['specialist_practitioner_fee']['value'] ?? 1) == 1) {
$coverage['admin_fee'] = true;
}
if ($serviceSpeciality->active == 1) {
$coverage['benefit'] = true;
}
}
// TODO THIS EXCLUSION IS USED AS INCLUSION NOW, MUST BE CHANGE TO USED AS EXCLUSION AND MAYBE MOVE THE TABLE
$excluded = [];
foreach ($serviceSpecialityRules as $ruleName => $rule) {
if ($ruleName == 'msc') {
$values = explode(',', $rule->values);
if (!in_array(strtolower($member->marital_status), $values)) {
$excluded[] = $rule;
}
}
if ($ruleName == 'gender') {
$values = explode(',', $rule->values);
if (!in_array(strtolower($member->gender), $values)) {
$excluded[] = $rule;
}
}
if ($ruleName == 'min_age') {
if (!empty($rule->values) && $member->age < $rule->values) {
$excluded[] = $rule;
}
}
if ($ruleName == 'max_age') {
if (!empty($rule->values) && $member->age > $rule->values) {
$excluded[] = $rule;
}
}
if ($ruleName == 'plan') {
$values = explode(',', $rule->values);
if (!in_array($member->currentPlan->code, $values)) {
$excluded[] = $rule;
}
}
}
if ( count($excluded) ) {
$coverage['benefit'] = false;
$coverage['benefit_exclusion'] = $excluded;
} else {
$coverage['benefit'] = true;
}
} }
$corporateServiceSpeciality = $corporateService->corporateServiceSpecialities->first() ?? null;
$serviceSpecialityRules = $corporateServiceSpeciality->exclusions->first()->rules ?? collect([]);
$serviceSpecialityRules = $serviceSpecialityRules->mapWithKeys(function ($rule) {
return [$rule->name => $rule];
});
$configs = $corporateService->configs->mapWithKeys(function ($config) {
return [$config->name => $config];
});
$gpSpecialityName = config('aso.general_practitioner_speciality_name', 'Umum');
$isGp = $gpSpecialityName == ($currentSpeciality ? $currentSpeciality->name : false);
if ($request->type == 'medicine') {
$benefitCode = 'OPMEDI1';
} else if ($isGp) {
$benefitCode = 'OPCONS1';
} else {
$benefitCode = 'OPCONS2';
}
$limits = ClaimService::showMemberBenefitLimit($member, $benefitCode);
$limits['postponed_claims'] = $member->postponedClaims;
$limits['postponed_claims_payment_url'] = route('postpone-pay', $member->member_id);
$limits['postponed_claims_unpaid_total'] = $member->postponedClaims->sum('total_claim');
$coverage['medicine_benefit'] = false;
if ($benefitCode = 'OPMEDI1') {
$medicineBenefit = $member->currentPlan->benefits()->where('code', $benefitCode)->wherePivot('active', 1)->first();
$coverage['medicine_benefit'] = !empty($medicineBenefit);
}
$coverage['medicine_delivery_fee'] = (($configs['delivery_fee']['value'] ?? 1) == 1);
if ($currentSpeciality) {
$xCoverage['sp_consultation_benefit'] = (($configs['sp_internal_doctor_offline']['value'] ?? 1) == 1);
$xCoverage['sp_teleconsultation_benefit'] = (($configs['sp_internal_doctor_online']['value'] ?? 1) == 1);
$xCoverage['gp_consultation_benefit'] = (($configs['gp_internal_doctor_offline']['value'] ?? 1) == 1);
$xCoverage['gp_teleconsultation_benefit'] = (($configs['gp_internal_doctor_online']['value'] ?? 1) == 1);
$coverage['consultation_benefit'] = ($isGp)
? $xCoverage['gp_consultation_benefit']
: $xCoverage['sp_consultation_benefit'];
$coverage['teleconsultation_benefit'] = ($isGp)
? $xCoverage['gp_teleconsultation_benefit']
: $xCoverage['sp_teleconsultation_benefit'];
$xCoverage['sp_admin_fee'] = (($configs['specialist_practitioner_fee']['value'] ?? 1) == 1);
$xCoverage['gp_admin_fee'] = (($configs['general_practitioner_fee']['value'] ?? 1) == 1);
$coverage['admin_fee'] = ($isGp)
? $xCoverage['gp_admin_fee']
: $xCoverage['sp_admin_fee'];
} else {
// Not Supported
$coverage['consultation_benefit'] = false;
$coverage['teleconsultation_benefit'] = false;
$coverage['admin_fee'] = false;
}
$limits['coverage'] = $coverage; $limits['coverage'] = $coverage;
// TODO THIS EXCLUSION IS USED AS INCLUSION NOW, MUST BE CHANGE TO USED AS EXCLUSION AND MAYBE MOVE THE TABLE
$excluded = [];
foreach ($serviceSpecialityRules as $ruleName => $rule) {
if ($ruleName == 'msc') {
$values = explode(',', $rule->values);
if (!in_array(strtolower($member->marital_status), $values)) {
$excluded[] = $rule;
}
}
if ($ruleName == 'gender') {
$values = explode(',', $rule->values);
if (!in_array(strtolower($member->gender), $values)) {
$excluded[] = $rule;
}
}
if ($ruleName == 'min_age') {
if (!empty($rule->values) && $member->age < $rule->values) {
$excluded[] = $rule;
}
}
if ($ruleName == 'max_age') {
if (!empty($rule->values) && $member->age > $rule->values) {
$excluded[] = $rule;
}
}
if ($ruleName == 'plan') {
$values = explode(',', $rule->values);
if (!in_array($member->currentPlan->code, $values)) {
$excluded[] = $rule;
}
}
}
return Helper::responseJson(data: $limits); return Helper::responseJson(data: $limits);
} }
} }

View File

@@ -18,6 +18,15 @@ class Benefit extends Model
'active' 'active'
]; ];
protected $hidden = [
"created_at",
"updated_at",
"deleted_at",
"created_by",
"updated_by",
"deleted_by",
];
public function scopeFilter($query, array $filters) public function scopeFilter($query, array $filters)
{ {
$query->when($filters['search'] ?? false, function ($query, $search) { $query->when($filters['search'] ?? false, function ($query, $search) {

View File

@@ -11,12 +11,13 @@ use App\Events\ClaimRequested;
use App\Traits\Blameable; use App\Traits\Blameable;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str; use Illuminate\Support\Str;
class Claim extends Model class Claim extends Model
{ {
use HasFactory, Blameable; use HasFactory, Blameable, SoftDeletes;
protected $fillable = [ protected $fillable = [
'code', 'code',

View File

@@ -0,0 +1,57 @@
<?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 ClaimRequest extends Model
{
use HasFactory, SoftDeletes, Blameable;
protected static $code_prefix = 'CRQ';
protected static function boot()
{
parent::boot();
static::creating(function ($model) {
try {
$model->code = self::getNextCode();
} catch (\Exception $e) {
abort(500, $e->getMessage());
}
});
}
public static function getNextCode()
{
$last_number = self::withTrashed()->max('code');
$next_number = empty($last_number) ? 1 : ((int) explode('-', $last_number)[1] + 1);
return self::makeCode($next_number);
}
public static function makeCode($next_number)
{
return (string) self::$code_prefix .'-'. str_pad($next_number, 5, 0, STR_PAD_LEFT);
}
public $fillable = [
'submission_date',
'member_id',
'status'
];
public function files()
{
return $this->morphMany(File::class, 'fileable');
}
public function member()
{
return $this->belongsTo(Member::class, 'member_id', 'id');
}
}

View File

@@ -215,6 +215,11 @@ class CorporateBenefit extends Model
return $this->belongsTo(Plan::class); return $this->belongsTo(Plan::class);
} }
public function scopeActive($query)
{
$query->where('active', 1);
}
public function scopeFilter($query, array $filters) public function scopeFilter($query, array $filters)
{ {
$query->when($filters['search'] ?? false, function ($query, $search) { $query->when($filters['search'] ?? false, function ($query, $search) {

View File

@@ -4,10 +4,11 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class CorporateManager extends Model class CorporateManager extends Model
{ {
use HasFactory; use HasFactory, SoftDeletes;
protected $table = 'corporate_manager'; protected $table = 'corporate_manager';
} }

View File

@@ -16,10 +16,20 @@ class File extends Model
'fileable_id', 'fileable_id',
'type', 'type',
'name', 'name',
'original_name',
'extension', 'extension',
'path', 'path',
]; ];
protected $hidden = [
'created_at',
'updated_at',
'deleted_at',
'created_by',
'updated_by',
'deleted_by',
];
public $appends = [ public $appends = [
'url' 'url'
]; ];
@@ -27,7 +37,8 @@ class File extends Model
public static $file_directories = [ public static $file_directories = [
'import-temp' => 'import-temp/', 'import-temp' => 'import-temp/',
'avatar' => 'user-avatar/', 'avatar' => 'user-avatar/',
'dataDiri' => 'data-diri/' 'dataDiri' => 'data-diri/',
'claim' => 'claim/'
]; ];
public function fileable() public function fileable()
@@ -45,6 +56,11 @@ class File extends Model
return $type . '-' . $id . '-' . Str::random(10); return $type . '-' . $id . '-' . Str::random(10);
} }
public function getNameAttribute($value)
{
return !empty($this->original_name) ? $this->original_name : ($value . '.' . $this->extension);
}
public function getUrlAttribute() public function getUrlAttribute()
{ {
return url(Storage::url($this->path)); return url(Storage::url($this->path));

View File

@@ -192,12 +192,13 @@ class Member extends Model
public function getNameAttribute() public function getNameAttribute()
{ {
return $this->person->name ?? null; return $this->person->name ?? ($this->name ?? null);
} }
public function getBirthDateAttribute() public function getBirthDateAttribute()
{ {
return Carbon::parse($this->person->birth_date ?? null)->format('Y-m-d') ?? null; $date = $this->person->birth_date ?? ($this->birth_date ?? null);
return !empty($date) ? Carbon::parse($date)->format('Y-m-d') : null;
} }
public function getGenderAttribute() public function getGenderAttribute()

View File

@@ -0,0 +1,27 @@
<?php
namespace App\Models\OLDLMS;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Dokter extends Model
{
use HasFactory, SoftDeletes;
const CREATED_AT = 'dCreateOn';
const UPDATED_AT = 'dUpdateOn';
const DELETED_AT = 'dDeleteOn';
protected $connection = 'oldlms';
protected $table = 'tm_dokter';
protected $primaryKey = 'nID';
public function jadwalDokter()
{
return $this->hasMany(JadwalDokter::class, 'nIDDokter', 'nID');
}
}

View File

@@ -4,8 +4,24 @@ namespace App\Models\OLDLMS;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Healthcare extends Model class Healthcare extends Model
{ {
use HasFactory; use HasFactory, SoftDeletes;
const CREATED_AT = 'dCreateOn';
const UPDATED_AT = 'dUpdateOn';
const DELETED_AT = 'dDeleteOn';
protected $connection = 'oldlms';
protected $table = 'tm_healthcare';
protected $primaryKey = 'nID';
public function jadwalDokter()
{
return $this->hasMany(JadwalDokter::class, 'nIDHealthCare', 'nID');
}
} }

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Models\OLDLMS;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class JadwalDokter extends Model
{
use HasFactory, SoftDeletes;
const CREATED_AT = 'dCreateOn';
const UPDATED_AT = 'dUpdateOn';
const DELETED_AT = 'dDeleteOn';
protected $connection = 'oldlms';
protected $table = 'tx_jadwal_dokter';
protected $primaryKey = 'nID';
public function jadwalDokterDay()
{
return $this->hasMany(JadwalDokterDay::class, 'nIDJadwalDokter', 'nID');
}
public function healthcare()
{
return $this->belongsTo(Healthcare::class, 'nIDHealthCare', 'nID');
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Models\OLDLMS;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class JadwalDokterDay extends Model
{
use HasFactory, SoftDeletes;
const CREATED_AT = 'dCreateOn';
const UPDATED_AT = 'dUpdateOn';
const DELETED_AT = 'dDeleteOn';
protected $connection = 'oldlms';
protected $table = 'tx_jadwal_dokter_detail';
protected $primaryKey = 'nID';
}

View File

@@ -182,7 +182,63 @@ class Plan extends Model
return $this->belongsToMany(Benefit::class, 'corporate_benefits', 'plan_id', 'benefit_id') return $this->belongsToMany(Benefit::class, 'corporate_benefits', 'plan_id', 'benefit_id')
->withTimestamps() ->withTimestamps()
->withPivot([ ->withPivot([
// TODO corporate_benefits pivot 'corporate_id',
'plan_id',
'benefit_id',
'corporate_benefit_code',
'budget',
'budget_conditions',
'budget_code',
'primary_benefit_code',
'benefit_mode',
'room_class_coverage',
'max_bed_coverage',
'tolerance_parameter',
'max_room_class',
'limit_amount',
'area_limit',
'shared_benefit',
'shared_benefit_type',
'msc',
'genders',
'min_age',
'max_age',
'max_frequency_period',
'daily_frequency',
'weekly_frequency',
'monthly_frequency',
'yearly_frequency',
'custom_frequency_days',
'custom_duration_value',
'allowed_transaction_types',
'high_plan_factor',
'pre_post_treatment',
'pre_treatment_days',
'post_treatment_days',
'layer_type_1',
'layer_value_1',
'layer_type_2',
'layer_value_2',
'cashless_percentage',
'reimbursement_percentage',
'digital_percentage',
'co_share_m_percentage',
'co_share_s_percentage',
'co_share_c_percentage',
'cashless_deductible',
'reimbursement_deductible',
'digital_deductible',
'co_share_m_deductible',
'co_share_s_deductible',
'co_share_c_deductible',
'prorate_type',
'prorate_lookup',
'max_days_for_disability',
'max_period_for_disability',
'currency',
'show_benefit_item',
'show_benefit_value',
'active'
]); ]);
} }
@@ -190,4 +246,9 @@ class Plan extends Model
{ {
return $this->hasMany(CorporateBenefit::class, 'plan_id', 'id'); return $this->hasMany(CorporateBenefit::class, 'plan_id', 'id');
} }
public function service()
{
return $this->belongsTo(Service::class, 'service_code', 'code');
}
} }

View File

@@ -14,4 +14,9 @@ class Service extends Model
'name', 'name',
'description', 'description',
]; ];
public function corporateService()
{
return $this->hasMany(CorporateService::class, 'service_code', 'code');
}
} }

View File

@@ -7,10 +7,11 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens; use Laravel\Sanctum\HasApiTokens;
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable class User extends Authenticatable
{ {
use HasApiTokens, HasFactory, Notifiable; use HasApiTokens, HasFactory, Notifiable, HasRoles;
/** /**
* The attributes that are mass assignable. * The attributes that are mass assignable.
@@ -48,13 +49,26 @@ class User extends Authenticatable
]; ];
public $with = [ public $with = [
'metas' 'metas',
'person'
]; ];
public $appends = [ public $appends = [
'meta' 'meta',
'avatar_url',
'full_name'
]; ];
public function getAvatarUrlAttribute()
{
return asset('images/specialities/anak.png');
}
public function getFullNameAttribute()
{
return $this->person?->full_name;
}
public function getMetaAttribute() public function getMetaAttribute()
{ {
$orgMeta = []; $orgMeta = [];

View File

@@ -112,8 +112,12 @@ class ClaimService{
// $policy = $member->currentPolicy; // $policy = $member->currentPolicy;
// $corporate = $member->currentCorporate; // $corporate = $member->currentCorporate;
$benefit = $member->currentPlan->benefits()->where('code', $benefit_code)->first(); $benefit = $member->currentPlan->benefits()->where('code', $benefit_code)->first();
// dd($member->currentPlan->benefits->toArray()); $corporateBenefit = $member->currentPlan
$corporateBenefit = $member->currentPlan->corporateBenefits()->where('benefit_id', $benefit->id)->first(); ->corporateBenefits()
->where('benefit_id', $benefit->id ?? null)
->where('plan_id', $member->currentPlan->id)
->active()
->first();
// dd($benefit->toArray()); // dd($benefit->toArray());
// dd(compact(['plan', 'policy', 'corporate', 'benefit'])); // dd(compact(['plan', 'policy', 'corporate', 'benefit']));
@@ -129,7 +133,7 @@ class ClaimService{
'usage_yearly' => null 'usage_yearly' => null
]; ];
switch ($corporateBenefit->max_frequency_period) { switch ($corporateBenefit->max_frequency_period ?? 0) {
case(0) : case(0) :
$limits['usage_yearly'] = $member->claims()->used(Carbon::now()->firstOfYear(), now())->count(); $limits['usage_yearly'] = $member->claims()->used(Carbon::now()->firstOfYear(), now())->count();
$limits['total_claim'] = $member->claims()->used(Carbon::now()->firstOfYear(), now())->sum('total_claim'); $limits['total_claim'] = $member->claims()->used(Carbon::now()->firstOfYear(), now())->sum('total_claim');
@@ -154,7 +158,7 @@ class ClaimService{
// return null; // return null;
break; break;
} }
$limits['remaining_limit'] = $corporateBenefit->limit_amount - $limits['total_claim']; $limits['remaining_limit'] = ($corporateBenefit->limit_amount ?? 0) - $limits['total_claim'];
return $limits; return $limits;
} }

View File

@@ -39,19 +39,36 @@ class LmsApi
$data['channel'] = 'Website'; $data['channel'] = 'Website';
} }
$res = self::http()->post( self::baseUrl() . '/jadwaldokter', $data)->json(); $res = self::http()->post(self::baseUrl() . '/jadwaldokter', $data)->json();
// Reformat Jam Data // Reformat Jam Data
$res['data'] = collect($res['data'])->map(function($day) { $res['data'] = collect($res['data'])->map(function ($day) {
$day['Jam'] = !empty($day['Jam']) ? explode(', ', $day['Jam']) : null; $day['Jam'] = !empty($day['Jam']) ? explode(', ', $day['Jam']) : null;
return $day; return $day;
})->toArray(); })->toArray();
return $res; return $res;
} }
/**
* dokter
*
*
*/
public static function dokter($kodeRs, $channel = 'hospitaloka', $timeout = 30)
{
$data = [
'rs' => $kodeRs,
'channel' => $channel,
];
$res = self::http()->timeout($timeout)->post('http://lmsapi.primaya.id/dokter', $data)->json();
return $res;
}
/** /**
* jadwalDokterTersedia * jadwalDokterTersedia
* *
@@ -72,21 +89,20 @@ class LmsApi
$data['channel'] = 'Website'; $data['channel'] = 'Website';
} }
$res = self::http()->post( self::baseUrl() . '/jadwaldoktertersedia', $data)->json(); $res = self::http()->post(self::baseUrl() . '/jadwaldoktertersedia', $data)->json();
// Reformat Jam Data // Reformat Jam Data
$res['data'] = collect($res['data'])->map(function($day) { $res['data'] = collect($res['data'])->map(function ($day) {
// Change jam to Jam to Standarize // Change jam to Jam to Standarize
$day['Jam'] = !empty($day['jam']) ? explode(', ', $day['jam']) : null; $day['Jam'] = !empty($day['jam']) ? explode(', ', $day['jam']) : null;
unset($day['jam']); unset($day['jam']);
return $day; return $day;
})->toArray(); })->toArray();
return $res; return $res;
} }
/** /**
* checkMedrec * checkMedrec
* *
@@ -113,11 +129,11 @@ class LmsApi
throw new Exception('name, birth_date, nik, phone are required in $patientData'); throw new Exception('name, birth_date, nik, phone are required in $patientData');
} }
$res = self::http()->post( self::baseUrl() . '/medrec_nama', $data)->json(); $res = self::http()->post(self::baseUrl() . '/medrec_nama', $data)->json();
return $res; return $res;
} }
/** /**
* checkGantung * checkGantung
* *
@@ -126,7 +142,7 @@ class LmsApi
* @return void * @return void
*/ */
public static function checkGantung($HISKodeRS, $HISMedrec, $patientData) public static function checkGantung($HISKodeRS, $HISMedrec, $patientData)
{ {
$data = [ $data = [
'rs' => $HISKodeRS, 'rs' => $HISKodeRS,
'rm' => $HISMedrec, 'rm' => $HISMedrec,
@@ -141,11 +157,11 @@ class LmsApi
throw new Exception('name, birth_date are required in $patientData'); throw new Exception('name, birth_date are required in $patientData');
} }
$res = self::http()->post( self::baseUrl() . '/cek_gantung', $data)->json(); $res = self::http()->post(self::baseUrl() . '/cek_gantung', $data)->json();
return $res; return $res;
} }
/** /**
* checkSlot * checkSlot
* *
@@ -156,9 +172,9 @@ class LmsApi
* @param string $type HIS Slot Type walkin, teleconsultation * @param string $type HIS Slot Type walkin, teleconsultation
* @return void * @return void
*/ */
public static function checkSlot( $HISKodeRS, $HISKodeDokter, $tanggalAppointment, $jamAppointment, $type ) public static function checkSlot($HISKodeRS, $HISKodeDokter, $tanggalAppointment, $jamAppointment, $type)
{ {
$data = [ $data = [
'rs' => $HISKodeRS, 'rs' => $HISKodeRS,
'dr' => $HISKodeDokter, 'dr' => $HISKodeDokter,
@@ -169,11 +185,11 @@ class LmsApi
$data['channel'] = 'Website'; $data['channel'] = 'Website';
} }
$res = self::http()->post( self::baseUrl() . '/cek_slot', $data)->json(); $res = self::http()->post(self::baseUrl() . '/cek_slot', $data)->json();
return $res; return $res;
} }
/** /**
* appointmentBaru * appointmentBaru
* *
@@ -189,7 +205,8 @@ class LmsApi
* @param mixed $userId * @param mixed $userId
* @return void * @return void
*/ */
public static function appointmentBaru( $HISKodeRS, $HISKodeDep, $HISKodeDokter, $jenisTC, $tanggalAppointment, $jamAppointment, $jumlahBayar, $kodePembayaran, $patientData, $userId ) { public static function appointmentBaru($HISKodeRS, $HISKodeDep, $HISKodeDokter, $jenisTC, $tanggalAppointment, $jamAppointment, $jumlahBayar, $kodePembayaran, $patientData, $userId)
{
$data = [ $data = [
'rs' => $HISKodeRS, 'rs' => $HISKodeRS,
'dep' => $HISKodeDep, 'dep' => $HISKodeDep,
@@ -220,11 +237,11 @@ class LmsApi
'jam' => $jamAppointment, 'jam' => $jamAppointment,
]; ];
$res = self::http()->post( self::baseUrl() . '/appointment_baru', $data)->json(); $res = self::http()->post(self::baseUrl() . '/appointment_baru', $data)->json();
return $res; return $res;
} }
/** /**
* appointment * appointment
* *
@@ -241,7 +258,8 @@ class LmsApi
* @param mixed $userId * @param mixed $userId
* @return void * @return void
*/ */
public static function appointment( $HISKodeRS, $HISKodeDep, $HISKodeDokter, $jenisTC, $tanggalAppointment, $jamAppointment, $jumlahBayar, $kodePembayaran, $HISMedrec, $patientData, $userId ) { public static function appointment($HISKodeRS, $HISKodeDep, $HISKodeDokter, $jenisTC, $tanggalAppointment, $jamAppointment, $jumlahBayar, $kodePembayaran, $HISMedrec, $patientData, $userId)
{
$data = [ $data = [
'rs' => $HISKodeRS, 'rs' => $HISKodeRS,
'dep' => $HISKodeDep, 'dep' => $HISKodeDep,
@@ -259,11 +277,11 @@ class LmsApi
'jam' => $jamAppointment, 'jam' => $jamAppointment,
]; ];
$res = self::http()->post( self::baseUrl() . '/appointment', $data)->json(); $res = self::http()->post(self::baseUrl() . '/appointment', $data)->json();
return $res; return $res;
} }
/** /**
* appointmentEdit * appointmentEdit
* *
@@ -277,7 +295,7 @@ class LmsApi
* @param mixed $patientData * @param mixed $patientData
* @return void * @return void
*/ */
public static function appointmentEdit( $HISRegid, $HISKodeRS, $HISKodeDep, $HISKodeDokter, $tanggalAppointment, $jamAppointment, $HISMedrec, $patientData ) public static function appointmentEdit($HISRegid, $HISKodeRS, $HISKodeDep, $HISKodeDokter, $tanggalAppointment, $jamAppointment, $HISMedrec, $patientData)
{ {
$data = [ $data = [
'regid' => $HISRegid, 'regid' => $HISRegid,
@@ -293,11 +311,11 @@ class LmsApi
'jam' => $jamAppointment, 'jam' => $jamAppointment,
]; ];
$res = self::http()->post( self::baseUrl() . '/appointment_edit', $data)->json(); $res = self::http()->post(self::baseUrl() . '/appointment_edit', $data)->json();
return $res; return $res;
} }
/** /**
* booking * booking
* *
@@ -314,7 +332,8 @@ class LmsApi
* @param mixed $nomorRujukanBPJS * @param mixed $nomorRujukanBPJS
* @return void * @return void
*/ */
public static function booking( $HISKodeRS, $HISKodeDep, $HISKodeDokter, $tanggalAppointment, $jamAppointment, $HISMedrec, $patientData, $jenisPenjamin = 0, $namaPenjamin = '', $nomorKartuBPJS = null, $nomorRujukanBPJS = null ) { public static function booking($HISKodeRS, $HISKodeDep, $HISKodeDokter, $tanggalAppointment, $jamAppointment, $HISMedrec, $patientData, $jenisPenjamin = 0, $namaPenjamin = '', $nomorKartuBPJS = null, $nomorRujukanBPJS = null)
{
$data = [ $data = [
'rs' => $HISKodeRS, 'rs' => $HISKodeRS,
'dep' => $HISKodeDep, 'dep' => $HISKodeDep,
@@ -334,11 +353,11 @@ class LmsApi
'norujukan' => $nomorRujukanBPJS 'norujukan' => $nomorRujukanBPJS
]; ];
$res = self::http()->post( self::baseUrl() . '/booking', $data)->json(); $res = self::http()->post(self::baseUrl() . '/booking', $data)->json();
return $res; return $res;
} }
/** /**
* bookingBaru * bookingBaru
* *
@@ -354,7 +373,8 @@ class LmsApi
* @param mixed $nomorRujukanBPJS * @param mixed $nomorRujukanBPJS
* @return void * @return void
*/ */
public static function bookingBaru( $HISKodeRS, $HISKodeDep, $HISKodeDokter, $tanggalAppointment, $jamAppointment, $patientData, $jenisPenjamin = 0, $namaPenjamin = '', $nomorKartuBPJS = null, $nomorRujukanBPJS = null) { public static function bookingBaru($HISKodeRS, $HISKodeDep, $HISKodeDokter, $tanggalAppointment, $jamAppointment, $patientData, $jenisPenjamin = 0, $namaPenjamin = '', $nomorKartuBPJS = null, $nomorRujukanBPJS = null)
{
$data = [ $data = [
'rs' => $HISKodeRS, 'rs' => $HISKodeRS,
'dep' => $HISKodeDep, 'dep' => $HISKodeDep,
@@ -385,12 +405,12 @@ class LmsApi
'nokartu' => $nomorKartuBPJS, 'nokartu' => $nomorKartuBPJS,
'norujukan' => $nomorRujukanBPJS 'norujukan' => $nomorRujukanBPJS
]; ];
$res = self::http()->post( self::baseUrl() . '/booking_baru', $data)->json(); $res = self::http()->post(self::baseUrl() . '/booking_baru', $data)->json();
return $res; return $res;
} }
/** /**
* bookingEdit * bookingEdit
* Used for Rescheduling appointment * Used for Rescheduling appointment
@@ -409,7 +429,8 @@ class LmsApi
* @param mixed $nomorRujukanBPJS * @param mixed $nomorRujukanBPJS
* @return void * @return void
*/ */
public static function bookingEdit( $kodeBooking, $HISKodeRS, $HISKodeDep, $HISKodeDokter, $tanggalAppointment, $jamAppointment, $tanggalAppointmentBaru, $jamAppointmentBaru, $jenisPenjamin = 0, $namaPenjamin = '', $nomorKartuBPJS = null, $nomorRujukanBPJS = null ) { public static function bookingEdit($kodeBooking, $HISKodeRS, $HISKodeDep, $HISKodeDokter, $tanggalAppointment, $jamAppointment, $tanggalAppointmentBaru, $jamAppointmentBaru, $jenisPenjamin = 0, $namaPenjamin = '', $nomorKartuBPJS = null, $nomorRujukanBPJS = null)
{
$data = [ $data = [
'kodebooking' => $kodeBooking, 'kodebooking' => $kodeBooking,
'rs' => $HISKodeRS, 'rs' => $HISKodeRS,
@@ -424,16 +445,16 @@ class LmsApi
'tglbaru' => $tanggalAppointmentBaru, 'tglbaru' => $tanggalAppointmentBaru,
'jambaru' => $jamAppointmentBaru, 'jambaru' => $jamAppointmentBaru,
]; ];
$res = self::http()->post( self::baseUrl() . '/booking_edit', $data)->json(); $res = self::http()->post(self::baseUrl() . '/booking_edit', $data)->json();
return $res; return $res;
} }
public static function bookingPaket($kodeRs, $kodeDep, $rm, $ktp, $nama_pasien, $tgl_lahir, $email, $telp, $tgl, $jam, $jenis_penjamin, $penjamin, $paket, $jenis_paket) public static function bookingPaket($kodeRs, $kodeDep, $rm, $ktp, $nama_pasien, $tgl_lahir, $email, $telp, $tgl, $jam, $jenis_penjamin, $penjamin, $paket, $jenis_paket)
{ {
throw new Exception("Not Implemented", 1); throw new Exception("Not Implemented", 1);
$url = Http::withHeaders([ $url = Http::withHeaders([
'id' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjE3NWZiNDI0LTA4MzMtNGZiMS1iOWNhLWQwMzQ5Nzc' 'id' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjE3NWZiNDI0LTA4MzMtNGZiMS1iOWNhLWQwMzQ5Nzc'
])->post('http://lmsapidev.primaya.id/booking_paket', [ ])->post('http://lmsapidev.primaya.id/booking_paket', [
@@ -485,7 +506,7 @@ class LmsApi
$jenis_paket $jenis_paket
) { ) {
throw new Exception("Not Implemented", 1); throw new Exception("Not Implemented", 1);
$url = Http::withHeaders([ $url = Http::withHeaders([
'id' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjE3NWZiNDI0LTA4MzMtNGZiMS1iOWNhLWQwMzQ5Nzc' 'id' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjE3NWZiNDI0LTA4MzMtNGZiMS1iOWNhLWQwMzQ5Nzc'
])->post('http://lmsapidev.primaya.id/booking_baru_paket', [ ])->post('http://lmsapidev.primaya.id/booking_baru_paket', [
@@ -537,7 +558,7 @@ class LmsApi
$jenis_paket $jenis_paket
) { ) {
throw new Exception("Not Implemented", 1); throw new Exception("Not Implemented", 1);
$url = Http::withHeaders([ $url = Http::withHeaders([
'id' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjE3NWZiNDI0LTA4MzMtNGZiMS1iOWNhLWQwMzQ5Nzc' 'id' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjE3NWZiNDI0LTA4MzMtNGZiMS1iOWNhLWQwMzQ5Nzc'
])->post('http://lmsapidev.primaya.id/booking_edit_paket', [ ])->post('http://lmsapidev.primaya.id/booking_edit_paket', [
@@ -558,7 +579,7 @@ class LmsApi
return $url; return $url;
} }
public static function bookingBayar( $kodeBooking, $HISKodeRS, $tanggalBooking, $jumlahBayar, $merchantCode, $merchantOrderId, $reference) public static function bookingBayar($kodeBooking, $HISKodeRS, $tanggalBooking, $jumlahBayar, $merchantCode, $merchantOrderId, $reference)
{ {
$data = [ $data = [
"rs" => $HISKodeRS, "rs" => $HISKodeRS,
@@ -570,9 +591,9 @@ class LmsApi
'merchantorderid' => $merchantOrderId, 'merchantorderid' => $merchantOrderId,
'reference' => $reference, 'reference' => $reference,
]; ];
$res = self::http()->post( self::baseUrl() . '/booking_bayar', $data)->json(); $res = self::http()->post(self::baseUrl() . '/booking_bayar', $data)->json();
return $res; return $res;
} }
@@ -603,4 +624,4 @@ class LmsApi
return $url; return $url;
} }
} }

View File

@@ -6,9 +6,11 @@
"license": "MIT", "license": "MIT",
"require": { "require": {
"php": "^8.0.2", "php": "^8.0.2",
"barryvdh/laravel-snappy": "^1.0",
"box/spout": "^3.3", "box/spout": "^3.3",
"duitkupg/duitku-php": "dev-master", "duitkupg/duitku-php": "dev-master",
"guzzlehttp/guzzle": "^7.2", "guzzlehttp/guzzle": "^7.2",
"h4cc/wkhtmltopdf-amd64": "0.12.x",
"laravel/framework": "^9.11", "laravel/framework": "^9.11",
"laravel/sanctum": "^2.15", "laravel/sanctum": "^2.15",
"laravel/socialite": "^5.5", "laravel/socialite": "^5.5",
@@ -16,7 +18,8 @@
"maatwebsite/excel": "^3.1", "maatwebsite/excel": "^3.1",
"nwidart/laravel-modules": "^9.0", "nwidart/laravel-modules": "^9.0",
"psr/simple-cache": "^1.0", "psr/simple-cache": "^1.0",
"pusher/pusher-php-server": "^7.2" "pusher/pusher-php-server": "^7.2",
"spatie/laravel-permission": "^5.9"
}, },
"require-dev": { "require-dev": {
"barryvdh/laravel-debugbar": "^3.7", "barryvdh/laravel-debugbar": "^3.7",

1277
composer.lock generated Executable file → Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -187,6 +187,8 @@ return [
*/ */
Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class, Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class,
Maatwebsite\Excel\ExcelServiceProvider::class, Maatwebsite\Excel\ExcelServiceProvider::class,
Barryvdh\Snappy\ServiceProvider::class,
Spatie\Permission\PermissionServiceProvider::class,
/* /*
* Application Service Providers... * Application Service Providers...
@@ -218,6 +220,8 @@ return [
'Duitku' => App\Services\Duitku::class, 'Duitku' => App\Services\Duitku::class,
'Excel' => Maatwebsite\Excel\Facades\Excel::class, 'Excel' => Maatwebsite\Excel\Facades\Excel::class,
'LmsApi' => App\Services\LmsApi::class, 'LmsApi' => App\Services\LmsApi::class,
'PDF' => Barryvdh\Snappy\Facades\SnappyPdf::class,
'SnappyImage' => Barryvdh\Snappy\Facades\SnappyImage::class,
])->toArray(), ])->toArray(),
]; ];

161
config/permission.php Normal file
View File

@@ -0,0 +1,161 @@
<?php
return [
'models' => [
/*
* When using the "HasPermissions" trait from this package, we need to know which
* Eloquent model should be used to retrieve your permissions. Of course, it
* is often just the "Permission" model but you may use whatever you like.
*
* The model you want to use as a Permission model needs to implement the
* `Spatie\Permission\Contracts\Permission` contract.
*/
'permission' => Spatie\Permission\Models\Permission::class,
/*
* When using the "HasRoles" trait from this package, we need to know which
* Eloquent model should be used to retrieve your roles. Of course, it
* is often just the "Role" model but you may use whatever you like.
*
* The model you want to use as a Role model needs to implement the
* `Spatie\Permission\Contracts\Role` contract.
*/
'role' => Spatie\Permission\Models\Role::class,
],
'table_names' => [
/*
* When using the "HasRoles" trait from this package, we need to know which
* table should be used to retrieve your roles. We have chosen a basic
* default value but you may easily change it to any table you like.
*/
'roles' => 'roles',
/*
* When using the "HasPermissions" trait from this package, we need to know which
* table should be used to retrieve your permissions. We have chosen a basic
* default value but you may easily change it to any table you like.
*/
'permissions' => 'permissions',
/*
* When using the "HasPermissions" trait from this package, we need to know which
* table should be used to retrieve your models permissions. We have chosen a
* basic default value but you may easily change it to any table you like.
*/
'model_has_permissions' => 'model_has_permissions',
/*
* When using the "HasRoles" trait from this package, we need to know which
* table should be used to retrieve your models roles. We have chosen a
* basic default value but you may easily change it to any table you like.
*/
'model_has_roles' => 'model_has_roles',
/*
* When using the "HasRoles" trait from this package, we need to know which
* table should be used to retrieve your roles permissions. We have chosen a
* basic default value but you may easily change it to any table you like.
*/
'role_has_permissions' => 'role_has_permissions',
],
'column_names' => [
/*
* Change this if you want to name the related pivots other than defaults
*/
'role_pivot_key' => null, //default 'role_id',
'permission_pivot_key' => null, //default 'permission_id',
/*
* Change this if you want to name the related model primary key other than
* `model_id`.
*
* For example, this would be nice if your primary keys are all UUIDs. In
* that case, name this `model_uuid`.
*/
'model_morph_key' => 'model_id',
/*
* Change this if you want to use the teams feature and your related model's
* foreign key is other than `team_id`.
*/
'team_foreign_key' => 'team_id',
],
/*
* When set to true, the method for checking permissions will be registered on the gate.
* Set this to false, if you want to implement custom logic for checking permissions.
*/
'register_permission_check_method' => true,
/*
* When set to true the package implements teams using the 'team_foreign_key'. If you want
* the migrations to register the 'team_foreign_key', you must set this to true
* before doing the migration. If you already did the migration then you must make a new
* migration to also add 'team_foreign_key' to 'roles', 'model_has_roles', and
* 'model_has_permissions'(view the latest version of package's migration file)
*/
'teams' => false,
/*
* When set to true, the required permission names are added to the exception
* message. This could be considered an information leak in some contexts, so
* the default setting is false here for optimum safety.
*/
'display_permission_in_exception' => false,
/*
* When set to true, the required role names are added to the exception
* message. This could be considered an information leak in some contexts, so
* the default setting is false here for optimum safety.
*/
'display_role_in_exception' => false,
/*
* By default wildcard permission lookups are disabled.
*/
'enable_wildcard_permission' => false,
'cache' => [
/*
* By default all permissions are cached for 24 hours to speed up performance.
* When permissions or roles are updated the cache is flushed automatically.
*/
'expiration_time' => \DateInterval::createFromDateString('24 hours'),
/*
* The cache key used to store all permissions.
*/
'key' => 'spatie.permission.cache',
/*
* You may optionally indicate a specific cache driver to use for permission and
* role caching using any of the `store` drivers listed in the cache.php config
* file. Using 'default' here means to use the `default` set in cache.php.
*/
'store' => 'default',
],
];

52
config/snappy.php Normal file
View File

@@ -0,0 +1,52 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Snappy PDF / Image Configuration
|--------------------------------------------------------------------------
|
| This option contains settings for PDF generation.
|
| Enabled:
|
| Whether to load PDF / Image generation.
|
| Binary:
|
| The file path of the wkhtmltopdf / wkhtmltoimage executable.
|
| Timout:
|
| The amount of time to wait (in seconds) before PDF / Image generation is stopped.
| Setting this to false disables the timeout (unlimited processing time).
|
| Options:
|
| The wkhtmltopdf command options. These are passed directly to wkhtmltopdf.
| See https://wkhtmltopdf.org/usage/wkhtmltopdf.txt for all options.
|
| Env:
|
| The environment variables to set while running the wkhtmltopdf process.
|
*/
'pdf' => [
'enabled' => true,
'binary' => env('WKHTML_PDF_BINARY', '/usr/local/bin/wkhtmltopdf'),
'timeout' => false,
'options' => [],
'env' => [],
],
'image' => [
'enabled' => true,
'binary' => env('WKHTML_IMG_BINARY', '/usr/local/bin/wkhtmltoimage'),
'timeout' => false,
'options' => [],
'env' => [],
],
];

View File

@@ -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('claim_requests', function (Blueprint $table) {
$table->id();
$table->string('code')->index();
$table->dateTime('submission_date')->nullable();
$table->foreignId('member_id');
$table->string('status')->nullable();
$table->foreignId('claim_id')->nullable()->comment('After Claim is Created');
$table->timestamps();
$table->softDeletes();
$table->unsignedBigInteger('created_by')->nullable()->index();
$table->unsignedBigInteger('updated_by')->nullable()->index();
$table->unsignedBigInteger('deleted_by')->nullable()->index();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('claim_requests');
}
};

View File

@@ -0,0 +1,141 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Spatie\Permission\PermissionRegistrar;
class CreatePermissionTables extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$tableNames = config('permission.table_names');
$columnNames = config('permission.column_names');
$teams = config('permission.teams');
if (empty($tableNames)) {
throw new \Exception('Error: config/permission.php not loaded. Run [php artisan config:clear] and try again.');
}
if ($teams && empty($columnNames['team_foreign_key'] ?? null)) {
throw new \Exception('Error: team_foreign_key on config/permission.php not loaded. Run [php artisan config:clear] and try again.');
}
Schema::create($tableNames['permissions'], function (Blueprint $table) {
$table->bigIncrements('id'); // permission id
$table->string('name'); // For MySQL 8.0 use string('name', 125);
$table->string('guard_name'); // For MySQL 8.0 use string('guard_name', 125);
$table->timestamps();
$table->unique(['name', 'guard_name']);
});
Schema::create($tableNames['roles'], function (Blueprint $table) use ($teams, $columnNames) {
$table->bigIncrements('id'); // role id
if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing
$table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable();
$table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index');
}
$table->string('name'); // For MySQL 8.0 use string('name', 125);
$table->string('guard_name'); // For MySQL 8.0 use string('guard_name', 125);
$table->timestamps();
if ($teams || config('permission.testing')) {
$table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']);
} else {
$table->unique(['name', 'guard_name']);
}
});
Schema::create($tableNames['model_has_permissions'], function (Blueprint $table) use ($tableNames, $columnNames, $teams) {
$table->unsignedBigInteger(PermissionRegistrar::$pivotPermission);
$table->string('model_type');
$table->unsignedBigInteger($columnNames['model_morph_key']);
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index');
$table->foreign(PermissionRegistrar::$pivotPermission)
->references('id') // permission id
->on($tableNames['permissions'])
->onDelete('cascade');
if ($teams) {
$table->unsignedBigInteger($columnNames['team_foreign_key']);
$table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index');
$table->primary([$columnNames['team_foreign_key'], PermissionRegistrar::$pivotPermission, $columnNames['model_morph_key'], 'model_type'],
'model_has_permissions_permission_model_type_primary');
} else {
$table->primary([PermissionRegistrar::$pivotPermission, $columnNames['model_morph_key'], 'model_type'],
'model_has_permissions_permission_model_type_primary');
}
});
Schema::create($tableNames['model_has_roles'], function (Blueprint $table) use ($tableNames, $columnNames, $teams) {
$table->unsignedBigInteger(PermissionRegistrar::$pivotRole);
$table->string('model_type');
$table->unsignedBigInteger($columnNames['model_morph_key']);
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index');
$table->foreign(PermissionRegistrar::$pivotRole)
->references('id') // role id
->on($tableNames['roles'])
->onDelete('cascade');
if ($teams) {
$table->unsignedBigInteger($columnNames['team_foreign_key']);
$table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index');
$table->primary([$columnNames['team_foreign_key'], PermissionRegistrar::$pivotRole, $columnNames['model_morph_key'], 'model_type'],
'model_has_roles_role_model_type_primary');
} else {
$table->primary([PermissionRegistrar::$pivotRole, $columnNames['model_morph_key'], 'model_type'],
'model_has_roles_role_model_type_primary');
}
});
Schema::create($tableNames['role_has_permissions'], function (Blueprint $table) use ($tableNames) {
$table->unsignedBigInteger(PermissionRegistrar::$pivotPermission);
$table->unsignedBigInteger(PermissionRegistrar::$pivotRole);
$table->foreign(PermissionRegistrar::$pivotPermission)
->references('id') // permission id
->on($tableNames['permissions'])
->onDelete('cascade');
$table->foreign(PermissionRegistrar::$pivotRole)
->references('id') // role id
->on($tableNames['roles'])
->onDelete('cascade');
$table->primary([PermissionRegistrar::$pivotPermission, PermissionRegistrar::$pivotRole], 'role_has_permissions_permission_id_role_id_primary');
});
app('cache')
->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null)
->forget(config('permission.cache.key'));
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
$tableNames = config('permission.table_names');
if (empty($tableNames)) {
throw new \Exception('Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.');
}
Schema::drop($tableNames['role_has_permissions']);
Schema::drop($tableNames['model_has_roles']);
Schema::drop($tableNames['model_has_permissions']);
Schema::drop($tableNames['roles']);
Schema::drop($tableNames['permissions']);
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('files', function (Blueprint $table) {
$table->string('original_name')->nullable()->after('name');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('files', function (Blueprint $table) {
$table->dropColumn('original_name');
});
}
};

View File

@@ -17,18 +17,23 @@ class DummyMemberSeeder extends Seeder
public function run() public function run()
{ {
$userEmails = [ $userEmails = [
'admin@linksehat.dev', 'admin@linksehat.dev' => ['administrator'],
'manager+one@gmail.com', 'manager+one@gmail.com' => ['corporate-manager'],
'manager+two@gmail.com' 'manager+two@gmail.com' => ['corporate-manager'],
'hospitaladmin@gmail.com' => ['hospital-admin']
]; ];
foreach ($userEmails as $email) { foreach ($userEmails as $email => $roles) {
User::updateOrCreate([ $user = User::updateOrCreate([
'email' => $email 'email' => $email
], [ ], [
'email' => $email, 'email' => $email,
'password' => Hash::make('password') 'password' => Hash::make('password')
]); ]);
if (isset($roles) && count($roles)) {
$user->syncRoles($roles);
}
} }
} }
} }

View File

@@ -0,0 +1,143 @@
<?php
namespace Database\Seeders;
use App\Models\OLDLMS\Healthcare;
use App\Models\OLDLMS\JadwalDokter;
use App\Models\OLDLMS\JadwalDokterDay;
use App\Services\LmsApi;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class JadwalDokterSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$mapHealthcare = [
'Q',
'C',
'D',
'E',
'F',
'M',
'O',
'P',
'Q',
'N',
'SG',
'BW',
'SK',
'PK',
'CK',
'DE'
];
$healthcares = Healthcare::whereIn('sKodeRS', $mapHealthcare)->get();
foreach ($healthcares as $healthcare) {
$jadwalDokterDay = LmsApi::dokter($healthcare->sKodeRS, 'hospitaloka', 300);
if (empty($jadwalDokterDay['data'])) {
continue;
}
$listDokter = $jadwalDokterDay['data'];
foreach ($listDokter as $dokter) {
$jadwalDokter = JadwalDokter::where('sIDDokter', $dokter['id'])->where('sDepartmenID', $dokter['DepartemenID'])->first() ?? null;
if ($jadwalDokter == null) {
continue;
}
// if ($jadwalDokter->nID != 1901) {
// continue;
// }
$jadwalDokterDay = $jadwalDokter->jadwalDokterDay()->get() ?? null;
// JadwalDokterDay::where('nIDJadwalDokter', $jadwalDokter->nID)->get() ?? null;
if ($jadwalDokterDay == null) {
continue;
}
// dd($dokter);
$listShcedule = $dokter['JadwalDokter'];
foreach ($jadwalDokterDay as $day) {
$NewJam = "";
foreach ($listShcedule as $key => $schedule) {
$jam = $schedule['Jam'];
$cek = $schedule['Jam'];
//jika jam memiliki hurug A-Z
if (preg_match('/[A-Z]/', $jam)) {
$jam = $jam;
} else {
//jika terdapat titik
if (strpos($jam, ".") !== false) {
//ganti titik dengan : dan tambahkan 00
$jam = str_replace(".", ":", $jam);
//jika jam nya terdapat strip
if (strpos($jam, "-") !== false) {
//jika didepan strip dan belakang strip ada spasi
if (strpos($jam, " ") !== false) {
//hapus spasi
$jam = str_replace(" ", "", $jam);
}
// try{
$jam = explode("-", $jam);
$jam = $jam[0] . " - " . $jam[1];
// } catch (\Exception $e) {
// $this->command->error($cek . "Id dokter : " . $jadwalDokter->nID);
// }
} else {
$jam = $jam;
}
} else {
//jika terdapat strip
if (strpos($jam, "-") !== false) {
//jika hanya ada strip tidak ada yang lain
if (strlen($jam) > 1) {
//jika sudah ada : maka diabaikan
if (strpos($jam, ":") !== false) {
$jam = explode("-", $jam);
$jam = $jam[0] . " - " . $jam[1];
} else {
//jika didepan strip ada spasi
if (strpos($jam, " ") !== false) {
//hapus spasi
$jam = str_replace(" ", "", $jam);
}
$jam = explode("-", $jam);
$jam = $jam[0] . ":00 - " . $jam[1] . ":00";
}
}
} else if (strpos($jam, ":") !== false) {
$jam = $jam;
} else {
$jam = $jam . ":00";
}
}
}
if ($day->sHari == $schedule['Hari']) {
if ($schedule['Jam'] == null) {
$NewJam = "";
} else {
$NewJam = $jam;
}
} else {
continue;
}
}
$day->sJam = $NewJam;
$day->save();
}
}
}
}
}

View File

@@ -0,0 +1,110 @@
<?php
namespace Database\Seeders;
use App\Models\OLDLMS\Healthcare;
use App\Models\OLDLMS\JadwalDokter;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class PricesJadwalDokter extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
// $healthcare_primaya = Healthcare::where('nIDHealthCareGroup', 1)->get();
// PHSM = semarang
// PHBU = Bekasi Utara
// PHMA = makasar
// PHPK = pasar kemis
// PHPC = cikini
// PHBW = Bakti wara
// PEVH = evasari
// PHTA = tangerang
// PHSB = sukabumi
// PHKA = karawang
// PHBB = bekasi barat
// PHBT = bekasi timur
$mapHealthcare = [
'SG' => 'PHSM',
'P' => 'PHBU',
'F' => 'PHMA',
'PK' => 'PHPK',
'CK' => 'PHPC',
'BW' => 'PHBW',
'E' => 'PEVH',
'C' => 'PHTA',
'SK' => 'PHSB',
'Q' => 'PHKA',
'D' => 'PHBB',
'M' => 'PHBT',
];
$file = fopen(public_path("files/Tarif Konsultasi Primaya 2023.csv"), "r");
$data = [];
while ($row = fgetcsv($file)) {
for ($i = 0; $i < count($row); $i++) {
$data[$i][] = $row[$i];
}
}
fclose($file);
// foreach ($healthcare_primaya as $healthcare) {
$jadwalDokter = JadwalDokter::get();
foreach ($jadwalDokter as $jadwal) {
$id_healthcare_jadwal = $jadwal->nIDHealthCare;
$healthcare = Healthcare::where('nID', $id_healthcare_jadwal)->first() ?? null;
if ($healthcare == null) {
continue;
}
$mapValue = $mapHealthcare[$healthcare->sKodeRS] ?? null;
if ($mapValue == null) {
continue;
}
foreach ($data as $value) {
if ($value[0] == "") {
continue;
}
$codeValue = $value[0];
$codeValue = substr($codeValue, 1, 4);
if ($codeValue == $mapValue) {
if ($jadwal->nIDSpesialis == 1) {
//umum
$jadwal->nBiaya = (int)str_replace(",", "", $value[2]) + (int)str_replace(",", "", $value[1]);
$jadwal->nBiayaTC = (int)str_replace(",", "", $value[5]);
$jadwal->nBiayaATC = (int)str_replace(",", "", $value[5]);
$jadwal->save();
} else if ($jadwal->nIDSpesialis !== 1 && $jadwal->sIsSubSpesialis == 1) {
//sub spesialis
$jadwal->nBiaya = (int)str_replace(",", "", $value[4]) + (int)str_replace(",", "", $value[1]);
$jadwal->nBiayaTC = (int)str_replace(",", "", $value[7]);
$jadwal->nBiayaATC = (int)str_replace(",", "", $value[7]);
$jadwal->save();
} else if ($jadwal->nIDSpesialis !== 1) {
//spesialis
$jadwal->nBiaya = (int)str_replace(",", "", $value[3]) + (int)str_replace(",", "", $value[1]);
$jadwal->nBiayaTC = (int)str_replace(",", "", $value[6]);
$jadwal->nBiayaATC = (int)str_replace(",", "", $value[6]);
$jadwal->save();
}
} else {
continue;
}
}
}
// }
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role;
class RoleSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$roles = [
'administrator',
'corporate-manager',
'hospital-admin'
];
foreach ($roles as $name) {
Role::create([
'name' => $name
]);
}
}
}

View File

@@ -47,6 +47,12 @@ class ServiceSeeder extends Seeder
'code' => 'OPT', 'code' => 'OPT',
'description' => 'Optical', 'description' => 'Optical',
], ],
[
'id' => 6,
'name' => 'Medical Check Up',
'code' => 'MCU',
'description' => 'Medical Check Up',
],
]; ];
@@ -56,12 +62,14 @@ class ServiceSeeder extends Seeder
$service = Service::updateOrCreate(['id' => $service['id']], $service); $service = Service::updateOrCreate(['id' => $service['id']], $service);
foreach ($corporates as $corporate) { foreach ($corporates as $corporate) {
$corporateService = $corporate->corporateServices()->create([ $corporateService = $corporate->corporateServices()->firstOrCreate([
'service_code' => $service->code
],[
'service_code' => $service->code, 'service_code' => $service->code,
'status' => 'active' 'status' => 'inactive'
]); ]);
$corporateService->configs()->insert([ $corporate_service_configs_data = [
[ [
'corporate_service_id' => $corporateService->id, 'corporate_service_id' => $corporateService->id,
'name' => 'gp_external_doctor_online', 'name' => 'gp_external_doctor_online',
@@ -122,7 +130,14 @@ class ServiceSeeder extends Seeder
'name' => 'specialist_practitioner_fee', 'name' => 'specialist_practitioner_fee',
'value' => false, 'value' => false,
], ],
]); ];
foreach ($corporate_service_configs_data as $config) {
$corporateService->configs()->firstOrCreate([
'corporate_service_id' => $config['corporate_service_id'],
'name' => $config['name']
], $config);
}
} }
} }
} }

View File

@@ -1,4 +1,12 @@
<IfModule mod_rewrite.c> <IfModule mod_rewrite.c>
RewriteEngine On RewriteEngine On
RewriteBase / RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) /index.html [QSA,L]
</IfModule> </IfModule>
<IfModule pagespeed_module>
ModPagespeed off
</IfModule>

View File

@@ -32,7 +32,7 @@ const MENU_OPTIONS = [
export default function AccountPopover() { export default function AccountPopover() {
const [open, setOpen] = useState<HTMLElement | null>(null); const [open, setOpen] = useState<HTMLElement | null>(null);
const navigate = useNavigate(); const navigate = useNavigate();
const { logout } = useAuth(); const { logout, user } = useAuth();
const handleOpen = (event: React.MouseEvent<HTMLElement>) => { const handleOpen = (event: React.MouseEvent<HTMLElement>) => {
setOpen(event.currentTarget); setOpen(event.currentTarget);
@@ -67,10 +67,10 @@ export default function AccountPopover() {
}), }),
}} }}
> >
<Avatar {user && user.user.avatar_url && (<Avatar
src="https://minimal-assets-api.vercel.app/assets/images/avatars/avatar_5.jpg" src={user ? user.user.avatar_url : ''}
alt="Rayan Moran" alt={user ? user.user.full_name : ''}
/> />)}
</IconButtonAnimate> </IconButtonAnimate>
<MenuPopover <MenuPopover
@@ -89,16 +89,16 @@ export default function AccountPopover() {
> >
<Box sx={{ my: 1.5, px: 2.5 }}> <Box sx={{ my: 1.5, px: 2.5 }}>
<Typography variant="subtitle2" noWrap> <Typography variant="subtitle2" noWrap>
Rayan Moran { user ? user.user.full_name ?? 'Hi, ' : 'Hi, '}
</Typography> </Typography>
<Typography variant="body2" sx={{ color: 'text.secondary' }} noWrap> <Typography variant="body2" sx={{ color: 'text.secondary' }} noWrap>
rayan.moran@gmail.com { user ? user.user.email : 'Please Wait'}
</Typography> </Typography>
</Box> </Box>
<Divider sx={{ borderStyle: 'dashed' }} /> <Divider sx={{ borderStyle: 'dashed' }} />
<Stack sx={{ p: 1 }}> {/* <Stack sx={{ p: 1 }}>
{MENU_OPTIONS.map((option) => ( {MENU_OPTIONS.map((option) => (
<MenuItem key={option.label} onClick={handleClose}> <MenuItem key={option.label} onClick={handleClose}>
{option.label} {option.label}
@@ -106,7 +106,7 @@ export default function AccountPopover() {
))} ))}
</Stack> </Stack>
<Divider sx={{ borderStyle: 'dashed' }} /> <Divider sx={{ borderStyle: 'dashed' }} /> */}
<MenuItem sx={{ m: 1 }} onClick={handleLogout}> <MenuItem sx={{ m: 1 }} onClick={handleLogout}>
Logout Logout

View File

@@ -1,6 +1,7 @@
// @mui // @mui
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
import { Box, Link, Typography, Avatar } from '@mui/material'; import { Box, Link, Typography, Avatar } from '@mui/material';
import useAuth from '../../../hooks/useAuth';
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
@@ -22,6 +23,10 @@ type Props = {
}; };
export default function NavbarAccount({ isCollapse }: Props) { export default function NavbarAccount({ isCollapse }: Props) {
const { user } = useAuth();
console.log('current user is ', user)
return ( return (
<Link underline="none" color="inherit"> <Link underline="none" color="inherit">
<RootStyle <RootStyle
@@ -31,10 +36,10 @@ export default function NavbarAccount({ isCollapse }: Props) {
}), }),
}} }}
> >
<Avatar {user && user.user.avatar_url && (<Avatar
src="https://minimal-assets-api.vercel.app/assets/images/avatars/avatar_5.jpg" src={user ? user.user.avatar_url : ''}
alt="Rayan Moran" alt={user ? user.user.full_name : ''}
/> />)}
<Box <Box
sx={{ sx={{
@@ -50,10 +55,10 @@ export default function NavbarAccount({ isCollapse }: Props) {
}} }}
> >
<Typography variant="subtitle2" noWrap> <Typography variant="subtitle2" noWrap>
Rayan Moran { user ? user.user.full_name ?? 'Hi, ' : 'Hi, '}
</Typography> </Typography>
<Typography variant="body2" noWrap sx={{ color: 'text.secondary' }}> <Typography variant="body2" noWrap sx={{ color: 'text.secondary', fontSize: '11px' }}>
user { user ? user.user.email : 'Please Wait'}
</Typography> </Typography>
</Box> </Box>
</RootStyle> </RootStyle>

View File

@@ -134,7 +134,7 @@ export default function DialogClaimSubmitMember({
params: { ...appliedParams, claimMember: true }, params: { ...appliedParams, claimMember: true },
}); });
setData(response.data); setData(response.data.data);
} }
})(); })();
}, [corporateValue, openDialog, appliedParams]); }, [corporateValue, openDialog, appliedParams]);

View File

@@ -409,11 +409,11 @@ export default function TableList(props: any) {
</Button> </Button>
)} )}
</TableCell> </TableCell>
<TableCell align="right"> {/* <TableCell align="right">
<IconButton> <IconButton>
<Iconify icon="ic:baseline-more-vert" /> <Iconify icon="ic:baseline-more-vert" />
</IconButton> </IconButton>
</TableCell> </TableCell> */}
</TableRow> </TableRow>
)) ))
) : ( ) : (

View File

@@ -1,7 +0,0 @@
GENERATE_SOURCEMAP=false
PORT=8083
REACT_APP_HOST_API_URL="http://localhost:8000"
VITE_API_URL="http://localhost:8000/api/internal"

View File

@@ -1,3 +1,3 @@
GENERATE_SOURCEMAP=false GENERATE_SOURCEMAP=false
VITE_API_URL="https://aso-api.linksehat.dev/api/internal" VITE_API_URL="https://primecenter-api.linksehat.com/api/internal"

View File

@@ -0,0 +1 @@
VITE_API_URL="https://aso-api.linksehat.dev/api/internal"

View File

@@ -1,5 +1,4 @@
<IfModule mod_rewrite.c> <IfModule mod_rewrite.c>
Modpagespeed Off
RewriteEngine On RewriteEngine On
RewriteBase / RewriteBase /
@@ -7,3 +6,7 @@
RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) /index.html [QSA,L] RewriteRule (.*) /index.html [QSA,L]
</IfModule> </IfModule>
<IfModule pagespeed_module>
ModPagespeed off
</IfModule>

View File

@@ -9,7 +9,7 @@
"lint:fix": "eslint --fix --ext .ts,.tsx ./src", "lint:fix": "eslint --fix --ext .ts,.tsx ./src",
"start": "vite --port=3000", "start": "vite --port=3000",
"build": "vite build --mode production && cp .htaccess build/.htaccess && rm -f -r ../../public/dashboard && cp -r build ../../public/dashboard", "build": "vite build --mode production && cp .htaccess build/.htaccess && rm -f -r ../../public/dashboard && cp -r build ../../public/dashboard",
"build-two": "vite build --mode production", "build-staging": "vite build --mode staging && cp .htaccess build/.htaccess && rm -f -r ../../public/dashboard-staging && cp -r build ../../public/dashboard-staging",
"serve": "vite preview", "serve": "vite preview",
"clear-all": "rm -rf build node_modules", "clear-all": "rm -rf build node_modules",
"re-start": "rm -rf build node_modules && yarn install && yarn start", "re-start": "rm -rf build node_modules && yarn install && yarn start",
@@ -38,78 +38,78 @@
] ]
}, },
"dependencies": { "dependencies": {
"@date-io/date-fns": "^2.14.0", "@date-io/date-fns": "^2.16.0",
"@emotion/cache": "^11.9.3", "@emotion/cache": "^11.10.5",
"@emotion/react": "^11.9.3", "@emotion/react": "^11.10.5",
"@emotion/styled": "^11.9.3", "@emotion/styled": "^11.10.5",
"@hookform/resolvers": "^2.9.6", "@hookform/resolvers": "^2.9.10",
"@iconify/react": "^3.2.2", "@iconify/react": "^3.2.2",
"@mui/icons-material": "^5.8.4", "@mui/icons-material": "^5.11.0",
"@mui/lab": "5.0.0-alpha.80", "@mui/lab": "5.0.0-alpha.80",
"@mui/material": "^5.9.1", "@mui/material": "^5.11.5",
"@mui/system": "^5.9.1", "@mui/system": "^5.11.5",
"@mui/x-data-grid": "^5.14.0", "@mui/x-data-grid": "^5.17.19",
"@mui/x-date-pickers": "5.0.0-beta.2", "@mui/x-date-pickers": "5.0.0-beta.2",
"@vitejs/plugin-react": "^1.3.2", "@vitejs/plugin-react": "^1.3.2",
"apexcharts": "^3.35.5", "apexcharts": "^3.36.3",
"axios": "^0.27.2", "axios": "^0.27.2",
"change-case": "^4.1.2", "change-case": "^4.1.2",
"csstype": "^3.1.0", "csstype": "^3.1.1",
"date-fns": "^2.29.1", "date-fns": "^2.29.3",
"framer-motion": "^6.5.1", "framer-motion": "^6.5.1",
"highlight.js": "^11.6.0", "highlight.js": "^11.7.0",
"history": "^5.3.0", "history": "^5.3.0",
"jsx-runtime": "^1.2.0", "jsx-runtime": "^1.2.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"notistack": "^3.0.0-alpha.7", "notistack": "3.0.0-alpha.11",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"numeral": "^2.0.6", "numeral": "^2.0.6",
"react": "^17.0.2", "react": "^17.0.2",
"react-apexcharts": "^1.4.0", "react-apexcharts": "^1.4.0",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-dropzone": "^14.2.2", "react-dropzone": "^14.2.3",
"react-helmet-async": "^1.3.0", "react-helmet-async": "^1.3.0",
"react-hook-form": "^7.33.1", "react-hook-form": "^7.42.1",
"react-intersection-observer": "^8.34.0", "react-intersection-observer": "^8.34.0",
"react-lazy-load-image-component": "^1.5.5", "react-lazy-load-image-component": "^1.5.6",
"react-quill": "2.0.0-beta.4", "react-quill": "2.0.0-beta.4",
"react-router": "^6.3.0", "react-router": "^6.7.0",
"react-router-dom": "^6.3.0", "react-router-dom": "^6.7.0",
"simplebar": "^5.3.8", "simplebar": "^5.3.9",
"simplebar-react": "^2.4.1", "simplebar-react": "^2.4.3",
"stylis": "^4.1.1", "stylis": "^4.1.3",
"stylis-plugin-rtl": "^2.1.1", "stylis-plugin-rtl": "^2.1.1",
"vite": "^3.0.4", "vite": "^3.2.5",
"vite-plugin-svgr": "^2.2.1", "vite-plugin-svgr": "^2.4.0",
"yup": "^0.32.11" "yup": "^0.32.11"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.18.9", "@babel/core": "^7.20.12",
"@babel/eslint-parser": "^7.18.9", "@babel/eslint-parser": "^7.19.1",
"@babel/plugin-syntax-flow": "^7.18.6", "@babel/plugin-syntax-flow": "^7.18.6",
"@babel/plugin-transform-react-jsx": "^7.18.6", "@babel/plugin-transform-react-jsx": "^7.20.7",
"@types/lodash": "^4.14.182", "@types/lodash": "^4.14.191",
"@types/nprogress": "^0.2.0", "@types/nprogress": "^0.2.0",
"@types/react": "^17.0.47", "@types/react": "^17.0.53",
"@types/react-dom": "^17.0.17", "@types/react-dom": "^17.0.18",
"@types/react-lazy-load-image-component": "^1.5.2", "@types/react-lazy-load-image-component": "^1.5.2",
"@types/stylis": "^4.0.2", "@types/stylis": "^4.0.2",
"@typescript-eslint/eslint-plugin": "^5.30.7", "@typescript-eslint/eslint-plugin": "^5.48.2",
"@typescript-eslint/parser": "^5.30.7", "@typescript-eslint/parser": "^5.48.2",
"eslint": "^8.20.0", "eslint": "^8.32.0",
"eslint-config-airbnb": "19.0.4", "eslint-config-airbnb": "19.0.4",
"eslint-config-airbnb-typescript": "^16.2.0", "eslint-config-airbnb-typescript": "^16.2.0",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^8.6.0",
"eslint-config-react-app": "7.0.0", "eslint-config-react-app": "7.0.0",
"eslint-import-resolver-typescript": "^2.7.1", "eslint-import-resolver-typescript": "^2.7.1",
"eslint-plugin-flowtype": "^8.0.3", "eslint-plugin-flowtype": "^8.0.3",
"eslint-plugin-import": "^2.26.0", "eslint-plugin-import": "^2.27.5",
"eslint-plugin-jsx-a11y": "6.5.1", "eslint-plugin-jsx-a11y": "6.5.1",
"eslint-plugin-prettier": "^4.2.1", "eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.30.1", "eslint-plugin-react": "^7.32.1",
"eslint-plugin-react-hooks": "4.3.0", "eslint-plugin-react-hooks": "4.3.0",
"prettier": "^2.7.1", "prettier": "^2.8.3",
"typescript": "^4.7.4", "typescript": "^4.9.4",
"vite-plugin-pwa": "^0.12.3" "vite-plugin-pwa": "^0.12.8"
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -58,6 +58,13 @@ const navConfig = [
{ title: 'Hospitals', path: '/hospitals' }, { title: 'Hospitals', path: '/hospitals' },
], ],
}, },
{
title: 'LOG REQUEST',
path: '/claim-requests',
// children: [
// { title: 'Request', path: '/case-request' },
// ],
},
{ {
title: 'CASE MANAGEMENT', title: 'CASE MANAGEMENT',
path: '/claims', path: '/claims',

View File

@@ -0,0 +1,64 @@
import * as Yup from 'yup';
import { yupResolver } from '@hookform/resolvers/yup';
import { Autocomplete, Button, Card, Collapse, Container, Divider, Grid, Stack, Table, TableBody, TableCell, TableRow, TextField, Typography } from '@mui/material';
import { Controller, useForm } from 'react-hook-form';
import { useParams, useNavigate } 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 { useEffect, useMemo, useRef, useState } from 'react';
import MemberSelectDialog from '../../components/dialogs/MemberSelectDialog';
import { styled } from '@mui/system';
import axios from '../../utils/axios';
import { enqueueSnackbar } from 'notistack';
import { LoadingButton } from '@mui/lab';
import { fCurrency } from '../../utils/formatNumber';
import Iconify from '../../components/Iconify';
import Form from './Form';
export default function ClaimsCreateUpdate() {
const { themeStretch } = useSettings();
const { id } = useParams();
const isEdit = id ? true : false;
const [currentClaim, setCurrentClaim] = useState();
useEffect(() => {
if (isEdit) {
axios.get('/claims/' + id).then((res) => {
// console.log('Yeet', res.data);
setCurrentClaim(res.data);
});
}
}, [id]);
return (
<Page title={isEdit ? `Edit Claim : ${currentClaim?.id}` : "Create New Claim"}>
<Container maxWidth={themeStretch ? false : 'xl'}>
<Stack direction="row" alignItems="center">
<HeaderBreadcrumbs
heading={
!isEdit
? 'Create New Claim'
: `Edit Claim : ${currentClaim?.code}`
}
links={[
{ name: 'Dashboard', href: '/dashboard' },
{
name: 'Claim',
href: '/claims',
},
{ name: !isEdit ? 'Create' : currentClaim?.id ?? '' },
]}
/>
</Stack>
<Form isEdit={isEdit} currentClaim={currentClaim} />
</Container>
</Page>
);
}

View File

@@ -0,0 +1,596 @@
import * as Yup from 'yup';
import { useSnackbar } from 'notistack';
import { useNavigate } from 'react-router-dom';
import { yupResolver } from '@hookform/resolvers/yup';
import { Controller, useForm } from 'react-hook-form';
import React, { useEffect, useMemo, useState } from 'react';
import axios from '../../utils/axios';
import { FormProvider, RHFTextField } from '../../components/hook-form';
import {
Autocomplete,
Button,
Grid,
Stack,
Table,
TableBody,
TableCell,
TableRow,
TextField,
Typography,
useTheme,
List,
ListItem,
IconButton,
ListItemAvatar,
Avatar,
ListItemText,
} from '@mui/material';
import Iconify from '../../components/Iconify';
import { LoadingButton } from '@mui/lab';
import { fCurrency } from '../../utils/formatNumber';
import MemberSelectDialog from '../../components/dialogs/MemberSelectDialog';
import { Add, DeleteOutline } from '@mui/icons-material';
type Props = {
isEdit: boolean;
currentClaim?: any;
};
export default function ClaimForm({ isEdit, currentClaim }: Props) {
const navigate = useNavigate();
const { enqueueSnackbar } = useSnackbar();
const NewCorporateSchema = 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'),
// file: Yup.boolean().required('Corporate Status is required'),
});
const defaultValues = useMemo(
() => ({
member: currentClaim?.member || {},
member_id: currentClaim?.member_id || null,
diagnosis_id: currentClaim?.diagnosis_id || null,
total_claim: currentClaim?.total_claim || 0,
}),
// eslint-disable-next-line react-hooks/exhaustive-deps
[currentClaim]
);
const methods = useForm<any>({
resolver: yupResolver(NewCorporateSchema),
defaultValues,
});
const {
reset,
watch,
control,
setValue,
getValues,
setError,
handleSubmit,
formState: { isSubmitting },
} = methods;
const values = watch();
const [isCheckingLimit, setIsCheckingLimit] = useState(false);
const [isEligible, setIsEligible] = useState(false);
const [memberBenefits, setMemberBenefits] = useState([]);
const [diagnosisOption, setDiagnosisOption] = useState([]);
const [isMemberDialogOpen, setIsMemberDialogOpen] = useState(false);
const [member, setMember] = useState({})
useEffect(() => {
console.log('defaultValues', defaultValues);
if (isEdit && currentClaim) {
reset(defaultValues);
setMember(defaultValues.member)
}
if (!isEdit) {
reset(defaultValues);
setMember(defaultValues.member)
}
}, [isEdit, currentClaim]);
const fileSelected = (event, type) => {
const files = event.target.files;
const currentFiles = getValues(`uploaded_files.${type}`) ?? [];
setValue(`uploaded_files.${type}`, [...currentFiles, ...files]);
console.log('currentFiles', getValues('uploaded_files'));
};
const memberSelected = (member) => {
setMember(member)
};
const checkLimit = async () => {
console.log('CHECKING LIMIT');
};
const onSubmit = async (data: any) => {
try {
if (!isEdit) {
const response = await axios.post('/claims', data);
} else {
const response = await axios.put('/claims/' + currentClaim?.id ?? '', data);
}
reset();
enqueueSnackbar(
!isEdit ? 'Organizations Created Successfully!' : 'Organizations Udpated Successfully!',
{ variant: 'success' }
);
navigate('/claims');
} catch (error: any) {
if (error && error.response.status === 422) {
for (const [key, value] of Object.entries(error.response.data.errors)) {
setError(key, { message: value[0] });
enqueueSnackbar(value[0] ?? 'Failed Processing Request', { variant: 'error' });
}
} else {
enqueueSnackbar(error.message ?? 'Failed Processing Request', { variant: 'error' });
}
}
const ascent = document?.querySelector('ascent');
if (ascent != null) {
ascent.innerHTML = '';
}
};
function generate(files, element: React.ReactElement) {
return files.map((value) =>
React.cloneElement(element, {
key: value,
})
);
}
const headStyle = {};
return (
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
<Stack spacing={3}>
<Typography variant="h6">Member</Typography>
<Stack spacing={2} direction="row">
<Grid item xs={12}>
<RHFTextField
name="member_id"
label="Member"
variant="outlined"
fullWidth
value={member?.name || ''}
InputProps={{
readOnly: true,
}}
onClick={() => {
if (!isEdit) setIsMemberDialogOpen(true);
if (isEdit) enqueueSnackbar('Cannot Change Member', { variant: 'error' });
}}
/>
</Grid>
{/* <Grid item xs={2}>
<Button variant="outlined" fullWidth sx={{ p: 1.8 }} onClick={() => {
setIsMemberDialogOpen(true)
}}>
{member ? 'Change' : 'Search'}
</Button>
</Grid> */}
</Stack>
{member?.id && (
<Stack>
<Grid container spacing={2}>
<Grid item xs={12} md={6}>
<Table border="light-700">
<TableBody>
<TableRow>
<TableCell style={headStyle} align="left">
Name
</TableCell>
<TableCell align="left">{member?.full_name}</TableCell>
</TableRow>
<TableRow>
<TableCell style={headStyle} align="left">
DOB
</TableCell>
<TableCell align="left">
{member?.birth_date} ({member?.age + ' years'})
</TableCell>
</TableRow>
<TableRow>
<TableCell style={headStyle} align="left">
Marital Status
</TableCell>
<TableCell align="left">{member?.marital_status}</TableCell>
</TableRow>
<TableRow>
<TableCell style={headStyle} align="left">
Record Type
</TableCell>
<TableCell align="left">{member?.record_type}</TableCell>
</TableRow>
<TableRow>
<TableCell style={headStyle} align="left">
Principal ID
</TableCell>
<TableCell align="left">
{member?.principal_id} (
{member?.relation_with_principal})
</TableCell>
</TableRow>
</TableBody>
</Table>
</Grid>
<Grid item xs={12} md={6}>
<Table border="light-700">
<TableBody>
<TableRow>
<TableCell style={headStyle} align="left">
Plan
</TableCell>
<TableCell align="left">{member?.current_plan?.code}</TableCell>
</TableRow>
<TableRow>
<TableCell style={headStyle} align="left">
Active
</TableCell>
<TableCell align="left">
{member?.current_plan?.start} -{' '}
{member?.current_plan?.end} (Active)
</TableCell>
</TableRow>
<TableRow>
<TableCell style={headStyle} align="left">
Corporate Limit
</TableCell>
<TableCell align="left">
{fCurrency(0)} / {fCurrency(member?.current_plan?.limit_rules)}
</TableCell>
</TableRow>
<TableRow>
<TableCell style={headStyle} align="left">
Plan Usage
</TableCell>
<TableCell align="left">
{fCurrency(0)} / {fCurrency(member?.current_plan?.limit_rules)}
</TableCell>
</TableRow>
</TableBody>
</Table>
</Grid>
</Grid>
</Stack>
)}
<Controller
name="benefit"
control={control}
render={({ field: { onChange, value } }) => (
<Autocomplete
options={memberBenefits}
getOptionLabel={(option) =>
option ? `#${option.id} (${option.code}) ${option.description}` : ''
}
value={value || ''}
onChange={(event: any, newValue: any) => {
setValue('benefit_id', newValue?.id);
onChange(newValue);
}}
renderInput={(params) => (
<TextField
name="benefit"
{...params}
label="Benefit"
variant="outlined"
fullWidth
// onKeyPress={(event) => {
// if (event.key === 'Enter')
// searchDiagnosis(event.target.value)
// }}
/>
)}
/>
)}
/>
<Controller
name="diagnosis"
control={control}
render={({ field: { onChange, value } }) => (
<Autocomplete
options={diagnosisOption}
getOptionLabel={(option) => (option ? `(${option.code}) ${option.name}` : '')}
value={value || ''}
onChange={(event: any, newValue: any) => {
setValue('diagnosis_id', newValue?.id);
// setValue('diagnosis', newValue)
onChange(newValue);
}}
renderInput={(params) => (
<TextField
name="diagnosis"
{...params}
label="Diagnosis"
variant="outlined"
fullWidth
onKeyPress={(event) => {
if (event.key === 'Enter') searchDiagnosis(event.target.value);
}}
/>
)}
/>
)}
/>
{isCheckingLimit && (
<Stack
sx={{
backgroundColor: 'gray',
paddingY: 1,
paddingX: 1.5,
mb: 2,
borderRadius: '3-xl',
}}
>
{/* Checking */}
<Typography sx={{ typography: 'caption', display: 'flex', alignItems: 'center' }}>
<Iconify
icon="bxs:info-circle"
width={12}
height={13}
sx={{ color: '#424242', marginRight: '6px' }}
/>
<Typography variant="caption" component="span">
Please Wait, Checking Eligibilty
</Typography>
</Typography>
</Stack>
)}
{false && isCheckingLimit == false && isEligible == null && (
<Stack
sx={{
backgroundColor: 'gray',
paddingY: 1,
paddingX: 1.5,
mb: 2,
borderRadius: '3-xl',
}}
>
{/* No Data Selected */}
<Typography sx={{ typography: 'caption', display: 'flex', alignItems: 'center' }}>
<Iconify
icon="bxs:info-circle"
width={12}
height={13}
sx={{ color: '#424242', marginRight: '6px' }}
/>
<Typography variant="caption" component="span">
Please Select Diagnosis !
</Typography>
</Typography>
</Stack>
)}
{!isCheckingLimit && isEligible !== null && isEligible && (
<Stack
sx={{
backgroundColor: '#B2E8E8',
paddingY: 1,
paddingX: 1.5,
mb: 2,
borderRadius: '3-xl',
}}
>
{/* Eligible */}
<Typography sx={{ typography: 'caption', display: 'flex', alignItems: 'center' }}>
<Iconify
icon="bxs:lock-alt"
width={12}
height={13}
sx={{ color: '#424242', marginRight: '6px' }}
/>
<Typography variant="caption" component="span">
Diagnosis is Eligible
</Typography>
</Typography>
<Typography sx={{ typography: 'caption', color: '#637381' }}>
125.000.000 / 125.000.000
</Typography>
</Stack>
)}
{!isCheckingLimit && isEligible !== null && !isEligible && (
<Stack
sx={{
backgroundColor: '#B2E8E8',
paddingY: 1,
paddingX: 1.5,
mb: 2,
borderRadius: '3-xl',
}}
>
{/* Not Eligible */}
{/* <Typography sx={{ typography: 'caption', display: 'flex', alignItems: 'center' }}>
<Iconify
icon="bxs:lock-alt"
width={12}
height={13}
sx={{ color: '#424242', marginRight: '6px' }}
/>
<Typography variant="caption" component="span">
Not Eligible
</Typography>
</Typography>
<Typography sx={{ typography: 'caption', color: '#637381' }}>
125.000.000 / 125.000.000
</Typography> */}
</Stack>
)}
<RHFTextField type="number" name="total_claim" label="Total Claim" />
{isEdit && (
<React.Fragment>
<Typography variant="h6">Documents</Typography>
<List>
{(getValues('uploaded_files.invoice') && getValues('uploaded_files.invoice').length
? getValues('uploaded_files.invoice')
: []
).map((file, index) => (
<ListItem
secondaryAction={
<IconButton edge="end" aria-label="delete">
<DeleteOutline />
</IconButton>
}
>
<ListItemAvatar>
<Avatar>
{/* <FileIcon /> */}
I
</Avatar>
</ListItemAvatar>
<ListItemText primary={file.name} secondary={file.type} />
</ListItem>
))}
</List>
<Button
variant="outlined"
startIcon={<Add />}
component="label"
sx={{ paddingY: 2, width: '100%', ':hover': { border: 'none' } }}
>
Invoice
<input
name="invoice"
hidden
accept="image/*,application/pdf"
multiple
type="file"
onChange={(event) => {
fileSelected(event, 'invoice');
}}
/>
</Button>
<List>
{(getValues('uploaded_files.prescription') && getValues('uploaded_files.prescription').length
? getValues('uploaded_files.prescription')
: []
).map((file, index) => (
<ListItem
secondaryAction={
<IconButton edge="end" aria-label="delete">
<DeleteOutline />
</IconButton>
}
>
<ListItemAvatar>
<Avatar>
{/* <FileIcon /> */}
P
</Avatar>
</ListItemAvatar>
<ListItemText primary={file.name} secondary={file.type} />
</ListItem>
))}
</List>
<Button
variant="outlined"
startIcon={<Add />}
component="label"
sx={{ paddingY: 2, width: '100%', ':hover': { border: 'none' } }}
>
Prescription
<input
name="prescription"
hidden
accept="image/*,application/pdf"
multiple
type="file"
onChange={(event) => {
fileSelected(event, 'prescription');
}}
/>
</Button>
<List>
{(getValues('uploaded_files.diagnosis') && getValues('uploaded_files.diagnosis').length
? getValues('uploaded_files.diagnosis')
: []
).map((file, index) => (
<ListItem
secondaryAction={
<IconButton edge="end" aria-label="delete">
<DeleteOutline />
</IconButton>
}
>
<ListItemAvatar>
<Avatar>
{/* <FileIcon /> */}
DR
</Avatar>
</ListItemAvatar>
<ListItemText primary={file.name} secondary={file.type} />
</ListItem>
))}
</List>
<Button
variant="outlined"
startIcon={<Add />}
component="label"
sx={{ paddingY: 2, width: '100%', ':hover': { border: 'none' } }}
>
Doctor Result
<input
name="invoice"
hidden
accept="image/*,application/pdf"
multiple
type="file"
onChange={(event) => {
fileSelected(event, 'diagnosis');
}}
/>
</Button>
</React.Fragment>
)}
{isEligible === true ? (
<LoadingButton
onClick={handleSubmit(onSubmit)}
variant="contained"
color="success"
style={{ color: '#ffffff' }}
size="large"
fullWidth={true}
loading={isCheckingLimit}
>
Create Claim
</LoadingButton>
) : (
<LoadingButton
onClick={checkLimit}
variant="outlined"
size="large"
fullWidth={true}
loading={isCheckingLimit}
>
Check Limit
</LoadingButton>
)}
</Stack>
<MemberSelectDialog
openDialog={isMemberDialogOpen}
setOpenDialog={setIsMemberDialogOpen}
onSelect={memberSelected}
></MemberSelectDialog>
</FormProvider>
);
}

View File

@@ -0,0 +1,30 @@
import { Card, Stack } from "@mui/material";
import HeaderBreadcrumbs from "../../components/HeaderBreadcrumbs";
import Page from "../../components/Page";
import List from "./List";
export default function Claims() {
const pageTitle = 'Claim Request';
return (
<Page title={ pageTitle } sx={{ mx: 2}}>
<HeaderBreadcrumbs
heading={ pageTitle }
links={[
{ name: 'Dashboard', href: '/dashboard' },
{
name: 'Claim Request',
href: '/claim-requests',
},
]}
/>
{/* <Stack> */}
<List />
{/* </Stack> */}
</Page>
);
}

View File

@@ -0,0 +1,294 @@
// @mui
import {
Box,
Button,
Card,
Collapse,
IconButton,
MenuItem,
Table,
TableBody,
TableCell,
TableRow,
TextField,
Typography,
Stack,
Menu,
ButtonGroup,
Link,
Chip,
} 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, useEffect, useRef, useState } from 'react';
import { Navigate, useNavigate, useSearchParams } from 'react-router-dom';
// components
import axios from '../../utils/axios';
import { LaravelPaginatedData, LaravelPaginatedDataDefault } from '../../@types/paginated-data';
import DataTable from '../../components/LaravelTable';
import { fCurrency } from '../../utils/formatNumber';
import EditRoundedIcon from '@mui/icons-material/EditRounded';
import { LoadingButton } from '@mui/lab';
import { enqueueSnackbar } from 'notistack';
import { Divider } from '@mui/material';
import Iconify from '@/components/Iconify';
// import LoadingButton from '@/theme/overrides/LoadingButton';
export default function List() {
const [searchParams, setSearchParams] = useSearchParams();
const [importResult, setImportResult] = useState(null);
const navigate = useNavigate();
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({ search: searchText }); // Trigger to Parent
};
useEffect(() => {
// Trigger First Search
setSearchText(searchParams.get('search') ?? '');
}, []);
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 handleClose = () => {
setAnchorEl(null);
};
return (
<div>
<Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
<SearchInput onSearch={applyFilter} />
{/* <Button
variant="outlined"
startIcon={<AddIcon />}
sx={{ p: 1.8 }}
onClick={() => {
navigate('/claims/create');
}}
>
Create
</Button> */}
</Stack>
</div>
);
}
// Dummy Default Data
const [dataTableIsLoading, setDataTableLoading] = useState(true);
const [dataTableData, setDataTableData] = useState<LaravelPaginatedData>(
LaravelPaginatedDataDefault
);
const loadDataTableData = async (appliedFilter: any | null = null) => {
setDataTableLoading(true);
const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]);
const response = await axios.get('/claim-requests', { params: filter });
// console.log(response.data);
setDataTableLoading(false);
setDataTableData(response.data);
};
const applyFilter = async (searchFilter: { search: string }) => {
await loadDataTableData(searchFilter);
setSearchParams(searchFilter);
};
const handlePageChange = (event: ChangeEvent, value: number): void => {
const filter = Object.fromEntries([...searchParams.entries(), ['page', value]]);
loadDataTableData(filter);
setSearchParams(filter);
};
const handleApprove = (claimRequest) => {
axios.post(`claim-requests/${claimRequest.id}/approve`)
.then((response) => {
enqueueSnackbar('Success Approve', {variant: 'success'})
loadDataTableData()
})
.catch(({response}) => {
enqueueSnackbar(response.data.message ?? 'Something went wrong!', {variant : "error"})
})
}
useEffect(() => {
loadDataTableData();
}, []);
const headStyle = {
fontWeight: 'bold',
};
// Called on every row to map the data to the columns
function createData(data: any): any {
return {
...data,
};
}
{
/* ------------------ TABLE ROW ------------------ */
}
function Row(props: { row: ReturnType<typeof createData> }) {
const { row } = props;
const [open, setOpen] = React.useState(false);
const [loadingApprove, setLoadingApprove] = 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.code}</TableCell>
<TableCell align="left">{row.member?.full_name}</TableCell>
<TableCell align="left">{row.submission_date}</TableCell>
<TableCell align="left">{row.service_type}</TableCell>
<TableCell align="right"><Chip label={row.status}/></TableCell>
<TableCell align="right">{ row.status == 'requested' && (<LoadingButton loading={loadingApprove} variant="outlined" onClick={() => {handleApprove(row)}}>Approve</LoadingButton> )}</TableCell>
</TableRow>
{/* COLLAPSIBLE ROW */}
<TableRow>
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={99}>
<Collapse in={open} timeout="auto" unmountOnExit>
<Box sx={{ borderBottom: 1 }}>
<Stack
divider={<Divider orientation="horizontal" flexItem />}
spacing={1}
sx={{ marginY: 2 }}
>
<Box>
<Typography fontWeight={600}>Berkas Hasil Penunjang</Typography>
{row.files_by_type?.result &&
row.files_by_type?.result.map((file, index) => (
<Stack direction="row" key={index}>
<Typography sx={{marginRight: 2}}>-</Typography> <a href={file.url} target="_blank">{file.name}</a>
</Stack>
))}
{ !row.files_by_type?.result && (
<Typography>Tidak ada berkas</Typography>
)}
</Box>
</Stack>
</Box>
</Collapse>
</TableCell>
</TableRow>
</React.Fragment>
);
}
{
/* ------------------ END TABLE ROW ------------------ */
}
function TableContent() {
return (
<Table aria-label="collapsible table">
{/* ------------------ TABLE HEADER ------------------ */}
<TableBody>
<TableRow>
<TableCell style={headStyle} align="left" />
<TableCell style={headStyle} align="left">
Code
</TableCell>
<TableCell style={headStyle} align="left">
Member Name
</TableCell>
<TableCell style={headStyle} align="left">
Submission Date
</TableCell>
<TableCell style={headStyle} align="left">
Jenis Layanan
</TableCell>
<TableCell style={headStyle} align="left">
Status
</TableCell>
<TableCell style={headStyle} align="right">
Action
</TableCell>
</TableRow>
</TableBody>
{/* ------------------ END TABLE HEADER ------------------ */}
{/* ------------------ TABLE ROW ------------------ */}
{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>
)}
{/* ------------------ END TABLE ROW ------------------ */}
</Table>
);
}
return (
<Card>
<ImportForm />
<DataTable
isLoading={dataTableIsLoading}
lastRequest={0}
data={dataTableData}
handlePageChange={handlePageChange}
TableContent={<TableContent />}
/>
</Card>
);
}

View File

@@ -221,8 +221,8 @@ export default function List() {
{ (row.status == 'approved' && ( { (row.status == 'approved' && (
<TableCell align="left">Approved</TableCell> <TableCell align="left">Approved</TableCell>
)) } )) }
{ (row.status == 'postponed' && ( { (row.status == 'postpone' && (
<TableCell align="left">Postpone</TableCell> <TableCell align="left">Postponed</TableCell>
)) } )) }
<TableCell align="right"> <TableCell align="right">

View File

@@ -62,12 +62,12 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
const onSubmit = async (data: any) => { const onSubmit = async (data: any) => {
if (!isEdit) { if (!isEdit) {
await axios await axios
.post('/corporates/' + corporate_id + '/divisions', data) .post('/corporate/' + corporate_id + '/divisions', data)
.then((res) => { .then((res) => {
enqueueSnackbar('Division created successfully', { variant: 'success' }); enqueueSnackbar('Division created successfully', { variant: 'success' });
}) })
.then((res) => { .then((res) => {
navigate('/corporates/' + corporate_id + '/divisions', { replace: true }); navigate('/corporate/' + corporate_id + '/divisions', { replace: true });
}) })
.catch(({ response }) => { .catch(({ response }) => {
if (response.status === 422) { if (response.status === 422) {
@@ -81,12 +81,12 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
}); });
} else { } else {
await axios await axios
.put('/corporates/' + corporate_id + '/divisions/' + currentCorporatePlan?.id, data) .put('/corporate/' + corporate_id + '/divisions/' + currentCorporatePlan?.id, data)
.then((res) => { .then((res) => {
enqueueSnackbar('Division updated successfully', { variant: 'success' }); enqueueSnackbar('Division updated successfully', { variant: 'success' });
}) })
.then((res) => { .then((res) => {
navigate('/corporates/' + corporate_id + '/divisions/', { replace: true }); navigate('/corporate/' + corporate_id + '/divisions/', { replace: true });
}) })
.catch(({ response }) => { .catch(({ response }) => {
enqueueSnackbar('Update Failed : ' + response.data.message, { variant: 'error' }); enqueueSnackbar('Update Failed : ' + response.data.message, { variant: 'error' });

View File

@@ -35,11 +35,11 @@ export default function Divisions() {
}, },
{ {
name: corporate?.name ?? '-', name: corporate?.name ?? '-',
href: '/corporates/' + corporate_id, href: '/corporate/' + corporate_id,
}, },
{ {
name: 'Benefit', name: 'Benefit',
href: '/corporates/' + corporate_id + '/benefits', href: '/corporate/' + corporate_id + '/benefits',
}, },
]} ]}
/> />

View File

@@ -60,6 +60,7 @@ import Form from './Form';
import { LaravelPaginatedData } from '../../../@types/paginated-data'; import { LaravelPaginatedData } from '../../../@types/paginated-data';
import BasePagination from '../../../components/BasePagination'; import BasePagination from '../../../components/BasePagination';
import { enqueueSnackbar } from 'notistack'; import { enqueueSnackbar } from 'notistack';
import { LoadingButton } from '@mui/lab';
export default function PlanList() { export default function PlanList() {
const { themeStretch } = useSettings(); const { themeStretch } = useSettings();
@@ -109,6 +110,7 @@ export default function PlanList() {
const createMenu = Boolean(anchorEl); const createMenu = Boolean(anchorEl);
const importPlan = useRef<HTMLInputElement>(null); const importPlan = useRef<HTMLInputElement>(null);
const [currentImportFileName, setCurrentImportFileName] = useState(null); const [currentImportFileName, setCurrentImportFileName] = useState(null);
const [importLoading, setImportLoading] = useState(false);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => { const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget); setAnchorEl(event.currentTarget);
@@ -144,6 +146,7 @@ export default function PlanList() {
if (importPlan.current?.files.length) { if (importPlan.current?.files.length) {
const formData = new FormData(); const formData = new FormData();
formData.append('file', importPlan.current?.files[0]); formData.append('file', importPlan.current?.files[0]);
setImportLoading(true);
axios axios
.post(`corporates/${corporate_id}/import-plan-benefit`, formData) .post(`corporates/${corporate_id}/import-plan-benefit`, formData)
.then((response) => { .then((response) => {
@@ -151,6 +154,7 @@ export default function PlanList() {
loadDataTableData(); loadDataTableData();
setImportResult(response.data); setImportResult(response.data);
// alert('Succesfully read '+ response.data.total_successed_row + ' with ' + response.data.total_failed_row + ' failed rows'); // alert('Succesfully read '+ response.data.total_successed_row + ' with ' + response.data.total_failed_row + ' failed rows');
setImportLoading(false);
}) })
.catch((response) => { .catch((response) => {
enqueueSnackbar( enqueueSnackbar(
@@ -158,11 +162,25 @@ export default function PlanList() {
response.message, response.message,
{ variant: 'error' } { variant: 'error' }
); );
setImportLoading(false);
}); });
} else { } else {
enqueueSnackbar('No File Selected', { variant: 'warning' }); enqueueSnackbar('No File Selected', { variant: 'warning' });
} }
}; };
const handleGetTemplate = (type :string) => {
axios.get('corporates/import-document-example/' + type)
.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 ( return (
<div> <div>
@@ -200,7 +218,7 @@ export default function PlanList() {
}} }}
> >
<MenuItem onClick={handleImportButton}>Import</MenuItem> <MenuItem onClick={handleImportButton}>Import</MenuItem>
<MenuItem onClick={handleClose}>Download Template</MenuItem> <MenuItem onClick={() => {handleGetTemplate('plan-benefit')}}>Download Template</MenuItem>
</Menu> </Menu>
</Stack> </Stack>
)} )}
@@ -221,15 +239,16 @@ export default function PlanList() {
</Button> </Button>
</ButtonGroup> </ButtonGroup>
<Button <LoadingButton
id="upload-button" id="upload-button"
variant="outlined" variant="outlined"
startIcon={<UploadIcon />} startIcon={<UploadIcon />}
sx={{ p: 1.8 }} sx={{ p: 1.8 }}
onClick={handleUpload} onClick={handleUpload}
loading={importLoading}
> >
Upload Upload
</Button> </LoadingButton>
</Stack> </Stack>
)} )}
{importResult && ( {importResult && (
@@ -326,7 +345,7 @@ export default function PlanList() {
</Button> </Button>
)} )}
</TableCell> </TableCell>
<TableCell align="center"> {/* <TableCell align="center">
<Button <Button
variant="outlined" variant="outlined"
color="success" color="success"
@@ -340,7 +359,7 @@ export default function PlanList() {
> >
{openEdit ? 'Save' : 'Edit'} {openEdit ? 'Save' : 'Edit'}
</Button> </Button>
</TableCell> </TableCell> */}
</TableRow> </TableRow>
{/* COLLAPSIBLE ROW */} {/* COLLAPSIBLE ROW */}
<TableRow> <TableRow>
@@ -767,9 +786,9 @@ export default function PlanList() {
<TableCell style={headStyle} align="center"> <TableCell style={headStyle} align="center">
Status Status
</TableCell> </TableCell>
<TableCell style={headStyle} align="center"> {/* <TableCell style={headStyle} align="center">
Action Action
</TableCell> </TableCell> */}
</TableRow> </TableRow>
</TableBody> </TableBody>
{dataTableIsLoading ? ( {dataTableIsLoading ? (

View File

@@ -64,12 +64,12 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
const onSubmit = async (data: any) => { const onSubmit = async (data: any) => {
if (!isEdit) { if (!isEdit) {
await axios await axios
.post('/corporates/' + corporate_id + '/divisions', data) .post('/corporate/' + corporate_id + '/divisions', data)
.then((res) => { .then((res) => {
enqueueSnackbar('Division created successfully', { variant: 'success' }); enqueueSnackbar('Division created successfully', { variant: 'success' });
}) })
.then((res) => { .then((res) => {
navigate('/corporates/' + corporate_id + '/divisions', { replace: true }); navigate('/corporate/' + corporate_id + '/divisions', { replace: true });
}) })
.catch(({ response }) => { .catch(({ response }) => {
if (response.status === 422) { if (response.status === 422) {
@@ -84,12 +84,12 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
}); });
} else { } else {
await axios await axios
.put('/corporates/' + corporate_id + '/divisions/' + currentCorporatePlan?.id , data) .put('/corporate/' + corporate_id + '/divisions/' + currentCorporatePlan?.id , data)
.then((res) => { .then((res) => {
enqueueSnackbar('Division updated successfully', { variant: 'success' }); enqueueSnackbar('Division updated successfully', { variant: 'success' });
}) })
.then((res) => { .then((res) => {
navigate('/corporates/' + corporate_id + '/divisions/' , { replace: true }); navigate('/corporate/' + corporate_id + '/divisions/' , { replace: true });
}) })
.catch(({ response }) => { .catch(({ response }) => {
enqueueSnackbar('Update Failed : '+ response.data.message, { variant: 'error' }); enqueueSnackbar('Update Failed : '+ response.data.message, { variant: 'error' });

View File

@@ -33,11 +33,11 @@ export default function Divisions() {
}, },
{ {
name: corporate?.name ?? '-', name: corporate?.name ?? '-',
href: '/corporates/' + corporate_id, href: '/corporate/' + corporate_id,
}, },
{ {
name: 'Claim History', name: 'Claim History',
href: '/corporates/' + corporate_id + '/claim-histories', href: '/corporate/' + corporate_id + '/claim-histories',
}, },
]} ]}
/> />

Some files were not shown because too many files have changed in this diff Show More