1/** 2 * tec-tab3-ssot.js â Classificazione P/S/C Tab 3 (Luoghi & Sopralluoghi) â Tab 4 Principale 3 * P = mirror read-only da Luogo Principale (Tab 4); S = fonte solo Tab 3/sede; C = calcolato. 4 * 5 * CPI SSOT (P2): i campi antincendio/CPI del Luogo Principale vivono in 6 * ambientiSede[principale=true].impianti.cpi (legacy: luoghiLavoro[principale_home].impianti.cpi) 7 * Tab 2 (Sede Generale) = mirror read-only mono-Luogo; multi-sede = blocchi CPI editabili 8 * che scrivono sul bag cpi + sync bidirezionale verso d.* flat (legacy DVR/readiness). 9 */ 10(function (root) { 11 'use strict'; 12 13 var P = 'P'; 14 var S = 'S'; 15 var C = 'C'; 16 var G = 'G'; 17 var L = 'L'; 18 var O = 'O'; 19 20 function _t(tier, pin, nav, extra) { 21 var o = { tier: tier, pin: pin || '', nav: nav || (tier === P || tier === L ? 'luogo_principale' : tier === C ? 'computed' : 'tab3') }; 22 if (extra) Object.keys(extra).forEach(function (k) { o[k] = extra[k]; }); 23 return o; 24 } 25 26 /** Entity tier G/L/C/O (v3.2) â indipendente da mirror P/S legacy. */ 27 root.TAB3_FIELD_ENTITY = { 28 areaEstPresente: L, areaEstDest: L, areaEstDelimitazione: L, nAccessiCarrabili: L, nAccessiPedonali: L, 29 areaEstSeparaPedCarr: L, problemaAccessoVeic: L, problemaAccessoVeicTipo: L, 30 problemaAccessoVeicMisure: L, descrizioneEdificio: G, 31 ingressoPrincVia: L, ingressoPrincTipo: L, ingressoPrincQuota: L, rampDisabili: L, 32 impLegionella_presente: G, impLegionella_pianoControllo: G, impLegionella_responsabile: G, 33 impLegionella_ultimaVerifica: G, impLegionella_esito: G, impLegionella_ditta: G, 34 sciaNumero: G, sciaData: G, sciaCategoria: G, sciaNotaInterna: G, sciaTestoDVR: G, sciaIncludiDVR: G, 35 osservAccessi: O, osservLocali: O, osservImpiantistica: O, osservRischi: O, osservNote: O, 36 nDipendenti: C, nBlocchiWCTotale: C, nServiziIgienici: C, nBlocchiWC: C, rischioIncendioVecchio: C, 37 tipoEdificio: L, tipologiaStrutturale: L, annoCostruzione: L, nPianiFT: L, nPianiInterrati: L, 38 superficie: L, superficieCoperta: L, superficieEsterna: L, maxPresenze: L, nPostazioniVdt: L, 39 destinazioneUso: L, descrizioneLuogo: L, piani: L, corpoScalaInterno: L, blocchiWC: L, conformitaDPR503: L, 40 soggettoVVF: L, statoCPI: L, cpiNumero: L, cpiScadenza: L, rischioIncendioNuovo: L, gruppoPS: L 41 }; 42 43 root._tab3FieldEntityTier = function (key) { 44 return root.TAB3_FIELD_ENTITY[key] || null; 45 }; 46 47 /** Marker esplicito P/S/C per campi Tab 3 (3Aâ3M) + nav SSOT Legal «Vai â». */ 48 root.TAB3_FIELD_SSC = { 49 /* 3A â Struttura */ 50 tipoEdificio: _t(P, '3A.1'), 51 tipologiaStrutturale: _t(P, '3A.2'), 52 annoCostruzione: _t(P, '3A.3'), 53 nPianiFT: _t(P, '3A.4'), 54 nPianiInterrati: _t(P, '3A.5'), 55 superficie: _t(P, '3A.6'), 56 superficieCoperta: _t(P, '3A.6'), 57 superficieEsterna: _t(P, '3A.7'), 58 maxPresenze: _t(P, '3A.8'), 59 nPostazioniVdt: _t(P, '3A.9'), 60 destinazioneUso: _t(P, '3A.10', 'luogo_principale', { openT2Sec: 'struct', luogoSubTab: 'struttura' }), 61 62 /* 3B â Area esterna (mirror Luogo Principale â Tab 4 Struttura) */ 63 areaEstPresente: _t(P, '3B', 'luogo_principale', { openT2Sec: 'area', luogoSubTab: 'struttura' }), 64 areaEstDest: _t(P, '3B', 'luogo_principale', { openT2Sec: 'area', luogoSubTab: 'struttura' }), 65 areaEstDelimitazione: _t(P, '3B', 'luogo_principale', { openT2Sec: 'area', luogoSubTab: 'struttura' }), 66 nAccessiCarrabili: _t(P, '3B', 'luogo_principale', { openT2Sec: 'area', luogoSubTab: 'struttura' }), 67 nAccessiPedonali: _t(P, '3B', 'luogo_principale', { openT2Sec: 'area', luogoSubTab: 'struttura' }), 68 areaEstSeparaPedCarr: _t(P, '3B', 'luogo_principale', { openT2Sec: 'area', luogoSubTab: 'struttura' }), 69 accessiCarrabili: _t(S, '3B', 'tab3', { openT2Sec: 'area' }), 70 problemaAccessoVeic: _t(P, '3B', 'luogo_principale', { openT2Sec: 'area', luogoSubTab: 'struttura' }), 71 problemaAccessoVeicTipo: _t(P, '3B', 'luogo_principale', { openT2Sec: 'area', luogoSubTab: 'struttura' }), 72 problemaAccessoVeicMisure: _t(P, '3B', 'luogo_principale', { openT2Sec: 'area', luogoSubTab: 'struttura' }), 73 descrizioneEdificio: _t(S, '3B.2', 'tab3', { openT2Sec: 'note2i' }), 74 descrizioneAmbiente: _t(S, '3B.1', 'tab3'), 75 descrizioneLuogo: _t(S, '3B.1', 'tab3', { entity: L, aliasOf: 'descrizioneAmbiente' }), 76 77 /* 3C â Ingresso (mirror Luogo Principale â Tab 4 Struttura / Anagrafica) */ 78 ingressoPrincVia: _t(P, '3C.1', 'luogo_principale', { openT2Sec: 'ingr', luogoSubTab: 'anagrafica', entity: L }), 79 ingressoPrincTipo: _t(P, '3C', 'luogo_principale', { openT2Sec: 'ingr_g', luogoSubTab: 'struttura', entity: L }), 80 ingressoPrincQuota: _t(P, '3C', 'luogo_principale', { openT2Sec: 'ingr_g', luogoSubTab: 'struttura', entity: L }), 81 rampDisabili: _t(P, '3C', 'luogo_principale', { openT2Sec: 'ingr_g', luogoSubTab: 'struttura', entity: L }), 82 83 /* 3D â Piani */ 84 piani: _t(P, '3D'), 85 86 /* 3F â Verticali */ 87 corpoScalaInterno: _t(P, '3F'), 88 nCorpiScala: _t(P, '3F'), 89 montascale: _t(P, '3F'), 90 montascaleTipo: _t(P, '3F'), 91 impAscensore_presente: _t(P, '3F'), 92 ascensore: _t(P, '3F'), 93 nAscensori: _t(P, '3F'), 94 nAscensors: _t(P, '3F'), 95 scalaEmergenzaEst: _t(P, '3F'), 96 nScaleEmergenza: _t(P, '3F'), 97 scalaEmergenzaUbicazione: _t(P, '3F.1'), 98 99 /* 3G â Servizi igienici */ 100 blocchiWC: _t(P, '3G', 'luogo_principale', { openT2Sec: 'wc' }), 101 nBlocchiWCTotale: _t(C, '3G', 'tab3_wc', { compute: 'sum_wc_luoghi', openT2Sec: 'wc' }), 102 nServiziIgienici: _t(C, '3G', 'tab3_wc', { compute: 'sum_wc_luoghi', openT2Sec: 'wc' }), 103 nBlocchiWC: _t(C, '3G', 'tab3_wc', { compute: 'sum_wc_luoghi', openT2Sec: 'wc' }), 104 wcPavPiastrellati: _t(P, '3G'), 105 wcAltPiastrellatura: _t(P, '3G'), 106
107 /* 3H â Accessibilità */ 108 conformitaDPR503: _t(P, '3H'), 109 barrierePresenti: _t(P, '3H'), 110 tipoBarriere: _t(P, '3H'), 111 112 /* 3I â Impiant; 3I.7 Legionella = Sede */ 113 impLegionella_presente: _t(S, '3I.7', 'tab3', { openT2Sec: 'impianti' }), 114 impLegionella_pianoControllo: _t(S, '3I.7', 'tab3'), 115 impLegionella_responsabile: _t(S, '3I.7', 'tab3'), 116 impLegionella_ultimaVerifica: _t(S, '3I.7', 'tab3'), 117 impLegionella_esito: _t(S, '3I.7', 'tab3'), 118 impLegionella_ditta: _t(S, '3I.7', 'tab3'), 119 120 /* 3J/3K/3L â Antincendio principale + SCIA sede */ 121 attivitaDPR151: _t(P, '3J'), 122 numAttivitaPrinc: _t(P, '3J'), 123 categoriaAttivita: _t(P, '3J'), 124 criterioClassifica: _t(P, '3J'), 125 attivitaSecondarie: _t(P, '3J'), 126 centraleTerm: _t(P, '3J'), 127 centraleTermCombust: _t(P, '3J'), 128 centraleTermKW: _t(P, '3J'), 129 rischioIncendioVecchio: _t(C, '3K', 'tab3', { compute: 'incendio_vecchio' }), 130 rischioIncendioNuovo: _t(P, '3K'), 131 classeRischioIncendio: _t(P, '3K'), 132 gruppoPS: _t(P, '3K'), 133 soggettoVVF: _t(P, '3L'), 134 statoCPI: _t(P, '3L'), 135 cpiNumero: _t(P, '3L'), 136 cpiScadenza: _t(P, '3L'), 137 sciaNumero: _t(S, '3L', 'tab3', { openT2Sec: 'fire' }), 138 sciaData: _t(S, '3L', 'tab3', { openT2Sec: 'fire' }), 139 sciaCategoria: _t(S, '3L', 'tab3', { openT2Sec: 'fire' }), 140 sciaNotaInterna: _t(S, '3L', 'tab3', { openT2Sec: 'fire' }), 141 sciaTestoDVR: _t(S, '3L', 'tab3', { openT2Sec: 'fire' }), 142 sciaIncludiDVR: _t(S, '3L', 'tab3', { openT2Sec: 'fire' }), 143 porteRei: _t(P, '3I'), 144 145 /* 3M â Osservazioni sopralluogo (solo Tab 3) */ 146 osservAccessi: _t(S, '3M.1', 'tab3', { openT2Sec: 'osserv_sopralluogo' }), 147 osservLocali: _t(S, '3M.2', 'tab3', { openT2Sec: 'osserv_sopralluogo' }), 148 osservImpiantistica: _t(S, '3M.3', 'tab3', { openT2Sec: 'osserv_sopralluogo' }), 149 osservRischi: _t(S, '3M.4', 'tab3', { openT2Sec: 'osserv_sopralluogo' }), 150 osservNote: _t(S, '3M.5', 'tab3', { openT2Sec: 'osserv_sopralluogo' }), 151 152 /* Calcolati organico */ 153 nDipendenti: _t(C, '5A.1', 'triade_mansioni', { compute: 'organico' }) 154 }; 155 156 root._tab3FieldTier = function (key) { 157 var m = root.TAB3_FIELD_SSC[key]; 158 return m ? m.tier : null; 159 }; 160 161 root._tab3IsPrincipaleMirror = function (key) { 162 return root._tab3FieldTier(key) === P; 163 }; 164 165 root._tab3IsSedeSource = function (key) { 166 return root._tab3FieldTier(key) === S; 167 }; 168 169 root._tab3IsComputed = function (key) { 170 return root._tab3FieldTier(key) === C; 171 }; 172 173 /** SSOT CPI â chiavi nel bag impianti.cpi del Luogo Principale (tier L, mirror P in Tab 3). */ 174 root.TAB3_CPI_SSOT_KEYS = [ 175 'soggettoVVF', 'statoCPI', 'cpiNumero', 'cpiScadenza', 176 'rischioIncendioVecchio', 'rischioIncendioNuovo', 'gruppoPS', 177 'attivitaDPR151', 'numAttivitaPrinc', 'categoriaAttivita', 'criterioClassifica', 178 'centraleTerm', 'centraleTermKW', 'centraleTermCombust' 179 ]; 180 root.TAB3_CPI_SSOT_PATH = 'ambientiSede[principale].impianti.cpi'; 181 182 function _sedeIdFromProject() { 183 try { 184 var p = typeof CP === 'function' ? CP() : null; 185 if (typeof root._projectSedeId === 'function') return root._projectSedeId(p) || ''; 186 return (p && (p.sedeId || (p.data && p.data.sedeId))) || ''; 187 } catch (_) { return ''; } 188 } 189 190 function _cpiBag(luogo) { 191 return (luogo && luogo.impianti && luogo.impianti.cpi) || {}; 192 } 193 194 function _cpiVal(luogo, d, key) { 195 if (typeof root._tab2LuogoFieldVal === 'function') { 196 return root._tab2LuogoFieldVal(luogo, key, d || {}); 197 } 198 var cpi = _cpiBag(luogo); 199 if (cpi[key] != null && cpi[key] !== '') return cpi[key]; 200 return d ? d[key] : undefined; 201 } 202 203 var TAB2_LUOGO_BAG_KEYS = { 204 areaEstPresente: ['areeEsterne', 'areaEstPresente'], 205 areaEstDest: ['areeEsterne', 'areaEstDest'], 206 areaEstDelimitazione: ['areeEsterne', 'areaEstDelimitazione'], 207 nAccessiCarrabili: ['areeEsterne', 'nAccessiCarrabili'], 208 nAccessiPedonali: ['areeEsterne', 'nAccessiPedonali'], 209 areaEstSeparaPedCarr: ['areeEsterne', 'areaEstSeparaPedCarr'], 210 problemaAccessoVeic: ['areeEsterne', 'problemaAccessoVeic'], 211 problemaAccessoVeicTipo: ['areeEsterne', 'problemaAccessoVeicTipo'], 212 problemaAccessoVeicMisure: ['areeEsterne', 'problemaAccessoVeicMisure'], 213 ingressoPrincTipo: ['ingresso', 'ingressoPrincTipo'], 214 ingressoPrincQuota: ['ingresso', 'ingressoPrincQuota'], 215 rampDisabili: ['ingresso', 'rampDisabili'], 216 barrierePresenti: ['accessibilita', 'barrierePresenti'], 217 tipoBarriere: ['accessibilita', 'tipoBarriere'], 218 conformitaDPR503: ['accessibilita', 'conformitaDPR503'], 219 nBlocchiWCTotale: ['serviziIgienici', 'nBlocchiWCTotale'], 220 wcPavPiastrellati: ['serviziIgienici', 'wcPavPiastrellati'], 221 wcAltPiastrellatura: ['serviziIgienici', 'wcAltPiastrellatura'], 222 blocchiWC: ['serviziIgienici', 'blocchiWC'] 223 }; 224 225 function _hasLuogoVal(v) { 226 return v != null && v !== '' && !(Array.isArray(v) && !v.length); 227 } 228 229 /** SSOT lettura campo per ambiente/luogo Tab 18 â alias superficie â superficie_mq, maxPresenze â capienza_max. */ 230 root._tab2LuogoFieldVal = function (luogo, key, d) {
231 if (!luogo || !key) return null; 232 d = d || (typeof root.D === 'function' ? root.D() : null); 233 if (key === 'superficie') { 234 if (_hasLuogoVal(luogo.superficie_mq)) return luogo.superficie_mq; 235 if (_hasLuogoVal(luogo.superficie)) return luogo.superficie; 236 if (_hasLuogoVal(luogo.superficieCoperta)) return luogo.superficieCoperta; 237 return null; 238 } 239 if (key === 'superficieCoperta') { 240 if (_hasLuogoVal(luogo.superficieCoperta)) return luogo.superficieCoperta; 241 if (_hasLuogoVal(luogo.superficie_mq)) return luogo.superficie_mq; 242 return null; 243 } 244 if (key === 'maxPresenze') { 245 if (_hasLuogoVal(luogo.capienza_max)) return luogo.capienza_max; 246 if (_hasLuogoVal(luogo.presenzeMassime)) return luogo.presenzeMassime; 247 if (_hasLuogoVal(luogo.maxPresenze)) return luogo.maxPresenze; 248 return null; 249 } 250 if (key === 'nPostazioniVdt') { 251 if (_hasLuogoVal(luogo.nPostazioniVdt)) return luogo.nPostazioniVdt; 252 var comfort = luogo.comfort || {}; 253 if (_hasLuogoVal(comfort.nPostazioniVdt)) return comfort.nPostazioniVdt; 254 return null; 255 } 256 if (key === 'destinazioneUso') { 257 if (_hasLuogoVal(luogo.destinazioneUso)) return luogo.destinazioneUso; 258 if (_hasLuogoVal(luogo.descrizioneLuogo)) return luogo.descrizioneLuogo; 259 return null; 260 } 261 if (root.TAB3_CPI_SSOT_KEYS && root.TAB3_CPI_SSOT_KEYS.indexOf(key) >= 0) { 262 if (root._tecCpiEdificioScope && typeof root._tecCpiEdificioScope.getCpiField === 'function') { 263 var dCtx = d || (typeof root.D === 'function' ? root.D() : null); 264 var listCtx = (dCtx && dCtx.ambientiSede) || []; 265 var resolved = root._tecCpiEdificioScope.getCpiField(luogo, key, listCtx, dCtx); 266 if (_hasLuogoVal(resolved)) return resolved; 267 } 268 var cpi = _cpiBag(luogo); 269 if (_hasLuogoVal(cpi[key])) return cpi[key]; 270 if (d && _hasLuogoVal(d[key])) return d[key]; 271 return null; 272 } 273 var bagPath = TAB2_LUOGO_BAG_KEYS[key]; 274 if (bagPath) { 275 var bag = luogo[bagPath[0]]; 276 if (bag && _hasLuogoVal(bag[bagPath[1]])) return bag[bagPath[1]]; 277 } 278 if (key === 'ingressoPrincVia' && _hasLuogoVal(luogo.posizione)) return luogo.posizione; 279 if (key === 'piani') return luogo.piani || null; 280 if (key === 'porteRei') { 281 // v20.373.102 â SSOT reale: luogo.porteRei. `impianti.porteRei` non e' mai scritto da nessuno 282 // (era una copia di d.porteRei innestata al build) â il lettore concludeva sempre «nessuna». 283 if (_hasLuogoVal(luogo.porteRei)) return luogo.porteRei; 284 var pr = luogo.impianti && luogo.impianti.porteRei; 285 return _hasLuogoVal(pr) ? pr : null; 286 } 287 if (key === 'attivitaSecondarie') { 288 var cpiAs = _cpiBag(luogo); 289 return _hasLuogoVal(cpiAs.attivitaSecondarie) ? cpiAs.attivitaSecondarie : null; 290 } 291 // v20.371.13 â SoT UI = flat sul luogo; bag impianti.ascensore è mirror legacy (fallback se flat vuoto). 292 if (_hasLuogoVal(luogo[key])) return luogo[key]; 293 var imp = luogo.impianti || {}; 294 var asc = imp.ascensore || {}; 295 var ascKeys = ['corpoScalaInterno', 'nCorpiScala', 'montascale', 'montascaleTipo', 'scalaEmergenzaEst', 'nScaleEmergenza', 'scalaEmergenzaUbicazione']; 296 if (ascKeys.indexOf(key) >= 0 && _hasLuogoVal(asc[key])) return asc[key]; 297 if ((key === 'ascensore' || key === 'impAscensore_presente') && _hasLuogoVal(asc.ascensore)) return asc.ascensore; 298 if ((key === 'impAscensore_presente') && _hasLuogoVal(asc.impAscensore_presente)) return asc.impAscensore_presente; 299 if ((key === 'nAscensors' || key === 'nAscensori') && _hasLuogoVal(asc.nAscensori)) return asc.nAscensori; 300 return null; 301 }; 302 303 function _isEmptyCpiVal(v) { 304 return v == null || v === '' || (Array.isArray(v) && !v.length); 305 } 306 307 /** Luogo Principale (SoT) â mirror flat d.* per legacy DVR/readiness/scadenziario. */ 308 root._tab3MirrorCpiFlatFromLuogo = function (d, luogo, opts) { 309 opts = opts || {}; 310 if (!d) return false; 311 var cpi = _cpiBag(luogo); 312 var keys = opts.keys || root.TAB3_CPI_SSOT_KEYS; 313 var changed = false;
314 keys.forEach(function (key) { 315 var lv = cpi[key]; 316 if (opts.singleKey && key !== opts.singleKey) return; 317 if (opts.singleKey && opts.value !== undefined) lv = opts.value; 318 if (opts.rewireAll && _isEmptyCpiVal(lv)) lv = ''; 319 else if (_isEmptyCpiVal(lv)) return; 320 if (d[key] !== lv) { 321 d[key] = lv; 322 changed = true; 323 } 324 }); 325 return changed; 326 }; 327 328 /** Backfill bag cpi vuoto da mirror flat (migrazione progetti pre-Luogo). */ 329 root._tab3CpiBackfillPatch = function (luogo, d) { 330 if (!luogo || !d) return null; 331 var cpi = Object.assign({}, _cpiBag(luogo)); 332 var patch = {}; 333 var needs = false; 334 root.TAB3_CPI_SSOT_KEYS.forEach(function (key) { 335 if (!_isEmptyCpiVal(cpi[key])) return; 336 var fv = d[key]; 337 if (_isEmptyCpiVal(fv)) return; 338 cpi[key] = fv; 339 patch[key] = fv; 340 needs = true; 341 }); 342 if (!needs) return null; 343 return { cpi: cpi, patch: patch, needsSave: true }; 344 }; 345 346 /** Sync bidirezionale: SoT luogoâflat; flatâluogo solo se bag cpi vuoto (backfill). */ 347 root._tab3SyncCpiBidirectional = function (d, luogo, opts) { 348 opts = opts || {}; 349 var out = { changed: false, backfill: null, directions: [] }; 350 if (!d) return out; 351 if (luogo && root._tab3MirrorCpiFlatFromLuogo(d, luogo, opts)) { 352 out.changed = true; 353 out.directions.push('luogoâflat'); 354 } 355 if (opts.backfillLuogo !== false && luogo) { 356 var bf = root._tab3CpiBackfillPatch(luogo, d); 357 if (bf && bf.needsSave) { 358 out.backfill = bf; 359 out.directions.push('flatâluogo(backfill)'); 360 if (opts.persistBackfill && root._tecGrafo && root._tecGrafo.saveAmbiente) { 361 var sedeId = _sedeIdFromProject(); 362 if (sedeId && luogo.id) { 363 var imp = Object.assign({}, luogo.impianti || {}, { cpi: bf.cpi }); 364 try { 365 root._tecGrafo.saveAmbiente(sedeId, { id: luogo.id, impianti: imp }); 366 if (root._tab2LuogoHomeCache && root._tab2LuogoHomeCache.id === luogo.id) { 367 root._tab2LuogoHomeCache.impianti = imp; 368 } 369 } catch (_) {} 370 } 371 } 372 } 373 } 374 return out; 375 }; 376 377 /** Luoghi operativi per guard P13 / KPI Tab 3 â allineato a sidebar Tab 4 (no leak, no tombstone, no sopralluogo). */ 378 root._tab3OperationalAmbientiList = function (d) { 379 d = d || (typeof D === 'function' ? D() : null); 380 var list = (d && d.ambientiSede) ? d.ambientiSede.slice() : []; 381 if (!list.length && typeof root._tab2MergedAmbientiList === 'function') { 382 list = root._tab2MergedAmbientiList(d) || []; 383 } 384 if (!list.length && typeof root._getEntitaForAssessment === 'function') { 385 try { 386 return (root._getEntitaForAssessment(d, 'luogo') || []).filter(function (ent) { 387 return ent && ent._grafoAmbienteId; 388 }).map(function (ent) { 389 return { id: ent._grafoAmbienteId || ent.id, nome: ent.nome, principale: ent.principale, sopralluogo: ent.sopralluogo }; 390 }); 391 } catch (_) {} 392 return []; 393 } 394 var G = root._tecGrafo; 395 if (G && typeof G.filterAmbientiByTombstones === 'function') { 396 list = G.filterAmbientiByTombstones(list, d); 397 } 398 var E = root._tecGmrEpcLuoghi; 399 if (E && typeof E.filterConsultantLuogoLeak === 'function') { 400 list = E.filterConsultantLuogoLeak(list, d); 401 } 402 var R = root._tecSopralluogoRegistro; 403 return list.filter(function (amb) { 404 if (!amb) return false; 405 if (R && typeof R.isAmbienteSopralluogo === 'function') return !R.isAmbienteSopralluogo(amb, d); 406 return amb.sopralluogo !== true; 407 }); 408 }; 409 410 root._tab3CountLuoghi = function (d) { 411 var ops = root._tab3OperationalAmbientiList(d); 412 if (ops.length) return ops.length; 413 if (typeof root._getEntitaForAssessment === 'function') { 414 try { return (root._getEntitaForAssessment(d, 'luogo') || []).length; } catch (_) {} 415 } 416 return 0; 417 }; 418 419 /** Mono + multi: CPI editabile in Tab 2 (scrittura SSOT impianti.cpi Principale). Tab 4 ha editor baseline 3K. */ 420 root._tab3CpiTab2Editable = function (d) { 421 return true; 422 }; 423 424 /** Campi 3A UI â mirror chirurgico da Luogo Principale (Tab 4 Struttura / Anagrafica / Comfort). */ 425 root.TAB3_MIRROR_3A_KEYS = [ 426 'tipoEdificio', 'tipologiaStrutturale', 'annoCostruzione', 'destinazioneUso', 427 'nPianiFT', 'nPianiInterrati', 'superficie', 'superficieCoperta', 'superficieEsterna', 428 'maxPresenze', 'nPostazioniVdt' 429 ]; 430 431 /** Campi 3B â solo quelli editabili su Tab 4 â Struttura â areeEsterne. */ 432 root.TAB3_MIRROR_3B_KEYS = [ 433 'areaEstPresente', 'areaEstDest', 'areaEstDelimitazione', 'nAccessiCarrabili', 'nAccessiPedonali', 434 'areaEstSeparaPedCarr', 'problemaAccessoVeic', 'problemaAccessoVeicTipo', 'problemaAccessoVeicMisure' 435 ]; 436 437 /** Campi 3C â ingresso + posizione (via). */ 438 root.TAB3_MIRROR_3C_KEYS = [ 439 'ingressoPrincVia', 'ingressoPrincTipo', 'ingressoPrincQuota', 'rampDisabili'
440 ]; 441 442 root.TAB3_MIRROR_3ABC_KEYS = (root.TAB3_MIRROR_3A_KEYS || []) 443 .concat(root.TAB3_MIRROR_3B_KEYS || [], root.TAB3_MIRROR_3C_KEYS || []); 444 445 /** P13 â Campi 3A struttura edificio: SSOT Tier L su ogni Luogo (Tab 4). */ 446 root.TAB3_EDIFICIO_SSOT_KEYS = [ 447 'tipoEdificio', 'tipologiaStrutturale', 'annoCostruzione', 'destinazioneUso', 448 'nPianiFT', 'nPianiInterrati', 'pianiFT', 'pianiInterrati', 449 'superficie', 'superficieCoperta', 'superficieEsterna', 'maxPresenze', 'nPostazioniVdt', 450 'caricoMaxSolaiKgMq', 'postiElevatiPresenti', 'postiElevatiAccessoSicuro', 451 'corpoScalaInterno', 'nCorpiScala', 'montascale', 'montascaleTipo', 452 'scalaCorrimano', 'scalaParapetti', 'scalaPedataCm', 'scalaAlzataCm', 'scalaConformita', 453 'impAscensore_presente', 'ascensore', 'nAscensori', 'nAscensors', 454 'scalaEmergenzaEst', 'nScaleEmergenza', 'scalaEmergenzaUbicazione' 455 ]; 456 457 /** Bag annidati sul Luogo Principale â flat d.* per render Tab 3 (solo 3B/3C mirror-safe). */ 458 root.TAB3_BAG_MIRROR_KEYS = root.TAB3_MIRROR_3B_KEYS.concat(root.TAB3_MIRROR_3C_KEYS).filter(function (k) { 459 return k !== 'ingressoPrincVia'; 460 }); 461 462 root._tab3IsMultiLuogo = function (d) { 463 return root._tab3CountLuoghi(d) > 1; 464 }; 465 466 function _tab3RedirectToPrincipale(key, msg) { 467 try { 468 if (typeof toast === 'function') toast(msg || 'Campo SSOT Luogo Principale â modifica in Tab 4 Luoghi.', 'info'); 469 if (typeof root._goToLuogoPrincipale === 'function') { 470 var _sub = (typeof window._dvrLuogoPrincipaleSubTabForField === 'function') 471 ? window._dvrLuogoPrincipaleSubTabForField(key) : 'struttura'; 472 root._goToLuogoPrincipale({ subTab: _sub, fieldKey: key }); 473 } else if (root._tecTriade && root._tecTriade.openTriadeTab) { 474 root._tecTriade.openTriadeTab('amb'); 475 } 476 } catch (_) {} 477 } 478 479 /** Tier P (mirror Principale): vietata scrittura d.* se esiste almeno un Luogo operativo Tab 4. */ 480 root._tab3GuardPrincipaleMirrorSetD = function (key, d) { 481 if (!root._tab3IsPrincipaleMirror(key)) return false; 482 d = d || (typeof D === 'function' ? D() : null); 483 if (root._tab3CountLuoghi(d) < 1) return false; 484 _tab3RedirectToPrincipale(key, 'Campo del Luogo Principale (SSOT) â modifica in Tab 4 Luoghi, non in Tab 3.'); 485 return true; 486 }; 487 488 /** Struttura edificio 3A/3D/3F/3G/3H: SSOT per-Luogo su Tab 4 â mai d.* se c'è un Luogo operativo. */ 489 root._tab3GuardEdificioSetD = function (key, d) { 490 if (root.TAB3_EDIFICIO_SSOT_KEYS.indexOf(key) < 0) return false; 491 d = d || (typeof D === 'function' ? D() : null); 492 // v20.373.102 â QUI SERVONO I LUOGHI CENSITI, NON QUELLI SINTETIZZATI. 493 // _tab3CountLuoghi, quando la lista operativa e' vuota, ricade su _getEntitaForAssessment che 494 // COSTRUISCE un luogo dai dati di progetto: cosi' anche un progetto senza alcun luogo risultava 495 // averne uno, e la scrittura dei dati dell'edificio veniva bloccata «perche' si compila nel 496 // Luogo» â cioe' in un luogo che non esiste. Il tecnico non poteva ne' scrivere qui ne' andare 497 // altrove: bootstrap impossibile. Il gate ssot-audit-v3/P13 lo diceva da tempo, ma esplodeva 498 // prima di stamparlo per una funzione mancante nell'harness dei test. 499 var _cens = (typeof root._tab3OperationalAmbientiList === 'function') 500 ? (root._tab3OperationalAmbientiList(d) || []).length 501 : root._tab3CountLuoghi(d); 502 if (_cens < 1) return false; 503 _tab3RedirectToPrincipale(key, 'Struttura edificio (3A) â SSOT Luogo Principale in Tab 4 Luoghi.'); 504 return true; 505 }; 506 507 /** dvrStruct su Anagrafica sede: solo mono-Luogo (multi = struct per-Luogo). */ 508 root._tab3EdificioPersistToSedeAllowed = function (d) { 509 d = d || (typeof D === 'function' ? D() : null); 510 return !root._tab3IsMultiLuogo(d); 511 }; 512 513 /** Mono-Luogo: Principale â mirror flat d.* (legacy DVR/readiness). Multi: skip. */ 514 root._tab3SanitizeHiddenProfileFlatFromLuogo = function (d, luogo) { 515 if (!d || !luogo) return false; 516 var F = root._tecLuogoTipoForm; 517 if (!F) return false; 518 var tipo = luogo.tipo; 519 var changed = false;
520 if (typeof F.isComfortFieldVisible === 'function' && !F.isComfortFieldVisible(tipo, 'nPostazioniVdt')) { 521 if (d.nPostazioniVdt != null && String(d.nPostazioniVdt).trim() !== '' && String(d.nPostazioniVdt).trim() !== '0') { 522 d.nPostazioniVdt = '0'; 523 changed = true; 524 } 525 } 526 if (typeof F.isStrutturaFieldVisible === 'function') { 527 ['tipologiaStrutturale', 'annoCostruzione', 'nPianiFT', 'nPianiInterrati', 'superficie', 'superficieEsterna', 'destinazioneUso'].forEach(function (key) { 528 if (F.isStrutturaFieldVisible(tipo, key)) return; 529 if (d[key] != null && String(d[key]).trim() !== '') { 530 d[key] = ''; 531 changed = true; 532 } 533 }); 534 } 535 return changed; 536 }; 537 538 root._tab3MirrorEdificioFlatFromLuogo = function (d, luogo, opts) { 539 opts = opts || {}; 540 if (!d || !luogo || root._tab3IsMultiLuogo(d)) return false; 541 var keys = opts.keys || root.TAB3_EDIFICIO_SSOT_KEYS; 542 var changed = false; 543 keys.forEach(function (key) { 544 if (opts.singleKey && key !== opts.singleKey) return; 545 var lv; 546 if (typeof root._tab2LuogoFieldVal === 'function') { 547 lv = root._tab2LuogoFieldVal(luogo, key, d); 548 } 549 if ((lv == null || lv === '') && luogo[key] != null && luogo[key] !== '') { 550 lv = luogo[key]; 551 } 552 if (lv == null || lv === '' || (Array.isArray(lv) && !lv.length)) return; 553 if (opts.singleKey && opts.value !== undefined) lv = opts.value; 554 if (d[key] !== lv) { 555 d[key] = lv; 556 changed = true; 557 } 558 }); 559 if (root._tab3SanitizeHiddenProfileFlatFromLuogo(d, luogo)) changed = true; 560 return changed; 561 }; 562 563 root._tab3SyncEdificioBidirectional = function (d, luogo, opts) { 564 opts = opts || {}; 565 var out = { changed: false, skipped: false, directions: [] }; 566 if (!d) return out; 567 if (root._tab3IsMultiLuogo(d)) { 568 out.skipped = true; 569 out.reason = 'multi_luogo'; 570 return out; 571 } 572 if (luogo && root._tab3MirrorEdificioFlatFromLuogo(d, luogo, opts)) { 573 out.changed = true; 574 out.directions.push('luogoâflat'); 575 } 576 return out; 577 }; 578 579 /** Prima del render Tab 3: allinea d.* (flat legacy) ai valori tier P del Luogo Principale. */ 580 root._tab3SyncPrincipaleMirrorToFlat = function (d, luogo, opts) { 581 opts = opts || {}; 582 var out = { changed: false, keys: [] }; 583 if (!d || !luogo) return out; 584 if (typeof root._tab3CountLuoghi === 'function' && root._tab3CountLuoghi(d) < 1) return out; 585 586 function _apply(key, lv) { 587 if (opts.rewireAll) { 588 var rv = (lv == null || (Array.isArray(lv) && !lv.length)) ? '' : lv; 589 if (typeof rv === 'number') rv = String(rv); 590 if (d[key] !== rv) { 591 d[key] = rv; 592 out.changed = true; 593 out.keys.push(key); 594 } 595 return; 596 } 597 if (lv == null || lv === '' || (Array.isArray(lv) && !lv.length)) return; 598 // v20.190.4 â coerce numeric primitives to string for consistency with HTML input values 599 // (prevents type mismatch: select option '1' vs mirror number 1) 600 if (typeof lv === 'number') lv = String(lv); 601 if (d[key] !== lv) { 602 d[key] = lv; 603 out.changed = true; 604 out.keys.push(key); 605 } 606 } 607 608 (root.TAB3_MIRROR_3A_KEYS || []).forEach(function (key) { 609 if (opts.singleKey && key !== opts.singleKey) return; 610 var lv = typeof root._tab2LuogoFieldVal === 'function' 611 ? root._tab2LuogoFieldVal(luogo, key, d) : luogo[key]; 612 if ((lv == null || lv === '') && luogo[key] != null && luogo[key] !== '') lv = luogo[key]; 613 if (opts.singleKey && opts.value !== undefined) lv = opts.value; 614 _apply(key, lv); 615 }); 616 617 (root.TAB3_EDIFICIO_SSOT_KEYS || []).forEach(function (key) { 618 if (root.TAB3_MIRROR_3A_KEYS && root.TAB3_MIRROR_3A_KEYS.indexOf(key) >= 0) return; 619 if (opts.singleKey && key !== opts.singleKey) return; 620 var lv; 621 if (typeof root._tab2LuogoFieldVal === 'function') lv = root._tab2LuogoFieldVal(luogo, key, d); 622 if ((lv == null || lv === '') && luogo[key] != null && luogo[key] !== '') lv = luogo[key]; 623 if (opts.singleKey && opts.value !== undefined) lv = opts.value; 624 _apply(key, lv); 625 }); 626 627 if (typeof root._tab3MirrorCpiFlatFromLuogo === 'function') { 628 if (root._tab3MirrorCpiFlatFromLuogo(d, luogo, opts)) out.changed = true; 629 } 630 631 Object.keys(root.TAB3_FIELD_SSC || {}
631).forEach(function (key) { 632 var meta = root.TAB3_FIELD_SSC[key]; 633 if (!meta || meta.tier !== P) return; 634 if (root.TAB3_EDIFICIO_SSOT_KEYS && root.TAB3_EDIFICIO_SSOT_KEYS.indexOf(key) >= 0) return; 635 if (root.TAB3_CPI_SSOT_KEYS && root.TAB3_CPI_SSOT_KEYS.indexOf(key) >= 0) return; 636 if (opts.singleKey && key !== opts.singleKey) return; 637 var lv = typeof root._tab2LuogoFieldVal === 'function' 638 ? root._tab2LuogoFieldVal(luogo, key, d) : luogo[key]; 639 if (opts.singleKey && opts.value !== undefined) lv = opts.value; 640 _apply(key, lv); 641 }); 642 643 (root.TAB3_BAG_MIRROR_KEYS || []).forEach(function (key) { 644 if (opts.singleKey && key !== opts.singleKey) return; 645 var lvBag = typeof root._tab2LuogoFieldVal === 'function' 646 ? root._tab2LuogoFieldVal(luogo, key, d) : null; 647 if (opts.singleKey && opts.value !== undefined) lvBag = opts.value; 648 _apply(key, lvBag); 649 }); 650 651 if (!opts.singleKey || opts.singleKey === 'ingressoPrincVia') { 652 var lvVia = typeof root._tab2LuogoFieldVal === 'function' 653 ? root._tab2LuogoFieldVal(luogo, 'ingressoPrincVia', d) : (luogo.posizione || null); 654 if (opts.singleKey && opts.value !== undefined) lvVia = opts.value; 655 _apply('ingressoPrincVia', lvVia); 656 } 657 658 if (typeof root._tab3SanitizeHiddenProfileFlatFromLuogo === 'function') { 659 if (root._tab3SanitizeHiddenProfileFlatFromLuogo(d, luogo)) out.changed = true; 660 } 661 return out; 662 }; 663 664 function _exportHasVal(v) { 665 return v != null && v !== '' && !(Array.isArray(v) && !v.length); 666 } 667 668 function _cloneArr(val) { 669 if (!Array.isArray(val)) return []; 670 try { return JSON.parse(JSON.stringify(val)); } catch (_) { return val.slice(); } 671 } 672 673 /** Anagrafica sede cliente per fallback export (Soluzione D). */ 674 root._tab3ResolveSedeForExport = function (d) { 675 d = d || {}; 676 try { 677 var p = typeof root.CP === 'function' ? root.CP() : null; 678 var cliId = p && (p.clienteMasterId || p.clienteId); 679 var sedeId = p && p.sedeId; 680 if (!cliId || !sedeId || !Array.isArray(root.CLIENTI_LIST)) return null; 681 var cl = root.CLIENTI_LIST.find(function (c) { return c && c.id === cliId; }); 682 if (!cl || !Array.isArray(cl.sedi)) return null; 683 return cl.sedi.find(function (s) { return s && (s.sedeId || s.id || s.nome) === sedeId; }) || null; 684 } catch (_) { 685 return null; 686 } 687 }; 688 689 /** 690 * Soluzione D â export DVR: Principale grafo â d.* â sede anagrafica. 691 * Tier S (es. accessiCarrabili[]) resta solo su d.* Tab 3. 692 */ 693 root._tab3ResolveExportField = function (key, d, opts) { 694 opts = opts || {}; 695 d = d || {}; 696 if (!key) return null; 697 var meta = (root.TAB3_FIELD_SSC || {})[key]; 698 699 if (typeof root._tab3ComputeField === 'function' && meta && meta.compute) { 700 try { 701 var c = root._tab3ComputeField(key, d); 702 if (c && _exportHasVal(c.value)) return c.value; 703 } catch (_) {} 704 } 705 706 if (meta && meta.tier === S) { 707 return _exportHasVal(d[key]) ? d[key] : null; 708 } 709 710 if (!opts.skipPrincipale && typeof root._tab3CountLuoghi === 'function' && root._tab3CountLuoghi(d) >= 1) { 711 var lp = typeof root._tab3ResolvePrincipaleAmb === 'function' ? root._tab3ResolvePrincipaleAmb(d) : null; 712 if (lp && typeof root._tab2LuogoFieldVal === 'function') { 713 try { 714 var lv = root._tab2LuogoFieldVal(lp, key, d); 715 if (!_exportHasVal(lv) && opts.altKeys) { 716 for (var ai = 0; ai < opts.altKeys.length; ai++) { 717 lv = root._tab2LuogoFieldVal(lp, opts.altKeys[ai], d); 718 if (_exportHasVal(lv)) break; 719 } 720 } 721 if (_exportHasVal(lv)) return lv; 722 } catch (_) {} 723 } 724 } 725 726 if (key === 'superficie') { 727 if (_exportHasVal(d.superficie)) return d.superficie; 728 if (_exportHasVal(d.superficieCoperta)) return d.superficieCoperta; 729 } else if (_exportHasVal(d[key])) { 730 return d[key]; 731 } 732 if (opts.altKeys) { 733 for (var bi = 0; bi < opts.altKeys.length; bi++) { 734 var ak = opts.altKeys[bi];
735 if (_exportHasVal(d[ak])) return d[ak]; 736 } 737 } 738 739 if (!opts.skipSede) { 740 var sede = opts.sede || root._tab3ResolveSedeForExport(d); 741 if (sede) { 742 var sk = opts.sedeKey || key; 743 if (_exportHasVal(sede[sk])) return sede[sk]; 744 if (sk !== key && _exportHasVal(sede[key])) return sede[key]; 745 var ds = sede.dvrStruct; 746 if (ds && _exportHasVal(ds[sk])) return ds[sk]; 747 if (ds && sk !== key && _exportHasVal(ds[key])) return ds[key]; 748 } 749 } 750 return null; 751 }; 752 753 /** Array tier P su grafo Luogo Principale (3D piani, 3G blocchiWC). */ 754 root.TAB3_GRAFO_ARRAY_KEYS = ['piani', 'blocchiWC']; 755 756 /** Tab 3 setD â patch array su Luogo Principale in RAM (+ grafo se disponibile). */ 757 root._tab3SyncGrafoArrayToPrincipale = function (d, key, val) { 758 if (!d || !key || root.TAB3_GRAFO_ARRAY_KEYS.indexOf(key) < 0) { 759 return { changed: false }; 760 } 761 if (typeof root._tab3CountLuoghi === 'function' && root._tab3CountLuoghi(d) !== 1) { 762 return { changed: false, reason: 'multi_luogo' }; 763 } 764 var lp = typeof root._tab3ResolvePrincipaleAmb === 'function' ? root._tab3ResolvePrincipaleAmb(d) : null; 765 if (!lp || !lp.id) return { changed: false, reason: 'no_principale' }; 766 767 var patch = { id: lp.id }; 768 if (key === 'piani') { 769 patch.piani = _cloneArr(val); 770 } else if (key === 'blocchiWC') { 771 patch.serviziIgienici = Object.assign({}, lp.serviziIgienici || {}, { blocchiWC: _cloneArr(val) }); 772 } 773 774 var list = d.ambientiSede; 775 if (Array.isArray(list)) { 776 for (var i = 0; i < list.length; i++) { 777 if (list[i] && list[i].id === lp.id) { 778 if (key === 'piani') list[i].piani = patch.piani; 779 else if (key === 'blocchiWC') { 780 list[i].serviziIgienici = Object.assign({}, list[i].serviziIgienici || {}, patch.serviziIgienici); 781 } 782 lp = list[i]; 783 break; 784 } 785 } 786 } 787 if (root._tab2LuogoHomeCache && root._tab2LuogoHomeCache.id === lp.id) { 788 if (key === 'piani') root._tab2LuogoHomeCache.piani = patch.piani; 789 else if (key === 'blocchiWC') { 790 root._tab2LuogoHomeCache.serviziIgienici = Object.assign( 791 {}, root._tab2LuogoHomeCache.serviziIgienici || {}, patch.serviziIgienici 792 ); 793 } 794 } 795 796 var sedeId = _sedeIdFromProject(); 797 if (sedeId && root._tecGrafo && typeof root._tecGrafo.saveAmbiente === 'function') { 798 try { root._tecGrafo.saveAmbiente(sedeId, patch); } catch (_) {} 799 } 800 return { changed: true, key: key }; 801 }; 802 803 /** Risolve Luogo Principale operativo (Tab 4) per mirror Tab 3. */ 804 root._tab3ResolvePrincipaleAmb = function (d) { 805 d = d || (typeof D === 'function' ? D() : null); 806 if (!d) return null; 807 if (typeof root._tab2ResolvePrincipaleAmb === 'function') { 808 try { 809 var hit = root._tab2ResolvePrincipaleAmb(d); 810 if (hit) return hit; 811 } catch (_) {} 812 } 813 if (typeof root._tab2LuogoHome === 'function') { 814 try { 815 var h = root._tab2LuogoHome(); 816 if (h) return h; 817 } catch (_) {} 818 } 819 var list = root._tab3OperationalAmbientiList ? root._tab3OperationalAmbientiList(d) : (d.ambientiSede || []); 820 if (root._tecGrafo && typeof root._tecGrafo.resolveCanonicalPrincipaleAmb === 'function') { 821 var canon = root._tecGrafo.resolveCanonicalPrincipaleAmb(list, d); 822 if (canon) return canon; 823 } 824 return list.filter(function (a) { return a && a.principale === true; })[0] || null; 825 }; 826 827 /** Prima dell'export DVR: allinea d.* al Luogo Principale (3A/3B/3C + CPI). */ 828 root._tab3EnsureMirrorBeforeExport = function (d) { 829 d = d || (typeof D === 'function' ? D() : null); 830 if (!d || typeof root._tab3CountLuoghi !== 'function' || root._tab3CountLuoghi(d) < 1) { 831 return { changed: false }; 832 } 833 var lp = root._tab3ResolvePrincipaleAmb(d); 834 if (!lp) return { changed: false }; 835 return root._tab3SyncPrincipaleMirrorToFlat(d, lp, {}) || { changed: false }; 836 }; 837 838 /** Risolve currentTab (let in index.html â non sempre su window). */ 839 function _resolveCurrentTabId() { 840 try { 841 var viaFn = (new Function('return (typeof currentTab !== "undefined" ? currentTab : null)'))(); 842 if (viaFn != null) return viaFn; 843 } catch (_) {} 844 return typeof root.currentTab !== 'undefined' ? root.currentTab : null; 845 } 846 847 /** Cambio Luogo Principale / patch struttura â invalida cache e refresh Tab 3 se aperta. */ 848 root._tab3RefreshAfterPrincipaleChange = function (opts) { 849 opts = opts || {}; 850 try { root._tab2LuogoHomeCache = null; } catch (_) {} 851 var d = typeof D === 'function' ? D() : null; 852 if (!d) return; 853 var lp = null; 854 if (opts.ambId && Array.isArray(d.ambientiSede)) { 855 lp = d.ambientiSede.find(function (a) { return a && a.id === opts.ambId; }) || null; 856 } 857 if (!lp && opts.ambId && typeof root._tab2MergedAmbientiList === 'function') { 858 var merged = root._tab2MergedAmbientiList(d) || []; 859 lp = merged.find(function (a) { return a && a.id === opts.ambId; }) || null; 860 } 861 if (!lp) lp = root._tab3ResolvePrincipaleAmb(d); 862 if (lp && typeof root._tab3PushPrincipaleMirrorToFlat === 'function') { 863 root._tab3PushPrincipaleMirrorToFlat(lp, opts); 864 } 865 var ct = _resolveCurrentTabId(); 866 if (opts.renderTab !== false && ct === 2) {
867 try { 868 var mainEl = typeof document !== 'undefined' ? document.getElementById('main') : null; 869 if (mainEl && typeof root.renderRaccolta === 'function') { 870 root.renderRaccolta(mainEl); 871 } else if (typeof root.renderTab === 'function') { 872 root.renderTab(); 873 } 874 } catch (_) {} 875 } 876 }; 877 878 /** Live push Luogo Principale â d.* (Tab 3 mirror) + impianti 3I flat. */ 879 root._tab3PushPrincipaleMirrorToFlat = function (amb, opts) { 880 opts = opts || {}; 881 if (!amb) return { changed: false }; 882 var isPrinc = amb.principale === true; 883 if (!isPrinc && typeof root._tab3ResolvePrincipaleAmb === 'function') { 884 var dChk = typeof root.D === 'function' ? root.D() : null; 885 var hit = root._tab3ResolvePrincipaleAmb(dChk); 886 isPrinc = !!(hit && hit.id === amb.id); 887 } 888 if (!isPrinc) return { changed: false }; 889 var d = typeof root.D === 'function' ? root.D() : null; 890 if (!d) return { changed: false }; 891 var out = root._tab3SyncPrincipaleMirrorToFlat(d, amb, opts) || { changed: false }; 892 if (root._tecImpiantiSync && typeof root._tecImpiantiSync.syncImpiantiGrafoToSede === 'function') { 893 root._tecImpiantiSync.syncImpiantiGrafoToSede(d, [amb]); 894 out.impianti = true; 895 out.changed = true; 896 } 897 return out; 898 }; 899 900 var _CPI_ENUM_OPTS = { 901 rischioIncendioNuovo: [ 902 ['1', 'Livello 1 â Basso'], 903 ['2', 'Livello 2 â Medio'], 904 ['3', 'Livello 3 â Alto'] 905 ], 906 rischioIncendioVecchio: [ 907 ['basso', 'Basso (ex D.M. 10/03/98 â abrogato)'], 908 ['medio', 'Medio (ex D.M. 10/03/98 â abrogato)'], 909 ['alto', 'Alto (ex D.M. 10/03/98 â abrogato)'] 910 ], 911 gruppoPS: [ 912 ['A', 'Gruppo A â rischio basso'], 913 ['B', 'Gruppo B â rischio medio'], 914 ['C', 'Gruppo C â rischio elevato'] 915 ] 916 }; 917 918 function _cpiNormSelectVal(key, raw) { 919 if (raw == null || raw === '') return ''; 920 if (key === 'rischioIncendioNuovo') { 921 var s = String(raw).trim().toLowerCase(); 922 var m = { basso: '1', medio: '2', alto: '3', elevato: '3', a: '3', b: '2', c: '1' }; 923 if (m[s]) return m[s]; 924 var dig = s.match(/^(\d)/); 925 return dig ? dig[1] : s; 926 } 927 if (key === 'rischioIncendioVecchio') return String(raw).trim().toLowerCase(); 928 if (key === 'gruppoPS') return String(raw).trim().charAt(0).toUpperCase(); 929 return String(raw); 930 } 931 932 /** Suggerimenti CPI: _proponiClasseIncendio (ATECO/edificio/sport) + _derivaGruppoPrimoSoccorso. */ 933 root._tab3CpiSuggestFor = function (d) { 934 d = d || {}; 935 var inc = typeof root._proponiClasseIncendio === 'function' ? root._proponiClasseIncendio(d) : {}; 936 var ps = typeof root._derivaGruppoPrimoSoccorso === 'function' ? root._derivaGruppoPrimoSoccorso(d) : {}; 937 return { 938 rischioIncendioNuovo: _cpiNormSelectVal('rischioIncendioNuovo', inc.propostaNuovo), 939 rischioIncendioVecchio: _cpiNormSelectVal('rischioIncendioVecchio', inc.propostaVecchio), 940 gruppoPS: _cpiNormSelectVal('gruppoPS', ps.gruppo), 941 incendio: inc, 942 ps: ps 943 }; 944 }; 945 946 /** Patch ottimistico SSOT impianti.cpi su tutte le cache Luogo Principale (evita revert al renderTab). */ 947 function _patchCpiLuogoCaches(lh, key, value) { 948 if (!lh || !key) return; 949 if (!lh.impianti) lh.impianti = {}; 950 if (!lh.impianti.cpi) lh.impianti.cpi = {}; 951 lh.impianti.cpi[key] = value; 952 var lid = lh.id; 953 if (root._tab2LuogoHomeCache && (!lid || root._tab2LuogoHomeCache.id === lid)) { 954 if (!root._tab2LuogoHomeCache.impianti) root._tab2LuogoHomeCache.impianti = {}; 955 if (!root._tab2LuogoHomeCache.impianti.cpi) root._tab2LuogoHomeCache.impianti.cpi = {}; 956 root._tab2LuogoHomeCache.impianti.cpi[key] = value; 957 } 958 var eng = root._tecEngine; 959 if (eng && eng._luogoListCache && lid) { 960 for (var i = 0; i < eng._luogoListCache.length; i++) { 961 var x = eng._luogoListCache[i]; 962 if (x && x.id === lid) { 963 if (!x.impianti) x.impianti = {}; 964 if (!x.impianti.cpi) x.impianti.cpi = {}; 965 x.impianti.cpi[key] = value; 966 break; 967 } 968 } 969 } 970 } 971 972 function _cpiWriteFlat(key, value, d) { 973 var run = function () { 974 if (typeof setD === 'function') setD(key, value); 975 else if (d) d[key] = value; 976 }; 977 if (key === 'rischioIncendioVecchio') { 978 root._allowIncendioVecchioOverride = true;
979 try { 980 if (typeof root._withSsotBypass === 'function') root._withSsotBypass(run); 981 else run(); 982 } finally { 983 root._allowIncendioVecchioOverride = false; 984 } 985 } else { 986 run(); 987 } 988 } 989 990 function _cpiPersistOne(key, value, d, lh) { 991 _patchCpiLuogoCaches(lh, key, value); 992 _cpiWriteFlat(key, value, d); 993 var sedeId = _sedeIdFromProject(); 994 if (lh && lh.id && sedeId && root._tecEngine && root._tecEngine._saveAmbImpiantoField) { 995 root._tecEngine._saveAmbImpiantoField(sedeId, lh.id, 'cpi', key, value, 0); 996 } 997 } 998 999 root._setCpiSsotField = function (key, value) { 1000 if (root.TAB3_CPI_SSOT_KEYS.indexOf(key) < 0) return; 1001 var d = typeof D === 'function' ? D() : null; 1002 if (!d) return; 1003 var pairs = [[key, value]]; 1004 if (key === 'rischioIncendioNuovo' && typeof root._incendioNuovoToVecchio === 'function') { 1005 var dv = root._incendioNuovoToVecchio(value); 1006 if (dv) pairs.push(['rischioIncendioVecchio', dv]); 1007 } else if (key === 'rischioIncendioVecchio' && typeof root._incendioVecchioToNuovo === 'function') { 1008 var nv = root._incendioVecchioToNuovo(value); 1009 if (nv) pairs.push(['rischioIncendioNuovo', nv]); 1010 } 1011 var lh = typeof root._tab2LuogoHome === 'function' ? root._tab2LuogoHome() : null; 1012 pairs.forEach(function (pair) { _cpiPersistOne(pair[0], pair[1], d, lh); }); 1013 if (root._tecTriParere && typeof root._tecTriParere.recordDecision === 'function') { 1014 root._tecTriParere.recordDecision(key, value, d); 1015 } 1016 if (pairs.length > 1 && typeof renderTab === 'function') renderTab(); 1017 }; 1018 1019 function _esc(s) { 1020 return String(s == null ? '' : s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); 1021 } 1022 1023 function _fmtCpiDisp(raw) { 1024 if (raw == null || raw === '') return 'â'; 1025 if (raw === 'si') return 'Sì'; 1026 if (raw === 'no') return 'No'; 1027 var incLbl = { 1028 '1': 'Livello 1 â Basso', '2': 'Livello 2 â Medio', '3': 'Livello 3 â Alto', 1029 basso: 'Basso', medio: 'Medio', alto: 'Alto', 1030 A: 'Gruppo A', B: 'Gruppo B', C: 'Gruppo C' 1031 }; 1032 if (incLbl[raw]) return incLbl[raw]; 1033 return String(raw).replace(/_/g, ' '); 1034 } 1035 1036 function _tab3CpiSuggestBadge(key, suggestVal, currentVal, meta) { 1037 if (!suggestVal) return ''; 1038 var cur = _cpiNormSelectVal(key, currentVal); 1039 var match = cur === String(suggestVal); 1040 var tip = (meta && meta.perche) ? String(meta.perche).replace(/"/g, "'") : ''; 1041 var bg = match ? '#dcfce7' : '#eff6ff'; 1042 var col = match ? '#166534' : '#1d4ed8'; 1043 var border = match ? '#86efac' : '#93c5fd'; 1044 var lbl = 'Suggerito: ' + _fmtCpiDisp(suggestVal) + (match ? ' â' : ''); 1045 return '<span title="' + tip + '" style="font-size:8px;font-weight:700;color:' + col + ';background:' + bg + ';padding:1px 8px;border-radius:999px;margin-left:5px;border:1px solid ' + border + '">' + lbl + '</span>'; 1046 } 1047 1048 /** Badge «Validato dal Legale» â stesso contratto di index.html `_legalValidatedBadge`. */ 1049 function _tab3LegalValidatedBadge(key, val) { 1050 try { 1051 if (typeof root._legalFieldValidation !== 'function') return ''; 1052 var lv = root._legalFieldValidation(key); 1053 if (!lv || lv.stato !== 'validato') return ''; 1054 var norma = lv.norma ? (' · ' + String(lv.norma)) : ''; 1055 var empty = val == null || (function () { 1056 var s = String(val).trim(); 1057 return s === '' || s === '?' || s === 'â' || s === '-'; 1058 })(); 1059 if (empty) { 1060 var tipE = ('Regola validata dal Legale, ma il campo è ancora da compilare' + (lv.validatoDa ? (' · ' + lv.validatoDa) : '')).replace(/"/g, "'"); 1061 return '<span title="' + tipE + '" style="cursor:help;font-size:8px;padding:1px 6px;border-radius:4px;background:#fef3c7;color:#92400e;font-weight:700;margin-left:5px;border:1px solid #fcd34d">✓ Validato â campo da compilare</span>'; 1062 } 1063 var tip = ('Validato dal Legale' + (lv.validatoDa ? (' · ' + lv.validatoDa) : '') + (lv.data ? (' · ' + String(lv.data).slice(0, 10)) : '') + (lv.nota ? ('\n' + lv.nota) : '')).replace(/"/g, "'"); 1064 return '<span title="' + tip + '" style="cursor:help;font-size:8px;padding:1px 6px;border-radius:4px;background:#dcfce7;color:#166534;font-weight:700;margin-left:5px;border:1px solid #86efac">✓ Validato dal Legale' + norma.replace(/</g, '<') + '</span>'; 1065 } catch (_) { return ''; } 1066 } 1067 1068 var _CPI_CHIP_KEY = { 1069 rischioIncendioVecchio: 'rischioIncendio', 1070 rischioIncendioNuovo: 'rischioIncendio', 1071 cpiNumero: 'statoCPI', 1072 cpiScadenza: 'statoCPI' 1073 }; 1074
1075 function _tab3CpiLabelTitle(key) { 1076 try { 1077 if (typeof root._fieldMeta !== 'function') return ''; 1078 var m = root._fieldMeta(key); 1079 if (!m || !m.locator) return ''; 1080 return ' title="' + String((m.categoria || '') + ' · ' + (m.norma || 'â') + ' · ' + m.locator).replace(/"/g, "'") + '"'; 1081 } catch (_) { return ''; } 1082 } 1083 1084 function _tab3CpiFieldBadges(key, val, d) { 1085 var html = ''; 1086 try { if (typeof root._fieldMetaBadge === 'function') html += root._fieldMetaBadge(key); } catch (_) {} 1087 html += _tab3LegalValidatedBadge(key, val); 1088 try { 1089 var chipKey = _CPI_CHIP_KEY[key] || key; 1090 if (typeof root._renderLuoghiImpiantiChip === 'function') { 1091 var chip = root._renderLuoghiImpiantiChip(d, chipKey); 1092 if (chip) html += chip; 1093 } 1094 } catch (_) {} 1095 return html; 1096 } 1097 1098 /** Pannello 3Jâ3L CPI in Tab 2 Sede Generale: RO mono-Luogo · edit multi-sede. */ 1099 root._tab3RenderCpiTab2Panel = function (d, ctx) { 1100 d = d || {}; 1101 ctx = ctx || {}; 1102 var SEC = ctx.SEC; 1103 if (!SEC) return ''; 1104 var lh = typeof root._tab2LuogoHome === 'function' ? root._tab2LuogoHome() : null; 1105 root._tab3SyncCpiBidirectional(d, lh, { persistBackfill: true }); 1106 var editable = root._tab3CpiTab2Editable(d); 1107 var lv = function (k) { return _cpiVal(lh, d, k); }; 1108 var nLu = root._tab3CountLuoghi(d); 1109 var intro = '<div style="font-size:10.5px;color:#92400e;margin-bottom:10px;padding:8px 12px;background:#fff7ed;border-radius:8px;border:1px solid #fdba74">' 1110 + '<strong>' + (nLu > 1 ? 'Multi-sede (' + nLu + ' Luoghi)' : 'Mono-Luogo') + '</strong> â CPI del <em>Luogo Principale</em> editabile qui; SSOT su <code>' 1111 + root.TAB3_CPI_SSOT_PATH + '</code> + mirror <code>d.*</code>. ' 1112 + 'Classe derivata per fattori luogo â ' 1113 + '<button type="button" onclick="window._goToLuogoPrincipale({subTab:\'antincendio\',fieldKey:\'rischioIncendioNuovo\'})" style="margin-left:4px;padding:4px 10px;border-radius:6px;border:1px solid #2563eb;background:#fff;color:#1d4ed8;font-size:10px;font-weight:700;cursor:pointer">Vai â Tab 4 Antincendio</button></div>'; 1114 1115 function fieldWrap(key, tier, inner, extraAttrs) { 1116 extraAttrs = extraAttrs || ''; 1117 return '<div data-field-key="' + key + '" data-tab3-tier="' + (tier || 'P') + '"' + extraAttrs + '>' + inner + '</div>'; 1118 } 1119 1120 function roField(label, key) { 1121 var raw = lv(key); 1122 return fieldWrap(key, 'P', 1123 '<label class="fl"' + _tab3CpiLabelTitle(key) + '><span class="dot dot-r"></span>' + label + _tab3CpiFieldBadges(key, raw, d) + '</label>' 1124 + '<div style="border:1.5px solid #e2e8f0;border-radius:10px;padding:9px 13px;font-size:13px;background:#f8fafc;font-weight:600">' + _esc(_fmtCpiDisp(raw)) + '</div>', 1125 ' data-ro-luogo="1"'); 1126 } 1127 1128 function ynSelect(label, key) { 1129 var v = lv(key) || ''; 1130 return fieldWrap(key, 'P', 1131 '<label class="fl"' + _tab3CpiLabelTitle(key) + '><span class="dot dot-r"></span>' + label + _tab3CpiFieldBadges(key, v, d) + '</label>' 1132 + '<select onchange="window._setCpiSsotField(\'' + key + '\',this.value)" style="width:100%;padding:9px 13px;border:1.5px solid #cbd5e1;border-radius:10px;font-size:13px">' 1133 + '<option value="">â</option><option value="si"' + (v === 'si' ? ' selected' : '') + '>Sì</option><option value="no"' + (v === 'no' ? ' selected' : '') + '>No</option></select>'); 1134 } 1135 1136 function textInput(label, key, type) { 1137 type = type || 'text'; 1138 var v = lv(key) || ''; 1139 return fieldWrap(key, 'P', 1140 '<label class="fl"' + _tab3CpiLabelTitle(key) + '><span class="dot dot-r"></span>' + label + _tab3CpiFieldBadges(key, v, d) + '</label>' 1141 + '<input type="' + type + '" value="' + _esc(v) + '" onchange="window._setCpiSsotField(\'' + key + '\',this.value)" style="width:100%;padding:9px 13px;border:1.5px solid #cbd5e1;border-radius:10px;font-size:13px">'); 1142 } 1143 1144 function statoCpiSelect(label, key) { 1145 var v = lv(key) || ''; 1146 return fieldWrap(key, 'P',
1147 '<label class="fl"' + _tab3CpiLabelTitle(key) + '><span class="dot dot-r"></span>' + label + _tab3CpiFieldBadges(key, v, d) + '</label>' 1148 + '<select onchange="window._setCpiSsotField(\'' + key + '\',this.value)" style="width:100%;padding:9px 13px;border:1.5px solid #cbd5e1;border-radius:10px;font-size:13px">' 1149 + ['non_richiesto:Non richiesto', 'presente:CPI presente', 'scaduto:Scaduto', 'scia_completa:SCIA completa', 'scia_parziale:SCIA parziale', 'assente:Assente', 'in_iter:In iter', 'in_corso:In corso'].map(function (o) { 1150 var p = o.split(':'); 1151 return '<option value="' + p[0] + '"' + (v === p[0] ? ' selected' : '') + '>' + p[1] + '</option>'; 1152 }).join('') 1153 + '</select>'); 1154 } 1155 1156 function enumSelect(label, key, suggestVal, suggestMeta) { 1157 var opts = _CPI_ENUM_OPTS[key] || []; 1158 var v = _cpiNormSelectVal(key, lv(key)); 1159 var suggestBadge = _tab3CpiSuggestBadge(key, suggestVal, v, suggestMeta); 1160 var optHtml = opts.map(function (pair) { 1161 var val = pair[0]; 1162 var lbl = pair[1]; 1163 var isSugg = suggestVal && String(suggestVal) === String(val); 1164 return '<option value="' + val + '"' + (v === val ? ' selected' : '') + (isSugg ? ' data-suggested="1"' : '') + '>' 1165 + lbl + (isSugg ? ' â ' : '') + '</option>'; 1166 }).join(''); 1167 var hintStyle = !v && suggestVal ? 'border-color:#93c5fd;background:#f8fafc' : ''; 1168 var tier = key === 'rischioIncendioVecchio' ? 'C' : 'P'; 1169 return fieldWrap(key, tier, 1170 '<label class="fl"' + _tab3CpiLabelTitle(key) + '><span class="dot dot-r"></span>' + label + _tab3CpiFieldBadges(key, v, d) + suggestBadge + '</label>' 1171 + '<select onchange="window._setCpiSsotField(\'' + key + '\',this.value)" style="width:100%;padding:9px 13px;border:1.5px solid #cbd5e1;border-radius:10px;font-size:13px;' + hintStyle + '">' 1172 + '<option value=""' + (!v ? ' selected' : '') + '>â seleziona â</option>' + optHtml 1173 + '</select>' 1174 + ((root._tecTriParere && typeof root._tecTriParere.renderStrip === 'function') 1175 ? root._tecTriParere.renderStrip(key, d, { currentVal: v }) : '')); 1176 } 1177 1178 var suggests = root._tab3CpiSuggestFor(d); 1179 1180 var body = intro + '<div class="grid grid-cols-2 gap-4 mb-4">'; 1181 if (editable) { 1182 body += ynSelect('2L.1 Soggetto a controllo VVF?', 'soggettoVVF'); 1183 body += statoCpiSelect('Stato CPI', 'statoCPI'); 1184 } else { 1185 body += roField('2L.1 Soggetto a controllo VVF?', 'soggettoVVF'); 1186 body += roField('Stato CPI', 'statoCPI'); 1187 } 1188 body += '</div>'; 1189 1190 if (lv('soggettoVVF') === 'si' && (lv('statoCPI') === 'presente' || lv('statoCPI') === 'scaduto')) { 1191 body += '<div class="grid grid-cols-2 gap-4 mb-4">'; 1192 if (editable) { 1193 body += textInput('Numero CPI', 'cpiNumero'); 1194 body += textInput('Data scadenza CPI', 'cpiScadenza', 'date'); 1195 } else { 1196 body += roField('Numero CPI', 'cpiNumero'); 1197 body += roField('Data scadenza CPI', 'cpiScadenza'); 1198 } 1199 body += '</div>'; 1200 } 1201 1202 body += '<div class="grid grid-cols-2 gap-4 mt-2">'; 1203 if (editable) { 1204 body += ynSelect('2J.1 Attività DPR 151/2011?', 'attivitaDPR151'); 1205 body += enumSelect('2K.2 Livello rischio (D.M. 03/09/2021)', 'rischioIncendioNuovo', suggests.rischioIncendioNuovo, suggests.incendio); 1206 body += enumSelect((root._tecNormativa && root._tecNormativa.label('rischioIncendioVecchioField')) || '2K.1 Classificazione storica (ex D.M. 10/03/98 â abrogato)', 'rischioIncendioVecchio', suggests.rischioIncendioVecchio, suggests.incendio); 1207 body += enumSelect('2K.3 Gruppo Primo Soccorso', 'gruppoPS', suggests.gruppoPS, suggests.ps); 1208 } else { 1209 body += roField('2J.1 Attività DPR 151/2011?', 'attivitaDPR151'); 1210 body += roField('2K.2 Livello rischio (D.M. 03/09/2021)', 'rischioIncendioNuovo'); 1211 body += roField((root._tecNormativa && root._tecNormativa.label('rischioIncendioVecchioField')) || '2K.1 Classificazione storica (ex D.M. 10/03/98 â abrogato)', 'rischioIncendioVecchio'); 1212 body += roField('2K.3 Gruppo Primo Soccorso', 'gruppoPS'); 1213 } 1214 body += '</div>'; 1215 1216 return SEC('cpi_ssot', 'ð¥', '3L â CPI / Antincendio (Luogo Principale)', body); 1217 }; 1218 1219 function _luoghiList(sedeId) { 1220 var list = []; 1221 var eng = root._tecEngine; 1222 if (eng && eng._luogoListCache && (!sedeId || eng._luogoSedeId === sedeId)) { 1223 list = eng._luogoListCache.slice(); 1224 } 1225 if (!list.length && root._tecGrafo && root._tecGrafo.getGrafoCache) {
1226 try { 1227 var g = root._tecGrafo.getGrafoCache(); 1228 if (g && Array.isArray(g.luoghi)) list = g.luoghi.slice(); 1229 if (!list.length && g && Array.isArray(g.ambientiSede)) list = g.ambientiSede.slice(); 1230 } catch (_) {} 1231 } 1232 // v20.372.3 â fallback progetto: cache luoghi stale non deve far Σ=0 dopo save bag 1233 if (!list.length && typeof D === 'function') { 1234 try { 1235 var dL = D(); 1236 if (dL && Array.isArray(dL.ambientiSede) && dL.ambientiSede.length) list = dL.ambientiSede.slice(); 1237 } catch (_) {} 1238 } 1239 return list; 1240 } 1241 1242 root._tab3SumServiziIgieniciLuoghi = function (sedeId) { 1243 var sum = 0; 1244 var list = _luoghiList(sedeId); 1245 // v20.373.367 â ROLL-UP SOLO FOGLIE: non sommare i nodi CONTENITORE (con figli), altrimenti 1246 // Master + piani = doppio conteggio dei blocchi WC. Modello piatto: nessun figlio -> invariato. 1247 var _hasChildWc = function (id) { return !!id && list.some(function (x) { return x && (x.parentEdificioId === id || x.parentLuogoId === id); }); }; 1248 list.forEach(function (l) { 1249 if (!l) return; 1250 if (_hasChildWc(l.id)) return; 1251 var si = l.serviziIgienici || {}; 1252 var n = parseInt(si.nBlocchiWCTotale || si.nBlocchiWC || 0, 10); 1253 if (!n && Array.isArray(si.blocchiWC)) { 1254 n = si.blocchiWC.reduce(function (s, b) { 1255 return s + (parseInt(b && b.nBlocchi, 10) || 0); 1256 }, 0); 1257 } 1258 sum += n || 0; 1259 }); 1260 if (sum === 0 && typeof root._tab2LuogoHome === 'function') { 1261 try { 1262 var h = root._tab2LuogoHome(); 1263 if (h && h.serviziIgienici) { 1264 sum = parseInt(h.serviziIgienici.nBlocchiWCTotale || h.serviziIgienici.nBlocchiWC || 0, 10) || 0; 1265 } 1266 } catch (_) {} 1267 } 1268 if (sum === 0 && typeof D === 'function') { 1269 try { 1270 var d = D(); 1271 sum = parseInt(d.nBlocchiWCTotale || d.nBlocchiWC || 0, 10) || 0; 1272 } catch (_) {} 1273 } 1274 return sum; 1275 }; 1276 1277 root._tab3ComputeField = function (key, d) { 1278 d = d || (typeof D === 'function' ? D() : {}); 1279 var meta = root.TAB3_FIELD_SSC[key] || {}; 1280 if (key === 'nDipendenti' || meta.compute === 'organico') { 1281 var n = typeof root._countDipendentiOrganico === 'function' 1282 ? root._countDipendentiOrganico(d) 1283 : (parseInt(d.nDipendenti || 0, 10) || 0); 1284 return { 1285 value: n, 1286 provenance: 'Organico nominativo â Tab 3.3 Mansioni (Σ righe dipendenti)', 1287 navAction: 'triade_mansioni' 1288 }; 1289 } 1290 if (key === 'nBlocchiWCTotale' || key === 'nServiziIgienici' || key === 'nBlocchiWC' || meta.compute === 'sum_wc_luoghi') { 1291 var sedeId = null; 1292 try { 1293 var p = typeof CP === 'function' ? CP() : null; 1294 sedeId = p && (p.sedeId || (p.data && p.data.sedeId)); 1295 } catch (_) {} 1296 var tot = root._tab3SumServiziIgieniciLuoghi(sedeId); 1297 var nLu = _luoghiList(sedeId).length; 1298 return { 1299 value: tot, 1300 provenance: nLu > 1 1301 ? ('Σ servizi igienici su ' + nLu + ' Luoghi censiti') 1302 : 'Servizi igienici dai Luoghi (Tab 4) â totale blocchi WC', 1303 navAction: 'tab3_wc' 1304 }; 1305 } 1306 if (key === 'rischioIncendioVecchio' || meta.compute === 'incendio_vecchio') { 1307 var v = d.rischioIncendioVecchio; 1308 if (!v && d.rischioIncendioNuovo && typeof root._incendioNuovoToVecchio === 'function') { 1309 v = root._incendioNuovoToVecchio(d.rischioIncendioNuovo); 1310 } 1311 return { 1312 value: v || '', 1313 provenance: 'Derivato da 2K.2 rischioIncendioNuovo (DM 03/09/2021)', 1314 navAction: 'luogo_principale' 1315 }; 1316 } 1317 return { value: d[key], provenance: '', navAction: meta.nav || 'tab3' }; 1318 }; 1319 1320 /** 1321 * v20.372.6 â emptyData() storico seminava wcPavPiastrellati:'si' + wcAltPiastrellatura:'2'. 1322 * Su progetti già creati quei flat restano e hydrate/merge li rimettono nel bag al F5 1323 * (UI: WC vuoto, pavimenti «â», altezza «2»). Strip se nBlocchi assente/0 (pattern seed). 1324 */ 1325 root._tab3StripWcEmptyDataSeeds = function (d) { 1326 d = d || (typeof D === 'function' ? D() : null); 1327 if (!d) return false;
1328 var n = String(d.nBlocchiWCTotale == null ? '' : d.nBlocchiWCTotale).trim(); 1329 if (n === '' && d.nBlocchiWC != null) n = String(d.nBlocchiWC).trim(); 1330 var nEmpty = !n || n === '0'; 1331 if (!nEmpty) return false; 1332 var pav = String(d.wcPavPiastrellati == null ? '' : d.wcPavPiastrellati).trim().toLowerCase(); 1333 var alt = String(d.wcAltPiastrellatura == null ? '' : d.wcAltPiastrellatura).trim(); 1334 var stripPav = (pav === 'si'); 1335 var stripAlt = (alt === '2'); 1336 if (!stripPav && !stripAlt) { 1337 // bag-only poison (flat già vuoto, bag ha ancora seed) 1338 } else { 1339 /* flat poison */ 1340 } 1341 var changed = false; 1342 function _clearFlat(key) { 1343 if (typeof setD === 'function') { 1344 var _prev = (typeof window !== 'undefined') ? window._tecSsotBypass : false; 1345 if (typeof window !== 'undefined') window._tecSsotBypass = true; 1346 try { setD(key, ''); } finally { if (typeof window !== 'undefined') window._tecSsotBypass = _prev; } 1347 } else { 1348 d[key] = ''; 1349 } 1350 changed = true; 1351 } 1352 if (stripPav) _clearFlat('wcPavPiastrellati'); 1353 if (stripAlt) _clearFlat('wcAltPiastrellatura'); 1354 1355 function _clearBag(amb) { 1356 if (!amb || !amb.serviziIgienici) return; 1357 var si = amb.serviziIgienici; 1358 var bn = String(si.nBlocchiWCTotale == null ? '' : si.nBlocchiWCTotale).trim(); 1359 if (bn && bn !== '0') return; 1360 if (stripPav || String(si.wcPavPiastrellati || '').toLowerCase() === 'si') { 1361 if (String(si.wcPavPiastrellati || '').toLowerCase() === 'si') { si.wcPavPiastrellati = ''; changed = true; } 1362 } 1363 if (stripAlt || String(si.wcAltPiastrellatura || '') === '2') { 1364 if (String(si.wcAltPiastrellatura || '') === '2') { si.wcAltPiastrellatura = ''; changed = true; } 1365 } 1366 } 1367 (d.ambientiSede || []).forEach(_clearBag); 1368 if (root._tab2LuogoHomeCache) _clearBag(root._tab2LuogoHomeCache); 1369 return changed; 1370 }; 1371 1372 /** 1373 * v20.372.1/3/6 â flat progetto â bag Luogo Principale se bag vuoto/indebolito post-merge F5. 1374 * NON idratare da flat «0» né da seed emptyData (pav si / alt 2 con nBlocchi vuoto). 1375 */ 1376 root._tab3HydrateWcBagFromFlat = function (d) { 1377 d = d || (typeof D === 'function' ? D() : null); 1378 if (!d) return false; 1379 try { root._tab3StripWcEmptyDataSeeds(d); } catch (_st) {} 1380 var lp = typeof root._tab3ResolvePrincipaleAmb === 'function' ? root._tab3ResolvePrincipaleAmb(d) : null; 1381 if (!lp) { 1382 var list = Array.isArray(d.ambientiSede) ? d.ambientiSede : []; 1383 for (var i = 0; i < list.length; i++) { 1384 if (list[i] && list[i].principale === true) { lp = list[i]; break; } 1385 } 1386 if (!lp && list.length === 1) lp = list[0]; 1387 } 1388 if (!lp) return false; 1389 if (!lp.serviziIgienici) lp.serviziIgienici = {}; 1390 var changed = false; 1391 1392 function _bagEmptyOrNa(v) { 1393 if (v == null || v === '') return true; 1394 return String(v).toLowerCase() === 'na'; 1395 } 1396 function _isSynthZero(v) { 1397 if (v == null || v === '') return false; 1398 var n = parseInt(v, 10); 1399 return Number.isFinite(n) && n === 0; 1400 } 1401 function _applyBagKey(key, flatVal, allowOverwriteNa) { 1402 if (flatVal == null || String(flatVal).trim() === '') return; 1403 if (key === 'nBlocchiWCTotale' && _isSynthZero(flatVal)) return; 1404 // v20.372.6 â non ripopolare bag da seed emptyData 1405 var nFlat = String(d.nBlocchiWCTotale == null ? '' : d.nBlocchiWCTotale).trim(); 1406 var nEmpty = !nFlat || nFlat === '0'; 1407 if (nEmpty && key === 'wcPavPiastrellati' && String(flatVal).toLowerCase() === 'si') return; 1408 if (nEmpty && key === 'wcAltPiastrellatura' && String(flatVal).trim() === '2') return; 1409 var cur = lp.serviziIgienici[key]; 1410 var empty = allowOverwriteNa ? _bagEmptyOrNa(cur) : (cur == null || String(cur).trim() === ''); 1411 if (!empty && !(key === 'nBlocchiWCTotale' && _isSynthZero(cur) && !_isSynthZero(flatVal))) return; 1412 lp.serviziIgienici[key] = flatVal; 1413 changed = true; 1414 if (root._tab2LuogoHomeCache && root._tab2LuogoHomeCache.id === lp.id) { 1415 if (!root._tab2LuogoHomeCache.serviziIgienici) root._tab2LuogoHomeCache.serviziIgienici = {}; 1416 var cCur = root._tab2LuogoHomeCache.serviziIgienici[key]; 1417 var cEmpty = allowOverwriteNa ? _bagEmptyOrNa(cCur) : (cCur == null || String(cCur).trim() === ''); 1418 if (cEmpty || (key === 'nBlocchiWCTotale' && _isSynthZero(cCur) && !_isSynthZero(flatVal))) { 1419 root._tab2LuogoHomeCache.serviziIgienici[key] = flatVal; 1420 } 1421 } 1422 } 1423 1424 var flatWc = d.nBlocchiWCTotale != null && String(d.nBlocchiWCTotale).trim() !== '' 1425 ? d.nBlocchiWCTotale 1426 : (d.nBlocchiWC != null && String(d.nBlocchiWC).trim() !== '' ? d.nBlocchiWC : null);
1427 _applyBagKey('nBlocchiWCTotale', flatWc, false); 1428 _applyBagKey('wcPavPiastrellati', d.wcPavPiastrellati, true); 1429 _applyBagKey('wcAltPiastrellatura', d.wcAltPiastrellatura, false); 1430 return changed; 1431 }; 1432 1433 root._tab3SyncComputedFields = function (d, opts) { 1434 opts = opts || {}; 1435 if (!d) return; 1436 // v20.148.0 â no _syncOrganicoDerivati su render (write storm Tab 2/3) 1437 // v20.371.13 â anti F5 overwrite: al backfill NON riscrivere un flat già valorizzato. 1438 // v20.372.1 â prima ripristina bag da flat se merge ha azzerato serviziIgienici 1439 // v20.372.3 â MAI scrivere «0» sintetico (onlyIfEmpty/force con Σ=0): crea ciclo F5 1440 // flat=0 â hydrate bag=0 â merge azzera FSâUI mostra 0 / «â». 1441 try { root._tab3HydrateWcBagFromFlat(d); } catch (_hw) {} 1442 var wc = root._tab3SumServiziIgieniciLuoghi(null); 1443 if (wc < 0) return; 1444 if (wc === 0 && !opts.allowZero) { 1445 // v20.372.3 â rimuovi «0» sintetico già presente (non inventare, non lasciare in UI) 1446 var curZ = String(d.nBlocchiWCTotale == null ? '' : d.nBlocchiWCTotale).trim(); 1447 if (curZ === '0') { 1448 var _clearZ = function () { 1449 if (typeof setD === 'function') { 1450 setD('nBlocchiWCTotale', ''); 1451 setD('nServiziIgienici', ''); 1452 } else { 1453 d.nBlocchiWCTotale = ''; 1454 d.nServiziIgienici = ''; 1455 } 1456 }; 1457 if (typeof root._withSsotBypass === 'function') root._withSsotBypass(_clearZ); 1458 else { 1459 var _pbz = (typeof window !== 'undefined') ? window._tecSsotBypass : false; 1460 if (typeof window !== 'undefined') window._tecSsotBypass = true; 1461 try { _clearZ(); } finally { if (typeof window !== 'undefined') window._tecSsotBypass = _pbz; } 1462 } 1463 try { 1464 var lpZ = typeof root._tab3ResolvePrincipaleAmb === 'function' ? root._tab3ResolvePrincipaleAmb(d) : null; 1465 if (lpZ && lpZ.serviziIgienici 1466 && String(lpZ.serviziIgienici.nBlocchiWCTotale == null ? '' : lpZ.serviziIgienici.nBlocchiWCTotale).trim() === '0') { 1467 lpZ.serviziIgienici.nBlocchiWCTotale = ''; 1468 } 1469 } catch (_cz) {} 1470 } 1471 return; 1472 } 1473 var wcStr = String(wc); 1474 var cur = String(d.nBlocchiWCTotale == null ? '' : d.nBlocchiWCTotale).trim(); 1475 var curSvc = String(d.nServiziIgienici == null ? '' : d.nServiziIgienici).trim(); 1476 if (cur === wcStr && curSvc === wcStr) return; 1477 if (!opts.force) { 1478 if (opts.onlyIfEmpty !== false && cur !== '') return; 1479 } 1480 if (opts.persist === false) { 1481 d.nBlocchiWCTotale = wcStr; 1482 d.nServiziIgienici = wcStr; 1483 return; 1484 } 1485 var _write = function () { 1486 if (typeof setD === 'function') { 1487 setD('nBlocchiWCTotale', wcStr); 1488 setD('nServiziIgienici', wcStr); 1489 } else { 1490 d.nBlocchiWCTotale = wcStr; 1491 d.nServiziIgienici = wcStr; 1492 } 1493 }; 1494 if (typeof root._withSsotBypass === 'function') root._withSsotBypass(_write); 1495 else if (typeof window !== 'undefined' && window._tecSsotBypass !== undefined) { 1496 var _pb = window._tecSsotBypass; 1497 window._tecSsotBypass = true; 1498 try { _write(); } finally { window._tecSsotBypass = _pb; } 1499 } else { 1500 _write(); 1501 } 1502 }; 1503 1504 /** Gate assessment per-luogo: bag assente â non conforme «Da censire â Luogo X». */ 1505 root._tab3PerLuogoFieldGate = function (luogo, key) { 1506 if (!luogo) return { ok: false, label: 'Da censire â Luogo (non selezionato)', conforme: false }; 1507 var nome = luogo.nome || luogo.label || luogo.id || 'Luogo'; 1508 if (typeof root._tab2LuogoFieldVal !== 'function') { 1509 return { ok: false, label: 'Da censire â ' + nome, conforme: false }; 1510 } 1511 var d = typeof D === 'function' ? D() : {}; 1512 var v = root._tab2LuogoFieldVal(luogo, key, d); 1513 var empty = v == null || v === '' || (Array.isArray(v) && !v.length); 1514 if (empty) return { ok: false, label: 'Da censire â ' + nome, conforme: false }; 1515 return { ok: true, label: String(v), conforme: true, value: v }; 1516 }; 1517 1518 root._tab3TriadeNavTab = function (tabNum, fieldKey) { 1519 var meta = root.TAB3_FIELD_SSC[fieldKey]; 1520 if (!meta) return null; 1521 if (meta.tier === P) return 18; 1522 if (meta.tier === C && meta.nav === 'triade_mansioni') return 20; 1523 if (meta.tier === C || meta.tier === S) return 2; 1524 return null; 1525 }; 1526 1527 root._tab3LegalResolveNav = function (fieldKey) { 1528 if (!fieldKey) return null; 1529 var meta = root.TAB3_FIELD_SSC[fieldKey]; 1530 if (!meta) return null; 1531 var subTabFn = root._legalLuogoSubTabForField || function () { return 'struttura'; }; 1532 if (meta.tier === P) { 1533 var sub = meta.luogoSubTab; 1534 if (!sub && root.TAB3_CPI_SSOT_KEYS && root.TAB3_CPI_SSOT_KEYS.indexOf(fieldKey) >
1534= 0) sub = 'antincendio'; 1535 if (!sub && typeof window !== 'undefined' && typeof window._dvrLuogoPrincipaleSubTabForField === 'function') { 1536 sub = window._dvrLuogoPrincipaleSubTabForField(fieldKey); 1537 } 1538 if (!sub) sub = subTabFn(fieldKey); 1539 return { 1540 kind: 'luogo', 1541 fieldKey: fieldKey, 1542 tab: 18, 1543 luogoSubTab: sub 1544 }; 1545 } 1546 if (meta.tier === S) { 1547 return { kind: 'normal', fieldKey: fieldKey, tab: 2, openT2Sec: meta.openT2Sec }; 1548 } 1549 if (meta.tier === C) { 1550 if (meta.nav === 'triade_mansioni') { 1551 return { kind: 'normal', fieldKey: fieldKey, tab: 20 }; 1552 } 1553 return { kind: 'normal', fieldKey: fieldKey, tab: 2, openT2Sec: meta.openT2Sec || 'wc' }; 1554 } 1555 return null; 1556 }; 1557 1558 root._tab3SsotSelfTest = function () { 1559 var errs = []; 1560 var ssc = root.TAB3_FIELD_SSC; 1561 if (!ssc.destinazioneUso || ssc.destinazioneUso.tier !== P) errs.push('destinazioneUso must be P'); 1562 if (!ssc.areaEstPresente || ssc.areaEstPresente.tier !== P) errs.push('areaEstPresente must be P'); 1563 if (!ssc.ingressoPrincVia || ssc.ingressoPrincVia.tier !== P) errs.push('ingressoPrincVia must be P'); 1564 if (!root.TAB3_MIRROR_3ABC_KEYS || root.TAB3_MIRROR_3ABC_KEYS.indexOf('tipoEdificio') < 0) { 1565 errs.push('TAB3_MIRROR_3ABC_KEYS'); 1566 } 1567 if (!ssc.nDipendenti || ssc.nDipendenti.tier !== C) errs.push('nDipendenti must be C'); 1568 if (!ssc.nBlocchiWCTotale || ssc.nBlocchiWCTotale.tier !== C) errs.push('nBlocchiWCTotale must be C'); 1569 if (!ssc.tipoEdificio || ssc.tipoEdificio.tier !== P) errs.push('tipoEdificio must be P'); 1570 if (!root.TAB3_FIELD_ENTITY || root.TAB3_FIELD_ENTITY.ingressoPrincVia !== L) errs.push('ingressoPrincVia entity L'); 1571 if (root._tab3FieldEntityTier('areaEstPresente') !== L) errs.push('areaEstPresente entity L'); 1572 if (root._tab3FieldEntityTier('ingressoPrincVia') !== L) errs.push('ingressoPrincVia entity L'); 1573 if (root._tab3FieldEntityTier('osservAccessi') !== O) errs.push('osservAccessi entity O'); 1574 if (root._tab3FieldEntityTier('descrizioneLuogo') !== L) errs.push('descrizioneLuogo entity L'); 1575 if (!root.TAB3_CPI_SSOT_KEYS || root.TAB3_CPI_SSOT_KEYS.indexOf('statoCPI') < 0) errs.push('TAB3_CPI_SSOT_KEYS'); 1576 if (!root.TAB3_CPI_SSOT_PATH || root.TAB3_CPI_SSOT_PATH.indexOf('impianti.cpi') < 0) errs.push('TAB3_CPI_SSOT_PATH'); 1577 if (typeof root._tab3SyncCpiBidirectional !== 'function') errs.push('_tab3SyncCpiBidirectional missing'); 1578 if (typeof root._setCpiSsotField !== 'function') errs.push('_setCpiSsotField missing'); 1579 if (typeof root._tab3SyncEdificioBidirectional !== 'function') errs.push('_tab3SyncEdificioBidirectional missing'); 1580 if (typeof root._tab3SyncPrincipaleMirrorToFlat !== 'function') errs.push('_tab3SyncPrincipaleMirrorToFlat missing'); 1581 if (typeof root._tab3PushPrincipaleMirrorToFlat !== 'function') errs.push('_tab3PushPrincipaleMirrorToFlat missing'); 1582 if (typeof root._tab3SyncPrincipaleMirrorToFlat === 'function') { 1583 var dMir = { tipoEdificio: 'Vecchio', ambientiSede: [{ id: 'p', principale: true }] }; 1584 var lMir = { id: 'p', principale: true, tipoEdificio: 'Capannone industriale', annoCostruzione: '1990' }; 1585 var mir = root._tab3SyncPrincipaleMirrorToFlat(dMir, lMir, {}); 1586 if (!mir.changed || dMir.tipoEdificio !== 'Capannone industriale' || dMir.annoCostruzione !== '1990') { 1587 errs.push('_tab3SyncPrincipaleMirrorToFlat mono'); 1588 } 1589 var dRew = { tipoEdificio: 'Vecchio', annoCostruzione: '1980', statoCPI: 'presente', ambientiSede: [{ id: 'n', principale: true }] }; 1590 var lRew = { id: 'n', principale: true, tipoEdificio: 'Ufficio', impianti: { cpi: { statoCPI: '' } } }; 1591 var rew = root._tab3SyncPrincipaleMirrorToFlat(dRew, lRew, { rewireAll: true }); 1592 if (!rew.changed || dRew.tipoEdificio !== 'Ufficio' || dRew.annoCostruzione !== '' || dRew.statoCPI !== '') { 1593 errs.push('_tab3SyncPrincipaleMirrorToFlat rewireAll'); 1594 } 1595 } 1596 if (!root.TAB3_EDIFICIO_SSOT_KEYS || root.TAB3_EDIFICIO_SSOT_KEYS.indexOf('nPianiFT') < 0) errs.push('TAB3_EDIFICIO_SSOT_KEYS'); 1597 if (typeof root._tab3GuardEdificioSetD !== 'function') errs.push('_tab3GuardEdificioSetD missing'); 1598 if (root._tab3GuardEdificioSetD('tipoEdificio', { ambientiSede: [{ id: 'a' }, { id: 'b' }] }) !== true) { 1599 errs.push('P13 guard tipoEdificio multi'); 1600 } 1601 if (root._tab3GuardEdificioSetD('tipoEdificio', { ambientiSede: [{ id: 'a', principale: true }] }) !== true) { 1602 errs.push('P13 guard tipoEdificio mono con luogo'); 1603 } 1604 if (root._tab3GuardEdificioSetD('tipoEdificio', { ambientiSede: [] }) !== false) { 1605 errs.push('P13 guard tipoEdificio senza luoghi deve passare'); 1606 } 1607 if (typeof root._tab3GuardPrincipaleMirrorSetD !== 'function') errs.push('_tab3GuardPrincipaleMirrorSetD missing'); 1608 if (root._tab3GuardPrincipaleMirrorSetD('statoCPI', { ambientiSede: [{ id: 'a' }] }) !== true) { 1609 errs.push('P13 mirror guard statoCPI'); 1610 } 1611 if (typeof root._tab3OperationalAmbientiList !== 'function') errs.push('_tab3OperationalAmbientiList missing'); 1612 if (root._tecGmrEpcLuoghi && typeof root._tab3CountLuoghi === 'function') { 1613 var dLeak = { 1614 ambientiSede: [ 1615 { id: 'a', nome: 'Sede operativa', principale: true }, 1616 { id: 'tec', nome: 'TECNOLOGICA SERVICE s.r.l.' } 1617 ], 1618 ragioneSociale: 'GMR s.r.l.' 1619 }; 1620 if (root._tab3CountLuoghi(dLeak) !== 1) errs.push('operational count excludes consultant leak'); 1621 if (root._tab3GuardEdificioSetD('tipoEdificio', dLeak) !== false) { 1622 errs.push('consultant leak must not trigger multi-luogo guard'); 1623 } 1624 } 1625 if (typeof root._tab3LegalResolveNav !== 'function') errs.push('_tab3LegalResolveNav missing'); 1626 var navS = root._tab3LegalResolveNav('destinazioneUso'); 1627 if (!navS || navS.tab !== 18 || navS.luogoSubTab !== 'struttura') errs.push('Legal nav destinazioneUso â tab 18 struttura'); 1628 var navB = root._tab3LegalResolveNav('areaEstPresente'); 1629 if (!navB || navB.tab !== 18 || navB.luogoSubTab !== 'struttura') errs.push('Legal nav areaEstPresente â tab 18 struttura'); 1630 var navC3 = root._tab3LegalResolveNav('ingressoPrincVia'); 1631 if (!navC3 || navC3.tab !== 18) errs.push('Legal nav ingressoPrincVia â
1631 tab 18'); 1632 var navP = root._tab3LegalResolveNav('tipoEdificio'); 1633 if (!navP || navP.tab !== 18) errs.push('Legal nav tipoEdificio â tab 18'); 1634 var navC = root._tab3LegalResolveNav('nDipendenti'); 1635 if (!navC || navC.tab !== 20) errs.push('Legal nav nDipendenti â tab 20'); 1636 ['soggettoVVF', 'statoCPI', 'attivitaDPR151', 'rischioIncendioNuovo', 'gruppoPS'].forEach(function (k) { 1637 var nav = root._tab3LegalResolveNav(k); 1638 if (!nav || nav.tab !== 18 || nav.luogoSubTab !== 'antincendio') errs.push('Legal nav CPI ' + k + ' â tab 18 antincendio'); 1639 }); 1640 if (typeof root._tab3RenderCpiTab2Panel === 'function') { 1641 var dMock = { 1642 soggettoVVF: 'si', statoCPI: 'presente', attivitaDPR151: 'no', 1643 rischioIncendioVecchio: 'medio', rischioIncendioNuovo: '2', gruppoPS: 'C', 1644 ambientiSede: [{ id: 'a1', principale: true }, { id: 'a2' }] 1645 }; 1646 var html = root._tab3RenderCpiTab2Panel(dMock, { SEC: function (_id, _ic, _t, b) { return b; } }); 1647 if (html.indexOf('data-field-key="soggettoVVF"') < 0) errs.push('CPI panel missing data-field-key soggettoVVF'); 1648 if (html.indexOf('data-field-key="statoCPI"') < 0) errs.push('CPI panel missing data-field-key statoCPI'); 1649 if (html.indexOf('data-field-key="rischioIncendioNuovo"') < 0) errs.push('CPI panel missing rischioIncendioNuovo'); 1650 if (html.indexOf('<select') < 0 || html.indexOf('rischioIncendioNuovo') < 0) errs.push('CPI multi: rischioIncendioNuovo select'); 1651 if (typeof root._proponiClasseIncendio === 'function') { 1652 if (html.indexOf('Suggerito:') < 0) errs.push('CPI multi: badge Suggerito'); 1653 if (html.indexOf('data-suggested="1"') < 0) errs.push('CPI multi: option suggerita â '); 1654 } 1655 } 1656 if (typeof root._tab3CpiSuggestFor !== 'function') errs.push('_tab3CpiSuggestFor missing'); 1657 if (typeof root._tab2LuogoFieldVal !== 'function') errs.push('_tab2LuogoFieldVal missing'); 1658 else { 1659 var amb = { superficie_mq: 15, capienza_max: 8 }; 1660 if (root._tab2LuogoFieldVal(amb, 'superficie') !== 15) errs.push('_tab2LuogoFieldVal superficieâsuperficie_mq'); 1661 if (root._tab2LuogoFieldVal(amb, 'maxPresenze') !== 8) errs.push('_tab2LuogoFieldVal maxPresenzeâcapienza_max'); 1662 var cop = { superficieCoperta: '120' }; 1663 if (root._tab2LuogoFieldVal(cop, 'superficieCoperta') !== '120') errs.push('_tab2LuogoFieldVal superficieCoperta'); 1664 var luArr = { 1665 id: 'p1', principale: true, 1666 piani: [{ nome: 'Piano Terra', locali: ['Reception'] }], 1667 serviziIgienici: { blocchiWC: [{ piano: 'PT', nBlocchi: '2' }] } 1668 }; 1669 if (!Array.isArray(root._tab2LuogoFieldVal(luArr, 'piani')) || root._tab2LuogoFieldVal(luArr, 'piani').length !== 1) { 1670 errs.push('_tab2LuogoFieldVal piani array'); 1671 } 1672 if (!Array.isArray(root._tab2LuogoFieldVal(luArr, 'blocchiWC')) || root._tab2LuogoFieldVal(luArr, 'blocchiWC').length !== 1) { 1673 errs.push('_tab2LuogoFieldVal blocchiWC array'); 1674 } 1675 } 1676 if (typeof root._tab3ResolveExportField !== 'function') errs.push('_tab3ResolveExportField missing'); 1677 else { 1678 var dExp = { 1679 tipoEdificio: 'Legacy flat', 1680 accessiCarrabili: [{ via: 'Via Tab3' }], 1681 ambientiSede: [{ id: 'p1', principale: true, tipoEdificio: 'Da grafo' }] 1682 }; 1683 root._tab3CountLuoghi = function () { return 1; }; 1684 if (root._tab3ResolveExportField('tipoEdificio', dExp) !== 'Da grafo') { 1685 errs.push('_tab3ResolveExportField principale before d.*'); 1686 } 1687 if (!Array.isArray(root._tab3ResolveExportField('accessiCarrabili', dExp)) || 1688 root._tab3ResolveExportField('accessiCarrabili', dExp)[0].via !== 'Via Tab3') { 1689 errs.push('_tab3ResolveExportField tier S accessiCarrabili'); 1690 } 1691 var dSede = { tipoEdificio: '', ambientiSede: [{ id: 'p1', principale: true }] }; 1692 root.CLIENTI_LIST = [{ 1693 id: 'cl1', 1694 sedi: [{ sedeId: 's1', tipoEdificio: 'Da sede anagrafica' }] 1695 }]; 1696 root.CP = function () { return { clienteMasterId: 'cl1', sedeId: 's1' }; }; 1697 if (root._tab3ResolveExportField('tipoEdificio', dSede) !== 'Da sede anagrafica') { 1698 errs.push('_tab3ResolveExportField sede fallback'); 1699 } 1700 } 1701 if (typeof root._tab3SyncGrafoArrayToPrincipale !== 'function') errs.push('_tab3SyncGrafoArrayToPrincipale missing'); 1702 else { 1703 var dG = { ambientiSede: [{ id: 'p1', principale: true, piani: [] }] }; 1704 root._tab3CountLuoghi = function () { return 1; }; 1705 root._tab3ResolvePrincipaleAmb = function (dd) { 1706 return (dd.ambientiSede || []).filter(function (a) { return a && a.principale; })[0] || null; 1707 }; 1708 var syncP = root._tab3SyncGrafoArrayToPrincipale(dG, 'piani', [{ nome: 'Terra' }]); 1709 if (!syncP.changed || !dG.ambientiSede[0].piani || dG.ambientiSede[0].piani[0].nome !== 'Terra') { 1710 errs.push('_tab3SyncGrafoArrayToPrincipale piani'); 1711 } 1712 } 1713 return { ok: !errs.length, errors: errs, count: Object.keys(ssc).length }; 1714 }; 1715 1716 (function installTab3SetDHook() { 1717 var prevAfter = root._ssotAfterSetD; 1718 root._ssotAfterSetD = function (p, key, val) { 1719 if (typeof prevAfter === 'function') prevAfter(p, key, val); 1720 if (!p || !p.data || !key || root.TAB3_GRAFO_ARRAY_KEYS.indexOf(key) < 0) return; 1721 if (typeof root._tab3SyncGrafoArrayToPrincipale === 'function') { 1722 root._tab3SyncGrafoArrayToPrincipale(p.data, key, val); 1723 } 1724 }; 1725 })(); 1726 1727})(typeof window !== 'undefined' ? window : globalThis);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.