<?php
 namespace App\Services; use App\Models\ClientDomain; use App\Models\ClientProduct; use App\Models\Invoice; use App\Models\Order; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; class OrderCancellationService { public function cancel(Order $order, string $reason = '', string $source = 'system'): bool { if (in_array($order->status, ['cancelled', 'refunded'], true)) { return false; } return DB::transaction(function () use ($order, $reason, $source) { $order->update(['status' => 'cancelled']); $invoice = $order->invoice; if ($invoice && ! in_array($invoice->status, ['paid', 'cancelled', 'refunded'], true)) { $invoice->update([ 'status' => 'cancelled', 'cancel_date' => now(), ]); } $cancelledProducts = ClientProduct::where('order_id', $order->id) ->where('status', 'pending') ->update(['status' => 'terminated', 'terminate_date' => now()]); $domainIds = []; if ($invoice) { $domainIds = $invoice->items() ->where('related_type', 'domain') ->whereNotNull('related_service_id') ->pluck('related_service_id') ->all(); } $cancelledDomains = 0; if (! empty($domainIds)) { $cancelledDomains = ClientDomain::whereIn('id', $domainIds) ->where('status', 'pending') ->delete(); } $invoiceStatus = $invoice ? $invoice->status : null; $revertGate = in_array($order->status, ['pending', 'cancelled'], true) && (! $invoice || in_array($invoiceStatus, ['unpaid', 'cancelled'], true)); if ($revertGate) { try { app(DiscountUsageReverter::class)->revertForOrder($order); } catch (\Throwable $e) { Log::warning('Discount usage revert failed on order cancel', [ 'order_id' => $order->id, 'error' => $e->getMessage(), ]); } } Log::info('Order cancelled', [ 'order_id' => $order->id, 'order_number' => $order->order_number, 'client_id' => $order->client_id, 'source' => $source, 'reason' => $reason, 'invoice_cancelled' => (bool) ($invoice && $invoice->status === 'cancelled'), 'products_cancelled' => $cancelledProducts, 'domains_cancelled' => $cancelledDomains, ]); return true; }); } } 