$payload */ public function complete( EventPackageAddon $addon, array $payload, ?string $transactionId, ?string $checkoutId, ?float $amount, ?string $currency, array $metadata = [], ): void { if ($addon->status === 'completed') { return; } $increments = $this->resolveAddonIncrements($addon, $addon->addon_key); DB::transaction(function () use ($addon, $payload, $transactionId, $checkoutId, $amount, $currency, $metadata, $increments) { $addon->forceFill([ 'transaction_id' => $transactionId ?? $addon->transaction_id, 'checkout_id' => $addon->checkout_id ?: $checkoutId, 'status' => 'completed', 'amount' => $amount ?? $addon->amount, 'currency' => $currency ?? $addon->currency, 'metadata' => array_merge($addon->metadata ?? [], array_filter([ 'payment_payload' => $payload, ]), $metadata), 'purchased_at' => now(), ])->save(); /** @var EventPackage $eventPackage */ $eventPackage = EventPackage::query() ->lockForUpdate() ->find($addon->event_package_id); if (! $eventPackage) { return; } $eventPackage->forceFill([ 'extra_photos' => ($eventPackage->extra_photos ?? 0) + (int) ($increments['extra_photos'] ?? 0) * $addon->quantity, 'extra_guests' => ($eventPackage->extra_guests ?? 0) + (int) ($increments['extra_guests'] ?? 0) * $addon->quantity, 'extra_gallery_days' => ($eventPackage->extra_gallery_days ?? 0) + (int) ($increments['extra_gallery_days'] ?? 0) * $addon->quantity, ]); if (($increments['extra_gallery_days'] ?? 0) > 0) { $base = $eventPackage->gallery_expires_at ?? now(); $eventPackage->gallery_expires_at = $base->copy()->addDays((int) ($increments['extra_gallery_days'] ?? 0) * $addon->quantity); } $eventPackage->save(); $tenant = $addon->tenant; if ($tenant) { Notification::route('mail', [$tenant->contact_email ?? $tenant->user?->email]) ->notify(new AddonPurchaseReceipt($addon)); $opsEmail = config('mail.ops_address'); if ($opsEmail) { Notification::route('mail', $opsEmail)->notify(new AddonPurchased($addon)); } } }); } /** * @param array $payload */ public function fail(EventPackageAddon $addon, string $reason, array $payload = []): void { $addon->forceFill([ 'status' => 'failed', 'error' => $reason, 'metadata' => array_merge($addon->metadata ?? [], array_filter([ 'payment_payload' => $payload, ])), ])->save(); } /** * @return array */ private function resolveAddonIncrements(EventPackageAddon $addon, string $addonKey): array { $stored = Arr::get($addon->metadata ?? [], 'increments', []); if (is_array($stored) && $stored !== []) { $filtered = collect($stored) ->map(fn ($value) => is_numeric($value) ? (int) $value : 0) ->filter(fn ($value) => $value > 0) ->all(); if ($filtered !== []) { return $filtered; } } return $this->catalog->resolveIncrements($addonKey); } }