159 lines
6.6 KiB
PHP
Executable File
159 lines
6.6 KiB
PHP
Executable File
<?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;
|
|
use App\Services\Anagrafiche\RubricaPhoneLookupService;
|
|
use Illuminate\Support\Facades\Schema;
|
|
|
|
class LiveIncomingCallService
|
|
{
|
|
/**
|
|
* @return array<string,mixed>|null
|
|
*/
|
|
public function getForUser(User $user): ?array
|
|
{
|
|
if (! Schema::hasTable('communication_messages')) {
|
|
return null;
|
|
}
|
|
|
|
$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
|
|
{
|
|
return app(RubricaPhoneLookupService::class)->findByPhone($digits);
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|