@open3cl/engine 1.6.2 → 1.7.1

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 (51) hide show
  1. package/10_besoin_fr.spec.js +1 -0
  2. package/10_clim.spec.js +1 -0
  3. package/11_besoin_ecs.spec.js +1 -0
  4. package/11_ecs.spec.js +1 -0
  5. package/12.4_pac.spec.js +1 -0
  6. package/13.2_generateur_combustion.spec.js +3 -3
  7. package/13.2_generateur_combustion_ch.spec.js +3 -3
  8. package/14_generateur_ecs.spec.js +1 -0
  9. package/15_conso_aux.js +121 -1
  10. package/15_conso_aux.spec.js +329 -4
  11. package/2021_04_13_confort_ete.spec.js +1 -0
  12. package/3.1_b.spec.js +1 -0
  13. package/3.2.1_mur.spec.js +1 -0
  14. package/3.2.2_plancher_bas.spec.js +1 -0
  15. package/3.2.3_plancher_haut.spec.js +1 -0
  16. package/3.3.1.4_porte.spec.js +1 -0
  17. package/3.3_baie_vitree.spec.js +1 -0
  18. package/3.4_pont_thermique.spec.js +1 -0
  19. package/4_ventilation.spec.js +1 -0
  20. package/5_conso_ventilation.spec.js +1 -0
  21. package/6.2_surface_sud_equivalente.js +2 -1
  22. package/6.2_surface_sud_equivalente.spec.js +1 -0
  23. package/9_besoin_ch.spec.js +1 -0
  24. package/9_chauffage.spec.js +3 -3
  25. package/9_conso_ch.spec.js +1 -0
  26. package/9_emetteur_ch.spec.js +1 -0
  27. package/9_generateur_ch.spec.js +1 -0
  28. package/README.md +412 -291
  29. package/conso.js +20 -6
  30. package/conso.spec.js +21 -0
  31. package/engine.js +19 -1
  32. package/engine.spec.js +96 -0
  33. package/package.json +15 -14
  34. package/features/engine/domain/apport_et_besoin/apport-et-besoin.service.spec.js +0 -222
  35. package/features/engine/domain/apport_et_besoin/ch/perte-ch-recup.service.spec.js +0 -345
  36. package/features/engine/domain/apport_et_besoin/ecs/besoin-ecs.service.spec.js +0 -87
  37. package/features/engine/domain/apport_et_besoin/ecs/perte-ecs-recup.service.spec.js +0 -260
  38. package/features/engine/domain/apport_et_besoin/froid/besoin-froid.service.spec.js +0 -272
  39. package/features/engine/domain/apport_et_besoin/surface-sud-equivalente.service.spec.js +0 -231
  40. package/features/engine/domain/ch/generateur-ch.service.spec.js +0 -849
  41. package/features/engine/domain/conso/froid/conso-froid.service.spec.js +0 -233
  42. package/features/engine/domain/ecs/installation-ecs.service.spec.js +0 -337
  43. package/features/engine/domain/enveloppe/baie_vitree/deperdition-baie-vitree.service.spec.js +0 -607
  44. package/features/engine/domain/enveloppe/deperdition-enveloppe.service.spec.js +0 -550
  45. package/features/engine/domain/enveloppe/espace_tampon/espace-tampon.service.spec.js +0 -82
  46. package/features/engine/domain/enveloppe/mur/deperdition-mur.service.spec.js +0 -542
  47. package/features/engine/domain/enveloppe/plancher_bas/deperdition-plancher-bas.service.spec.js +0 -430
  48. package/features/engine/domain/enveloppe/plancher_haut/deperdition-plancher-haut.service.spec.js +0 -411
  49. package/features/engine/domain/enveloppe/pont_thermique/deperdition-pont-thermique.service.spec.js +0 -653
  50. package/features/engine/domain/enveloppe/porte/deperdition-porte.service.spec.js +0 -117
  51. package/features/engine/domain/enveloppe/ventilation/deperdition-ventilation.service.spec.js +0 -508
@@ -1,345 +0,0 @@
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
- import { describeIntegration } from '../../../../../../test/helpers/integration-test.js';
13
-
14
- /** @type {PerteChRecupService} **/
15
- let service;
16
-
17
- /** @type {BesoinChService} **/
18
- let besoinChService;
19
-
20
- /** @type {ApportGratuitService} **/
21
- let apportGratuitService;
22
-
23
- /** @type {FrTvStore} **/
24
- let tvStore;
25
-
26
- /** @type {DpeNormalizerService} **/
27
- let normalizerService;
28
-
29
- /** @type {ContexteBuilder} **/
30
- let contexteBuilder;
31
-
32
- describe('Calcul des pertes de génération de chauffage récupérées', () => {
33
- beforeEach(() => {
34
- tvStore = new FrTvStore();
35
- service = new PerteChRecupService(tvStore);
36
- besoinChService = new BesoinChService();
37
- apportGratuitService = new ApportGratuitService();
38
- normalizerService = new DpeNormalizerService();
39
- contexteBuilder = new ContexteBuilder();
40
- });
41
-
42
- test.each([
43
- {
44
- label: 'Installation CH uniquement avec ventouse, utilisation de nref',
45
- enumUsageGenerateurId: 1,
46
- presenceVentouse: 1,
47
- expected: 562.5
48
- },
49
- {
50
- label: 'Installation CH uniquement sans ventouse, utilisation de nref',
51
- enumUsageGenerateurId: 1,
52
- presenceVentouse: 0,
53
- expected: 375
54
- },
55
- {
56
- label: "Installation CH uniquement sans ventouse, pas d'utilisation de nref",
57
- enumUsageGenerateurId: 1,
58
- presenceVentouse: 0,
59
- nref: 500,
60
- expected: 7971.08
61
- },
62
- {
63
- label: 'Installation ECS uniquement avec ventouse',
64
- enumUsageGenerateurId: 2,
65
- presenceVentouse: 1,
66
- expected: 114.94
67
- },
68
- {
69
- label: 'Installation ECS uniquement sans ventouse',
70
- enumUsageGenerateurId: 2,
71
- presenceVentouse: 0,
72
- expected: 76.627
73
- },
74
- {
75
- label: 'Installation ECS + CH avec ventouse, utilisation de nref',
76
- enumUsageGenerateurId: 3,
77
- presenceVentouse: 1,
78
- expected: 562.5
79
- },
80
- {
81
- label: 'Installation ECS + CH sans ventouse, utilisation de nref',
82
- enumUsageGenerateurId: 3,
83
- presenceVentouse: 0,
84
- expected: 375
85
- },
86
- {
87
- label: "Installation ECS + CH sans ventouse, pas d'utilisation de nref",
88
- enumUsageGenerateurId: 3,
89
- presenceVentouse: 0,
90
- nref: 450,
91
- expected: 10729.642
92
- }
93
- ])(
94
- 'Calcul des pertes récupérées de génération pour le chauffage sur un mois pour $label',
95
- ({ enumUsageGenerateurId, presenceVentouse, nref = undefined, expected }) => {
96
- /** @type {GenerateurChauffage[]} */
97
- const generateurs = [
98
- {
99
- donnee_entree: {
100
- presence_ventouse: presenceVentouse,
101
- enum_usage_generateur_id: enumUsageGenerateurId
102
- },
103
- donnee_intermediaire: { pn: 25000, qp0: 125 }
104
- }
105
- ];
106
-
107
- expect(service.Qrec(generateurs, nref ?? 12.5, 1532.9)).toBeCloseTo(expected, 3);
108
- }
109
- );
110
-
111
- test('Filtre des générateurs avec pertes de génération', () => {
112
- const generateur1 = {
113
- donnee_entree: {}
114
- };
115
- const generateur2 = {
116
- donnee_entree: { position_volume_chauffe: 0, enum_type_generateur_ch_id: 45 }
117
- };
118
- const generateur3 = {
119
- donnee_entree: { position_volume_chauffe: 0, enum_type_generateur_ch_id: 50 }
120
- };
121
- const generateur4 = {
122
- donnee_entree: { position_volume_chauffe: 1, enum_type_generateur_ch_id: 50 }
123
- };
124
- const generateur5 = {
125
- donnee_entree: { position_volume_chauffe: 1, enum_type_generateur_ch_id: 48 }
126
- };
127
-
128
- /** @type {Logement} */
129
- let logement = { installation_chauffage_collection: {} };
130
- expect(service.generateursWithPertesGeneration(logement)).toStrictEqual([]);
131
-
132
- logement.installation_chauffage_collection = { installation_chauffage: [] };
133
- expect(service.generateursWithPertesGeneration(logement)).toStrictEqual([]);
134
-
135
- logement.installation_chauffage_collection = {
136
- installation_chauffage: [{ generateur_chauffage_collection: {} }]
137
- };
138
- expect(service.generateursWithPertesGeneration(logement)).toStrictEqual([]);
139
-
140
- logement.installation_chauffage_collection = {
141
- installation_chauffage: [{ generateur_chauffage_collection: { generateur_chauffage: [] } }]
142
- };
143
- expect(service.generateursWithPertesGeneration(logement)).toStrictEqual([]);
144
-
145
- logement.installation_chauffage_collection = {
146
- installation_chauffage: [
147
- {
148
- generateur_chauffage_collection: {
149
- generateur_chauffage: [generateur1, generateur2, generateur3]
150
- }
151
- },
152
- { generateur_chauffage_collection: { generateur_chauffage: [generateur4, generateur5] } }
153
- ]
154
- };
155
- expect(service.generateursWithPertesGeneration(logement)).toStrictEqual([generateur5]);
156
- });
157
-
158
- test.each([
159
- {
160
- label: 'Installation CH en mode conventionnel',
161
- depensier: false,
162
- expected: 288
163
- },
164
- {
165
- label: 'Installation CH en mode dépensier',
166
- depensier: true,
167
- expected: 540
168
- }
169
- ])('Pertes de chauffage récupérées pour $label', ({ depensier, expected }) => {
170
- vi.spyOn(tvStore, 'getData').mockReturnValue(depensier ? 1.5 : 0.8);
171
-
172
- /** @type {Contexte} */
173
- const ctx = {
174
- altitude: { value: '400-800m' },
175
- zoneClimatique: { value: 'h1a' },
176
- inertie: { ilpa: 1 }
177
- };
178
-
179
- /** @type {Logement} */
180
- const logement = {
181
- installation_chauffage_collection: {
182
- installation_chauffage: [
183
- {
184
- generateur_chauffage_collection: {
185
- generateur_chauffage: [
186
- {
187
- donnee_entree: {
188
- position_volume_chauffe: 1,
189
- enum_type_generateur_ch_id: 48,
190
- enum_usage_generateur_id: 1
191
- },
192
- donnee_intermediaire: { pn: 25000, qp0: 125 }
193
- }
194
- ]
195
- }
196
- }
197
- ]
198
- },
199
- donnees_de_calcul: {
200
- besoinChauffageHP: {
201
- Janvier: 102.5,
202
- Février: 102.5,
203
- Mars: 102.5,
204
- Avril: 102.5,
205
- Mai: 102.5,
206
- Juin: 102.5,
207
- Juillet: 102.5,
208
- Aout: 102.5,
209
- Septembre: 102.5,
210
- Octobre: 102.5,
211
- Novembre: 102.5,
212
- Décembre: 102.5
213
- },
214
- besoinChauffageDepensierHP: {
215
- Janvier: 112.5,
216
- Février: 112.5,
217
- Mars: 112.5,
218
- Avril: 112.5,
219
- Mai: 112.5,
220
- Juin: 112.5,
221
- Juillet: 112.5,
222
- Aout: 112.5,
223
- Septembre: 112.5,
224
- Octobre: 112.5,
225
- Novembre: 112.5,
226
- Décembre: 112.5
227
- }
228
- }
229
- };
230
-
231
- expect(service.pertesGenerateurChRecup(ctx, logement, depensier)).toBeCloseTo(expected, 3);
232
- for (const mois of mois_liste) {
233
- expect(tvStore.getData).toHaveBeenCalledWith(
234
- depensier ? 'nref21' : 'nref19',
235
- '400-800m',
236
- 'h1a',
237
- mois,
238
- 1
239
- );
240
- }
241
- });
242
-
243
- test('Qrec vaut 0 pour un usage de générateur inconnu (aucune durée de récupération)', () => {
244
- // enum_usage_generateur_id hors {1, 2, 3} : le switch ne définit pas Dperj (undefined),
245
- // le produit devient NaN et la garde `|| 0` ramène la contribution à 0.
246
- /** @type {GenerateurChauffage[]} */
247
- const generateurs = [
248
- {
249
- donnee_entree: { presence_ventouse: 0, enum_usage_generateur_id: 99 },
250
- donnee_intermediaire: { pn: 25000, qp0: 125 }
251
- }
252
- ];
253
-
254
- expect(service.Qrec(generateurs, 12.5, 1532.9)).toBe(0);
255
- });
256
-
257
- test('Conversion en kWh des pertes de génération récupérées (execute)', () => {
258
- // On isole execute de la formule mensuelle : pertesGenerateurChRecup est doublée pour
259
- // ne vérifier que la conversion Wh -> kWh (division par 1000) et le mapping des 2 champs.
260
- vi.spyOn(service, 'pertesGenerateurChRecup').mockImplementation((ctx, logement, depensier) =>
261
- depensier ? 6000 : 3000
262
- );
263
-
264
- const res = service.execute({}, {});
265
-
266
- expect(res).toStrictEqual({
267
- pertes_generateur_ch_recup: 3,
268
- pertes_generateur_ch_recup_depensier: 6
269
- });
270
- expect(service.pertesGenerateurChRecup).toHaveBeenCalledWith({}, {}, false);
271
- expect(service.pertesGenerateurChRecup).toHaveBeenCalledWith({}, {}, true);
272
- });
273
-
274
- describeIntegration("Test d'intégration des installations CH", () => {
275
- test.each(corpus)('vérification des pertes de génération ch pour dpe %s', (ademeId) => {
276
- let dpeRequest = getAdemeFileJson(ademeId);
277
- dpeRequest = normalizerService.normalize(dpeRequest);
278
- dpeRequest.logement.donnees_de_calcul = {
279
- apportsInterneDepensier: [],
280
- apportsInterneCh: [],
281
- apportsSolaire: [],
282
- besoinChauffageHP: [],
283
- besoinChauffageDepensierHP: []
284
- };
285
-
286
- /** @type {Contexte} */
287
- const ctx = contexteBuilder.fromDpe(dpeRequest);
288
- apportGratuitService.apportInterne(ctx, dpeRequest.logement);
289
- apportGratuitService.apportSolaire(ctx, dpeRequest.logement);
290
- besoinChService.execute(ctx, dpeRequest.logement);
291
- const pertesGeneration = service.execute(ctx, dpeRequest.logement);
292
-
293
- const expectedValue = dpeRequest.logement.sortie.apport_et_besoin.pertes_generateur_ch_recup;
294
- const calculatedValue = pertesGeneration.pertes_generateur_ch_recup;
295
-
296
- expect_or(
297
- () =>
298
- expect(Math.abs(calculatedValue - expectedValue) / (expectedValue || 1)).toBeLessThan(
299
- PRECISION_PERCENT
300
- ),
301
- () =>
302
- expect(
303
- Math.abs(calculatedValue - expectedValue * 1000) / (expectedValue * 1000 || 1)
304
- ).toBeLessThan(PRECISION_PERCENT)
305
- );
306
- });
307
-
308
- test.each(corpus)(
309
- 'vérification des pertes de génération ch depensier des installations CH pour dpe %s',
310
- (ademeId) => {
311
- let dpeRequest = getAdemeFileJson(ademeId);
312
- dpeRequest = normalizerService.normalize(dpeRequest);
313
- dpeRequest.logement.donnees_de_calcul = {
314
- apportsInterneDepensier: [],
315
- apportsInterneCh: [],
316
- apportsSolaire: [],
317
- besoinChauffageHP: [],
318
- besoinChauffageDepensierHP: []
319
- };
320
-
321
- /** @type {Contexte} */
322
- const ctx = contexteBuilder.fromDpe(dpeRequest);
323
- apportGratuitService.apportInterne(ctx, dpeRequest.logement);
324
- apportGratuitService.apportSolaire(ctx, dpeRequest.logement);
325
- besoinChService.execute(ctx, dpeRequest.logement);
326
- const pertesGeneration = service.execute(ctx, dpeRequest.logement);
327
-
328
- const expectedValue =
329
- dpeRequest.logement.sortie.apport_et_besoin.pertes_generateur_ch_recup_depensier;
330
- const calculatedValue = pertesGeneration.pertes_generateur_ch_recup_depensier;
331
-
332
- expect_or(
333
- () =>
334
- expect(Math.abs(calculatedValue - expectedValue) / (expectedValue || 1)).toBeLessThan(
335
- PRECISION_PERCENT
336
- ),
337
- () =>
338
- expect(
339
- Math.abs(calculatedValue - expectedValue * 1000) / (expectedValue * 1000 || 1)
340
- ).toBeLessThan(PRECISION_PERCENT)
341
- );
342
- }
343
- );
344
- });
345
- });
@@ -1,87 +0,0 @@
1
- import corpus from '../../../../../../test/corpus-sano.json';
2
- import { beforeEach, describe, expect, test, vi } from 'vitest';
3
- import { DpeNormalizerService } from '../../../../normalizer/domain/dpe-normalizer.service.js';
4
- import { ContexteBuilder } from '../../contexte.builder.js';
5
- import { getAdemeFileJson } from '../../../../../../test/test-helpers.js';
6
- import { BesoinEcsService } from './besoin-ecs.service.js';
7
- import { EcsTvStore } from '../../../../dpe/infrastructure/ecs/ecsTv.store.js';
8
- import { describeIntegration } from '../../../../../../test/helpers/integration-test.js';
9
-
10
- /** @type {BesoinEcsService} **/
11
- let service;
12
-
13
- /** @type {DpeNormalizerService} **/
14
- let normalizerService;
15
-
16
- /** @type {ContexteBuilder} **/
17
- let contexteBuilder;
18
-
19
- /** @type {EcsTvStore} **/
20
- let tvStore;
21
-
22
- describe('Calcul du besoin en eau chaude sanitaire', () => {
23
- beforeEach(() => {
24
- tvStore = new EcsTvStore();
25
- service = new BesoinEcsService(tvStore);
26
- normalizerService = new DpeNormalizerService();
27
- contexteBuilder = new ContexteBuilder();
28
- });
29
-
30
- test('Determination du besoin en eau chaude sanitaire pour un mois donné', () => {
31
- vi.spyOn(tvStore, 'getTefs').mockReturnValue(0.5);
32
-
33
- /** @type {Contexte} */
34
- const ctx = {
35
- altitude: {
36
- value: '400-800m'
37
- },
38
- zoneClimatique: {
39
- value: 'h1a'
40
- },
41
- nadeq: 2
42
- };
43
-
44
- expect(service.besoinEcsMois(ctx, 'Janvier', false)).toBeCloseTo(159.5, 2);
45
- expect(service.besoinEcsMois(ctx, 'Janvier', true)).toBeCloseTo(225.01, 2);
46
- expect(tvStore.getTefs).toHaveBeenCalledWith('400-800m', 'h1a', 'Janvier');
47
- });
48
-
49
- test("Sommation du besoin ECS sur les douze mois de l'année", () => {
50
- // On isole execute de la formule mensuelle : besoinEcsMois est doublé pour ne mesurer
51
- // que la logique d'agrégation (une valeur conventionnelle, une valeur dépensière par mois).
52
- vi.spyOn(service, 'besoinEcsMois').mockImplementation((ctx, mois, depensier) =>
53
- depensier ? 10 : 1
54
- );
55
-
56
- /** @type {Contexte} */
57
- const ctx = { altitude: { value: '400-800m' }, zoneClimatique: { value: 'h1a' }, nadeq: 2 };
58
-
59
- const res = service.execute(ctx);
60
-
61
- // 12 mois : conventionnel = 12 * 1, dépensier = 12 * 10
62
- expect(res).toStrictEqual({ besoin_ecs: 12, besoin_ecs_depensier: 120 });
63
- expect(service.besoinEcsMois).toHaveBeenCalledTimes(24);
64
- expect(service.besoinEcsMois).toHaveBeenCalledWith(ctx, 'Janvier', false);
65
- expect(service.besoinEcsMois).toHaveBeenCalledWith(ctx, 'Janvier', true);
66
- });
67
-
68
- describeIntegration("Test d'intégration pour le besoin en eau chaude sanitaire", () => {
69
- test.each(corpus)('vérification des sorties besoin_ecs pour dpe %s', (ademeId) => {
70
- /**
71
- * @type {Dpe}
72
- */
73
- let dpeRequest = getAdemeFileJson(ademeId);
74
- dpeRequest = normalizerService.normalize(dpeRequest);
75
-
76
- /** @type {Contexte} */
77
- const ctx = contexteBuilder.fromDpe(dpeRequest);
78
-
79
- const ecs = service.execute(ctx);
80
- expect(ecs.besoin_ecs).toBeCloseTo(dpeRequest.logement.sortie.apport_et_besoin.besoin_ecs, 2);
81
- expect(ecs.besoin_ecs_depensier).toBeCloseTo(
82
- dpeRequest.logement.sortie.apport_et_besoin.besoin_ecs_depensier,
83
- 2
84
- );
85
- });
86
- });
87
- });
@@ -1,260 +0,0 @@
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
- import { describeIntegration } from '../../../../../../test/helpers/integration-test.js';
13
-
14
- /** @type {PerteEcsRecupService} **/
15
- let service;
16
-
17
- /** @type {FrTvStore} **/
18
- let tvStore;
19
-
20
- /** @type {InstallationEcsService} **/
21
- let installationEcsService;
22
-
23
- /** @type {DpeNormalizerService} **/
24
- let normalizerService;
25
-
26
- /** @type {ContexteBuilder} **/
27
- let contexteBuilder;
28
-
29
- describe('Calcul des pertes de distribution et stockage récupérées', () => {
30
- beforeEach(() => {
31
- tvStore = new FrTvStore();
32
- service = new PerteEcsRecupService(tvStore);
33
- installationEcsService = new InstallationEcsService(new GenerateurEcsService(new EcsTvStore()));
34
- normalizerService = new DpeNormalizerService();
35
- contexteBuilder = new ContexteBuilder();
36
- });
37
-
38
- test.each([
39
- {
40
- label: 'Installation ECS en mode conventionnel',
41
- depensier: false,
42
- expected: 0.192
43
- },
44
- {
45
- label: 'Installation ECS en mode dépensier',
46
- depensier: true,
47
- expected: 0.725
48
- }
49
- ])('Calcul des pertes de distribution récupérées pour $label', ({ depensier, expected }) => {
50
- vi.spyOn(tvStore, 'getData').mockReturnValue(depensier ? 1.5 : 0.8);
51
-
52
- /** @type {Contexte} */
53
- const ctx = {
54
- altitude: { value: '400-800m' },
55
- zoneClimatique: { value: 'h1a' },
56
- inertie: { ilpa: 1 }
57
- };
58
-
59
- /** @type {Logement} */
60
- const logement = {
61
- installation_ecs_collection: {
62
- installation_ecs: [
63
- {
64
- donnee_utilisateur: {
65
- QdwIndVc: { conventionnel: 100, depensier: 200 },
66
- QdwColVc: { conventionnel: 50, depensier: 120 }
67
- }
68
- },
69
- {
70
- donnee_utilisateur: {
71
- QdwIndVc: { conventionnel: 150, depensier: 280 },
72
- QdwColVc: { conventionnel: 65, depensier: 135 }
73
- }
74
- }
75
- ]
76
- }
77
- };
78
-
79
- expect(service.pertesDistributionEcsRecup(ctx, logement, depensier)).toBeCloseTo(expected, 3);
80
- for (const mois of mois_liste) {
81
- expect(tvStore.getData).toHaveBeenCalledWith(
82
- depensier ? 'nref21' : 'nref19',
83
- '400-800m',
84
- 'h1a',
85
- mois,
86
- 1
87
- );
88
- }
89
- });
90
-
91
- test.each([
92
- {
93
- label: 'Installation ECS en mode conventionnel',
94
- depensier: false,
95
- expected: 63.209
96
- },
97
- {
98
- label: 'Installation ECS en mode dépensier',
99
- depensier: true,
100
- expected: 118.516
101
- }
102
- ])('Calcul des pertes de stockage récupérées pour $label', ({ depensier, expected }) => {
103
- vi.spyOn(tvStore, 'getData').mockReturnValue(depensier ? 1.5 : 0.8);
104
-
105
- /** @type {Contexte} */
106
- const ctx = {
107
- altitude: { value: '400-800m' },
108
- zoneClimatique: { value: 'h1a' },
109
- inertie: { ilpa: 1 }
110
- };
111
-
112
- /** @type {Logement} */
113
- const logement = {
114
- installation_ecs_collection: {
115
- installation_ecs: [
116
- { donnee_utilisateur: { QgwRecuperable: 120012 } },
117
- { donnee_utilisateur: { QgwRecuperable: 150 } }
118
- ]
119
- }
120
- };
121
-
122
- expect(service.pertesStockageEcsRecup(ctx, logement, depensier)).toBeCloseTo(expected, 3);
123
- for (const mois of mois_liste) {
124
- expect(tvStore.getData).toHaveBeenCalledWith(
125
- depensier ? 'nref21' : 'nref19',
126
- '400-800m',
127
- 'h1a',
128
- mois,
129
- 1
130
- );
131
- }
132
- });
133
-
134
- test('Agrégation et conversion en kWh des pertes ECS récupérées (execute)', () => {
135
- // On isole execute des formules mensuelles : les deux méthodes de calcul sont doublées
136
- // pour ne vérifier que la conversion Wh -> kWh (division par 1000) et le mapping des 4 champs.
137
- vi.spyOn(service, 'pertesDistributionEcsRecup').mockImplementation(
138
- (ctx, logement, depensier) => (depensier ? 2000 : 1000)
139
- );
140
- vi.spyOn(service, 'pertesStockageEcsRecup').mockImplementation((ctx, logement, depensier) =>
141
- depensier ? 4000 : 3000
142
- );
143
-
144
- const res = service.execute({}, {});
145
-
146
- expect(res).toStrictEqual({
147
- pertes_distribution_ecs_recup: 1,
148
- pertes_distribution_ecs_recup_depensier: 2,
149
- pertes_stockage_ecs_recup: 3,
150
- pertes_stockage_ecs_recup_depensier: 4
151
- });
152
- expect(service.pertesDistributionEcsRecup).toHaveBeenCalledWith({}, {}, false);
153
- expect(service.pertesDistributionEcsRecup).toHaveBeenCalledWith({}, {}, true);
154
- expect(service.pertesStockageEcsRecup).toHaveBeenCalledWith({}, {}, false);
155
- expect(service.pertesStockageEcsRecup).toHaveBeenCalledWith({}, {}, true);
156
- });
157
-
158
- test("Pertes nulles en l'absence d'installation ECS", () => {
159
- // Valeur de repli [] quand installation_ecs_collection est absente : aucune installation à sommer.
160
- vi.spyOn(tvStore, 'getData').mockReturnValue(1);
161
-
162
- /** @type {Contexte} */
163
- const ctx = {
164
- altitude: { value: '400-800m' },
165
- zoneClimatique: { value: 'h1a' },
166
- inertie: { ilpa: 0 }
167
- };
168
-
169
- expect(service.pertesDistributionEcsRecup(ctx, {}, false)).toBe(0);
170
- expect(service.pertesStockageEcsRecup(ctx, {}, false)).toBe(0);
171
- });
172
-
173
- describeIntegration("Test d'intégration des installations ECS", () => {
174
- test.each(corpus)(
175
- 'vérification des pertes de distribution ecs recup des installations ECS pour dpe %s',
176
- (ademeId) => {
177
- let dpeRequest = getAdemeFileJson(ademeId);
178
- dpeRequest = normalizerService.normalize(dpeRequest);
179
-
180
- /** @type {Contexte} */
181
- const ctx = contexteBuilder.fromDpe(dpeRequest);
182
-
183
- installationEcsService.execute(ctx, dpeRequest.logement, {
184
- besoin_ecs: dpeRequest.logement.sortie.apport_et_besoin.besoin_ecs,
185
- besoin_ecs_depensier: dpeRequest.logement.sortie.apport_et_besoin.besoin_ecs_depensier
186
- });
187
-
188
- const pertesStockage = service.execute(ctx, dpeRequest.logement);
189
-
190
- expect_or(
191
- () =>
192
- expect(pertesStockage.pertes_distribution_ecs_recup).toBeCloseTo(
193
- dpeRequest.logement.sortie.apport_et_besoin.pertes_distribution_ecs_recup
194
- ),
195
- () =>
196
- expect(pertesStockage.pertes_distribution_ecs_recup * 1000).toBeCloseTo(
197
- dpeRequest.logement.sortie.apport_et_besoin.pertes_distribution_ecs_recup
198
- )
199
- );
200
- }
201
- );
202
-
203
- test.each(corpus)(
204
- 'vérification des pertes de distribution ecs recup depensier des installations ECS pour dpe %s',
205
- (ademeId) => {
206
- let dpeRequest = getAdemeFileJson(ademeId);
207
- dpeRequest = normalizerService.normalize(dpeRequest);
208
-
209
- /** @type {Contexte} */
210
- const ctx = contexteBuilder.fromDpe(dpeRequest);
211
-
212
- installationEcsService.execute(ctx, dpeRequest.logement, {
213
- besoin_ecs: dpeRequest.logement.sortie.apport_et_besoin.besoin_ecs,
214
- besoin_ecs_depensier: dpeRequest.logement.sortie.apport_et_besoin.besoin_ecs_depensier
215
- });
216
-
217
- const pertesStockage = service.execute(ctx, dpeRequest.logement);
218
-
219
- expect_or(
220
- () =>
221
- expect(pertesStockage.pertes_distribution_ecs_recup_depensier).toBeCloseTo(
222
- dpeRequest.logement.sortie.apport_et_besoin.pertes_distribution_ecs_recup_depensier
223
- ),
224
- () =>
225
- expect(pertesStockage.pertes_distribution_ecs_recup_depensier * 1000).toBeCloseTo(
226
- dpeRequest.logement.sortie.apport_et_besoin.pertes_distribution_ecs_recup_depensier
227
- )
228
- );
229
- }
230
- );
231
-
232
- test.each(corpus)(
233
- 'vérification des pertes de stockage ecs recup des installations ECS pour dpe %s',
234
- (ademeId) => {
235
- let dpeRequest = getAdemeFileJson(ademeId);
236
- dpeRequest = normalizerService.normalize(dpeRequest);
237
-
238
- /** @type {Contexte} */
239
- const ctx = contexteBuilder.fromDpe(dpeRequest);
240
-
241
- installationEcsService.execute(ctx, dpeRequest.logement, {
242
- besoin_ecs: dpeRequest.logement.sortie.apport_et_besoin.besoin_ecs,
243
- besoin_ecs_depensier: dpeRequest.logement.sortie.apport_et_besoin.besoin_ecs_depensier
244
- });
245
-
246
- const pertesStockage = service.execute(ctx, dpeRequest.logement);
247
- expect_or(
248
- () =>
249
- expect(pertesStockage.pertes_stockage_ecs_recup).toBeCloseTo(
250
- dpeRequest.logement.sortie.apport_et_besoin.pertes_stockage_ecs_recup
251
- ),
252
- () =>
253
- expect(pertesStockage.pertes_stockage_ecs_recup * 1000).toBeCloseTo(
254
- dpeRequest.logement.sortie.apport_et_besoin.pertes_stockage_ecs_recup
255
- )
256
- );
257
- }
258
- );
259
- });
260
- });