diff --git a/Modules/Internal/Http/Controllers/Api/MemberController.php b/Modules/Internal/Http/Controllers/Api/MemberController.php
new file mode 100644
index 00000000..119bf1e2
--- /dev/null
+++ b/Modules/Internal/Http/Controllers/Api/MemberController.php
@@ -0,0 +1,188 @@
+memberEnrollmentService = $memberEnrollmentService;
+ }
+ /**
+ * Display a listing of the resource.
+ * @return Renderable
+ */
+ public function index(Request $request, $corporate_id)
+ {
+ $benefits = Member::query()
+ ->filter($request->all())
+ // ->where('corporate_id', $corporate_id)
+ ->paginate(20)
+ ->appends($request->all());
+
+ return $benefits;
+ }
+
+ /**
+ * 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 import(Request $request, $corporate_id)
+ {
+ $request->validate([
+ 'file' => 'required|file|mimes:xls,xlsx,csv,txt',
+ ]);
+ $corporate = Corporate::findOrFail($corporate_id);
+
+ $file_name = now()->getPreciseTimestamp(3).'-'.$request->file('file')->getClientOriginalName();
+ $file = $request->file('file')->storeAs('temp', $file_name);
+
+ $reader = ReaderEntityFactory::createReaderFromFile(Storage::path('temp/'.$file_name));
+ $reader->open(Storage::path('temp/'.$file_name));
+
+ $writer = WriterEntityFactory::createXLSXWriter();
+ $writer->openToFile(Storage::disk('public')->path('temp/result-'.$file_name));
+
+ $headers_map_to_table_fields = Member::$doc_headers_to_field_map;
+
+ // Write Header to File
+ $result_headers = array_keys($headers_map_to_table_fields);
+ array_push($result_headers, 'Ingestion Status');
+ $singleRow = WriterEntityFactory::createRow($this->memberEnrollmentService->makeResultRow($result_headers));
+ $writer->addRow($singleRow);
+
+ $imported_member_data = 0;
+ $failed_member_data = [];
+ foreach ($reader->getSheetIterator() as $sheet) {
+ $doc_headers_indexes = [];
+ foreach ($sheet->getRowIterator() as $index => $row) {
+ if ($index == 1) { // First Row Must be Header
+ foreach ($row->getCells() as $index => $cell) {
+ // Clear up the string and remove all spaces
+ $title = $cell->getValue();
+ $title = preg_replace( "/\r|\n/", " ", $title );
+ $title = preg_replace('/\xc2\xa0/', " ", $title );
+ $title = rtrim($title);
+ $title = ltrim($title);
+ $doc_headers_indexes[$index] = $title;
+ }
+ } else { // Next Row Should be Data
+ $new_member_data = [];
+ foreach ($row->getCells() as $header_index => $cell) {
+ if (isset($headers_map_to_table_fields[$doc_headers_indexes[$header_index]])) {
+ $new_member_data[$headers_map_to_table_fields[$doc_headers_indexes[$header_index]]] = $cell->getValue();
+ }
+ }
+
+ try {
+ $rowResponse = $this->memberEnrollmentService->handleImportRow($corporate, $new_member_data);
+
+ // Write Success Result to File
+ array_push($new_member_data, 'SUCCESS');
+ $singleRow = WriterEntityFactory::createRow($this->memberEnrollmentService->makeResultRow($new_member_data));
+ $writer->addRow($singleRow);
+ $imported_member_data++;
+ } catch (ImportRowException $e) {
+ // Write Data Validation Error to File
+ array_push($new_member_data, $e->getMessage());
+ $singleRow = WriterEntityFactory::createRow($this->memberEnrollmentService->makeResultRow($new_member_data));
+ $writer->addRow($singleRow);
+ $failed_member_data[] = ['row_number' => $index, 'error' => $e->getMessage()];
+ } catch (\Exception $e) {
+ // Write Server Error to File
+ array_push($new_member_data, "Server Error");
+ $singleRow = WriterEntityFactory::createRow($this->memberEnrollmentService->makeResultRow($new_member_data));
+ $writer->addRow($singleRow);
+ $failed_member_data[] = ['row_number' => $index, 'error' => $e->getMessage()];
+ }
+ }
+
+ }
+
+ break; //only read first sheet
+ }
+ $reader->close();
+ $writer->close();
+ Storage::delete('temp/'.$file_name);
+ // throw(404);
+
+ return [
+ 'total_success_row' => $imported_member_data,
+ 'total_failed_row' => count($failed_member_data),
+ 'failed_row' => $failed_member_data,
+ 'result_file' => [
+ 'url' => Storage::disk('public')->url('temp/result-'.$file_name),
+ 'name' => 'result-'.$file_name,
+ ]
+ ];
+ }
+}
diff --git a/Modules/Internal/Routes/api.php b/Modules/Internal/Routes/api.php
index e9ef230f..258ac329 100644
--- a/Modules/Internal/Routes/api.php
+++ b/Modules/Internal/Routes/api.php
@@ -7,6 +7,7 @@ use Modules\Internal\Http\Controllers\Api\CorporateBenefitController;
use Modules\Internal\Http\Controllers\Api\CorporateController;
use Modules\Internal\Http\Controllers\Api\CorporatePlanController;
use Modules\Internal\Http\Controllers\Api\DivisionController;
+use Modules\Internal\Http\Controllers\Api\MemberController;
use Modules\Internal\Http\Controllers\Api\PlanController;
/*
@@ -57,5 +58,9 @@ Route::prefix('internal')->group(function () {
Route::post('corporates/{corporate_id}/divisions', [DivisionController::class, 'store']);
Route::get('corporates/{corporate_id}/divisions/{id}/edit', [DivisionController::class, 'edit']);
Route::put('corporates/{corporate_id}/divisions/{id}', [DivisionController::class, 'update']);
+
+ Route::get('corporates/{corporate_id}/members', [MemberController::class, 'index']);
+ Route::post('corporates/{corporate_id}/members/import', [MemberController::class, 'import']);
+
});
});
diff --git a/Modules/Internal/Services/MemberEnrollmentService.php b/Modules/Internal/Services/MemberEnrollmentService.php
new file mode 100644
index 00000000..04df67f4
--- /dev/null
+++ b/Modules/Internal/Services/MemberEnrollmentService.php
@@ -0,0 +1,537 @@
+member = $member;
+ }
+
+ protected function validateRow($row)
+ {
+ if (empty($row['record_type'])) {
+ throw new ImportRowException(__('enrollment.RECORD_TYPE_REQUIRED'), 0, null, $row);
+ }
+
+ if (empty($row['payor_id'])) {
+ throw new ImportRowException(__('enrollment.PAYOR_ID_REQUIRED'), 0, null, $row);
+ }
+
+ if (empty($row['member_id'])) {
+ throw new ImportRowException(__('enrollment.MEMBER_ID_REQUIRED'), 0, null, $row);
+ }
+
+ if ($row['record_type'] == 'P') {
+ if (!empty($row['principal_id'])) {
+ throw new ImportRowException(__('enrollment.PRINCIPAL_ID_NOT_REQUIRED'), 0, null, $row);
+ }
+
+ if (empty($row['corporate_id'])) {
+ throw new ImportRowException(__('enrollment.CORPORATE_ID_REQUIRED'), 0, null, $row);
+ }
+ }
+
+ if ($row['record_type'] == 'D') {
+ if (empty($row['principal_id'])) {
+ throw new ImportRowException(__('enrollment.PRINCIPAL_ID_REQUIRED'), 0, null, $row);
+ }
+ }
+
+ // TOOD RECORD BCA ONLY
+ if ($row['record_type'] == 'D' && !empty($row['branch_code'])) {
+ throw new ImportRowException(__('enrollment.BRANCH_CODE_NOT_REQUIRED'), 0, null, $row);
+ }
+
+ // TODO BANK VALIDATION
+ // if ($row['record_type'] == 'D' && !empty($row['branch_code'])) {
+ // throw new ImportRowException(__('enrollment.BRANCH_CODE_NOT_REQUIRED'), 0, null, $row);
+ // }
+
+ if (!empty($row['language']) && !in_array($row['language'], ['M', 'E', 'C', 'I', 'O'])) {
+ throw new ImportRowException(__('enrollment.INVALID_LANGUAGE'), 0, null, $row);
+ }
+
+ if (!empty($row['type_of_work']) && !in_array($row['type_of_work'], ['0', '1', '2', '3'])) {
+ throw new ImportRowException(__('enrollment.INVALID_TYPE_OF_WORK'), 0, null, $row);
+ }
+
+ if (!empty($row['race']) && !in_array($row['race'], ['M', 'C', 'I', 'O'])) {
+ throw new ImportRowException(__('enrollment.INVALID_RACE'), 0, null, $row);
+ }
+
+ if (empty($row['policy_number'])) {
+ throw new ImportRowException(__('enrollment.POLICY_NUMBER_REQUIRED'), 0, null, $row);
+ }
+
+ if (!empty($row['marital_status']) && !in_array($row['marital_status'], ['S', 'M', 'D'])) {
+ throw new ImportRowException(__('enrollment.INVALID_MARITAL_STATUS'), 0, null, $row);
+ }
+
+ if (empty($row['member_effective_date']) ) {
+ throw new ImportRowException(__('enrollment.MEMBER_EFFECTIVE_REQUIRED'), 0, null, $row);
+ }
+ // TODO EFFECTIVE DATE VALIDATION
+
+ if (empty($row['member_expiry_date']) ) {
+ throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_REQUIRED'), 0, null, $row);
+ }
+ // TODO EFFECTIVE DATE VALIDATION
+
+ // TODO FKTP VALIDATION
+ // TODO FKRTL VALIDATION
+
+ if (!empty($row['marital_status']) && !in_array($row['marital_status'], ['S', 'M', 'D'])) {
+ throw new ImportRowException(__('enrollment.INVALID_MARITAL_STATUS'), 0, null, $row);
+ }
+
+ if (empty($row['name'])) {
+ throw new ImportRowException(__('enrollment.NAME_REQUIRED'), 0, null, $row);
+ }
+
+ if (!empty($row['telephone_mobile'])
+ && substr($row['telephone_mobile'], 0, 4) != '+628') {
+ throw new ImportRowException(__('enrollment.PHONE_INVALID'), 0, null, $row);
+ }
+
+ if (!empty($row['email'])
+ && !filter_var($row['email'], FILTER_VALIDATE_EMAIL)) {
+ throw new ImportRowException(__('enrollment.EMAIL_INVALID'), 0, null, $row);
+ }
+
+ if (empty($row['date_of_birth'])) {
+ throw new ImportRowException(__('enrollment.DATE_OF_BIRTH_REQUIRED'), 0, null, $row);
+ }
+ // TODO DOB FORMAT VALIDATION
+
+ if (empty($row['sex'])) {
+ throw new ImportRowException(__('enrollment.SEX_REQUIRED'), 0, null, $row);
+ }
+
+ if (empty($row['sex'])) {
+ throw new ImportRowException(__('enrollment.SEX_REQUIRED'), 0, null, $row);
+ }
+ }
+
+ public function handleImportRow(Corporate $corporate, $row)
+ {
+ try {
+ $member_data = [
+ "name" => $row['name'],
+ "member_id" => $row['member_id'],
+ "payor_id" => $row['payor_id'],
+ "nik" => $row['nik'],
+ "birth_date" => Carbon::parse($row['date_of_birth']),
+ "gender" => Helper::genderNormalization($row['sex']),
+ "language" => $row['language'],
+ "race" => $row['race'],
+ "marital_status" => $row['marital_status'],
+ "record_type" => $row['record_type'],
+ "principal_id" => $row['principal_id'],
+ "relation_with_principal" => $row['relationship_with_principal'],
+ "bpjs_class" => $row['bpjs_class'],
+ ];
+
+ switch ($row['record_mode']) {
+ case "1": // New Member
+ $member = Member::query()
+ ->where('member_id', $row['member_id'])
+ ->first();
+
+ if ($member) {
+ throw new ImportRowException(__('enrollment.MEMBER_EXISTS', [
+ 'member_id' => $row['member_id'],
+ 'policy_id' => $row['policy_number']
+ ]), 0, null, $row);
+ } else {
+ $member = new Member();
+ }
+
+ $memberPolicy = $member->policies()
+ ->where('policy_id', $row['policy_number'])
+ ->first();
+
+ if ($memberPolicy) {
+ throw new ImportRowException(__('enrollment.MEMBER_EXISTS', [
+ 'member_id' => $row['member_id'],
+ 'policy_id' => $row['policy_number']
+ ]), 0, null, $row);
+ }
+
+ $this->validateRow($row);
+
+ try {
+ DB::beginTransaction();
+ $member->fill($member_data);
+ if ($member->save()) {
+ $memberPolicy = new MemberPolicy();
+ $memberPolicy->fill([
+ 'member_id' => $member->id,
+ 'policy_id' => $row['policy_number'],
+ 'start' => Carbon::parse($row['member_effective_date']),
+ 'end' => Carbon::parse($row['member_expiry_date']),
+ 'status' => 'active'
+ ]);
+ $memberPolicy->save();
+
+ if (!empty($row['division'])) {
+ $division_id = CorporateDivision::where('code', $row['division_code'])->where('')->pluck('id');
+ }
+
+ $member->employeds()->create([
+ 'corporate_id' => $corporate->id,
+ 'branch_code' => $row['branch_code'],
+ 'division_id' => $division_id ?? null,
+ 'nik' => $row['nik']
+ ]);
+ }
+ DB::commit();
+ } catch (\Exception $e) {
+ DB::rollback();
+ throw new ImportRowException($e->getMessage(), $e->getCode(), $e, $row);
+ }
+ break;
+ case "2": // Member Information Update (Without Replacement Card)
+ $memberPolicy = MemberPolicy::query()
+ ->where('policy_id', $row['policy_number'])
+ ->where('member_id', $row['member_id'])
+ ->with('member')
+ ->first();
+
+ if (!$memberPolicy) {
+ throw new ImportRowException(__('enrollment.MEMBER_NOT_EXISTS', [
+ 'member_id' => $row['member_id'],
+ 'policy_id' => $row['policy_number']
+ ]), 0, null, $row);
+ }
+
+ if ($memberPolicy->status != 'active') {
+ throw new ImportRowException(__('enrollment.MEMBER_INACTIVE', [
+ 'member_id' => $row['member_id'],
+ 'policy_id' => $row['policy_number']
+ ]), 0, null, $row);
+ }
+
+ $memberPolicy->member->fill($member_data);
+ if (!$memberPolicy->member->isDirty()) {
+ throw new ImportRowException(__('enrollment.MEMBER_NO_CHANGE'), 0, null, $row);
+ }
+
+ return $memberPolicy->member->save();
+
+ break;
+ case "3": // Member Deletion
+ $memberPolicy = MemberPolicy::query()
+ ->where('policy_id', $row['policy_number'])
+ ->where('member_id', $row['member_id'])
+ ->first();
+
+ if (!$memberPolicy) {
+ throw new ImportRowException(__('enrollment.MEMBER_NOT_EXISTS', [
+ 'member_id' => $row['member_id'],
+ 'policy_id' => $row['policy_number']
+ ]), 0, null, $row);
+ }
+
+ if ($memberPolicy->status != 'active') {
+ throw new ImportRowException(__('enrollment.MEMBER_INACTIVE', [
+ 'member_id' => $row['member_id'],
+ 'policy_id' => $row['policy_number']
+ ]), 0, null, $row);
+ }
+
+ return $memberPolicy->delete();
+ break;
+ case "4": // Member Update Start and End Date
+ $memberPolicy = MemberPolicy::query()
+ ->where('policy_id', $row['policy_number'])
+ ->where('member_id', $row['member_id'])
+ ->first();
+
+ if (!$memberPolicy) {
+ throw new ImportRowException(__('enrollment.MEMBER_NOT_EXISTS', [
+ 'member_id' => $row['member_id'],
+ 'policy_id' => $row['policy_number']
+ ]), 0, null, $row);
+ }
+
+ if ($memberPolicy->status != 'active') {
+ throw new ImportRowException(__('enrollment.MEMBER_INACTIVE', [
+ 'member_id' => $row['member_id'],
+ 'policy_id' => $row['policy_number']
+ ]), 0, null, $row);
+ }
+
+ $memberPolicy->fill([
+ 'start' => $row['start_date'],
+ 'end' => $row['end_date']
+ ]);
+
+ if (!$memberPolicy->isDirty()) {
+ throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_NO_CHANGE'), 0, null, $row);
+ }
+
+ if (Carbon::parse($row['member_effective_date']) > Carbon::parse($row['end_date'])) {
+ throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_INVALID'), 0, null, $row);
+ }
+
+ return $memberPolicy->save();
+
+ break;
+ case "5": // Member Renewal Policy (without card)
+ $memberPolicy = MemberPolicy::query()
+ ->where('policy_id', $row['policy_number'])
+ ->where('member_id', $row['member_id'])
+ ->first();
+
+ if (!$memberPolicy) {
+ throw new ImportRowException(__('enrollment.MEMBER_NOT_EXISTS', [
+ 'member_id' => $row['member_id'],
+ 'policy_id' => $row['policy_number']
+ ]), 0, null, $row);
+ }
+
+ if ($memberPolicy->status != 'active') {
+ throw new ImportRowException(__('enrollment.MEMBER_INACTIVE', [
+ 'member_id' => $row['member_id'],
+ 'policy_id' => $row['policy_number']
+ ]), 0, null, $row);
+ }
+
+ if (Carbon::parse($row['member_effective_date']) > Carbon::parse($row['member_expiry_date'])) {
+ throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_INVALID'), 0, null, $row);
+ }
+
+ if (Carbon::parse($memberPolicy->end) > Carbon::parse($row['member_expiry_date']
+ || $memberPolicy->end > Carbon::parse($row['member_expiry_date']))) {
+ throw new ImportRowException(__('enrollment.MEMBER_RENEWAL_STILL_ACTIVE'), 0, null, $row);
+ }
+
+ $memberPolicy->fill([
+ 'start' => $row['member_expiry_date'],
+ 'end' => $row['member_expiry_date']
+ ]);
+
+ if (!$memberPolicy->isDirty()) {
+ throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_NO_CHANGE'), 0, null, $row);
+ }
+
+ return $memberPolicy->save();
+ break;
+ case "6": // Member Renewal Policy (with card)
+ $memberPolicy = MemberPolicy::query()
+ ->where('policy_id', $row['policy_number'])
+ ->where('member_id', $row['member_id'])
+ ->first();
+
+ if (!$memberPolicy) {
+ throw new ImportRowException(__('enrollment.MEMBER_NOT_EXISTS', [
+ 'member_id' => $row['member_id'],
+ 'policy_id' => $row['policy_number']
+ ]), 0, null, $row);
+ }
+
+ if ($memberPolicy->status != 'active') {
+ throw new ImportRowException(__('enrollment.MEMBER_INACTIVE', [
+ 'member_id' => $row['member_id'],
+ 'policy_id' => $row['policy_number']
+ ]), 0, null, $row);
+ }
+
+ if (Carbon::parse($row['member_effective_date']) > Carbon::parse($row['member_expiry_date'])) {
+ throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_INVALID'), 0, null, $row);
+ }
+
+ if (Carbon::parse($memberPolicy->end) > Carbon::parse($row['member_expiry_date']
+ || $memberPolicy->end > Carbon::parse($row['member_expiry_date']))) {
+ throw new ImportRowException(__('enrollment.MEMBER_RENEWAL_STILL_ACTIVE'), 0, null, $row);
+ }
+
+ $memberPolicy->fill([
+ 'start' => $row['member_expiry_date'],
+ 'end' => $row['member_expiry_date']
+ ]);
+
+ if (!$memberPolicy->isDirty()) {
+ throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_NO_CHANGE'), 0, null, $row);
+ }
+
+ return $memberPolicy->save();
+ break;
+ case "7": // Requesting to Change the Unique Data of the Member
+ $memberPolicy = MemberPolicy::query()
+ ->where('policy_id', $row['policy_number'])
+ ->where('member_id', $row['member_id'])
+ ->with('member')
+ ->first();
+
+ if (!$memberPolicy) {
+ throw new ImportRowException(__('enrollment.MEMBER_NOT_EXISTS', [
+ 'member_id' => $row['member_id'],
+ 'policy_id' => $row['policy_number']
+ ]), 0, null, $row);
+ }
+
+ if ($memberPolicy->status != 'active') {
+ throw new ImportRowException(__('enrollment.MEMBER_INACTIVE', [
+ 'member_id' => $row['member_id'],
+ 'policy_id' => $row['policy_number']
+ ]), 0, null, $row);
+ }
+
+ // TODO OPTION MODE FORMAT VALIDATION
+ if (empty($row["option_mode"])) {
+ throw new ImportRowException(__('enrollment.OPTION_MODE_INVALID_FORMAT', [
+ 'member_id' => $row['member_id'],
+ 'policy_id' => $row['policy_number']
+ ]), 0, null, $row);
+ }
+
+ if (
+ $row['record_type'] == 'P' &&
+ $memberPolicy->member->corporate->code == $row["corporate_id"] &&
+ $memberPolicy->policy_id == $row['policy_number'] &&
+ $memberPolicy->member_id == $row['member_id'] &&
+ $memberPolicy->member->record_type == $row['record_type']
+ ) {
+ throw new ImportRowException(__('enrollment.UNIQUE_CHANGE_PRINCIPAL_INVALID', [
+ 'member_id' => $row['member_id'],
+ 'policy_id' => $row['policy_number']
+ ]), 0, null, $row);
+ }
+
+ if (
+ $row['record_type'] == 'D' &&
+ $memberPolicy->member->corporate->code == $row["corporate_id"] &&
+ $memberPolicy->policy_id == $row['policy_number'] &&
+ $memberPolicy->member->record_type == $row['record_type'] &&
+ $memberPolicy->member->payor_id == $row['payor_id']
+ ) {
+ throw new ImportRowException(__('enrollment.UNIQUE_CHANGE_DEPENDANT_INVALID', [
+ 'member_id' => $row['member_id'],
+ 'policy_id' => $row['policy_number']
+ ]), 0, null, $row);
+ }
+
+ throw new ImportRowException(__('MODE 7 NOT HANDLED PROPERLY'), 0, null, $row);
+ break;
+ case "8": // Member Information Update (With Replacement Card)
+
+ break;
+ case "9": // Member Reactivation and Personal information update (Without replacement Card)
+ $memberPolicy = MemberPolicy::query()
+ ->where('policy_id', $row['policy_number'])
+ ->where('member_id', $row['member_id'])
+ ->first();
+
+ if (!$memberPolicy) {
+ throw new ImportRowException(__('enrollment.MEMBER_NOT_EXISTS', [
+ 'member_id' => $row['member_id'],
+ 'policy_id' => $row['policy_number']
+ ]), 0, null, $row);
+ }
+
+ if (Carbon::parse($row['member_effective_date']) < now() || Carbon::parse($row['member_expiry_date']) < now()) {
+ throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_MUST_BE_AFTER_TODAY'), 0, null, $row);
+ }
+
+ if (Carbon::parse($row['member_effective_date']) > Carbon::parse($row['member_expiry_date'])) {
+ throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_INVALID'), 0, null, $row);
+ }
+
+ $memberPolicy->fill([
+ 'start' => $row['member_effective_date'],
+ 'end' => $row['member_expiry_date']
+ ]);
+
+ return $memberPolicy->save();
+ break;
+ // case "10": // No Information Available
+
+ // break;
+ case "11": // Advance Renewal with OLD Card No. (PRINT)
+
+ throw new ImportRowException(__('MODE 11 NOT HANDLED PROPERLY'), 0, null, $row);
+ break;
+ case "12": // Advance Renewal iwh NEW Card No. (PRINT)
+
+ throw new ImportRowException(__('MODE 12 NOT HANDLED PROPERLY'), 0, null, $row);
+ break;
+ case "13": // Advance Renewal with OLD Card No. (NO PRINT)
+
+ throw new ImportRowException(__('MODE 13 NOT HANDLED PROPERLY'), 0, null, $row);
+ break;
+ // case "14": // No Information Available
+
+ // break;
+ case "15": // Lost Card / Change Card with new card number (Print) (Rarely Used)
+
+ throw new ImportRowException(__('MODE 15 NOT HANDLED PROPERLY'), 0, null, $row);
+ break;
+ case "16": // Endorsement Plan OLD Card No. (NO PRINT)
+ $plan = CorporatePlan::query()
+ ->where('corporate_id', $corporate->id)
+ ->where('code', $row['plan_id'])
+ ->where('active', true)
+ ->first();
+ if (!$plan) {
+ throw new ImportRowException(__('enrollment.PLAN_NOT_FOUND'), 0, null, $row);
+ }
+
+ $memberPolicy = MemberPolicy::query()
+ ->where('policy_id', $row['policy_number'])
+ ->where('member_id', $row['member_id'])
+ ->first();
+
+ if (!$memberPolicy) {
+ throw new ImportRowException(__('enrollment.MEMBER_NOT_EXISTS', [
+ 'member_id' => $row['member_id'],
+ 'policy_id' => $row['policy_number']
+ ]), 0, null, $row);
+ }
+
+ if ($memberPolicy->status != 'active') {
+ throw new ImportRowException(__('enrollment.MEMBER_INACTIVE', [
+ 'member_id' => $row['member_id'],
+ 'policy_id' => $row['policy_number']
+ ]), 0, null, $row);
+ }
+
+ throw new ImportRowException(__('MODE 16 NOT HANDLED PROPERLY'), 0, null, $row);
+ break;
+ case "17": // Endorsement Plan OLD Card No. (PRINT)
+
+ throw new ImportRowException(__('MODE 17 NOT HANDLED PROPERLY'), 0, null, $row);
+ break;
+ default:
+ throw new ImportRowException(__("enrollment.MODE_UNAVAILABLE"), 0, null, $row);
+ }
+ } catch (\Exception $e) {
+ throw new ImportRowException($e->getMessage(), (int) $e->getCode(), $e, $row);
+ }
+ }
+
+ public function makeResultRow($row_data)
+ {
+ $cells = [];
+ foreach ($row_data as $cellValue) {
+ $cells[] = WriterEntityFactory::createCell($cellValue);
+ }
+
+ return $cells;
+ }
+}
diff --git a/app/Exceptions/ImportRowException.php b/app/Exceptions/ImportRowException.php
new file mode 100644
index 00000000..a6167832
--- /dev/null
+++ b/app/Exceptions/ImportRowException.php
@@ -0,0 +1,22 @@
+data = $data;
+ }
+
+ public function getData()
+ {
+ return $this->data;
+ }
+}
diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php
new file mode 100644
index 00000000..a256791c
--- /dev/null
+++ b/app/Helpers/Helper.php
@@ -0,0 +1,20 @@
+where('active', true)
->latestOfMany();
}
+
+ public function corporatePlans()
+ {
+ return $this->hasMany(CorporatePlan::class, 'corporate_id');
+ }
+
+ public function corporateBenefits()
+ {
+ return $this->hasMany(CorporateBenefit::class, 'corporate_id');
+ }
+
+ public function corporateDivisions()
+ {
+ return $this->hasMany(CorporateDivision::class, 'corporate_id');
+ }
}
diff --git a/app/Models/CorporateEmployee.php b/app/Models/CorporateEmployee.php
new file mode 100644
index 00000000..925b6a12
--- /dev/null
+++ b/app/Models/CorporateEmployee.php
@@ -0,0 +1,20 @@
+ "record_mode",
+ "Record Type" => "record_type",
+ "Payor ID" => "payor_id",
+ "Member ID" => "member_id",
+ "Mapping ID" => "principal_id",
+ "Halodoc Member ID" => "halodoc_member_id",
+ "Corporate ID" => "corporate_id",
+ "NIK" => "nik",
+ "Division" => "division_code",
+ "Branch Code" => "branch_code",
+ "Bank Info" => "banks_info",
+ "Language" => "language",
+ "Type of work" => "type_of_work",
+ "Race" => "race",
+ "Policy Number" => "policy_number",
+ "Marital Status" => "marital_status",
+ "Relationship" => "relationship_with_principal",
+ "Member's Effective Date" => "member_effective_date",
+ "Member's Expiry Date" => "member_expiry_date",
+ "Faskes FKTP (First Level Provider) or Individual preferred provider" => "faskes_fktp",
+ "Faskes FKRTL (Next Level Provider) or Individual group preferred provider" => "faskes_fkrtl",
+ "The Right Classes Room of BPJS Participants" => "bpjs_class",
+ "Name of Faskes" => "faskes_name",
+ "Rule_BPJSK ('Y' or 'N')" => "bpjsk",
+ "Agent Code / intermediary code" => "agent_code",
+ "Member Name" => "name",
+ "Address1" => "address1",
+ "Address2" => "address2",
+ "Address3" => "address3",
+ "Address4" => "address4",
+ "City" => "city",
+ "State" => "state",
+ "Post Code" => "post_code",
+ "Telephone – Mobile" => "telephone_mobile",
+ "Telephone – Res" => "telephone_res",
+ "Telephone – Office" => "telephone_office",
+ "NRIC" => "nric",
+ "Passport No" => "passport_number",
+ "Passport Country" => "passport_country",
+ "Email" => "email",
+ "Identification Code" => "identification_code",
+ "Date of Birth" => "date_of_birth",
+ "Sex" => "sex",
+ "Internal Use" => "internal_use",
+ "Plan-ID" => "plan_id",
+ "Employment-Status" => "employment_status",
+ "Internal Use" => "internal_use_1",
+ "Internal Use" => "internal_use_2",
+ "Internal Use" => "internal_use_3",
+ "Date Terminated" => "date_terminated",
+ "Pre Existing" => "pre_existing",
+ "BPJS ID" => "bpjs_id",
+ "Endorsement Date" => "endorsement_date",
+ "Remarks" => "remarks",
+ "Internal Use" => "internal_use_4",
+ "Member Since" => "member_since",
+ "Internal Use" => "internal_use_5",
+ "Policy In Force" => "policy_in_force",
+ "Member Suspended" => "member_suspended",
+ "Activation Date" => "activation_date",
+ "Internal Use" => "internal_use_6",
+ "StartNoClaim" => "start_no_claim",
+ "EndNoClaim" => "end_no_claim",
+ "Option Mode" => "option_mode",
+ ];
+
+ public function employeds()
+ {
+ return $this->hasMany(CorporateEmployee::class, 'member_id');
+ }
+
+ public function policies()
+ {
+ return $this->hasMany(MemberPolicy::class, 'member_id');
+ }
+
+ public function scopeFilter($query, array $filters)
+ {
+ $query->when($filters['search'] ?? false, function ($query, $search) {
+ return $query
+ ->where('member_id', 'like', "%" . $search . "%")
+ ->orWhere('payor_id', 'like', "%" . $search . "%")
+ ->orWhere('name', 'like', "%" . $search . "%")
+ ;
+ // ->orWhereHas('corporatePlan', function ($query) use ($search) {
+ // $query->where('code', 'like', "%" . $search . "%");
+ // });
+ });
+ }
}
diff --git a/app/Models/MemberPolicy.php b/app/Models/MemberPolicy.php
new file mode 100644
index 00000000..c4561dd1
--- /dev/null
+++ b/app/Models/MemberPolicy.php
@@ -0,0 +1,31 @@
+belongsTo(Policy::class, 'policy_id', 'policy_id');
+ }
+
+ public function member()
+ {
+ return $this->belongsTo(Member::class, 'member_id', 'member_id');
+ }
+}
diff --git a/database/migrations/2022_05_23_073350_create_members_table.php b/database/migrations/2022_05_23_073350_create_members_table.php
index 0224a4e6..0fbaa089 100644
--- a/database/migrations/2022_05_23_073350_create_members_table.php
+++ b/database/migrations/2022_05_23_073350_create_members_table.php
@@ -16,6 +16,8 @@ return new class extends Migration
Schema::create('members', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->nullable()->index();
+ $table->string('member_id')->nullable()->unique();
+ $table->string('payor_id')->nullable();
$table->string('name_prefix')->nullable();
$table->string('name');
$table->string('name_suffix')->nullable();
@@ -25,9 +27,10 @@ return new class extends Migration
$table->string('language')->nullable();
$table->string('race')->nullable();
$table->string('marital_status')->nullable();
- $table->foreignId('principle_id')->nullable()->index();
- $table->string('relation_with_principle')->nullable();
- $table->date('bpjs_class')->nullable();
+ $table->string('record_type', 1)->nullable();
+ $table->string('principal_id')->nullable()->index();
+ $table->string('relation_with_principal')->nullable();
+ $table->string('bpjs_class')->nullable();
$table->boolean('active')->default(true);
$table->timestamps();
diff --git a/database/migrations/2022_06_17_024432_create_corporate_employees_table.php b/database/migrations/2022_06_17_024432_create_corporate_employees_table.php
index 7ce9cf18..aa6b43a8 100644
--- a/database/migrations/2022_06_17_024432_create_corporate_employees_table.php
+++ b/database/migrations/2022_06_17_024432_create_corporate_employees_table.php
@@ -15,7 +15,19 @@ return new class extends Migration
{
Schema::create('corporate_employees', function (Blueprint $table) {
$table->id();
+ $table->foreignId('corporate_id')->index();
+ $table->foreignId('member_id')->index();
+ $table->string('branch_code')->nullable()->index();
+ $table->foreignId('division_id')->nullable()->index();
+ $table->string('nik')->nullable()->index();
+ $table->string('status')->nullable();
+
$table->timestamps();
+ $table->softDeletes();
+
+ $table->unsignedBigInteger('created_by')->nullable();
+ $table->unsignedBigInteger('updated_by')->nullable();
+ $table->unsignedBigInteger('deleted_by')->nullable();
});
}
diff --git a/database/migrations/2022_06_21_042321_create_corporate_policies_table.php b/database/migrations/2022_06_21_042321_create_corporate_policies_table.php
index de8d2aae..af7a9d23 100644
--- a/database/migrations/2022_06_21_042321_create_corporate_policies_table.php
+++ b/database/migrations/2022_06_21_042321_create_corporate_policies_table.php
@@ -16,7 +16,7 @@ return new class extends Migration
Schema::create('corporate_policies', function (Blueprint $table) {
$table->id();
$table->string('corporate_id');
- $table->string('code')->unique();
+ $table->string('policy_id')->unique();
$table->decimal('total_premi', 15, 2)->nullable();
$table->decimal('minimal_deposit_percentage', 15, 2)->nullable();
$table->decimal('minimal_deposit_net', 15, 2)->nullable();
diff --git a/database/migrations/2022_07_21_121346_create_member_policies_table.php b/database/migrations/2022_07_21_121346_create_member_policies_table.php
new file mode 100644
index 00000000..c2ef0b69
--- /dev/null
+++ b/database/migrations/2022_07_21_121346_create_member_policies_table.php
@@ -0,0 +1,44 @@
+id();
+ $table->string('policy_id');
+ $table->string('member_id');
+ $table->string('status')->default('active');
+ $table->dateTime('start')->nullable();
+ $table->dateTime('end')->nullalbe();
+
+ $table->timestamps();
+ $table->softDeletes();
+
+ $table->unsignedBigInteger('created_by')->nullable();
+ $table->unsignedBigInteger('updated_by')->nullable();
+ $table->unsignedBigInteger('deleted_by')->nullable();
+
+ $table->index(['policy_id', 'member_id']);
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('member_policies');
+ }
+};
diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php
index 71f673f0..a1df7280 100644
--- a/database/seeders/DatabaseSeeder.php
+++ b/database/seeders/DatabaseSeeder.php
@@ -15,5 +15,10 @@ class DatabaseSeeder extends Seeder
public function run()
{
// \App\Models\User::factory(10)->create();
+
+ $this->call([
+ DummyMemberSeeder::class,
+ DummyCorprateSeeder::class
+ ]);
}
}
diff --git a/database/seeders/DummyCorporateSeeder.php b/database/seeders/DummyCorporateSeeder.php
new file mode 100644
index 00000000..70ecbbac
--- /dev/null
+++ b/database/seeders/DummyCorporateSeeder.php
@@ -0,0 +1,49 @@
+ 'UNTR0001',
+ 'name' => 'United Tractor',
+ 'welcome_message' => 'Welcome to United Tractor',
+ 'help_text' => 'You can blah blah blah blah',
+ 'active' => true
+ ]);
+
+ $corporate->corporatePlans()->create([
+ 'code' => 'PLAN001',
+ 'name' => 'PLAN Name',
+ 'description' => 'Description of PLAN Name',
+ 'active' => true,
+ ]);
+
+ $corporate->corporateBenefits()->create([
+ 'code' => 'BENEFIT001',
+ 'name' => 'BENEFIT Name',
+ 'description' => 'Description of BENEFIT Name',
+ 'active' => true,
+ ]);
+
+ $corporate->corporateDivisions()->create([
+ 'code' => 'DIVISION001',
+ 'name' => 'DIVISION Name',
+ 'description' => 'Description of DIVISION Name',
+ 'active' => true,
+ ]);
+ }
+}
diff --git a/frontend/dashboard/src/@types/member.ts b/frontend/dashboard/src/@types/member.ts
index a141bb56..c38b0640 100644
--- a/frontend/dashboard/src/@types/member.ts
+++ b/frontend/dashboard/src/@types/member.ts
@@ -1,5 +1,21 @@
// ----------------------------------------------------------------------
export type Member = {
-
+ id: string,
+ member_id: string,
+ record_type: string,
+ payor_id: string,
+ user_id: string,
+ name_prefix: string,
+ name: string,
+ name_suffix: string,
+ birth_date: string,
+ gender: string,
+ language: string,
+ race: string,
+ marital_status: string,
+ principal_id: string,
+ relation_with_principal: string,
+ bpjs_class: string,
+ active: string,
};
diff --git a/frontend/dashboard/src/pages/Corporates/Member/Create.tsx b/frontend/dashboard/src/pages/Corporates/Member/Create.tsx
index c6a6250a..80c9b007 100644
--- a/frontend/dashboard/src/pages/Corporates/Member/Create.tsx
+++ b/frontend/dashboard/src/pages/Corporates/Member/Create.tsx
@@ -151,15 +151,15 @@ export default function PlanCreate() {
},
{
name: 'Corporate Name',
- href: '/corporates/'+id,
+ href: '/corporates/'+corporate_id,
},
{
name: 'Plans',
- href: '/corporates/'+id+'/plans',
+ href: '/corporates/'+corporate_id+'/plans',
},
{
name: 'Create',
- href: '/corporates/'+id+'/plans/create',
+ href: '/corporates/'+corporate_id+'/plans/create',
},
]}
/>
diff --git a/frontend/dashboard/src/pages/Corporates/Member/Index.tsx b/frontend/dashboard/src/pages/Corporates/Member/Index.tsx
index bd264631..1f3412ef 100644
--- a/frontend/dashboard/src/pages/Corporates/Member/Index.tsx
+++ b/frontend/dashboard/src/pages/Corporates/Member/Index.tsx
@@ -34,20 +34,10 @@ export default function Divisions() {
]}
/>
-
-
-
-
-
-
-
-
-
- Corporate Detail Goes Here
-
-
-
-
+
+
+
+
);
}
diff --git a/frontend/dashboard/src/pages/Corporates/Member/List.tsx b/frontend/dashboard/src/pages/Corporates/Member/List.tsx
index 223f9e31..1a8e8cd4 100644
--- a/frontend/dashboard/src/pages/Corporates/Member/List.tsx
+++ b/frontend/dashboard/src/pages/Corporates/Member/List.tsx
@@ -13,11 +13,13 @@ import { useParams, useSearchParams } from 'react-router-dom';
import axios from '../../../utils/axios';
import { Plan } from '../../../@types/corporates';
import { LaravelPaginatedData } from '../../../@types/paginated-data';
+import { Member } from '../../../@types/member';
export default function CorporatePlanList() {
const { themeStretch } = useSettings();
const { corporate_id } = useParams();
const [searchParams, setSearchParams] = useSearchParams();
+ const [importResult, setImportResult] = useState(null)
function SearchInput(props: any) {
// SEARCH
@@ -90,13 +92,16 @@ export default function CorporatePlanList() {
formData.append("file", importPlan.current?.files[0])
axios.post(`corporates/${corporate_id}/members/import`, formData )
.then(response => {
+ setImportResult(response.data)
handleCancelImportButton();
loadDataTableData();
- alert('Succesfully read '+ response.data.total_successed_row + ' with ' + response.data.total_failed_row + ' failed rows');
})
.catch(response => {
alert('Looks like something went wrong. Please check your data and try again. ' + response.message)
})
+ .then(x => {
+ console.log('motherfucker', importResult)
+ })
} else {
alert('No File Selected')
}
@@ -150,6 +155,11 @@ export default function CorporatePlanList() {
)}
+ {( importResult &&
+
+ Last Import Result : { importResult.total_success_row ?? 0 } Row Processed, { importResult.total_failed_row } Failed, Report : {importResult.result_file?.name ?? "-"}
+
+ )}
);
}
@@ -161,6 +171,20 @@ export default function CorporatePlanList() {
}
}
+ const [columns, setColumns] = React.useState([
+ { id: 'member_id', label: 'MemberID', minWidth: 100, align: "left" },
+ { id: 'principal_id', label: 'Mapping ID', minWidth: 100, align: "left" },
+ { id: 'nik', label: 'NIK', minWidth: 100, align: "left" },
+ { id: 'policy_number', label: 'Policy Number', minWidth: 100, align: "left" },
+ { id: 'effective_date', label: 'Effective Date', minWidth: 100, align: "left" },
+ { id: 'name', label: 'Name', minWidth: 100, align: "left" },
+ { id: 'nric', label: 'NRIC', minWidth: 100, align: "left" },
+ { id: 'email', label: 'E-mail', minWidth: 100, align: "left" },
+ { id: 'plan_id', label: 'PlanID', minWidth: 100, align: "left" },
+ { id: 'termination_date', label: 'Termination Date', minWidth: 100, align: 'right' },
+ { id: 'activation_date', label: 'Activation Date', minWidth: 100, align: "right" },
+ ]);
+
// Generate the every row of the table
function Row(props: { row: ReturnType }) {
const { row } = props;
@@ -178,54 +202,9 @@ export default function CorporatePlanList() {
{open ? : }
- {row.service_code}
- {row.corporate_plan?.code}
- {row.code}
- {row.type}
- {row.start}
- {row.end}
- {row.require_referral}
- {row.referral_source}
- {row.referral_duration}
- {row.family_plan}
- {row.family_plan_share_rules}
- {row.limit_rules}
- {row.layer}
- {row.layer_conditions}
- {row.budget_type}
- {row.budget_code}
- {row.budget_conditions}
- {row.surgery_limit}
- {row.non_surgery_limit}
- {row.max_claim_limit}
- {row.max_claim_count}
- {row.area_limit}
- {row.limit_shared_plans}
- {row.limit_shared_plan_type}
- {row.cashless_percentage}
- {row.reimbursement_percentage}
- {row.digital_percentage}
- {row.co_share_m_percentage}
- {row.co_share_s_percentage}
- {row.co_share_c_percentage}
- {row.cashless_deductible}
- {row.reimbursement_deductible}
- {row.digital_deductible}
- {row.co_share_m_deductible}
- {row.co_share_s_deductible}
- {row.co_share_c_deductible}
- {row.co_share_deductible_condition}
- {row.msc}
- {row.genders}
- {row.min_age}
- {row.max_age}
- {row.rule_of_excess}
- {row.max_excess_covered}
- {row.prorate_type}
- {row.prorate_lookup}
- {row.currency}
- {row.max_surgery_reinstatement_days}
- {row.max_surgery_periode_days}
+ { columns.map((column, index) =>
+ { row[column.id] ?? '-' }
+ ) }
Active
Edit
@@ -238,37 +217,7 @@ export default function CorporatePlanList() {
No Extra Data
- {false &&
-
- Rules
-
-
-
-
- Date
- Customer
- Amount
- Total price ($)
-
-
-
- {/* {row.history ? row.history.map((historyRow) => ( */}
-
- {row.start} - {row.end}
- {row.start}
- {row.start}
- {row.start}
-
- {/* ))
- : (
-
- No Data
-
- )
- } */}
-
-
- }
+ {false && }
@@ -296,7 +245,7 @@ export default function CorporatePlanList() {
const loadDataTableData = async (appliedFilter = null) => {
setDataTableLoading(true);
const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]);
- const response = await axios.get('/corporates/'+corporate_id+'/plans', { params: filter });
+ const response = await axios.get('/corporates/'+corporate_id+'/members', { params: filter });
// console.log(response.data);
setDataTableLoading(false);
@@ -327,54 +276,9 @@ export default function CorporatePlanList() {
- Service
- Plan
- Code
- Type
- Start
- End
- Referral
- Referral Source
- Referral Duration
- Family Plan
- Family Sharing Overflow
- Plan Limit
- Layer ID
- Layer Condition
- Budget Type
- Budget Code
- Budget Condition
- Surgery
- Non Surgery
- Max/Claim
- Max Count of Claim
- Area
- Shared Plan
- Limit Shared Type
- Cashless(%)
- Reimbursement(%)
- Digital(%)
- CoShare M(%)
- CoShare S(%)
- CoShare C(%)
- Cashless Deductible
- Reimbursement Deductible
- Digital Deductible
- DeductibleM
- DeductibleS
- DeductibleC
- CoShare & Deductible Condition
- MSC
- Gender
- Min Age
- Max Age
- Rule of Excess
- Max Excess Covered
- Prorate Type
- Prorate Lookup
- Currency
- Reinstatement Surgery
- Period of Surgery
+ { columns.map((column, index) => (
+ {column.label}
+ )) }
Status
Action
@@ -396,8 +300,8 @@ export default function CorporatePlanList() {
) : (
- {dataTableData.data.map(row => (
-
+ {dataTableData.data.map((row, index) => (
+
))}
)
diff --git a/lang/en/enrollment.php b/lang/en/enrollment.php
new file mode 100644
index 00000000..21fbc63e
--- /dev/null
+++ b/lang/en/enrollment.php
@@ -0,0 +1,56 @@
+ "Record mode must be filled",
+ "MODE_UNAVAILABLE" => "Record mode for member is not available",
+ "RECORD_TYPE_REQUIRED" => "Record Type must be filled for member (Member ID)",
+ "MEMBER_EXISTS" => "Member (:member_id) for policy (:policy_id) already exist in database",
+ "MEMBER_NOT_EXISTS" => "Member (Member ID) for policy (Policy No) not found",
+ "MEMBER_INACTIVE" => "Member (Member ID) for policy (Policy No) is inactive",
+ "MEMBER_NO_CHANGE" => "No changes in plan/ personal info found",
+ "MEMBER_EXPIRY_DATE_NO_CHANGE" => "No changes in member effective/ expiry date found",
+ "MEMBER_EXPIRY_DATE_INVALID" => "Member Effective Date must be before or equal to Member Expiry Date",
+ "MEMBER_RENEWAL_STILL_ACTIVE" => "Policy period is still active, please use mode 11/12/13",
+ "OPTION_MODE_INVALID_FORMAT" => "Option Mode must follow delimited format",
+ "UNIQUE_CHANGE_PRINCIPAL_INVALID" => "No changes in the following info found:
+ > Corporate Code (Field 7)
+ > Policy No (Field 15)
+ > Member ID (Field 4)
+ > Record Type (Field 2)",
+ "UNIQUE_CHANGE_DEPENDANT_INVALID" => "No changes in the following info found:
+ > Corporate Code (Field 7)
+ > Policy No (Field 15)
+ > Record Type (Field 2)
+ > Payor ID (Field 3)",
+ "MEMBER_EXPIRY_MUST_BE_AFTER_TODAY" => "Valid if Activation Date is later than member effective date, not empty and in YYYYMMDD format",
+ "PLAN_NOT_FOUND" => "Plan ID inactive / not found in the system",
+
+ "PAYOR_ID_REQUIRED" => "Payor ID must be filled for member (Member ID)",
+ "MEMBER_ID_REQUIRED" => "Member ID must be filled",
+ "PRINCIPAL_ID_NOT_REQUIRED" => "Mapping ID should only be filled for dependents",
+ "CORPORATE_ID_REQUIRED" => "Corporate ID must be filled",
+ "PRINCIPAL_ID_REQUIRED" => "Mapping ID must be filled",
+ "BRANCH_CODE_NOT_REQUIRED" => "Dependents don't need to fill in Branch Code ",
+ "INVALID_LANGUAGE" => "Language (field 12) is invalid",
+ "INVALID_TYPE_OF_WORK" => "Type of work (field 13) is invalid",
+ "INVALID_RACE" => "Race (field 14) is invalid",
+ "POLICY_NUMBER_REQUIRED" => "Policy Number must be filled for member (Member ID)",
+ "MEMBER_EFFECTIVE_REQUIRED" => "Member's Effective Date must be filled for member (Member ID)",
+ "MEMBER_EXPIRY_REQUIRED" => "Member's Expiry Date must be filled for member (Member ID)",
+ "INVALID_MARITAL_STATUS" => "Marital Status (field 16) is invalid",
+ "NAME_REQUIRED" => "Member Name must be filled",
+ "PHONE_INVALID" => "Telephone - Mobile must follow +628 format",
+ "EMAIL_INVALID" => "Email must folllow email format e.g. xx@gmail.com",
+ "DATE_OF_BIRTH_REQUIRED" => "Date of Birth must be filled",
+ "SEX_REQUIRED" => "Sex must be filled",
+
+];