258 lines
10 KiB
PHP
258 lines
10 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\Amministratore;
|
|
use App\Models\Scadenza;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Arr;
|
|
use Illuminate\Support\Carbon;
|
|
use Illuminate\Support\Facades\Http;
|
|
|
|
class GoogleSyncScadenzeCalendarCommand extends Command
|
|
{
|
|
protected $signature = 'google:sync-scadenze-calendar
|
|
{--admin-id=* : Limita la sincronizzazione a uno o piu ID amministratore}
|
|
{--calendar-id= : Sovrascrive il Calendar ID configurato}
|
|
{--limit=100 : Numero massimo di scadenze da sincronizzare per admin}
|
|
{--days=365 : Orizzonte massimo di giorni futuri da sincronizzare}
|
|
{--dry-run : Simula la sync senza scrivere su Google Calendar}';
|
|
|
|
protected $description = 'Sincronizza le scadenze legacy importate su Google Calendar.';
|
|
|
|
public function handle(): int
|
|
{
|
|
$dryRun = (bool) $this->option('dry-run');
|
|
$limit = max(1, (int) $this->option('limit'));
|
|
$days = max(1, (int) $this->option('days'));
|
|
$forcedCalendarId = trim((string) $this->option('calendar-id'));
|
|
$filterAdminIds = collect((array) $this->option('admin-id'))
|
|
->map(fn($value) => (int) $value)
|
|
->filter(fn(int $value) => $value > 0)
|
|
->values()
|
|
->all();
|
|
|
|
$admins = Amministratore::query()
|
|
->when($filterAdminIds !== [], fn($query) => $query->whereIn('id', $filterAdminIds))
|
|
->get();
|
|
|
|
if ($admins->isEmpty()) {
|
|
$this->warn('Nessun amministratore trovato per i filtri richiesti.');
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
foreach ($admins as $admin) {
|
|
$google = Arr::get($admin->impostazioni ?? [], 'google', []);
|
|
$oauth = Arr::get($google, 'oauth', []);
|
|
|
|
if (! (bool) Arr::get($oauth, 'connected', false)) {
|
|
$this->line("Admin {$admin->id}: Google non collegato, salto.");
|
|
continue;
|
|
}
|
|
|
|
$calendarId = $forcedCalendarId !== ''
|
|
? $forcedCalendarId
|
|
: ((string) Arr::get($google, 'calendar_id', 'primary') ?: 'primary');
|
|
|
|
$token = $this->resolveAccessToken($admin, $google, $oauth, $dryRun);
|
|
if ($token === null) {
|
|
$this->warn("Admin {$admin->id}: token non disponibile, salto.");
|
|
continue;
|
|
}
|
|
|
|
$query = Scadenza::query()
|
|
->with('stabile:id,amministratore_id,denominazione')
|
|
->whereNotNull('data_scadenza')
|
|
->whereDate('data_scadenza', '<=', now()->addDays($days)->toDateString())
|
|
->orderBy('data_scadenza')
|
|
->orderBy('id');
|
|
|
|
$query->where(function ($sub) use ($admin): void {
|
|
$sub->whereHas('stabile', function ($stabileQuery) use ($admin): void {
|
|
$stabileQuery->where('amministratore_id', (int) $admin->id);
|
|
})->orWhereNull('stabile_id');
|
|
});
|
|
|
|
$scadenze = $query->limit($limit)->get();
|
|
$created = 0;
|
|
$updated = 0;
|
|
$errors = 0;
|
|
|
|
foreach ($scadenze as $scadenza) {
|
|
$payload = $this->buildEventPayload($scadenza);
|
|
$event = $this->findEventByScadenzaId($token, $calendarId, (int) $scadenza->id);
|
|
|
|
if ($event === null) {
|
|
if ($dryRun) {
|
|
$created++;
|
|
continue;
|
|
}
|
|
|
|
$response = Http::withToken($token)
|
|
->acceptJson()
|
|
->post('https://www.googleapis.com/calendar/v3/calendars/' . rawurlencode($calendarId) . '/events', $payload);
|
|
|
|
if (! $response->successful()) {
|
|
$errors++;
|
|
continue;
|
|
}
|
|
|
|
$scadenza->calendar_event_id = (string) ($response->json('id') ?? '');
|
|
$scadenza->calendar_synced_at = now();
|
|
$scadenza->save();
|
|
$created++;
|
|
continue;
|
|
}
|
|
|
|
if ($dryRun) {
|
|
$updated++;
|
|
continue;
|
|
}
|
|
|
|
$eventId = trim((string) Arr::get($event, 'id', ''));
|
|
if ($eventId === '') {
|
|
$errors++;
|
|
continue;
|
|
}
|
|
|
|
$response = Http::withToken($token)
|
|
->acceptJson()
|
|
->patch('https://www.googleapis.com/calendar/v3/calendars/' . rawurlencode($calendarId) . '/events/' . rawurlencode($eventId), $payload);
|
|
|
|
if (! $response->successful()) {
|
|
$errors++;
|
|
continue;
|
|
}
|
|
|
|
$scadenza->calendar_event_id = $eventId;
|
|
$scadenza->calendar_synced_at = now();
|
|
$scadenza->save();
|
|
$updated++;
|
|
}
|
|
|
|
$mode = $dryRun ? 'dry-run' : 'apply';
|
|
$this->info("Admin {$admin->id} ({$mode}): create {$created}, aggiornate {$updated}, errori {$errors}.");
|
|
}
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
private function buildEventPayload(Scadenza $scadenza): array
|
|
{
|
|
$date = Carbon::parse($scadenza->data_scadenza);
|
|
$title = $scadenza->titolo_calendario;
|
|
$description = implode("\n", array_filter([
|
|
'Natura: ' . (string) ($scadenza->natura_label ?: $scadenza->natura ?: '-'),
|
|
'Gestione: ' . (string) ($scadenza->gestione_tipo ?: '-'),
|
|
'Stabile: ' . (string) ($scadenza->stabile?->denominazione ?: ($scadenza->codice_stabile_legacy ?: '-')),
|
|
$scadenza->anno ? ('Anno gestione: ' . $scadenza->anno) : null,
|
|
$scadenza->rata ? ('Rata: ' . $scadenza->rata) : null,
|
|
$scadenza->rif_f24 ? ('Rif. F24: ' . $scadenza->rif_f24) : null,
|
|
$scadenza->importo_f24 ? ('Importo F24: ' . number_format((float) $scadenza->importo_f24, 2, ',', '.')) : null,
|
|
]));
|
|
|
|
$payload = [
|
|
'summary' => $title,
|
|
'description' => $description,
|
|
'extendedProperties' => [
|
|
'private' => [
|
|
'netgescon_scadenza_id' => (string) $scadenza->id,
|
|
],
|
|
],
|
|
];
|
|
|
|
if ($scadenza->ora_scadenza) {
|
|
$start = Carbon::parse($scadenza->data_scadenza->format('Y-m-d') . ' ' . $scadenza->ora_scadenza, 'Europe/Rome');
|
|
$payload['start'] = ['dateTime' => $start->toIso8601String(), 'timeZone' => 'Europe/Rome'];
|
|
$payload['end'] = ['dateTime' => $start->copy()->addMinutes(30)->toIso8601String(), 'timeZone' => 'Europe/Rome'];
|
|
} else {
|
|
$payload['start'] = ['date' => $date->toDateString()];
|
|
$payload['end'] = ['date' => $date->copy()->addDay()->toDateString()];
|
|
}
|
|
|
|
return $payload;
|
|
}
|
|
|
|
private function findEventByScadenzaId(string $token, string $calendarId, int $scadenzaId): ?array
|
|
{
|
|
$response = Http::withToken($token)
|
|
->acceptJson()
|
|
->get('https://www.googleapis.com/calendar/v3/calendars/' . rawurlencode($calendarId) . '/events', [
|
|
'privateExtendedProperty' => 'netgescon_scadenza_id=' . $scadenzaId,
|
|
'maxResults' => 1,
|
|
]);
|
|
|
|
if (! $response->successful()) {
|
|
return null;
|
|
}
|
|
|
|
$items = $response->json('items');
|
|
if (! is_array($items) || $items === []) {
|
|
return null;
|
|
}
|
|
|
|
return is_array($items[0]) ? $items[0] : null;
|
|
}
|
|
|
|
private function resolveAccessToken(Amministratore $amministratore, array $google, array $oauth, bool $dryRun, bool $forceRefresh = false): ?string
|
|
{
|
|
$accessToken = trim((string) Arr::get($oauth, 'access_token', ''));
|
|
$refreshToken = trim((string) Arr::get($oauth, 'refresh_token', ''));
|
|
|
|
if (! $forceRefresh && $accessToken !== '') {
|
|
return $accessToken;
|
|
}
|
|
|
|
if ($refreshToken === '') {
|
|
return null;
|
|
}
|
|
|
|
$settingsClientId = trim((string) Arr::get($google, 'client_id', ''));
|
|
$settingsClientSecret = trim((string) Arr::get($google, 'client_secret', ''));
|
|
$configClientId = trim((string) config('services.google.client_id'));
|
|
$configClientSecret = trim((string) config('services.google.client_secret'));
|
|
|
|
$credentialPairs = [];
|
|
if ($settingsClientId !== '' && $settingsClientSecret !== '') {
|
|
$credentialPairs[] = [$settingsClientId, $settingsClientSecret];
|
|
}
|
|
if ($configClientId !== '' && $configClientSecret !== '' && ($configClientId !== $settingsClientId || $configClientSecret !== $settingsClientSecret)) {
|
|
$credentialPairs[] = [$configClientId, $configClientSecret];
|
|
}
|
|
|
|
foreach ($credentialPairs as [$clientId, $clientSecret]) {
|
|
$response = Http::asForm()->post('https://oauth2.googleapis.com/token', [
|
|
'client_id' => $clientId,
|
|
'client_secret' => $clientSecret,
|
|
'refresh_token' => $refreshToken,
|
|
'grant_type' => 'refresh_token',
|
|
]);
|
|
|
|
if (! $response->successful()) {
|
|
continue;
|
|
}
|
|
|
|
$token = trim((string) Arr::get($response->json(), 'access_token', ''));
|
|
if ($token === '') {
|
|
continue;
|
|
}
|
|
|
|
if (! $dryRun) {
|
|
$settings = $amministratore->impostazioni ?? [];
|
|
$settingsGoogle = Arr::get($settings, 'google', []);
|
|
$settingsOauth = Arr::get($settingsGoogle, 'oauth', []);
|
|
$settingsOauth['access_token'] = $token;
|
|
$settingsOauth['expires_in'] = (int) Arr::get($response->json(), 'expires_in', 3600);
|
|
$settingsOauth['refreshed_at'] = now()->toDateTimeString();
|
|
$settingsGoogle['oauth'] = $settingsOauth;
|
|
$settings['google'] = $settingsGoogle;
|
|
$amministratore->impostazioni = $settings;
|
|
$amministratore->save();
|
|
}
|
|
|
|
return $token;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
} |