@open3cl/engine 1.0.9 → 1.0.10

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.
Files changed (28) hide show
  1. package/features/dpe/domain/models/type-habitation.model.js +8 -0
  2. package/features/dpe/infrastructure/baieVitreeTv.store.js +70 -0
  3. package/features/dpe/infrastructure/baieVitreeTv.store.spec.js +106 -0
  4. package/features/engine/domain/contexte.builder.js +59 -63
  5. package/features/engine/domain/contexte.builder.spec.js +41 -62
  6. package/features/engine/domain/engine.service.js +18 -1
  7. package/features/engine/domain/enveloppe/baie_vitree/deperdition-baie-vitree.service.js +1 -1
  8. package/features/engine/domain/enveloppe/deperdition-enveloppe.service.js +19 -0
  9. package/features/engine/domain/enveloppe/deperdition-enveloppe.service.spec.js +3 -3
  10. package/features/engine/domain/enveloppe/deperdition.service.js +2 -3
  11. package/features/engine/domain/enveloppe/espace_tampon/espace-tampon.service.js +44 -0
  12. package/features/engine/domain/enveloppe/espace_tampon/espace-tampon.service.spec.js +81 -0
  13. package/features/engine/domain/enveloppe/mur/deperdition-mur.service.js +3 -3
  14. package/features/engine/domain/enveloppe/mur/deperdition-mur.service.spec.js +30 -10
  15. package/features/engine/domain/enveloppe/plancher_bas/deperdition-plancher-bas.service.js +2 -2
  16. package/features/engine/domain/enveloppe/plancher_bas/deperdition-plancher-bas.service.spec.js +18 -6
  17. package/features/engine/domain/enveloppe/plancher_haut/deperdition-plancher-haut.service.js +2 -2
  18. package/features/engine/domain/enveloppe/plancher_haut/deperdition-plancher-haut.service.spec.js +21 -7
  19. package/features/engine/domain/enveloppe/porte/deperdition-porte.service.js +1 -1
  20. package/features/engine/domain/enveloppe/porte/deperdition-porte.service.spec.js +2 -2
  21. package/features/engine/domain/enveloppe/ventilation/deperdition-ventilation.service.js +1 -1
  22. package/features/engine/domain/logement/nadeq.service.js +62 -0
  23. package/features/engine/domain/logement/nadeq.service.spec.js +71 -0
  24. package/features/engine/domain/logement/surface-sud-equivalente.service.js +169 -0
  25. package/features/engine/domain/logement/surface-sud-equivalente.service.spec.js +210 -0
  26. package/features/engine/domain/models/contexte.model.ts +10 -5
  27. package/features/engine/domain/models/deperdition.model.ts +1 -1
  28. package/package.json +1 -1
@@ -6,3 +6,11 @@ export const TypeHabitation = {
6
6
  APPARTEMENT: 'APPARTEMENT',
7
7
  IMMEUBLE: 'IMMEUBLE'
8
8
  };
9
+ /**
10
+ * @type {{[key: string]: string}}
11
+ */
12
+ export const TypeDpe = {
13
+ MAISON: 'MAISON',
14
+ APPARTEMENT: 'APPARTEMENT',
15
+ IMMEUBLE: 'IMMEUBLE'
16
+ };
@@ -2,6 +2,7 @@ import { tvs as tv } from '../../../tv-v2.js';
2
2
  import { getRange } from '../../../utils.js';
3
3
  import { logger } from '../../../core/util/logger/log-service.js';
4
4
  import { TvStore } from './tv.store.js';
5
+ import enums from '../../../enums.js';
5
6
 
6
7
  /**
7
8
  * Accès aux données des tables de valeurs pour les baies vitrées
@@ -289,4 +290,73 @@ export class BaieVitreeTvStore extends TvStore {
289
290
 
290
291
  return parseFloat(fe2);
291
292
  }
293
+
294
+ /**
295
+ * Calcul des coefficients de réduction de température des espaces tampons
296
+ *
297
+ * @param zoneClimatique {string}
298
+ * @param enumCfgIsolationLncId {number}
299
+ * @return {number|undefined}
300
+ */
301
+ getBver(zoneClimatique, enumCfgIsolationLncId) {
302
+ const bver = tv['coef_reduction_deperdition'].find(
303
+ (v) =>
304
+ zoneClimatique.toLowerCase().startsWith(v.zone_climatique?.toLowerCase()) &&
305
+ parseInt(v.enum_cfg_isolation_lnc_id) === parseInt(enumCfgIsolationLncId)
306
+ )?.b;
307
+
308
+ if (!bver) {
309
+ logger.error(
310
+ `Pas de valeur b pour zoneClimatique:${zoneClimatique}, enumCfgIsolationLncId:${enumCfgIsolationLncId}`
311
+ );
312
+ return;
313
+ }
314
+
315
+ return parseFloat(bver);
316
+ }
317
+
318
+ /**
319
+ * Calcul des coefficients de transparence des espaces tampons
320
+ *
321
+ * @param tvCoefTransparenceEtsId {number}
322
+ * @return {number|undefined}
323
+ */
324
+ getCoefTransparenceEts(tvCoefTransparenceEtsId) {
325
+ const coefTransparence = tv['coef_transparence_ets'].find(
326
+ (v) => parseInt(v.tv_coef_transparence_ets_id) === parseInt(tvCoefTransparenceEtsId)
327
+ )?.coef_transparence_ets;
328
+
329
+ if (!coefTransparence) {
330
+ logger.error(
331
+ `Pas de valeur coef_transparence_ets pour tvCoefTransparenceEtsId:${tvCoefTransparenceEtsId}`
332
+ );
333
+ return;
334
+ }
335
+
336
+ return parseFloat(coefTransparence);
337
+ }
338
+
339
+ /**
340
+ * @see 18.5 - Coefficients d’orientation et d’inclinaison des parois vitrées : C1
341
+ *
342
+ * @param enumOrientationId {number}
343
+ * @param enumInclinaisonVitrageId {number}
344
+ * @param zoneClimatiqueId {number}
345
+ * @param mois {string}
346
+ *
347
+ * @return {number|undefined}
348
+ */
349
+ getCoefficientBaieVitree(enumOrientationId, enumInclinaisonVitrageId, zoneClimatiqueId, mois) {
350
+ const orientation = enums.orientation[enumOrientationId];
351
+ const inclinaison = enums.inclinaison_vitrage[enumInclinaisonVitrageId];
352
+ const zoneClimatique = enums.zone_climatique[zoneClimatiqueId];
353
+
354
+ const c1ZoneClimatique = tv['c1'][zoneClimatique][mois];
355
+
356
+ if (inclinaison === 'horizontal') {
357
+ return c1ZoneClimatique[inclinaison];
358
+ }
359
+
360
+ return c1ZoneClimatique[`${orientation} ${inclinaison}`];
361
+ }
292
362
  }
@@ -345,6 +345,112 @@ describe('Lecture des tables de valeurs', () => {
345
345
  });
346
346
  });
347
347
 
348
+ describe('lecture des valeurs coefficients de réduction de température des espaces tampons', () => {
349
+ test.each([
350
+ {
351
+ label: 'lc non isolé + espace tampon solarisé orienté nord',
352
+ zoneClimatique: 'H1a',
353
+ enumCfgIsolationLncId: '9',
354
+ expected: 0.85
355
+ },
356
+ {
357
+ label: 'lc isolé + espace tampon solarisé orienté sud',
358
+ zoneClimatique: 'H2C',
359
+ enumCfgIsolationLncId: '7',
360
+ expected: 0.57
361
+ }
362
+ ])(
363
+ `incidence masque proche pour baie vitrée $label`,
364
+ ({ zoneClimatique, enumCfgIsolationLncId, expected }) => {
365
+ expect(tvStore.getBver(zoneClimatique, enumCfgIsolationLncId)).toBe(expected);
366
+ }
367
+ );
368
+
369
+ test('pas de valeur de coefficients de réduction de température', () => {
370
+ const ug = tvStore.getBver('h3C', 1);
371
+ expect(ug).toBeUndefined();
372
+ });
373
+ });
374
+
375
+ describe('lecture des valeurs de coefficients de transparence des espaces tampons', () => {
376
+ test.each([
377
+ {
378
+ label: 'Parois en polycarbonate',
379
+ tvCoefTransparenceEtsId: '9',
380
+ expected: 0.39
381
+ },
382
+ {
383
+ label: 'Parois triple vitrage en Bois / Bois-métal',
384
+ tvCoefTransparenceEtsId: '5',
385
+ expected: 0.49
386
+ }
387
+ ])(
388
+ `incidence masque proche pour baie vitrée $label`,
389
+ ({ tvCoefTransparenceEtsId, expected }) => {
390
+ expect(tvStore.getCoefTransparenceEts(tvCoefTransparenceEtsId)).toBe(expected);
391
+ }
392
+ );
393
+
394
+ test('pas de valeur de coefficients de transparence', () => {
395
+ const ug = tvStore.getCoefTransparenceEts(0);
396
+ expect(ug).toBeUndefined();
397
+ });
398
+ });
399
+
400
+ describe("lecture des coefficients d'orientation et inclinaison des parois vitrées", () => {
401
+ test.each([
402
+ {
403
+ label: 'Baie vitrée orientée nord, inclinaison inf25°',
404
+ enumOrientationId: '2',
405
+ enumInclinaisonVitrageId: '1',
406
+ zoneClimatiqueId: '1',
407
+ mois: 'Janvier',
408
+ expected: 0.52
409
+ },
410
+ {
411
+ label: 'Baie vitrée orientée nord, inclinaison inf25°',
412
+ enumOrientationId: '2',
413
+ enumInclinaisonVitrageId: '1',
414
+ zoneClimatiqueId: '1',
415
+ mois: 'Juillet',
416
+ expected: 1.98
417
+ },
418
+ {
419
+ label: 'Baie vitrée orientée sud, inclinaison sup75°',
420
+ enumOrientationId: '1',
421
+ enumInclinaisonVitrageId: '3',
422
+ zoneClimatiqueId: '2',
423
+ mois: 'Janvier',
424
+ expected: 1
425
+ },
426
+ {
427
+ label: 'Baie vitrée orientée sud, inclinaison horizontale',
428
+ enumOrientationId: '1',
429
+ enumInclinaisonVitrageId: '4',
430
+ zoneClimatiqueId: '2',
431
+ mois: 'Janvier',
432
+ expected: 0.58
433
+ }
434
+ ])(
435
+ `coefficient pour $label`,
436
+ ({ enumOrientationId, enumInclinaisonVitrageId, zoneClimatiqueId, mois, expected }) => {
437
+ expect(
438
+ tvStore.getCoefficientBaieVitree(
439
+ enumOrientationId,
440
+ enumInclinaisonVitrageId,
441
+ zoneClimatiqueId,
442
+ mois
443
+ )
444
+ ).toMatchObject(expected);
445
+ }
446
+ );
447
+ });
448
+
449
+ test('lecture des épaisseurs disponibles pour les coefficients de transmission thermique ug', () => {
450
+ const ug = tvStore.getEpaisseurAvailableForUg();
451
+ expect(ug).toStrictEqual([0, 6, 8, 10, 12, 14, 15, 16, 18, 20]);
452
+ });
453
+
348
454
  test('lecture des épaisseurs disponibles pour les coefficients de transmission thermique ug', () => {
349
455
  const ug = tvStore.getEpaisseurAvailableForUg();
350
456
  expect(ug).toStrictEqual([0, 6, 8, 10, 12, 14, 15, 16, 18, 20]);
@@ -1,4 +1,5 @@
1
- import { TypeHabitation } from '../../dpe/domain/models/type-habitation.model.js';
1
+ import { TypeDpe, TypeHabitation } from '../../dpe/domain/models/type-habitation.model.js';
2
+ import enums from '../../../enums.js';
2
3
 
3
4
  /**
4
5
  * Génère un contexte du logement à étudier avec des données persistées durant l'analyse
@@ -11,14 +12,30 @@ export class ContexteBuilder {
11
12
  * @return {Contexte}
12
13
  */
13
14
  fromDpe(dpe) {
15
+ const caracteristiqueGenerale = dpe.logement.caracteristique_generale;
16
+
14
17
  return {
15
- zoneClimatiqueId: dpe.logement.meteo?.enum_zone_climatique_id.toString(),
16
- typeHabitation: this.#getTypeHabitation(dpe),
17
- enumPeriodeConstructionId:
18
- dpe.logement.caracteristique_generale.enum_periode_construction_id?.toString(),
18
+ zoneClimatique: this.#zoneClimatique(dpe),
19
+ typeHabitation: this.#getTypeHabitation(caracteristiqueGenerale),
20
+ typeDpe: this.#getTypeDpe(caracteristiqueGenerale),
21
+ enumPeriodeConstructionId: caracteristiqueGenerale.enum_periode_construction_id?.toString(),
19
22
  effetJoule: this.#hasEffetJoule(dpe),
20
- surfaceHabitable: this.#getSurfaceHabitable(dpe),
21
- hauteurSousPlafond: dpe.logement.caracteristique_generale.hsp
23
+ surfaceHabitable: this.#getSurfaceHabitable(caracteristiqueGenerale),
24
+ hauteurSousPlafond: caracteristiqueGenerale.hsp,
25
+ nombreAppartement: caracteristiqueGenerale.nombre_appartement
26
+ };
27
+ }
28
+
29
+ /**
30
+ * La zone climatique à partir du type de DPE
31
+ * @param dpe {Dpe}
32
+ * @return {{id: number, value: string}}
33
+ */
34
+ #zoneClimatique(dpe) {
35
+ const zoneClimatiqueId = parseInt(dpe.logement.meteo?.enum_zone_climatique_id);
36
+ return {
37
+ id: zoneClimatiqueId.toString(),
38
+ value: enums.zone_climatique[zoneClimatiqueId]
22
39
  };
23
40
  }
24
41
 
@@ -39,43 +56,20 @@ export class ContexteBuilder {
39
56
 
40
57
  /**
41
58
  * Le type d'habitation est détecté à partir du type de DPE
42
- * @param dpe {Dpe}
59
+ * @param caracteristiqueGenerale {CaracteristiqueGenerale}
43
60
  * @return {TypeHabitation}
44
61
  */
45
- #getTypeHabitation(dpe) {
46
- const methodeApplication =
47
- dpe.logement.caracteristique_generale.enum_methode_application_dpe_log_id;
62
+ #getTypeHabitation(caracteristiqueGenerale) {
63
+ const methodeApplication = parseInt(
64
+ caracteristiqueGenerale.enum_methode_application_dpe_log_id
65
+ );
48
66
 
49
- if (['1', '14', '18'].includes(methodeApplication)) {
67
+ if ([1, 14, 18].includes(methodeApplication)) {
50
68
  return TypeHabitation.MAISON;
51
69
  } else if (
52
70
  [
53
- '2',
54
- '3',
55
- '4',
56
- '5',
57
- '10',
58
- '11',
59
- '12',
60
- '13',
61
- '15',
62
- '16',
63
- '19',
64
- '20',
65
- '22',
66
- '23',
67
- '24',
68
- '25',
69
- '31',
70
- '32',
71
- '33',
72
- '34',
73
- '35',
74
- '36',
75
- '37',
76
- '38',
77
- '39',
78
- '40'
71
+ 2, 3, 4, 5, 10, 11, 12, 13, 15, 16, 19, 20, 22, 23, 24, 25, 31, 32, 33, 34, 35, 36, 37, 38,
72
+ 39, 40
79
73
  ].includes(methodeApplication)
80
74
  ) {
81
75
  return TypeHabitation.APPARTEMENT;
@@ -84,10 +78,28 @@ export class ContexteBuilder {
84
78
  }
85
79
 
86
80
  /**
87
- * @param dpe {Dpe}
81
+ * Le type de DPE est détecté à partir du type de DPE
82
+ * @param caracteristiqueGenerale {CaracteristiqueGenerale}
83
+ * @return {TypeDpe}
84
+ */
85
+ #getTypeDpe(caracteristiqueGenerale) {
86
+ const methodeApplication = parseInt(
87
+ caracteristiqueGenerale.enum_methode_application_dpe_log_id
88
+ );
89
+
90
+ if ([1, 14, 18].includes(methodeApplication)) {
91
+ return TypeDpe.MAISON;
92
+ } else if ([2, 3, 4, 5, 31, 32, 35, 36, 37].includes(methodeApplication)) {
93
+ return TypeDpe.APPARTEMENT;
94
+ }
95
+ return TypeDpe.IMMEUBLE;
96
+ }
97
+
98
+ /**
99
+ * @param caracteristiqueGenerale {CaracteristiqueGenerale}
88
100
  * @return {number}
89
101
  */
90
- #getSurfaceHabitable(dpe) {
102
+ #getSurfaceHabitable(caracteristiqueGenerale) {
91
103
  /**
92
104
  * Certains DPE appartement sont générés à partir des données du DPE immeuble, la surface à prendre en compte est
93
105
  * celle de l'immeuble pour les besoins ECS
@@ -110,31 +122,15 @@ export class ContexteBuilder {
110
122
  * 40 - dpe appartement généré à partir des données DPE immeuble chauffage collectif ecs mixte (collectif-individuel)
111
123
  */
112
124
  if (
113
- [
114
- '10',
115
- '11',
116
- '12',
117
- '13',
118
- '15',
119
- '16',
120
- '19',
121
- '20',
122
- '22',
123
- '23',
124
- '24',
125
- '25',
126
- '33',
127
- '34',
128
- '38',
129
- '39',
130
- '40'
131
- ].includes(dpe.logement.caracteristique_generale.enum_methode_application_dpe_log_id)
125
+ [10, 11, 12, 13, 15, 16, 19, 20, 22, 23, 24, 25, 33, 34, 38, 39, 40].includes(
126
+ parseInt(caracteristiqueGenerale.enum_methode_application_dpe_log_id)
127
+ )
132
128
  ) {
133
- return dpe.logement.caracteristique_generale.surface_habitable_immeuble;
129
+ return caracteristiqueGenerale.surface_habitable_immeuble;
134
130
  }
135
131
 
136
- return this.#getTypeHabitation(dpe) === TypeHabitation.IMMEUBLE
137
- ? dpe.logement.caracteristique_generale.surface_habitable_immeuble
138
- : dpe.logement.caracteristique_generale.surface_habitable_logement;
132
+ return this.#getTypeHabitation(caracteristiqueGenerale) === TypeHabitation.IMMEUBLE
133
+ ? caracteristiqueGenerale.surface_habitable_immeuble
134
+ : caracteristiqueGenerale.surface_habitable_logement;
139
135
  }
140
136
  }
@@ -1,5 +1,6 @@
1
1
  import { ContexteBuilder } from './contexte.builder.js';
2
2
  import { beforeEach, describe, expect, test } from 'vitest';
3
+ import { TypeDpe, TypeHabitation } from '../../dpe/domain/models/type-habitation.model.js';
3
4
 
4
5
  /** @type {ContexteBuilder} **/
5
6
  let contexteBuilder;
@@ -12,13 +13,7 @@ describe('Generateur du contexte du calcul', () => {
12
13
  test('Contexte avec effet joule', () => {
13
14
  const dpe = {
14
15
  logement: {
15
- meteo: { enum_zone_climatique_id: 1 },
16
- caracteristique_generale: {
17
- enum_periode_construction_id: 1,
18
- surface_habitable_logement: 48.9,
19
- surface_habitable_immeuble: 105,
20
- hsp: 2.8
21
- },
16
+ caracteristique_generale: {},
22
17
  installation_chauffage_collection: {
23
18
  installation_chauffage: [
24
19
  {
@@ -31,26 +26,15 @@ describe('Generateur du contexte du calcul', () => {
31
26
  }
32
27
  };
33
28
 
34
- expect(contexteBuilder.fromDpe(dpe)).toStrictEqual({
35
- effetJoule: true,
36
- enumPeriodeConstructionId: '1',
37
- zoneClimatiqueId: '1',
38
- hauteurSousPlafond: 2.8,
39
- surfaceHabitable: 105,
40
- typeHabitation: 'IMMEUBLE'
29
+ expect(contexteBuilder.fromDpe(dpe)).toMatchObject({
30
+ effetJoule: true
41
31
  });
42
32
  });
43
33
 
44
34
  test('Contexte sans effet joule', () => {
45
35
  const dpe = {
46
36
  logement: {
47
- meteo: { enum_zone_climatique_id: 1 },
48
- caracteristique_generale: {
49
- enum_periode_construction_id: 1,
50
- surface_habitable_logement: 48.9,
51
- surface_habitable_immeuble: 105,
52
- hsp: 2.8
53
- },
37
+ caracteristique_generale: {},
54
38
  installation_chauffage_collection: {
55
39
  installation_chauffage: [
56
40
  {
@@ -65,88 +49,83 @@ describe('Generateur du contexte du calcul', () => {
65
49
  }
66
50
  };
67
51
 
68
- expect(contexteBuilder.fromDpe(dpe)).toStrictEqual({
69
- effetJoule: false,
70
- enumPeriodeConstructionId: '1',
71
- zoneClimatiqueId: '1',
72
- hauteurSousPlafond: 2.8,
73
- surfaceHabitable: 105,
74
- typeHabitation: 'IMMEUBLE'
52
+ expect(contexteBuilder.fromDpe(dpe)).toMatchObject({
53
+ effetJoule: false
75
54
  });
76
55
  });
77
56
 
78
57
  test('Contexte sans chauffage', () => {
79
58
  const dpe = {
80
59
  logement: {
81
- meteo: { enum_zone_climatique_id: 1 },
82
- caracteristique_generale: {
83
- enum_periode_construction_id: 1,
84
- surface_habitable_logement: 48.9,
85
- surface_habitable_immeuble: 105,
86
- hsp: 2.8
87
- }
60
+ caracteristique_generale: {}
88
61
  }
89
62
  };
90
63
 
91
- expect(contexteBuilder.fromDpe(dpe)).toStrictEqual({
92
- effetJoule: false,
93
- enumPeriodeConstructionId: '1',
94
- zoneClimatiqueId: '1',
95
- hauteurSousPlafond: 2.8,
96
- surfaceHabitable: 105,
97
- typeHabitation: 'IMMEUBLE'
64
+ expect(contexteBuilder.fromDpe(dpe)).toMatchObject({
65
+ effetJoule: false
98
66
  });
99
67
  });
100
68
 
101
69
  test('Contexte sans emetteur de chauffage', () => {
102
70
  const dpe = {
103
71
  logement: {
104
- meteo: { enum_zone_climatique_id: 1 },
105
- caracteristique_generale: {
106
- enum_periode_construction_id: 1,
107
- surface_habitable_logement: 48.9,
108
- surface_habitable_immeuble: 105,
109
- hsp: 2.8
110
- },
72
+ caracteristique_generale: {},
111
73
  installation_chauffage_collection: {}
112
74
  }
113
75
  };
114
76
 
115
- expect(contexteBuilder.fromDpe(dpe)).toStrictEqual({
116
- effetJoule: false,
117
- enumPeriodeConstructionId: '1',
118
- zoneClimatiqueId: '1',
119
- hauteurSousPlafond: 2.8,
120
- surfaceHabitable: 105,
121
- typeHabitation: 'IMMEUBLE'
77
+ expect(contexteBuilder.fromDpe(dpe)).toMatchObject({
78
+ effetJoule: false
122
79
  });
123
80
  });
124
81
 
125
- test('Récupération de la surface habitable du logement concerné par le DPE', () => {
82
+ test('Récupération des informations du logement concerné par le DPE', () => {
126
83
  let dpe = {
127
84
  logement: {
85
+ meteo: {
86
+ enum_zone_climatique_id: 1
87
+ },
128
88
  caracteristique_generale: {
129
- enum_periode_construction_id: 1,
89
+ enum_periode_construction_id: 4,
130
90
  surface_habitable_logement: 48.9,
131
91
  surface_habitable_immeuble: 105,
132
- hsp: 2.8
92
+ hsp: 2.8,
93
+ nombre_appartement: 18
133
94
  }
134
95
  }
135
96
  };
136
97
 
137
98
  dpe.logement.caracteristique_generale.enum_methode_application_dpe_log_id = '1';
138
99
  expect(contexteBuilder.fromDpe(dpe)).toMatchObject({
139
- surfaceHabitable: dpe.logement.caracteristique_generale.surface_habitable_logement
100
+ surfaceHabitable: dpe.logement.caracteristique_generale.surface_habitable_logement,
101
+ typeHabitation: TypeHabitation.MAISON,
102
+ typeDpe: TypeDpe.MAISON,
103
+ enumPeriodeConstructionId: '4',
104
+ hauteurSousPlafond: 2.8,
105
+ nombreAppartement: 18,
106
+ zoneClimatique: {
107
+ id: '1',
108
+ value: 'h1a'
109
+ }
140
110
  });
141
111
 
142
112
  dpe.logement.caracteristique_generale.enum_methode_application_dpe_log_id = '5';
113
+ dpe.logement.meteo.enum_zone_climatique_id = '4';
143
114
  expect(contexteBuilder.fromDpe(dpe)).toMatchObject({
144
- surfaceHabitable: dpe.logement.caracteristique_generale.surface_habitable_logement
115
+ surfaceHabitable: dpe.logement.caracteristique_generale.surface_habitable_logement,
116
+ typeHabitation: TypeHabitation.APPARTEMENT,
117
+ typeDpe: TypeDpe.APPARTEMENT,
118
+ zoneClimatique: {
119
+ id: '4',
120
+ value: 'h2a'
121
+ }
145
122
  });
146
123
 
147
124
  dpe.logement.caracteristique_generale.enum_methode_application_dpe_log_id = '8';
148
125
  expect(contexteBuilder.fromDpe(dpe)).toMatchObject({
149
- surfaceHabitable: dpe.logement.caracteristique_generale.surface_habitable_immeuble
126
+ surfaceHabitable: dpe.logement.caracteristique_generale.surface_habitable_immeuble,
127
+ typeHabitation: TypeHabitation.IMMEUBLE,
128
+ typeDpe: TypeDpe.IMMEUBLE
150
129
  });
151
130
  });
152
131
  });
@@ -2,12 +2,19 @@ import { inject } from 'dioma';
2
2
  import { ContexteBuilder } from './contexte.builder.js';
3
3
  import { DeperditionEnveloppeService } from './enveloppe/deperdition-enveloppe.service.js';
4
4
  import { logger } from '../../../core/util/logger/log-service.js';
5
+ import { SurfaceSudEquivalenteService } from './logement/surface-sud-equivalente.service.js';
5
6
 
6
7
  export class EngineService {
7
8
  /**
8
9
  * @type {DeperditionEnveloppeService}
9
10
  */
10
11
  #deperditionService;
12
+
13
+ /**
14
+ * @type {SurfaceSudEquivalenteService}
15
+ */
16
+ #surfaceSudEquivalenteService;
17
+
11
18
  /**
12
19
  * @type {ContexteBuilder}
13
20
  */
@@ -15,13 +22,16 @@ export class EngineService {
15
22
 
16
23
  /**
17
24
  * @param deperditionService {DeperditionEnveloppeService}
25
+ * @param surfaceSudEquivalenteService {SurfaceSudEquivalenteService}
18
26
  * @param contextBuilder {ContexteBuilder}
19
27
  */
20
28
  constructor(
21
29
  deperditionService = inject(DeperditionEnveloppeService),
30
+ surfaceSudEquivalenteService = inject(SurfaceSudEquivalenteService),
22
31
  contextBuilder = inject(ContexteBuilder)
23
32
  ) {
24
33
  this.#deperditionService = deperditionService;
34
+ this.#surfaceSudEquivalenteService = surfaceSudEquivalenteService;
25
35
  this.#contextBuilder = contextBuilder;
26
36
  }
27
37
 
@@ -55,9 +65,16 @@ export class EngineService {
55
65
  // Calcul des déperditions
56
66
  proceededDpe.logement.sortie.deperdition = this.#deperditionService.deperditions(
57
67
  ctx,
58
- dpe.logement
68
+ proceededDpe.logement
59
69
  );
60
70
 
71
+ proceededDpe.logement.sortie.apport_et_besoin = {
72
+ surface_sud_equivalente: this.#surfaceSudEquivalenteService.execute(
73
+ ctx,
74
+ proceededDpe.logement.enveloppe
75
+ )
76
+ };
77
+
61
78
  // Calcul des déperditions par renouvellement de l'air
62
79
 
63
80
  // Calcul de l'intermittence
@@ -31,7 +31,7 @@ export class DeperditionBaieVitreeService extends DeperditionService {
31
31
  surfaceAiu: bvDE.surface_aiu,
32
32
  surfaceAue: bvDE.surface_aue,
33
33
  enumCfgIsolationLncId: bvDE.enum_cfg_isolation_lnc_id,
34
- zoneClimatiqueId: ctx.zoneClimatiqueId
34
+ zoneClimatique: ctx.zoneClimatique?.value
35
35
  });
36
36
 
37
37
  let sw = this.sw(bv);
@@ -6,6 +6,7 @@ import { DeperditionPlancherHautService } from './plancher_haut/deperdition-plan
6
6
  import { DeperditionVentilationService } from './ventilation/deperdition-ventilation.service.js';
7
7
  import { DeperditionBaieVitreeService } from './baie_vitree/deperdition-baie-vitree.service.js';
8
8
  import { DeperditionPontThermiqueService } from './pont_thermique/deperdition-pont-thermique.service.js';
9
+ import { EspaceTamponService } from './espace_tampon/espace-tampon.service.js';
9
10
 
10
11
  /**
11
12
  * Calcul des déperditions de l’enveloppe
@@ -37,6 +38,11 @@ export class DeperditionEnveloppeService {
37
38
  */
38
39
  #deperditionBaieVitreeService;
39
40
 
41
+ /**
42
+ * @type {EspaceTamponService}
43
+ */
44
+ #espaceTamponService;
45
+
40
46
  /**
41
47
  * @type {DeperditionPontThermiqueService}
42
48
  */
@@ -79,6 +85,7 @@ export class DeperditionEnveloppeService {
79
85
  * @param deperditionPlancherBasService {DeperditionPlancherBasService}
80
86
  * @param deperditionPlancherHautService {DeperditionPlancherHautService}
81
87
  * @param deperditionBaieVitreeService {DeperditionBaieVitreeService}
88
+ * @param espaceTamponService {EspaceTamponService}
82
89
  * @param deperditionPontThermiqueService {DeperditionPontThermiqueService}
83
90
  * @param deperditionVentilationService {DeperditionVentilationService}
84
91
  */
@@ -88,6 +95,7 @@ export class DeperditionEnveloppeService {
88
95
  deperditionPlancherBasService = inject(DeperditionPlancherBasService),
89
96
  deperditionPlancherHautService = inject(DeperditionPlancherHautService),
90
97
  deperditionBaieVitreeService = inject(DeperditionBaieVitreeService),
98
+ espaceTamponService = inject(EspaceTamponService),
91
99
  deperditionPontThermiqueService = inject(DeperditionPontThermiqueService),
92
100
  deperditionVentilationService = inject(DeperditionVentilationService)
93
101
  ) {
@@ -96,6 +104,7 @@ export class DeperditionEnveloppeService {
96
104
  this.#deperditionPlancherBasService = deperditionPlancherBasService;
97
105
  this.#deperditionPlancherHautService = deperditionPlancherHautService;
98
106
  this.#deperditionBaieVitreeService = deperditionBaieVitreeService;
107
+ this.#espaceTamponService = espaceTamponService;
99
108
  this.#deperditionPontThermiqueService = deperditionPontThermiqueService;
100
109
  this.#deperditionVentilationService = deperditionVentilationService;
101
110
  this.#surfaceDeperditive = 0;
@@ -249,6 +258,16 @@ export class DeperditionEnveloppeService {
249
258
  }
250
259
  });
251
260
 
261
+ let ets = enveloppe.ets_collection?.ets;
262
+ if (ets) {
263
+ // Certaines vérandas sont dupliqués dans les DPE.
264
+ if (Array.isArray(ets)) {
265
+ ets = ets[0];
266
+ }
267
+
268
+ ets.donnee_intermediaire = this.#espaceTamponService.execute(ctx, ets);
269
+ }
270
+
252
271
  enveloppe.pont_thermique_collection.pont_thermique?.forEach((pt) => {
253
272
  pt.donnee_intermediaire = this.#deperditionPontThermiqueService.execute(
254
273
  ctx,