[WIP] ASO Payment

This commit is contained in:
R
2023-01-05 18:28:45 +07:00
parent 0fdad5a6c2
commit 804ac883fa
41 changed files with 882 additions and 177 deletions

View File

@@ -39,7 +39,7 @@ class CorporateMemberController extends Controller
'currentPolicy',
// 'claims',
'claims' => function ($claim) {
return $claim->whereBetween('requested_at', [now()->startOfYear(), now()->endOfYear()]);
// return $claim->whereBetween('requested_at', [now()->startOfYear(), now()->endOfYear()]);
// return $claim->used(now()->startOfYear(), now()->endOfYear());
}
])

View File

@@ -117,9 +117,9 @@ class CorporateServiceController extends Controller
->where('service_code', $service_code)
->with([
'configs', 'service',
'specialities',
'specialities.speciality',
'specialities.exclusions.rules'
'corporateServiceSpecialities',
'corporateServiceSpecialities.speciality',
'corporateServiceSpecialities.exclusions.rules'
])
->first();
// $service = CorporateServiceConfigResource::make($corporateService);
@@ -425,9 +425,9 @@ class CorporateServiceController extends Controller
->where('service_code', $service_code)
->with([
'configs', 'service',
'specialities',
'specialities.speciality',
'specialities.exclusions.rules'
'corporateServiceSpecialities',
'corporateServiceSpecialities.speciality',
'corporateServiceSpecialities.exclusions.rules'
])
->first();

View File

@@ -23,8 +23,8 @@ class CorporateServiceConfigResource extends JsonResource
'name' => $this->service->name,
'description' => $this->service->description,
'configurations' => $this->configs->pluck('value', 'name'),
'selected_specialities' => $this->specialities->where('active', true)->pluck('speciality.name', 'speciality_id'),
'exclusions' => $this->specialities->map(function ($speciality) {
'selected_specialities' => $this->corporateServiceSpecialities->where('active', true)->pluck('speciality.name', 'speciality_id'),
'exclusions' => $this->corporateServiceSpecialities->map(function ($speciality) {
return [
'speciality_id' => $speciality->speciality_id,
// 'rules' => $speciality->exclusions->first()->rules->map(
@@ -40,7 +40,7 @@ class CorporateServiceConfigResource extends JsonResource
}),
];
$list_msc = $this->specialities->map(function ($speciality) {
$list_msc = $this->corporateServiceSpecialities->map(function ($speciality) {
return explode(',', $speciality->exclusions->first()->rules->where('name', 'msc')->first()->values ?? '');
})->map(function ($item) {
return [
@@ -50,7 +50,7 @@ class CorporateServiceConfigResource extends JsonResource
];
});
$list_gender = $this->specialities->map(function ($speciality) {
$list_gender = $this->corporateServiceSpecialities->map(function ($speciality) {
// dd($speciality->exclusions->first()->rules);
return explode(',', $speciality->exclusions->first()->rules->where('name', 'gender')->first()->values ?? '');
})->map(function ($item) {
@@ -61,15 +61,15 @@ class CorporateServiceConfigResource extends JsonResource
];
});
$min_age = $this->specialities->map(function ($speciality) {
$min_age = $this->corporateServiceSpecialities->map(function ($speciality) {
return $speciality->exclusions->first()->rules->where('name', 'min_age')->first()->values ?? '';
});
$max_age = $this->specialities->map(function ($speciality) {
$max_age = $this->corporateServiceSpecialities->map(function ($speciality) {
return $speciality->exclusions->first()->rules->where('name', 'max_age')->first()->values ?? '';
});
$plan = $this->specialities->map(function ($speciality) {
$plan = $this->corporateServiceSpecialities->map(function ($speciality) {
return $speciality->exclusions->first()->rules->where('name', 'plan')->first()->values ?? null;
});

View File

@@ -0,0 +1,39 @@
<?php
namespace App\Events;
use App\Models\Claim;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class ClaimApproved
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $claim;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(Claim $claim)
{
$this->claim = $claim;
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class ClaimDeclined
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}

36
app/Events/ClaimPaid.php Normal file
View File

@@ -0,0 +1,36 @@
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class ClaimPaid
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class ClaimPostpone
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class ClaimReceived
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class ClaimRequested
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}

View File

@@ -1,104 +0,0 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Member;
use Illuminate\Http\Request;
class MemberController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$members = [];
$faker = \Faker\Factory::create();
for ($i = 0; $i < 10; $i++) {
$members[] = [
'id' => (10-$i),
'code' => 'UT0000'.sprintf("%02d", 10-$i),
'nik' => 'UNTR0000'.sprintf("%02d", $i),
'name' => $faker->name,
'plan_code' => collect(['PLAN001', 'PLAN002', 'PLAN003', 'PLAN004', 'PLAN005'])->random(),
'number_of_families' => random_int(2,4),
'number_of_claim' => random_int(0,2),
'active' => true,
'history' => []
];
}
return $members;
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}

View File

@@ -37,10 +37,12 @@ class ClaimController extends Controller
'currentPlan',
])
->firstOrFail();
$benefit = $member->currentPlan->benefits()->where('benefit_code', $benefitCode)->first();
$benefit = $member->currentPlan->benefits()->where('code', $benefitCode)->first();
// $diagnosis = Icd::first();
$claim = ClaimService::storeClaim($member, null, $request->total_claim, $benefit, 'approved');
$claim = ClaimService::storeClaim($member, null, $request->total_claim, $benefit, 'requested');
$claim->status = 'approved';
$claim->save();
return Helper::responseJson($claim);
}

View File

@@ -15,7 +15,7 @@ class MembershipController extends Controller
{
$request->validate([
'member_id' => 'required',
'birth_date' => 'required',
// 'birth_date' => 'required',
]);
$member = Member::where('member_id', $request->member_id)->first();
@@ -28,7 +28,6 @@ class MembershipController extends Controller
return Helper::responseJson(statusCode: 406, message: 'The Member '.$request->member_id.' is Inactive.', status: 'error');
}
return Helper::responseJson(data: $member, message: 'Member Found');
}
@@ -36,7 +35,8 @@ class MembershipController extends Controller
{
$request->validate([
'member_id' => 'required',
'type' => 'required|in:consultation-gp,consultation-specialist,medicine'
'type' => 'required|in:consultation-gp,consultation-specialist,medicine',
// 'speciality_code' => 'sometimes'
]);
if ($request->type == 'consultation-gp') {
@@ -49,9 +49,170 @@ class MembershipController extends Controller
$benefitCode = 'OPMEDI1';
}
$member = Member::where('member_id', $request->member_id)->with(['currentCorporate', 'currentPolicy', 'currentPlan'])->first();
$member = Member::where('member_id', $request->member_id)->with(['currentCorporate', 'currentPolicy', 'currentPlan', 'postponedClaims'])->first();
$limits = ClaimService::showMemberBenefitLimit($member, $benefitCode);
$limits['postponed_claims'] = $member->postponedClaims;
$limits['postponed_claims_payment_url'] = "http://google.com";
$limits['postponed_claims_unpaid_total'] = $member->postponedClaims->sum('total_claim');
if ($request->has('speciality_code') && !empty($request->speciality_code)) {
$corporateService = $member->currentCorporate
->corporateServices()
->active()
->where('service_code', 'OP')
->with([
'specialities' => function ($speciality) use ($request) {
$speciality->where('code', $request->speciality_code)
->wherePivot('active', 1);
}])
->first();
// $rules = $corporateServiceConfigs->
// dd($corporateServiceConfigs->toArray());
if (empty($corporateService)) {
$limit['coverage'] = [
'benefit' => false,
'admin_fee' => false,
'delivery_fee' => false
];
return Helper::responseJson(data: $limits);
}
if (empty($corporateService->specialities)) {
$limit['coverage'] = [
'benefit' => false,
'admin_fee' => false,
'delivery_fee' => false
];
return Helper::responseJson(data: $limits);
}
$currentSpeciality = $corporateService->specialities->first();
// Load the Relation Data after speciality check is supported
$corporateService->load([
'configs',
// 'configs.exclusions.rules',
'corporateServiceSpecialities' => function ($corporateServiceSpeciality) use ($currentSpeciality) {
$corporateServiceSpeciality->where('speciality_id', $currentSpeciality->id);
},
'corporateServiceSpecialities.exclusions' => function ($exclusion) {
$exclusion->where('service_code', 'OP');
},
'corporateServiceSpecialities.exclusions.rules'
]);
$configs = $corporateService->configs->mapWithKeys(function ($config) {
return [$config->name => $config];
});
$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');
// dd($serviceSpecialityRules->toArray());
$coverage = [
'benefit' => false,
'admin_fee' => false,
'delivery_fee' => false
];
// dd($configs->toArray());
// dd($gpSpecialityName, $currentSpeciality->name);
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;
}
$limits['coverage'] = $coverage;
} else {
$limits['coverage'] = [
'benefit' => true,
'admin_fee' => true,
'delivery_fee' => true
];
}
return Helper::responseJson(data: $limits);
}

View File

@@ -4,6 +4,7 @@ namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class LinksehatOldAuthMiddleware
{
@@ -17,6 +18,8 @@ class LinksehatOldAuthMiddleware
public function handle(Request $request, Closure $next)
{
if ($request->header('authorization') == 'Bearer LpMbGm0NQvFC3lUBiy1Ch3NzS0CIPSmanR12FcdP') {
Auth::loginUsingId(1);
return $next($request);
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Http\Resources\OLDLMS;
use Illuminate\Http\Resources\Json\JsonResource;
class MemberLimitResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Http\Resources\OLDLMS;
use Illuminate\Http\Resources\Json\JsonResource;
class MemberResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

37
app/Jobs/TestJob.php Normal file
View File

@@ -0,0 +1,37 @@
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;
class TestJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct()
{
// dd('asdasd');
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
// dd('adsasd');
Mail::raw('Hello World!', function($msg) {$msg->to('myemail@gmail.com')->subject('Test Email'); });
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace App\Listeners;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
class LogClaimJournal
{
public $afterCommit = true;
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
$policy = $event->claim->member->currentPolicy;
$policy->limitJournals()->create([
'previous_balance' => $policy->limit_balance,
'total_credit' => $event->claim->total_claim * -1,
'type' => 'credit',
'balance' => bcsub($policy->limit_balance, $event->claim->total_claim),
'description' => 'Log for Claim #'. $event->claim->code,
]);
}
}

View File

@@ -2,33 +2,30 @@
namespace App\Models;
use App\Events\ClaimApproved;
use App\Events\ClaimDeclined;
use App\Events\ClaimPaid;
use App\Events\ClaimPostpone;
use App\Events\ClaimReceived;
use App\Events\ClaimRequested;
use App\Traits\Blameable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
class Claim extends Model
{
use HasFactory;
use HasFactory, Blameable;
protected $fillable = [
'code',
'member_id',
'diagnosis_id',
'total_claim',
'currency',
'plan_id',
'benefit_id',
'status',
'requested_at',
'requested_by',
'received_at',
'received_by',
'approved_at',
'approved_by',
'declined',
'declined_by',
'paid_at',
'paid_by',
];
protected $hidden = [
@@ -45,6 +42,7 @@ class Claim extends Model
'requested' => 'Requested',
'received' => 'Received',
'approved' => 'Approved',
'postpone' => 'Postpone',
'paid' => 'Paid',
'declined' => 'Declined'
];
@@ -60,6 +58,50 @@ class Claim extends Model
abort(500, $e->getMessage());
}
});
static::created(function ($model) {
try {
if (!empty($model->status)) {
$model->statusHistories()->create([
'status' => $model->status
]);
}
} catch (\Exception $e) {
abort(500, $e->getMessage());
}
});
static::updated(function ($model) {
if ($model->hasChanges(['status'])) {
$model->statusHistories()->create([
'status' => $model->status
]);
if ($model->status == 'requested') {
ClaimRequested::dispatch($model);
}
if ($model->status == 'received') {
ClaimReceived::dispatch($model);
}
if ($model->status == 'approved') {
ClaimApproved::dispatch($model);
}
if ($model->status == 'postpone') {
ClaimPostpone::dispatch($model);
}
if ($model->status == 'paid') {
ClaimPaid::dispatch($model);
}
if ($model->status == 'declined') {
ClaimDeclined::dispatch($model);
}
}
});
}
public function files()
@@ -72,9 +114,19 @@ class Claim extends Model
return $this->belongsTo(Member::class, 'member_id');
}
public function diagnoses()
{
return $this->hasMany(ClaimDiagnosis::class, 'claim_id');
}
// TODO Remove this !, Sementara
public function diagnosis()
{
return $this->belongsTo(Icd::class, 'diagnosis_id');
return $this->hasOne(ClaimDiagnosis::class, 'claim_id')->ofMany([
'id' => 'min',
], function ($query) {
$query->where('type', 'primary');
});
}
public function plan()
@@ -87,11 +139,16 @@ class Claim extends Model
return $this->belongsTo(Benefit::class, 'benefit_id');
}
public function statusHistories()
{
return $this->morphMany(StatusHistory::class, 'statusable');
}
public function scopeUsed($query, $startDate, $endDate)
{
return $query
->whereIn('status', ['approved', 'paid'])
->whereBetween('requested_at', [$startDate, $endDate]);
->whereIn('status', ['approved', 'paid']);
// ->whereBetween('requested_at', [$startDate, $endDate]);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class ClaimDiagnosis extends Model
{
use HasFactory;
protected $table = 'claim_diagnosis';
}

View File

@@ -29,6 +29,15 @@ class Corporate extends Model
protected $appends = [
'avatar_url',
];
protected $hidden = [
'created_at',
'updated_at',
'deleted_at',
'created_by',
'updated_by',
'deleted_by',
];
public function imports()
{

View File

@@ -28,6 +28,15 @@ class CorporatePolicy extends Model
'end',
'active',
];
protected $hidden = [
'created_at',
'updated_at',
'deleted_at',
'created_by',
'updated_by',
'deleted_by',
];
protected $with = [
'latestLimitJournal'

View File

@@ -17,6 +17,15 @@ class CorporateService extends Model
'status',
];
protected $hidden = [
'created_at',
'updated_at',
'deleted_at',
'created_by',
'updated_by',
'deleted_by',
];
public function corporate()
{
return $this->belongsTo(Corporate::class);
@@ -33,10 +42,20 @@ class CorporateService extends Model
}
public function specialities()
{
return $this->belongsToMany(Speciality::class, 'corporate_service_specialities', 'corporate_service_id', 'speciality_id', 'id', 'id')
->withPivot(['active']);
}
public function corporateServiceSpecialities()
{
return $this->hasMany(CorporateServiceSpeciality::class, 'corporate_service_id');
}
public function scopeActive($query) {
$query->where('status', 'active');
}
public function scopeFilter($query, array $filters)
{
if (!empty($filters['search'])) {

View File

@@ -16,9 +16,23 @@ class CorporateServiceConfig extends Model
'name',
'value'
];
protected $hidden = [
'created_at',
'updated_at',
'deleted_at',
'created_by',
'updated_by',
'deleted_by',
];
public function corporateService()
{
return $this->belongsTo(CorporateService::class, 'corporate_service_id');
}
public function exclusions()
{
return $this->morphMany(Exclusion::class, 'exclusionable');
}
}

View File

@@ -16,6 +16,15 @@ class CorporateServiceSpeciality extends Model
'speciality_id',
'active'
];
protected $hidden = [
'created_at',
'updated_at',
'deleted_at',
'created_by',
'updated_by',
'deleted_by',
];
public function corporateService()
{

View File

@@ -18,6 +18,15 @@ class Exclusion extends Model
'exclusionable_id',
'exclusionable_type',
];
protected $hidden = [
'created_at',
'updated_at',
'deleted_at',
'created_by',
'updated_by',
'deleted_by',
];
public function rules()
{

View File

@@ -16,6 +16,15 @@ class ExclusionRules extends Model
'name',
'values',
];
protected $hidden = [
'created_at',
'updated_at',
'deleted_at',
'created_by',
'updated_by',
'deleted_by',
];
public function exclusion()
{

View File

@@ -18,6 +18,15 @@ class LimitJournal extends Model
'balance',
'description',
];
protected $hidden = [
'created_at',
'updated_at',
'deleted_at',
'created_by',
'updated_by',
'deleted_by',
];
public function journalable()
{

View File

@@ -62,7 +62,6 @@ class Member extends Model
'full_name',
'age',
'gender_code',
''
];
protected $hidden = [
@@ -74,13 +73,16 @@ class Member extends Model
'deleted_by',
];
public function claims()
{
return $this->hasMany(Claim::class, 'member_id', 'id');
}
public function postponedClaims()
{
return $this->hasMany(Claim::class, 'member_id', 'id')->where('status', 'postpone');
}
public function person()
{
return $this->belongsTo(Person::class, 'person_id', 'id');

View File

@@ -40,6 +40,15 @@ class Person extends Model
'updated_by',
'deleted_by'
];
protected $hidden = [
'created_at',
'updated_at',
'deleted_at',
'created_by',
'updated_by',
'deleted_by',
];
public function getFullNameAttribute()
{

View File

@@ -64,6 +64,15 @@ class Plan extends Model
"max_surgery_reinstatement_days",
"max_surgery_periode_days",
];
protected $hidden = [
'created_at',
'updated_at',
'deleted_at',
'created_by',
'updated_by',
'deleted_by',
];
public static $doc_headers_to_field_map = [
"Service" => "service_code",
@@ -170,15 +179,15 @@ class Plan extends Model
public function benefits()
{
return $this->belongsToMany(Benefit::class, 'corporate_benefits', 'benefit_id', 'id')
return $this->belongsToMany(Benefit::class, 'corporate_benefits', 'plan_id', 'id')
->withTimestamps()
->withPivot([
// TODO corporate_benefits pivot
]);
}
public function corporateBeneftis()
public function corporateBenefits()
{
return $this->hasMany(CorporateBenefit::class, 'benefit_id', 'id');
return $this->hasMany(CorporateBenefit::class, 'plan_id', 'id');
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace App\Models;
use App\Traits\Blameable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class StatusHistory extends Model
{
use HasFactory, Blameable;
protected $fillable = [
'status'
];
}

View File

@@ -4,6 +4,7 @@ namespace App\Providers;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider;
use Str;
class AppServiceProvider extends ServiceProvider
{
@@ -25,5 +26,9 @@ class AppServiceProvider extends ServiceProvider
public function boot()
{
Schema::defaultStringLength(191);
Str::macro('initials', fn($value, $sep = ' ', $glue = '') => trim(collect(explode($sep, $value))->map(function ($segment) {
return $segment[0] ?? '';
})->join($glue)));
}
}

View File

@@ -2,6 +2,8 @@
namespace App\Providers;
use App\Events\ClaimApproved;
use App\Listeners\LogClaimJournal;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
@@ -18,6 +20,10 @@ class EventServiceProvider extends ServiceProvider
Registered::class => [
SendEmailVerificationNotification::class,
],
ClaimApproved::class => [
LogClaimJournal::class,
]
];
/**

View File

@@ -2,6 +2,7 @@
namespace App\Services;
use App\Events\ClaimApproved;
use App\Models\Claim;
use App\Models\Icd;
use App\Models\Member;
@@ -111,22 +112,23 @@ class ClaimService{
// $policy = $member->currentPolicy;
// $corporate = $member->currentCorporate;
$benefit = $member->currentPlan->benefits()->where('code', $benefit_code)->first();
$corporateBenefit = $member->currentPlan->corporateBenefits()->where('benefit_id', $benefit->id)->first();
// dd($benefit->toArray());
// dd(compact(['plan', 'policy', 'corporate', 'benefit']));
$limits = [
'total_limit' => $benefit->limit_amount,
'frequency_limit_name' => $benefit->max_frequency_period_name,
'frequency_limit' => $benefit->max_frequency,
'total_limit' => $corporateBenefit ? $corporateBenefit->limit_amount : 0,
'frequency_limit_name' => $corporateBenefit ? $corporateBenefit->max_frequency_period_name : null,
'frequency_limit' => $corporateBenefit ? $corporateBenefit->max_frequency : 0,
'total_claim' => 0,
'remaining_limit' => $benefit->limit_amount,
'remaining_limit' => $corporateBenefit ? $corporateBenefit->limit_amount : 0,
'usage_daily' => null,
'usage_weekly' => null,
'usage_monthly' => null,
'usage_yearly' => null
];
switch ($benefit->max_frequency_period) {
switch ($corporateBenefit->max_frequency_period) {
case(0) :
$limits['usage_yearly'] = $member->claims()->used(Carbon::now()->firstOfYear(), now())->count();
$limits['total_claim'] = $member->claims()->used(Carbon::now()->firstOfYear(), now())->sum('total_claim');
@@ -151,7 +153,7 @@ class ClaimService{
// return null;
break;
}
$limits['remaining_limit'] = $benefit->limit_amount - $limits['total_claim'];
$limits['remaining_limit'] = $corporateBenefit->limit_amount - $limits['total_claim'];
return $limits;
}
@@ -170,20 +172,11 @@ class ClaimService{
'benefit_id' => $benefit->id,
'status' => $status
];
$claimData[$status.'_at'] = now();
$claimData[$status.'_by'] = auth()->user()->id ?? null;
// $claimData[$status.'_at'] = now();
// $claimData[$status.'_by'] = auth()->user()->id ?? null;
$claim = Claim::create($claimData);
$policy = $member->currentPolicy;
$policy->limitJournals()->create([
'previous_balance' => $policy->limit_balance,
'total_credit' => $totalClaim,
'type' => 'credit',
'balance' => bcsub($policy->limit_balance, $totalClaim),
'description' => 'Log for Claim #'. $claim->code,
]);
DB::commit();
return $claim;
} catch (\Exception $error) {
@@ -192,4 +185,23 @@ class ClaimService{
throw new \Exception($error);
}
}
// public static function claimApprove(Claim $claim)
// {
// if (!in_array($claim->status, ['approved', 'paid', 'declined'])) {
// // Only Update Claim is not approved yet
// if (empty($claim->approved_at)) {
// $claim->approved_at = now();
// $claim->status = 'approved';
// $claim->save();
// ClaimApproved::dispatch($claim);
// }
// }
// return false;
// }
}

View File

@@ -7,6 +7,7 @@ trait Blameable {
public static function bootBlameable() {
static::creating(function ($model) {
$model->created_by = auth()->id() ?? NULL;
$model->updated_by = auth()->id() ?? NULL;
});
static::updating(function ($model) {

5
config/aso.php Normal file
View File

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

View File

@@ -17,28 +17,28 @@ return new class extends Migration
$table->id();
$table->string('code')->index();
$table->foreignId('member_id')->index();
$table->foreignId('diagnosis_id')->index()->nullable();
$table->string('total_claim')->nullable();
// $table->foreignId('diagnosis_id')->index()->nullable();
$table->string('currency');
$table->string('total_claim')->nullable();
$table->foreignId('plan_id')->index()->nullable();
$table->foreignId('benefit_id')->index()->nullable();
$table->string('status');
$table->dateTime('requested_at')->nullable();
$table->unsignedBigInteger('requested_by')->nullable()->index();
// $table->dateTime('requested_at')->nullable();
// $table->unsignedBigInteger('requested_by')->nullable()->index();
$table->dateTime('received_at')->nullable();
$table->unsignedBigInteger('received_by')->nullable()->index();
// $table->dateTime('received_at')->nullable();
// $table->unsignedBigInteger('received_by')->nullable()->index();
$table->dateTime('approved_at')->nullable();
$table->unsignedBigInteger('approved_by')->nullable()->index();
// $table->dateTime('approved_at')->nullable();
// $table->unsignedBigInteger('approved_by')->nullable()->index();
$table->dateTime('declined')->nullable();
$table->unsignedBigInteger('declined_by')->nullable()->index();
// $table->dateTime('declined')->nullable();
// $table->unsignedBigInteger('declined_by')->nullable()->index();
$table->dateTime('paid_at')->nullable();
$table->unsignedBigInteger('paid_by')->nullable()->index();
// $table->dateTime('paid_at')->nullable();
// $table->unsignedBigInteger('paid_by')->nullable()->index();
$table->timestamps();
$table->softDeletes();

View File

@@ -0,0 +1,38 @@
<?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('status_histories', function (Blueprint $table) {
$table->id();
$table->morphs('statusable');
$table->string('status');
$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('status_histories');
}
};

View File

@@ -0,0 +1,40 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('claim_diagnosis', function (Blueprint $table) {
$table->id();
$table->foreignId('claim_id');
$table->string('type')->comment('primary, secondary');
$table->foreignId('diagnosis_id')->nullable();
$table->string('note')->nullable();
$table->text('description')->nullable();
$table->timestamps();
$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_diagnosis');
}
};

View File

@@ -15,6 +15,7 @@ use App\Models\Unit;
use Box\Spout\Reader\Common\Creator\ReaderEntityFactory;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Str;
class DrugSeeder extends Seeder
{
@@ -25,6 +26,12 @@ class DrugSeeder extends Seeder
*/
public function run()
{
Drug::truncate();
Organization::where('type', 'manufacturer')->delete();
Ingredient::truncate();
DrugComposition::truncate();
DrugCategory::truncate();
$file_path = resource_path('files/daftar_masteritem_ccp_14-06-2022.xlsx');
$reader = ReaderEntityFactory::createReaderFromFile($file_path);
$reader->open($file_path);
@@ -69,12 +76,13 @@ class DrugSeeder extends Seeder
'name' => $row_data['brand']
]) : null;
$manufacturerCode = 'MAN'.str_pad(Str::initials($row_data['pabrikan']), 10, "0", STR_PAD_LEFT);
$manufacturer = Organization::firstOrCreate([
'name' => $row_data['pabrikan']
'code' => $manufacturerCode
], [
'name' => $row_data['pabrikan'],
'type' => 'manufacturer',
'code' => $row_data['pabrikan']
'code' => $manufacturerCode
]);
if (in_array($row_data['golongan'], ['VITAMINS & MINERALS', 'NUTRITIONS'])) {

View File

@@ -20,6 +20,7 @@ use Illuminate\Support\Facades\Route;
Route::middleware('linksehat.old.auth')->group(function() {
Route::post('check-membership', [MembershipController::class, 'check']);
Route::post('check-limit', [MembershipController::class, 'checkLimit']);
Route::post('check-coverage-limit', [MembershipController::class, 'checkLimit']);
Route::post('claim-create', [ClaimController::class, 'store']);
});