diff --git a/Modules/Internal/Http/Controllers/Api/MemberController.php b/Modules/Internal/Http/Controllers/Api/MemberController.php index e3d7bb93..bd912037 100644 --- a/Modules/Internal/Http/Controllers/Api/MemberController.php +++ b/Modules/Internal/Http/Controllers/Api/MemberController.php @@ -123,11 +123,10 @@ class MemberController extends Controller $writer = WriterEntityFactory::createXLSXWriter(); $writer->openToFile(Storage::disk('public')->path('temp/result-'.$file_name)); - $headers_map_to_table_fields = Member::$doc_headers_to_field_map; + $headers_map_to_table_fields = $this->memberEnrollmentService->doc_headers_to_field_map; - // Write Header to File - $result_headers = array_keys($headers_map_to_table_fields); - array_push($result_headers, 'Ingestion Status'); + // Write Header to File with certain Format from MemberEnrollmentService::$result_doc_headers + $result_headers = $this->memberEnrollmentService->result_doc_headers; $singleRow = WriterEntityFactory::createRow($this->memberEnrollmentService->makeResultRow($result_headers)); $writer->addRow($singleRow); @@ -147,6 +146,7 @@ class MemberController extends Controller $doc_headers_indexes[$index] = $title; } } else { // Next Row Should be Data + // Collecting Values from table rows and map it to correct fields $new_member_data = []; foreach ($row->getCells() as $header_index => $cell) { if (isset($headers_map_to_table_fields[$doc_headers_indexes[$header_index]])) { @@ -155,23 +155,29 @@ class MemberController extends Controller } try { + // dd($new_member_data); $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)); + $singleRow = WriterEntityFactory::createRow($this->memberEnrollmentService->makeResultRowWithResultFormat($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)); + $new_member_data = array_merge($new_member_data, [ + 'ingestion_code' => $e->getCode(), + 'ingestion_status' => $e->getMessage(), + ]); + $singleRow = WriterEntityFactory::createRow($this->memberEnrollmentService->makeResultRowWithResultFormat($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)); + $new_member_data = array_merge($new_member_data, [ + 'ingestion_code' => $e->getCode(), + 'ingestion_status' => $e->getMessage(), + ]); + $singleRow = WriterEntityFactory::createRow($this->memberEnrollmentService->makeResultRowWithResultFormat($new_member_data)); $writer->addRow($singleRow); $failed_member_data[] = ['row_number' => $index, 'error' => $e->getMessage()]; } diff --git a/Modules/Internal/Services/MemberEnrollmentService.php b/Modules/Internal/Services/MemberEnrollmentService.php index 1bd36957..ebd1dcf0 100644 --- a/Modules/Internal/Services/MemberEnrollmentService.php +++ b/Modules/Internal/Services/MemberEnrollmentService.php @@ -17,6 +17,230 @@ use DB; class MemberEnrollmentService { + public $doc_headers_to_field_map = [ + "Record Mode" => "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", + "Policy No." => "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", + "Address 1" => "address1", + "Address2" => "address2", + "Address3" => "address3", + "Address4" => "address4", + "City" => "city", + "State" => "state", + "Post Code" => "post_code", + "Telephone - Mobile" => "telephone_mobile", + "Telephone – Mobile" => "telephone_mobile", + "Telephone - mobile" => "telephone_mobile", + "Telephone – Res" => "telephone_res", + "Telephone Res" => "telephone_res", + "Telephone - Res" => "telephone_res", + "Telephone – Office" => "telephone_office", + "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", + "Policy Inforce" => "policy_inforce", + "Renewal activation date" => "renewal_activation_date", + "Renewal Activation Date" => "renewal_activation_date", + "Ingestion Code" => "ingestion_code", // TODO I think this should not be here because if user uploading result then ingestion code and status will be filled + "Ingestion Status" => "ingestion_status", + ]; + + public $field_to_doc_headers_map = [ + "record_mode" => "Record Mode", + "record_type" => "Record Type", + "payor_id" => "Payor ID", + "member_id" => "Member ID", + "principal_id" => "Mapping ID", + "halodoc_member_id" => "Halodoc Member ID", + "corporate_id" => "Corporate ID", + "nik" => "NIK", + "division_code" => "Division", + "branch_code" => "Branch Code", + "banks_info" => "Bank Info", + "language" => "Language", + "type_of_work" => "Type of work", + "race" => "Race", + "policy_number" => "Policy Number", + "policy_number" => "Policy No.", + "marital_status" => "Marital Status", + "relationship_with_principal" => "Relationship", + "member_effective_date" => "Member's Effective Date", + "member_expiry_date" => "Member's Expiry Date", + "faskes_fktp" => "Faskes FKTP (First Level Provider) or Individual preferred provider", + "faskes_fkrtl" => "Faskes FKRTL (Next Level Provider) or Individual group preferred provider", + "bpjs_class" => "The Right Classes Room of BPJS Participants", + "faskes_name" => "Name of Faskes", + "bpjsk" => "Rule_BPJSK ('Y' or 'N')", + "agent_code" => "Agent Code / intermediary code", + "name" => "Member Name", + "address1" => "Address1", + "address1" => "Address 1", + "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_number" => "Passport No", + "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_1" => "Internal Use", + "internal_use_2" => "Internal Use", + "internal_use_3" => "Internal Use", + "date_terminated" => "Date Terminated", + "pre_existing" => "Pre Existing", + "bpjs_id" => "BPJS ID", + "endorsement_date" => "Endorsement Date", + "remarks" => "Remarks", + "internal_use_4" => "Internal Use", + "member_since" => "Member Since", + "internal_use_5" => "Internal Use", + "policy_in_force" => "Policy In Force", + "member_suspended" => "Member Suspended", + "activation_date" => "Activation Date", + "internal_use_6" => "Internal Use", + "start_no_claim" => "StartNoClaim", + "end_no_claim" => "EndNoClaim", + "option_mode" => "Option Mode", + "policy_inforce" => "Policy Inforce", + "renewal_activation_date" => "Renewal Activation Date", + "ingestion_code" => "Ingestion Code", + "ingestion_status" => "Ingestion Status", + ]; + public $result_doc_headers = [ + "Record Mode", + "Record Type", + "Payor ID", + "Member ID", + "Mapping ID", + "Halodoc Member ID", + "Corporate ID", + "NIK", + "Division", + "Branch Code", + "Bank Info", + "Language", + "Type of work", + "Race", + "Policy Number", + "Policy No.", + "Marital Status", + "Relationship", + "Member's Effective Date", + "Member's Expiry Date", + "Faskes FKTP (First Level Provider) or Individual preferred provider", + "Faskes FKRTL (Next Level Provider) or Individual group preferred provider", + "The Right Classes Room of BPJS Participants", + "Name of Faskes", + "Rule_BPJSK ('Y' or 'N')", + "Agent Code / intermediary code", + "Member Name", + "Address1", + "Address 1", + "Address2", + "Address3", + "Address4", + "City", + "State", + "Post Code", + "Telephone - Mobile", + "Telephone - Res", + "Telephone - Office", + "NRIC", + "Passport No", + "Passport Country", + "Email", + "Identification Code", + "Date of Birth", + "Sex", + "Internal Use", + "Plan-ID", + "Employment-Status", + "Internal Use", + "Internal Use", + "Internal Use", + "Date Terminated", + "Pre Existing", + "BPJS ID", + "Endorsement Date", + "Remarks", + "Internal Use", + "Member Since", + "Internal Use", + "Policy In Force", + "Member Suspended", + "Activation Date", + "Internal Use", + "StartNoClaim", + "EndNoClaim", + "Option Mode", + "Policy Inforce", + "Renewal Activation Date", + "Ingestion Code", + "Ingestion Status", + ]; + public function __construct(Member $member) { $this->member = $member; @@ -102,9 +326,9 @@ class MemberEnrollmentService 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') { + && !(substr($row['telephone_mobile'], 0, 4) == '+628' || substr($row['telephone_mobile'], 0, 3) == '628')) { throw new ImportRowException(__('enrollment.PHONE_INVALID'), 0, null, $row); } @@ -121,50 +345,46 @@ class MemberEnrollmentService 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'], + "name" => $row['name'] ?? null, + "member_id" => $row['member_id'] ?? null, + "payor_id" => $row['payor_id'] ?? null, + "nik" => $row['nik'] ?? null, "birth_date" => Carbon::parse(strtotime($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'], - "nric" => $row['nric'], - "email" => $row['email'], - "bank_info" => $row['banks_info'], - "agent_code" => $row['agent_code'], - "address1" => $row['address1'], - "address2" => $row['address2'], - "address3" => $row['address3'], - "address4" => $row['address4'], - "city" => $row['city'], - "state" => $row['state'], - "postal_code" => $row['post_code'], - "passport_no" => $row['passport_number'], - "passport_country" => $row['passport_country'], - "identification_code" => $row['identification_code'], - "pre_existing" => $row['pre_existing'], - "bpjs_id" => $row['bpjs_id'], - "endorsement_date" => $row['endorsement_date'], - "remarks" => $row['remarks'], - "policy_in_force" => $row['policy_in_force'], - "start_no_claim" => $row['start_no_claim'], - "end_no_claim" => $row['end_no_claim'], + "language" => $row['language'] ?? null, + "race" => $row['race'] ?? null, + "marital_status" => $row['marital_status'] ?? null, + "record_type" => $row['record_type'] ?? null, + "principal_id" => $row['principal_id'] ?? null, + "relation_with_principal" => $row['relationship_with_principal'] ?? null, + "bpjs_class" => $row['bpjs_class'] ?? null, + "nric" => $row['nric'] ?? null, + "email" => $row['email'] ?? null, + "bank_info" => $row['banks_info'] ?? null, + "agent_code" => $row['agent_code'] ?? null, + "address1" => $row['address1'] ?? null, + "address2" => $row['address2'] ?? null, + "address3" => $row['address3'] ?? null, + "address4" => $row['address4'] ?? null, + "city" => $row['city'] ?? null, + "state" => $row['state'] ?? null, + "postal_code" => $row['post_code'] ?? null, + "passport_no" => $row['passport_number'] ?? null, + "passport_country" => $row['passport_country'] ?? null, + "identification_code" => $row['identification_code'] ?? null, + "pre_existing" => $row['pre_existing'] ?? null, + "bpjs_id" => $row['bpjs_id'] ?? null, + "endorsement_date" => $row['endorsement_date'] ?? null, + "remarks" => $row['remarks'] ?? null, + "policy_in_force" => $row['policy_in_force'] ?? null, + "start_no_claim" => $row['start_no_claim'] ?? null, + "end_no_claim" => $row['end_no_claim'] ?? null, ]; if (!isset($corporate->currentPolicy) || $corporate->currentPolicy->code != $row['policy_number']) { @@ -261,8 +481,8 @@ class MemberEnrollmentService if (!$memberPolicy->member->isDirty()) { throw new ImportRowException(__('enrollment.MEMBER_NO_CHANGE'), 0, null, $row); } - - return $memberPolicy->member->save(); + + $memberPolicy->member->save(); break; case "3": // Member Deletion @@ -288,7 +508,7 @@ class MemberEnrollmentService $member = $memberPolicy->member; $member->active = false; - return $member->save(); + $member->save(); break; case "4": // Member Update Start and End Date $memberPolicy = MemberPolicy::query() @@ -323,7 +543,7 @@ class MemberEnrollmentService throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_INVALID'), 0, null, $row); } - return $memberPolicy->save(); + $memberPolicy->save(); break; case "5": // Member Renewal Policy (without card) @@ -364,7 +584,8 @@ class MemberEnrollmentService throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_NO_CHANGE'), 0, null, $row); } - return $memberPolicy->save(); + $memberPolicy->save(); + break; case "6": // Member Renewal Policy (with card) $memberPolicy = MemberPolicy::query() @@ -404,7 +625,8 @@ class MemberEnrollmentService throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_NO_CHANGE'), 0, null, $row); } - return $memberPolicy->save(); + $memberPolicy->save(); + break; case "7": // Requesting to Change the Unique Data of the Member $memberPolicy = MemberPolicy::query() @@ -492,7 +714,7 @@ class MemberEnrollmentService 'end' => $row['member_expiry_date'] ]); - return $memberPolicy->save(); + $memberPolicy->save(); break; // case "10": // No Information Available @@ -555,10 +777,31 @@ class MemberEnrollmentService throw new ImportRowException(__("enrollment.MODE_UNAVAILABLE"), 0, null, $row); } } catch (\Exception $e) { + // dd($row, $e->getMessage()); throw new ImportRowException($e->getMessage(), (int) $e->getCode(), $e, $row); } + + // Should be success then returning new member data with extra ingestion code & status + $member_data['ingestion_code'] = "200"; + $member_data['ingestion_status'] = "SUCCESS"; + + return $member_data; } + + // This returning row with format or order following $result_doc_headers + public function makeResultRowWithResultFormat($row_data) + { + $cells = []; + foreach ($this->result_doc_headers as $header) { + $value = $row_data[$this->doc_headers_to_field_map[$header]] ?? null; + $cells[] = WriterEntityFactory::createCell($value); + } + + return $cells; + } + + // This returning row with format or order as it is public function makeResultRow($row_data) { $cells = []; diff --git a/app/Models/Member.php b/app/Models/Member.php index e42390a2..f938c85a 100644 --- a/app/Models/Member.php +++ b/app/Models/Member.php @@ -56,73 +56,6 @@ class Member extends Model "end_no_claim", ]; - public static $doc_headers_to_field_map = [ - "Record Mode" => "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'); diff --git a/frontend/dashboard/.eslintrc b/frontend/dashboard/.eslintrc index fdc41fd7..0ddcccd0 100644 --- a/frontend/dashboard/.eslintrc +++ b/frontend/dashboard/.eslintrc @@ -17,7 +17,8 @@ "settings": { "import/resolver": { "typescript": { - "alwaysTryTypes": true + "alwaysTryTypes": true, + "exceptAfterSingleLine": true } } }, diff --git a/frontend/dashboard/src/pages/Corporates/Member/List.tsx b/frontend/dashboard/src/pages/Corporates/Member/List.tsx index b45b896f..ba1ad6d8 100644 --- a/frontend/dashboard/src/pages/Corporates/Member/List.tsx +++ b/frontend/dashboard/src/pages/Corporates/Member/List.tsx @@ -262,14 +262,14 @@ export default function CorporatePlanList() { {row.member_id} {row.principal_id} {row.employeds[0]?.nik} - {row.current_policy.policy_id} - {row.current_policy.start} + {row.current_policy?.policy_id} + {row.current_policy?.start} {row.name} {row.nric} {row.email} {row.plan_id} - {row.current_policy.start} - {row.current_policy.end} + {row.current_policy?.start} + {row.current_policy?.end} {( row.active ? () : () )}