@open3cl/engine 1.11.2 → 1.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -60,3 +60,81 @@ export function reconstituerRdimEcsIndividuelleUnique(th, instal_ecs, surfaceHab
60
60
  instal_ecs[0].donnee_entree.rdim_reconstitue = true;
61
61
  return true;
62
62
  }
63
+
64
+ /**
65
+ * DPE immeuble avec plusieurs installations ECS individuelles, chacune décrite pour un logement type.
66
+ *
67
+ * Même convention d'export que l'installation unique (3.0.x, 2.0.x, 1.1.x) : pour chaque
68
+ * installation i, `surface_habitable` = Sh_i d'un logement type et `nombre_logement` = N_i, sans
69
+ * `rdim`, avec Σ Sh_i × N_i = SH. Tribu traite chaque installation indépendamment avec Rdim_i = N_i :
70
+ * Becs_i = Becs_immeuble × Sh_i × Rdim_i / SH / Rdim_i, puis Cecs = Σ Cecs_i × Rdim_i. L'export ADEME
71
+ * le confirme : besoin_ecs_i = Becs_immeuble × Sh_i / SH et conso_ecs = Σ conso_ecs_i × N_i.
72
+ *
73
+ * Sans rdim, Σ Sh_i ≠ SH : Open3CL se replie sur Becs_immeuble / nombre_appartement par
74
+ * installation et ne remultiplie pas la conso par N_i.
75
+ *
76
+ * Gardes :
77
+ * - Σ Sh_i × N_i ≈ SH (TOLERANCE_SURFACE_LOGEMENT_TYPE) : exclut les exports où Sh_i est déjà
78
+ * la surface totale desservie (Σ Sh_i = SH, ex. N_i fractionnaires) ;
79
+ * - au moins un N_i > 1 : sinon rdim = 1 partout, sans effet (LICIEL, nombre_logement = 1).
80
+ *
81
+ * @see Methode_de_calcul_3CL_DPE_2021-338.pdf - § 11.4 et § 17.1.3.2
82
+ * @see Tribu : Calcul_batiment.cs l. 581-588 (boucle par installation, Ratio = Sh·Rdim/SH,
83
+ * Becs / Rdim), l. 1660-1662 (Cecs_i / Rdim puis × Rdim) ; Calcul_installation_ECS.cs l. 75
84
+ * @see Guide Tribu TE-211208 « Particularités d'une répétition de systèmes d'ECS individuel dans un
85
+ * immeuble collectif » (Sh_ecs = surface d'un logement, Rdim = nombre d'installations identiques)
86
+ */
87
+
88
+ /**
89
+ * Rdim implicites des installations ECS individuelles multiples d'un immeuble (dans l'ordre des
90
+ * installations), ou null si non concernées.
91
+ *
92
+ * @param th {string} type de bâtiment (maison, appartement, immeuble)
93
+ * @param instal_ecs {Array} installation_ecs
94
+ * @param surfaceHabitableImmeuble {number|string} surface habitable de l'immeuble (SH)
95
+ * @return {number[]|null}
96
+ */
97
+ export function rdimsImplicitesEcsIndividuellesMultiples(th, instal_ecs, surfaceHabitableImmeuble) {
98
+ if (th !== 'immeuble' || !Array.isArray(instal_ecs) || instal_ecs.length < 2) return null;
99
+
100
+ const des = instal_ecs.map((inst) => inst?.donnee_entree);
101
+ const concernees = des.every(
102
+ (de) => de && String(de.enum_type_installation_id) === '1' && !de.rdim
103
+ );
104
+ if (!concernees) return null;
105
+
106
+ const SH = Number(surfaceHabitableImmeuble);
107
+ if (!(SH > 0)) return null;
108
+
109
+ const surfaces = des.map((de) => Number(de.surface_habitable));
110
+ const rdims = des.map((de) => Number(de.nombre_logement) || 1);
111
+ if (!surfaces.every((sh) => sh > 0) || !rdims.every((n) => n > 0)) return null;
112
+ if (!rdims.some((n) => n > 1)) return null;
113
+
114
+ const sommeShN = surfaces.reduce((acc, sh, i) => acc + sh * rdims[i], 0);
115
+ return Math.abs(sommeShN - SH) <= TOLERANCE_SURFACE_LOGEMENT_TYPE * SH ? rdims : null;
116
+ }
117
+
118
+ /**
119
+ * Reconstitue le rdim des installations ECS individuelles multiples d'un immeuble décrites pour un
120
+ * logement type. Chaque installation reçoit `rdim` = nombre_logement (1 si absent) et le flag
121
+ * `rdim_reconstitue`.
122
+ *
123
+ * @param th {string} type de bâtiment
124
+ * @param instal_ecs {Array} installation_ecs
125
+ * @param surfaceHabitableImmeuble {number|string} surface habitable de l'immeuble (SH)
126
+ * @return {boolean} true si les rdim ont été reconstitués
127
+ */
128
+ export function reconstituerRdimEcsIndividuellesMultiples(
129
+ th,
130
+ instal_ecs,
131
+ surfaceHabitableImmeuble
132
+ ) {
133
+ const rdims = rdimsImplicitesEcsIndividuellesMultiples(th, instal_ecs, surfaceHabitableImmeuble);
134
+ if (rdims === null) return false;
135
+ instal_ecs.forEach((inst, i) => {
136
+ inst.donnee_entree.rdim = rdims[i];
137
+ inst.donnee_entree.rdim_reconstitue = true;
138
+ });
139
+ return true;
140
+ }
@@ -1,7 +1,9 @@
1
1
  import { describe, expect, test } from 'vitest';
2
2
  import {
3
3
  rdimImpliciteEcsIndividuelleUnique,
4
+ rdimsImplicitesEcsIndividuellesMultiples,
4
5
  reconstituerRdimEcsIndividuelleUnique,
6
+ reconstituerRdimEcsIndividuellesMultiples,
5
7
  TOLERANCE_SURFACE_LOGEMENT_TYPE
6
8
  } from './11_rdim_ecs_individuelle_unique.js';
7
9
 
@@ -111,3 +113,137 @@ describe("Rdim de l'installation ECS individuelle unique d'un immeuble", () => {
111
113
  });
112
114
  });
113
115
  });
116
+
117
+ /**
118
+ * @see Methode_de_calcul_3CL_DPE_2021-338.pdf - § 11.4 et § 17.1.3.2
119
+ * @see Tribu : Calcul_batiment.cs l. 581-588 et l. 1660-1662 ; Calcul_installation_ECS.cs l. 75
120
+ */
121
+ describe("Rdim des installations ECS individuelles multiples d'un immeuble", () => {
122
+ /** Installation ECS individuelle décrite pour un logement type */
123
+ const inst = (surface_habitable, nombre_logement, de = {}) => ({
124
+ donnee_entree: { enum_type_installation_id: '1', surface_habitable, nombre_logement, ...de }
125
+ });
126
+ /** Cas type 2244E3039157K : 48,82 × 2 + 78,09 × 6 = 566,18 ≈ SH = 566,16 */
127
+ const ecs = () => [inst(48.82, 2), inst(78.09, 6)];
128
+
129
+ describe('rdimsImplicitesEcsIndividuellesMultiples', () => {
130
+ test('installations individuelles, Σ Sh × N = SH, sans rdim : rdim_i = nombre_logement_i', () => {
131
+ expect(rdimsImplicitesEcsIndividuellesMultiples('immeuble', ecs(), 566.16)).toEqual([2, 6]);
132
+ expect(
133
+ rdimsImplicitesEcsIndividuellesMultiples(
134
+ 'immeuble',
135
+ [
136
+ inst('48.82', '2', { enum_type_installation_id: 1 }),
137
+ inst('78.09', '6', { enum_type_installation_id: 1 })
138
+ ],
139
+ '566.16'
140
+ )
141
+ ).toEqual([2, 6]);
142
+ });
143
+
144
+ test('nombre_logement absent sur une installation : rdim = 1 pour celle-ci', () => {
145
+ // 100 × 4 + 50 × 1 = 450
146
+ expect(
147
+ rdimsImplicitesEcsIndividuellesMultiples(
148
+ 'immeuble',
149
+ [inst(100, 4), inst(50, undefined)],
150
+ 450
151
+ )
152
+ ).toEqual([4, 1]);
153
+ });
154
+
155
+ test('tolérance de 5 % sur Σ Sh × N ≈ SH', () => {
156
+ // Σ = 100 × 4 + 50 × 2 = 500 ; |500 − SH| ≤ 0,05 × SH ⇔ 476,19 ≤ SH ≤ 526,31
157
+ const deux = () => [inst(100, 4), inst(50, 2)];
158
+ expect(rdimsImplicitesEcsIndividuellesMultiples('immeuble', deux(), 526)).toEqual([4, 2]);
159
+ expect(rdimsImplicitesEcsIndividuellesMultiples('immeuble', deux(), 477)).toEqual([4, 2]);
160
+ expect(rdimsImplicitesEcsIndividuellesMultiples('immeuble', deux(), 527)).toBeNull();
161
+ expect(rdimsImplicitesEcsIndividuellesMultiples('immeuble', deux(), 476)).toBeNull();
162
+ });
163
+
164
+ test('surfaces exportées comme surface totale desservie (Σ Sh = SH) : non concerné', () => {
165
+ // Cas type 2224E1374434V : 74,4 × 3 + 31 × 1 = 254,2 ≠ SH = 105,4 = Σ Sh
166
+ expect(
167
+ rdimsImplicitesEcsIndividuellesMultiples('immeuble', [inst(74.4, 3), inst(31, 1)], 105.4)
168
+ ).toBeNull();
169
+ });
170
+
171
+ test('tous les nombre_logement à 1 (LICIEL) : non concerné', () => {
172
+ expect(
173
+ rdimsImplicitesEcsIndividuellesMultiples('immeuble', [inst(60, 1), inst(40, 1)], 100)
174
+ ).toBeNull();
175
+ });
176
+
177
+ test('un rdim exporté sur une installation : on conserve la saisie', () => {
178
+ expect(
179
+ rdimsImplicitesEcsIndividuellesMultiples(
180
+ 'immeuble',
181
+ [inst(48.82, 2, { rdim: 2 }), inst(78.09, 6)],
182
+ 566.16
183
+ )
184
+ ).toBeNull();
185
+ });
186
+
187
+ test('une installation collective : non concerné', () => {
188
+ expect(
189
+ rdimsImplicitesEcsIndividuellesMultiples(
190
+ 'immeuble',
191
+ [inst(48.82, 2), inst(78.09, 6, { enum_type_installation_id: '2' })],
192
+ 566.16
193
+ )
194
+ ).toBeNull();
195
+ });
196
+
197
+ test('maison ou appartement : non concerné', () => {
198
+ expect(rdimsImplicitesEcsIndividuellesMultiples('maison', ecs(), 566.16)).toBeNull();
199
+ expect(rdimsImplicitesEcsIndividuellesMultiples('appartement', ecs(), 566.16)).toBeNull();
200
+ });
201
+
202
+ test('installation unique : non concerné (cf. rdimImpliciteEcsIndividuelleUnique)', () => {
203
+ expect(rdimsImplicitesEcsIndividuellesMultiples('immeuble', [inst(64, 10)], 640)).toBeNull();
204
+ });
205
+
206
+ test('données manquantes ou invalides : non concerné', () => {
207
+ expect(rdimsImplicitesEcsIndividuellesMultiples('immeuble', undefined, 566.16)).toBeNull();
208
+ expect(rdimsImplicitesEcsIndividuellesMultiples('immeuble', [], 566.16)).toBeNull();
209
+ expect(
210
+ rdimsImplicitesEcsIndividuellesMultiples('immeuble', [inst(48.82, 2), {}], 566.16)
211
+ ).toBeNull();
212
+ expect(
213
+ rdimsImplicitesEcsIndividuellesMultiples('immeuble', [inst(48.82, 2), null], 566.16)
214
+ ).toBeNull();
215
+ expect(rdimsImplicitesEcsIndividuellesMultiples('immeuble', ecs(), undefined)).toBeNull();
216
+ expect(rdimsImplicitesEcsIndividuellesMultiples('immeuble', ecs(), 0)).toBeNull();
217
+ expect(
218
+ rdimsImplicitesEcsIndividuellesMultiples(
219
+ 'immeuble',
220
+ [inst(48.82, 2), inst(undefined, 6)],
221
+ 566.16
222
+ )
223
+ ).toBeNull();
224
+ expect(
225
+ rdimsImplicitesEcsIndividuellesMultiples('immeuble', [inst(100, 4), inst(50, -2)], 300)
226
+ ).toBeNull();
227
+ });
228
+ });
229
+
230
+ describe('reconstituerRdimEcsIndividuellesMultiples', () => {
231
+ test('installations concernées : rdim et flag positionnés sur chacune', () => {
232
+ const installations = ecs();
233
+ expect(reconstituerRdimEcsIndividuellesMultiples('immeuble', installations, 566.16)).toBe(
234
+ true
235
+ );
236
+ expect(installations[0].donnee_entree).toMatchObject({ rdim: 2, rdim_reconstitue: true });
237
+ expect(installations[1].donnee_entree).toMatchObject({ rdim: 6, rdim_reconstitue: true });
238
+ });
239
+
240
+ test('installations non concernées : inchangées', () => {
241
+ const installations = [inst(60, 1), inst(40, 1)];
242
+ expect(reconstituerRdimEcsIndividuellesMultiples('immeuble', installations, 100)).toBe(false);
243
+ installations.forEach((i) => {
244
+ expect(i.donnee_entree.rdim).toBeUndefined();
245
+ expect(i.donnee_entree.rdim_reconstitue).toBeUndefined();
246
+ });
247
+ });
248
+ });
249
+ });
package/README.md CHANGED
@@ -383,7 +383,7 @@ Ces résultats sont **générés automatiquement** à la fin de `npm run test:co
383
383
 
384
384
  <!-- CORPUS:START -->
385
385
 
386
- > **Version `1.10.0`** · branche `main` · généré le 2026-10-29
386
+ > **Version `1.11.2`** · à publier · branche `main` · généré le 2026-10-30
387
387
  > Seuil de tolérance **5%**
388
388
 
389
389
  <table>
@@ -416,24 +416,24 @@ Ces résultats sont **générés automatiquement** à la fin de `npm run test:co
416
416
 
417
417
  <table>
418
418
  <tr>
419
- <td align="center"><strong>5,64 ms</strong><br/><sub>moyenne</sub></td>
420
- <td align="center"><strong>4,87 ms</strong><br/><sub>médiane</sub></td>
419
+ <td align="center"><strong>5,99 ms</strong><br/><sub>moyenne</sub></td>
420
+ <td align="center"><strong>5,23 ms</strong><br/><sub>médiane</sub></td>
421
421
  <td align="center"><strong>0,11 ms</strong><br/><sub>min</sub></td>
422
- <td align="center"><strong>957,0 ms</strong><br/><sub>max</sub></td>
422
+ <td align="center"><strong>641,5 ms</strong><br/><sub>max</sub></td>
423
423
  </tr>
424
424
  </table>
425
425
 
426
426
  | Corpus | Moyenne | Médiane | Min | Max | p95 | p99 |
427
427
  | :--------------------------------------------- | ------: | ------: | ------: | -------: | ------: | ------: |
428
- | **Appartement · chauffage individuel (2025)** | 4,00 ms | 3,58 ms | 1,42 ms | 34,6 ms | 6,99 ms | 9,30 ms |
429
- | **Appartement · chauffage collectif (2025)** | 4,46 ms | 4,04 ms | 1,62 ms | 42,4 ms | 7,33 ms | 9,33 ms |
430
- | **Logement individuel (2025)** | 5,20 ms | 4,57 ms | 1,74 ms | 56,0 ms | 9,72 ms | 13,5 ms |
431
- | **Maison individuelle (2025)** | 6,01 ms | 5,41 ms | 2,04 ms | 51,8 ms | 10,7 ms | 14,3 ms |
432
- | **Maison individuelle (2026)** | 6,16 ms | 5,47 ms | 2,09 ms | 46,7 ms | 11,1 ms | 15,1 ms |
433
- | **Immeuble · chauffage collectif** | 5,81 ms | 4,91 ms | 0,14 ms | 126,7 ms | 10,9 ms | 17,7 ms |
434
- | **Immeuble · chauffage individuel** | 7,07 ms | 5,99 ms | 0,11 ms | 123,4 ms | 14,5 ms | 22,6 ms |
435
- | **Immeuble · chauffage mixte** | 5,73 ms | 4,63 ms | 0,20 ms | 957,0 ms | 11,9 ms | 19,7 ms |
436
- | **Individuel généré depuis l'immeuble (2026)** | 6,33 ms | 5,26 ms | 1,79 ms | 79,2 ms | 12,0 ms | 19,1 ms |
428
+ | **Appartement · chauffage individuel (2025)** | 4,09 ms | 3,70 ms | 1,56 ms | 47,5 ms | 7,05 ms | 9,52 ms |
429
+ | **Appartement · chauffage collectif (2025)** | 4,98 ms | 4,64 ms | 1,66 ms | 41,1 ms | 8,18 ms | 10,7 ms |
430
+ | **Logement individuel (2025)** | 5,36 ms | 4,70 ms | 1,75 ms | 61,9 ms | 10,0 ms | 14,0 ms |
431
+ | **Maison individuelle (2025)** | 6,37 ms | 5,70 ms | 1,93 ms | 58,0 ms | 11,5 ms | 15,4 ms |
432
+ | **Maison individuelle (2026)** | 6,43 ms | 5,76 ms | 2,16 ms | 48,3 ms | 11,7 ms | 15,7 ms |
433
+ | **Immeuble · chauffage collectif** | 5,75 ms | 4,90 ms | 0,11 ms | 102,7 ms | 10,6 ms | 17,6 ms |
434
+ | **Immeuble · chauffage individuel** | 7,49 ms | 6,40 ms | 0,11 ms | 127,0 ms | 15,3 ms | 23,9 ms |
435
+ | **Immeuble · chauffage mixte** | 6,57 ms | 5,44 ms | 0,19 ms | 641,5 ms | 13,8 ms | 23,4 ms |
436
+ | **Individuel généré depuis l'immeuble (2026)** | 6,88 ms | 5,83 ms | 1,86 ms | 79,6 ms | 12,9 ms | 21,8 ms |
437
437
 
438
438
  <sub>La moyenne est tirée vers le haut par les DPE collectifs, dont le coût atteint plusieurs
439
439
  dizaines de fois la médiane : c’est la médiane qui décrit le cas courant, et p95/p99 le cas
package/engine.js CHANGED
@@ -34,9 +34,12 @@ import getFicheTechnique from './ficheTechnique.js';
34
34
  import { ProductionENR, ratioProrataPvLogement } from './16.2_production_enr.js';
35
35
  import DpeSanitizerService from './dpe-sanitizer.service.js';
36
36
  import { reconstituerRdimDpeGenereImmeuble } from './17.2_rdim_dpe_genere_immeuble.js';
37
- import { reconstituerRdimEcsIndividuelleUnique } from './11_rdim_ecs_individuelle_unique.js';
37
+ import {
38
+ reconstituerRdimEcsIndividuelleUnique,
39
+ reconstituerRdimEcsIndividuellesMultiples
40
+ } from './11_rdim_ecs_individuelle_unique.js';
38
41
 
39
- const LIB_VERSION = '1.11.2';
42
+ const LIB_VERSION = '1.11.3';
40
43
 
41
44
  const dpeSanitizerService = new DpeSanitizerService();
42
45
 
@@ -305,6 +308,11 @@ export function calcul_3cl(inputDpe, options) {
305
308
  * @see https://github.com/Open3CL/engine/issues/288
306
309
  */
307
310
  reconstituerRdimEcsIndividuelleUnique(th, ecs, cg.surface_habitable_immeuble);
311
+ /**
312
+ * Immeuble avec plusieurs installations ECS individuelles décrites chacune pour un logement type
313
+ * (Σ Sh_i × nombre_logement_i ≈ SH, sans rdim) : rdim_i = nombre_logement_i.
314
+ */
315
+ reconstituerRdimEcsIndividuellesMultiples(th, ecs, cg.surface_habitable_immeuble);
308
316
  const Nb_lgt = cg.nombre_appartement || 1;
309
317
 
310
318
  /**
package/engine.spec.js CHANGED
@@ -75,7 +75,8 @@ vi.mock('./17.2_rdim_dpe_genere_immeuble.js', () => ({
75
75
  reconstituerRdimDpeGenereImmeuble: vi.fn()
76
76
  }));
77
77
  vi.mock('./11_rdim_ecs_individuelle_unique.js', () => ({
78
- reconstituerRdimEcsIndividuelleUnique: vi.fn()
78
+ reconstituerRdimEcsIndividuelleUnique: vi.fn(),
79
+ reconstituerRdimEcsIndividuellesMultiples: vi.fn()
79
80
  }));
80
81
 
81
82
  // Les instances Inertie / ProductionENR sont créées au chargement du module.
@@ -129,7 +130,7 @@ const calc_confort_ete = (await import('./2021_04_13_confort_ete.js')).default;
129
130
  const calc_qualite_isolation = (await import('./2021_04_13_qualite_isolation.js')).default;
130
131
  const getFicheTechnique = (await import('./ficheTechnique.js')).default;
131
132
  const { reconstituerRdimDpeGenereImmeuble } = await import('./17.2_rdim_dpe_genere_immeuble.js');
132
- const { reconstituerRdimEcsIndividuelleUnique } =
133
+ const { reconstituerRdimEcsIndividuelleUnique, reconstituerRdimEcsIndividuellesMultiples } =
133
134
  await import('./11_rdim_ecs_individuelle_unique.js');
134
135
 
135
136
  /** Objet conso renvoyé par le mock de `calc_conso` (mêmes réf pour les 3 appels). */
@@ -1326,6 +1327,26 @@ describe('calcul_3cl - rdim de l’installation ECS individuelle unique d’un i
1326
1327
  });
1327
1328
  });
1328
1329
 
1330
+ describe('calcul_3cl - rdim des installations ECS individuelles multiples d’un immeuble', () => {
1331
+ test('reconstitution appelée avec le type de bâtiment, les installations ECS et SH, avant le calcul ECS', () => {
1332
+ const dpe = makeDpe();
1333
+ dpe.logement.caracteristique_generale.surface_habitable_immeuble = 566.16;
1334
+ vi.mocked(reconstituerRdimEcsIndividuellesMultiples).mockImplementationOnce(() => {
1335
+ expect(calc_ecs).not.toHaveBeenCalled();
1336
+ return false;
1337
+ });
1338
+
1339
+ calcul_3cl(dpe, { sanitize: false });
1340
+
1341
+ expect(reconstituerRdimEcsIndividuellesMultiples).toHaveBeenCalledWith(
1342
+ 'maison',
1343
+ dpe.logement.installation_ecs_collection.installation_ecs,
1344
+ 566.16
1345
+ );
1346
+ expect(calc_ecs).toHaveBeenCalled();
1347
+ });
1348
+ });
1349
+
1329
1350
  describe('get_conso_coeff_1_7_2027', () => {
1330
1351
  test('projette la conso EP 2027 pour une maison', () => {
1331
1352
  vi.mocked(classe_bilan_dpe).mockReturnValue('C');
@@ -1,12 +1,9 @@
1
- import { DE } from './dpe.model';
1
+ // Alias des types générés depuis le XSD DPE (voir dpe-xsd.generated.ts). Les extensions propres
2
+ // à Open3CL se déclarent ici (hors fichier généré) pour survivre à la régénération.
3
+ import type {
4
+ XsdLogementEnveloppeEtsBaieEts,
5
+ XsdLogementEnveloppeEtsBaieEtsDonneeEntree
6
+ } from './dpe-xsd.generated';
2
7
 
3
- export interface BaieEts {
4
- donnee_entree?: BaieEtsDE;
5
- }
6
-
7
- export interface BaieEtsDE extends DE {
8
- enum_orientation_id?: number;
9
- enum_inclinaison_vitrage_id?: number; // ENUM inclinaison_vitrage
10
- surface_totale_baie?: number;
11
- nb_baie?: number;
12
- }
8
+ export type BaieEts = XsdLogementEnveloppeEtsBaieEts;
9
+ export type BaieEtsDE = XsdLogementEnveloppeEtsBaieEtsDonneeEntree;
@@ -1,97 +1,25 @@
1
- import { DE } from './dpe.model';
1
+ // Alias des types générés depuis le XSD DPE (voir dpe-xsd.generated.ts). Les extensions propres
2
+ // à Open3CL se déclarent ici (hors fichier généré) pour survivre à la régénération.
3
+ import type {
4
+ XsdLogementEnveloppeBaieVitree,
5
+ XsdLogementEnveloppeBaieVitreeBaieVitreeDoubleFenetre,
6
+ XsdLogementEnveloppeBaieVitreeBaieVitreeDoubleFenetreDonneeEntree,
7
+ XsdLogementEnveloppeBaieVitreeBaieVitreeDoubleFenetreDonneeIntermediaire,
8
+ XsdLogementEnveloppeBaieVitreeDonneeEntree,
9
+ XsdLogementEnveloppeBaieVitreeDonneeEntreeMasqueLointainNonHomogene,
10
+ XsdLogementEnveloppeBaieVitreeDonneeIntermediaire
11
+ } from './dpe-xsd.generated';
2
12
 
3
- export interface BaieVitree {
4
- donnee_entree?: BaieVitreeDE;
5
- donnee_intermediaire?: BaieVitreeDI;
6
- baie_vitree_double_fenetre?: BaieVitreeDoubleFenetre;
7
- }
8
-
9
- export interface BaieVitreeDE extends DE {
10
- reference_paroi?: string;
11
- reference_lnc?: string;
12
- tv_coef_reduction_deperdition_id?: string; // TV
13
- surface_aiu?: number;
14
- surface_aue?: number;
15
- enum_cfg_isolation_lnc_id?: string; // ENUM cfg_isolation_lnc
16
- enum_type_adjacence_id?: string; // ENUM type_adjacence
17
- surface_totale_baie?: number;
18
- nb_baie?: number;
19
- tv_ug_id?: string; // TV
20
- enum_type_vitrage_id?: string; // ENUM type_vitrage
21
- enum_inclinaison_vitrage_id?: string; // ENUM inclinaison_vitrage
22
- enum_type_gaz_lame_id?: string; // ENUM type_gaz_lame
23
- epaisseur_lame?: number;
24
- vitrage_vir?: boolean;
25
- enum_methode_saisie_perf_vitrage_id?: string; // ENUM methode_saisie_perf_vitrage
26
- ug_saisi?: number;
27
- tv_uw_id?: string;
28
- enum_type_materiaux_menuiserie_id?: string; // ENUM type_materiaux_menuiserie
29
- enum_type_baie_id?: string; // ENUM type_baie
30
- uw_saisi?: number;
31
- double_fenetre?: number;
32
- uw_1?: number;
33
- sw_1?: number;
34
- uw_2?: number;
35
- sw_2?: number;
36
- tv_deltar_id?: string;
37
- tv_ujn_id?: string;
38
- enum_type_fermeture_id?: string;
39
- presence_protection_solaire_hors_fermeture?: boolean;
40
- ujn_saisi?: number;
41
- presence_retour_isolation?: boolean;
42
- presence_joint?: boolean;
43
- largeur_dormant?: number;
44
- tv_sw_id?: string;
45
- sw_saisi?: number;
46
- enum_type_pose_id?: string; // ENUM type_pose
47
- enum_orientation_id?: string;
48
- tv_coef_masque_proche_id?: number;
49
- tv_coef_masque_lointain_homogene_id?: number;
50
- masque_lointain_non_homogene_collection: {
51
- masque_lointain_non_homogene: MasqueLointainNonHomogene;
52
- }[];
53
- }
54
-
55
- export interface BaieVitreeDI {
56
- b: number;
57
- ug?: number;
58
- uw: number;
59
- ujn?: number;
60
- u_menuiserie: number;
61
- sw: number;
62
- fe1: number;
63
- fe2: number;
64
- }
65
-
66
- export interface BaieVitreeDoubleFenetre {
67
- donnee_entree?: BaieVitreeDoubleFenetreDE;
68
- donnee_intermediaire?: BaieVitreeDoubleFenetreDI;
69
- }
70
-
71
- export interface BaieVitreeDoubleFenetreDE {
72
- tv_ug_id?: string;
73
- enum_type_vitrage_id: string;
74
- enum_inclinaison_vitrage_id: string;
75
- enum_type_gaz_lame_id?: string;
76
- epaisseur_lame?: number;
77
- vitrage_vir?: boolean;
78
- enum_methode_saisie_perf_vitrage_id: string;
79
- ug_saisi?: number;
80
- tv_uw_id?: string;
81
- enum_type_materiaux_menuiserie_id: string;
82
- enum_type_baie_id: string;
83
- uw_saisi?: number;
84
- tv_sw_id?: string;
85
- sw_saisi?: number;
86
- enum_type_pose_id: string;
87
- }
88
-
89
- export interface BaieVitreeDoubleFenetreDI {
90
- ug?: number;
91
- uw: number;
92
- sw: number;
93
- }
94
-
95
- export interface MasqueLointainNonHomogene {
96
- tv_coef_masque_lointain_non_homogene_id?: string;
97
- }
13
+ /** + `donnee_utilisateur` Open3CL hors XSD. */
14
+ export type BaieVitree = XsdLogementEnveloppeBaieVitree & {
15
+ donnee_utilisateur?: Record<string, any>;
16
+ };
17
+ export type BaieVitreeDE = XsdLogementEnveloppeBaieVitreeDonneeEntree;
18
+ export type BaieVitreeDI = XsdLogementEnveloppeBaieVitreeDonneeIntermediaire;
19
+ export type BaieVitreeDoubleFenetre = XsdLogementEnveloppeBaieVitreeBaieVitreeDoubleFenetre;
20
+ export type BaieVitreeDoubleFenetreDE =
21
+ XsdLogementEnveloppeBaieVitreeBaieVitreeDoubleFenetreDonneeEntree;
22
+ export type BaieVitreeDoubleFenetreDI =
23
+ XsdLogementEnveloppeBaieVitreeBaieVitreeDoubleFenetreDonneeIntermediaire;
24
+ export type MasqueLointainNonHomogene =
25
+ XsdLogementEnveloppeBaieVitreeDonneeEntreeMasqueLointainNonHomogene;
@@ -1,26 +1,16 @@
1
- import { DE } from './dpe.model';
1
+ // Alias des types générés depuis le XSD DPE (voir dpe-xsd.generated.ts). Les extensions propres
2
+ // à Open3CL se déclarent ici (hors fichier généré) pour survivre à la régénération.
3
+ import type {
4
+ XsdLogementClimatisation,
5
+ XsdLogementClimatisationDonneeEntree,
6
+ XsdLogementClimatisationDonneeIntermediaire
7
+ } from './dpe-xsd.generated';
2
8
 
3
- export interface Climatisation {
4
- donnee_entree?: ClimatisationDE;
9
+ export interface Climatisation extends Omit<XsdLogementClimatisation, 'donnee_intermediaire'> {
5
10
  donnee_intermediaire?: ClimatisationDI;
6
11
  }
7
-
8
- export interface ClimatisationDE extends DE {
9
- tv_seer_id?: number;
10
- nombre_logement_echantillon?: number;
11
- surface_clim?: number;
12
- enum_methode_calcul_conso_id: number;
13
- enum_periode_installation_fr_id: number;
14
- cle_repartition_clim?: number;
15
- enum_type_generateur_fr_id: number;
16
- enum_type_energie_id?: number;
17
- enum_methode_saisie_carac_sys_id: number;
18
- ref_produit_fr?: string;
19
- }
20
-
21
- export interface ClimatisationDI {
22
- eer: number;
23
- besoin_fr: number;
24
- conso_fr: number;
25
- conso_fr_depensier: number;
26
- }
12
+ export type ClimatisationDE = XsdLogementClimatisationDonneeEntree;
13
+ /** + champ calculé Open3CL hors XSD. */
14
+ export type ClimatisationDI = XsdLogementClimatisationDonneeIntermediaire & {
15
+ besoin_fr_depensier?: number;
16
+ };