recreate project
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
namespace App\Commands;
|
||||
|
||||
use CodeIgniter\CLI\BaseCommand;
|
||||
use CodeIgniter\CLI\CLI;
|
||||
use App\Models\ConfigurationModel;
|
||||
use App\Models\InvoiceModel;
|
||||
use App\Models\PaymentNotificationLogModel;
|
||||
use App\Models\UserModel;
|
||||
use App\Models\FamilyGuardianModel;
|
||||
use App\Services\EmailService;
|
||||
|
||||
class SendTestPaymentNotification extends BaseCommand
|
||||
{
|
||||
protected $group = 'Payments';
|
||||
protected $name = 'payments:send-test';
|
||||
protected $description = 'Send a single test non-payment or installment reminder to a specific email.';
|
||||
|
||||
public function run(array $params)
|
||||
{
|
||||
$email = CLI::getOption('email');
|
||||
$type = CLI::getOption('type') ?? 'no_payment';
|
||||
if (!$email || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
CLI::write('Usage: php spark payments:send-test --email=addr@example.com [--type=no_payment|installment]', 'yellow');
|
||||
return;
|
||||
}
|
||||
|
||||
$config = new ConfigurationModel();
|
||||
$user = new UserModel();
|
||||
$invoice= new InvoiceModel();
|
||||
$logs = new PaymentNotificationLogModel();
|
||||
$fam = new FamilyGuardianModel();
|
||||
$mailer = new EmailService();
|
||||
|
||||
$tzName = (string) (config('School')->attendance['timezone'] ?? 'UTC');
|
||||
$tz = new \DateTimeZone($tzName);
|
||||
$now = new \DateTime('now', $tz);
|
||||
$year = (int)$now->format('Y');
|
||||
$month= (int)$now->format('n');
|
||||
$schoolYear = (string) ($config->getConfig('school_year') ?? $year);
|
||||
|
||||
$userRow = $user->where('email', $email)->first();
|
||||
$parentId = (int)($userRow['id'] ?? 0);
|
||||
|
||||
$invRows = $parentId ? $invoice->getAllInvoicesByUserIds([$parentId], $schoolYear) : [];
|
||||
$totalBalance = 0.0; $latestInvoiceId = null;
|
||||
foreach ($invRows as $ir) {
|
||||
$totalBalance += (float)($ir['balance'] ?? 0);
|
||||
if ($latestInvoiceId === null) $latestInvoiceId = (int)($ir['id'] ?? 0);
|
||||
}
|
||||
|
||||
// Secondary guardian if available
|
||||
$ccEmail = null;
|
||||
if ($parentId) {
|
||||
$row = $fam->where('user_id', $parentId)->first();
|
||||
if ($row && !empty($row['family_id'])) {
|
||||
$others = $fam->where('family_id', (int)$row['family_id'])
|
||||
->where('user_id !=', $parentId)
|
||||
->where('receive_emails', 1)->findAll();
|
||||
foreach ($others as $g) {
|
||||
$ccEmail = $user->select('email')->find((int)$g['user_id'])['email'] ?? null;
|
||||
if ($ccEmail && filter_var($ccEmail, FILTER_VALIDATE_EMAIL)) break;
|
||||
$ccEmail = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compose body (reuse layout)
|
||||
$parentName = trim(($userRow['firstname'] ?? '') . ' ' . ($userRow['lastname'] ?? ''));
|
||||
$monthYear = $now->format('F Y');
|
||||
$subject = sprintf('Monthly Tuition Reminder — %s', $schoolYear);
|
||||
$greeting = $parentName !== '' ? "Dear {$parentName}," : 'Dear Parent,';
|
||||
$balanceFmt = '$' . number_format($totalBalance, 2);
|
||||
$intro = ($type === 'no_payment')
|
||||
? "We noticed there are outstanding tuition charges for {$schoolYear} but no payment has been recorded yet."
|
||||
: "This is your monthly installment reminder for {$schoolYear}.";
|
||||
|
||||
$bodyHtml = <<<HTML
|
||||
<div style="font-family:Arial,Helvetica,sans-serif; font-size:14px; color:#212529; line-height:1.5;">
|
||||
<h2 style="margin:0 0 10px; font-size:18px;">Monthly Tuition Reminder (Test)</h2>
|
||||
<p>{$greeting}</p>
|
||||
<p>{$intro}</p>
|
||||
<p><strong>Current Outstanding Balance:</strong> {$balanceFmt}</p>
|
||||
<p>
|
||||
As a friendly reminder, our tuition installments are due at the beginning of each month.
|
||||
You can review your invoice and payment options by logging in to your parent portal.
|
||||
</p>
|
||||
<p>Thank you for your prompt attention.</p>
|
||||
<p><em>Reminder Period:</em> {$monthYear}</p>
|
||||
</div>
|
||||
HTML;
|
||||
// Compute remaining and max installments similar to Manual Payment UI
|
||||
$installmentEndRaw = (string)$config->getConfig('installment_date');
|
||||
$tz = new \DateTimeZone($tzName);
|
||||
$today = new \DateTimeImmutable('today', $tz);
|
||||
$end = null; try { if ($installmentEndRaw) { $end = new \DateTimeImmutable($installmentEndRaw, $tz); } } catch (\Throwable $e) { $end = null; }
|
||||
$remMonths = 0;
|
||||
if ($end) {
|
||||
$y = (int)$end->format('Y') - (int)$today->format('Y');
|
||||
$m = (int)$end->format('n') - (int)$today->format('n');
|
||||
$remMonths = $y * 12 + $m;
|
||||
if ((int)$end->format('j') > (int)$today->format('j')) $remMonths += 1;
|
||||
if ($remMonths < 0) $remMonths = 0;
|
||||
}
|
||||
$remainingInst = max(1, $remMonths);
|
||||
$maxInst = max(($remMonths ?: 0), ($totalBalance > 0 ? 2 : 0));
|
||||
$instDueFmt = '$' . number_format($remainingInst > 0 ? ($totalBalance / $remainingInst) : 0, 2);
|
||||
|
||||
$bodyHtml .= "<ul>"
|
||||
. "<li><strong>Remaining installments:</strong> {$remainingInst}</li>"
|
||||
. "<li><strong>Suggested installment this month:</strong> {$instDueFmt}</li>"
|
||||
. "<li><strong>Maximum installments available:</strong> {$maxInst}</li>"
|
||||
. "</ul>";
|
||||
|
||||
$body = view('emails/_wrap_layout', [ 'title' => 'Monthly Tuition Reminder', 'body_html' => $bodyHtml ], ['saveData' => true]);
|
||||
|
||||
$ok = $mailer->send($email, $subject, $body, 'finance');
|
||||
if ($ok && $ccEmail && strcasecmp($ccEmail, $email) !== 0) {
|
||||
$mailer->send($ccEmail, $subject, $body, 'finance');
|
||||
}
|
||||
|
||||
$existing = $logs->where('parent_id', $parentId)
|
||||
->where('period_year', $year)
|
||||
->where('period_month', $month)
|
||||
->where('type', $type)
|
||||
->first();
|
||||
|
||||
$payload = [
|
||||
'parent_id' => $parentId,
|
||||
'invoice_id' => $latestInvoiceId,
|
||||
'school_year' => $schoolYear,
|
||||
'period_year' => $year,
|
||||
'period_month' => $month,
|
||||
'type' => $type,
|
||||
'to_email' => $email,
|
||||
'cc_email' => $ccEmail,
|
||||
'head_fa_notified' => 0,
|
||||
'subject' => $subject,
|
||||
'body' => $body,
|
||||
'status' => $ok ? 'sent' : 'failed',
|
||||
'error_message' => $ok ? null : 'Email send failed (see logs)',
|
||||
'balance_snapshot' => $totalBalance,
|
||||
'sent_at' => $now->format('Y-m-d H:i:s'),
|
||||
];
|
||||
if ($existing) $logs->update($existing['id'], $payload); else $logs->insert($payload);
|
||||
|
||||
CLI::write(($ok ? 'Sent' : 'Failed') . " test reminder to {$email}", $ok ? 'green' : 'red');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user