@open3cl/engine 1.0.13 → 1.0.15

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 (30) hide show
  1. package/13.2_generateur_combustion_ch.js +1 -1
  2. package/features/dpe/domain/models/climatisation.model.ts +1 -0
  3. package/features/dpe/domain/models/installation-chauffage.model.ts +24 -0
  4. package/features/dpe/domain/models/type-generateur.model.js +8 -0
  5. package/features/dpe/infrastructure/ch/chTv.store.js +94 -0
  6. package/features/dpe/infrastructure/ch/chTv.store.spec.js +99 -0
  7. package/features/dpe/infrastructure/ecs/ecsTv.store.js +5 -3
  8. package/features/dpe/infrastructure/ecs/ecsTv.store.spec.js +4 -0
  9. package/features/dpe/infrastructure/froid/frTv.store.js +27 -0
  10. package/features/dpe/infrastructure/froid/frTv.store.spec.js +22 -0
  11. package/features/dpe/infrastructure/tv.store.js +28 -0
  12. package/features/dpe/infrastructure/tv.store.spec.js +12 -0
  13. package/features/engine/domain/apport_et_besoin/apport-et-besoin.service.js +14 -0
  14. package/features/engine/domain/apport_et_besoin/apport-et-besoin.service.spec.js +14 -0
  15. package/features/engine/domain/ch/emetteur-ch.service.js +100 -0
  16. package/features/engine/domain/ch/emetteur-ch.service.spec.js +78 -0
  17. package/features/engine/domain/ch/generateur-ch.service.js +365 -0
  18. package/features/engine/domain/ch/generateur-ch.service.spec.js +734 -0
  19. package/features/engine/domain/ch/installation-ch.service.js +39 -0
  20. package/features/engine/domain/ch/installation-ch.service.spec.js +41 -0
  21. package/features/engine/domain/conso/conso.service.js +26 -0
  22. package/features/engine/domain/conso/conso.service.spec.js +29 -0
  23. package/features/engine/domain/conso/froid/conso-froid.service.js +94 -0
  24. package/features/engine/domain/conso/froid/conso-froid.service.spec.js +152 -0
  25. package/features/engine/domain/contexte.builder.js +1 -0
  26. package/features/engine/domain/contexte.builder.spec.js +2 -0
  27. package/features/engine/domain/ecs/generateur-ecs.service.js +2 -2
  28. package/features/engine/domain/engine.service.js +10 -0
  29. package/features/engine/domain/models/contexte.model.ts +1 -0
  30. package/package.json +1 -1
@@ -37,7 +37,7 @@ export function tv_temp_fonc_30_100(di, de, du, em_ch, ac) {
37
37
  const em_ch_de = em.donnee_entree;
38
38
  const em_ch_du = em.donnee_utilisateur;
39
39
  const matcher = {
40
- type_generateur_ch_id: de.enum_type_generateur_ch_id,
40
+ enum_type_generateur_ch_id: de.enum_type_generateur_ch_id,
41
41
  enum_temp_distribution_ch_id: requestInputID(em_ch_de, em_ch_du, 'temp_distribution_ch'),
42
42
  periode_emetteurs: requestInput(em_ch_de, em_ch_du, 'periode_installation_emetteur')
43
43
  };
@@ -8,6 +8,7 @@ export interface Climatisation {
8
8
  export interface ClimatisationDE extends DE {
9
9
  tv_seer_id?: number;
10
10
  nombre_logement_echantillon?: number;
11
+ surface_clim?: number;
11
12
  enum_methode_calcul_conso_id: number;
12
13
  enum_periode_installation_fr_id: number;
13
14
  cle_repartition_clim?: number;
@@ -1,4 +1,5 @@
1
1
  import { DE } from './dpe.model';
2
+ import { GenerateurEcsDU } from './installation-ecs.model';
2
3
 
3
4
  export interface InstallationChauffage {
4
5
  donnee_entree?: InstallationChauffageDE;
@@ -62,6 +63,7 @@ export interface EmetteurChauffageDI {
62
63
 
63
64
  export interface GenerateurChauffage {
64
65
  donnee_entree?: GenerateurChauffageDE;
66
+ donnee_utilisateur?: GenerateurChauffageDU;
65
67
  donnee_intermediaire?: GenerateurChauffageDI;
66
68
  }
67
69
 
@@ -99,3 +101,25 @@ export interface GenerateurChauffageDI {
99
101
  conso_ch: number;
100
102
  conso_ch_depensier: number;
101
103
  }
104
+
105
+ export interface GenerateurChauffageDU {
106
+ ratio_virtualisation?: number;
107
+ typeGenerateur?: TypeGenerateur;
108
+ combustion: boolean;
109
+ pac: boolean;
110
+ generateur?: {
111
+ tv_generateur_combustion_id: string;
112
+ enum_type_generateur_ch_id: string;
113
+ type_generateur: string;
114
+ critere_pn: string;
115
+ pveil: string;
116
+ qp0_perc: string;
117
+ rpint: string;
118
+ rpn: string;
119
+ };
120
+ }
121
+
122
+ export enum TypeGenerateur {
123
+ CHAUDIERE = 'CHAUDIERE',
124
+ OTHER = 'OTHER'
125
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @type {{[key: string]: string}}
3
+ */
4
+ export const TypeGenerateur = {
5
+ COMBUSTION: 'COMBUSTION',
6
+ PAC: 'PAC',
7
+ OTHER: 'OTHER'
8
+ };
@@ -0,0 +1,94 @@
1
+ import { tvs as tv } from '../../../../tv-v2.js';
2
+ import { TvStore } from './../tv.store.js';
3
+ import { convertExpression } from '../../../../utils.js';
4
+ import enums from '../../../../enums.js';
5
+ import { logger } from '../../../../core/util/logger/log-service.js';
6
+
7
+ /**
8
+ * Accès aux données des tables de valeurs pour le chauffage
9
+ */
10
+ export class ChTvStore extends TvStore {
11
+ /**
12
+ * Récupération des ids des générateurs de chauffage à combustion
13
+ * @return {[number]}
14
+ */
15
+ getCombustionGenerateurs() {
16
+ return this.#getTypeGenerateurChId('generateur_combustion');
17
+ }
18
+ /**
19
+ * Récupération des ids des générateurs de chauffage pompes à chaleur
20
+ * @return {[number]}
21
+ */
22
+ getPacGenerateurs() {
23
+ return this.#getTypeGenerateurChId('scop');
24
+ }
25
+
26
+ /**
27
+ * @param tvType {string}
28
+ * @returns {any[]}
29
+ */
30
+ #getTypeGenerateurChId(tvType) {
31
+ return [
32
+ ...new Set(
33
+ tv[tvType].flatMap((v) =>
34
+ (v.enum_type_generateur_ch_id
35
+ ? v.enum_type_generateur_ch_id.split('|').map(Number)
36
+ : []
37
+ ).filter(Number.isFinite)
38
+ )
39
+ )
40
+ ].sort((a, b) => a - b);
41
+ }
42
+
43
+ /**
44
+ * Récupération des informations du générateur à combustion
45
+ * @param enumTypeGenerateurId
46
+ * @param pn
47
+ * @return {{tv_generateur_combustion_id: string, enum_type_generateur_ch_id: string, type_generateur: string, critere_pn: string, pveil: string, qp0_perc: string, rpint: string, rpn: string}}
48
+ */
49
+ getGenerateurCombustion(enumTypeGenerateurId, pn) {
50
+ return tv['generateur_combustion'].find(
51
+ (v) =>
52
+ v.enum_type_generateur_ch_id &&
53
+ v.enum_type_generateur_ch_id.split('|').includes(enumTypeGenerateurId) &&
54
+ (!v.critere_pn ||
55
+ eval(`let Pn=${pn} ;${convertExpression(v.critere_pn.replace('≤', '<='))}`))
56
+ );
57
+ }
58
+
59
+ /**
60
+ * Récupération de la température de fonctionnement
61
+ *
62
+ * @param pourcentageFonctionnement pourcentage de fonctionnement du générateur (30% ou 100%)
63
+ * @param enumTypeGenerateurId
64
+ * @param enumTemperatureDistribution
65
+ * @param enumPeriodeEmetteurs
66
+ * @return {number}
67
+ */
68
+ temperatureFonctionnement(
69
+ pourcentageFonctionnement,
70
+ enumTypeGenerateurId,
71
+ enumTemperatureDistribution,
72
+ enumPeriodeEmetteurs
73
+ ) {
74
+ const temperatureDistribution = enums.temp_distribution_ch[enumTemperatureDistribution];
75
+ const periodeEmetteur = enums.periode_installation_emetteur[enumPeriodeEmetteurs];
76
+
77
+ const temperature = tv[`temp_fonc_${pourcentageFonctionnement}`].find(
78
+ (v) =>
79
+ (!v.enum_type_generateur_ch_id ||
80
+ v.enum_type_generateur_ch_id.split('|').includes(enumTypeGenerateurId)) &&
81
+ v.temp_distribution_ch.toLowerCase() === temperatureDistribution?.toLowerCase() &&
82
+ v.periode_emetteurs.toLowerCase() === periodeEmetteur?.toLowerCase()
83
+ );
84
+
85
+ if (!temperature) {
86
+ logger.error(
87
+ `Pas de valeur forfaitaire temp_fonc_${pourcentageFonctionnement} pour enumTypeGenerateurId:${enumTypeGenerateurId}, enumTemperatureDistribution:${enumTemperatureDistribution}, enumPeriodeEmetteurs:${enumPeriodeEmetteurs}`
88
+ );
89
+ return;
90
+ }
91
+
92
+ return parseFloat(temperature[`temp_fonc_${pourcentageFonctionnement}`]);
93
+ }
94
+ }
@@ -0,0 +1,99 @@
1
+ import { beforeEach, describe, expect, test } from 'vitest';
2
+ import { ChTvStore } from './chTv.store.js';
3
+
4
+ /** @type {ChTvStore} **/
5
+ let chTvStore;
6
+
7
+ describe('Lecture des tables de valeurs', () => {
8
+ beforeEach(() => {
9
+ chTvStore = new ChTvStore();
10
+ });
11
+
12
+ test('ids des générateurs de chauffage à combustion', () => {
13
+ expect(chTvStore.getCombustionGenerateurs()).toStrictEqual([
14
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
15
+ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93,
16
+ 94, 95, 96, 97, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133,
17
+ 134, 135, 136, 137, 138, 139, 140, 141, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158,
18
+ 159, 160, 161
19
+ ]);
20
+ });
21
+
22
+ test('ids des générateurs de chauffage pompe à chaleur', () => {
23
+ expect(chTvStore.getPacGenerateurs()).toStrictEqual([
24
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 143, 145, 146, 147, 162,
25
+ 163, 164, 165, 166, 167, 168, 169, 170
26
+ ]);
27
+ });
28
+
29
+ test('Caractéristique du générateur à combustion', () => {
30
+ expect(chTvStore.getGenerateurCombustion('128', 125)).toStrictEqual({
31
+ tv_generateur_combustion_id: '2',
32
+ enum_type_generateur_ch_id: '86|128',
33
+ enum_type_generateur_ecs_id: '46|93',
34
+ type_generateur: 'Chaudière gaz classique 1981-1985',
35
+ pn: 'Pn',
36
+ rpn: '84 + 2 logPn',
37
+ rpint: '80 + 3 logPn',
38
+ qp0_perc: '2%',
39
+ pveil: '150'
40
+ });
41
+
42
+ expect(chTvStore.getGenerateurCombustion('84', 125)).toStrictEqual({
43
+ tv_generateur_combustion_id: '26',
44
+ enum_type_generateur_ch_id: '84',
45
+ enum_type_generateur_ecs_id: '44',
46
+ type_generateur: 'Chaudière fioul à condensation après 2015',
47
+ critere_pn: '70<Pn≤400',
48
+ pn: 'Pn',
49
+ rpn: '94 + logPn',
50
+ rpint: '100 + logPn',
51
+ qp0_perc: '0.60%'
52
+ });
53
+ });
54
+
55
+ describe('Lecture des valeurs de temp_fonc_30 ou temp_fonc_100', () => {
56
+ test.each([
57
+ {
58
+ label:
59
+ "Chaudière standard après 1990, emetteurs entre 1981 et 2000, basse température d'émission",
60
+ pourcentageFonctionnement: 30,
61
+ enumTypeGenerateurId: '89',
62
+ enumTemperatureDistribution: 2,
63
+ enumPeriodeEmetteurs: 2,
64
+ expected: 45
65
+ },
66
+ {
67
+ label: "Emetteurs entre 1981 et 2000, basse température d'émission",
68
+ pourcentageFonctionnement: 100,
69
+ enumTypeGenerateurId: '89',
70
+ enumTemperatureDistribution: 2,
71
+ enumPeriodeEmetteurs: 2,
72
+ expected: 35
73
+ }
74
+ ])(
75
+ `$label`,
76
+ ({
77
+ pourcentageFonctionnement,
78
+ enumTypeGenerateurId,
79
+ enumTemperatureDistribution,
80
+ enumPeriodeEmetteurs,
81
+ expected
82
+ }) => {
83
+ expect(
84
+ chTvStore.temperatureFonctionnement(
85
+ pourcentageFonctionnement,
86
+ enumTypeGenerateurId,
87
+ enumTemperatureDistribution,
88
+ enumPeriodeEmetteurs
89
+ )
90
+ ).toBe(expected);
91
+ }
92
+ );
93
+
94
+ test('pas de valeur de temp_fonc_30 ou temp_fonc_100', () => {
95
+ const pertes_stockage = chTvStore.temperatureFonctionnement(100, 600, 600, 600);
96
+ expect(pertes_stockage).toBeUndefined();
97
+ });
98
+ });
99
+ });
@@ -58,8 +58,10 @@ export class EcsTvStore extends TvStore {
58
58
  * @return {[number]}
59
59
  */
60
60
  getElectriqueEcsGenerateurs() {
61
- return tv['pertes_stockage'].flatMap((v) =>
62
- v.enum_type_generateur_ecs_id.split('|').map(Number)
63
- );
61
+ return [
62
+ ...new Set(
63
+ tv['pertes_stockage'].flatMap((v) => v.enum_type_generateur_ecs_id.split('|').map(Number))
64
+ )
65
+ ];
64
66
  }
65
67
  }
@@ -66,4 +66,8 @@ describe('Lecture des tables de valeurs', () => {
66
66
  expect(pertes_stockage).toBeUndefined();
67
67
  });
68
68
  });
69
+
70
+ test('ids des générateurs électriques ECS', () => {
71
+ expect(ecsTvStore.getElectriqueEcsGenerateurs()).toStrictEqual([68, 118, 69, 70, 71]);
72
+ });
69
73
  });
@@ -1,5 +1,6 @@
1
1
  import { tvs as tv } from '../../../../tv-v2.js';
2
2
  import { TvStore } from './../tv.store.js';
3
+ import { logger } from '../../../../core/util/logger/log-service.js';
3
4
 
4
5
  /**
5
6
  * Accès aux données des tables de valeurs pour le besoin en froid
@@ -35,4 +36,30 @@ export class FrTvStore extends TvStore {
35
36
 
36
37
  return parseFloat(values[classeAltitude][mois][zoneClimatique]);
37
38
  }
39
+
40
+ /**
41
+ * Coefficient d’efficience énergétique
42
+ * @see 10.3 - Les consommations de refroidissement
43
+ *
44
+ * @param zoneClimatiqueId {string}
45
+ * @param periodeInstallationId {number}
46
+ *
47
+ * @return {number|undefined}
48
+ */
49
+ getEer(zoneClimatiqueId, periodeInstallationId) {
50
+ const eer = tv['seer'].find(
51
+ (v) =>
52
+ v.enum_zone_climatique_id.split('|').includes(zoneClimatiqueId) &&
53
+ parseInt(v.enum_periode_installation_fr_id) === periodeInstallationId
54
+ )?.eer;
55
+
56
+ if (!eer) {
57
+ logger.error(
58
+ `Pas de valeur forfaitaire eer pour zoneClimatiqueId:${zoneClimatiqueId}, periodeInstallationId:${periodeInstallationId}`
59
+ );
60
+ return;
61
+ }
62
+
63
+ return parseFloat(eer);
64
+ }
38
65
  }
@@ -49,4 +49,26 @@ describe('Lecture des tables de valeurs', () => {
49
49
  expect(tvStore.getData(type, '400-800m', 'h1a', 'Juin', ilpa)).toBe(expected);
50
50
  });
51
51
  });
52
+
53
+ describe('Lecture des valeurs de coefficient d’efficience énergétique eer', () => {
54
+ test.each([
55
+ {
56
+ zoneClimatiqueId: '2',
57
+ periodeInstallationId: 1,
58
+ expected: 3.6
59
+ },
60
+ {
61
+ zoneClimatiqueId: '8',
62
+ periodeInstallationId: 2,
63
+ expected: 5.415
64
+ }
65
+ ])(`type: $type, ilpa: $ilpa`, ({ zoneClimatiqueId, periodeInstallationId, expected }) => {
66
+ expect(tvStore.getEer(zoneClimatiqueId, periodeInstallationId)).toBe(expected);
67
+ });
68
+
69
+ test('pas de valeur de eer', () => {
70
+ const eer = tvStore.getEer('8', 8);
71
+ expect(eer).toBeUndefined();
72
+ });
73
+ });
52
74
  });
@@ -353,4 +353,32 @@ export class TvStore {
353
353
 
354
354
  return q4paConv;
355
355
  }
356
+
357
+ /**
358
+ * Température extérieure de base(°C)
359
+ *
360
+ * @param classeAltitude {string}
361
+ * @param zoneClimatique {string}
362
+ */
363
+ getTempBase(classeAltitude, zoneClimatique) {
364
+ const Tbase = {
365
+ 1: {
366
+ h1: -9.5,
367
+ h2: -6.5,
368
+ h3: -3.5
369
+ },
370
+ 2: {
371
+ h1: -11.5,
372
+ h2: -8.5,
373
+ h3: -5.5
374
+ },
375
+ 3: {
376
+ h1: -13.5,
377
+ h2: -10.5,
378
+ h3: -7.5
379
+ }
380
+ };
381
+
382
+ return Tbase[classeAltitude][zoneClimatique];
383
+ }
356
384
  }
@@ -565,6 +565,18 @@ describe('Lecture des tables de valeurs', () => {
565
565
  });
566
566
  });
567
567
 
568
+ test('lecture des valeurs de tempBase', () => {
569
+ expect(tvStore.getTempBase('1', 'h1')).toBe(-9.5);
570
+ expect(tvStore.getTempBase('1', 'h2')).toBe(-6.5);
571
+ expect(tvStore.getTempBase('1', 'h3')).toBe(-3.5);
572
+ expect(tvStore.getTempBase('2', 'h1')).toBe(-11.5);
573
+ expect(tvStore.getTempBase('2', 'h2')).toBe(-8.5);
574
+ expect(tvStore.getTempBase('2', 'h3')).toBe(-5.5);
575
+ expect(tvStore.getTempBase('3', 'h1')).toBe(-13.5);
576
+ expect(tvStore.getTempBase('3', 'h2')).toBe(-10.5);
577
+ expect(tvStore.getTempBase('3', 'h3')).toBe(-7.5);
578
+ });
579
+
568
580
  describe.skip('Benchmark b', () => {
569
581
  test('reworked', () => {
570
582
  for (let i = 0; i < 1000; i++) {
@@ -7,6 +7,7 @@ import { InstallationEcsService } from '../ecs/installation-ecs.service.js';
7
7
  import { PerteEcsRecupService } from './ecs/perte-ecs-recup.service.js';
8
8
  import { BesoinChService } from './ch/besoin-ch.service.js';
9
9
  import { PerteChRecupService } from './ch/perte-ch-recup.service.js';
10
+ import { InstallationChService } from '../ch/installation-ch.service.js';
10
11
 
11
12
  /**
12
13
  * Calcul des déperditions de l’enveloppe GV
@@ -33,6 +34,11 @@ export class ApportEtBesoinService {
33
34
  */
34
35
  #installationEcsService;
35
36
 
37
+ /**
38
+ * @type {InstallationChService}
39
+ */
40
+ #installationChService;
41
+
36
42
  /**
37
43
  * @type {PerteEcsRecupService}
38
44
  */
@@ -57,6 +63,7 @@ export class ApportEtBesoinService {
57
63
  * @param besoinEcsService {BesoinEcsService}
58
64
  * @param besoinChService {BesoinChService}
59
65
  * @param installationEcsService {InstallationEcsService}
66
+ * @param installationChService {InstallationChService}
60
67
  * @param perteEcsRecupService {PerteEcsRecupService}
61
68
  * @param besoinFroidService {BesoinFroidService}
62
69
  * @param surfaceSudEquivalenteService {SurfaceSudEquivalenteService}
@@ -67,6 +74,7 @@ export class ApportEtBesoinService {
67
74
  besoinEcsService = inject(BesoinEcsService),
68
75
  besoinChService = inject(BesoinChService),
69
76
  installationEcsService = inject(InstallationEcsService),
77
+ installationChService = inject(InstallationChService),
70
78
  perteEcsRecupService = inject(PerteEcsRecupService),
71
79
  besoinFroidService = inject(BesoinFroidService),
72
80
  surfaceSudEquivalenteService = inject(SurfaceSudEquivalenteService),
@@ -76,6 +84,7 @@ export class ApportEtBesoinService {
76
84
  this.#besoinEcsService = besoinEcsService;
77
85
  this.#besoinChService = besoinChService;
78
86
  this.#installationEcsService = installationEcsService;
87
+ this.#installationChService = installationChService;
79
88
  this.#perteEcsRecupService = perteEcsRecupService;
80
89
  this.#besoinFroidService = besoinFroidService;
81
90
  this.#surfaceSudEquivalenteService = surfaceSudEquivalenteService;
@@ -98,6 +107,11 @@ export class ApportEtBesoinService {
98
107
  */
99
108
  this.#installationEcsService.execute(ctx, logement, besoinEcs);
100
109
 
110
+ /**
111
+ * Détermination des données des installations de chauffage
112
+ */
113
+ this.#installationChService.execute(ctx, logement);
114
+
101
115
  const apportsInternes = this.#apportGratuitService.apportInterne(ctx, logement);
102
116
  const apportsSolaires = this.#apportGratuitService.apportSolaire(ctx, logement);
103
117
 
@@ -14,6 +14,7 @@ import { getAdemeFileJson } from '../../../../../test/test-helpers.js';
14
14
  import { PRECISION_PERCENT } from '../../../../../test/constant.js';
15
15
  import { DpeNormalizerService } from '../../../normalizer/domain/dpe-normalizer.service.js';
16
16
  import { ContexteBuilder } from '../contexte.builder.js';
17
+ import { InstallationChService } from '../ch/installation-ch.service.js';
17
18
 
18
19
  /** @type {SurfaceSudEquivalenteService} **/
19
20
  let surfaceSudEquivalenteService;
@@ -27,6 +28,9 @@ let besoinFroidService;
27
28
  /** @type {InstallationEcsService} **/
28
29
  let installationEcsService;
29
30
 
31
+ /** @type {InstallationChService} **/
32
+ let installationChService;
33
+
30
34
  /** @type {PerteEcsRecupService} **/
31
35
  let perteEcsRecupService;
32
36
 
@@ -59,6 +63,7 @@ describe('Calcul des apports et besoin du logement', () => {
59
63
  besoinChService = new BesoinChService();
60
64
  besoinFroidService = new BesoinFroidService();
61
65
  installationEcsService = new InstallationEcsService();
66
+ installationChService = new InstallationChService();
62
67
  perteEcsRecupService = new PerteEcsRecupService();
63
68
  apportGratuitService = new ApportGratuitService();
64
69
  perteChRecupService = new PerteChRecupService();
@@ -66,6 +71,7 @@ describe('Calcul des apports et besoin du logement', () => {
66
71
  besoinEcsService,
67
72
  besoinChService,
68
73
  installationEcsService,
74
+ installationChService,
69
75
  perteEcsRecupService,
70
76
  besoinFroidService,
71
77
  surfaceSudEquivalenteService,
@@ -99,6 +105,7 @@ describe('Calcul des apports et besoin du logement', () => {
99
105
  apport_interne_fr: 3345.2
100
106
  });
101
107
  vi.spyOn(installationEcsService, 'execute').mockReturnThis();
108
+ vi.spyOn(installationChService, 'execute').mockReturnThis();
102
109
  vi.spyOn(perteEcsRecupService, 'execute').mockReturnValue({
103
110
  pertes_distribution_ecs_recup: 354.2,
104
111
  pertes_distribution_ecs_recup_depensier: 532.6,
@@ -141,6 +148,13 @@ describe('Calcul des apports et besoin du logement', () => {
141
148
  expect(besoinFroidService.execute).toHaveBeenCalledWith(ctx, logement);
142
149
  expect(apportGratuitService.apportSolaire).toHaveBeenCalledWith(ctx, logement);
143
150
  expect(apportGratuitService.apportInterne).toHaveBeenCalledWith(ctx, logement);
151
+ expect(perteEcsRecupService.execute).toHaveBeenCalledWith(ctx, logement);
152
+ expect(perteChRecupService.execute).toHaveBeenCalledWith(ctx, logement);
153
+ expect(installationEcsService.execute).toHaveBeenCalledWith(ctx, logement, {
154
+ besoin_ecs: 1526,
155
+ besoin_ecs_depensier: 2685.3
156
+ });
157
+ expect(installationChService.execute).toHaveBeenCalledWith(ctx, logement);
144
158
  });
145
159
 
146
160
  describe("Test d'intégration pour les besoins en chauffage", () => {
@@ -0,0 +1,100 @@
1
+ import { ChTvStore } from '../../../dpe/infrastructure/ch/chTv.store.js';
2
+ import { inject } from 'dioma';
3
+
4
+ /**
5
+ * Calcul des données des émetteurs de chauffage
6
+ * Données calculées
7
+ * — temperature de distribution
8
+ * — période d'installation des émetteurs
9
+ */
10
+ export class EmetteurChService {
11
+ /**
12
+ * @type {ChTvStore}
13
+ */
14
+ #chTvStore;
15
+
16
+ /**
17
+ * @param chTvStore {ChTvStore}
18
+ */
19
+ constructor(chTvStore = inject(ChTvStore)) {
20
+ this.#chTvStore = chTvStore;
21
+ }
22
+
23
+ /**
24
+ * Détermination de l'année d'installation d'un émetteur
25
+ *
26
+ * 13.2.1.5 Chaudières basse température et condensation
27
+ * Si l’année d’installation des émetteurs est inconnue, prendre l’année de construction du bâtiment.
28
+ *
29
+ * @param ctx {Contexte}
30
+ * @param emetteurChauffage {EmetteurChauffage}
31
+ */
32
+ periodeInstallationEmetteur(ctx, emetteurChauffage) {
33
+ const periodeInstallationEmetteur = parseInt(
34
+ emetteurChauffage.donnee_entree.enum_periode_installation_emetteur_id
35
+ );
36
+
37
+ if (!periodeInstallationEmetteur) {
38
+ return ctx.anneeConstruction < 1981 ? 1 : ctx.anneeConstruction < 2000 ? 2 : 3;
39
+ }
40
+
41
+ return periodeInstallationEmetteur;
42
+ }
43
+
44
+ /**
45
+ * Calcul des températures de fonctionnement à 30% ou 100%
46
+ *
47
+ * @param ctx {Contexte}
48
+ * @param generateurChauffageDE {GenerateurChauffageDE}
49
+ * @param emetteursChauffage {EmetteurChauffage[]}
50
+ * @return {{temp_fonc_30: number, temp_fonc_100: number}}
51
+ */
52
+ temperatureFonctionnement(ctx, generateurChauffageDE, emetteursChauffage) {
53
+ let temperatureFonctionnement30;
54
+ let temperatureFonctionnement100;
55
+
56
+ emetteursChauffage
57
+ .filter(
58
+ (emetteurChauffage) =>
59
+ parseInt(emetteurChauffage.donnee_entree.enum_temp_distribution_ch_id) !== 1
60
+ )
61
+ .forEach((emetteurChauffage) => {
62
+ // Récupération de la température de distribution
63
+ const temperatureDistribution = Number(
64
+ emetteurChauffage.donnee_entree.enum_temp_distribution_ch_id
65
+ );
66
+
67
+ // Récupération de la période d'installation de distribution
68
+ const periodeInstallationEmetteur = this.periodeInstallationEmetteur(
69
+ ctx,
70
+ emetteurChauffage
71
+ );
72
+
73
+ const tempFonctionnement30 = this.#chTvStore.temperatureFonctionnement(
74
+ '30',
75
+ generateurChauffageDE.enum_type_generateur_ch_id,
76
+ temperatureDistribution,
77
+ periodeInstallationEmetteur
78
+ );
79
+
80
+ const tempFonctionnement100 = this.#chTvStore.temperatureFonctionnement(
81
+ '100',
82
+ generateurChauffageDE.enum_type_generateur_ch_id,
83
+ temperatureDistribution,
84
+ periodeInstallationEmetteur
85
+ );
86
+
87
+ if (!temperatureFonctionnement30 || tempFonctionnement30 > temperatureFonctionnement30) {
88
+ temperatureFonctionnement30 = tempFonctionnement30;
89
+ }
90
+ if (!temperatureFonctionnement100 || tempFonctionnement100 > temperatureFonctionnement100) {
91
+ temperatureFonctionnement100 = tempFonctionnement100;
92
+ }
93
+ });
94
+
95
+ return {
96
+ temp_fonc_30: temperatureFonctionnement30,
97
+ temp_fonc_100: temperatureFonctionnement100
98
+ };
99
+ }
100
+ }