# GSPL — Verifiche aperte / Analisi del codice

> Aggiornato 13/05/2026 sera dopo lettura del codice.

---

## 1. Disinstallazione + cancellazione eventi VTE + reinstallazione

### Cosa fa il codice (confermato dalla lettura)

Il plugin **ha** un meccanismo specifico per il caso "eventi VTE eliminati mentre il
plugin era offline": si chiama **`gspl_reconcile_orphaned()`**
(vedi `modules/GoogleSyncPlus/cron_sync.php` riga ~524).

Logica del reconcile (eseguito ad ogni run del cron, all'interno di
`syncCalendarForUser`):

```sql
SELECT m.google_id, m.crmid, m.google_updated
FROM vte_googlesyncplus_map m
LEFT JOIN vte_crmentity e ON e.crmid = m.crmid
WHERE m.userid = ? AND m.calendar_id = ?
  AND (e.crmid IS NULL OR e.deleted = 1)
```

Per ogni "mapping orfano" (record VTE eliminato definitivamente o nel cestino):

1. Chiama Google API `GET /calendars/{calId}/events/{googleId}`.
2. Se Google risponde con un evento **attivo**:
   → elimina il mapping orfano e **RICREA l'evento in VTE** (via `processGoogleEvent`).
3. Se Google risponde 404/410 oppure `status=cancelled`:
   → rimuove il mapping (cleanup silenzioso).
4. Altrimenti (errori HTTP transitori): skip, riprova al prossimo giro.

### Comportamento atteso del flusso

| Azione durante "plugin disinstallato" | Effetto al reinstall + cron successivo |
|---|---|
| Evento eliminato in VTE (presente in mapping) | **L'evento viene RICREATO in VTE** dal calendario Google (nuovo `crmid`). |
| Evento eliminato anche in Google nel frattempo | Mapping rimosso. Nessuna ricreazione. |
| Nuovo evento creato in Google | Importato in VTE al primo cron post-OTA (catchup + sync incrementale). |
| Evento modificato in VTE (impossibile: plugin offline = no handler) | N/A |
| Evento modificato in Google | Aggiornato in VTE come al solito (sync). |

**Implicazione importante per l'utente**: dopo la reinstallazione, eliminazioni
fatte in VTE durante il periodo "offline" verranno **annullate** (l'evento
ricomparirà in VTE). Questo è "safe by design" (non si cancella mai su Google
in modo speculativo) ma può sorprendere l'utente.

### Cosa verificare manualmente

- [ ] Disinstalla plugin (preserveData=1 → mapping resta), elimina 2-3 eventi in VTE.
- [ ] Reinstalla plugin.
- [ ] Aspetta il primo cron (o forzalo).
- [ ] Verifica: gli eventi eliminati in VTE sono **ricomparsi** (nuovo crmid),
      e il mapping è stato aggiornato? Confermare il log `[Reconcile] Orfano ...`.
- [ ] Verifica eventi creati su Google nel frattempo: importati correttamente?

### Eventuale miglioramento

- Aggiungere un'opzione nelle preferenze utente: "Eventi eliminati in VTE: ignora
  (default attuale: ricrea) / propaga delete a Google".
- Mostrare in UI un report del Reconcile post-OTA (es. "Ricreati X eventi
  cancellati offline").

---

## 2. Cambio del "calendario principale" lato VTE (target calendar Google)

### Cosa fa il codice (confermato dalla lettura)

Vedi `modules/GoogleSyncPlus/EventHandler.php` riga ~434.

Quando l'utente **modifica un evento Activity** già mappato:

```php
$existingMapping = pquery("SELECT google_id, calendar_id FROM map WHERE crmid = ?", [$eventId]);
$row = fetch(...);
$useCalendarId = !empty($useTargetCalendar) ? $useTargetCalendar : $row['calendar_id'];
$gid = $row['google_id'];
gspl_push_async('update', $eventId, $userId, $useCalendarId, $gid, ...);
syncEventToGoogle($eventId, $userId, $useCalendarId, $gid);
```

**Bug logico critico**:
`$useCalendarId` viene preso PRIMA dal `target_calendar` corrente dell'utente,
NON dal `calendar_id` del mapping originale. Quindi la PUT viene mandata su:

```
PUT https://www.googleapis.com/calendar/v3/calendars/{calB}/events/{googleId_di_calA}
```

Google risponde **404** (l'evento `googleId_di_calA` esiste in calA, non in calB).

`syncEventToGoogle` (vedi `SyncToGoogle.php` riga 550) gestisce 404 così:

```php
} else {
    $log->error("Failed to update event $eventId. Status: " . $response->getStatusCode());
    return false;
}
```

→ **fallimento silenzioso**: nessun fallback, nessun retry, nessuna notifica
all'utente. L'evento originale in calA NON viene aggiornato. Nessun evento
viene creato in calB.

### Cosa avviene dopo il cambio target (riepilogo runtime atteso)

| Evento / Azione | Effetto sul sistema |
|---|---|
| Evento già sincronizzato in calA (mapping=calA) | Continua a esistere in calA. |
| User cambia `google_sync_target_calendar` da calA → calB | Nessuna migrazione automatica. Nessun avviso. |
| User modifica l'evento in VTE | EventHandler manda PUT su calB → **404** → errore log, nessun update propagato. L'evento in calA diventa "stantio". |
| User crea un NUOVO evento in VTE | Va correttamente in calB (target corrente). Mapping=calB. Funziona. |
| User elimina l'evento in VTE | EventHandler usa `$row['calendar_id']` direttamente (vedi riga 549 EventHandler) → DELETE su calA. Funziona. |
| Cron periodico | Continua a fare sync dei calendari in `google_sync_calendars`. Se calA è ancora in `google_sync_calendars` (multi-source), l'evento in calA continua a essere "letto" → eventuali modifiche fatte su Google in calA arrivano comunque a VTE. |

### Bug confermati

1. **Update "stantio"**: modifiche VTE dopo cambio target → fallimento silenzioso
   sull'evento originale.
2. **Nessuna notifica all'utente** del cambio target che ha effetto solo
   sui NUOVI eventi, non sui pregressi.
3. **Nessuna funzionalità di migrazione** automatica (Google API supporta
   `events.move?destination=calB` ma non è usata).

### Possibili fix (in ordine di complessità)

**FIX MINIMO (corretto e semplice)**: in EventHandler, per gli UPDATE usare
sempre `$row['calendar_id']` dal mapping (ignorare `target_calendar` per
eventi già esistenti):

```php
// Patch proposta (EventHandler.php ~ riga 434):
$useCalendarId = $row['calendar_id']; // SEMPRE quello del mapping per update
$gid = $row['google_id'];
gspl_push_async('update', ...);
```

Effetto: l'update lavora sempre sul calendario in cui l'evento ESISTE.
Conseguenza: eventi VTE pre-cambio target restano in calA per sempre
(non migrano), ma almeno le modifiche si propagano correttamente.

**FIX MEDIO**: aggiungere un job di "migrazione target" che, al salvataggio
delle preferenze (cambio `google_sync_target_calendar`), chiama
`events.move?destination=newTarget` su tutti i mapping con
`calendar_id != newTarget`. Aggiorna il mapping con il nuovo `calendar_id`.

**FIX UX**: al cambio target_calendar, mostrare un dialog:
- [ ] Migra X eventi esistenti su <nuovo calendario>  (sposta + aggiorna mapping)
- [ ] Lascia gli eventi esistenti su <vecchio calendario>  (UPDATE futuro lavora sul vecchio)
- [ ] Annulla cambio.

### Cosa verificare manualmente

- [ ] Crea evento in VTE con target_calendar=A. Sincronizza. Verifica in DB
      che il mapping abbia `calendar_id='A'`.
- [ ] Cambia target_calendar a B nelle preferenze utente.
- [ ] Modifica subject/orario dell'evento in VTE.
- [ ] Verifica log `gspl_sync_*.log` / `gspl_ui.log`: dovrebbe esserci
      "Failed to update event X. Status: 404".
- [ ] Verifica su Google Calendar: in calA l'evento è invariato (titolo vecchio),
      in calB non è apparso nulla.
- [ ] Decide la policy (FIX MINIMO / MEDIO / UX) e implementare.

---

## Stato attuale del workspace

- Pacchetto: `GoogleCalendarSyncPlus_v2.3.14_20260513.zip` (root workspace).
- Build dir: `/tmp/gspl_build_v36/`.
- Live install: `/var/www/html/vte23083_2711/modules/GoogleSyncPlus/`.
- File core VTE (Calendar) lasciati allo stato originale 26.04 ufficiale.
- Bug invitati Calendar VTE 26.04: report inviato al team VTE
  (`BUGREPORT_VTE_Calendar_Invitees.md` / `.pdf`), in attesa di fix upstream.
