<?php
 namespace App\Services\Support; use App\Jobs\SendEmailJob; use App\Models\Admin; use App\Models\Attachment; use App\Models\EmailTemplate; use App\Models\Log; use App\Models\Ticket; use App\Models\TicketReply; use App\Models\TicketStatus; use Illuminate\Support\Facades\DB; use InvalidArgumentException; use RuntimeException; class TicketMergeService { public function merge(Ticket $source, Ticket $target, Admin $admin, bool $notify = false): Ticket { if ($source->id === $target->id) { throw new InvalidArgumentException('Cannot merge a ticket into itself'); } if ($source->merged_into_ticket_id !== null) { throw new InvalidArgumentException('Source ticket is already merged'); } if ($source->client_id !== $target->client_id) { throw new InvalidArgumentException('Cross-client ticket merge is not allowed'); } $mergedStatus = TicketStatus::where('slug', 'merged')->first(); if (! $mergedStatus) { throw new RuntimeException('Merged ticket status missing — run migrations'); } return DB::transaction(function () use ($source, $target, $admin, $mergedStatus, $notify) { $replyIds = TicketReply::where('ticket_id', $source->id)->pluck('id'); TicketReply::whereIn('id', $replyIds)->update(['ticket_id' => $target->id]); Attachment::where('uploadable_type', Ticket::class) ->where('uploadable_id', $source->id) ->update(['uploadable_id' => $target->id]); Log::create([ 'type' => Log::TYPE_ADMIN, 'observer' => $admin->name, 'module' => 'ticket', 'method' => 'merged', 'admin_id' => $admin->id, 'client_id' => $source->client_id, 'ip_address' => request()?->ip() ?? '0.0.0.0', 'user_agent' => request()?->userAgent(), 'description' => "Merged ticket #{$source->id} into #{$target->id}", 'request' => [ 'source_ticket_id' => $source->id, 'target_ticket_id' => $target->id, 'replies_moved' => $replyIds->count(), ], ]); $source->update([ 'status_id' => $mergedStatus->id, 'merged_into_ticket_id' => $target->id, 'merged_at' => now(), 'merged_by_admin_id' => $admin->id, ]); if ($notify && $source->client_id) { $template = EmailTemplate::where('name', 'Support Ticket Merged') ->where('status', 'active') ->first(); if ($template) { SendEmailJob::dispatch( 'Support Ticket Merged', 'client', $source->client_id, [ 'TICKET_ID' => (string) $source->id, 'TICKET_TITLE' => (string) $source->title, 'TARGET_TICKET_ID' => (string) $target->id, 'TARGET_TITLE' => (string) $target->title, 'MERGED_AT' => now()->format('d.m.Y H:i'), 'MERGED_BY_ADMIN_NAME' => (string) $admin->name, 'TARGET_TICKET_URL' => url('/clientarea/tickets/' . $target->id), ] ); } } return $target->fresh(); }); } } 