Amministrazione

📊 Amministrazione

Gestione amministrativa, costi e prezzi per preventivi

📄
Gestione Amministrativa
Istruzioni, clienti, fatturazione e note operative
📋
Storico Rese
Database rese (ore/u.m.) – aggiornabile solo da diari di cantiere
💰
Costo Orario Operaio
Costo orario medio squadra e coefficienti per i prezzi
🏢
Spese Generali
Calcolo analitico SG reale, incidenza oraria e coefficiente di ricarico
💰
Prezzario
Listino prezzi finale (Tetto, Carpenteria, Demolizioni)
💬
Chat AI Prezziari AI
Interrogazione listini 2025 via Gemini RAG – doppio scenario (Ufficiale/Aziendale), margini SG+UI.

📊 Amministrazione – Protocolli e Struttura

Protocollo repo V2.2: margini e prezziari non dipendono dai commit Auto-sync CRM; la sequenza operativa di deploy (pull, controllo crm_anagrafica.json, push, SSH) è documentata in app/index.php → Sync Git e tracciamento accessi.

Fonte unica coefficienti, protocollo prezzario passivo e regole di calcolo per Agenti AI


🎯 ECCEZIONE – File Amministrazione (Agenti AI): Per ogni ricalcolo costi o prezzi leggi con MASSIMA potenza (lettura COMPLETA) i file chiave: storico_rese.php, costo_orario_operaio.php, spese_generali.php, prezzario.php. Non ottimizzare i crediti su questi file.

PARTE I - STRUTTURA

1. File e gerarchia

Tre fonti collegate: tecnica (rese), economica (coefficienti orari), output commerciale (listino prezzi).

2. Prezziari 2025 – Documenti ufficiali e ricerca globale

I listini anno 2025 sono disponibili in due formati: PDF (documento ufficiale) e Excel (dati). Entrambi sono indicizzati dalla ricerca globale: cercando ad esempio «opere in ferro» o un codice articolo l’utente ottiene risultati che puntano al documento originale (PDF o Excel), non a file intermedi.

Documenti ufficiali (PDF) Database dati (Excel)
Listini in formato documento per stampa e condivisione. Specchio HTML in cache_index/*_pdf.html per l’indicizzazione. Listini in formato foglio (Codice, Descrizione, Prezzo). Specchio HTML in cache_index/*_xlsx.html per l’indicizzazione.

🤖 Documentazione tecnica per Agenti AI – Prezziari 2025 (cache e indicizzazione)

1. LOGICA CACHE: I file in amministrazione/prezziari/2025/cache_index/ sono specchi HTML usati solo per la ricerca full-text. Non modificarli a mano: vengono generati dagli script di conversione.

2. PROTOCOLLO ORIGIN: Ogni file di cache DEVE contenere in cima il tag <!-- ORIGIN_FILE: percorso/file.pdf --> (o .xlsx). Serve a mappare il risultato di ricerca al documento binario originale; l'indexer legge questo commento e espone il link al PDF/Excel.

3. MANUTENZIONE MEMORIA: Per rigenerare la cache di file pesanti (Vol. D, E, F) è OBBLIGATORIO usare PHP con -d memory_limit=2048M. Gli script ottimizzati sono: app/scripts/prezziari_excel_to_html.php (usa setReadDataOnly, filtro fogli, limite 5000 righe) e app/scripts/prezziari_pdf_to_html.php (prime 100 pagine). Senza questo limite i file grandi causano memory exhausted.

4. SCRIPT DI EMERGENZA (manutenzione indicizzazione):

  • Conversione Excel → HTML: app/scripts/prezziari_excel_to_html.php
  • Conversione PDF → HTML: app/scripts/prezziari_pdf_to_html.php
  • Indicizzazione full: app/core/search_indexer.php (argomento full)

Comando consigliato (PowerShell, dalla root): php -d memory_limit=2048M app/scripts/prezziari_excel_to_html.php; poi stesso per prezziari_pdf_to_html.php; infine php app/core/search_indexer.php full.

La Ricerca Globale include entrambi i formati: in caso di match in un file di cache, il link punta al file originale (PDF o Excel) indicato nel commento ORIGIN_FILE. Rigenerazione: php app/scripts/prezziari_excel_to_html.php, php app/scripts/prezziari_pdf_to_html.php; poi php app/core/search_indexer.php full.

Struttura cartella prezziari/2025: PDF in pdf/ (ufficiali), Excel in excel/ (dati). cache_index/: file HTML generati per l'indexer (*_xlsx.html da Excel, *_pdf.html da PDF). Ogni file cache deve avere in cima <!-- ORIGIN_FILE: amministrazione/prezziari/2025/excel|pdf/NOMEFILE.ext -->. Generazione cache: php app/scripts/prezziari_excel_to_html.php (da Excel); per PDF estrarre testo e salvare in cache_index/NOMEFILE_pdf.html. Dopo aggiornamento cache: App → Sincronizza Indice o php app/core/search_indexer.php full. Link risultati ricerca → documento originale (PDF/Excel), non file cache.

💬 Chat AI Prezziari: interrogazione listini 2025 via Gemini RAG. Apri Chat Prezziari 2025

📋 Note per lo Sviluppo – Chat AI Prezziari (Gemini RAG)

ARCHITETTURA: search_to_ai.php estrae contesto da fast_prices.json (o fallback search_index.json) e lo invia a gemini_api.php. API: app/api/chat_prezziari.php (POST message, model).

OBBLIGO DI RAGIONAMENTO: L'AI dichiara sempre il processo: FASE 1 (prezzo finito in listino) → FASE 2 (rese da storico_rese_data.inc.php) → FASE 3 (rese da web se mancano, citando fonte).

FORMATO RISPOSTA (Single-Shot): [ANALISI DELLE FONTI] | [PREZZO SU BASE UFFICIALE] | [PREZZO SU BASE AZIENDALE] | [CONCLUSIONI] | ### FINE_ANALISI ###

COSTO AZIENDALE: Solo «Costo Orario Medio» da costo_orario_operaio.php (nessuna media tra qualifiche). Margini a cascata: Totale = ((Base × 1,15) × 1,10).

MARGINI OBBLIGATORI: Costo base = Resa × Costo orario; SG = +15% sul costo base; UI = +10% su (Costo base + SG); TOTALE = Costo base + SG + UI.

RESE: Da RESE_DI_PREVENTIVO_TETTO in storico_rese_data.inc.php (voci tetto legno); se assente, Gemini può stimare indicando la fonte.

LIMITI: MAX_CONTEXT_CHARS 15000, maxOutputTokens 4096, timeout 120s. API: JSON valido anche in caso di eccezione.

FALLBACK PROSEGUI: Solo se la risposta è troncata (limite token) e non contiene ### FINE_ANALISI ###, il sistema attende 15 secondi e invia «prosegui», concatenando la seconda parte. Barra blu durante l'attesa. Rate limit 429: attesa 65 secondi.

⚠️ STATO SISTEMA: Se il sistema non funziona, Google potrebbe aver bloccato la chiave API Gemini. Per ripristinare: accedere a Google AI Studio o Google Cloud Console, creare nuova API key, aggiornare .env (GEMINI_API_KEY) o app/config/gemini_credentials.php. Verificare debug_log.txt (root) per errori.

📘 Documentazione tecnica completa – Chat Prezziari AI (RAG)

Pipeline indicizzazione: Excel/PDF → prezziari_excel_to_html.php / prezziari_pdf_to_html.php → cache_index/*.html → generate_fast_index.php → fast_prices.json. Schema JSON: c=codice, d=descrizione, p=prezzo, s=sorgente.

Generazione cache: app/scripts/prezziari_excel_to_html.php, prezziari_pdf_to_html.php. Naming: *_xlsx.html, *_pdf.html. Obbligatorio: <!-- ORIGIN_FILE: path --> in cima.

generate_fast_index.php: php app/scripts/generate_fast_index.php. Priorità cache_index, fallback excel. Excel-HTML: regex /<tr>\s*<td>([^<]*)<\/td>...<\/tr>/u. Parte 3 PDF: extractFromParte3Pdf con regex flessibile (1h, 1 ora, ore).

search_to_ai.php (SearchToAi): getContextForQuery(). searchFastIndex() su fast_prices.json: scoring codice peso 3, descrizione 1; boost +50 codici esatti. Parametri: MAX_PREZZARI_ROWS=30, MAX_RESE_ROWS=10, MAX_LABOR_ROWS=10, MAX_CONTEXT_CHARS=8000. LABOR_COST_KEYWORDS per iniezione manodopera. searchFastIndexFallback() per RU/RM/noli. Follow-up: isFollowUpQuery(). Fallback search_index.json se fast_prices vuoto.

API chat_prezziari.php: POST message, model → getContextForQuery → GeminiClient::queryWithContext. Dati iniettati: OFFICIAL_LABOR_RATES (getOfficialLaborRates), COSTI_ORARIO_AZIENDALI (costo_orario_export), RESE_DI_PREVENTIVO_TETTO (storico_rese_data). maxOutputTokens 4096, timeout 120s. Debug: debug_log.txt (RAW_RESPONSE, JSON_DECODE_ERROR, FALLBACK_PING_RESPONSE).

Rate limit 429: 5 RPM piano Free. API restituisce HTTP 429. Frontend: attesa 65s, max 2 retry, pulsante «Riprova ora».

Barre progresso: Blu=attesa rate limit (65s/15s); Verde=trigger testuali (ANALISI FONTI 25%, PREZZO UFFICIALE 50%, PREZZO AZIENDALE 75%, CONCLUSIONI 90%, FINE_ANALISI 100%).

Auto-selezione modello: gemini-2.5-pro 100 req/giorno, gemini-2.5-flash 250/giorno. Storage: app/data/ai_usage.sqlite. ai_usage_log(), ai_usage_get_today_count(), ai_usage_get_dual_stats(). API stats: app/api/ai_usage_stats.php.

File chiave: prezziari_excel_to_html.php, prezziari_pdf_to_html.php, generate_fast_index.php; fast_prices.json, search_index.json; search_to_ai.php, gemini_api.php; chat_prezziari.php (API), chat_prezziari.php (UI); ai_usage_db.php, ai_usage_stats.php.

Troubleshooting: Chiave bloccata → nuova API key. debug_log.txt: RAW_RESPONSE (http_code, curl_error), JSON_DECODE_ERROR, FALLBACK_PING_RESPONSE. «Canale API OK»=chiave OK; «Fallback Ciao fallito»=chiave sospesa.

amministrazione/
├── index.php                  (questa pagina: protocolli e documentazione AI)
├── storico_rese.php           ← FONTE TECNICA: log esperienze di cantiere, Resa Media (ore/u.m.)
├── storico_rese_data.inc.php  (log esperienze + calcolo Resa Media; RESE_DI_PREVENTIVO_TETTO per Chat AI)
├── costo_orario_operaio.php   ← FONTE ECONOMICA: Costo Orario Medio + Monte Ore Squadra (dati in $RUOLI_SQUADRA, base $ORE_MENSILI_STD)
├── spese_generali.php         (pagina dedicata SG: costi annuali, incidenza oraria, percentuale SG reale)
├── costo_orario_export.inc.php  (export coefficienti per Chat Prezziari API – sync con costo_orario_operaio)
├── prezzario.php              ← OUTPUT COMMERCIALE: Prezzo = Resa × Coefficiente
├── gestione.php

4. Storico Rese (fonte tecnica) – Log esperienze di cantiere

Il file storico_rese.php (e i dati in storico_rese_data.inc.php) gestisce un log di esperienze di cantiere per ogni lavorazione. La Resa per prezziario è usata dal Prezzario; Squadra e Qualifiche sono riferimenti vincolanti per pianificazione e preventivi. Export PDF: pulsante «Scarica tabella PDF» per ogni tabella, export client-side tramite DataTables pdfHtml5 (stesso protocollo di prezzario: A3 landscape, font 8/9pt, colonna Dettaglio storico esclusa con no-export). Vedi app/index.php – Sistemi di Esportazione PDF.

📌 Formula Resa per prezziario (Tetto Legno):
  • Se Resa Storica presente (> 0): ((DEI × 0,60) + Resa_Storica) / 2
  • Se Resa Storica assente: DEI × 0,60 (DEI -40%)

La tabella include la colonna DEI -40% (resa DEI × 0,60). Arrotondamento 2 decimali. Carpenteria/Demolizioni: stessa formula (media se Resa Storica presente, altrimenti solo DEI -40%). Funzione calcola_resa_di_preventivo_carpenteria().

Protocollo Storico Rese (Agenti AI)

Istruzioni obbligatorie per storico_rese / storico_rese_data.inc.php. Tutte le spiegazioni tecniche (log, medie, formati, regole squadre) risiedono qui; la pagina storico_rese.php contiene solo dati e legenda.

  • Rese sempre decimali: Le rese devono essere SEMPRE in formato decimale (es. 0.500, 0.278). Mai 1:30, 1h30m o altre notazioni.
  • Squadra ideale – rapporti Q:C: La squadra ideale deve seguire i rapporti Q:C equilibrati (1:1 o 1:2): 2 op. = 1 Qualificato + 1 Comune; 3 op. = 1 Qualificato + 2 Comuni; 4 op. = 2 Qualificati + 2 Comuni.
  • Priorità dati reali: Il sistema deve dare priorità ai dati reali (✅ Effettivo) rispetto alle stime (📝 Stimato): se esistono esperienze Effettive, la Resa Media si calcola solo su quelle; altrimenti si usa la media degli Stimati.
  • Date: GG/MM/AAAA. Squadra Ideale e Qualifiche Ideali = riferimenti vincolanti per pianificazione e preventivi.

Struttura tabelle unificata (Tetti, Carpenteria, Demolizioni):

  • Colonne obbligatorie: Codice, Lavorazione, Note, U.M., Squadra, Qualifiche, Resa DEI (h/U.M.), DEI -40%, Resa storica (h/U.M.), Dettaglio storico, Resa per prezziario (h/U.M.). Usare sempre COLONNE_HEADER_TETTO. Arrotondamento DEI -40% e Resa per prezziario: 2 decimali.
  • Carpenteria/Demolizioni: Dati in storico_rese_data.inc.php con resa_dei, squadra_n, qualifiche, esperienze => []. Resa per prezziario tramite calcola_resa_di_preventivo_carpenteria(): se esistono esperienze con Resa Storica > 0, media tra (DEI×0,60) e Resa Storica; altrimenti solo DEI × 0,60. Icone: ⚖️ media bilanciata, 💡 solo DEI -40%.
  • Nomenclatura colonna: Usare "Resa per prezziario (h/U.M.)" come intestazione, non "Resa di preventivo".

5. Costo Orario Operaio (fonte economica)

Il file costo_orario_operaio.php calcola:

Box in cima: COSTO ORARIO MEDIO OPERAIO e MONTE ORE MENSILE SQUADRA. Sincronizzare costo_orario_export.inc.php (base_medio) con il valore mostrato.

4.1 Spese Generali (SG) – pagina dedicata

Il file spese_generali.php è dedicato solo all'analisi SG: input costi annuali, Totale SG, Incidenza oraria SG e Percentuale SG Reale evidenziata nel KPI principale.

Default variabili operative: la voce Carburante e Pedaggi (2 Auto) usa default dinamico (60 * 2 * 220) ma resta sempre editabile per forfait annuale.

Regola: non reintrodurre nella pagina SG simulazioni prezzo/utile o calcoli commerciali. Le logiche prezzo restano in prezzario.php.

6. Prezzario (output commerciale)

Il file prezzario.php:

5.1 Nota tecnica – Codici Tetto Legno (gerarchia U.M.)

Logica commerciale dei codici univoci (ACC, STR, ABB, FIN, ISO, VEN, SER, SIC, EXT):

  • U.M. cad (a pezzo): Le voci STR-03 (Puntoni/Zoppi pretagliati CNC), ABB-01 (Extra montaggio abbaino), SER-01 (Lucernari + Compensi), EXT-01 (Taglio testa semplice), EXT-02 (Taglio composto/Bocca di lupo) utilizzano l'unità di misura cad per riflettere il tempo di movimentazione e posa dei componenti (pretagliati CNC o lavorati in opera).
  • U.M. ml (metri lineari): La voce TET-07-VEN-03 (Raccordi colmi/Compluvi) utilizza ml per quantificare correttamente il tempo di taglio e sfrido sui raccordi delle pendenze.
  • Sincronizzazione: I prezzi in prezzario.php e le rese in storico_rese.php (e in storico_rese_data.inc.php) devono essere mantenuti sincronizzati usando questi codici univoci; ogni modifica alle rese va propagata al prezzario (obbligo di rigenerazione).

7. COEFFICIENTE_ORARIO vs DIVISORE_34 – Non mischiare

COEFFICIENTE_ORARIO (€/h): costo della singola ora uomo. Usato per calcolo prezzi: Prezzo = Resa × Coefficiente (es. 0,40 ore/mq × 26,73 €/h = 10,69 €/mq).

DIVISORE_34 (4 operai × 8,5 h/giorno = 34 ore uomo/giornata): usato solo per pianificazione temporale – quante giornate servono: Ore uomo totali ÷ 34. Non va mai usato per calcoli economici (prezzi, costi).


PARTE II - PROTOCOLLI OPERATIVI

8. Protocollo Costo Orario

🎯 FONTE COSTO ORARIO MEDIO

costo_orario_operaio.php è la fonte unica per Costo Orario Medio e Monte Ore Squadra. Dati in $RUOLI_SQUADRA, $ORE_MENSILI_STD (160, margine sicurezza), $CONTRIBUTI_MESI (1.100). Calcolo dinamico.

Sync: Aggiornare costo_orario_export.inc.php (base_medio) con il valore Costo Orario Medio mostrato in pagina.

9. Protocollo Prezzario

🎯 FILE PASSIVO

Il Prezzario è un file passivo: usa rese e parametri economici già calcolati dalle fonti amministrative e genera il prezzo finale per utile 10%/20%/30%. Non ricalcola contributi, IVA o costi extra fuori dalle fonti ufficiali.

Procedura: (1) leggi Resa per prezziario (storico), Costo Orario Base (costo_orario_operaio), SG reale (spese_generali). (2) calcola Costo Reale e poi Prezzo = Costo Reale / (1 - %Utile). (3) applica applicaArrotondamentoCommerciale() prima della stampa in tabella.

OBBLIGO DI RIGENERAZIONE: Ogni modifica a storico_rese_data.inc.php, costo_orario_operaio.php o spese_generali.php richiede verifica/ricalcolo del Prezzario.

9.1 Protocollo Lavori in Economia

📌 PROTOCOLLO LAVORI IN ECONOMIA

Per i lavori non presenti nel prezzario (lavori in economia), il prezzo orario da fatturare al cliente deve essere SEMPRE basato sul coefficiente con Margine 30% (base_medio / 0,70) da costo_orario_export.inc.php. Questo serve a coprire l'imprevisto e l'assenza di una resa certificata nello storico.

10. Regole di calcolo e aggiornamento


🤖 Istruzioni Agenti AI

Lettura con MASSIMA potenza

Per ogni ricalcolo costi o prezzi gli Agenti AI devono leggere con MASSIMA potenza (lettura COMPLETA) i file chiave:

  • storico_rese.php (e dati in storico_rese_data.inc.php): rese ore/u.m. per ogni lavorazione.
  • costo_orario_operaio.php: Costo Orario Medio e Monte Ore Squadra (dati in $RUOLI_SQUADRA, base $ORE_MENSILI_STD).
  • spese_generali.php: analisi SG reale (totale, incidenza oraria, percentuale SG).
  • prezzario.php: tabelle commerciali dinamiche (prezzi 10%/20%/30%) con arrotondamento a scaglioni.

Non ottimizzare i crediti su questi file; rispettare la gerarchia (fonte tecnica → fonte economica → output commerciale) e la regola ferrea sulle rese.


🤖 Prompt Ricorrenti

📝 Prompt: "Ricalcolare il Prezzario"

🎯 Obiettivi

  1. Leggi storico_rese.php / storico_rese_data.inc.php, costo_orario_operaio.php, prezzario.php (MASSIMA potenza).
  2. Il Prezzario legge Costo Orario Base da costo_orario_operaio.php e SG reale da spese_generali.php; poi applica Prezzo = (Resa × Costo × (1+SG)) / (1-Margine).
  3. Le rese restano in storico_rese_data.inc.php. Verifica che le tabelle mostrino sempre le tre colonne Prezzo (10% u.i.), Prezzo (20% u.i.), Prezzo (30% u.i.) con arrotondamento commerciale.
  4. Aggiorna la data di aggiornamento. Applica l'arrotondamento commerciale a scaglioni sul prezzo finale di ogni colonna utile.

⚠️ Non introdurre contributi o IVA in prezzario. SG è consentita solo come valore letto dalla pagina dedicata spese_generali.php. Non modificare le rese in storico_rese se non da dati certi dai diari.

🔄 Prompt: "Aggiornare Parametri Amministrativi"

🎯 Obiettivi

  1. Leggi i file chiave (storico_rese, costo_orario_operaio, spese_generali, prezzario) con MASSIMA potenza.
  2. Modifica i parametri in costo_orario_operaio.php (array $RUOLI_SQUADRA, $ORE_MENSILI_STD, $CONTRIBUTI_MESI). I box si aggiornano dinamicamente.
  3. Aggiorna data e note “Modifiche recenti” in costo_orario_operaio. Sincronizza costo_orario_export.inc.php (base_medio) con il Costo Orario Medio mostrato; il prezzario usa quel valore per i coefficienti.

⚠️ Risultato atteso: Costo orario, storico rese e prezzario coerenti; nessun coefficiente obsoleto; rese modificate solo se da diari.

🔍 Prompt: "Verifica Coerenza Matematica"

🎯 Obiettivi (check-up)

  1. Leggi storico_rese_data.inc.php e prendi una lavorazione a campione (es. Isolante Sopra Perlina: resa 0,278 ore/mq).
  2. Usa il coefficiente Listino 30%: Costo_Orario_Medio / 0,70. Calcola: Listino = Resa × Coeff_30%; Sconto 12% = Listino × 0,88; Sconto 22% = Listino × 0,78.
  3. Verifica che i prezzi nel Prezzario corrispondano esattamente (arrotondati a 2 decimali). Se non corrispondono, segnala discrepanza e proponi correzione.

Uso: Eseguire periodicamente o dopo modifiche a rese/coefficienti per garantire coerenza matematica tra storico rese, costo orario e listino prezzi.

📄 Prompt: "Genera Preventivo in Economia"

🎯 Obiettivi

  1. Per lavori non presenti nel prezzario (lavori in economia), usare il coefficiente Aggressivo 30%: Costo_Orario_Medio / 0,70 (da costo_orario_export.inc.php o prezzario).
  2. Calcolare il costo del preventivo basandosi sulle ore stimate moltiplicate per il coefficiente del 30%: Costo = Ore stimate × Coefficiente 30%.
  3. Applicare arrotondamento per eccesso dove previsto. Non usare coefficienti Standard o Conservativo per i lavori in economia.

Uso: Quando il cliente richiede una lavorazione non in listino: stimare le ore uomo necessarie e fatturare con il prezzo orario al 30% per coprire imprevisti e assenza di resa certificata.


Modifiche recenti (21 Febbraio 2026)

Costo Orario Operaio – Squadra tipo 2 team: configurazione per ruoli/quantità ($RUOLI_SQUADRA) con 8 operai totali. Ore standard su base 160h/mese ($ORE_MENSILI_STD) per margine sicurezza, contributi fissi 1.100 €/mese, calcolo dinamico Costo Orario Medio e Monte Ore Mensile Squadra.

Spese Generali – Pagina dedicata SG: KPI primario «Percentuale Spese Generali Reale» in cima; output focalizzato su Totale SG, Incidenza Oraria SG e Percentuale SG. Rimossi simulatore prezzo e dati commerciali non pertinenti.

Prezzario dinamico multi-margine: lettura fonti da costo orario + SG + rese; tre colonne utili (10% / 20% / 30%) con arrotondamento commerciale a scaglioni e colonna Descrizione dedicata.

Storico Rese: colonna “Note” rinominata in “Descrizione”; DEI -40% (×0,60), arrotondamento 2 decimali, struttura unificata tabelle.

Responsive Amministrazione: tabelle principali avvolte in .table-responsive (scroll orizzontale), con header sticky e larghezze minime per evitare wrap verticale estremo della Descrizione su smartphone.

COEFFICIENTE_ORARIO vs DIVISORE_34: COEFFICIENTE = €/h per prezzi; DIVISORE_34 = ore/giorno per pianificazione. Non mischiare.