754 lines
26 KiB
PHP
754 lines
26 KiB
PHP
<?php
|
|
namespace App\Filament\Pages\Strumenti;
|
|
|
|
use App\Filament\Pages\Gescon\RubricaUniversaleScheda;
|
|
use App\Models\ChiamataPostIt;
|
|
use App\Models\CommunicationMessage;
|
|
use App\Models\PbxClickToCallRequest;
|
|
use App\Models\RubricaUniversale;
|
|
use App\Models\Ticket;
|
|
use App\Models\User;
|
|
use BackedEnum;
|
|
use Filament\Notifications\Notification;
|
|
use Filament\Pages\Page;
|
|
use Illuminate\Database\QueryException;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\Schema;
|
|
use UnitEnum;
|
|
|
|
class PostItGestione extends Page
|
|
{
|
|
protected static ?string $title = 'Post-it Gestione';
|
|
|
|
protected static ?string $navigationLabel = 'Post-it Gestione';
|
|
|
|
protected static BackedEnum|string|null $navigationIcon = 'heroicon-o-clipboard-document-list';
|
|
|
|
protected static ?string $slug = 'strumenti/post-it-gestione';
|
|
|
|
protected static bool $shouldRegisterNavigation = true;
|
|
|
|
protected static UnitEnum|string|null $navigationGroup = 'Strumenti';
|
|
|
|
protected static ?int $navigationSort = 11;
|
|
|
|
protected string $view = 'filament.pages.strumenti.post-it-gestione';
|
|
|
|
public ?int $focusPostItId = null;
|
|
|
|
public string $activeTab = 'storico';
|
|
|
|
public string $tecnicoCallView = 'esterne';
|
|
|
|
public string $tecnicoDirectionFilter = 'tutte';
|
|
|
|
public string $tecnicoSearch = '';
|
|
|
|
public string $tecnicoLineFilter = '';
|
|
|
|
public string $tecnicoScopeFilter = 'tutti';
|
|
|
|
/** @var array<int,string> */
|
|
public array $riaperturaNote = [];
|
|
|
|
/** @var array<int,string> */
|
|
public array $conversioneNote = [];
|
|
|
|
/** @var array<string, int|null> */
|
|
private array $rubricaPhoneCache = [];
|
|
|
|
/** @var array<string, array{id:int|null,name:string|null}> */
|
|
private array $pbxExtensionCache = [];
|
|
|
|
public function mount(): void
|
|
{
|
|
$focus = (int) request()->query('focus_post_it', 0);
|
|
$this->focusPostItId = $focus > 0 ? $focus : null;
|
|
|
|
if (request()->query('tab') === 'storico') {
|
|
$this->activeTab = 'storico';
|
|
}
|
|
}
|
|
|
|
public function getPostItInserimentoUrl(): string
|
|
{
|
|
return PostIt::getUrl(panel: 'admin-filament');
|
|
}
|
|
|
|
public function convertiInTicket(int $postItId): void
|
|
{
|
|
if (! $this->isPostItTableReady()) {
|
|
Notification::make()
|
|
->title('Tabella chiamate non pronta')
|
|
->body('Esegui prima le migrazioni per usare la gestione Post-it.')
|
|
->danger()
|
|
->send();
|
|
return;
|
|
}
|
|
|
|
$postIt = ChiamataPostIt::query()->find($postItId);
|
|
if (! $postIt) {
|
|
return;
|
|
}
|
|
|
|
if ($postIt->ticket_id) {
|
|
Notification::make()->title('Gia convertito in ticket')->warning()->send();
|
|
return;
|
|
}
|
|
|
|
if (! $postIt->stabile_id) {
|
|
Notification::make()
|
|
->title('Stabile mancante')
|
|
->body('Associa prima uno stabile al Post-it per poter creare il ticket.')
|
|
->danger()
|
|
->send();
|
|
return;
|
|
}
|
|
|
|
$ticket = Ticket::query()->create([
|
|
'stabile_id' => $postIt->stabile_id,
|
|
'aperto_da_user_id' => Auth::id(),
|
|
'titolo' => $postIt->oggetto ?: ('Chiamata da ' . ($postIt->nome_chiamante ?: 'Contatto sconosciuto')),
|
|
'descrizione' => $this->buildTicketDescriptionFromPostIt($postItId, $postIt),
|
|
'data_apertura' => now(),
|
|
'stato' => 'Aperto',
|
|
'priorita' => $postIt->priorita,
|
|
]);
|
|
|
|
$postIt->ticket_id = $ticket->id;
|
|
$postIt->stato = 'ticket';
|
|
$postIt->save();
|
|
|
|
Notification::make()
|
|
->title('Ticket creato')
|
|
->body("Ticket #{$ticket->id} creato dal Post-it #{$postIt->id}")
|
|
->success()
|
|
->send();
|
|
|
|
unset($this->conversioneNote[$postItId]);
|
|
}
|
|
|
|
public function chiudiPostIt(int $postItId): void
|
|
{
|
|
if (! $this->isPostItTableReady()) {
|
|
return;
|
|
}
|
|
|
|
$postIt = ChiamataPostIt::query()->find($postItId);
|
|
if (! $postIt) {
|
|
return;
|
|
}
|
|
|
|
$postIt->stato = 'chiusa';
|
|
$postIt->save();
|
|
|
|
Notification::make()
|
|
->title('Post-it chiuso')
|
|
->success()
|
|
->send();
|
|
}
|
|
|
|
public function riapriPostIt(int $postItId): void
|
|
{
|
|
if (! $this->isPostItTableReady()) {
|
|
return;
|
|
}
|
|
|
|
$postIt = ChiamataPostIt::query()->find($postItId);
|
|
if (! $postIt) {
|
|
return;
|
|
}
|
|
|
|
$noteInput = trim((string) ($this->riaperturaNote[$postItId] ?? ''));
|
|
$stamp = now()->format('d/m/Y H:i');
|
|
$noteLine = $noteInput !== ''
|
|
? '[' . $stamp . '] Riapertura: ' . $noteInput
|
|
: '[' . $stamp . '] Riapertura da gestione Post-it';
|
|
|
|
$existing = trim((string) ($postIt->nota ?? ''));
|
|
$postIt->nota = $existing !== '' ? ($existing . "\n" . $noteLine) : $noteLine;
|
|
$postIt->stato = $postIt->ticket_id ? 'ticket' : 'post_it';
|
|
|
|
if (Schema::hasColumn('chiamate_post_it', 'chiusa_il')) {
|
|
$postIt->chiusa_il = null;
|
|
}
|
|
|
|
$postIt->save();
|
|
|
|
if ($postIt->ticket_id) {
|
|
$ticket = Ticket::query()->find((int) $postIt->ticket_id);
|
|
if ($ticket && in_array((string) $ticket->stato, ['Chiuso', 'Risolto'], true)) {
|
|
$ticket->stato = 'Preso in Carico';
|
|
|
|
if (Schema::hasColumn('tickets', 'data_chiusura_effettiva')) {
|
|
$ticket->data_chiusura_effettiva = null;
|
|
}
|
|
|
|
if (Schema::hasColumn('tickets', 'data_risoluzione_effettiva')) {
|
|
$ticket->data_risoluzione_effettiva = null;
|
|
}
|
|
|
|
$ticket->save();
|
|
|
|
if (method_exists($ticket, 'messages') && Schema::hasTable('ticket_messages')) {
|
|
$ticket->messages()->create([
|
|
'user_id' => Auth::id(),
|
|
'messaggio' => $noteLine,
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
|
|
unset($this->riaperturaNote[$postItId]);
|
|
|
|
Notification::make()
|
|
->title('Post-it riaperto')
|
|
->body('Riapertura completata con nota di tracciamento.')
|
|
->success()
|
|
->send();
|
|
}
|
|
|
|
public function getRecentiProperty()
|
|
{
|
|
if (! $this->isPostItTableReady()) {
|
|
return collect();
|
|
}
|
|
|
|
try {
|
|
$query = ChiamataPostIt::query()
|
|
->with(['rubrica', 'stabile', 'ticket', 'creatoDa'])
|
|
->orderByDesc('chiamata_il')
|
|
->orderByDesc('id');
|
|
|
|
if ($this->focusPostItId) {
|
|
$query->orderByRaw('CASE WHEN id = ? THEN 0 ELSE 1 END', [$this->focusPostItId]);
|
|
}
|
|
|
|
return $query->limit(50)->get();
|
|
} catch (QueryException) {
|
|
return collect();
|
|
}
|
|
}
|
|
|
|
public function getChiamateTecnicheProperty()
|
|
{
|
|
if (! Schema::hasTable('communication_messages')) {
|
|
return collect();
|
|
}
|
|
|
|
try {
|
|
$query = CommunicationMessage::query()
|
|
->with(['assignedUser:id,name', 'stabile:id,denominazione'])
|
|
->latest('id');
|
|
|
|
if ($this->activeTab === 'smdr') {
|
|
$query->where('channel', 'smdr');
|
|
} elseif ($this->activeTab === 'csta') {
|
|
$query->where('channel', 'panasonic_csta');
|
|
} else {
|
|
$query->whereIn('channel', ['smdr', 'panasonic_csta']);
|
|
}
|
|
|
|
if ($this->tecnicoCallView === 'interne') {
|
|
$query->where('direction', 'internal');
|
|
} elseif ($this->tecnicoCallView === 'esterne') {
|
|
$query->where('direction', '!=', 'internal');
|
|
}
|
|
|
|
if (in_array($this->tecnicoDirectionFilter, ['inbound', 'outbound', 'internal'], true)) {
|
|
$query->where('direction', $this->tecnicoDirectionFilter);
|
|
}
|
|
|
|
$search = trim($this->tecnicoSearch);
|
|
if ($search !== '') {
|
|
$query->where(function ($q) use ($search): void {
|
|
$q->where('phone_number', 'like', '%' . $search . '%')
|
|
->orWhere('target_extension', 'like', '%' . $search . '%')
|
|
->orWhere('message_text', 'like', '%' . $search . '%')
|
|
->orWhere('sender_name', 'like', '%' . $search . '%');
|
|
});
|
|
}
|
|
|
|
$items = $query
|
|
->limit(250)
|
|
->get();
|
|
|
|
if (in_array($this->tecnicoScopeFilter, ['studio', 'esterno', 'interno'], true)) {
|
|
$items = $items->filter(fn(CommunicationMessage $message): bool => $this->getTecnicoScope($message) === $this->tecnicoScopeFilter)->values();
|
|
}
|
|
|
|
$lineFilter = trim($this->tecnicoLineFilter);
|
|
if ($lineFilter !== '') {
|
|
$items = $items->filter(fn(CommunicationMessage $message): bool => $this->matchesTecnicoLineFilter($message, $lineFilter))->values();
|
|
}
|
|
|
|
return $items;
|
|
} catch (QueryException) {
|
|
return collect();
|
|
}
|
|
}
|
|
|
|
public function getRecentClickToCallRequestsProperty()
|
|
{
|
|
if (! Schema::hasTable('pbx_click_to_call_requests')) {
|
|
return collect();
|
|
}
|
|
|
|
$user = Auth::user();
|
|
if (! $user instanceof User) {
|
|
return collect();
|
|
}
|
|
|
|
$extension = $this->normalizeExtension((string) ($user->pbx_extension ?? ''));
|
|
|
|
return PbxClickToCallRequest::query()
|
|
->when($extension !== '', function ($query) use ($extension, $user): void {
|
|
$query->where(function ($inner) use ($extension, $user): void {
|
|
$inner->where('source_extension', $extension)
|
|
->orWhere('requested_by_user_id', (int) $user->id);
|
|
});
|
|
}, fn($query) => $query->where('requested_by_user_id', (int) $user->id))
|
|
->orderByDesc('requested_at')
|
|
->orderByDesc('id')
|
|
->limit(20)
|
|
->get();
|
|
}
|
|
|
|
public function creaPostItDaMessaggio(int $messageId): void
|
|
{
|
|
if (! $this->isPostItTableReady()) {
|
|
Notification::make()->title('Tabella post-it non pronta')->danger()->send();
|
|
return;
|
|
}
|
|
|
|
$message = CommunicationMessage::query()->find($messageId);
|
|
if (! $message) {
|
|
return;
|
|
}
|
|
|
|
if (! empty($message->post_it_id)) {
|
|
Notification::make()->title('Post-it già associato')->warning()->send();
|
|
return;
|
|
}
|
|
|
|
$sourceKey = (string) ($message->channel ?: 'cti');
|
|
$sourceLabel = $sourceKey === 'panasonic_csta' ? 'Panasonic CTI' : 'SMDR';
|
|
$smdr = (array) data_get($message->metadata, 'smdr', []);
|
|
$line = trim((string) ($message->message_text ?? ''));
|
|
$phone = (string) ($message->phone_number ?: ($smdr['dial_number'] ?? ''));
|
|
$nominativo = $this->getTecnicoNominativo($message);
|
|
$lineLabel = $this->getTecnicoLineaLabel($message);
|
|
$direction = match (strtolower(trim((string) $message->direction))) {
|
|
'inbound' => 'Chiamata ricevuta',
|
|
'outbound' => 'Chiamata effettuata',
|
|
'internal' => 'Chiamata interna',
|
|
default => 'Evento telefonico',
|
|
};
|
|
|
|
$oggetto = $direction;
|
|
if ($lineLabel !== '-') {
|
|
$oggetto .= (string) $message->channel === 'smdr'
|
|
? ' - linea ' . $lineLabel
|
|
: ' - ' . $lineLabel;
|
|
}
|
|
|
|
$notaParts = [];
|
|
if ($phone !== '') {
|
|
$notaParts[] = 'Numero: ' . $phone;
|
|
}
|
|
if ($nominativo) {
|
|
$notaParts[] = 'Contatto: ' . $nominativo;
|
|
}
|
|
if ($line !== '') {
|
|
$notaParts[] = 'Dettaglio sorgente: ' . $line;
|
|
}
|
|
|
|
$postIt = ChiamataPostIt::query()->create([
|
|
'stabile_id' => $message->stabile_id,
|
|
'creato_da_user_id' => Auth::id(),
|
|
'telefono' => $message->phone_number,
|
|
'nome_chiamante' => $nominativo ?: ($phone !== '' ? $phone : ($sourceLabel . ' ' . strtoupper((string) $message->direction))),
|
|
'direzione' => $this->normalizePostItDirection((string) $message->direction),
|
|
'origine' => $sourceKey . '_table',
|
|
'origine_id' => (string) $message->id,
|
|
'durata_secondi' => is_numeric($smdr['duration_seconds'] ?? null) ? (int) $smdr['duration_seconds'] : null,
|
|
'oggetto' => $oggetto,
|
|
'nota' => $notaParts !== [] ? implode("\n", $notaParts) : ('Evento ' . $sourceLabel . ' senza dettagli operativi'),
|
|
'priorita' => 'Media',
|
|
'stato' => 'post_it',
|
|
'chiamata_il' => $message->received_at ?? now(),
|
|
]);
|
|
|
|
$message->post_it_id = $postIt->id;
|
|
$message->save();
|
|
|
|
Notification::make()
|
|
->title('Post-it creato da riga tecnica')
|
|
->body('Post-it #' . $postIt->id . ' collegato al messaggio #' . $message->id)
|
|
->success()
|
|
->send();
|
|
}
|
|
|
|
private function normalizePostItDirection(string $direction): string
|
|
{
|
|
$d = strtolower(trim($direction));
|
|
if ($d === 'inbound') {
|
|
return 'in_arrivo';
|
|
}
|
|
if ($d === 'outbound' || $d === 'internal') {
|
|
return 'in_uscita';
|
|
}
|
|
|
|
return 'in_arrivo';
|
|
}
|
|
|
|
public function isPostItTableReady(): bool
|
|
{
|
|
return Schema::hasTable('chiamate_post_it');
|
|
}
|
|
|
|
public function getRubricaUrlByPhone(?string $phone): ?string
|
|
{
|
|
$rubricaId = $this->resolveRubricaIdByPhone($phone);
|
|
if (! $rubricaId) {
|
|
return null;
|
|
}
|
|
|
|
return RubricaUniversaleScheda::getUrl(['record' => $rubricaId], panel: 'admin-filament');
|
|
}
|
|
|
|
public function getRubricaNomeByPhone(?string $phone): ?string
|
|
{
|
|
$rubricaId = $this->resolveRubricaIdByPhone($phone);
|
|
if (! $rubricaId) {
|
|
return null;
|
|
}
|
|
|
|
$rubrica = RubricaUniversale::query()->find($rubricaId, ['id', 'ragione_sociale', 'nome', 'cognome']);
|
|
if (! $rubrica) {
|
|
return null;
|
|
}
|
|
|
|
$nome = trim((string) ($rubrica->ragione_sociale ?: ((string) ($rubrica->nome ?? '') . ' ' . (string) ($rubrica->cognome ?? ''))));
|
|
return $nome !== '' ? $nome : null;
|
|
}
|
|
|
|
public function getTecnicoNominativo(CommunicationMessage $message): ?string
|
|
{
|
|
$extension = $this->extractExtensionFromMessage($message);
|
|
if ($this->isInternalSmdrMessage($message)) {
|
|
return $this->getCollaboratoreNomeByExtension($extension);
|
|
}
|
|
|
|
$phone = (string) ($message->phone_number ?: data_get($message->metadata, 'smdr.dial_number', ''));
|
|
|
|
return $this->getRubricaNomeByPhone($phone);
|
|
}
|
|
|
|
public function getTecnicoProviderLabel(CommunicationMessage $message): string
|
|
{
|
|
$provider = strtolower(trim((string) data_get($message->metadata, 'provider', '')));
|
|
if ($provider === '') {
|
|
$provider = (string) $message->channel;
|
|
}
|
|
|
|
return match ($provider) {
|
|
'smdr' => 'SMDR',
|
|
'panasonic_csta' => 'CSTA',
|
|
'panasonic_ns1000' => 'Panasonic NS1000',
|
|
'freepbx' => 'FreePBX',
|
|
default => strtoupper(str_replace('_', ' ', $provider)),
|
|
};
|
|
}
|
|
|
|
public function getTecnicoLineaLabel(CommunicationMessage $message): string
|
|
{
|
|
if ((string) $message->channel === 'smdr') {
|
|
$line = trim((string) data_get($message->metadata, 'smdr.co', ''));
|
|
return $line !== '' ? $line : '-';
|
|
}
|
|
|
|
$eventType = trim((string) data_get($message->metadata, 'event_type', ''));
|
|
$providerCallId = trim((string) data_get($message->metadata, 'provider_call_id', ''));
|
|
$parts = array_values(array_filter([$eventType, $providerCallId], fn(string $value): bool => $value !== ''));
|
|
|
|
return $parts !== [] ? implode(' / ', $parts) : '-';
|
|
}
|
|
|
|
private function matchesTecnicoLineFilter(CommunicationMessage $message, string $filter): bool
|
|
{
|
|
$needle = mb_strtolower(trim($filter));
|
|
if ($needle === '') {
|
|
return true;
|
|
}
|
|
|
|
$haystacks = [
|
|
mb_strtolower($this->getTecnicoLineaLabel($message)),
|
|
mb_strtolower((string) ($message->target_extension ?? '')),
|
|
mb_strtolower((string) data_get($message->metadata, 'smdr.co', '')),
|
|
mb_strtolower((string) data_get($message->metadata, 'provider_call_id', '')),
|
|
mb_strtolower((string) ($message->message_text ?? '')),
|
|
];
|
|
|
|
foreach ($haystacks as $haystack) {
|
|
if ($haystack !== '' && str_contains($haystack, $needle)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private function buildTicketDescriptionFromPostIt(int $postItId, ChiamataPostIt $postIt): string
|
|
{
|
|
$parts = [];
|
|
|
|
$nota = trim((string) ($postIt->nota ?? ''));
|
|
if ($nota !== '') {
|
|
$parts[] = $nota;
|
|
}
|
|
|
|
$conversioneNote = trim((string) ($this->conversioneNote[$postItId] ?? ''));
|
|
if ($conversioneNote !== '') {
|
|
$parts[] = 'Nota operatore prima della conversione:' . "\n" . $conversioneNote;
|
|
}
|
|
|
|
$parts[] = 'Riferimento chiamata: #' . $postIt->id;
|
|
|
|
return implode("\n\n", $parts);
|
|
}
|
|
|
|
public function richiediClickToCallDaMessaggio(int $messageId): void
|
|
{
|
|
$user = Auth::user();
|
|
if (! $user instanceof User) {
|
|
return;
|
|
}
|
|
|
|
$extension = $this->normalizeExtension((string) ($user->pbx_extension ?? ''));
|
|
if (! (bool) ($user->pbx_click_to_call_enabled ?? false) || $extension === '') {
|
|
Notification::make()->title('Click-to-call non abilitato per il tuo utente')->warning()->send();
|
|
return;
|
|
}
|
|
|
|
$message = CommunicationMessage::query()->find($messageId);
|
|
if (! $message) {
|
|
Notification::make()->title('Messaggio tecnico non trovato')->warning()->send();
|
|
return;
|
|
}
|
|
|
|
$phone = preg_replace('/\D+/', '', (string) ($message->phone_number ?: data_get($message->metadata, 'smdr.dial_number', '')));
|
|
if (! is_string($phone) || $phone === '') {
|
|
Notification::make()->title('Numero non valido')->warning()->send();
|
|
return;
|
|
}
|
|
|
|
PbxClickToCallRequest::query()->create([
|
|
'requested_by_user_id' => (int) $user->id,
|
|
'assigned_user_id' => (int) $user->id,
|
|
'stabile_id' => $message->stabile_id,
|
|
'communication_message_id' => (int) $message->id,
|
|
'source_extension' => $extension,
|
|
'target_number' => $phone,
|
|
'status' => 'pending',
|
|
'note' => 'Richiesta da Post-it Gestione [' . $this->getTecnicoProviderLabel($message) . ']',
|
|
'requested_at' => now(),
|
|
'metadata' => [
|
|
'requested_from' => 'post_it_gestione',
|
|
'source_channel' => (string) $message->channel,
|
|
'provider' => (string) data_get($message->metadata, 'provider', $message->channel),
|
|
'target_extension' => (string) ($message->target_extension ?? ''),
|
|
],
|
|
]);
|
|
|
|
Notification::make()
|
|
->title('Richiesta click-to-call registrata')
|
|
->body('Interno ' . $extension . ' -> ' . $phone)
|
|
->success()
|
|
->send();
|
|
}
|
|
|
|
public function getCollaboratoreNomeByExtension(?string $extension): ?string
|
|
{
|
|
$normalized = $this->normalizeExtension($extension);
|
|
if ($normalized === null) {
|
|
return null;
|
|
}
|
|
|
|
if (array_key_exists($normalized, $this->pbxExtensionCache)) {
|
|
return $this->pbxExtensionCache[$normalized]['name'];
|
|
}
|
|
|
|
if (! Schema::hasColumn('users', 'pbx_extension')) {
|
|
$this->pbxExtensionCache[$normalized] = ['id' => null, 'name' => null];
|
|
return null;
|
|
}
|
|
|
|
$user = User::query()
|
|
->select(['id', 'name', 'pbx_extension'])
|
|
->where('pbx_extension', $normalized)
|
|
->first();
|
|
|
|
$result = [
|
|
'id' => $user ? (int) $user->id : null,
|
|
'name' => $user ? trim((string) $user->name) : null,
|
|
];
|
|
|
|
$this->pbxExtensionCache[$normalized] = $result;
|
|
|
|
return $result['name'];
|
|
}
|
|
|
|
public function isInternalSmdrMessage(CommunicationMessage $message): bool
|
|
{
|
|
if ((string) $message->direction === 'internal') {
|
|
return true;
|
|
}
|
|
|
|
$extension = $this->extractExtensionFromMessage($message);
|
|
$phone = preg_replace('/\D+/', '', (string) ($message->phone_number ?: data_get($message->metadata, 'smdr.dial_number', '')));
|
|
|
|
return $extension !== null && $phone !== '' && $phone === $extension;
|
|
}
|
|
|
|
public function getTecnicoInternoLabel(CommunicationMessage $message): string
|
|
{
|
|
$extension = $this->extractExtensionFromMessage($message);
|
|
if ($extension === null) {
|
|
return '-';
|
|
}
|
|
|
|
$name = $this->getCollaboratoreNomeByExtension($extension);
|
|
if ($name === null) {
|
|
return $extension;
|
|
}
|
|
|
|
return $extension . ' - ' . $name;
|
|
}
|
|
|
|
public function getTecnicoScope(CommunicationMessage $message): string
|
|
{
|
|
if ($this->isInternalSmdrMessage($message)) {
|
|
return 'interno';
|
|
}
|
|
|
|
if ($this->isManagedStudioNumberMessage($message)) {
|
|
return 'studio';
|
|
}
|
|
|
|
return 'esterno';
|
|
}
|
|
|
|
public function getTecnicoScopeLabel(CommunicationMessage $message): string
|
|
{
|
|
return match ($this->getTecnicoScope($message)) {
|
|
'interno' => 'Interno collaboratore',
|
|
'studio' => 'Numero studio gestito',
|
|
default => 'Numero esterno',
|
|
};
|
|
}
|
|
|
|
private function resolveRubricaIdByPhone(?string $phone): ?int
|
|
{
|
|
$digits = preg_replace('/\D+/', '', (string) $phone);
|
|
if (! is_string($digits) || $digits === '') {
|
|
return null;
|
|
}
|
|
|
|
if ($this->isKnownPbxExtension($digits)) {
|
|
return null;
|
|
}
|
|
|
|
if (array_key_exists($digits, $this->rubricaPhoneCache)) {
|
|
return $this->rubricaPhoneCache[$digits];
|
|
}
|
|
|
|
$adminId = (int) (Auth::user()?->amministratore?->id ?? 0);
|
|
|
|
$query = RubricaUniversale::query();
|
|
if ($adminId > 0 && Schema::hasColumn('rubrica_universale', 'amministratore_id')) {
|
|
$query->where(function ($q) use ($adminId): void {
|
|
$q->where('amministratore_id', $adminId)
|
|
->orWhereNull('amministratore_id');
|
|
});
|
|
}
|
|
|
|
$rubricaId = $query
|
|
->where(function ($q) use ($digits): void {
|
|
$q->orWhereRaw("REPLACE(REPLACE(REPLACE(COALESCE(telefono_ufficio,''), ' ', ''), '+', ''), '-', '') LIKE ?", ['%' . $digits . '%'])
|
|
->orWhereRaw("REPLACE(REPLACE(REPLACE(COALESCE(telefono_cellulare,''), ' ', ''), '+', ''), '-', '') LIKE ?", ['%' . $digits . '%'])
|
|
->orWhereRaw("REPLACE(REPLACE(REPLACE(COALESCE(telefono_casa,''), ' ', ''), '+', ''), '-', '') LIKE ?", ['%' . $digits . '%']);
|
|
})
|
|
->orderByDesc('id')
|
|
->value('id');
|
|
|
|
$result = is_numeric($rubricaId) ? (int) $rubricaId : null;
|
|
$this->rubricaPhoneCache[$digits] = $result;
|
|
|
|
return $result;
|
|
}
|
|
|
|
private function extractExtensionFromMessage(CommunicationMessage $message): ?string
|
|
{
|
|
$extension = (string) ($message->target_extension ?: data_get($message->metadata, 'smdr.extension', ''));
|
|
|
|
return $this->normalizeExtension($extension);
|
|
}
|
|
|
|
private function normalizeExtension(?string $extension): ?string
|
|
{
|
|
$digits = preg_replace('/\D+/', '', (string) $extension);
|
|
|
|
return is_string($digits) && $digits !== '' ? $digits : null;
|
|
}
|
|
|
|
private function isKnownPbxExtension(string $digits): bool
|
|
{
|
|
if (strlen($digits) > 6 || ! Schema::hasColumn('users', 'pbx_extension')) {
|
|
return false;
|
|
}
|
|
|
|
return User::query()->where('pbx_extension', $digits)->exists();
|
|
}
|
|
|
|
private function isManagedStudioNumberMessage(CommunicationMessage $message): bool
|
|
{
|
|
$phoneDigits = preg_replace('/\D+/', '', (string) ($message->phone_number ?: data_get($message->metadata, 'smdr.dial_number', '')));
|
|
if (! is_string($phoneDigits) || $phoneDigits === '') {
|
|
return false;
|
|
}
|
|
|
|
return in_array($phoneDigits, $this->getManagedStudioNumbers(), true);
|
|
}
|
|
|
|
/** @return array<int,string> */
|
|
private function getManagedStudioNumbers(): array
|
|
{
|
|
$user = Auth::user();
|
|
if (! $user) {
|
|
return [];
|
|
}
|
|
|
|
$impostazioni = (array) (($user->amministratore?->impostazioni ?? []));
|
|
$centralino = (array) ($impostazioni['centralino'] ?? []);
|
|
|
|
$numbers = [];
|
|
foreach (['numero_principale', 'numero_backup', 'numero_emergenza'] as $key) {
|
|
$digits = preg_replace('/\D+/', '', (string) ($centralino[$key] ?? ''));
|
|
if (is_string($digits) && $digits !== '') {
|
|
$numbers[] = $digits;
|
|
}
|
|
}
|
|
|
|
return array_values(array_unique($numbers));
|
|
}
|
|
|
|
public static function canAccess(): bool
|
|
{
|
|
$user = Auth::user();
|
|
|
|
return $user instanceof User
|
|
&& $user->hasAnyRole(['super-admin', 'admin', 'amministratore', 'collaboratore']);
|
|
}
|
|
}
|