verbesserung von benachrichtungen und warnungen an nutzer abgeschlossen. layout editor nun auf gutem stand.
This commit is contained in:
250
app/Console/Commands/RetryTenantNotification.php
Normal file
250
app/Console/Commands/RetryTenantNotification.php
Normal file
@@ -0,0 +1,250 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Jobs\Packages\SendEventPackageGalleryExpired;
|
||||
use App\Jobs\Packages\SendEventPackageGalleryWarning;
|
||||
use App\Jobs\Packages\SendEventPackageGuestLimitNotification;
|
||||
use App\Jobs\Packages\SendEventPackageGuestThresholdWarning;
|
||||
use App\Jobs\Packages\SendEventPackagePhotoLimitNotification;
|
||||
use App\Jobs\Packages\SendEventPackagePhotoThresholdWarning;
|
||||
use App\Jobs\Packages\SendTenantCreditsLowNotification;
|
||||
use App\Jobs\Packages\SendTenantPackageEventLimitNotification;
|
||||
use App\Jobs\Packages\SendTenantPackageEventThresholdWarning;
|
||||
use App\Jobs\Packages\SendTenantPackageExpiredNotification;
|
||||
use App\Jobs\Packages\SendTenantPackageExpiringNotification;
|
||||
use App\Models\TenantNotificationLog;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class RetryTenantNotification extends Command
|
||||
{
|
||||
protected $signature = 'tenant:notifications:retry {log_id?} {--tenant=} {--status=failed}';
|
||||
|
||||
protected $description = 'Retry tenant package limit notifications based on stored notification logs.';
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$query = TenantNotificationLog::query();
|
||||
|
||||
if ($logId = $this->argument('log_id')) {
|
||||
$query->whereKey($logId);
|
||||
}
|
||||
|
||||
if ($tenantId = $this->option('tenant')) {
|
||||
$query->where('tenant_id', $tenantId);
|
||||
}
|
||||
|
||||
if ($status = $this->option('status')) {
|
||||
$query->where('status', $status);
|
||||
}
|
||||
|
||||
$logs = $query->orderBy('id')->get();
|
||||
|
||||
if ($logs->isEmpty()) {
|
||||
$this->warn('No notification logs matched the given filters.');
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
foreach ($logs as $log) {
|
||||
$dispatched = $this->dispatchForLog($log);
|
||||
|
||||
if ($dispatched) {
|
||||
$log->forceFill([
|
||||
'status' => 'queued',
|
||||
'failed_at' => null,
|
||||
'failure_reason' => null,
|
||||
])->save();
|
||||
|
||||
$this->info("Queued retry for log #{$log->id} ({$log->type})");
|
||||
} else {
|
||||
$this->warn("Skipped log #{$log->id} ({$log->type}) – missing context");
|
||||
}
|
||||
}
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
private function dispatchForLog(TenantNotificationLog $log): bool
|
||||
{
|
||||
$context = $log->context ?? [];
|
||||
|
||||
return match ($log->type) {
|
||||
'photo_threshold' => $this->dispatchPhotoThreshold($context),
|
||||
'photo_limit' => $this->dispatchPhotoLimit($context),
|
||||
'guest_threshold' => $this->dispatchGuestThreshold($context),
|
||||
'guest_limit' => $this->dispatchGuestLimit($context),
|
||||
'gallery_warning' => $this->dispatchGalleryWarning($context),
|
||||
'gallery_expired' => $this->dispatchGalleryExpired($context),
|
||||
'credits_low' => $this->dispatchCreditsLow($log->tenant_id, $context),
|
||||
'event_threshold' => $this->dispatchEventThreshold($context),
|
||||
'event_limit' => $this->dispatchEventLimit($context),
|
||||
'package_expiring' => $this->dispatchPackageExpiring($context),
|
||||
'package_expired' => $this->dispatchPackageExpired($context),
|
||||
default => false,
|
||||
};
|
||||
}
|
||||
|
||||
private function dispatchPhotoThreshold(array $context): bool
|
||||
{
|
||||
$eventPackageId = Arr::get($context, 'event_package_id');
|
||||
$threshold = Arr::get($context, 'threshold');
|
||||
$limit = Arr::get($context, 'limit');
|
||||
$used = Arr::get($context, 'used');
|
||||
|
||||
if ($eventPackageId === null || $threshold === null || $limit === null || $used === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SendEventPackagePhotoThresholdWarning::dispatch($eventPackageId, (float) $threshold, (int) $limit, (int) $used);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function dispatchPhotoLimit(array $context): bool
|
||||
{
|
||||
$eventPackageId = Arr::get($context, 'event_package_id');
|
||||
$limit = Arr::get($context, 'limit');
|
||||
|
||||
if ($eventPackageId === null || $limit === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SendEventPackagePhotoLimitNotification::dispatch($eventPackageId, (int) $limit);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function dispatchGuestThreshold(array $context): bool
|
||||
{
|
||||
$eventPackageId = Arr::get($context, 'event_package_id');
|
||||
$threshold = Arr::get($context, 'threshold');
|
||||
$limit = Arr::get($context, 'limit');
|
||||
$used = Arr::get($context, 'used');
|
||||
|
||||
if ($eventPackageId === null || $threshold === null || $limit === null || $used === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SendEventPackageGuestThresholdWarning::dispatch($eventPackageId, (float) $threshold, (int) $limit, (int) $used);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function dispatchGuestLimit(array $context): bool
|
||||
{
|
||||
$eventPackageId = Arr::get($context, 'event_package_id');
|
||||
$limit = Arr::get($context, 'limit');
|
||||
|
||||
if ($eventPackageId === null || $limit === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SendEventPackageGuestLimitNotification::dispatch($eventPackageId, (int) $limit);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function dispatchGalleryWarning(array $context): bool
|
||||
{
|
||||
$eventPackageId = Arr::get($context, 'event_package_id');
|
||||
$days = Arr::get($context, 'days_remaining');
|
||||
|
||||
if ($eventPackageId === null || $days === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SendEventPackageGalleryWarning::dispatch($eventPackageId, (int) $days);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function dispatchGalleryExpired(array $context): bool
|
||||
{
|
||||
$eventPackageId = Arr::get($context, 'event_package_id');
|
||||
|
||||
if ($eventPackageId === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SendEventPackageGalleryExpired::dispatch($eventPackageId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function dispatchCreditsLow(int $tenantId, array $context): bool
|
||||
{
|
||||
$balance = Arr::get($context, 'balance');
|
||||
$threshold = Arr::get($context, 'threshold');
|
||||
|
||||
if ($balance === null || $threshold === null) {
|
||||
Log::warning('credits_low retry missing balance or threshold', compact('tenantId', 'context'));
|
||||
}
|
||||
|
||||
$balance = $balance !== null ? (int) $balance : 0;
|
||||
$threshold = $threshold !== null ? (int) $threshold : 0;
|
||||
|
||||
SendTenantCreditsLowNotification::dispatch($tenantId, $balance, $threshold);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function dispatchEventThreshold(array $context): bool
|
||||
{
|
||||
$tenantPackageId = Arr::get($context, 'tenant_package_id');
|
||||
$threshold = Arr::get($context, 'threshold');
|
||||
$limit = Arr::get($context, 'limit');
|
||||
$used = Arr::get($context, 'used');
|
||||
|
||||
if ($tenantPackageId === null || $threshold === null || $limit === null || $used === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SendTenantPackageEventThresholdWarning::dispatch($tenantPackageId, (float) $threshold, (int) $limit, (int) $used);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function dispatchEventLimit(array $context): bool
|
||||
{
|
||||
$tenantPackageId = Arr::get($context, 'tenant_package_id');
|
||||
$limit = Arr::get($context, 'limit');
|
||||
|
||||
if ($tenantPackageId === null || $limit === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SendTenantPackageEventLimitNotification::dispatch($tenantPackageId, (int) $limit);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function dispatchPackageExpiring(array $context): bool
|
||||
{
|
||||
$tenantPackageId = Arr::get($context, 'tenant_package_id');
|
||||
$days = Arr::get($context, 'days_remaining');
|
||||
|
||||
if ($tenantPackageId === null || $days === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SendTenantPackageExpiringNotification::dispatch($tenantPackageId, (int) $days);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function dispatchPackageExpired(array $context): bool
|
||||
{
|
||||
$tenantPackageId = Arr::get($context, 'tenant_package_id');
|
||||
|
||||
if ($tenantPackageId === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SendTenantPackageExpiredNotification::dispatch($tenantPackageId);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Tenant;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\TenantNotificationLog;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class NotificationLogController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$tenant = $request->attributes->get('tenant') ?? $request->user()?->tenant;
|
||||
|
||||
if (! $tenant) {
|
||||
return response()->json([
|
||||
'error' => [
|
||||
'code' => 'tenant_context_missing',
|
||||
'title' => 'Tenant context missing',
|
||||
'message' => 'Unable to resolve tenant for notification logs.',
|
||||
],
|
||||
], 403);
|
||||
}
|
||||
|
||||
$query = TenantNotificationLog::query()
|
||||
->where('tenant_id', $tenant->id)
|
||||
->latest();
|
||||
|
||||
if ($type = $request->query('type')) {
|
||||
$query->where('type', $type);
|
||||
}
|
||||
|
||||
if ($status = $request->query('status')) {
|
||||
$query->where('status', $status);
|
||||
}
|
||||
|
||||
$perPage = (int) $request->query('per_page', 20);
|
||||
$perPage = max(1, min($perPage, 100));
|
||||
|
||||
$logs = $query->paginate($perPage);
|
||||
|
||||
return response()->json([
|
||||
'data' => $logs->items(),
|
||||
'meta' => [
|
||||
'current_page' => $logs->currentPage(),
|
||||
'last_page' => $logs->lastPage(),
|
||||
'per_page' => $logs->perPage(),
|
||||
'total' => $logs->total(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
60
app/Jobs/Concerns/LogsTenantNotifications.php
Normal file
60
app/Jobs/Concerns/LogsTenantNotifications.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs\Concerns;
|
||||
|
||||
use App\Models\Tenant;
|
||||
use App\Services\Packages\TenantNotificationLogger;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
trait LogsTenantNotifications
|
||||
{
|
||||
protected function notificationLogger(): TenantNotificationLogger
|
||||
{
|
||||
return app(TenantNotificationLogger::class);
|
||||
}
|
||||
|
||||
protected function logNotification(Tenant $tenant, array $attributes): void
|
||||
{
|
||||
$this->notificationLogger()->log($tenant, $attributes);
|
||||
}
|
||||
|
||||
protected function dispatchToRecipients(
|
||||
Tenant $tenant,
|
||||
iterable $recipients,
|
||||
string $type,
|
||||
callable $callback,
|
||||
array $context = []
|
||||
): void {
|
||||
foreach ($recipients as $recipient) {
|
||||
try {
|
||||
$callback($recipient);
|
||||
|
||||
$this->logNotification($tenant, [
|
||||
'type' => $type,
|
||||
'channel' => 'mail',
|
||||
'recipient' => $recipient,
|
||||
'status' => 'sent',
|
||||
'context' => $context,
|
||||
'sent_at' => now(),
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Tenant notification failed', [
|
||||
'tenant_id' => $tenant->id,
|
||||
'type' => $type,
|
||||
'recipient' => $recipient,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
|
||||
$this->logNotification($tenant, [
|
||||
'type' => $type,
|
||||
'channel' => 'mail',
|
||||
'recipient' => $recipient,
|
||||
'status' => 'failed',
|
||||
'context' => $context,
|
||||
'failed_at' => now(),
|
||||
'failure_reason' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Jobs\Packages;
|
||||
|
||||
use App\Jobs\Concerns\LogsTenantNotifications;
|
||||
use App\Models\EventPackage;
|
||||
use App\Notifications\Packages\EventPackageGalleryExpiredNotification;
|
||||
use Illuminate\Bus\Queueable;
|
||||
@@ -16,6 +17,7 @@ class SendEventPackageGalleryExpired implements ShouldQueue
|
||||
{
|
||||
use Dispatchable;
|
||||
use InteractsWithQueue;
|
||||
use LogsTenantNotifications;
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
@@ -40,6 +42,12 @@ class SendEventPackageGalleryExpired implements ShouldQueue
|
||||
|
||||
$preferences = app(\App\Services\Packages\TenantNotificationPreferences::class);
|
||||
if (! $preferences->shouldNotify($tenant, 'gallery_expired')) {
|
||||
$this->logNotification($tenant, [
|
||||
'type' => 'gallery_expired',
|
||||
'status' => 'skipped',
|
||||
'context' => $this->context($eventPackage),
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -54,11 +62,33 @@ class SendEventPackageGalleryExpired implements ShouldQueue
|
||||
'event_package_id' => $eventPackage->id,
|
||||
]);
|
||||
|
||||
$this->logNotification($tenant, [
|
||||
'type' => 'gallery_expired',
|
||||
'status' => 'skipped',
|
||||
'context' => array_merge($this->context($eventPackage), ['reason' => 'no_recipient']),
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($emails as $email) {
|
||||
Notification::route('mail', $email)->notify(new EventPackageGalleryExpiredNotification($eventPackage));
|
||||
}
|
||||
$context = $this->context($eventPackage);
|
||||
|
||||
$this->dispatchToRecipients(
|
||||
$tenant,
|
||||
$emails,
|
||||
'gallery_expired',
|
||||
function (string $email) use ($eventPackage) {
|
||||
Notification::route('mail', $email)->notify(new EventPackageGalleryExpiredNotification($eventPackage));
|
||||
},
|
||||
$context
|
||||
);
|
||||
}
|
||||
|
||||
private function context(EventPackage $eventPackage): array
|
||||
{
|
||||
return [
|
||||
'event_package_id' => $eventPackage->id,
|
||||
'event_id' => $eventPackage->event_id,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Jobs\Packages;
|
||||
|
||||
use App\Jobs\Concerns\LogsTenantNotifications;
|
||||
use App\Models\EventPackage;
|
||||
use App\Notifications\Packages\EventPackageGalleryExpiringNotification;
|
||||
use Illuminate\Bus\Queueable;
|
||||
@@ -16,6 +17,7 @@ class SendEventPackageGalleryWarning implements ShouldQueue
|
||||
{
|
||||
use Dispatchable;
|
||||
use InteractsWithQueue;
|
||||
use LogsTenantNotifications;
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
@@ -43,6 +45,12 @@ class SendEventPackageGalleryWarning implements ShouldQueue
|
||||
|
||||
$preferences = app(\App\Services\Packages\TenantNotificationPreferences::class);
|
||||
if (! $preferences->shouldNotify($tenant, 'gallery_warnings')) {
|
||||
$this->logNotification($tenant, [
|
||||
'type' => 'gallery_warning',
|
||||
'status' => 'skipped',
|
||||
'context' => $this->context($eventPackage),
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -58,14 +66,37 @@ class SendEventPackageGalleryWarning implements ShouldQueue
|
||||
'days_remaining' => $this->daysRemaining,
|
||||
]);
|
||||
|
||||
$this->logNotification($tenant, [
|
||||
'type' => 'gallery_warning',
|
||||
'status' => 'skipped',
|
||||
'context' => array_merge($this->context($eventPackage), ['reason' => 'no_recipient']),
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($emails as $email) {
|
||||
Notification::route('mail', $email)->notify(new EventPackageGalleryExpiringNotification(
|
||||
$eventPackage,
|
||||
$this->daysRemaining,
|
||||
));
|
||||
}
|
||||
$context = $this->context($eventPackage);
|
||||
|
||||
$this->dispatchToRecipients(
|
||||
$tenant,
|
||||
$emails,
|
||||
'gallery_warning',
|
||||
function (string $email) use ($eventPackage) {
|
||||
Notification::route('mail', $email)->notify(new EventPackageGalleryExpiringNotification(
|
||||
$eventPackage,
|
||||
$this->daysRemaining,
|
||||
));
|
||||
},
|
||||
$context
|
||||
);
|
||||
}
|
||||
|
||||
private function context(EventPackage $eventPackage): array
|
||||
{
|
||||
return [
|
||||
'event_package_id' => $eventPackage->id,
|
||||
'event_id' => $eventPackage->event_id,
|
||||
'days_remaining' => $this->daysRemaining,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Jobs\Packages;
|
||||
|
||||
use App\Jobs\Concerns\LogsTenantNotifications;
|
||||
use App\Models\EventPackage;
|
||||
use App\Notifications\Packages\EventPackageGuestLimitNotification;
|
||||
use Illuminate\Bus\Queueable;
|
||||
@@ -16,6 +17,7 @@ class SendEventPackageGuestLimitNotification implements ShouldQueue
|
||||
{
|
||||
use Dispatchable;
|
||||
use InteractsWithQueue;
|
||||
use LogsTenantNotifications;
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
@@ -43,6 +45,12 @@ class SendEventPackageGuestLimitNotification implements ShouldQueue
|
||||
|
||||
$preferences = app(\App\Services\Packages\TenantNotificationPreferences::class);
|
||||
if (! $preferences->shouldNotify($tenant, 'guest_limits')) {
|
||||
$this->logNotification($tenant, [
|
||||
'type' => 'guest_limit',
|
||||
'status' => 'skipped',
|
||||
'context' => $this->context($eventPackage),
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -57,14 +65,37 @@ class SendEventPackageGuestLimitNotification implements ShouldQueue
|
||||
'event_package_id' => $eventPackage->id,
|
||||
]);
|
||||
|
||||
$this->logNotification($tenant, [
|
||||
'type' => 'guest_limit',
|
||||
'status' => 'skipped',
|
||||
'context' => array_merge($this->context($eventPackage), ['reason' => 'no_recipient']),
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($emails as $email) {
|
||||
Notification::route('mail', $email)->notify(new EventPackageGuestLimitNotification(
|
||||
$eventPackage,
|
||||
$this->limit,
|
||||
));
|
||||
}
|
||||
$context = $this->context($eventPackage);
|
||||
|
||||
$this->dispatchToRecipients(
|
||||
$tenant,
|
||||
$emails,
|
||||
'guest_limit',
|
||||
function (string $email) use ($eventPackage) {
|
||||
Notification::route('mail', $email)->notify(new EventPackageGuestLimitNotification(
|
||||
$eventPackage,
|
||||
$this->limit,
|
||||
));
|
||||
},
|
||||
$context
|
||||
);
|
||||
}
|
||||
|
||||
private function context(EventPackage $eventPackage): array
|
||||
{
|
||||
return [
|
||||
'event_package_id' => $eventPackage->id,
|
||||
'event_id' => $eventPackage->event_id,
|
||||
'limit' => $this->limit,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Jobs\Packages;
|
||||
|
||||
use App\Jobs\Concerns\LogsTenantNotifications;
|
||||
use App\Models\EventPackage;
|
||||
use App\Notifications\Packages\EventPackageGuestThresholdNotification;
|
||||
use Illuminate\Bus\Queueable;
|
||||
@@ -16,6 +17,7 @@ class SendEventPackageGuestThresholdWarning implements ShouldQueue
|
||||
{
|
||||
use Dispatchable;
|
||||
use InteractsWithQueue;
|
||||
use LogsTenantNotifications;
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
@@ -45,6 +47,12 @@ class SendEventPackageGuestThresholdWarning implements ShouldQueue
|
||||
|
||||
$preferences = app(\App\Services\Packages\TenantNotificationPreferences::class);
|
||||
if (! $preferences->shouldNotify($tenant, 'guest_thresholds')) {
|
||||
$this->logNotification($tenant, [
|
||||
'type' => 'guest_threshold',
|
||||
'status' => 'skipped',
|
||||
'context' => $this->context($eventPackage),
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -60,16 +68,41 @@ class SendEventPackageGuestThresholdWarning implements ShouldQueue
|
||||
'threshold' => $this->threshold,
|
||||
]);
|
||||
|
||||
$this->logNotification($tenant, [
|
||||
'type' => 'guest_threshold',
|
||||
'status' => 'skipped',
|
||||
'context' => array_merge($this->context($eventPackage), ['reason' => 'no_recipient']),
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($emails as $email) {
|
||||
Notification::route('mail', $email)->notify(new EventPackageGuestThresholdNotification(
|
||||
$eventPackage,
|
||||
$this->threshold,
|
||||
$this->limit,
|
||||
$this->used,
|
||||
));
|
||||
}
|
||||
$context = $this->context($eventPackage);
|
||||
|
||||
$this->dispatchToRecipients(
|
||||
$tenant,
|
||||
$emails,
|
||||
'guest_threshold',
|
||||
function (string $email) use ($eventPackage) {
|
||||
Notification::route('mail', $email)->notify(new EventPackageGuestThresholdNotification(
|
||||
$eventPackage,
|
||||
$this->threshold,
|
||||
$this->limit,
|
||||
$this->used,
|
||||
));
|
||||
},
|
||||
$context
|
||||
);
|
||||
}
|
||||
|
||||
private function context(EventPackage $eventPackage): array
|
||||
{
|
||||
return [
|
||||
'event_package_id' => $eventPackage->id,
|
||||
'event_id' => $eventPackage->event_id,
|
||||
'threshold' => $this->threshold,
|
||||
'limit' => $this->limit,
|
||||
'used' => $this->used,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Jobs\Packages;
|
||||
|
||||
use App\Jobs\Concerns\LogsTenantNotifications;
|
||||
use App\Models\EventPackage;
|
||||
use App\Notifications\Packages\EventPackagePhotoLimitNotification;
|
||||
use Illuminate\Bus\Queueable;
|
||||
@@ -16,6 +17,7 @@ class SendEventPackagePhotoLimitNotification implements ShouldQueue
|
||||
{
|
||||
use Dispatchable;
|
||||
use InteractsWithQueue;
|
||||
use LogsTenantNotifications;
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
@@ -43,6 +45,12 @@ class SendEventPackagePhotoLimitNotification implements ShouldQueue
|
||||
|
||||
$preferences = app(\App\Services\Packages\TenantNotificationPreferences::class);
|
||||
if (! $preferences->shouldNotify($tenant, 'photo_limits')) {
|
||||
$this->logNotification($tenant, [
|
||||
'type' => 'photo_limit',
|
||||
'status' => 'skipped',
|
||||
'context' => $this->context($eventPackage),
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -58,16 +66,39 @@ class SendEventPackagePhotoLimitNotification implements ShouldQueue
|
||||
'limit' => $this->limit,
|
||||
]);
|
||||
|
||||
$this->logNotification($tenant, [
|
||||
'type' => 'photo_limit',
|
||||
'status' => 'skipped',
|
||||
'context' => array_merge($this->context($eventPackage), ['reason' => 'no_recipient']),
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($emails as $email) {
|
||||
Notification::route('mail', $email)->notify(
|
||||
new EventPackagePhotoLimitNotification(
|
||||
$eventPackage,
|
||||
$this->limit,
|
||||
)
|
||||
);
|
||||
}
|
||||
$context = $this->context($eventPackage);
|
||||
|
||||
$this->dispatchToRecipients(
|
||||
$tenant,
|
||||
$emails,
|
||||
'photo_limit',
|
||||
function (string $email) use ($eventPackage) {
|
||||
Notification::route('mail', $email)->notify(
|
||||
new EventPackagePhotoLimitNotification(
|
||||
$eventPackage,
|
||||
$this->limit,
|
||||
)
|
||||
);
|
||||
},
|
||||
$context
|
||||
);
|
||||
}
|
||||
|
||||
private function context(EventPackage $eventPackage): array
|
||||
{
|
||||
return [
|
||||
'event_package_id' => $eventPackage->id,
|
||||
'event_id' => $eventPackage->event_id,
|
||||
'limit' => $this->limit,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Jobs\Packages;
|
||||
|
||||
use App\Jobs\Concerns\LogsTenantNotifications;
|
||||
use App\Models\EventPackage;
|
||||
use App\Notifications\Packages\EventPackagePhotoThresholdNotification;
|
||||
use Illuminate\Bus\Queueable;
|
||||
@@ -16,6 +17,7 @@ class SendEventPackagePhotoThresholdWarning implements ShouldQueue
|
||||
{
|
||||
use Dispatchable;
|
||||
use InteractsWithQueue;
|
||||
use LogsTenantNotifications;
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
@@ -45,6 +47,12 @@ class SendEventPackagePhotoThresholdWarning implements ShouldQueue
|
||||
|
||||
$preferences = app(\App\Services\Packages\TenantNotificationPreferences::class);
|
||||
if (! $preferences->shouldNotify($tenant, 'photo_thresholds')) {
|
||||
$this->logNotification($tenant, [
|
||||
'type' => 'photo_threshold',
|
||||
'status' => 'skipped',
|
||||
'context' => $this->context($eventPackage),
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -60,18 +68,43 @@ class SendEventPackagePhotoThresholdWarning implements ShouldQueue
|
||||
'threshold' => $this->threshold,
|
||||
]);
|
||||
|
||||
$this->logNotification($tenant, [
|
||||
'type' => 'photo_threshold',
|
||||
'status' => 'skipped',
|
||||
'context' => array_merge($this->context($eventPackage), ['reason' => 'no_recipient']),
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($emails as $email) {
|
||||
Notification::route('mail', $email)->notify(
|
||||
new EventPackagePhotoThresholdNotification(
|
||||
$eventPackage,
|
||||
$this->threshold,
|
||||
$this->limit,
|
||||
$this->used,
|
||||
)
|
||||
);
|
||||
}
|
||||
$context = $this->context($eventPackage);
|
||||
|
||||
$this->dispatchToRecipients(
|
||||
$tenant,
|
||||
$emails,
|
||||
'photo_threshold',
|
||||
function (string $email) use ($eventPackage) {
|
||||
Notification::route('mail', $email)->notify(
|
||||
new EventPackagePhotoThresholdNotification(
|
||||
$eventPackage,
|
||||
$this->threshold,
|
||||
$this->limit,
|
||||
$this->used,
|
||||
)
|
||||
);
|
||||
},
|
||||
$context
|
||||
);
|
||||
}
|
||||
|
||||
private function context(EventPackage $eventPackage): array
|
||||
{
|
||||
return [
|
||||
'event_package_id' => $eventPackage->id,
|
||||
'event_id' => $eventPackage->event_id,
|
||||
'threshold' => $this->threshold,
|
||||
'limit' => $this->limit,
|
||||
'used' => $this->used,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Jobs\Packages;
|
||||
|
||||
use App\Jobs\Concerns\LogsTenantNotifications;
|
||||
use App\Models\Tenant;
|
||||
use App\Notifications\Packages\TenantCreditsLowNotification;
|
||||
use Illuminate\Bus\Queueable;
|
||||
@@ -16,6 +17,7 @@ class SendTenantCreditsLowNotification implements ShouldQueue
|
||||
{
|
||||
use Dispatchable;
|
||||
use InteractsWithQueue;
|
||||
use LogsTenantNotifications;
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
@@ -39,6 +41,16 @@ class SendTenantCreditsLowNotification implements ShouldQueue
|
||||
|
||||
$preferences = app(\App\Services\Packages\TenantNotificationPreferences::class);
|
||||
if (! $preferences->shouldNotify($tenant, 'credits_low')) {
|
||||
$this->logNotification($tenant, [
|
||||
'type' => 'credits_low',
|
||||
'status' => 'skipped',
|
||||
'context' => [
|
||||
'balance' => $this->balance,
|
||||
'threshold' => $this->threshold,
|
||||
'reason' => 'opt_out',
|
||||
],
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -53,15 +65,36 @@ class SendTenantCreditsLowNotification implements ShouldQueue
|
||||
'tenant_id' => $tenant->id,
|
||||
]);
|
||||
|
||||
$this->logNotification($tenant, [
|
||||
'type' => 'credits_low',
|
||||
'status' => 'skipped',
|
||||
'context' => [
|
||||
'balance' => $this->balance,
|
||||
'threshold' => $this->threshold,
|
||||
'reason' => 'no_recipient',
|
||||
],
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($emails as $email) {
|
||||
Notification::route('mail', $email)->notify(new TenantCreditsLowNotification(
|
||||
$tenant,
|
||||
$this->balance,
|
||||
$this->threshold,
|
||||
));
|
||||
}
|
||||
$context = [
|
||||
'balance' => $this->balance,
|
||||
'threshold' => $this->threshold,
|
||||
];
|
||||
|
||||
$this->dispatchToRecipients(
|
||||
$tenant,
|
||||
$emails,
|
||||
'credits_low',
|
||||
function (string $email) use ($tenant) {
|
||||
Notification::route('mail', $email)->notify(new TenantCreditsLowNotification(
|
||||
$tenant,
|
||||
$this->balance,
|
||||
$this->threshold,
|
||||
));
|
||||
},
|
||||
$context
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Jobs\Packages;
|
||||
|
||||
use App\Jobs\Concerns\LogsTenantNotifications;
|
||||
use App\Models\TenantPackage;
|
||||
use App\Notifications\Packages\TenantPackageEventLimitNotification;
|
||||
use Illuminate\Bus\Queueable;
|
||||
@@ -16,6 +17,7 @@ class SendTenantPackageEventLimitNotification implements ShouldQueue
|
||||
{
|
||||
use Dispatchable;
|
||||
use InteractsWithQueue;
|
||||
use LogsTenantNotifications;
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
@@ -36,14 +38,22 @@ class SendTenantPackageEventLimitNotification implements ShouldQueue
|
||||
return;
|
||||
}
|
||||
|
||||
$tenant = $tenantPackage->tenant;
|
||||
|
||||
$preferences = app(\App\Services\Packages\TenantNotificationPreferences::class);
|
||||
if (! $preferences->shouldNotify($tenantPackage->tenant, 'event_limits')) {
|
||||
if (! $preferences->shouldNotify($tenant, 'event_limits')) {
|
||||
$this->logNotification($tenant, [
|
||||
'type' => 'event_limit',
|
||||
'status' => 'skipped',
|
||||
'context' => $this->context($tenantPackage),
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$emails = collect([
|
||||
$tenantPackage->tenant->contact_email,
|
||||
$tenantPackage->tenant->user?->email,
|
||||
$tenant->contact_email,
|
||||
$tenant->user?->email,
|
||||
])->filter(fn ($email) => is_string($email) && filter_var($email, FILTER_VALIDATE_EMAIL))
|
||||
->unique();
|
||||
|
||||
@@ -52,14 +62,36 @@ class SendTenantPackageEventLimitNotification implements ShouldQueue
|
||||
'tenant_package_id' => $tenantPackage->id,
|
||||
]);
|
||||
|
||||
$this->logNotification($tenant, [
|
||||
'type' => 'event_limit',
|
||||
'status' => 'skipped',
|
||||
'context' => array_merge($this->context($tenantPackage), ['reason' => 'no_recipient']),
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($emails as $email) {
|
||||
Notification::route('mail', $email)->notify(new TenantPackageEventLimitNotification(
|
||||
$tenantPackage,
|
||||
$this->limit,
|
||||
));
|
||||
}
|
||||
$context = $this->context($tenantPackage);
|
||||
|
||||
$this->dispatchToRecipients(
|
||||
$tenant,
|
||||
$emails,
|
||||
'event_limit',
|
||||
function (string $email) use ($tenantPackage) {
|
||||
Notification::route('mail', $email)->notify(new TenantPackageEventLimitNotification(
|
||||
$tenantPackage,
|
||||
$this->limit,
|
||||
));
|
||||
},
|
||||
$context
|
||||
);
|
||||
}
|
||||
|
||||
private function context(TenantPackage $tenantPackage): array
|
||||
{
|
||||
return [
|
||||
'tenant_package_id' => $tenantPackage->id,
|
||||
'limit' => $this->limit,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Jobs\Packages;
|
||||
|
||||
use App\Jobs\Concerns\LogsTenantNotifications;
|
||||
use App\Models\TenantPackage;
|
||||
use App\Notifications\Packages\TenantPackageEventThresholdNotification;
|
||||
use Illuminate\Bus\Queueable;
|
||||
@@ -16,6 +17,7 @@ class SendTenantPackageEventThresholdWarning implements ShouldQueue
|
||||
{
|
||||
use Dispatchable;
|
||||
use InteractsWithQueue;
|
||||
use LogsTenantNotifications;
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
@@ -38,14 +40,22 @@ class SendTenantPackageEventThresholdWarning implements ShouldQueue
|
||||
return;
|
||||
}
|
||||
|
||||
$tenant = $tenantPackage->tenant;
|
||||
|
||||
$preferences = app(\App\Services\Packages\TenantNotificationPreferences::class);
|
||||
if (! $preferences->shouldNotify($tenantPackage->tenant, 'event_thresholds')) {
|
||||
if (! $preferences->shouldNotify($tenant, 'event_thresholds')) {
|
||||
$this->logNotification($tenant, [
|
||||
'type' => 'event_threshold',
|
||||
'status' => 'skipped',
|
||||
'context' => $this->context($tenantPackage),
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$emails = collect([
|
||||
$tenantPackage->tenant->contact_email,
|
||||
$tenantPackage->tenant->user?->email,
|
||||
$tenant->contact_email,
|
||||
$tenant->user?->email,
|
||||
])->filter(fn ($email) => is_string($email) && filter_var($email, FILTER_VALIDATE_EMAIL))
|
||||
->unique();
|
||||
|
||||
@@ -55,16 +65,40 @@ class SendTenantPackageEventThresholdWarning implements ShouldQueue
|
||||
'threshold' => $this->threshold,
|
||||
]);
|
||||
|
||||
$this->logNotification($tenant, [
|
||||
'type' => 'event_threshold',
|
||||
'status' => 'skipped',
|
||||
'context' => array_merge($this->context($tenantPackage), ['reason' => 'no_recipient']),
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($emails as $email) {
|
||||
Notification::route('mail', $email)->notify(new TenantPackageEventThresholdNotification(
|
||||
$tenantPackage,
|
||||
$this->threshold,
|
||||
$this->limit,
|
||||
$this->used,
|
||||
));
|
||||
}
|
||||
$context = $this->context($tenantPackage);
|
||||
|
||||
$this->dispatchToRecipients(
|
||||
$tenant,
|
||||
$emails,
|
||||
'event_threshold',
|
||||
function (string $email) use ($tenantPackage) {
|
||||
Notification::route('mail', $email)->notify(new TenantPackageEventThresholdNotification(
|
||||
$tenantPackage,
|
||||
$this->threshold,
|
||||
$this->limit,
|
||||
$this->used,
|
||||
));
|
||||
},
|
||||
$context
|
||||
);
|
||||
}
|
||||
|
||||
private function context(TenantPackage $tenantPackage): array
|
||||
{
|
||||
return [
|
||||
'tenant_package_id' => $tenantPackage->id,
|
||||
'threshold' => $this->threshold,
|
||||
'limit' => $this->limit,
|
||||
'used' => $this->used,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Jobs\Packages;
|
||||
|
||||
use App\Jobs\Concerns\LogsTenantNotifications;
|
||||
use App\Models\TenantPackage;
|
||||
use App\Notifications\Packages\TenantPackageExpiredNotification;
|
||||
use Illuminate\Bus\Queueable;
|
||||
@@ -16,6 +17,7 @@ class SendTenantPackageExpiredNotification implements ShouldQueue
|
||||
{
|
||||
use Dispatchable;
|
||||
use InteractsWithQueue;
|
||||
use LogsTenantNotifications;
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
@@ -33,14 +35,25 @@ class SendTenantPackageExpiredNotification implements ShouldQueue
|
||||
return;
|
||||
}
|
||||
|
||||
$tenant = $tenantPackage->tenant;
|
||||
|
||||
$preferences = app(\App\Services\Packages\TenantNotificationPreferences::class);
|
||||
if (! $preferences->shouldNotify($tenantPackage->tenant, 'package_expired')) {
|
||||
if (! $preferences->shouldNotify($tenant, 'package_expired')) {
|
||||
$this->logNotification($tenant, [
|
||||
'type' => 'package_expired',
|
||||
'status' => 'skipped',
|
||||
'context' => [
|
||||
'tenant_package_id' => $tenantPackage->id,
|
||||
'reason' => 'opt_out',
|
||||
],
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$emails = collect([
|
||||
$tenantPackage->tenant->contact_email,
|
||||
$tenantPackage->tenant->user?->email,
|
||||
$tenant->contact_email,
|
||||
$tenant->user?->email,
|
||||
])->filter(fn ($email) => is_string($email) && filter_var($email, FILTER_VALIDATE_EMAIL))
|
||||
->unique();
|
||||
|
||||
@@ -49,11 +62,30 @@ class SendTenantPackageExpiredNotification implements ShouldQueue
|
||||
'tenant_package_id' => $tenantPackage->id,
|
||||
]);
|
||||
|
||||
$this->logNotification($tenant, [
|
||||
'type' => 'package_expired',
|
||||
'status' => 'skipped',
|
||||
'context' => [
|
||||
'tenant_package_id' => $tenantPackage->id,
|
||||
'reason' => 'no_recipient',
|
||||
],
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($emails as $email) {
|
||||
Notification::route('mail', $email)->notify(new TenantPackageExpiredNotification($tenantPackage));
|
||||
}
|
||||
$context = [
|
||||
'tenant_package_id' => $tenantPackage->id,
|
||||
];
|
||||
|
||||
$this->dispatchToRecipients(
|
||||
$tenant,
|
||||
$emails,
|
||||
'package_expired',
|
||||
function (string $email) use ($tenantPackage) {
|
||||
Notification::route('mail', $email)->notify(new TenantPackageExpiredNotification($tenantPackage));
|
||||
},
|
||||
$context
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Jobs\Packages;
|
||||
|
||||
use App\Jobs\Concerns\LogsTenantNotifications;
|
||||
use App\Models\TenantPackage;
|
||||
use App\Notifications\Packages\TenantPackageExpiringNotification;
|
||||
use Illuminate\Bus\Queueable;
|
||||
@@ -16,6 +17,7 @@ class SendTenantPackageExpiringNotification implements ShouldQueue
|
||||
{
|
||||
use Dispatchable;
|
||||
use InteractsWithQueue;
|
||||
use LogsTenantNotifications;
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
@@ -36,14 +38,26 @@ class SendTenantPackageExpiringNotification implements ShouldQueue
|
||||
return;
|
||||
}
|
||||
|
||||
$tenant = $tenantPackage->tenant;
|
||||
|
||||
$preferences = app(\App\Services\Packages\TenantNotificationPreferences::class);
|
||||
if (! $preferences->shouldNotify($tenantPackage->tenant, 'package_expiring')) {
|
||||
if (! $preferences->shouldNotify($tenant, 'package_expiring')) {
|
||||
$this->logNotification($tenant, [
|
||||
'type' => 'package_expiring',
|
||||
'status' => 'skipped',
|
||||
'context' => [
|
||||
'tenant_package_id' => $tenantPackage->id,
|
||||
'days_remaining' => $this->daysRemaining,
|
||||
'reason' => 'opt_out',
|
||||
],
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$emails = collect([
|
||||
$tenantPackage->tenant->contact_email,
|
||||
$tenantPackage->tenant->user?->email,
|
||||
$tenant->contact_email,
|
||||
$tenant->user?->email,
|
||||
])->filter(fn ($email) => is_string($email) && filter_var($email, FILTER_VALIDATE_EMAIL))
|
||||
->unique();
|
||||
|
||||
@@ -53,14 +67,35 @@ class SendTenantPackageExpiringNotification implements ShouldQueue
|
||||
'days_remaining' => $this->daysRemaining,
|
||||
]);
|
||||
|
||||
$this->logNotification($tenant, [
|
||||
'type' => 'package_expiring',
|
||||
'status' => 'skipped',
|
||||
'context' => [
|
||||
'tenant_package_id' => $tenantPackage->id,
|
||||
'days_remaining' => $this->daysRemaining,
|
||||
'reason' => 'no_recipient',
|
||||
],
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($emails as $email) {
|
||||
Notification::route('mail', $email)->notify(new TenantPackageExpiringNotification(
|
||||
$tenantPackage,
|
||||
$this->daysRemaining,
|
||||
));
|
||||
}
|
||||
$context = [
|
||||
'tenant_package_id' => $tenantPackage->id,
|
||||
'days_remaining' => $this->daysRemaining,
|
||||
];
|
||||
|
||||
$this->dispatchToRecipients(
|
||||
$tenant,
|
||||
$emails,
|
||||
'package_expiring',
|
||||
function (string $email) use ($tenantPackage) {
|
||||
Notification::route('mail', $email)->notify(new TenantPackageExpiringNotification(
|
||||
$tenantPackage,
|
||||
$this->daysRemaining,
|
||||
));
|
||||
},
|
||||
$context
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,11 @@ class Tenant extends Model
|
||||
return $this->hasOne(TenantPackage::class)->where('active', true);
|
||||
}
|
||||
|
||||
public function notificationLogs(): HasMany
|
||||
{
|
||||
return $this->hasMany(TenantNotificationLog::class);
|
||||
}
|
||||
|
||||
public function canCreateEvent(): bool
|
||||
{
|
||||
return $this->hasEventAllowance();
|
||||
|
||||
31
app/Models/TenantNotificationLog.php
Normal file
31
app/Models/TenantNotificationLog.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class TenantNotificationLog extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'tenant_id',
|
||||
'type',
|
||||
'channel',
|
||||
'recipient',
|
||||
'status',
|
||||
'context',
|
||||
'sent_at',
|
||||
'failed_at',
|
||||
'failure_reason',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'context' => 'array',
|
||||
'sent_at' => 'datetime',
|
||||
'failed_at' => 'datetime',
|
||||
];
|
||||
|
||||
public function tenant()
|
||||
{
|
||||
return $this->belongsTo(Tenant::class);
|
||||
}
|
||||
}
|
||||
37
app/Services/Packages/TenantNotificationLogger.php
Normal file
37
app/Services/Packages/TenantNotificationLogger.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Packages;
|
||||
|
||||
use App\Models\Tenant;
|
||||
use App\Models\TenantNotificationLog;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class TenantNotificationLogger
|
||||
{
|
||||
public function log(Tenant $tenant, array $attributes): TenantNotificationLog
|
||||
{
|
||||
$context = Arr::get($attributes, 'context', []);
|
||||
|
||||
$log = $tenant->notificationLogs()->create([
|
||||
'type' => $attributes['type'] ?? 'unknown',
|
||||
'channel' => $attributes['channel'] ?? 'mail',
|
||||
'recipient' => $attributes['recipient'] ?? null,
|
||||
'status' => $attributes['status'] ?? 'sent',
|
||||
'context' => $context,
|
||||
'sent_at' => $attributes['sent_at'] ?? now(),
|
||||
'failed_at' => $attributes['failed_at'] ?? null,
|
||||
'failure_reason' => $attributes['failure_reason'] ?? null,
|
||||
]);
|
||||
|
||||
Log::info('tenant_notification_log', [
|
||||
'tenant_id' => $tenant->id,
|
||||
'log_id' => $log->id,
|
||||
'type' => $log->type,
|
||||
'status' => $log->status,
|
||||
'recipient' => $log->recipient,
|
||||
]);
|
||||
|
||||
return $log;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user