--- aliases: ["GemmaClient"] type: progetto status: completed --- # CLAUDE.md — GemmaClient **Versione:** v4 **Ultimo aggiornamento:** 2026-06-15 ## Scopo Client Python nativo per GEMMA GSV (`gsv.apps.mediaset.it`) — il sistema interno Mediaset per la gestione del catalogo prodotti TV (acquisizioni, anagrafica, diritti). Obiettivo: applicazione **PyQt6 desktop** che: 1. **Replica l'interfaccia** Anagrafica Prodotti e Prestiti — griglia ricerca + scheda dettaglio 2. **Comunica direttamente** con il backend GEMMA via HTTP (`requests`), nessun browser 3. **Abilita mass data entry** — base per automazioni schedulabili da Frank **Scope:** solo sezione "Anagrafica Prodotti e Prestiti". Tutto il resto di GEMMA è fuori scope. --- ## Autenticazione Il JSESSIONID viene inserito **manualmente** dall'utente (copia dai cookie del browser, come in `C:\Gemma-restyling`). Nessun Selenium, nessun OAuth. - Sessione dura ~1h - Quando scade, l'app mostra "Disconnesso" e chiede di reinserire il JSESSIONID - Il check avviene su ogni risposta: redirect a `/unauthorized` o `/login` = sessione scaduta --- ## Endpoint mappati | Operazione | Metodo | URL | |---|---|---| | Ricerca | GET | `/GSV/mvc/icrTitoli/ricercaParamCustom` | | Dettaglio | GET | `/GSV/mvc/icrTitoli/dettaglioTitolo` | | Salvataggio | POST | `/GSV/mvc/icrTitoli/aggiornaTitolo` | ### Ricerca — parametri query string ``` pagina=1 titolo= tipoRicercaTitolo=contiene|uguale|inizia _supportoIdList=1 _distributoreIdList=1 _tipologiaCodeList=1 ordineVisione=tutto _statoPrestitoCodiceList=1 ``` Headers obbligatori: `x-requested-with: XMLHttpRequest`, `accept: text/html, */*; q=0.01` ### Dettaglio — parametri query string ``` id= isUpdateModality=true isReadonly=false GSVfromICR=false ``` ### Salvataggio — body form-encoded Invia **tutti** i campi del form (non solo quelli modificati). Pattern: GET dettaglio → modifica campi → POST con tutto. Campi principali: `id`, `titolo`, `codiceImdb`, `acquistatoVenduto`, `autore`, `starring`, `data`, `tipologiaCode`, `attivo`, `distributore.id`, `prestito.*`, `episodi[n].*`, `materiali[n].*` **Nessun CSRF token** richiesto. Risposta: HTML (non JSON) — `window.alert` nel browser è solo cosmetic, non ha logica server-side. --- ## Stack - **PyQt6 == 6.7.0** (PINNED) — UI desktop - `requests` — HTTP client verso backend GEMMA - `beautifulsoup4` — parsing HTML risposte - `loguru` — logging standard - `urllib3` — disabilita warning SSL (certificato aziendale) SSL: `verify=False` + `urllib3.disable_warnings(InsecureRequestWarning)` --- ## Struttura directory ``` GemmaClient/ client/ session.py ← GemmaSession (requests.Session + JSESSIONID) search.py ← ricerca prodotti + parse tabella HTML detail.py ← get dettaglio + parse form fields + save app/ main_window.py ← finestra principale (sessione + ricerca + griglia) detail_dialog.py ← dialog dettaglio prodotto (form + salvataggio) main.py ← entry point requirements.txt CLAUDE.md ``` --- ## Nodi aperti / da verificare - **ID nelle righe di ricerca**: il parser `_extract_id()` in `search.py` prova data-id, onclick, hidden input, prima td numerica. Da verificare con HTML reale quale si applica. - **Colonne griglia**: le colonne vengono lette dinamicamente da ``. Da verificare quali colonne ritorna GEMMA. - **Valori tipologiaCode**: `F=Film` confermato. S/D/M da verificare con dati reali. - **Risposta aggiornaTitolo**: da loggare per capire il formato esatto (vedere `save_detail()` in `detail.py`). --- ## Backlog feature - **Batch da Excel**: importare un file Excel con colonne `Titolo`/`IMDB`/`OP` e aggiornare campi in bulk (codice IMDB, stato acquistato). Pattern già usato in Gemma_DatiLoader (ora eliminato). Stesso approccio del bulk-distributore già implementato. --- ## Regole operative - Tieni aggiornato `SESSION_NOTES.md` durante il lavoro - Commit dopo ogni cambiamento rilevante, messaggi in inglese - NON committare: `logs/`, `SESSION_NOTES.md`, credenziali, cookie