Deploy Ladill Queue / deploy (push) Successful in 2m17s
Counters gain destination/staff metadata; tickets can be pre-assigned to a service point with assigned_only queues for healthcare while shared_pool preserves generic bank/government behavior. Display and announcements expose ticket, staff, and destination clearly for Care and public boards. Co-authored-by: Cursor <cursoragent@cursor.com>
88 lines
3.1 KiB
PHP
88 lines
3.1 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Qms;
|
|
|
|
use App\Models\Counter;
|
|
use App\Models\Ticket;
|
|
use App\Models\VoiceAnnouncement;
|
|
|
|
class VoiceAnnouncementService
|
|
{
|
|
public function announceCalled(Ticket $ticket, Counter $counter, ?string $locale = null): VoiceAnnouncement
|
|
{
|
|
$locale ??= data_get($ticket->serviceQueue?->settings, 'announcement_locale', 'en');
|
|
$message = $this->buildMessage($ticket, $counter, $locale);
|
|
|
|
return VoiceAnnouncement::create([
|
|
'owner_ref' => $ticket->owner_ref,
|
|
'organization_id' => $ticket->organization_id,
|
|
'branch_id' => $ticket->branch_id,
|
|
'ticket_id' => $ticket->id,
|
|
'locale' => $locale,
|
|
'message' => $message,
|
|
'voice' => data_get($ticket->serviceQueue?->settings, 'voice', 'female'),
|
|
'volume' => (int) data_get($ticket->serviceQueue?->settings, 'announcement_volume', 80),
|
|
'repeat_count' => (int) data_get($ticket->serviceQueue?->settings, 'announcement_repeat', 1),
|
|
'status' => 'pending',
|
|
]);
|
|
}
|
|
|
|
protected function buildMessage(Ticket $ticket, Counter $counter, string $locale): string
|
|
{
|
|
$templates = config('qms.announcement_templates');
|
|
$template = $templates[$locale] ?? $templates['en'];
|
|
$destination = $counter->displayDestination();
|
|
$staff = trim((string) ($counter->staff_display_name ?? ''));
|
|
$queueName = trim((string) ($ticket->serviceQueue?->name ?? ''));
|
|
|
|
// Prefer rich healthcare-style copy when staff is known:
|
|
// "A005, Dr. Mensah, Consultation Room 4."
|
|
if ($staff !== '') {
|
|
$parts = array_values(array_filter([
|
|
$ticket->ticket_number,
|
|
$staff,
|
|
$queueName !== '' ? $queueName.' '.$destination : $destination,
|
|
]));
|
|
|
|
return implode(', ', $parts).'.';
|
|
}
|
|
|
|
return str_replace(
|
|
[':ticket', ':counter'],
|
|
[$ticket->ticket_number, $destination],
|
|
$template,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param list<int>|null $queueIds
|
|
* @return list<array<string, mixed>>
|
|
*/
|
|
public function pendingForBranch(int $branchId, ?array $queueIds = null, int $limit = 10): array
|
|
{
|
|
return VoiceAnnouncement::query()
|
|
->where('branch_id', $branchId)
|
|
->where('status', 'pending')
|
|
->when($queueIds, function ($query, array $queueIds) {
|
|
$query->whereHas('ticket', fn ($ticket) => $ticket->whereIn('service_queue_id', $queueIds));
|
|
})
|
|
->orderBy('id')
|
|
->limit($limit)
|
|
->get()
|
|
->map(fn (VoiceAnnouncement $a) => [
|
|
'id' => $a->id,
|
|
'message' => $a->message,
|
|
'locale' => $a->locale,
|
|
'voice' => $a->voice,
|
|
'volume' => $a->volume,
|
|
'repeat_count' => $a->repeat_count,
|
|
])
|
|
->all();
|
|
}
|
|
|
|
public function markPlayed(VoiceAnnouncement $announcement): void
|
|
{
|
|
$announcement->update(['status' => 'played', 'played_at' => now()]);
|
|
}
|
|
}
|