netgescon-day0/app/Services/Cti/LiveIncomingCallService.php

171 lines
7.8 KiB
PHP

<?php
namespace App\Services\Cti;
use App\Filament\Pages\Supporto\TicketMobile;
use App\Models\CommunicationMessage;
use App\Models\RubricaUniversale;
use App\Models\Soggetto;
use App\Models\User;
class LiveIncomingCallService
{
/**
* @return array<string,mixed>|null
*/
public function getForUser(User $user): ?array
{
$userExtension = trim((string) ($user->pbx_extension ?? ''));
$watchedExtensions = app(PbxRoutingService::class)->getWatchedExtensionsForUser($user);
$popupRestricted = (bool) ($user->pbx_popup_enabled ?? false) && count($watchedExtensions) > 0;
$candidates = CommunicationMessage::query()
->whereIn('channel', ['smdr', 'panasonic_csta'])
->where('direction', 'inbound')
->whereNotNull('received_at')
->where('received_at', '>=', now()->subMinutes(8))
->where(function ($query): void {
$query->whereNull('metadata->outcome')
->orWhere(function ($inner): void {
$inner->where('metadata->outcome', 'not like', '%miss%')
->where('metadata->outcome', 'not like', '%no_answer%');
});
})
->where(function ($query): void {
$query->whereNull('message_text')
->orWhere('message_text', 'not like', '%persa%');
})
->when($popupRestricted, function ($query) use ($watchedExtensions): void {
$query->whereIn('target_extension', $watchedExtensions);
})
->latest('received_at')
->limit(30)
->get(['id', 'channel', 'status', 'phone_number', 'target_extension', 'received_at', 'message_text', 'metadata']);
$latest = $candidates
->sortByDesc(function (CommunicationMessage $message): int {
$metadata = is_array($message->metadata) ? $message->metadata : [];
$eventType = strtolower(trim((string) ($metadata['event_type'] ?? '')));
$endedAt = trim((string) ($metadata['ended_at'] ?? ''));
$isActiveCsta = (string) $message->channel === 'panasonic_csta'
&& (string) ($message->status ?? '') !== 'completed'
&& $endedAt === ''
&& ! in_array($eventType, ['connectioncleared', 'cleared', 'released'], true);
if ($isActiveCsta) {
return 5000000000 + (int) ($message->received_at?->getTimestamp() ?? 0);
}
$isRecentCsta = (string) $message->channel === 'panasonic_csta'
&& (int) ($message->received_at?->getTimestamp() ?? 0) >= now()->subSeconds(45)->getTimestamp();
if ($isRecentCsta) {
return 4000000000 + (int) ($message->received_at?->getTimestamp() ?? 0);
}
return 1000000000 + (int) ($message->received_at?->getTimestamp() ?? 0);
})
->first();
if (! $latest) {
return null;
}
$phone = $this->normalizePhoneDigits((string) ($latest->phone_number ?? ''));
if ($phone === '') {
$phone = $this->normalizePhoneDigits((string) data_get($latest->metadata, 'smdr.dial_number', ''));
}
if ($phone === '') {
return null;
}
$rubrica = $this->matchRubricaByPhone($phone);
$soggetto = $this->matchSoggetto($rubrica, $phone);
return [
'message_id' => (int) $latest->id,
'phone' => $phone,
'received_at' => optional($latest->received_at)->format('d/m/Y H:i:s'),
'line' => (string) ($latest->message_text ?? ''),
'target_extension' => (string) ($latest->target_extension ?? ''),
'rubrica_id' => (int) ($rubrica?->id ?? 0),
'rubrica_nome' => (string) ($rubrica?->nome_completo ?: $rubrica?->ragione_sociale ?: ''),
'soggetto_id' => (int) ($soggetto?->id ?? 0),
'can_click_to_call' => (bool) ($user->pbx_click_to_call_enabled ?? false) && $userExtension !== '',
'ticket_mobile_url' => TicketMobile::getUrl([
'live_phone' => $phone,
'live_message_id' => (int) $latest->id,
'live_note' => (string) ($latest->message_text ?? ''),
], panel: 'admin-filament'),
'rubrica_url' => (int) ($rubrica?->id ?? 0) > 0
? \App\Filament\Pages\Gescon\RubricaUniversaleScheda::getUrl(['record' => (int) $rubrica->id], panel : 'admin-filament')
: null,
'estratto_conto_url' => (int) ($soggetto?->id ?? 0) > 0
? \App\Filament\Pages\Contabilita\EstrattoContoSoggetto::getUrl(['record' => (int) $soggetto->id], panel : 'admin-filament')
: null,
'post_it_redirect_url' => TicketMobile::getUrl([
'live_phone' => $phone,
'live_message_id' => (int) $latest->id,
'live_note' => (string) ($latest->message_text ?? ''),
'live_action' => 'post-it',
], panel: 'admin-filament'),
];
}
private function normalizePhoneDigits(string $value): string
{
return preg_replace('/\D+/', '', $value) ?: '';
}
private function matchRubricaByPhone(string $digits): ?RubricaUniversale
{
if ($digits === '') {
return null;
}
$needle = '%' . $digits . '%';
$tail = strlen($digits) >= 7 ? substr($digits, -7) : $digits;
$tailNeedle = '%' . $tail . '%';
return RubricaUniversale::query()
->where(function ($query) use ($needle, $tailNeedle): void {
$query->orWhereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono_cellulare, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') LIKE ?", [$needle])
->orWhereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono_ufficio, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') LIKE ?", [$needle])
->orWhereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono_casa, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') LIKE ?", [$needle])
->orWhereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono_cellulare, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') LIKE ?", [$tailNeedle])
->orWhereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono_ufficio, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') LIKE ?", [$tailNeedle])
->orWhereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono_casa, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') LIKE ?", [$tailNeedle]);
})
->orderByDesc('updated_at')
->first();
}
private function matchSoggetto(?RubricaUniversale $rubrica, string $phone): ?Soggetto
{
if ($rubrica) {
$cf = trim((string) ($rubrica->codice_fiscale ?? ''));
if ($cf !== '') {
$found = Soggetto::query()->where('codice_fiscale', $cf)->first();
if ($found) {
return $found;
}
}
$piva = trim((string) ($rubrica->partita_iva ?? ''));
if ($piva !== '') {
$found = Soggetto::query()->where('partita_iva', $piva)->first();
if ($found) {
return $found;
}
}
}
$tail = strlen($phone) >= 7 ? substr($phone, -7) : $phone;
if ($tail === '') {
return null;
}
return Soggetto::query()->where('telefono', 'like', '%' . $tail . '%')->first();
}
}