$data * @param array $files */ public function create(User $user, array $data, array $files = []): Ticket { return DB::transaction(function () use ($user, $data, $files): Ticket { $defaultStatusSlug = (string) config('helpdesk.default_status_slug', 'new'); $status = ! empty($data['status_id']) ? Status::query()->whereKey((int) $data['status_id'])->first() : null; if (! $status && Schema::hasTable('helpdesk_statuses') && Schema::hasColumn('helpdesk_statuses', 'is_default')) { $status = Status::query()->where('is_default', true)->orderBy('sort_order')->first(); } if (! $status) { $status = Status::query()->where('slug', $defaultStatusSlug)->first(); } if (! $status) { $status = Status::query()->create([ 'name' => 'New', 'slug' => $defaultStatusSlug, 'color' => 'sky', 'sort_order' => 1, 'is_closed' => false, ]); } /** @var Ticket $ticket */ $ticket = Ticket::query()->create([ 'reference' => $this->references->next(), 'company_id' => $data['company_id'] ?? ($user->company_id ?? null), 'user_id' => $user->id, 'agent_id' => $this->assignment->selectAgentId($data['category_id'] ?? null), 'status_id' => $status->id, 'priority_id' => $data['priority_id'], 'category_id' => $data['category_id'] ?? null, 'project_id' => $data['project_id'] ?? null, 'product_id' => $data['product_id'] ?? null, 'team_id' => $data['team_id'] ?? null, 'subject' => $data['subject'], 'body' => $data['body'], 'due_at' => $data['due_at'] ?? null, 'last_activity_at' => now(), ]); if (! empty($data['tag_ids']) && is_array($data['tag_ids'])) { $ticket->tags()->sync(array_values(array_unique(array_map('intval', $data['tag_ids'])))); } $ticket = $this->automation->apply($ticket, $data); $ticket = $this->sla->applyPolicy($ticket); $this->checklists->applyTemplates($ticket); $this->attachments->storeMany($ticket, $files, (int) $user->id); $ticket = $ticket->fresh(['owner', 'agent', 'status', 'priority', 'category', 'project', 'team', 'product', 'tags', 'attachments', 'checklistItems']) ?? $ticket; $this->workflow->dispatch($ticket, 'ticket.created', $user); return $ticket; }); } /** * Add a public or internal comment and optional attachments. * * @param array $files */ public function comment(Ticket $ticket, User $user, string $body, bool $internal = false, array $files = [], ?int $parentId = null): Comment { return DB::transaction(function () use ($ticket, $user, $body, $internal, $files, $parentId): Comment { /** @var Comment $comment */ $comment = $ticket->comments()->create([ 'parent_id' => $parentId, 'user_id' => $user->id, 'body' => $body, 'is_internal' => $internal, ]); $ticket->forceFill(['last_activity_at' => now()])->save(); if (! $internal) { $this->sla->recordPublicResponse($ticket, $user); } $this->attachments->storeMany($ticket, $files, (int) $user->id, $comment); $this->workflow->dispatch($ticket->fresh(['owner', 'agent', 'status', 'priority', 'category', 'project', 'team']) ?? $ticket, $parentId === null ? 'ticket.commented' : 'ticket.reply_created', $user); return $comment->fresh(['user', 'attachments']) ?? $comment; }); } /** * Close a ticket. */ public function close(Ticket $ticket, User $user): Ticket { $status = Status::query()->where('slug', config('helpdesk.closed_status_slug'))->firstOrFail(); $ticket->forceFill([ 'status_id' => $status->id, 'completed_at' => now(), 'last_activity_at' => now(), ])->save(); $ticket = $ticket->fresh(['owner', 'agent', 'status', 'priority', 'category', 'project', 'team', 'product']) ?? $ticket; $this->sla->recordClosure($ticket); $this->workflow->dispatch($ticket, 'ticket.closed', $user); return $ticket; } }