nhance/tests/smoke_cd_low_balance_alert.php

197 lines
7.7 KiB
PHP

<?php
/**
* Smoke test: CD low balance alert on debit (DepositHelper + CdLowBalanceAlertHelper)
*
* Run:
* php tests/smoke_cd_low_balance_alert.php [cd_ac_pk] # dry-run: show state only
* php tests/smoke_cd_low_balance_alert.php [cd_ac_pk] --debit 1 # live: post 1 INR test debit + alert check
* php tests/smoke_cd_low_balance_alert.php --cron # run cron scan only
*/
declare(strict_types=1);
ob_start();
define('FCPATH', __DIR__ . '/../public/');
chdir(FCPATH);
require FCPATH . '../app/Config/Paths.php';
$paths = new Config\Paths();
require rtrim($paths->systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'bootstrap.php';
require_once SYSTEMPATH . 'Config/DotEnv.php';
(new CodeIgniter\Config\DotEnv(ROOTPATH))->load();
defined('ENVIRONMENT') || define('ENVIRONMENT', env('CI_ENVIRONMENT', 'development'));
$boot = APPPATH . 'Config/Boot/' . ENVIRONMENT . '.php';
if (is_file($boot)) {
require_once $boot;
}
use App\Helpers\CdLowBalanceAlertHelper;
use App\Helpers\DepositHelper;
use App\Models\CDMasterModel;
use App\Models\ClientDepositModel;
use App\Models\ClientRMModel;
$pass = 0;
$fail = 0;
$results = [];
function ok(string $label, bool $cond, string $detail = ''): void
{
global $pass, $fail, $results;
if ($cond) {
$pass++;
$results[] = '[PASS] ' . $label . ($detail ? "{$detail}" : '');
} else {
$fail++;
$results[] = '[FAIL] ' . $label . ($detail ? "{$detail}" : '');
}
}
function argValue(string $flag): ?string
{
global $argv;
$idx = array_search($flag, $argv, true);
if ($idx === false || ! isset($argv[$idx + 1])) {
return null;
}
return (string) $argv[$idx + 1];
}
function resolveCurrentBalance(ClientDepositModel $depositModel, int $cdAcPk, float $openingBalance): float
{
$lastDeposit = $depositModel
->select('balance')
->where('cd_ac_pk', $cdAcPk)
->where('is_active', 1)
->orderBy('id', 'DESC')
->first();
if (! empty($lastDeposit)) {
return (float) ($lastDeposit['balance'] ?? 0);
}
return $openingBalance;
}
$db = db_connect('default');
$cdMasterModel = new CDMasterModel();
$depositModel = new ClientDepositModel();
$runCron = in_array('--cron', $argv, true);
$debitAmount = argValue('--debit');
$cdAcPkArg = null;
foreach (array_slice($argv, 1) as $arg) {
if (str_starts_with($arg, '--')) {
continue;
}
if (ctype_digit($arg)) {
$cdAcPkArg = (int) $arg;
break;
}
}
echo PHP_EOL . '=== smoke_cd_low_balance_alert ===' . PHP_EOL;
if ($runCron) {
$response = CdLowBalanceAlertHelper::runCron();
ok('cron status', ($response['status'] ?? false) === true, (string) ($response['message'] ?? ''));
ok('cron response has data key', array_key_exists('data', $response));
echo 'Cron response: ' . json_encode($response, JSON_PRETTY_PRINT) . PHP_EOL;
} else {
$configured = $cdMasterModel->getCdMastersWithLowAlertThreshold();
ok('at least one CD master has alert threshold', count($configured) > 0, 'count=' . count($configured));
if ($cdAcPkArg === null && ! empty($configured)) {
$cdAcPkArg = (int) ($configured[0]['id'] ?? 0);
}
ok('cd_ac_pk resolved', $cdAcPkArg !== null && $cdAcPkArg > 0, 'cd_ac_pk=' . ($cdAcPkArg ?? 'none'));
if ($cdAcPkArg > 0) {
$cdMaster = $cdMasterModel->getCdMasterWithLowAlertThresholdById($cdAcPkArg);
ok('CD master found with alert threshold', $cdMaster !== null, 'cd_ac_pk=' . $cdAcPkArg);
if ($cdMaster !== null) {
$threshold = (float) ($cdMaster['cd_balance_low_alert_amount'] ?? 0);
$currentBalance = resolveCurrentBalance($depositModel, $cdAcPkArg, (float) ($cdMaster['opening_bal'] ?? 0));
$isLow = $currentBalance < $threshold;
echo PHP_EOL . 'Account snapshot:' . PHP_EOL;
echo ' client_id : ' . ($cdMaster['client_id'] ?? '') . ' (' . ($cdMaster['client_name'] ?? '') . ')' . PHP_EOL;
echo ' cd_ac_pk : ' . $cdAcPkArg . PHP_EOL;
echo ' cd_ac_no : ' . ($cdMaster['cd_ac_no'] ?? '') . PHP_EOL;
echo ' balance : ' . number_format($currentBalance, 2) . PHP_EOL;
echo ' alert amt : ' . number_format($threshold, 2) . PHP_EOL;
echo ' below alert : ' . ($isLow ? 'yes' : 'no') . PHP_EOL;
$acmRows = (new ClientRMModel())
->select('user_profiles.first_name, user_profiles.email')
->join('user_profiles', 'user_profiles.id = client_rm.user_id')
->where('client_rm.client_id', (int) $cdMaster['client_id'])
->where('client_rm.level', 3)
->where('client_rm.is_active', 1)
->where('user_profiles.is_active', 1)
->findAll();
ok('account manager exists for client', count($acmRows) > 0, 'count=' . count($acmRows));
foreach ($acmRows as $row) {
echo ' ACM : ' . ($row['first_name'] ?? '') . ' <' . ($row['email'] ?? '') . '>' . PHP_EOL;
}
if ($debitAmount !== null) {
$amount = (float) $debitAmount;
ok('debit amount > 0', $amount > 0, 'amount=' . $amount);
$beforeBalance = $currentBalance;
$afterBalance = $beforeBalance - $amount;
echo PHP_EOL . 'Posting test debit of ' . number_format($amount, 2) . ' ...' . PHP_EOL;
$saveResult = DepositHelper::saveDeposit([
'amount' => $amount,
'sub_type_id' => 4,
'client_id' => (int) $cdMaster['client_id'],
'client_policy_id' => 0,
'endorsement_no' => 'SMOKE-TEST-' . date('YmdHis'),
'cd_ac_no' => (string) ($cdMaster['cd_ac_no'] ?? ''),
'insurer_id' => (int) ($cdMaster['insurer_id'] ?? 0),
'unit' => 'SMOKE',
'description' => 'Smoke test debit for CD low balance alert',
'transaction_type' => 'Debit',
'updated_by' => 1,
'event_name' => 'smoke_test',
'is_active' => 1,
'cd_ac_pk' => $cdAcPkArg,
], 1);
ok('saveDeposit succeeded', ($saveResult['success'] ?? false) === true, json_encode($saveResult));
$newBalance = resolveCurrentBalance($depositModel, $cdAcPkArg, (float) ($cdMaster['opening_bal'] ?? 0));
ok('balance reduced after debit', $newBalance < $beforeBalance, "before={$beforeBalance}, after={$newBalance}");
if ($afterBalance < $threshold) {
ok('balance now below alert threshold', $newBalance < $threshold);
echo 'Check writable/logs/log-' . date('Y-m-d') . '.log for CdLowBalanceAlertHelper triggerAfterBalanceReduction' . PHP_EOL;
echo 'ACM mail should be sent if mail is configured.' . PHP_EOL;
} else {
echo 'Balance still above alert threshold after debit; no mail expected.' . PHP_EOL;
echo 'Tip: use a larger --debit amount or lower cd_balance_low_alert_amount for this account.' . PHP_EOL;
}
} else {
echo PHP_EOL . 'Dry run only (no debit posted).' . PHP_EOL;
echo 'To test live debit + alert: php tests/smoke_cd_low_balance_alert.php ' . $cdAcPkArg . ' --debit 1' . PHP_EOL;
echo 'To test cron scan: php tests/smoke_cd_low_balance_alert.php --cron' . PHP_EOL;
}
}
}
}
echo PHP_EOL . implode(PHP_EOL, $results) . PHP_EOL;
echo PHP_EOL . "Summary: {$pass} passed, {$fail} failed" . PHP_EOL;
exit($fail > 0 ? 1 : 0);