diff --git a/Modules/Client/Http/Controllers/Api/CorporateMemberController.php b/Modules/Client/Http/Controllers/Api/CorporateMemberController.php index a109ac9c..c698b5a8 100644 --- a/Modules/Client/Http/Controllers/Api/CorporateMemberController.php +++ b/Modules/Client/Http/Controllers/Api/CorporateMemberController.php @@ -9,6 +9,7 @@ use Illuminate\Http\Request; use Illuminate\Routing\Controller; use Modules\Client\Transformers\ClaimReport\MemberResources as ClaimReportMemberResources; use Modules\Client\Transformers\Dashboard\MemberResources as DashboardMemberResources; +use Modules\Client\Transformers\Dashboard\MemberAlarmCenterResources as DashboardMemberAlarmResources; class CorporateMemberController extends Controller { @@ -29,6 +30,9 @@ class CorporateMemberController extends Controller case 'claim-submit': $members = $this->corporateMemberService->getAllMemberClaimReports($corporate_id, $request); return response()->json(Helper::paginateResources(ClaimReportMemberResources::collection($members))); + case 'alarm-center': + $members = $this->corporateMemberService->getAllMemberAlarmCenter($corporate_id, $request); + return response()->json(Helper::paginateResources(DashboardMemberAlarmResources::collection($members))); default: $members = $this->corporateMemberService->getAllMemberDashboards($corporate_id, $request); return response()->json(Helper::paginateResources(DashboardMemberResources::collection($members))); diff --git a/Modules/Client/Transformers/Dashboard/MemberAlarmCenterResources.php b/Modules/Client/Transformers/Dashboard/MemberAlarmCenterResources.php new file mode 100644 index 00000000..6bb0587b --- /dev/null +++ b/Modules/Client/Transformers/Dashboard/MemberAlarmCenterResources.php @@ -0,0 +1,26 @@ + $this->id, + 'memberId' => $this->member_id, + 'fullName' => $this->full_name, + 'service' => $this->service_code, + 'start_date' => $this->start_date, + 'end_date' => $this->end_date, + 'status' => $this->active, + ]; + } +} diff --git a/Modules/Internal/Http/Controllers/Api/CorporateController.php b/Modules/Internal/Http/Controllers/Api/CorporateController.php index b9d182ea..d064d0ea 100644 --- a/Modules/Internal/Http/Controllers/Api/CorporateController.php +++ b/Modules/Internal/Http/Controllers/Api/CorporateController.php @@ -77,6 +77,7 @@ class CorporateController extends Controller */ public function store(Request $request) { + $request->validate([ 'code' => 'required|regex:/^[a-zA-Z0-9]+$/', 'name' => 'required', @@ -90,7 +91,6 @@ class CorporateController extends Controller 'policy_stop_service_percentage' => 'required_with:policy_code', 'policy_stop_service_net' => 'required_with:policy_code', ]); - try { DB::beginTransaction(); $corporate_data = $request->all(); @@ -98,7 +98,6 @@ class CorporateController extends Controller $newCorporate = Corporate::create($request->all()); if ($request->has('policy_code') && !empty($request->policy_code)) { - // dd($request->policy_code, 'fuck you'); $newCorporate->policies()->create([ 'code' => $request->policy_code ?? NULL, 'total_premi' => $request->policy_total_premi ?? NULL, @@ -521,4 +520,5 @@ class CorporateController extends Controller break; } } + } diff --git a/Modules/Internal/Http/Controllers/Api/DivisionController.php b/Modules/Internal/Http/Controllers/Api/DivisionController.php index 3584abff..df33f22c 100644 --- a/Modules/Internal/Http/Controllers/Api/DivisionController.php +++ b/Modules/Internal/Http/Controllers/Api/DivisionController.php @@ -91,7 +91,8 @@ class DivisionController extends Controller $request->validate([ 'code' => [ 'required', - Rule::unique('corporate_plans')->where('corporate_id', $corporate_id)->ignore($corporatePlan->id) + // Rule::unique('corporate_plans')->where('corporate_id', $corporate_id)->ignore($corporatePlan->id) + Rule::unique('corporate_divisions')->where('corporate_id', $corporate_id) ], 'name' => 'required' ]); diff --git a/Modules/Internal/Services/CorporateService.php b/Modules/Internal/Services/CorporateService.php index ea7a1358..b7134877 100644 --- a/Modules/Internal/Services/CorporateService.php +++ b/Modules/Internal/Services/CorporateService.php @@ -39,11 +39,10 @@ class CorporateService try { $plan_data = $row; $plan_data["corporate_id"] = $corporate->id; - $this->validatePlanRow($plan_data); - $plan = $corporate->plans()->updateOrCreate([ - 'service_code' => $plan_data['service_code'], + 'corporate_plan_id' => $plan_data['corporate_plan_id'], + // 'active' => 0, ], $plan_data); return $plan; diff --git a/app/Builders/MemberBuilder.php b/app/Builders/MemberBuilder.php index 78158016..1b16e396 100644 --- a/app/Builders/MemberBuilder.php +++ b/app/Builders/MemberBuilder.php @@ -46,4 +46,20 @@ class MemberBuilder extends Builder 'right' => $this->rightJoin('claim_requests', 'members.id', '=', 'claim_requests.member_id') }; } + + public function joinMemberPlans(string $value = 'join'): static + { + return match ($value) { + 'join' => $this->join('member_plans', 'members.id', '=', 'member_plans.member_id'), + 'left' => $this->leftJoin('member_plans', 'members.id', '=', 'member_plans.member_id'), + }; + } + + public function joinPlans(string $value = 'join'): static + { + return match ($value) { + 'join' => $this->join('plans', 'member_plans.plan_id', '=', 'plans.id'), + 'left' => $this->leftJoin('plans', 'member_plans.plan_id', '=', 'plans.id'), + }; + } } diff --git a/app/Http/Controllers/Api/OLDLMS/MembershipController.php b/app/Http/Controllers/Api/OLDLMS/MembershipController.php index d0b0ee39..0b574f10 100644 --- a/app/Http/Controllers/Api/OLDLMS/MembershipController.php +++ b/app/Http/Controllers/Api/OLDLMS/MembershipController.php @@ -191,8 +191,7 @@ class MembershipController extends Controller 'corporate_id' => 'required' ]); - $corporate = Corporate::findOrFail($request->corporate_id); - + $corporate = Corporate::findOrFail($request->corporate_id); // Make Validation from Linking Rules $linkingRulesArr = $corporate->linking_rules->toArray(); $validationRules = []; @@ -245,9 +244,9 @@ class MembershipController extends Controller ]) ->first(); - if ($member) { - return Helper::responseJson(data: MemberResource::make($member), message: 'Data Member ditemukan!'); + $message = $member->currentPolicy->corporate->welcome_message; + return Helper::responseJson(data: MemberResource::make($member), message: $message); } return Helper::responseJson(data: [], message: 'Member Tidak ditemukan', statusCode: 404, status: 'error'); diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 20b3f86e..18e416ba 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -37,6 +37,7 @@ class Kernel extends HttpKernel \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, + \Fruitcake\Cors\HandleCors::class, ], 'api' => [ diff --git a/app/Http/Resources/OLDLMS/MemberResource.php b/app/Http/Resources/OLDLMS/MemberResource.php index 15b4a649..4f4edc7e 100644 --- a/app/Http/Resources/OLDLMS/MemberResource.php +++ b/app/Http/Resources/OLDLMS/MemberResource.php @@ -35,7 +35,7 @@ class MemberResource extends JsonResource 'corporate' => [ 'code' => $this->currentPolicy?->corporate->code ?? null, 'name' => $this->currentPolicy?->corporate->name, - 'welcome_message' => $this->currentPolicy?->corporate?->welcome_message, + 'welcome_message' => $this->currentPolicy?->corporate->welcome_message, 'help_text' => $this->currentPolicy?->corporate?->help_text, 'avatar_url' => $this->currentpolicy?->corporate?->avatar_url ], diff --git a/app/Models/Plan.php b/app/Models/Plan.php index 1758a4eb..dab9b882 100644 --- a/app/Models/Plan.php +++ b/app/Models/Plan.php @@ -63,6 +63,7 @@ class Plan extends Model "currency", "max_surgery_reinstatement_days", "max_surgery_periode_days", + "active", ]; protected $hidden = [ diff --git a/app/Services/CorporateMemberService.php b/app/Services/CorporateMemberService.php index 8a8d59eb..afcec6f6 100644 --- a/app/Services/CorporateMemberService.php +++ b/app/Services/CorporateMemberService.php @@ -82,4 +82,42 @@ class CorporateMemberService ->select(['members.id', 'members.person_id', 'members.member_id', 'members.name', 'corporate_divisions.name AS division_name', 'members.active', 'claim_requests.id', 'claim_requests.member_id', 'claim_requests.submission_date']) ->paginate($limit); } + + public function getAllMemberAlarmCenter(int $corporateId, Request $request) + { + $limit = $request->has('perPage') ? $request->input('perPage') : 10; + + return Member::query() + ->joinCorporateEmployees('left') + ->joinMemberPlans('left') + ->joinPlans('left') + ->with(['currentPlan', 'person']) + ->where('corporate_employees.corporate_id', $corporateId) + ->when($request->input('search'), function (Builder $query, $search) { + $query->where(function (Builder $query) use ($search) { + $query->orWhere('members.member_id', 'like', "%" . $search . "%") + ->orWhere('members.name', 'like', "%" . $search . "%"); + }); + }) + ->when($request->input('division'), function (Builder $query, $value) { + $query->where('corporate_employees.division_id', $value); + }) + ->when($request->has('orderBy'), function (Builder $query) use ($request) { + $orderBy = match ($request->input('orderBy')) { + 'memberId' => 'member_id', + 'fullName' => 'name', + 'status' => 'active', + 'start_date' => 'member_plans.start', + 'end_date' => 'member_plans.end', + 'service' => 'plans.service_code', + + default => '' + }; + + $query->getQuery()->orderBy($orderBy, $request->order); + }) + ->select(['members.id', 'members.person_id', 'members.member_id', 'members.name', 'member_plans.start AS start_date', 'member_plans.end AS end_date', 'plans.active', 'plans.service_code']) + ->selectRaw("(select sum(`claims`.`total_claim`) from `claims` where `members`.`id` = `claims`.`member_id` AND `claims`.`deleted_at` IS NULL) AS `claims_sum_total_claim`") + ->paginate($limit); + } } diff --git a/composer.json b/composer.json index eb5ff3b7..b1778fb4 100644 --- a/composer.json +++ b/composer.json @@ -9,6 +9,7 @@ "barryvdh/laravel-snappy": "^1.0", "box/spout": "^3.3", "duitkupg/duitku-php": "dev-master", + "fruitcake/laravel-cors": "^3.0", "guzzlehttp/guzzle": "^7.2", "h4cc/wkhtmltopdf-amd64": "0.12.x", "laravel/framework": "^9.11", diff --git a/composer.lock b/composer.lock index aa4d4d3d..e4c87c3a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3173df7bfbfeeb8f05d3670505b69a05", + "content-hash": "f81882bbe6fbd0202d58351a9dbf3340", "packages": [ { "name": "barryvdh/laravel-snappy", @@ -768,6 +768,86 @@ }, "time": "2022-09-18T07:06:19+00:00" }, + { + "name": "fruitcake/laravel-cors", + "version": "v3.0.0", + "source": { + "type": "git", + "url": "https://github.com/fruitcake/laravel-cors.git", + "reference": "7c036ec08972d8d5d9db637e772af6887828faf5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fruitcake/laravel-cors/zipball/7c036ec08972d8d5d9db637e772af6887828faf5", + "reference": "7c036ec08972d8d5d9db637e772af6887828faf5", + "shasum": "" + }, + "require": { + "fruitcake/php-cors": "^1.2", + "illuminate/contracts": "^6|^7|^8|^9", + "illuminate/support": "^6|^7|^8|^9", + "php": "^7.4|^8.0" + }, + "require-dev": { + "laravel/framework": "^6|^7.24|^8", + "orchestra/testbench-dusk": "^4|^5|^6|^7", + "phpunit/phpunit": "^9", + "squizlabs/php_codesniffer": "^3.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + }, + "laravel": { + "providers": [ + "Fruitcake\\Cors\\CorsServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Fruitcake\\Cors\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fruitcake", + "homepage": "https://fruitcake.nl" + }, + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "Adds CORS (Cross-Origin Resource Sharing) headers support in your Laravel application", + "keywords": [ + "api", + "cors", + "crossdomain", + "laravel" + ], + "support": { + "issues": "https://github.com/fruitcake/laravel-cors/issues", + "source": "https://github.com/fruitcake/laravel-cors/tree/v3.0.0" + }, + "funding": [ + { + "url": "https://fruitcake.nl", + "type": "custom" + }, + { + "url": "https://github.com/barryvdh", + "type": "github" + } + ], + "abandoned": true, + "time": "2022-02-23T14:53:22+00:00" + }, { "name": "fruitcake/php-cors", "version": "v1.2.0", diff --git a/frontend/client-portal/src/sections/dashboard/CardPolicy.tsx b/frontend/client-portal/src/sections/dashboard/CardPolicy.tsx index 2fa94b92..41ba3808 100644 --- a/frontend/client-portal/src/sections/dashboard/CardPolicy.tsx +++ b/frontend/client-portal/src/sections/dashboard/CardPolicy.tsx @@ -95,9 +95,10 @@ export default function CardPolicy(props: CardPolicyProps) { const [dialogTitle, setDialogTitle] = useState(''); const [isDialog, setIsDialog] = useState(''); - const { limit, topUpLimit } = props.data; - - console.log(limit); + const { limit, topUpLimit } = props.data || {}; + if (!limit || !topUpLimit) { + return null; + } const clickHandler = (isDialog: string) => { switch (isDialog) { diff --git a/frontend/dashboard/src/pages/Corporates/Division/Form.tsx b/frontend/dashboard/src/pages/Corporates/Division/Form.tsx index 2e088d92..dfdde430 100644 --- a/frontend/dashboard/src/pages/Corporates/Division/Form.tsx +++ b/frontend/dashboard/src/pages/Corporates/Division/Form.tsx @@ -64,12 +64,12 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop const onSubmit = async (data: any) => { if (!isEdit) { await axios - .post('/corporate/' + corporate_id + '/divisions', data) + .post('/corporates/' + corporate_id + '/divisions', data) .then((res) => { enqueueSnackbar('Division created successfully', { variant: 'success' }); }) .then((res) => { - navigate('/corporate/' + corporate_id + '/divisions', { replace: true }); + navigate('/corporates/' + corporate_id + '/divisions', { replace: true }); }) .catch(({ response }) => { if (response.status === 422) { @@ -84,12 +84,12 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop }); } else { await axios - .put('/corporate/' + corporate_id + '/divisions/' + currentCorporatePlan?.id , data) + .put('/corporates/' + corporate_id + '/divisions/' + currentCorporatePlan?.id , data) .then((res) => { enqueueSnackbar('Division updated successfully', { variant: 'success' }); }) .then((res) => { - navigate('/corporate/' + corporate_id + '/divisions/' , { replace: true }); + navigate('/corporates/' + corporate_id + '/divisions/' , { replace: true }); }) .catch(({ response }) => { enqueueSnackbar('Update Failed : '+ response.data.message, { variant: 'error' }); diff --git a/frontend/dashboard/src/pages/Corporates/Form.tsx b/frontend/dashboard/src/pages/Corporates/Form.tsx index 35d98d8d..9a7eab2c 100644 --- a/frontend/dashboard/src/pages/Corporates/Form.tsx +++ b/frontend/dashboard/src/pages/Corporates/Form.tsx @@ -43,6 +43,7 @@ import axios from '../../utils/axios'; import { fCurrency } from '../../utils/formatNumber'; import RHFAutocomplete from '../../components/hook-form/RHFAutocomplete'; import UploadImage from '../../components/UploadImage'; +import { fPostFormat } from '@/utils/formatTime'; const LabelStyle = styled(Typography)(({ theme }) => ({ ...theme.typography.subtitle2, @@ -70,15 +71,78 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) { const NewCorporateSchema = Yup.object().shape({ name: Yup.string().required('Name is required'), - code: Yup.string().required('Corporate Code is required'), + code: Yup.string().required('Corporate Code is required').test( + 'unique-code', + 'Code must be unique', + async function (value) { + const existingCodes = await getExistingCodes(); + return !existingCodes.includes(value); + } + ), active: Yup.boolean().required('Corporate Status is required'), type: Yup.string().required('Type is required'), + welcome_message: Yup.string().required('Welcome Message is required'), + help_text: Yup.string().required('Help Text is required'), + // policy_code: Yup.string().required('Policy Code is required'), + policy_start: Yup.date().required('Start Date is required'), + policy_end: Yup.date().required('End Date is required').min(Yup.ref('policy_start'), "end date can't be before start date"), + policy_total_premi: Yup.number().required('Deposit Initial Fund is required').min(0), + // linking_rules: Yup.string().required('Link Rules is required'), + policy_minimal_deposit_percentage: + Yup.number() + .typeError("Please enter a valid number") + .required('Percentage Deposit is required') + .min(0, "Minimum atleast 0") + .max(100, "Allowed maximum is 100"), + policy_minimal_alert_percentage: + Yup.number() + .typeError("Please enter a valid number") + .required('Percentage Alert is required') + .min(0, "Minimum atleast 0") + .max(100, "Allowed maximum is 100"), + policy_stop_service_percentage: + Yup.number() + .typeError("Please enter a valid number") + .min(0, "Minimum atleast 0") + .required('Percentage Stop is required') + .test("max", "Total should not exceed 100 %", function(value) { + const { policy_minimal_alert_percentage } = this.parent; + const { policy_minimal_deposit_percentage } = this.parent; + return value == 100 - policy_minimal_alert_percentage- policy_minimal_deposit_percentage; + }), parent_id: Yup.string().when('type', { is: 'subcorporate', then: Yup.string().required('Corporate is required because type is Sub Corporate'), }), }); + async function getExistingCodes() { + // axios + // .get('/corporates/create') + // .then((res) => { + // setCorporateGroups(res.data.corporate_groups); + // }) + // .catch((err) => { + // enqueueSnackbar('Opps, failed to get Corporate Group List', { variant: 'error' }); + // }); + + try { + let response = await axios.get('/corporates'); // get data all corporate + let codeCurrent = "" + if (isEdit){ + let responseCodeCurrent = await axios.get(`/corporates/${currentCorporate?.id}/edit`); // get data current corporate + codeCurrent = responseCodeCurrent.data.code; // get data code corporate current + } + let existingCodes = response.data.data.map(item => item.code); // get data code corporate all + + var filteredArray = existingCodes.filter(e => e != codeCurrent) + return filteredArray; + } catch (error) { + console.error(error); + enqueueSnackbar('Failed to fetch existing codes', { variant: 'error' }); + } + } + const defaultValues = useMemo( () => ({ code: currentCorporate?.code || '', @@ -149,7 +213,7 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) { const [file, setFile] = useState(null); const [save, setSave] = useState(null); - console.log('save', save); + // console.log('save', save); const onSubmit = async (data: FormValuesProps) => { try { @@ -170,11 +234,12 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) { formData.append('policy_minimal_alert_net', data.policy_minimal_alert_net); formData.append('policy_stop_service_percentage', data.policy_stop_service_percentage); formData.append('policy_stop_service_net', data.policy_stop_service_net); - formData.append('policy_start', data.policy_start); - formData.append('policy_end', data.policy_end); + formData.append('policy_start', fPostFormat(data.policy_start)); + formData.append('policy_end', fPostFormat(data.policy_end)); formData.append('linking_rules', data.linking_rules); - console.log('MOTHERFUCKER', data.linking_rules) + + // console.log('MOTHERFUCKER', data.linking_rules) if (!isEdit) { const response = await axios.post('/corporates', formData); @@ -184,7 +249,7 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) { } reset(); enqueueSnackbar( - !isEdit ? 'Corporate Created Successfully!' : 'Corporate Udpated Successfully!', + !isEdit ? 'Corporate Created Successfully!' : 'Corporate Updated Successfully!', { variant: 'success' } ); navigate('/corporates');