CHANGE_SEND_MAIL_REMINDER

This commit is contained in:
VENKATESHWARAN 2026-06-30 10:55:18 +05:30
parent bd8c36a432
commit 0f16f73d0c
11 changed files with 1153 additions and 12 deletions

View File

@ -511,7 +511,6 @@ $routes->group("employeeRest", ['filter' => [ 'GlobalPostFileUploadGuard', 'appS
$routes->get("getExcelFileErrors/(:any)", "EmployeeController::getExcelFileErrors/$1");
$routes->post("sendReminderMail", "EmployeeRestController::sendReminderMail");
$routes->get("sendReminderMail", "EmployeeRestController::sendReminderMail");
$routes->get("getReminderMailConfig", "EmployeeRestController::getReminderMailConfig");
$routes->post("saveReminderMailConfig", "EmployeeRestController::saveReminderMailConfig");

View File

@ -350,7 +350,13 @@ class DashboardController extends AdminController
->where('template_name', 'member_reminder_mail')
->first();
if ($notification_data && $notification_data['enabled'] == 1 && !empty($notification_data['mail_content'])) {
$reminderConfig = $this->reminderMailConfigModel->getByClientPolicyId((int) $client_policy['id']);
$notification_data = $this->reminderMailConfigModel->resolveNotificationTemplate(
$reminderConfig,
$notification_data
);
if ($this->reminderMailConfigModel->canSendReminderMail($reminderConfig, $notification_data)) {
//manaual
if (empty($send_mail_for_manual_or_crone)) {

View File

@ -4684,8 +4684,9 @@ class EmployeeRestController extends AdminController
public function getReminderMailConfig()
{
try {
$clientPolicyId = $this->request->getGet('client_policy_id')
?? $this->request->getPost('client_policy_id');
$clientPolicyId = $this->request->getGet('client_policy_id');
$is_email_template = $this->request->getGet('is_email_template') ?? false;
if (empty($clientPolicyId)) {
return $this->respond([
@ -4707,6 +4708,27 @@ class EmployeeRestController extends AdminController
$config = $this->reminderMailConfigModel->getByClientPolicyId((int) $clientPolicyId);
if ($is_email_template) {
if (empty($config)) {
$notification = $this->notificationModel->where('client_id', $clientPolicy['client_id'])->where('template_name', 'member_reminder_mail')->first();
if (empty($notification)) {
return $this->respond([
'status' => false,
'code' => 404,
'message' => 'Member reminder mail notification not found',
], 200);
}
return $this->respond(['status' => true, 'code' => 200, 'data' => ['email_subject' => $notification['subject'], 'email_body' => $notification['mail_content']]], 200);
}
return $this->respond([
'status' => true,
'code' => 200,
'data' => ['email_subject' => $config['email_subject'], 'email_body' => $config['email_body']],
], 200);
}
if (empty($config) && !empty($clientPolicy['reminder_date'])) {
$config = [
'client_policy_id' => (int) $clientPolicyId,
@ -4750,6 +4772,8 @@ class EmployeeRestController extends AdminController
?? null;
$isEnabled = $requestData['is_enabled'] ?? null;
$hrId = $requestData['hr_id'] ?? null;
$emailSubject = $requestData['email_subject'] ?? null;
$emailBody = $requestData['email_body'] ?? null;
if (empty($clientPolicyId)) {
return $this->respond([
@ -4777,15 +4801,25 @@ class EmployeeRestController extends AdminController
], 200);
}
$saveOptions = [
'id' => $configId !== null && $configId !== '' ? (int) $configId : null,
'hr_id' => $hrId !== null && $hrId !== '' ? (int) $hrId : null,
];
if (array_key_exists('email_subject', $requestData)) {
$saveOptions['email_subject'] = $emailSubject;
}
if (array_key_exists('email_body', $requestData)) {
$saveOptions['email_body'] = $emailBody;
}
$result = $this->reminderMailConfigModel->saveConfig(
(int) $clientPolicyId,
$frequency,
$reminderDays !== null ? (string) $reminderDays : null,
$isEnabled === null ? 1 : (int) $isEnabled,
[
'id' => $configId !== null && $configId !== '' ? (int) $configId : null,
'hr_id' => $hrId !== null && $hrId !== '' ? (int) $hrId : null,
]
$saveOptions
);
if (!$result['status']) {
@ -4826,6 +4860,8 @@ class EmployeeRestController extends AdminController
'frequency' => $this->request->getVar('frequency'),
'reminder_days' => $this->request->getVar('reminder_days'),
'working_days' => $this->request->getVar('working_days'),
'email_subject' => $this->request->getVar('email_subject'),
'email_body' => $this->request->getVar('email_body'),
'is_enabled' => $this->request->getVar('is_enabled'),
'hr_id' => $this->request->getVar('hr_id'),
], static fn ($value) => $value !== null && $value !== '');
@ -4834,8 +4870,34 @@ class EmployeeRestController extends AdminController
public function sendReminderMail()
{
try {
$clientPolicyId = $this->request->getGet('client_policy_id')
?? $this->request->getPost('client_policy_id');
if (!$this->request->is('post')) {
return $this->respond([
'status' => false,
'code' => 405,
'message' => 'Only POST method is allowed',
], 200);
}
try {
$requestData = $this->request->getJSON(true);
} catch (\CodeIgniter\HTTP\Exceptions\HTTPException $e) {
return $this->respond([
'status' => false,
'code' => 400,
'message' => 'Invalid JSON request body',
], 200);
}
if (!is_array($requestData) || empty($requestData)) {
return $this->respond([
'status' => false,
'code' => 400,
'message' => 'JSON request body is required',
], 200);
}
$clientPolicyId = $requestData['client_policy_id'] ?? null;
if (empty($clientPolicyId)) {
return $this->respond([
@ -4855,9 +4917,20 @@ class EmployeeRestController extends AdminController
], 200);
}
$dashboardController = new DashboardController();
$emailSubject = $requestData['email_subject'] ?? null;
$emailBody = $requestData['email_body'] ?? null;
$hrId = $requestData['hr_id'] ?? null;
return $dashboardController->sendManualReminder(
if (array_key_exists('email_subject', $requestData) || array_key_exists('email_body', $requestData)) {
$this->reminderMailConfigModel->saveEmailTemplate(
(int) $clientPolicyId,
$emailSubject,
$emailBody,
$hrId !== null && $hrId !== '' ? (int) $hrId : null
);
}
return $this->dispatchManualReminder(
$clientPolicy['client_id'],
$clientPolicy['client_branch_id'],
$clientPolicyId
@ -4871,4 +4944,15 @@ class EmployeeRestController extends AdminController
}
}
protected function dispatchManualReminder($clientId, $clientBranchId, $clientPolicyId)
{
$dashboardController = new DashboardController();
return $dashboardController->sendManualReminder(
$clientId,
$clientBranchId,
$clientPolicyId
);
}
}

View File

@ -5,6 +5,8 @@ CREATE TABLE IF NOT EXISTS `reminder_mail_config` (
`client_policy_id` INT UNSIGNED NOT NULL,
`frequency` ENUM('daily', 'weekly', 'monthly', 'custom', 'working_days') NOT NULL DEFAULT 'custom',
`reminder_days` VARCHAR(255) DEFAULT NULL COMMENT 'weekly: 0-6 (Sun-Sat); working_days: 1-7 (Mon-Sun) or Mon,Tue,...; monthly/custom: 1-31; daily: NULL',
`email_subject` VARCHAR(500) DEFAULT NULL COMMENT 'Custom reminder mail subject; falls back to notification template when NULL',
`email_body` TEXT DEFAULT NULL COMMENT 'Custom reminder mail body; falls back to notification template when NULL',
`is_enabled` TINYINT(1) NOT NULL DEFAULT 1,
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
`created_by` INT UNSIGNED DEFAULT NULL,
@ -16,3 +18,10 @@ CREATE TABLE IF NOT EXISTS `reminder_mail_config` (
KEY `idx_reminder_mail_config_frequency` (`frequency`),
KEY `idx_reminder_mail_config_is_enabled` (`is_enabled`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Upgrade existing installations (ignore duplicate-column errors if already applied)
ALTER TABLE `reminder_mail_config`
ADD COLUMN `email_subject` VARCHAR(500) DEFAULT NULL COMMENT 'Custom reminder mail subject; falls back to notification template when NULL' AFTER `reminder_days`;
ALTER TABLE `reminder_mail_config`
ADD COLUMN `email_body` TEXT DEFAULT NULL COMMENT 'Custom reminder mail body; falls back to notification template when NULL' AFTER `email_subject`;

View File

@ -50,6 +50,8 @@ class ReminderMailConfigModel extends Model
'client_policy_id',
'frequency',
'reminder_days',
'email_subject',
'email_body',
'is_enabled',
'is_active',
'created_by',
@ -209,9 +211,90 @@ class ReminderMailConfigModel extends Model
$config['working_day_labels'] = $this->formatWorkingDayLabels($config['reminder_days'] ?? null);
}
$config['has_custom_template'] = $this->hasCustomTemplate($config);
return $config;
}
public function hasCustomTemplate(?array $config): bool
{
if (empty($config)) {
return false;
}
return trim((string) ($config['email_subject'] ?? '')) !== ''
&& trim((string) ($config['email_body'] ?? '')) !== '';
}
/**
* Apply reminder_mail_config template to notification data when configured.
*/
public function resolveNotificationTemplate(?array $config, ?array $notificationData): ?array
{
if (!$this->hasCustomTemplate($config)) {
return $notificationData;
}
$notificationData = is_array($notificationData) ? $notificationData : [];
$notificationData['subject'] = $config['email_subject'];
$notificationData['mail_content'] = $config['email_body'];
$notificationData['enabled'] = 1;
return $notificationData;
}
public function canSendReminderMail(?array $config, ?array $notificationData): bool
{
if ($this->hasCustomTemplate($config)) {
return true;
}
return !empty($notificationData)
&& (int) ($notificationData['enabled'] ?? 0) === 1
&& trim((string) ($notificationData['mail_content'] ?? '')) !== '';
}
public function saveEmailTemplate(
int $clientPolicyId,
?string $emailSubject,
?string $emailBody,
?int $hrId = null
): void {
if ($emailSubject === null && $emailBody === null) {
return;
}
$existing = $this->getByClientPolicyId($clientPolicyId);
if ($existing) {
$payload = ['updated_by' => $hrId];
if ($emailSubject !== null) {
$payload['email_subject'] = $emailSubject;
}
if ($emailBody !== null) {
$payload['email_body'] = $emailBody;
}
$this->update((int) $existing['id'], $payload);
return;
}
$this->insert([
'client_policy_id' => $clientPolicyId,
'frequency' => self::FREQUENCY_CUSTOM,
'reminder_days' => null,
'email_subject' => $emailSubject,
'email_body' => $emailBody,
'is_enabled' => 1,
'is_active' => 1,
'created_by' => $hrId,
'updated_by' => $hrId,
]);
}
public function normalizeReminderDays(string $frequency, ?string $reminderDays): ?string
{
if ($frequency === self::FREQUENCY_DAILY) {
@ -313,6 +396,14 @@ class ReminderMailConfigModel extends Model
'is_active' => 1,
];
if (array_key_exists('email_subject', $options)) {
$payload['email_subject'] = $options['email_subject'];
}
if (array_key_exists('email_body', $options)) {
$payload['email_body'] = $options['email_body'];
}
if ($id) {
$existing = $this->where('id', $id)->where('is_active', 1)->first();

View File

@ -0,0 +1,120 @@
<?php
namespace Tests\Support\Traits;
use App\Controllers\EmployeeRestController;
use CodeIgniter\HTTP\IncomingRequest;
use Config\Services;
use ReflectionClass;
trait ReminderMailControllerTestTrait
{
private function createNotificationModelStub(?array $result): object
{
return new class($result) {
private ?array $result;
public function __construct(?array $result)
{
$this->result = $result;
}
public function where(...$args)
{
return $this;
}
public function first(): ?array
{
return $this->result;
}
};
}
private function buildGetController(
array $getParams,
$clientPolicyModel,
$reminderMailConfigModel,
?object $notificationModel = null
): EmployeeRestController {
$request = $this->createMock(IncomingRequest::class);
$request->method('getGet')
->willReturnCallback(function ($key = null) use ($getParams) {
if ($key === null) {
return $getParams;
}
return array_key_exists($key, $getParams) ? $getParams[$key] : null;
});
return $this->injectReminderMailControllerDependencies(
$request,
$clientPolicyModel,
$reminderMailConfigModel,
$notificationModel
);
}
private function buildJsonPostController(
array $jsonData,
$clientPolicyModel,
$reminderMailConfigModel,
bool $isPost = true,
?object $notificationModel = null,
?EmployeeRestController $controller = null
): EmployeeRestController {
$request = $this->createMock(IncomingRequest::class);
$request->method('is')
->with('post')
->willReturn($isPost);
$request->method('getJSON')
->with(true)
->willReturn($jsonData);
$request->method('getVar')
->willReturn(null);
$controller = $controller ?? new EmployeeRestController();
return $this->injectReminderMailControllerDependencies(
$request,
$clientPolicyModel,
$reminderMailConfigModel,
$notificationModel,
$controller
);
}
private function injectReminderMailControllerDependencies(
IncomingRequest $request,
$clientPolicyModel,
$reminderMailConfigModel,
?object $notificationModel = null,
?EmployeeRestController $controller = null
): EmployeeRestController {
$controller = $controller ?? new EmployeeRestController();
$controller->initController($request, Services::response(), Services::logger());
$reflection = new ReflectionClass($controller);
foreach ([
'clientPolicyModel' => $clientPolicyModel,
'reminderMailConfigModel' => $reminderMailConfigModel,
'notificationModel' => $notificationModel,
] as $property => $value) {
if ($value === null) {
continue;
}
$prop = $reflection->getProperty($property);
$prop->setAccessible(true);
$prop->setValue($controller, $value);
}
return $controller;
}
private function decodeResponse($response): array
{
return json_decode($response->getBody(), true);
}
}

View File

@ -0,0 +1,317 @@
<?php
namespace Tests\Unit;
use App\Controllers\EmployeeRestController;
use App\Models\ClientPolicyModel;
use App\Models\ReminderMailConfigModel;
use CodeIgniter\HTTP\IncomingRequest;
use CodeIgniter\Test\CIUnitTestCase;
use Config\Services;
use ReflectionClass;
class GetReminderMailConfigTest extends CIUnitTestCase
{
private function createNotificationModelStub(?array $result): object
{
return new class($result) {
private ?array $result;
public function __construct(?array $result)
{
$this->result = $result;
}
public function where(...$args)
{
return $this;
}
public function first(): ?array
{
return $this->result;
}
};
}
private function buildController(
array $getParams,
$clientPolicyModel,
$reminderMailConfigModel,
?object $notificationModel = null
): EmployeeRestController {
$controller = new EmployeeRestController();
$request = $this->createMock(IncomingRequest::class);
$request->method('getGet')
->willReturnCallback(function ($key = null) use ($getParams) {
if ($key === null) {
return $getParams;
}
return array_key_exists($key, $getParams) ? $getParams[$key] : null;
});
$controller->initController($request, Services::response(), Services::logger());
$reflection = new ReflectionClass($controller);
foreach ([
'clientPolicyModel' => $clientPolicyModel,
'reminderMailConfigModel' => $reminderMailConfigModel,
'notificationModel' => $notificationModel,
] as $property => $value) {
if ($value === null) {
continue;
}
$prop = $reflection->getProperty($property);
$prop->setAccessible(true);
$prop->setValue($controller, $value);
}
return $controller;
}
private function decodeResponse($response): array
{
return json_decode($response->getBody(), true);
}
private function mockReminderMailConfigModel(array $methods): ReminderMailConfigModel
{
return $this->getMockBuilder(ReminderMailConfigModel::class)
->onlyMethods(array_keys($methods))
->getMock();
}
public function testMissingClientPolicyIdReturns400()
{
$clientPolicyModel = $this->createMock(ClientPolicyModel::class);
$reminderMailConfigModel = $this->mockReminderMailConfigModel([]);
$controller = $this->buildController([], $clientPolicyModel, $reminderMailConfigModel);
$body = $this->decodeResponse($controller->getReminderMailConfig());
$this->assertFalse($body['status']);
$this->assertSame(400, $body['code']);
$this->assertSame('client_policy_id is required', $body['message']);
}
public function testClientPolicyNotFoundReturns404()
{
$clientPolicyModel = $this->createMock(ClientPolicyModel::class);
$clientPolicyModel->method('find')->with(999)->willReturn(null);
$reminderMailConfigModel = $this->mockReminderMailConfigModel([]);
$controller = $this->buildController(
['client_policy_id' => '999'],
$clientPolicyModel,
$reminderMailConfigModel
);
$body = $this->decodeResponse($controller->getReminderMailConfig());
$this->assertFalse($body['status']);
$this->assertSame(404, $body['code']);
$this->assertSame('Client policy not found', $body['message']);
}
public function testExistingConfigReturnsEnrichedDataAndWorkingDayOptions()
{
$config = [
'id' => 10,
'client_policy_id' => 123,
'frequency' => ReminderMailConfigModel::FREQUENCY_WORKING_DAYS,
'reminder_days' => '1,3,5',
'email_subject' => 'Reminder',
'email_body' => '<p>Please enroll</p>',
'is_enabled' => 1,
'is_active' => 1,
];
$clientPolicyModel = $this->createMock(ClientPolicyModel::class);
$clientPolicyModel->method('find')->with(123)->willReturn([
'id' => 123,
'client_id' => 42,
]);
$reminderMailConfigModel = $this->mockReminderMailConfigModel([
'getByClientPolicyId' => null,
]);
$reminderMailConfigModel->method('getByClientPolicyId')->with(123)->willReturn($config);
$controller = $this->buildController(
['client_policy_id' => '123'],
$clientPolicyModel,
$reminderMailConfigModel
);
$body = $this->decodeResponse($controller->getReminderMailConfig());
$this->assertTrue($body['status']);
$this->assertSame(200, $body['code']);
$this->assertSame(123, $body['data']['client_policy_id']);
$this->assertSame(['Mon', 'Wed', 'Fri'], $body['data']['working_day_labels']);
$this->assertTrue($body['data']['has_custom_template']);
$this->assertCount(7, $body['working_day_options']);
$this->assertSame('Mon', $body['working_day_options'][0]['label']);
}
public function testLegacyFallbackWhenNoConfigButPolicyHasReminderDate()
{
$clientPolicyModel = $this->createMock(ClientPolicyModel::class);
$clientPolicyModel->method('find')->with(123)->willReturn([
'id' => 123,
'client_id' => 42,
'reminder_date' => '1,15,28',
]);
$reminderMailConfigModel = $this->mockReminderMailConfigModel([
'getByClientPolicyId' => null,
]);
$reminderMailConfigModel->method('getByClientPolicyId')->with(123)->willReturn(null);
$controller = $this->buildController(
['client_policy_id' => '123'],
$clientPolicyModel,
$reminderMailConfigModel
);
$body = $this->decodeResponse($controller->getReminderMailConfig());
$this->assertTrue($body['status']);
$this->assertSame(200, $body['code']);
$this->assertSame(123, $body['data']['client_policy_id']);
$this->assertSame(ReminderMailConfigModel::FREQUENCY_CUSTOM, $body['data']['frequency']);
$this->assertSame('1,15,28', $body['data']['reminder_days']);
$this->assertSame('legacy_client_policy', $body['data']['source']);
$this->assertArrayHasKey('working_day_options', $body);
}
public function testNoConfigAndNoLegacyReminderDateReturnsNullData()
{
$clientPolicyModel = $this->createMock(ClientPolicyModel::class);
$clientPolicyModel->method('find')->with(123)->willReturn([
'id' => 123,
'client_id' => 42,
]);
$reminderMailConfigModel = $this->mockReminderMailConfigModel([
'getByClientPolicyId' => null,
]);
$reminderMailConfigModel->method('getByClientPolicyId')->with(123)->willReturn(null);
$controller = $this->buildController(
['client_policy_id' => '123'],
$clientPolicyModel,
$reminderMailConfigModel
);
$body = $this->decodeResponse($controller->getReminderMailConfig());
$this->assertTrue($body['status']);
$this->assertSame(200, $body['code']);
$this->assertNull($body['data']);
$this->assertCount(7, $body['working_day_options']);
}
public function testEmailTemplateModeReturnsConfigTemplate()
{
$config = [
'client_policy_id' => 123,
'email_subject' => 'Custom subject',
'email_body' => '<p>Custom body</p>',
];
$clientPolicyModel = $this->createMock(ClientPolicyModel::class);
$clientPolicyModel->method('find')->with(123)->willReturn([
'id' => 123,
'client_id' => 42,
]);
$reminderMailConfigModel = $this->mockReminderMailConfigModel([
'getByClientPolicyId' => null,
]);
$reminderMailConfigModel->method('getByClientPolicyId')->with(123)->willReturn($config);
$controller = $this->buildController(
[
'client_policy_id' => '123',
'is_email_template' => '1',
],
$clientPolicyModel,
$reminderMailConfigModel
);
$body = $this->decodeResponse($controller->getReminderMailConfig());
$this->assertTrue($body['status']);
$this->assertSame(200, $body['code']);
$this->assertSame('Custom subject', $body['data']['email_subject']);
$this->assertSame('<p>Custom body</p>', $body['data']['email_body']);
$this->assertArrayNotHasKey('working_day_options', $body);
}
public function testEmailTemplateModeFallsBackToNotificationWhenNoConfig()
{
$clientPolicyModel = $this->createMock(ClientPolicyModel::class);
$clientPolicyModel->method('find')->with(123)->willReturn([
'id' => 123,
'client_id' => 42,
]);
$reminderMailConfigModel = $this->mockReminderMailConfigModel([
'getByClientPolicyId' => null,
]);
$reminderMailConfigModel->method('getByClientPolicyId')->with(123)->willReturn(null);
$notificationModel = $this->createNotificationModelStub([
'subject' => 'Default subject',
'mail_content' => '<p>Default body</p>',
]);
$controller = $this->buildController(
[
'client_policy_id' => '123',
'is_email_template' => '1',
],
$clientPolicyModel,
$reminderMailConfigModel,
$notificationModel
);
$body = $this->decodeResponse($controller->getReminderMailConfig());
$this->assertTrue($body['status']);
$this->assertSame(200, $body['code']);
$this->assertSame('Default subject', $body['data']['email_subject']);
$this->assertSame('<p>Default body</p>', $body['data']['email_body']);
}
public function testEmailTemplateModeReturns404WhenNotificationMissing()
{
$clientPolicyModel = $this->createMock(ClientPolicyModel::class);
$clientPolicyModel->method('find')->with(123)->willReturn([
'id' => 123,
'client_id' => 42,
]);
$reminderMailConfigModel = $this->mockReminderMailConfigModel([
'getByClientPolicyId' => null,
]);
$reminderMailConfigModel->method('getByClientPolicyId')->with(123)->willReturn(null);
$notificationModel = $this->createNotificationModelStub(null);
$controller = $this->buildController(
[
'client_policy_id' => '123',
'is_email_template' => '1',
],
$clientPolicyModel,
$reminderMailConfigModel,
$notificationModel
);
$body = $this->decodeResponse($controller->getReminderMailConfig());
$this->assertFalse($body['status']);
$this->assertSame(404, $body['code']);
$this->assertSame('Member reminder mail notification not found', $body['message']);
}
}

View File

@ -0,0 +1,161 @@
<?php
namespace Tests\Unit;
use App\Models\ReminderMailConfigModel;
use CodeIgniter\Test\CIUnitTestCase;
class ReminderMailConfigModelTest extends CIUnitTestCase
{
private ReminderMailConfigModel $model;
protected function setUp(): void
{
parent::setUp();
$this->model = new ReminderMailConfigModel();
}
public function testHasCustomTemplateRequiresBothSubjectAndBody()
{
$this->assertFalse($this->model->hasCustomTemplate(null));
$this->assertFalse($this->model->hasCustomTemplate([]));
$this->assertFalse($this->model->hasCustomTemplate([
'email_subject' => 'Reminder',
'email_body' => '',
]));
$this->assertFalse($this->model->hasCustomTemplate([
'email_subject' => ' ',
'email_body' => '<p>Body</p>',
]));
$this->assertTrue($this->model->hasCustomTemplate([
'email_subject' => 'Reminder',
'email_body' => '<p>Body</p>',
]));
}
public function testResolveNotificationTemplateUsesCustomTemplateWhenConfigured()
{
$config = [
'email_subject' => 'Custom subject',
'email_body' => '<p>Custom body</p>',
];
$notification = [
'id' => 5,
'enabled' => 0,
'subject' => 'Default subject',
'mail_content' => '<p>Default body</p>',
];
$resolved = $this->model->resolveNotificationTemplate($config, $notification);
$this->assertSame('Custom subject', $resolved['subject']);
$this->assertSame('<p>Custom body</p>', $resolved['mail_content']);
$this->assertSame(1, $resolved['enabled']);
$this->assertSame(5, $resolved['id']);
}
public function testResolveNotificationTemplateReturnsDefaultWhenCustomTemplateMissing()
{
$notification = [
'subject' => 'Default subject',
'mail_content' => '<p>Default body</p>',
];
$resolved = $this->model->resolveNotificationTemplate(
['email_subject' => 'Only subject'],
$notification
);
$this->assertSame($notification, $resolved);
}
public function testCanSendReminderMailAllowsCustomTemplateEvenWhenNotificationDisabled()
{
$config = [
'email_subject' => 'Custom subject',
'email_body' => '<p>Custom body</p>',
];
$notification = [
'enabled' => 0,
'mail_content' => '',
];
$this->assertTrue($this->model->canSendReminderMail($config, $notification));
}
public function testCanSendReminderMailRequiresEnabledDefaultNotification()
{
$this->assertFalse($this->model->canSendReminderMail(null, null));
$this->assertFalse($this->model->canSendReminderMail(null, [
'enabled' => 0,
'mail_content' => '<p>Body</p>',
]));
$this->assertFalse($this->model->canSendReminderMail(null, [
'enabled' => 1,
'mail_content' => '',
]));
$this->assertTrue($this->model->canSendReminderMail(null, [
'enabled' => 1,
'mail_content' => '<p>Body</p>',
]));
}
public function testValidateConfigRejectsInvalidFrequency()
{
$error = $this->model->validateConfig('hourly', '1');
$this->assertSame(
'Invalid frequency. Allowed values: daily, weekly, monthly, custom, working_days.',
$error
);
}
public function testValidateConfigDailyDoesNotRequireReminderDays()
{
$this->assertNull($this->model->validateConfig(
ReminderMailConfigModel::FREQUENCY_DAILY,
null
));
}
public function testValidateConfigWorkingDaysAcceptsDayNames()
{
$this->assertNull($this->model->validateConfig(
ReminderMailConfigModel::FREQUENCY_WORKING_DAYS,
'Mon,Wed,Fri'
));
}
public function testValidateConfigWeeklyRejectsInvalidDay()
{
$error = $this->model->validateConfig(
ReminderMailConfigModel::FREQUENCY_WEEKLY,
'0,8'
);
$this->assertSame(
'Weekly reminder_days must be between 0 (Sunday) and 6 (Saturday).',
$error
);
}
public function testEnrichConfigAddsCustomTemplateFlagAndWorkingDayLabels()
{
$config = $this->model->enrichConfig([
'frequency' => ReminderMailConfigModel::FREQUENCY_WORKING_DAYS,
'reminder_days' => '1,3,5',
'email_subject' => 'Reminder',
'email_body' => '<p>Please enroll</p>',
]);
$this->assertTrue($config['has_custom_template']);
$this->assertSame(['Mon', 'Wed', 'Fri'], $config['working_day_labels']);
}
public function testNormalizeWorkingDaysSortsAndDeduplicates()
{
$this->assertSame('1,3,5', $this->model->normalizeWorkingDays('Fri,Mon,Wed,Mon'));
}
}

View File

@ -0,0 +1,173 @@
<?php
namespace Tests\Unit;
use App\Controllers\EmployeeRestController;
use App\Models\ClientPolicyModel;
use App\Models\ReminderMailConfigModel;
use CodeIgniter\Test\CIUnitTestCase;
use Tests\Support\Traits\ReminderMailControllerTestTrait;
class SaveReminderMailConfigTest extends CIUnitTestCase
{
use ReminderMailControllerTestTrait;
private function mockReminderMailConfigModel(array $methods): ReminderMailConfigModel
{
return $this->getMockBuilder(ReminderMailConfigModel::class)
->onlyMethods(array_keys($methods))
->getMock();
}
public function testMissingClientPolicyIdReturns400()
{
$controller = $this->buildJsonPostController(
['frequency' => 'daily'],
$this->createMock(ClientPolicyModel::class),
$this->mockReminderMailConfigModel([])
);
$body = $this->decodeResponse($controller->saveReminderMailConfig());
$this->assertFalse($body['status']);
$this->assertSame(400, $body['code']);
$this->assertSame('client_policy_id is required', $body['message']);
}
public function testMissingFrequencyReturns400()
{
$clientPolicyModel = $this->createMock(ClientPolicyModel::class);
$controller = $this->buildJsonPostController(
['client_policy_id' => 123],
$clientPolicyModel,
$this->mockReminderMailConfigModel([])
);
$body = $this->decodeResponse($controller->saveReminderMailConfig());
$this->assertFalse($body['status']);
$this->assertSame(400, $body['code']);
$this->assertSame('frequency is required', $body['message']);
}
public function testClientPolicyNotFoundReturns404()
{
$clientPolicyModel = $this->createMock(ClientPolicyModel::class);
$clientPolicyModel->method('find')->with(123)->willReturn(null);
$controller = $this->buildJsonPostController(
[
'client_policy_id' => 123,
'frequency' => 'daily',
],
$clientPolicyModel,
$this->mockReminderMailConfigModel([])
);
$body = $this->decodeResponse($controller->saveReminderMailConfig());
$this->assertFalse($body['status']);
$this->assertSame(404, $body['code']);
$this->assertSame('Client policy not found', $body['message']);
}
public function testSaveConfigValidationErrorReturns400()
{
$clientPolicyModel = $this->createMock(ClientPolicyModel::class);
$clientPolicyModel->method('find')->with(123)->willReturn(['id' => 123]);
$reminderMailConfigModel = $this->mockReminderMailConfigModel(['saveConfig' => null]);
$reminderMailConfigModel->expects($this->once())
->method('saveConfig')
->with(
123,
'weekly',
'9',
1,
$this->callback(function (array $options): bool {
return !array_key_exists('email_subject', $options)
&& !array_key_exists('email_body', $options);
})
)
->willReturn([
'status' => false,
'message' => 'Weekly reminder_days must be between 0 (Sunday) and 6 (Saturday).',
]);
$controller = $this->buildJsonPostController(
[
'client_policy_id' => 123,
'frequency' => 'weekly',
'reminder_days' => '9',
],
$clientPolicyModel,
$reminderMailConfigModel
);
$body = $this->decodeResponse($controller->saveReminderMailConfig());
$this->assertFalse($body['status']);
$this->assertSame(400, $body['code']);
$this->assertSame(
'Weekly reminder_days must be between 0 (Sunday) and 6 (Saturday).',
$body['message']
);
}
public function testSuccessfulSaveIncludesEmailTemplateFields()
{
$savedConfig = [
'id' => 10,
'client_policy_id' => 123,
'frequency' => ReminderMailConfigModel::FREQUENCY_DAILY,
'email_subject' => 'Reminder subject',
'email_body' => '<p>Reminder body</p>',
'is_enabled' => 1,
];
$clientPolicyModel = $this->createMock(ClientPolicyModel::class);
$clientPolicyModel->method('find')->with(123)->willReturn(['id' => 123]);
$reminderMailConfigModel = $this->mockReminderMailConfigModel(['saveConfig' => null]);
$reminderMailConfigModel->expects($this->once())
->method('saveConfig')
->with(
123,
'daily',
null,
1,
$this->callback(function (array $options): bool {
return ($options['email_subject'] ?? null) === 'Reminder subject'
&& ($options['email_body'] ?? null) === '<p>Reminder body</p>'
&& ($options['hr_id'] ?? null) === 45;
})
)
->willReturn([
'status' => true,
'action' => 'updated',
'data' => $savedConfig,
]);
$controller = $this->buildJsonPostController(
[
'client_policy_id' => 123,
'frequency' => 'daily',
'email_subject' => 'Reminder subject',
'email_body' => '<p>Reminder body</p>',
'hr_id' => 45,
],
$clientPolicyModel,
$reminderMailConfigModel
);
$body = $this->decodeResponse($controller->saveReminderMailConfig());
$this->assertTrue($body['status']);
$this->assertSame(200, $body['code']);
$this->assertSame('updated', $body['action']);
$this->assertSame('Reminder mail configuration saved successfully', $body['message']);
$this->assertSame('Reminder subject', $body['data']['email_subject']);
$this->assertSame('<p>Reminder body</p>', $body['data']['email_body']);
}
}

View File

@ -0,0 +1,181 @@
<?php
namespace Tests\Unit;
use App\Controllers\EmployeeRestController;
use App\Models\ClientPolicyModel;
use App\Models\ReminderMailConfigModel;
use CodeIgniter\Test\CIUnitTestCase;
use Config\Services;
use Tests\Support\Traits\ReminderMailControllerTestTrait;
class SendReminderMailTest extends CIUnitTestCase
{
use ReminderMailControllerTestTrait;
private function mockReminderMailConfigModel(array $methods): ReminderMailConfigModel
{
return $this->getMockBuilder(ReminderMailConfigModel::class)
->onlyMethods(array_keys($methods))
->getMock();
}
public function testNonPostRequestReturns405()
{
$controller = $this->buildJsonPostController(
['client_policy_id' => 123],
$this->createMock(ClientPolicyModel::class),
$this->mockReminderMailConfigModel([]),
false
);
$body = $this->decodeResponse($controller->sendReminderMail());
$this->assertFalse($body['status']);
$this->assertSame(405, $body['code']);
$this->assertSame('Only POST method is allowed', $body['message']);
}
public function testEmptyJsonBodyReturns400()
{
$controller = $this->buildJsonPostController(
[],
$this->createMock(ClientPolicyModel::class),
$this->mockReminderMailConfigModel([])
);
$body = $this->decodeResponse($controller->sendReminderMail());
$this->assertFalse($body['status']);
$this->assertSame(400, $body['code']);
$this->assertSame('JSON request body is required', $body['message']);
}
public function testMissingClientPolicyIdReturns400()
{
$controller = $this->buildJsonPostController(
['email_subject' => 'Reminder'],
$this->createMock(ClientPolicyModel::class),
$this->mockReminderMailConfigModel([])
);
$body = $this->decodeResponse($controller->sendReminderMail());
$this->assertFalse($body['status']);
$this->assertSame(400, $body['code']);
$this->assertSame('client_policy_id is required', $body['message']);
}
public function testClientPolicyNotFoundReturns404()
{
$clientPolicyModel = $this->createMock(ClientPolicyModel::class);
$clientPolicyModel->method('find')->with(123)->willReturn(null);
$controller = $this->buildJsonPostController(
['client_policy_id' => 123],
$clientPolicyModel,
$this->mockReminderMailConfigModel([])
);
$body = $this->decodeResponse($controller->sendReminderMail());
$this->assertFalse($body['status']);
$this->assertSame(404, $body['code']);
$this->assertSame('Client policy not found', $body['message']);
}
public function testSavesEmailTemplateBeforeSendingMail()
{
$clientPolicyModel = $this->createMock(ClientPolicyModel::class);
$clientPolicyModel->method('find')->with(123)->willReturn([
'id' => 123,
'client_id' => 42,
'client_branch_id' => 7,
]);
$reminderMailConfigModel = $this->mockReminderMailConfigModel(['saveEmailTemplate' => null]);
$reminderMailConfigModel->expects($this->once())
->method('saveEmailTemplate')
->with(
123,
'Enrollment reminder',
'<p>Hi [[member_name]]</p>',
45
);
$controller = $this->getMockBuilder(EmployeeRestController::class)
->onlyMethods(['dispatchManualReminder'])
->getMock();
$controller->expects($this->once())
->method('dispatchManualReminder')
->with(42, 7, 123)
->willReturn(
Services::response()->setJSON([
'status' => true,
'code' => 200,
'message' => 'Mail sent successfully',
])->setStatusCode(200)
);
$controller = $this->buildJsonPostController(
[
'client_policy_id' => 123,
'email_subject' => 'Enrollment reminder',
'email_body' => '<p>Hi [[member_name]]</p>',
'hr_id' => 45,
],
$clientPolicyModel,
$reminderMailConfigModel,
true,
null,
$controller
);
$body = $this->decodeResponse($controller->sendReminderMail());
$this->assertTrue($body['status']);
$this->assertSame(200, $body['code']);
$this->assertSame('Mail sent successfully', $body['message']);
}
public function testSkipsTemplateSaveWhenEmailFieldsNotProvided()
{
$clientPolicyModel = $this->createMock(ClientPolicyModel::class);
$clientPolicyModel->method('find')->with(123)->willReturn([
'id' => 123,
'client_id' => 42,
'client_branch_id' => 7,
]);
$reminderMailConfigModel = $this->mockReminderMailConfigModel(['saveEmailTemplate' => null]);
$reminderMailConfigModel->expects($this->never())->method('saveEmailTemplate');
$controller = $this->getMockBuilder(EmployeeRestController::class)
->onlyMethods(['dispatchManualReminder'])
->getMock();
$controller->expects($this->once())
->method('dispatchManualReminder')
->with(42, 7, 123)
->willReturn(
Services::response()->setJSON([
'status' => false,
'code' => 200,
'message' => 'There is no data to send',
])->setStatusCode(200)
);
$controller = $this->buildJsonPostController(
['client_policy_id' => 123],
$clientPolicyModel,
$reminderMailConfigModel,
true,
null,
$controller
);
$body = $this->decodeResponse($controller->sendReminderMail());
$this->assertFalse($body['status']);
$this->assertSame('There is no data to send', $body['message']);
}
}

0
writable/venbaehn_nhance Normal file
View File