'Recipient email address (required)', '--premium-summary' => 'is_premium_summery value: 0=hide, 1=full columns, 2=Policy Name/Total only (default: 2)', '--type' => 'Sample data type: full|topup|parents|base|payable|simple (default: full)', '--client-id' => 'Client ID (optional; auto-picks a client with enabled template)', '--dry-run' => 'Build mail and save HTML under writable/tmp; do not send', ]; public function run(array $params) { $mail = $this->optionValue('mail', $params[0] ?? null); if (empty($mail) || ! filter_var($mail, FILTER_VALIDATE_EMAIL)) { CLI::error('Provide a valid --mail you@example.com'); CLI::write($this->usage, 'yellow'); return; } $premiumSummary = (int) ($this->optionValue('premium-summary', 2)); if (! in_array($premiumSummary, [0, 1, 2], true)) { CLI::error('--premium-summary must be 0, 1, or 2'); return; } $type = strtolower((string) ($this->optionValue('type', 'full'))); if (! in_array($type, ['full', 'topup', 'parents', 'base', 'payable', 'simple'], true)) { CLI::error('--type must be one of: full, topup, parents, base, payable, simple'); return; } $clientId = $this->optionValue('client-id'); $dryRun = CLI::getOption('dry-run') !== null || $this->hasFlag('dry-run'); $clientModel = new ClientModel(); $clientPolicyModel = new ClientPolicyModel(); $notificationModel = new NotificationModel(); $client = $this->resolveClient($clientModel, $notificationModel, $clientId); if ($client === null) { return; } $notification = $notificationModel ->where('client_id', $client['id']) ->where('template_name', 'member_review_and_summary_mail') ->first(); if (empty($notification)) { CLI::error("No member_review_and_summary_mail template for client #{$client['id']}"); return; } $wasEnabled = (int) ($notification['enabled'] ?? 0); if ($wasEnabled !== 1) { CLI::write('Template is disabled; temporarily enabling for this test...', 'yellow'); $notificationModel->update($notification['id'], ['enabled' => 1]); $notification['enabled'] = 1; } $policies = $this->resolvePolicies($clientPolicyModel, (int) $client['id'], $type); if ($policies === null) { if ($wasEnabled !== 1) { $notificationModel->update($notification['id'], ['enabled' => $wasEnabled]); } return; } $originalPremiumSummary = []; foreach ($policies as $key => $policy) { $originalPremiumSummary[$policy['id']] = $policy['is_premium_summery'] ?? 0; $clientPolicyModel->update($policy['id'], ['is_premium_summery' => $premiumSummary]); $policies[$key]['is_premium_summery'] = $premiumSummary; } try { $arrayList = $this->buildSampleArrayList($type, $policies, $mail); CLI::write('Test config:', 'yellow'); CLI::write(" client_id : {$client['id']} ({$client['client_name']})"); CLI::write(" recipient : {$mail}"); CLI::write(" premium-summary : {$premiumSummary} " . $this->premiumSummaryLabel($premiumSummary)); CLI::write(" sample type : {$type}"); CLI::write(' policy group(s) : ' . count($arrayList)); foreach ($policies as $label => $policy) { CLI::write(" [{$label}] id={$policy['id']} type={$policy['policy_type_id']} is_addon={$policy['is_addon']}"); } $paramsMail = [ 'array_list' => $arrayList, 'client_policy_id' => array_column($policies, 'id'), 'emp_code' => 'TEST001', 'client_id' => $client['id'], 'notification' => $notification, 'common' => [ 'client_id' => $client['id'], 'client_branch_id' => null, 'client_policy_id' => null, 'employee_policy_id' => null, 'employee_id' => null, 'mail_type' => 'member_review_and_summary_mail', ], ]; $wholeData = sendMailNotification::sendMailNotification('member_review_and_summary_mail', $paramsMail); if (empty($wholeData[0]['message'] ?? null)) { CLI::error('Mail payload was empty. Check that the notification template is enabled and sample data is valid.'); return; } // Force recipient to the provided test mail $wholeData[0]['mail'] = $mail; $wholeData[0]['bcc'] = ''; $htmlPath = WRITEPATH . 'tmp/member_review_summary_' . $premiumSummary . '_' . $type . '_' . date('Ymd_His') . '.html'; if (! is_dir(WRITEPATH . 'tmp')) { mkdir(WRITEPATH . 'tmp', 0775, true); } file_put_contents($htmlPath, $wholeData[0]['message']); CLI::write("Saved preview HTML: {$htmlPath}", 'green'); if ($dryRun) { CLI::write('Dry-run only — email was not sent.', 'yellow'); CLI::write('Subject: ' . ($wholeData[0]['subject'] ?? ''), 'white'); return; } $result = MailHelper::send_email($wholeData[0]); CLI::write('Send result:', 'yellow'); CLI::write(is_string($result) ? $result : json_encode($result)); CLI::write("Mail sent to {$mail}", 'green'); } finally { foreach ($originalPremiumSummary as $policyId => $originalValue) { $clientPolicyModel->update($policyId, ['is_premium_summery' => $originalValue]); } if ($wasEnabled !== 1) { $notificationModel->update($notification['id'], ['enabled' => $wasEnabled]); } CLI::write('Restored original is_premium_summery / notification enabled flags.', 'white'); } } private function premiumSummaryLabel(int $value): string { return match ($value) { 0 => '(hide premium summary)', 1 => '(full Premium/GST columns + summary)', 2 => '(hide columns; summary Policy Name/Total only)', default => '', }; } private function resolveClient(ClientModel $clientModel, NotificationModel $notificationModel, $clientId): ?array { if (! empty($clientId)) { $client = $clientModel->where('id', (int) $clientId)->where('is_active', 1)->first(); if (empty($client)) { CLI::error("Client #{$clientId} not found or inactive"); return null; } return $client; } $notification = $notificationModel ->where('template_name', 'member_review_and_summary_mail') ->where('enabled', 1) ->where('client_id >', 0) ->orderBy('id', 'DESC') ->first(); if (empty($notification['client_id'])) { // Fallback: any template row with client_id $notification = $notificationModel ->where('template_name', 'member_review_and_summary_mail') ->where('client_id >', 0) ->orderBy('id', 'DESC') ->first(); } if (empty($notification['client_id'])) { CLI::error('No client found with member_review_and_summary_mail template. Pass --client-id=ID'); return null; } $client = $clientModel->where('id', $notification['client_id'])->where('is_active', 1)->first(); if (empty($client)) { CLI::error('Resolved client is missing/inactive. Pass --client-id=ID'); return null; } return $client; } /** * @return array|null */ private function resolvePolicies(ClientPolicyModel $clientPolicyModel, int $clientId, string $type): ?array { $policies = $clientPolicyModel ->where('client_id', $clientId) ->where('is_active', 1) ->findAll() ?? []; if (empty($policies)) { CLI::error("No active client_policy rows for client #{$clientId}"); return null; } $withPremium = []; foreach ($policies as $policy) { if ($this->hasPremiumConfig($policy)) { $withPremium[] = $policy; } } if (empty($withPremium)) { CLI::error("No client_policy with active premium config for client #{$clientId}"); return null; } $pick = static function (array $list, ?callable $pref = null) { if ($pref !== null) { foreach ($list as $row) { if ($pref($row)) { return $row; } } } return $list[0]; }; $result = []; if (in_array($type, ['full', 'base', 'topup', 'parents', 'simple'], true)) { $result['main'] = $pick($withPremium, static function ($p) { return in_array((int) ($p['is_addon'] ?? 0), [2, 3], true) || in_array((int) ($p['policy_type_id'] ?? 0), [1, 2, 3, 6, 7], true); }); } if (in_array($type, ['full', 'payable'], true)) { $payable = $pick($withPremium, static function ($p) { return (int) ($p['policy_type_id'] ?? 0) === 2; }); if ((int) ($payable['policy_type_id'] ?? 0) !== 2) { CLI::write('Warning: no policy_type_id=2 found; payable sample will use main policy and may skip payable table.', 'yellow'); } $result['payable'] = $payable; } if ($type === 'payable' && empty($result['payable'])) { CLI::error('Could not resolve a policy for payable sample type'); return null; } if ($type !== 'payable' && empty($result['main'])) { CLI::error('Could not resolve a policy for sample type'); return null; } // Deduplicate by id while keeping labels $unique = []; foreach ($result as $label => $policy) { $unique[$label] = $policy; } return $unique; } private function hasPremiumConfig(array $policy): bool { $policyId = (int) $policy['id']; $typeId = (int) ($policy['policy_type_id'] ?? 0); if (in_array($typeId, [1, 6, 7], true)) { $row = (new PolicyPremium1Model()) ->where('client_policy_id', $policyId) ->where('is_active', '1') ->first(); } else { $row = (new PolicyPremium2Model()) ->where('client_policy_id', $policyId) ->where('is_active', '1') ->first(); } return ! empty($row); } /** * Build array_list shaped like getEmpFamilybyEmpCode() groups. * * @param array $policies */ private function buildSampleArrayList(string $type, array $policies, string $mail): array { $list = []; if (isset($policies['main']) && in_array($type, ['full', 'base'], true)) { $p = $policies['main']; $list[] = [ $this->memberRow($p, 'Self', 'Ravi Kumar', $mail, 500000, 0, 0, 1, 0), $this->memberRow($p, 'Spouse', 'Anita Kumar', '', 0, 0, 0, 1, 0), $this->memberRow($p, 'Child', 'Arjun Kumar', '', 0, 0, 0, 1, 0), ]; } // Single-policy layout matching UI mock: Health Insurance Plan + Premium/GST + summary if (isset($policies['main']) && $type === 'simple') { $p = $policies['main']; $list[] = [ $this->memberRow( $p, 'Self', 'John Doe', $mail, 500000, 12000, 2160, 2, 0, 'Health Insurance Plan', 'E12345' ), ]; } if (isset($policies['main']) && in_array($type, ['full', 'topup'], true)) { $p = $policies['main']; $list[] = [ $this->memberRow($p, 'Self', 'Ravi Kumar', $mail, 300000, 4500, 810, 2, 0, 'SI Top-up Cover'), $this->memberRow($p, 'Spouse', 'Anita Kumar', '', 300000, 3200, 576, 2, 0, 'SI Top-up Cover'), ]; } if (isset($policies['main']) && in_array($type, ['full', 'parents'], true)) { $p = $policies['main']; $list[] = [ $this->memberRow($p, 'Self', 'Ravi Kumar', $mail, 200000, 0, 0, 3, 0, 'Parent Medical Cover'), $this->memberRow($p, 'Father', 'Suresh Kumar', '', 200000, 6000, 1080, 3, 0, 'Parent Medical Cover'), $this->memberRow($p, 'Mother', 'Lakshmi Kumar', '', 200000, 5500, 990, 3, 0, 'Parent Medical Cover'), ]; } if (isset($policies['payable']) && in_array($type, ['full', 'payable'], true)) { $p = $policies['payable']; $list[] = [ $this->memberRow($p, 'Self', 'Ravi Kumar', $mail, 400000, 2800, 504, 1, 1, 'Voluntary Top-up'), $this->memberRow($p, 'Spouse', 'Anita Kumar', '', 400000, 2100, 378, 1, 1, 'Voluntary Top-up'), ]; } return $list; } private function memberRow( array $policy, string $relationship, string $name, string $email, float $si, float $premium, float $gst, int $isAddon, int $payableEmployee, ?string $policyName = null, string $empCode = 'TEST001' ): array { $dobOffsets = [ 'Self' => '-38 years', 'Spouse' => '-35 years', 'Child' => '-10 years', 'Father' => '-65 years', 'Mother' => '-62 years', ]; // Match mock DOB for simple Health Insurance Plan sample $dob = ($name === 'John Doe' && $empCode === 'E12345') ? '1985-05-15' : date('Y-m-d', strtotime($dobOffsets[$relationship] ?? '-30 years')); return [ 'emp_id' => 90001, 'client_id' => $policy['client_id'], 'client_branch_id' => null, 'relationship' => $relationship, 'emp_code' => $empCode, 'name' => $name, 'email_corporate' => $email, 'mobile' => '9876543210', 'dob' => $dob, 'client_policy_id' => $policy['id'], 'basic_cover_si' => $si, 'premium' => $premium, 'rata_premimum' => $premium, 'gst' => $gst, 'policy_name' => $policyName ?? ('Sample Policy #' . $policy['id']), 'is_addon' => $isAddon, 'payable_employee' => $payableEmployee, ]; } /** * Read CLI option from CI helper or raw argv (--key=value / --key value). */ private function optionValue(string $name, $default = null) { $fromCli = CLI::getOption($name); if ($fromCli !== null && $fromCli !== false && $fromCli !== '') { return $fromCli; } $argv = $_SERVER['argv'] ?? []; foreach ($argv as $i => $arg) { if ($arg === '--' . $name && isset($argv[$i + 1]) && strpos((string) $argv[$i + 1], '-') !== 0) { return $argv[$i + 1]; } if (strpos((string) $arg, '--' . $name . '=') === 0) { return substr((string) $arg, strlen($name) + 3); } } return $default; } private function hasFlag(string $name): bool { if (CLI::getOption($name) !== null) { return true; } $argv = $_SERVER['argv'] ?? []; foreach ($argv as $arg) { if ($arg === '--' . $name || strpos((string) $arg, '--' . $name . '=') === 0) { return true; } } return false; } }