@open3cl/engine 1.0.11 → 1.0.13

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 (25) hide show
  1. package/features/dpe/domain/models/dpe.model.ts +9 -0
  2. package/features/dpe/domain/models/installation-chauffage.model.ts +2 -2
  3. package/features/dpe/domain/models/installation-ecs.model.ts +15 -2
  4. package/features/dpe/domain/models/type-habitation.model.js +1 -0
  5. package/features/dpe/domain/models/type-stockage.model.js +8 -0
  6. package/features/dpe/infrastructure/ecs/ecsTv.store.js +43 -0
  7. package/features/dpe/infrastructure/ecs/ecsTv.store.spec.js +36 -0
  8. package/features/dpe/infrastructure/froid/frTv.store.js +4 -2
  9. package/features/engine/domain/apport_et_besoin/apport-et-besoin.service.js +69 -3
  10. package/features/engine/domain/apport_et_besoin/apport-et-besoin.service.spec.js +123 -1
  11. package/features/engine/domain/apport_et_besoin/apport_gratuit/apport-gratuit.service.js +18 -2
  12. package/features/engine/domain/apport_et_besoin/apport_gratuit/apport-gratuit.service.spec.js +13 -2
  13. package/features/engine/domain/apport_et_besoin/ch/besoin-ch.service.js +150 -0
  14. package/features/engine/domain/apport_et_besoin/ch/besoin-ch.service.spec.js +145 -0
  15. package/features/engine/domain/apport_et_besoin/ch/perte-ch-recup.service.js +168 -0
  16. package/features/engine/domain/apport_et_besoin/ch/perte-ch-recup.service.spec.js +313 -0
  17. package/features/engine/domain/apport_et_besoin/ecs/perte-ecs-recup.service.js +127 -0
  18. package/features/engine/domain/apport_et_besoin/ecs/perte-ecs-recup.service.spec.js +220 -0
  19. package/features/engine/domain/contexte.builder.js +5 -1
  20. package/features/engine/domain/ecs/generateur-ecs.service.js +106 -0
  21. package/features/engine/domain/ecs/generateur-ecs.service.spec.js +136 -0
  22. package/features/engine/domain/ecs/installation-ecs.service.js +156 -0
  23. package/features/engine/domain/ecs/installation-ecs.service.spec.js +284 -0
  24. package/features/engine/domain/engine.service.js +13 -2
  25. package/package.json +1 -1
@@ -0,0 +1,313 @@
1
+ import { beforeEach, describe, expect, test, vi } from 'vitest';
2
+ import corpus from '../../../../../../test/corpus-sano.json';
3
+ import { expect_or, getAdemeFileJson } from '../../../../../../test/test-helpers.js';
4
+ import { DpeNormalizerService } from '../../../../normalizer/domain/dpe-normalizer.service.js';
5
+ import { ContexteBuilder } from '../../contexte.builder.js';
6
+ import { FrTvStore } from '../../../../dpe/infrastructure/froid/frTv.store.js';
7
+ import { mois_liste } from '../../../../../utils.js';
8
+ import { PerteChRecupService } from './perte-ch-recup.service.js';
9
+ import { BesoinChService } from './besoin-ch.service.js';
10
+ import { ApportGratuitService } from '../apport_gratuit/apport-gratuit.service.js';
11
+ import { PRECISION_PERCENT } from '../../../../../../test/constant.js';
12
+
13
+ /** @type {PerteChRecupService} **/
14
+ let service;
15
+
16
+ /** @type {BesoinChService} **/
17
+ let besoinChService;
18
+
19
+ /** @type {ApportGratuitService} **/
20
+ let apportGratuitService;
21
+
22
+ /** @type {FrTvStore} **/
23
+ let tvStore;
24
+
25
+ /** @type {DpeNormalizerService} **/
26
+ let normalizerService;
27
+
28
+ /** @type {ContexteBuilder} **/
29
+ let contexteBuilder;
30
+
31
+ describe('Calcul des pertes de génération de chauffage récupérées', () => {
32
+ beforeEach(() => {
33
+ tvStore = new FrTvStore();
34
+ service = new PerteChRecupService(tvStore);
35
+ besoinChService = new BesoinChService();
36
+ apportGratuitService = new ApportGratuitService();
37
+ normalizerService = new DpeNormalizerService();
38
+ contexteBuilder = new ContexteBuilder();
39
+ });
40
+
41
+ test.each([
42
+ {
43
+ label: 'Installation CH uniquement avec ventouse, utilisation de nref',
44
+ enumUsageGenerateurId: 1,
45
+ presenceVentouse: 1,
46
+ expected: 562.5
47
+ },
48
+ {
49
+ label: 'Installation CH uniquement sans ventouse, utilisation de nref',
50
+ enumUsageGenerateurId: 1,
51
+ presenceVentouse: 0,
52
+ expected: 375
53
+ },
54
+ {
55
+ label: "Installation CH uniquement sans ventouse, pas d'utilisation de nref",
56
+ enumUsageGenerateurId: 1,
57
+ presenceVentouse: 0,
58
+ nref: 500,
59
+ expected: 7971.08
60
+ },
61
+ {
62
+ label: 'Installation ECS uniquement avec ventouse',
63
+ enumUsageGenerateurId: 2,
64
+ presenceVentouse: 1,
65
+ expected: 114.94
66
+ },
67
+ {
68
+ label: 'Installation ECS uniquement sans ventouse',
69
+ enumUsageGenerateurId: 2,
70
+ presenceVentouse: 0,
71
+ expected: 76.627
72
+ },
73
+ {
74
+ label: 'Installation ECS + CH avec ventouse, utilisation de nref',
75
+ enumUsageGenerateurId: 3,
76
+ presenceVentouse: 1,
77
+ expected: 562.5
78
+ },
79
+ {
80
+ label: 'Installation ECS + CH sans ventouse, utilisation de nref',
81
+ enumUsageGenerateurId: 3,
82
+ presenceVentouse: 0,
83
+ expected: 375
84
+ },
85
+ {
86
+ label: "Installation ECS + CH sans ventouse, pas d'utilisation de nref",
87
+ enumUsageGenerateurId: 3,
88
+ presenceVentouse: 0,
89
+ nref: 450,
90
+ expected: 10729.642
91
+ }
92
+ ])(
93
+ 'Calcul des pertes récupérées de génération pour le chauffage sur un mois pour $label',
94
+ ({ enumUsageGenerateurId, presenceVentouse, nref = undefined, expected }) => {
95
+ /** @type {GenerateurChauffage[]} */
96
+ const generateurs = [
97
+ {
98
+ donnee_entree: {
99
+ presence_ventouse: presenceVentouse,
100
+ enum_usage_generateur_id: enumUsageGenerateurId
101
+ },
102
+ donnee_intermediaire: { pn: 25000, qp0: 125 }
103
+ }
104
+ ];
105
+
106
+ expect(service.Qrec(generateurs, nref ?? 12.5, 1532.9)).toBeCloseTo(expected, 3);
107
+ }
108
+ );
109
+
110
+ test('Filtre des générateurs avec pertes de génération', () => {
111
+ const generateur1 = {
112
+ donnee_entree: {}
113
+ };
114
+ const generateur2 = {
115
+ donnee_entree: { position_volume_chauffe: 0, enum_type_generateur_ch_id: 45 }
116
+ };
117
+ const generateur3 = {
118
+ donnee_entree: { position_volume_chauffe: 0, enum_type_generateur_ch_id: 50 }
119
+ };
120
+ const generateur4 = {
121
+ donnee_entree: { position_volume_chauffe: 1, enum_type_generateur_ch_id: 50 }
122
+ };
123
+ const generateur5 = {
124
+ donnee_entree: { position_volume_chauffe: 1, enum_type_generateur_ch_id: 48 }
125
+ };
126
+
127
+ /** @type {Logement} */
128
+ let logement = { installation_chauffage_collection: {} };
129
+ expect(service.generateursWithPertesGeneration(logement)).toStrictEqual([]);
130
+
131
+ logement.installation_chauffage_collection = { installation_chauffage: [] };
132
+ expect(service.generateursWithPertesGeneration(logement)).toStrictEqual([]);
133
+
134
+ logement.installation_chauffage_collection = {
135
+ installation_chauffage: [{ generateur_chauffage_collection: {} }]
136
+ };
137
+ expect(service.generateursWithPertesGeneration(logement)).toStrictEqual([]);
138
+
139
+ logement.installation_chauffage_collection = {
140
+ installation_chauffage: [{ generateur_chauffage_collection: { generateur_chauffage: [] } }]
141
+ };
142
+ expect(service.generateursWithPertesGeneration(logement)).toStrictEqual([]);
143
+
144
+ logement.installation_chauffage_collection = {
145
+ installation_chauffage: [
146
+ {
147
+ generateur_chauffage_collection: {
148
+ generateur_chauffage: [generateur1, generateur2, generateur3]
149
+ }
150
+ },
151
+ { generateur_chauffage_collection: { generateur_chauffage: [generateur4, generateur5] } }
152
+ ]
153
+ };
154
+ expect(service.generateursWithPertesGeneration(logement)).toStrictEqual([generateur5]);
155
+ });
156
+
157
+ test.each([
158
+ {
159
+ label: 'Installation CH en mode conventionnel',
160
+ depensier: false,
161
+ expected: 288
162
+ },
163
+ {
164
+ label: 'Installation CH en mode dépensier',
165
+ depensier: true,
166
+ expected: 540
167
+ }
168
+ ])('Pertes de chauffage récupérées pour $label', ({ depensier, expected }) => {
169
+ vi.spyOn(tvStore, 'getData').mockReturnValue(depensier ? 1.5 : 0.8);
170
+
171
+ /** @type {Contexte} */
172
+ const ctx = {
173
+ altitude: { value: '400-800m' },
174
+ zoneClimatique: { value: 'h1a' },
175
+ inertie: { ilpa: 1 }
176
+ };
177
+
178
+ /** @type {Logement} */
179
+ const logement = {
180
+ installation_chauffage_collection: {
181
+ installation_chauffage: [
182
+ {
183
+ generateur_chauffage_collection: {
184
+ generateur_chauffage: [
185
+ {
186
+ donnee_entree: {
187
+ position_volume_chauffe: 1,
188
+ enum_type_generateur_ch_id: 48,
189
+ enum_usage_generateur_id: 1
190
+ },
191
+ donnee_intermediaire: { pn: 25000, qp0: 125 }
192
+ }
193
+ ]
194
+ }
195
+ }
196
+ ]
197
+ },
198
+ donnees_de_calcul: {
199
+ besoinChauffageHP: {
200
+ Janvier: 102.5,
201
+ Février: 102.5,
202
+ Mars: 102.5,
203
+ Avril: 102.5,
204
+ Mai: 102.5,
205
+ Juin: 102.5,
206
+ Juillet: 102.5,
207
+ Aout: 102.5,
208
+ Septembre: 102.5,
209
+ Octobre: 102.5,
210
+ Novembre: 102.5,
211
+ Décembre: 102.5
212
+ },
213
+ besoinChauffageDepensierHP: {
214
+ Janvier: 112.5,
215
+ Février: 112.5,
216
+ Mars: 112.5,
217
+ Avril: 112.5,
218
+ Mai: 112.5,
219
+ Juin: 112.5,
220
+ Juillet: 112.5,
221
+ Aout: 112.5,
222
+ Septembre: 112.5,
223
+ Octobre: 112.5,
224
+ Novembre: 112.5,
225
+ Décembre: 112.5
226
+ }
227
+ }
228
+ };
229
+
230
+ expect(service.pertesGenerateurChRecup(ctx, logement, depensier)).toBeCloseTo(expected, 3);
231
+ for (const mois of mois_liste) {
232
+ expect(tvStore.getData).toHaveBeenCalledWith(
233
+ depensier ? 'nref21' : 'nref19',
234
+ '400-800m',
235
+ 'h1a',
236
+ mois,
237
+ 1
238
+ );
239
+ }
240
+ });
241
+
242
+ describe("Test d'intégration des installations CH", () => {
243
+ test.each(corpus)('vérification des pertes de génération ch pour dpe %s', (ademeId) => {
244
+ let dpeRequest = getAdemeFileJson(ademeId);
245
+ dpeRequest = normalizerService.normalize(dpeRequest);
246
+ dpeRequest.logement.donnees_de_calcul = {
247
+ apportsInterneDepensier: [],
248
+ apportsInterneCh: [],
249
+ apportsSolaire: [],
250
+ besoinChauffageHP: [],
251
+ besoinChauffageDepensierHP: []
252
+ };
253
+
254
+ /** @type {Contexte} */
255
+ const ctx = contexteBuilder.fromDpe(dpeRequest);
256
+ apportGratuitService.apportInterne(ctx, dpeRequest.logement);
257
+ apportGratuitService.apportSolaire(ctx, dpeRequest.logement);
258
+ besoinChService.execute(ctx, dpeRequest.logement);
259
+ const pertesGeneration = service.execute(ctx, dpeRequest.logement);
260
+
261
+ const expectedValue = dpeRequest.logement.sortie.apport_et_besoin.pertes_generateur_ch_recup;
262
+ const calculatedValue = pertesGeneration.pertes_generateur_ch_recup;
263
+
264
+ expect_or(
265
+ () =>
266
+ expect(Math.abs(calculatedValue - expectedValue) / (expectedValue || 1)).toBeLessThan(
267
+ PRECISION_PERCENT
268
+ ),
269
+ () =>
270
+ expect(
271
+ Math.abs(calculatedValue - expectedValue * 1000) / (expectedValue * 1000 || 1)
272
+ ).toBeLessThan(PRECISION_PERCENT)
273
+ );
274
+ });
275
+
276
+ test.each(corpus)(
277
+ 'vérification des pertes de génération ch depensier des installations CH pour dpe %s',
278
+ (ademeId) => {
279
+ let dpeRequest = getAdemeFileJson(ademeId);
280
+ dpeRequest = normalizerService.normalize(dpeRequest);
281
+ dpeRequest.logement.donnees_de_calcul = {
282
+ apportsInterneDepensier: [],
283
+ apportsInterneCh: [],
284
+ apportsSolaire: [],
285
+ besoinChauffageHP: [],
286
+ besoinChauffageDepensierHP: []
287
+ };
288
+
289
+ /** @type {Contexte} */
290
+ const ctx = contexteBuilder.fromDpe(dpeRequest);
291
+ apportGratuitService.apportInterne(ctx, dpeRequest.logement);
292
+ apportGratuitService.apportSolaire(ctx, dpeRequest.logement);
293
+ besoinChService.execute(ctx, dpeRequest.logement);
294
+ const pertesGeneration = service.execute(ctx, dpeRequest.logement);
295
+
296
+ const expectedValue =
297
+ dpeRequest.logement.sortie.apport_et_besoin.pertes_generateur_ch_recup_depensier;
298
+ const calculatedValue = pertesGeneration.pertes_generateur_ch_recup_depensier;
299
+
300
+ expect_or(
301
+ () =>
302
+ expect(Math.abs(calculatedValue - expectedValue) / (expectedValue || 1)).toBeLessThan(
303
+ PRECISION_PERCENT
304
+ ),
305
+ () =>
306
+ expect(
307
+ Math.abs(calculatedValue - expectedValue * 1000) / (expectedValue * 1000 || 1)
308
+ ).toBeLessThan(PRECISION_PERCENT)
309
+ );
310
+ }
311
+ );
312
+ });
313
+ });
@@ -0,0 +1,127 @@
1
+ import { mois_liste } from '../../../../../utils.js';
2
+ import { inject } from 'dioma';
3
+ import { FrTvStore } from '../../../../dpe/infrastructure/froid/frTv.store.js';
4
+
5
+ /**
6
+ * Calcul des pertes récupérées de distribution et de stockage d'ECS
7
+ * Chapitre 9.1.1 Consommation de chauffage
8
+ *
9
+ * Données calculées
10
+ * — pertes_distribution_ecs_recup : pertes de distribution d'ECS récupérées(kWh)
11
+ * — pertes_distribution_ecs_recup_depensier : pertes de distribution d'ECS récupérées(kWh) pour le scénario dépensier
12
+ * — pertes_stockage_ecs_recup : pertes de stockage d'ECS récupérées(kWh)
13
+ *
14
+ * Methode_de_calcul_3CL_DPE_2021 - Page 57
15
+ * Octobre 2021
16
+ * @see consolide_anne…arrete_du_31_03_2021_relatif_aux_methodes_et_procedures_applicables.pdf
17
+ */
18
+ export class PerteEcsRecupService {
19
+ /**
20
+ * @type {FrTvStore}
21
+ */
22
+ #tvStore;
23
+
24
+ /**
25
+ * @param tvStore {FrTvStore}
26
+ */
27
+ constructor(tvStore = inject(FrTvStore)) {
28
+ this.#tvStore = tvStore;
29
+ }
30
+
31
+ /**
32
+ * Pertes de distribution et de stockage ECS (kWh)
33
+ * @param ctx {Contexte}
34
+ * @param logement {Logement}
35
+ * @return {{pertes_distribution_ecs_recup: number, pertes_distribution_ecs_recup_depensier: number, pertes_stockage_ecs_recup: number, pertes_stockage_ecs_recup_depensier: number}}
36
+ */
37
+ execute(ctx, logement) {
38
+ return {
39
+ pertes_distribution_ecs_recup: this.pertesDistributionEcsRecup(ctx, logement, false) / 1000,
40
+ pertes_distribution_ecs_recup_depensier:
41
+ this.pertesDistributionEcsRecup(ctx, logement, true) / 1000,
42
+ pertes_stockage_ecs_recup: this.pertesStockageEcsRecup(ctx, logement, false) / 1000,
43
+ pertes_stockage_ecs_recup_depensier: this.pertesStockageEcsRecup(ctx, logement, true) / 1000
44
+ };
45
+ }
46
+
47
+ /**
48
+ * Pertes récupérées de distribution d’ECS pour le chauffage (Wh)
49
+ * 9.1.1 Consommation de chauffage
50
+ *
51
+ * @param ctx {Contexte}
52
+ * @param logement {Logement}
53
+ * @param depensier {boolean}
54
+ * @returns {number}
55
+ */
56
+ pertesDistributionEcsRecup(ctx, logement, depensier) {
57
+ const installationsEcs = logement.installation_ecs_collection?.installation_ecs || [];
58
+
59
+ const pertesDistribution = installationsEcs.reduce((acc, installation) => {
60
+ /** @type {InstallationEcsDU}*/
61
+ const installationEcsDU = installation.donnee_utilisateur;
62
+
63
+ const pertesDistributionIndividuelleVolumeChauffee = depensier
64
+ ? installationEcsDU.QdwIndVc.depensier
65
+ : installationEcsDU.QdwIndVc.conventionnel;
66
+ const pertesDistributionCollectiveVolumeChauffee = depensier
67
+ ? installationEcsDU.QdwColVc.depensier
68
+ : installationEcsDU.QdwColVc.conventionnel;
69
+
70
+ return (
71
+ acc +
72
+ pertesDistributionIndividuelleVolumeChauffee +
73
+ pertesDistributionCollectiveVolumeChauffee
74
+ );
75
+ }, 0);
76
+
77
+ return mois_liste.reduce((acc, mois) => {
78
+ return (
79
+ acc +
80
+ (0.48 *
81
+ pertesDistribution *
82
+ this.#tvStore.getData(
83
+ depensier ? 'nref21' : 'nref19',
84
+ ctx.altitude.value,
85
+ ctx.zoneClimatique.value,
86
+ mois,
87
+ ctx.inertie.ilpa
88
+ )) /
89
+ 8760
90
+ );
91
+ }, 0);
92
+ }
93
+
94
+ /**
95
+ * Pertes récupérées du stockage d’ECS pour le chauffage (Wh)
96
+ * 9.1.1 Consommation de chauffage
97
+ *
98
+ * @param ctx {Contexte}
99
+ * @param logement {Logement}
100
+ * @param depensier {boolean}
101
+ * @returns {number}
102
+ */
103
+ pertesStockageEcsRecup(ctx, logement, depensier) {
104
+ const installationsEcs = logement.installation_ecs_collection?.installation_ecs || [];
105
+
106
+ let pertesStockage = installationsEcs.reduce((acc, installation) => {
107
+ /** @type {InstallationEcsDU}*/
108
+ const installationEcsDU = installation.donnee_utilisateur;
109
+
110
+ return acc + (0.48 * installationEcsDU.QgwRecuperable) / 8760.0;
111
+ }, 0);
112
+
113
+ return mois_liste.reduce((acc, mois) => {
114
+ return (
115
+ acc +
116
+ pertesStockage *
117
+ this.#tvStore.getData(
118
+ depensier ? 'nref21' : 'nref19',
119
+ ctx.altitude.value,
120
+ ctx.zoneClimatique.value,
121
+ mois,
122
+ ctx.inertie.ilpa
123
+ )
124
+ );
125
+ }, 0);
126
+ }
127
+ }
@@ -0,0 +1,220 @@
1
+ import { beforeEach, describe, expect, test, vi } from 'vitest';
2
+ import corpus from '../../../../../../test/corpus-sano.json';
3
+ import { expect_or, getAdemeFileJson } from '../../../../../../test/test-helpers.js';
4
+ import { DpeNormalizerService } from '../../../../normalizer/domain/dpe-normalizer.service.js';
5
+ import { ContexteBuilder } from '../../contexte.builder.js';
6
+ import { PerteEcsRecupService } from './perte-ecs-recup.service.js';
7
+ import { FrTvStore } from '../../../../dpe/infrastructure/froid/frTv.store.js';
8
+ import { mois_liste } from '../../../../../utils.js';
9
+ import { EcsTvStore } from '../../../../dpe/infrastructure/ecs/ecsTv.store.js';
10
+ import { GenerateurEcsService } from '../../ecs/generateur-ecs.service.js';
11
+ import { InstallationEcsService } from '../../ecs/installation-ecs.service.js';
12
+
13
+ /** @type {PerteEcsRecupService} **/
14
+ let service;
15
+
16
+ /** @type {FrTvStore} **/
17
+ let tvStore;
18
+
19
+ /** @type {InstallationEcsService} **/
20
+ let installationEcsService;
21
+
22
+ /** @type {DpeNormalizerService} **/
23
+ let normalizerService;
24
+
25
+ /** @type {ContexteBuilder} **/
26
+ let contexteBuilder;
27
+
28
+ describe('Calcul des pertes de distribution et stockage récupérées', () => {
29
+ beforeEach(() => {
30
+ tvStore = new FrTvStore();
31
+ service = new PerteEcsRecupService(tvStore);
32
+ installationEcsService = new InstallationEcsService(new GenerateurEcsService(new EcsTvStore()));
33
+ normalizerService = new DpeNormalizerService();
34
+ contexteBuilder = new ContexteBuilder();
35
+ });
36
+
37
+ test.each([
38
+ {
39
+ label: 'Installation ECS en mode conventionnel',
40
+ depensier: false,
41
+ expected: 0.192
42
+ },
43
+ {
44
+ label: 'Installation ECS en mode dépensier',
45
+ depensier: true,
46
+ expected: 0.725
47
+ }
48
+ ])('Calcul des pertes de distribution récupérées pour $label', ({ depensier, expected }) => {
49
+ vi.spyOn(tvStore, 'getData').mockReturnValue(depensier ? 1.5 : 0.8);
50
+
51
+ /** @type {Contexte} */
52
+ const ctx = {
53
+ altitude: { value: '400-800m' },
54
+ zoneClimatique: { value: 'h1a' },
55
+ inertie: { ilpa: 1 }
56
+ };
57
+
58
+ /** @type {Logement} */
59
+ const logement = {
60
+ installation_ecs_collection: {
61
+ installation_ecs: [
62
+ {
63
+ donnee_utilisateur: {
64
+ QdwIndVc: { conventionnel: 100, depensier: 200 },
65
+ QdwColVc: { conventionnel: 50, depensier: 120 }
66
+ }
67
+ },
68
+ {
69
+ donnee_utilisateur: {
70
+ QdwIndVc: { conventionnel: 150, depensier: 280 },
71
+ QdwColVc: { conventionnel: 65, depensier: 135 }
72
+ }
73
+ }
74
+ ]
75
+ }
76
+ };
77
+
78
+ expect(service.pertesDistributionEcsRecup(ctx, logement, depensier)).toBeCloseTo(expected, 3);
79
+ for (const mois of mois_liste) {
80
+ expect(tvStore.getData).toHaveBeenCalledWith(
81
+ depensier ? 'nref21' : 'nref19',
82
+ '400-800m',
83
+ 'h1a',
84
+ mois,
85
+ 1
86
+ );
87
+ }
88
+ });
89
+
90
+ test.each([
91
+ {
92
+ label: 'Installation ECS en mode conventionnel',
93
+ depensier: false,
94
+ expected: 63.209
95
+ },
96
+ {
97
+ label: 'Installation ECS en mode dépensier',
98
+ depensier: true,
99
+ expected: 118.516
100
+ }
101
+ ])('Calcul des pertes de stockage récupérées pour $label', ({ depensier, expected }) => {
102
+ vi.spyOn(tvStore, 'getData').mockReturnValue(depensier ? 1.5 : 0.8);
103
+
104
+ /** @type {Contexte} */
105
+ const ctx = {
106
+ altitude: { value: '400-800m' },
107
+ zoneClimatique: { value: 'h1a' },
108
+ inertie: { ilpa: 1 }
109
+ };
110
+
111
+ /** @type {Logement} */
112
+ const logement = {
113
+ installation_ecs_collection: {
114
+ installation_ecs: [
115
+ { donnee_utilisateur: { QgwRecuperable: 120012 } },
116
+ { donnee_utilisateur: { QgwRecuperable: 150 } }
117
+ ]
118
+ }
119
+ };
120
+
121
+ expect(service.pertesStockageEcsRecup(ctx, logement, depensier)).toBeCloseTo(expected, 3);
122
+ for (const mois of mois_liste) {
123
+ expect(tvStore.getData).toHaveBeenCalledWith(
124
+ depensier ? 'nref21' : 'nref19',
125
+ '400-800m',
126
+ 'h1a',
127
+ mois,
128
+ 1
129
+ );
130
+ }
131
+ });
132
+
133
+ describe("Test d'intégration des installations ECS", () => {
134
+ test.each(corpus)(
135
+ 'vérification des pertes de distribution ecs recup des installations ECS pour dpe %s',
136
+ (ademeId) => {
137
+ let dpeRequest = getAdemeFileJson(ademeId);
138
+ dpeRequest = normalizerService.normalize(dpeRequest);
139
+
140
+ /** @type {Contexte} */
141
+ const ctx = contexteBuilder.fromDpe(dpeRequest);
142
+
143
+ installationEcsService.execute(ctx, dpeRequest.logement, {
144
+ besoin_ecs: dpeRequest.logement.sortie.apport_et_besoin.besoin_ecs,
145
+ besoin_ecs_depensier: dpeRequest.logement.sortie.apport_et_besoin.besoin_ecs_depensier
146
+ });
147
+
148
+ const pertesStockage = service.execute(ctx, dpeRequest.logement);
149
+
150
+ expect_or(
151
+ () =>
152
+ expect(pertesStockage.pertes_distribution_ecs_recup).toBeCloseTo(
153
+ dpeRequest.logement.sortie.apport_et_besoin.pertes_distribution_ecs_recup
154
+ ),
155
+ () =>
156
+ expect(pertesStockage.pertes_distribution_ecs_recup * 1000).toBeCloseTo(
157
+ dpeRequest.logement.sortie.apport_et_besoin.pertes_distribution_ecs_recup
158
+ )
159
+ );
160
+ }
161
+ );
162
+
163
+ test.each(corpus)(
164
+ 'vérification des pertes de distribution ecs recup depensier des installations ECS pour dpe %s',
165
+ (ademeId) => {
166
+ let dpeRequest = getAdemeFileJson(ademeId);
167
+ dpeRequest = normalizerService.normalize(dpeRequest);
168
+
169
+ /** @type {Contexte} */
170
+ const ctx = contexteBuilder.fromDpe(dpeRequest);
171
+
172
+ installationEcsService.execute(ctx, dpeRequest.logement, {
173
+ besoin_ecs: dpeRequest.logement.sortie.apport_et_besoin.besoin_ecs,
174
+ besoin_ecs_depensier: dpeRequest.logement.sortie.apport_et_besoin.besoin_ecs_depensier
175
+ });
176
+
177
+ const pertesStockage = service.execute(ctx, dpeRequest.logement);
178
+
179
+ expect_or(
180
+ () =>
181
+ expect(pertesStockage.pertes_distribution_ecs_recup_depensier).toBeCloseTo(
182
+ dpeRequest.logement.sortie.apport_et_besoin.pertes_distribution_ecs_recup_depensier
183
+ ),
184
+ () =>
185
+ expect(pertesStockage.pertes_distribution_ecs_recup_depensier * 1000).toBeCloseTo(
186
+ dpeRequest.logement.sortie.apport_et_besoin.pertes_distribution_ecs_recup_depensier
187
+ )
188
+ );
189
+ }
190
+ );
191
+
192
+ test.each(corpus)(
193
+ 'vérification des pertes de stockage ecs recup des installations ECS pour dpe %s',
194
+ (ademeId) => {
195
+ let dpeRequest = getAdemeFileJson(ademeId);
196
+ dpeRequest = normalizerService.normalize(dpeRequest);
197
+
198
+ /** @type {Contexte} */
199
+ const ctx = contexteBuilder.fromDpe(dpeRequest);
200
+
201
+ installationEcsService.execute(ctx, dpeRequest.logement, {
202
+ besoin_ecs: dpeRequest.logement.sortie.apport_et_besoin.besoin_ecs,
203
+ besoin_ecs_depensier: dpeRequest.logement.sortie.apport_et_besoin.besoin_ecs_depensier
204
+ });
205
+
206
+ const pertesStockage = service.execute(ctx, dpeRequest.logement);
207
+ expect_or(
208
+ () =>
209
+ expect(pertesStockage.pertes_stockage_ecs_recup).toBeCloseTo(
210
+ dpeRequest.logement.sortie.apport_et_besoin.pertes_stockage_ecs_recup
211
+ ),
212
+ () =>
213
+ expect(pertesStockage.pertes_stockage_ecs_recup * 1000).toBeCloseTo(
214
+ dpeRequest.logement.sortie.apport_et_besoin.pertes_stockage_ecs_recup
215
+ )
216
+ );
217
+ }
218
+ );
219
+ });
220
+ });
@@ -132,8 +132,12 @@ export class ContexteBuilder {
132
132
 
133
133
  if ([1, 14, 18].includes(methodeApplication)) {
134
134
  return TypeDpe.MAISON;
135
- } else if ([2, 3, 4, 5, 31, 32, 35, 36, 37].includes(methodeApplication)) {
135
+ } else if (
136
+ [2, 3, 4, 5, 15, 16, 19, 20, 22, 23, 24, 25, 31, 32, 35, 36, 37].includes(methodeApplication)
137
+ ) {
136
138
  return TypeDpe.APPARTEMENT;
139
+ } else if ([10, 11, 12, 13, 33, 34, 38, 39, 40].includes(methodeApplication)) {
140
+ return TypeDpe.APPARTEMENT_A_PARTIR_IMMEUBLE;
137
141
  }
138
142
  return TypeDpe.IMMEUBLE;
139
143
  }