M3 Integration fixes
This commit is contained in:
Regular → Executable
Regular → Executable
+24
-41
@@ -45,16 +45,13 @@ final class AttachmentService
|
||||
$size = (int) Storage::disk($disk)->size($path);
|
||||
}
|
||||
|
||||
Attachment::query()->create($this->attachmentAttributes(
|
||||
ticket: $ticket,
|
||||
comment: $comment,
|
||||
userId: $userId,
|
||||
disk: $disk,
|
||||
path: $path,
|
||||
originalName: $originalName,
|
||||
mimeType: $mimeType,
|
||||
size: $size,
|
||||
));
|
||||
Attachment::query()->create($this->attachmentAttributes($ticket, $comment, $userId, [
|
||||
'disk' => $disk,
|
||||
'path' => $path,
|
||||
'original_name' => $originalName,
|
||||
'mime_type' => $mimeType,
|
||||
'size' => $size,
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,35 +64,34 @@ final class AttachmentService
|
||||
$attachment->delete();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Build attachment attributes while remaining compatible with older databases.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function attachmentAttributes(Ticket $ticket, ?Comment $comment, int $userId, string $disk, string $path, string $originalName, string $mimeType, int $size): array
|
||||
private function attachmentAttributes(Ticket $ticket, ?Comment $comment, int $userId, array $file): array
|
||||
{
|
||||
$attributes = [
|
||||
'ticket_id' => $ticket->id,
|
||||
'comment_id' => $comment?->id,
|
||||
'user_id' => $userId,
|
||||
'disk' => $disk,
|
||||
'path' => $path,
|
||||
'original_name' => $originalName,
|
||||
'mime_type' => $mimeType,
|
||||
'size' => $size,
|
||||
'disk' => $file['disk'],
|
||||
'path' => $file['path'],
|
||||
'original_name' => $file['original_name'],
|
||||
'mime_type' => $file['mime_type'],
|
||||
'size' => $file['size'],
|
||||
];
|
||||
|
||||
if (Schema::hasColumn('helpdesk_attachments', 'extension')) {
|
||||
$attributes['extension'] = strtolower((string) pathinfo($originalName, PATHINFO_EXTENSION));
|
||||
$attributes['extension'] = strtolower((string) pathinfo($file['original_name'], PATHINFO_EXTENSION));
|
||||
}
|
||||
|
||||
if (Schema::hasColumn('helpdesk_attachments', 'category')) {
|
||||
$attributes['category'] = $this->categoryFor($originalName, $mimeType);
|
||||
$attributes['category'] = $this->categoryFor($file['original_name'], $file['mime_type']);
|
||||
}
|
||||
|
||||
if (Schema::hasColumn('helpdesk_attachments', 'checksum_sha256') && Storage::disk($disk)->exists($path)) {
|
||||
$stream = Storage::disk($disk)->readStream($path);
|
||||
if (Schema::hasColumn('helpdesk_attachments', 'checksum_sha256') && Storage::disk($file['disk'])->exists($file['path'])) {
|
||||
$stream = Storage::disk($file['disk'])->readStream($file['path']);
|
||||
|
||||
if (is_resource($stream)) {
|
||||
$context = hash_init('sha256');
|
||||
@@ -115,27 +111,15 @@ final class AttachmentService
|
||||
{
|
||||
$extension = strtolower((string) pathinfo($originalName, PATHINFO_EXTENSION));
|
||||
|
||||
if (str_starts_with($mimeType, 'image/') || in_array($extension, ['png', 'jpg', 'jpeg', 'webp', 'gif'], true)) {
|
||||
return 'image';
|
||||
}
|
||||
|
||||
if ($extension === 'pdf' || $mimeType === 'application/pdf') {
|
||||
return 'pdf';
|
||||
}
|
||||
|
||||
if (in_array($extension, ['zip', 'tar', 'gz', '7z', 'rar'], true)) {
|
||||
return 'archive';
|
||||
}
|
||||
|
||||
if (in_array($extension, config('helpdesk.allowed_source_extensions', []), true)) {
|
||||
return 'source';
|
||||
}
|
||||
|
||||
return 'file';
|
||||
return match (true) {
|
||||
str_starts_with($mimeType, 'image/'), in_array($extension, ['png', 'jpg', 'jpeg', 'webp', 'gif'], true) => 'image',
|
||||
$extension === 'pdf', $mimeType === 'application/pdf' => 'pdf',
|
||||
in_array($extension, ['zip', 'tar', 'gz', '7z', 'rar'], true) => 'archive',
|
||||
in_array($extension, config('helpdesk.allowed_source_extensions', []), true) => 'source',
|
||||
default => 'file',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Soft-delete a stored attachment while retaining audit metadata.
|
||||
*/
|
||||
@@ -149,7 +133,6 @@ final class AttachmentService
|
||||
], static fn (mixed $value): bool => $value !== null));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether the value is a storeable uploaded file.
|
||||
*/
|
||||
|
||||
Regular → Executable
+25
-25
@@ -29,18 +29,7 @@ final class AutomationRuleService
|
||||
return;
|
||||
}
|
||||
|
||||
$updates = array_filter([
|
||||
'priority_id' => $rule->set_priority_id,
|
||||
'category_id' => $rule->set_category_id,
|
||||
'team_id' => $rule->set_team_id,
|
||||
'project_id' => $rule->set_project_id,
|
||||
'status_id' => $rule->set_status_id,
|
||||
'agent_id' => $rule->set_agent_id,
|
||||
], static fn ($value): bool => $value !== null);
|
||||
|
||||
if ($updates !== []) {
|
||||
$ticket->forceFill($updates + ['last_activity_at' => now()])->save();
|
||||
}
|
||||
$this->applyRuleUpdates($rule, $ticket);
|
||||
});
|
||||
|
||||
return $ticket->fresh() ?? $ticket;
|
||||
@@ -48,19 +37,30 @@ final class AutomationRuleService
|
||||
|
||||
private function matches(AutomationRule $rule, Ticket $ticket, string $sender, string $mailbox): bool
|
||||
{
|
||||
if ($rule->match_sender && ! Str::contains(Str::lower($sender), Str::lower($rule->match_sender))) {
|
||||
return false;
|
||||
}
|
||||
if ($rule->match_subject && ! Str::contains(Str::lower($ticket->subject), Str::lower($rule->match_subject))) {
|
||||
return false;
|
||||
}
|
||||
if ($rule->match_mailbox && ! Str::contains(Str::lower($mailbox), Str::lower($rule->match_mailbox))) {
|
||||
return false;
|
||||
}
|
||||
if ($rule->match_category_id && (int) $ticket->category_id !== (int) $rule->match_category_id) {
|
||||
return false;
|
||||
}
|
||||
return $this->containsWhenConfigured($sender, $rule->match_sender)
|
||||
&& $this->containsWhenConfigured($ticket->subject, $rule->match_subject)
|
||||
&& $this->containsWhenConfigured($mailbox, $rule->match_mailbox)
|
||||
&& (! $rule->match_category_id || (int) $ticket->category_id === (int) $rule->match_category_id);
|
||||
}
|
||||
|
||||
return true;
|
||||
private function containsWhenConfigured(string $value, ?string $match): bool
|
||||
{
|
||||
return ! $match || Str::contains(Str::lower($value), Str::lower($match));
|
||||
}
|
||||
|
||||
private function applyRuleUpdates(AutomationRule $rule, Ticket $ticket): void
|
||||
{
|
||||
$updates = array_filter([
|
||||
'priority_id' => $rule->set_priority_id,
|
||||
'category_id' => $rule->set_category_id,
|
||||
'team_id' => $rule->set_team_id,
|
||||
'project_id' => $rule->set_project_id,
|
||||
'status_id' => $rule->set_status_id,
|
||||
'agent_id' => $rule->set_agent_id,
|
||||
], static fn ($value): bool => $value !== null);
|
||||
|
||||
if ($updates !== []) {
|
||||
$ticket->forceFill($updates + ['last_activity_at' => now()])->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Regular → Executable
Regular → Executable
Regular → Executable
+12
-19
@@ -13,8 +13,8 @@ namespace Modules\Helpdesk\Services;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Str;
|
||||
use Modules\Helpdesk\Models\GitCommit;
|
||||
use Modules\Helpdesk\Models\GitRepository;
|
||||
use Modules\Helpdesk\Models\GitWebhookLog;
|
||||
@@ -23,6 +23,8 @@ use Throwable;
|
||||
|
||||
final class GitWebhookIngestionService
|
||||
{
|
||||
private const PUSH_HOOK = 'push hook';
|
||||
|
||||
/**
|
||||
* Matches the generated Helpdesk reference format, for example HD-2026-00042.
|
||||
*/
|
||||
@@ -173,10 +175,10 @@ final class GitWebhookIngestionService
|
||||
|
||||
return match ($normalisedProvider) {
|
||||
'github' => in_array($normalisedEvent, ['push', ''], true),
|
||||
'gitlab' => in_array($normalisedEvent, ['push hook', 'push', ''], true),
|
||||
'gitea' => in_array($normalisedEvent, ['push', 'push hook', ''], true),
|
||||
'gitlab' => in_array($normalisedEvent, [self::PUSH_HOOK, 'push', ''], true),
|
||||
'gitea' => in_array($normalisedEvent, ['push', self::PUSH_HOOK, ''], true),
|
||||
'bitbucket' => in_array($normalisedEvent, ['repo push', 'push', ''], true),
|
||||
default => in_array($normalisedEvent, ['push', 'repo push', 'push hook', ''], true),
|
||||
default => in_array($normalisedEvent, ['push', 'repo push', self::PUSH_HOOK, ''], true),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -214,23 +216,14 @@ final class GitWebhookIngestionService
|
||||
{
|
||||
$commits = $payload['commits'] ?? null;
|
||||
|
||||
if (is_array($commits) && $commits !== []) {
|
||||
return array_values(array_filter($commits, static fn (mixed $commit): bool => is_array($commit)));
|
||||
if (! is_array($commits) || $commits === []) {
|
||||
$headCommit = $payload['head_commit'] ?? null;
|
||||
$commits = is_array($headCommit) ? [$headCommit] : Arr::get($payload, 'push.changes.0.commits', []);
|
||||
}
|
||||
|
||||
$headCommit = $payload['head_commit'] ?? null;
|
||||
|
||||
if (is_array($headCommit)) {
|
||||
return [$headCommit];
|
||||
}
|
||||
|
||||
$bitbucketCommits = Arr::get($payload, 'push.changes.0.commits', []);
|
||||
|
||||
if (is_array($bitbucketCommits)) {
|
||||
return array_values(array_filter($bitbucketCommits, static fn (mixed $commit): bool => is_array($commit)));
|
||||
}
|
||||
|
||||
return [];
|
||||
return is_array($commits)
|
||||
? array_values(array_filter($commits, static fn (mixed $commit): bool => is_array($commit)))
|
||||
: [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Regular → Executable
+2
-1
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace Modules\Helpdesk\Services;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Modules\Helpdesk\Models\Comment;
|
||||
@@ -73,7 +74,7 @@ final class SlaService
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var \Illuminate\Database\Eloquent\Builder<Comment> $query */
|
||||
/** @var Builder<Comment> $query */
|
||||
$query = Comment::query()
|
||||
->where('ticket_id', $ticket->id)
|
||||
->where('is_internal', false)
|
||||
|
||||
Regular → Executable
Regular → Executable
+97
-68
@@ -10,6 +10,7 @@ use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Str;
|
||||
use Modules\Helpdesk\Exceptions\TicketPersistenceException;
|
||||
use Modules\Helpdesk\Models\Comment;
|
||||
use Modules\Helpdesk\Models\KanbanBoard;
|
||||
use Modules\Helpdesk\Models\Status;
|
||||
@@ -45,7 +46,7 @@ final class TicketService
|
||||
}
|
||||
}
|
||||
|
||||
throw new \RuntimeException('Unable to create a unique Helpdesk ticket reference.');
|
||||
throw new TicketPersistenceException('Unable to create a unique Helpdesk ticket reference.');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,32 +57,8 @@ final class TicketService
|
||||
*/
|
||||
private function createInsideTransaction(User $user, array $data, array $files = []): Ticket
|
||||
{
|
||||
$defaultStatusSlug = (string) config('helpdesk.default_status_slug', 'new');
|
||||
$status = Schema::hasTable('helpdesk_statuses') && Schema::hasColumn('helpdesk_statuses', 'is_default')
|
||||
? Status::query()->where('is_default', true)->orderBy('sort_order')->first()
|
||||
: null;
|
||||
|
||||
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,
|
||||
]);
|
||||
}
|
||||
|
||||
$boardId = $data['board_id'] ?? null;
|
||||
if (blank($boardId) && Schema::hasTable('helpdesk_kanban_boards')) {
|
||||
$boardId = KanbanBoard::query()
|
||||
->where('is_default', true)
|
||||
->orderBy('sort_order')
|
||||
->value('id') ?: KanbanBoard::query()->orderBy('sort_order')->value('id');
|
||||
}
|
||||
$status = $this->resolveInitialStatus();
|
||||
$boardId = $this->resolveBoardId($data['board_id'] ?? null);
|
||||
|
||||
/** @var Ticket $ticket */
|
||||
$ticket = Ticket::query()->create([
|
||||
@@ -102,9 +79,7 @@ final class TicketService
|
||||
'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']))));
|
||||
}
|
||||
$this->syncTags($ticket, $data['tag_ids'] ?? null);
|
||||
|
||||
$ticket = $this->automation->apply($ticket, $data);
|
||||
$ticket = $this->sla->applyPolicy($ticket);
|
||||
@@ -117,6 +92,43 @@ final class TicketService
|
||||
return $ticket;
|
||||
}
|
||||
|
||||
private function resolveInitialStatus(): Status
|
||||
{
|
||||
$defaultStatusSlug = (string) config('helpdesk.default_status_slug', 'new');
|
||||
$status = Schema::hasTable('helpdesk_statuses') && Schema::hasColumn('helpdesk_statuses', 'is_default')
|
||||
? Status::query()->where('is_default', true)->orderBy('sort_order')->first()
|
||||
: null;
|
||||
|
||||
$status ??= Status::query()->where('slug', $defaultStatusSlug)->first();
|
||||
|
||||
return $status ?? Status::query()->create([
|
||||
'name' => 'New',
|
||||
'slug' => $defaultStatusSlug,
|
||||
'color' => 'sky',
|
||||
'sort_order' => 1,
|
||||
'is_closed' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
private function resolveBoardId(mixed $boardId): mixed
|
||||
{
|
||||
if (! blank($boardId) || ! Schema::hasTable('helpdesk_kanban_boards')) {
|
||||
return $boardId;
|
||||
}
|
||||
|
||||
return KanbanBoard::query()->where('is_default', true)->orderBy('sort_order')->value('id')
|
||||
?: KanbanBoard::query()->orderBy('sort_order')->value('id');
|
||||
}
|
||||
|
||||
private function syncTags(Ticket $ticket, mixed $tagIds): void
|
||||
{
|
||||
if (! is_array($tagIds) || $tagIds === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
$ticket->tags()->sync(array_values(array_unique(array_map('intval', $tagIds))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a database error was caused by the ticket reference unique index.
|
||||
*/
|
||||
@@ -137,52 +149,69 @@ final class TicketService
|
||||
public function comment(Ticket $ticket, User $user, string $body, bool $internal = false, array $files = [], ?int $parentId = null, ?string $subject = null): Comment
|
||||
{
|
||||
return DB::transaction(function () use ($ticket, $user, $body, $internal, $files, $parentId, $subject): Comment {
|
||||
$parent = $parentId === null
|
||||
? null
|
||||
: Comment::query()
|
||||
->where('ticket_id', $ticket->id)
|
||||
->findOrFail($parentId);
|
||||
|
||||
$guid = (string) Str::uuid();
|
||||
$unid = strtoupper(hash('sha256', $guid . '|' . $ticket->id . '|' . microtime(true)));
|
||||
$parentUnid = $parent?->unid;
|
||||
$rootUnid = $parent?->root_unid ?: $parentUnid ?: $unid;
|
||||
$plainTextBody = trim(preg_replace('/\s+/', ' ', strip_tags($body)) ?: '');
|
||||
|
||||
$payload = [
|
||||
'parent_id' => $parentId,
|
||||
'user_id' => $user->id,
|
||||
'body' => $body,
|
||||
'body_text' => $plainTextBody,
|
||||
'is_internal' => $internal,
|
||||
'guid' => $guid,
|
||||
'unid' => $unid,
|
||||
'parent_unid' => $parentUnid,
|
||||
'root_unid' => $rootUnid,
|
||||
'originator_id' => $unid . ':1',
|
||||
'sync_sequence' => 1,
|
||||
'sync_hash' => hash('sha256', $body),
|
||||
'source_system' => 'wms-helpdesk',
|
||||
];
|
||||
|
||||
if (Schema::hasColumn('helpdesk_comments', 'subject')) {
|
||||
$payload['subject'] = trim((string) ($subject ?: ($parentId === null ? 'Response' : 'RE: Response')));
|
||||
}
|
||||
$parent = $this->resolveParentComment($ticket, $parentId);
|
||||
$payload = $this->commentPayload($ticket, $user, $body, $internal, $parent, $parentId, $subject);
|
||||
|
||||
/** @var Comment $comment */
|
||||
$comment = $ticket->comments()->create($payload);
|
||||
|
||||
$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(['status', 'priority', 'category', 'project', 'team']) ?? $ticket, $parentId === null ? 'ticket.commented' : 'ticket.reply_created', $user);
|
||||
$this->afterCommentCreated($ticket, $user, $comment, $files, $internal, $parentId);
|
||||
|
||||
return $comment->fresh(['user', 'attachments']) ?? $comment;
|
||||
});
|
||||
}
|
||||
|
||||
private function resolveParentComment(Ticket $ticket, ?int $parentId): ?Comment
|
||||
{
|
||||
return $parentId === null
|
||||
? null
|
||||
: Comment::query()->where('ticket_id', $ticket->id)->findOrFail($parentId);
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
private function commentPayload(Ticket $ticket, User $user, string $body, bool $internal, ?Comment $parent, ?int $parentId, ?string $subject): array
|
||||
{
|
||||
$guid = (string) Str::uuid();
|
||||
$unid = strtoupper(hash('sha256', $guid . '|' . $ticket->id . '|' . microtime(true)));
|
||||
$parentUnid = $parent?->unid;
|
||||
$payload = [
|
||||
'parent_id' => $parentId,
|
||||
'user_id' => $user->id,
|
||||
'body' => $body,
|
||||
'body_text' => trim(preg_replace('/\s+/', ' ', strip_tags($body)) ?: ''),
|
||||
'is_internal' => $internal,
|
||||
'guid' => $guid,
|
||||
'unid' => $unid,
|
||||
'parent_unid' => $parentUnid,
|
||||
'root_unid' => $parent?->root_unid ?: $parentUnid ?: $unid,
|
||||
'originator_id' => $unid . ':1',
|
||||
'sync_sequence' => 1,
|
||||
'sync_hash' => hash('sha256', $body),
|
||||
'source_system' => 'wms-helpdesk',
|
||||
];
|
||||
|
||||
if (Schema::hasColumn('helpdesk_comments', 'subject')) {
|
||||
$defaultSubject = $parentId === null ? 'Response' : 'RE: Response';
|
||||
$payload['subject'] = trim((string) ($subject ?: $defaultSubject));
|
||||
}
|
||||
|
||||
return $payload;
|
||||
}
|
||||
|
||||
/** @param array<int, UploadedFile> $files */
|
||||
private function afterCommentCreated(Ticket $ticket, User $user, Comment $comment, array $files, bool $internal, ?int $parentId): void
|
||||
{
|
||||
$ticket->forceFill(['last_activity_at' => now()])->save();
|
||||
|
||||
if (! $internal) {
|
||||
$this->sla->recordPublicResponse($ticket, $user);
|
||||
}
|
||||
|
||||
$this->attachments->storeMany($ticket, $files, (int) $user->id, $comment);
|
||||
$event = $parentId === null ? 'ticket.commented' : 'ticket.reply_created';
|
||||
$freshTicket = $ticket->fresh(['status', 'priority', 'category', 'project', 'team']) ?? $ticket;
|
||||
$this->workflow->dispatch($freshTicket, $event, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close a ticket.
|
||||
*/
|
||||
|
||||
Regular → Executable
+10
-10
@@ -34,7 +34,7 @@ final class WorkflowNotificationService
|
||||
$recipient = $this->recipient($template->to_role, $ticket, $actor);
|
||||
|
||||
if ($recipient === null || blank($recipient->email ?? null)) {
|
||||
$this->log($template, $ticket, $event, null, 'skipped', 'No recipient email was available.');
|
||||
$this->log($template, $ticket, $event, ['recipient' => null, 'status' => 'skipped', 'error' => 'No recipient email was available.']);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -42,7 +42,6 @@ final class WorkflowNotificationService
|
||||
$trackingToken = Str::random(48);
|
||||
$subject = $this->renderText($template->subject, $ticket, $actor);
|
||||
$html = $this->wrapHtml($this->renderText($template->html_body, $ticket, $actor), $ticket, $trackingToken);
|
||||
$text = $this->renderText($template->text_body ?: strip_tags($template->html_body), $ticket, $actor);
|
||||
|
||||
try {
|
||||
Mail::html($html, function ($message) use ($recipient, $template, $subject): void {
|
||||
@@ -57,10 +56,10 @@ final class WorkflowNotificationService
|
||||
}
|
||||
});
|
||||
|
||||
$this->log($template, $ticket, $event, (string) $recipient->email, 'sent', null, $subject, $trackingToken);
|
||||
$this->log($template, $ticket, $event, ['recipient' => (string) $recipient->email, 'status' => 'sent', 'subject' => $subject, 'tracking_token' => $trackingToken]);
|
||||
} catch (Throwable $exception) {
|
||||
Log::warning('Helpdesk workflow email failed.', ['event' => $event, 'ticket_id' => $ticket->id, 'error' => $exception->getMessage()]);
|
||||
$this->log($template, $ticket, $event, (string) $recipient->email, 'failed', $exception->getMessage(), $subject);
|
||||
$this->log($template, $ticket, $event, ['recipient' => (string) $recipient->email, 'status' => 'failed', 'error' => $exception->getMessage(), 'subject' => $subject]);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -158,17 +157,18 @@ final class WorkflowNotificationService
|
||||
return '<img src="' . e($url) . '" width="1" height="1" alt="" style="display:none" />';
|
||||
}
|
||||
|
||||
private function log(WorkflowTemplate $template, Ticket $ticket, string $event, ?string $recipient, string $status, ?string $error = null, ?string $subject = null, ?string $trackingToken = null): void
|
||||
/** @param array{recipient:?string,status:string,error?:?string,subject?:?string,tracking_token?:?string} $details */
|
||||
private function log(WorkflowTemplate $template, Ticket $ticket, string $event, array $details): void
|
||||
{
|
||||
WorkflowLog::query()->create([
|
||||
'template_id' => $template->id,
|
||||
'ticket_id' => $ticket->id,
|
||||
'event' => $event,
|
||||
'recipient' => $recipient,
|
||||
'subject' => $subject,
|
||||
'status' => $status,
|
||||
'tracking_token' => $trackingToken,
|
||||
'error' => $error,
|
||||
'recipient' => $details['recipient'],
|
||||
'subject' => $details['subject'] ?? null,
|
||||
'status' => $details['status'],
|
||||
'tracking_token' => $details['tracking_token'] ?? null,
|
||||
'error' => $details['error'] ?? null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user