add notifications logic and add support of both JWT and Sanctum
This commit is contained in:
@@ -0,0 +1,223 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\School;
|
||||
|
||||
use App\Services\EmailService;
|
||||
use App\Services\Notifications\UserNotificationDispatchService;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class PaymentEventService
|
||||
{
|
||||
public function __construct(
|
||||
private EmailService $emailService,
|
||||
private UserNotificationDispatchService $notifier
|
||||
) {
|
||||
}
|
||||
|
||||
public function paymentReceived(array $data, array $studentdata = []): array
|
||||
{
|
||||
$parentName = trim((string) ($data['firstname'] ?? '') . ' ' . (string) ($data['lastname'] ?? ''));
|
||||
|
||||
$fmtMoney = static fn ($v) => '$' . number_format((float) $v, 2);
|
||||
$fmtDateTz = static function (?string $s): string {
|
||||
if (!$s) {
|
||||
return '';
|
||||
}
|
||||
$dt = new \DateTime($s, new \DateTimeZone('UTC'));
|
||||
$tzName = (string) (config('School')->attendance['timezone'] ?? user_timezone());
|
||||
$dt->setTimezone(new \DateTimeZone($tzName ?: 'UTC'));
|
||||
return $dt->format('m-d-Y h:i A');
|
||||
};
|
||||
|
||||
$txid = $data['transaction_id']
|
||||
?? $data['transactionId']
|
||||
?? $data['payment_id']
|
||||
?? $data['id']
|
||||
?? '';
|
||||
|
||||
$methodRaw = $data['payment_method'] ?? ($data['method'] ?? '');
|
||||
$method = $methodRaw ? ucfirst((string) $methodRaw) : '';
|
||||
|
||||
$amountPaid = $fmtMoney($data['amount'] ?? 0);
|
||||
$preBalance = $fmtMoney($data['pre_balance'] ?? 0);
|
||||
$postBalance = $fmtMoney($data['post_balance'] ?? 0);
|
||||
$invoiceTotal = $fmtMoney($data['invoice_total'] ?? 0);
|
||||
|
||||
$invoiceDiscountRaw = isset($data['invoice_discount']) ? (float) $data['invoice_discount'] : 0.0;
|
||||
$parentYearDiscountTotalRaw = isset($data['parent_year_discount_total']) ? (float) $data['parent_year_discount_total'] : 0.0;
|
||||
|
||||
$emailData = [
|
||||
'title' => 'Payment Receipt',
|
||||
'parentName' => $parentName,
|
||||
'schoolYear' => $data['school_year'] ?? '',
|
||||
'semester' => $data['semester'] ?? '',
|
||||
'invoiceId' => $data['invoice_id'] ?? null,
|
||||
'invoiceNumber' => $data['invoice_number'] ?? null,
|
||||
'transactionId' => $txid,
|
||||
'paymentDate' => $fmtDateTz($data['payment_date'] ?? null),
|
||||
'method' => $method,
|
||||
'paymentMethod' => $method,
|
||||
'amount' => $amountPaid,
|
||||
'invoiceTotal' => $invoiceTotal,
|
||||
'preBalance' => $preBalance,
|
||||
'postBalance' => $postBalance,
|
||||
'checkNumber' => $data['check_number'] ?? null,
|
||||
'installmentSeq' => (int) ($data['installment_seq'] ?? 1),
|
||||
'invoiceDiscount' => $invoiceDiscountRaw > 0 ? $fmtMoney($invoiceDiscountRaw) : null,
|
||||
'parentYearDiscountTotal' => $parentYearDiscountTotalRaw > 0 ? $fmtMoney($parentYearDiscountTotalRaw) : null,
|
||||
'portalLink' => url('/login'),
|
||||
'students' => $studentdata,
|
||||
];
|
||||
|
||||
$inAppTitle = 'Payment Received';
|
||||
$inAppMsg = sprintf(
|
||||
'We received %s for Invoice #%s (Installment #%d). New balance: %s. Check your email for details.',
|
||||
$emailData['amount'],
|
||||
(string) ($emailData['invoiceId'] ?? $emailData['invoiceNumber'] ?? ''),
|
||||
(int) $emailData['installmentSeq'],
|
||||
$emailData['postBalance']
|
||||
);
|
||||
$this->notifyUser((int) ($data['user_id'] ?? 0), $inAppTitle, $inAppMsg, 'payments');
|
||||
|
||||
$emailBody = $this->renderEmail('emails/payment_receipt', $emailData, 'Payment Receipt');
|
||||
$subject = sprintf(
|
||||
'Payment Receipt - Invoice #%s (%s) %s',
|
||||
(string) ($emailData['invoiceId'] ?? $emailData['invoiceNumber'] ?? ''),
|
||||
$emailData['amount'],
|
||||
$txid ? "[TX: {$txid}]" : ''
|
||||
);
|
||||
|
||||
return $this->sendEmail((string) ($data['email'] ?? ''), $subject, $emailBody, 'payments');
|
||||
}
|
||||
|
||||
public function extraCharge(array $data, array $studentdata = []): array
|
||||
{
|
||||
$fmtMoney = static fn ($v) => '$' . number_format((float) $v, 2);
|
||||
$fmtFromUtc = static function (?string $s, string $fmt = 'm-d-Y h:i A'): string {
|
||||
if (!$s) {
|
||||
return '';
|
||||
}
|
||||
try {
|
||||
$dt = new \DateTime($s, new \DateTimeZone('UTC'));
|
||||
$tzName = (string) (config('School')->attendance['timezone'] ?? user_timezone());
|
||||
$dt->setTimezone(new \DateTimeZone($tzName ?: 'UTC'));
|
||||
return $dt->format($fmt);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('extraCharge date error: ' . $e->getMessage());
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
$fmtDueLocal = static function (?string $s): string {
|
||||
if (!$s) {
|
||||
return '';
|
||||
}
|
||||
try {
|
||||
if (strlen($s) <= 10) {
|
||||
$tzName = (string) (config('School')->attendance['timezone'] ?? user_timezone());
|
||||
$dt = \DateTime::createFromFormat('Y-m-d', $s, new \DateTimeZone($tzName ?: 'UTC'));
|
||||
return $dt ? $dt->format('m-d-Y') : '';
|
||||
}
|
||||
|
||||
if (preg_match('/(Z|[+\-]\d{2}:\d{2})$/', $s)) {
|
||||
$dt = new \DateTime($s);
|
||||
$tzName = (string) (config('School')->attendance['timezone'] ?? user_timezone());
|
||||
$dt->setTimezone(new \DateTimeZone($tzName ?: 'UTC'));
|
||||
return $dt->format('m-d-Y h:i A');
|
||||
}
|
||||
|
||||
$tzName = (string) (config('School')->attendance['timezone'] ?? user_timezone());
|
||||
$dt = new \DateTime($s, new \DateTimeZone($tzName ?: 'UTC'));
|
||||
return $dt->format('m-d-Y h:i A');
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('extraCharge due date error: ' . $e->getMessage());
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
$parentName = trim((string) ($data['firstname'] ?? '') . ' ' . (string) ($data['lastname'] ?? ''));
|
||||
|
||||
$amountSigned = (float) ($data['amount_signed'] ?? 0);
|
||||
$amountAbs = (float) ($data['amount_abs'] ?? abs($amountSigned));
|
||||
$preBalance = $fmtMoney($data['pre_balance'] ?? 0);
|
||||
$postBalance = $fmtMoney($data['post_balance'] ?? 0);
|
||||
$invoiceTotal = $fmtMoney($data['invoice_total'] ?? 0);
|
||||
$createdAt = $fmtFromUtc($data['created_at'] ?? null);
|
||||
$dueDate = $fmtDueLocal($data['due_date'] ?? null);
|
||||
$typeLabel = (($data['charge_type'] ?? 'add') === 'add') ? 'Added charge' : 'Deducted amount';
|
||||
$amountFmt = $fmtMoney($amountSigned);
|
||||
|
||||
$emailData = [
|
||||
'title' => 'Account Charge Update',
|
||||
'parentName' => $parentName,
|
||||
'schoolYear' => $data['school_year'] ?? '',
|
||||
'semester' => $data['semester'] ?? '',
|
||||
'invoiceId' => $data['invoice_id'] ?? null,
|
||||
'invoiceNumber' => $data['invoice_number'] ?? null,
|
||||
'typeLabel' => $typeLabel,
|
||||
'chargeTitle' => $data['charge_title'] ?? '',
|
||||
'chargeDesc' => $data['charge_desc'] ?? '',
|
||||
'chargeType' => $data['charge_type'] ?? 'add',
|
||||
'amountSigned' => $amountFmt,
|
||||
'amountAbs' => $fmtMoney($amountAbs),
|
||||
'invoiceTotal' => $invoiceTotal,
|
||||
'preBalance' => $preBalance,
|
||||
'postBalance' => $postBalance,
|
||||
'createdAt' => $createdAt,
|
||||
'dueDate' => $dueDate !== '' ? $dueDate : null,
|
||||
'portalLink' => $data['portal_link'] ?? url('/login'),
|
||||
'invoiceLink' => $data['invoice_link'] ?? null,
|
||||
'students' => $studentdata,
|
||||
];
|
||||
|
||||
$inAppTitle = 'Account Updated';
|
||||
$inAppMsg = sprintf(
|
||||
'%s: %s (%s). New balance: %s.',
|
||||
$typeLabel,
|
||||
$emailData['chargeTitle'],
|
||||
$emailData['amountSigned'],
|
||||
$emailData['postBalance']
|
||||
);
|
||||
$this->notifyUser((int) ($data['user_id'] ?? 0), $inAppTitle, $inAppMsg, 'billing');
|
||||
|
||||
$subject = sprintf(
|
||||
'Charge Update - Invoice #%s (%s)',
|
||||
(string) ($emailData['invoiceId'] ?? $emailData['invoiceNumber'] ?? ''),
|
||||
$emailData['amountSigned']
|
||||
);
|
||||
|
||||
$body = $this->renderEmail('emails/extra_charge_notice', $emailData, 'Account Charge Update');
|
||||
return $this->sendEmail((string) ($data['email'] ?? ''), $subject, $body, 'billing');
|
||||
}
|
||||
|
||||
private function notifyUser(int $userId, string $title, string $message, string $topic): void
|
||||
{
|
||||
if ($userId <= 0) {
|
||||
return;
|
||||
}
|
||||
$this->notifier->notifyUser($userId, $title, $message, ['in_app'], $topic, 'parent');
|
||||
}
|
||||
|
||||
private function sendEmail(string $to, string $subject, string $html, string $fromKey): array
|
||||
{
|
||||
if ($to === '') {
|
||||
Log::warning('Payment event missing recipient email', ['subject' => $subject]);
|
||||
return ['ok' => false, 'message' => 'Missing recipient email.'];
|
||||
}
|
||||
|
||||
$ok = $this->emailService->send($to, $subject, $html, $fromKey);
|
||||
if (!$ok) {
|
||||
Log::error('Payment event email failed', ['to' => $to, 'subject' => $subject]);
|
||||
}
|
||||
return ['ok' => $ok];
|
||||
}
|
||||
|
||||
private function renderEmail(string $viewName, array $data, string $fallbackTitle): string
|
||||
{
|
||||
try {
|
||||
return view($viewName, $data, ['saveData' => true]);
|
||||
} catch (\Throwable $e) {
|
||||
return '<p>' . e($fallbackTitle) . '</p>';
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user