nhance/app/Config/PtRenewalReminderConfig.php

322 lines
9.7 KiB
PHP

<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
use Config\Database;
class PtRenewalReminderConfig extends BaseConfig
{
public bool $enabled = false;
public bool $daily = false;
/** @var string[] Lowercase three-letter day abbreviations, e.g. mon, tue */
public array $days = [];
/** @var int[] Client type ids: 1=Group, 2=Individual */
public array $clientTypes = [];
/** Whitelisted: renewal_date | policy_end_date */
public string $dateField = 'renewal_date';
public int $daysBefore = 30;
public bool $includeClientEmail = false;
/** When true, also include policies whose dateField is already past */
public bool $includeOverdue = false;
/** @var string[] */
public array $toEmails = [];
/** @var string[] */
public array $ccEmails = [];
/** @var string[] */
public array $bccEmails = [];
public string $fromMail = '';
/** Loaded from notifications.subject when present */
public string $mailSubject = '';
/** Loaded from notifications.mail_content when present */
public string $mailContent = '';
public ?int $notificationId = null;
private const ALLOWED_DATE_FIELDS = ['renewal_date', 'policy_end_date'];
public const TEMPLATE_NAME = 'retail_reminder_mail';
public function __construct()
{
parent::__construct();
// Env defaults (seed / fallback)
$defaults = [
'enabled' => env('pt.renewalReminder.enabled', 'true'),
'daily' => env('pt.renewalReminder.daily', 'true'),
'days' => env('pt.renewalReminder.days', 'mon,tue,wed,thu,fri'),
'clientTypes' => env('pt.renewalReminder.clientTypes', '2'),
'dateField' => env('pt.renewalReminder.dateField', 'renewal_date'),
'daysBefore' => env('pt.renewalReminder.daysBefore', 30),
'includeClientEmail' => env('pt.renewalReminder.includeClientEmail', 'true'),
'includeOverdue' => env('pt.renewalReminder.includeOverdue', 'false'),
'toEmails' => env('pt.renewalReminder.toEmails', ''),
'ccEmails' => env('pt.renewalReminder.ccEmails', ''),
'bccEmails' => env('pt.renewalReminder.bccEmails', ''),
'fromMail' => env('pt.renewalReminder.fromMail', ''),
];
$dbConfig = $this->loadConfigFromNotification();
$merged = array_merge($defaults, $dbConfig);
$this->applyMergedConfig($merged);
}
/**
* @return array<string, mixed>
*/
private function loadConfigFromNotification(): array
{
try {
$db = Database::connect();
$row = $db->table('notifications')
->where('template_name', self::TEMPLATE_NAME)
->groupStart()
->where('client_id', null)
->orWhere('client_id', 0)
->orWhere('client_id', '')
->groupEnd()
->orderBy('id', 'DESC')
->get()
->getRowArray();
if (empty($row)) {
log_message('error', '[PtRenewalReminderConfig] No notifications row for retail_reminder_mail; using env defaults');
return [];
}
$this->notificationId = isset($row['id']) ? (int) $row['id'] : null;
$this->mailSubject = trim((string) ($row['subject'] ?? ''));
$this->mailContent = (string) ($row['mail_content'] ?? '');
$json = trim((string) ($row['config_json'] ?? ''));
if ($json === '') {
log_message('error', '[PtRenewalReminderConfig] config_json empty for notification_id=' . ($this->notificationId ?? 'n/a'));
return [];
}
$decoded = json_decode($json, true);
if (! is_array($decoded)) {
log_message('error', '[PtRenewalReminderConfig] Invalid config_json for notification_id=' . ($this->notificationId ?? 'n/a'));
return [];
}
return $decoded;
} catch (\Throwable $e) {
log_message(
'error',
'[PtRenewalReminderConfig] Failed loading notification config: ' . $e->getMessage()
);
return [];
}
}
/**
* @param array<string, mixed> $merged
*/
private function applyMergedConfig(array $merged): void
{
$this->enabled = $this->toBool($merged['enabled'] ?? false);
$this->daily = $this->toBool($merged['daily'] ?? false);
$daysRaw = $merged['days'] ?? 'mon,tue,wed,thu,fri';
if (is_array($daysRaw)) {
$daysRaw = implode(',', $daysRaw);
}
$this->days = array_values(array_filter(array_map(
static fn (string $day): string => strtolower(substr(trim($day), 0, 3)),
explode(',', (string) $daysRaw)
)));
$clientTypesRaw = $merged['clientTypes'] ?? '2';
if (is_array($clientTypesRaw)) {
$this->clientTypes = array_values(array_unique(array_filter(array_map(
static fn ($type): int => (int) $type,
$clientTypesRaw
), static fn (int $type): bool => $type > 0)));
} else {
$this->clientTypes = array_values(array_unique(array_filter(array_map(
static fn (string $type): int => (int) trim($type),
explode(',', (string) $clientTypesRaw)
), static fn (int $type): bool => $type > 0)));
}
$dateField = strtolower(trim((string) ($merged['dateField'] ?? 'renewal_date')));
if (! in_array($dateField, self::ALLOWED_DATE_FIELDS, true)) {
log_message(
'error',
'[PtRenewalReminderConfig] Invalid dateField "' . $dateField . '", falling back to renewal_date'
);
$dateField = 'renewal_date';
}
$this->dateField = $dateField;
$this->daysBefore = max(0, (int) ($merged['daysBefore'] ?? 30));
$this->includeClientEmail = $this->toBool($merged['includeClientEmail'] ?? true);
$this->includeOverdue = $this->toBool($merged['includeOverdue'] ?? false);
$this->toEmails = $this->parseEmailList($merged['toEmails'] ?? '');
$this->ccEmails = $this->parseEmailList($merged['ccEmails'] ?? '');
$this->bccEmails = $this->parseEmailList($merged['bccEmails'] ?? '');
$this->fromMail = trim((string) ($merged['fromMail'] ?? ''));
}
public function shouldRunToday(): bool
{
if (! $this->enabled) {
return false;
}
if ($this->daily) {
return true;
}
$today = strtolower(date('D'));
return in_array($today, $this->days, true);
}
public function getDateField(): string
{
return $this->dateField;
}
public function getDaysBefore(): int
{
return $this->daysBefore;
}
/**
* @return int[]
*/
public function getClientTypes(): array
{
return $this->clientTypes;
}
/**
* @return string[]
*/
public function getToEmails(): array
{
return $this->toEmails;
}
/**
* @return string[]
*/
public function getCcEmails(): array
{
return $this->ccEmails;
}
/**
* @return string[]
*/
public function getBccEmails(): array
{
return $this->bccEmails;
}
public function getFromMail(): string
{
return $this->fromMail;
}
public function includeClientEmail(): bool
{
return $this->includeClientEmail;
}
public function includeOverdue(): bool
{
return $this->includeOverdue;
}
public function getMailSubject(): string
{
return $this->mailSubject;
}
public function getMailContent(): string
{
return $this->mailContent;
}
/**
* Flatten config for UI / API response.
*
* @return array<string, mixed>
*/
public function toArray(): array
{
return [
'enabled' => $this->enabled,
'daily' => $this->daily,
'days' => implode(',', $this->days),
'clientTypes' => $this->clientTypes,
'dateField' => $this->dateField,
'daysBefore' => $this->daysBefore,
'includeClientEmail' => $this->includeClientEmail,
'includeOverdue' => $this->includeOverdue,
'toEmails' => implode(',', $this->toEmails),
'ccEmails' => implode(',', $this->ccEmails),
'bccEmails' => implode(',', $this->bccEmails),
'fromMail' => $this->fromMail,
];
}
/**
* @return string[]
*/
private function parseEmailList(mixed $value): array
{
if ($value === null || $value === '') {
return [];
}
if (is_array($value)) {
$emails = array_map('trim', $value);
} else {
$emails = array_map('trim', explode(',', (string) $value));
}
$unique = [];
foreach ($emails as $email) {
if ($email === '' || ! filter_var($email, FILTER_VALIDATE_EMAIL)) {
continue;
}
$key = strtolower($email);
if (! isset($unique[$key])) {
$unique[$key] = $email;
}
}
return array_values($unique);
}
private function toBool(mixed $value): bool
{
if (is_bool($value)) {
return $value;
}
return in_array(strtolower((string) $value), ['1', 'true', 'yes', 'on'], true);
}
}