@open3cl/engine 1.6.1 → 1.7.0
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.
- package/10_besoin_fr.spec.js +122 -0
- package/10_clim.spec.js +116 -0
- package/11_besoin_ecs.spec.js +69 -0
- package/11_ecs.spec.js +282 -0
- package/11_nadeq.spec.js +37 -0
- package/12.4_pac.spec.js +131 -0
- package/13.2_generateur_combustion.js +2 -0
- package/13.2_generateur_combustion.spec.js +537 -0
- package/13.2_generateur_combustion_bouilleur.js +4 -1
- package/13.2_generateur_combustion_bouilleur.spec.js +74 -0
- package/13.2_generateur_combustion_ch.spec.js +323 -0
- package/13.2_generateur_combustion_chaudiere.spec.js +85 -0
- package/13.2_generateur_pac.spec.js +64 -0
- package/13_rendement_distribution_ecs.spec.js +38 -0
- package/14_generateur_ecs.js +4 -4
- package/14_generateur_ecs.spec.js +745 -0
- package/15_conso_aux.js +121 -1
- package/15_conso_aux.spec.js +550 -0
- package/16.2_production_enr.spec.js +188 -0
- package/16_conso_eclairage.spec.js +62 -0
- package/2021_04_13_confort_ete.spec.js +159 -0
- package/2021_04_13_qualite_isolation.js +1 -1
- package/2021_04_13_qualite_isolation.spec.js +286 -0
- package/3.1_b.js +1 -1
- package/3.1_b.spec.js +367 -0
- package/3.2.1_mur.spec.js +812 -39
- package/3.2.2_plancher_bas.spec.js +643 -78
- package/3.2.3_plancher_haut.spec.js +452 -0
- package/3.3.1.4_porte.spec.js +114 -0
- package/3.3_baie_vitree.spec.js +449 -295
- package/3.4_pont_thermique.spec.js +890 -0
- package/3_deperdition.spec.js +397 -0
- package/4_ventilation.js +1 -1
- package/4_ventilation.spec.js +406 -0
- package/5_conso_ventilation.spec.js +186 -0
- package/6.2_surface_sud_equivalente.js +2 -1
- package/6.2_surface_sud_equivalente.spec.js +138 -0
- package/8_intermittence.spec.js +33 -0
- package/9_besoin_ch.js +2 -2
- package/9_besoin_ch.spec.js +381 -0
- package/9_chauffage.js +4 -0
- package/9_chauffage.spec.js +478 -92
- package/9_conso_ch.spec.js +502 -248
- package/9_emetteur_ch.spec.js +339 -0
- package/9_generateur_ch.spec.js +467 -81
- package/apport_et_besoin.spec.js +126 -0
- package/conso.js +21 -7
- package/conso.spec.js +491 -82
- package/core/assets/domain/add-additionnal-ue-values-tables.spec.js +53 -0
- package/core/assets/domain/synchronize-solicitations-tables.spec.js +25 -0
- package/core/assets/domain/synchronize-valeur-tables.spec.js +48 -0
- package/core/conf/infrastructure/application.config.spec.js +35 -0
- package/core/file/infrastructure/adapter/csv-parser.store.spec.js +31 -13
- package/core/file/infrastructure/adapter/file.store.spec.js +148 -12
- package/core/tv/infrastructure/assets/additional-ue-values.spec.js +36 -0
- package/core/util/infrastructure/object-util.spec.js +20 -0
- package/core/util/logger/log-service.js +16 -7
- package/core/util/logger/log-service.spec.js +101 -0
- package/dpe-sanitizer.service.spec.js +138 -0
- package/engine.js +20 -1
- package/engine.spec.js +949 -0
- package/enums.spec.js +46 -0
- package/features/dpe/domain/models/type-generateur.model.js +1 -2
- package/features/dpe/domain/models/type-generateur.model.spec.js +25 -0
- package/features/dpe/domain/models/type-habitation.model.spec.js +41 -0
- package/features/dpe/domain/models/type-stockage.model.spec.js +18 -0
- package/features/dpe/domain/models/type-ventilation.model.spec.js +19 -0
- package/features/dpe/infrastructure/ch/chTv.store.spec.js +4 -4
- package/features/dpe/infrastructure/enveloppe/baieVitreeTv.store.js +14 -2
- package/features/dpe/infrastructure/enveloppe/baieVitreeTv.store.spec.js +16 -0
- package/features/dpe/infrastructure/tv.store.js +28 -9
- package/features/dpe/infrastructure/tv.store.spec.js +44 -0
- package/features/engine/domain/apport_et_besoin/apport-et-besoin.service.spec.js +2 -1
- package/features/engine/domain/apport_et_besoin/ch/besoin-ch.service.spec.js +18 -0
- package/features/engine/domain/apport_et_besoin/ch/perte-ch-recup.service.spec.js +33 -1
- package/features/engine/domain/apport_et_besoin/ecs/besoin-ecs.service.spec.js +21 -1
- package/features/engine/domain/apport_et_besoin/ecs/perte-ecs-recup.service.spec.js +41 -1
- package/features/engine/domain/apport_et_besoin/froid/besoin-froid.service.spec.js +44 -1
- package/features/engine/domain/apport_et_besoin/surface-sud-equivalente.service.spec.js +2 -1
- package/features/engine/domain/ch/generateur-ch.service.js +2 -0
- package/features/engine/domain/ch/generateur-ch.service.spec.js +117 -2
- package/features/engine/domain/ch/installation-ch.service.spec.js +14 -0
- package/features/engine/domain/conso/froid/conso-froid.service.spec.js +82 -1
- package/features/engine/domain/constants.spec.js +14 -0
- package/features/engine/domain/contexte.builder.spec.js +21 -0
- package/features/engine/domain/ecs/generateur-ecs.service.spec.js +11 -0
- package/features/engine/domain/ecs/installation-ecs.service.spec.js +55 -2
- package/features/engine/domain/engine.service.spec.js +227 -4
- package/features/engine/domain/enveloppe/baie_vitree/deperdition-baie-vitree.service.spec.js +124 -1
- package/features/engine/domain/enveloppe/deperdition-enveloppe.service.spec.js +270 -2
- package/features/engine/domain/enveloppe/deperdition.service.spec.js +141 -0
- package/features/engine/domain/enveloppe/espace_tampon/espace-tampon.service.spec.js +2 -1
- package/features/engine/domain/enveloppe/mur/deperdition-mur.service.spec.js +117 -1
- package/features/engine/domain/enveloppe/plancher_bas/deperdition-plancher-bas.service.spec.js +134 -1
- package/features/engine/domain/enveloppe/plancher_haut/deperdition-plancher-haut.service.spec.js +126 -1
- package/features/engine/domain/enveloppe/pont_thermique/deperdition-pont-thermique.service.spec.js +18 -1
- package/features/engine/domain/enveloppe/porte/deperdition-porte.service.spec.js +2 -1
- package/features/engine/domain/enveloppe/ventilation/deperdition-ventilation.service.spec.js +67 -1
- package/features/normalizer/domain/dpe-normalizer.service.js +1 -1
- package/features/normalizer/domain/dpe-normalizer.service.spec.js +53 -2
- package/ficheTechnique.spec.js +26 -0
- package/index.spec.js +54 -0
- package/package.json +5 -2
- package/preprocessor/index.js +20 -0
- package/preprocessor/index.spec.js +15 -0
- package/tv.spec.js +38 -0
- package/utils.js +43 -1
- package/utils.spec.js +518 -2
- package/output.js +0 -1
package/conso.js
CHANGED
|
@@ -98,7 +98,7 @@ const coef_cout = {
|
|
|
98
98
|
* @param destination {'ch' | 'ecs' | 'éclairage'}
|
|
99
99
|
* @return {string} la clef à utiliser pour récupérer le coefficient depuis la table `coef_ges`
|
|
100
100
|
*/
|
|
101
|
-
function getCoefKey(type_energie, destination) {
|
|
101
|
+
export function getCoefKey(type_energie, destination) {
|
|
102
102
|
if (type_energie === 'électricité') {
|
|
103
103
|
if (!['ch', 'ecs', 'éclairage'].includes(destination)) {
|
|
104
104
|
console.error(`Type d'électricité inconnu: ${destination}`);
|
|
@@ -218,6 +218,11 @@ export default function calc_conso(
|
|
|
218
218
|
return acc.concat(generateur_chauffage);
|
|
219
219
|
}, []);
|
|
220
220
|
|
|
221
|
+
ecs = Array.isArray(ecs) ? ecs : [];
|
|
222
|
+
|
|
223
|
+
const conso_aux_distribution_ecs_total = ecs.reduce((acc, ecs) => {
|
|
224
|
+
return acc + (ecs.donnee_intermediaire.conso_auxiliaire_distribution_ecs || 0);
|
|
225
|
+
}, 0);
|
|
221
226
|
const gen_ecs = ecs.reduce((acc, ecs) => {
|
|
222
227
|
const generateur_ecs = ecs.generateur_ecs_collection.generateur_ecs;
|
|
223
228
|
if (prorataECS === 1) {
|
|
@@ -243,7 +248,8 @@ export default function calc_conso(
|
|
|
243
248
|
'conso',
|
|
244
249
|
null,
|
|
245
250
|
prorataECS,
|
|
246
|
-
prorataChauffage
|
|
251
|
+
prorataChauffage,
|
|
252
|
+
conso_aux_distribution_ecs_total
|
|
247
253
|
),
|
|
248
254
|
ep_conso: calc_conso_pond(
|
|
249
255
|
Sh,
|
|
@@ -255,7 +261,8 @@ export default function calc_conso(
|
|
|
255
261
|
'ep_conso',
|
|
256
262
|
coeffEp,
|
|
257
263
|
prorataECS,
|
|
258
|
-
prorataChauffage
|
|
264
|
+
prorataChauffage,
|
|
265
|
+
conso_aux_distribution_ecs_total
|
|
259
266
|
),
|
|
260
267
|
emission_ges: calc_conso_pond(
|
|
261
268
|
Sh,
|
|
@@ -267,7 +274,8 @@ export default function calc_conso(
|
|
|
267
274
|
'emission_ges',
|
|
268
275
|
coef_ges,
|
|
269
276
|
prorataECS,
|
|
270
|
-
prorataChauffage
|
|
277
|
+
prorataChauffage,
|
|
278
|
+
conso_aux_distribution_ecs_total
|
|
271
279
|
),
|
|
272
280
|
cout: calc_conso_pond(
|
|
273
281
|
Sh,
|
|
@@ -279,7 +287,8 @@ export default function calc_conso(
|
|
|
279
287
|
'cout',
|
|
280
288
|
coef_cout,
|
|
281
289
|
prorataECS,
|
|
282
|
-
prorataChauffage
|
|
290
|
+
prorataChauffage,
|
|
291
|
+
conso_aux_distribution_ecs_total
|
|
283
292
|
)
|
|
284
293
|
};
|
|
285
294
|
ret.ep_conso.classe_bilan_dpe = classe_bilan_dpe(
|
|
@@ -464,7 +473,8 @@ function calc_conso_pond(
|
|
|
464
473
|
prefix,
|
|
465
474
|
coef,
|
|
466
475
|
prorataECS,
|
|
467
|
-
prorataChauffage
|
|
476
|
+
prorataChauffage,
|
|
477
|
+
conso_aux_distribution_ecs_total
|
|
468
478
|
) {
|
|
469
479
|
const ret = {};
|
|
470
480
|
ret.auxiliaire_ventilation = vt_list.reduce((acc, vt) => {
|
|
@@ -528,7 +538,11 @@ function calc_conso_pond(
|
|
|
528
538
|
return acc + getConso(coef, 'électricité auxiliaire', conso);
|
|
529
539
|
}, 0);
|
|
530
540
|
|
|
531
|
-
ret.auxiliaire_distribution_ecs =
|
|
541
|
+
ret.auxiliaire_distribution_ecs = getConso(
|
|
542
|
+
coef,
|
|
543
|
+
'électricité auxiliaire',
|
|
544
|
+
conso_aux_distribution_ecs_total || 0
|
|
545
|
+
);
|
|
532
546
|
|
|
533
547
|
ret.ecs = getEcsConso(gen_ecs, 'conso_ecs', coef, prorataECS, prefix);
|
|
534
548
|
|
package/conso.spec.js
CHANGED
|
@@ -1,91 +1,500 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Dépendances mockées pour isoler `conso.js` :
|
|
5
|
+
* - `enums` : libellés de type d'énergie / classe d'altitude / zone climatique ;
|
|
6
|
+
* - `16_conso_eclairage` : consommation d'éclairage forcée à 1 kWh/m² (=> conso = Sh) ;
|
|
7
|
+
* - `tvs` : seuils de classe DPE / GES contrôlés ;
|
|
8
|
+
* - `tv` (utils) : lecture des réseaux de chaleur, retour maîtrisé.
|
|
9
|
+
* Les tables internes du module (coef_ges, coef_cout, coef_ep...) ne sont pas mockées :
|
|
10
|
+
* elles font partie du code testé.
|
|
11
|
+
*/
|
|
12
|
+
vi.mock('./enums.js', () => ({
|
|
13
|
+
default: {
|
|
14
|
+
type_energie: {
|
|
15
|
+
1: 'électricité',
|
|
16
|
+
2: 'gaz naturel',
|
|
17
|
+
3: 'réseau de chauffage urbain',
|
|
18
|
+
4: 'inconnu'
|
|
19
|
+
},
|
|
20
|
+
classe_altitude: { 1: 'inférieur à 400m', 2: 'supérieur à 800m' },
|
|
21
|
+
zone_climatique: { 1: 'h1a', 2: 'h1b' }
|
|
22
|
+
}
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
vi.mock('./16_conso_eclairage.js', () => ({ default: vi.fn(() => 1) }));
|
|
26
|
+
|
|
27
|
+
vi.mock('./tv.js', () => ({
|
|
28
|
+
default: {
|
|
29
|
+
dpe_class_limit: {
|
|
30
|
+
'inférieur à 400m': { 100: { A: 10, B: 20, C: 30, D: 40, E: 300, F: 400 } },
|
|
31
|
+
'supérieur à 800m': {}
|
|
32
|
+
},
|
|
33
|
+
ges_class_limit: {
|
|
34
|
+
'inférieur à 400m': { 100: { A: 1, B: 2, C: 3, D: 4, E: 60, F: 90 } },
|
|
35
|
+
'supérieur à 800m': {}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
vi.mock('./utils.js', () => ({
|
|
41
|
+
tv: vi.fn((table, matcher) => {
|
|
42
|
+
// Réseau de chaleur "R1" connu, "R2" inconnu
|
|
43
|
+
if (matcher?.identifiant_reseau === 'R1') return { contenu_co2_acv: 0.15 };
|
|
44
|
+
return null;
|
|
45
|
+
})
|
|
46
|
+
}));
|
|
47
|
+
|
|
48
|
+
const {
|
|
49
|
+
default: calc_conso,
|
|
50
|
+
classe_bilan_dpe,
|
|
51
|
+
classe_emission_ges,
|
|
52
|
+
getCoefKey,
|
|
53
|
+
coef_ep
|
|
54
|
+
} = await import('./conso.js');
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Classe énergétique (bilan DPE)
|
|
58
|
+
* @see : Methode_de_calcul_3CL_DPE_2021-338.pdf
|
|
59
|
+
*/
|
|
60
|
+
describe('classe_bilan_dpe - seuils de classe énergétique', () => {
|
|
61
|
+
test('consommation nulle (null) : aucune classe', () => {
|
|
62
|
+
expect(classe_bilan_dpe(null, 1, 1, 100)).toBeNull();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// ca_id=1 => seuils personnalisés {A:10,B:20,C:30,D:40,E:300,F:400}
|
|
66
|
+
test.each([
|
|
67
|
+
[5, 'A'],
|
|
68
|
+
[15, 'B'],
|
|
69
|
+
[25, 'C'],
|
|
70
|
+
[35, 'D'],
|
|
71
|
+
[250, 'E'],
|
|
72
|
+
[350, 'F'],
|
|
73
|
+
[450, 'G']
|
|
74
|
+
])('seuils personnalisés : conso %s => classe %s', (conso, classe) => {
|
|
75
|
+
expect(classe_bilan_dpe(conso, 1, 1, 100)).toBe(classe);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// ca_id=2 => seuils absents => valeurs par défaut
|
|
79
|
+
test('valeurs par défaut A-D quand la table ne fournit pas de seuil', () => {
|
|
80
|
+
expect(classe_bilan_dpe(50, 1, 2, 100)).toBe('A'); // < 70
|
|
81
|
+
expect(classe_bilan_dpe(100, 1, 2, 100)).toBe('B'); // < 110
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test('zone climatique standard : seuils E/F par défaut 330/420', () => {
|
|
85
|
+
// zc_id=1 (h1a) non concernée par le cas montagne => 330/420
|
|
86
|
+
expect(classe_bilan_dpe(300, 1, 2, 100)).toBe('E');
|
|
87
|
+
expect(classe_bilan_dpe(400, 1, 2, 100)).toBe('F');
|
|
88
|
+
expect(classe_bilan_dpe(500, 1, 2, 100)).toBe('G');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('zone montagne (h1b, > 800m) : seuils E/F relevés à 390/500', () => {
|
|
92
|
+
// zc_id=2 (h1b) + ca 'supérieur à 800m' => 390/500
|
|
93
|
+
expect(classe_bilan_dpe(350, 2, 2, 100)).toBe('E');
|
|
94
|
+
expect(classe_bilan_dpe(450, 2, 2, 100)).toBe('F');
|
|
95
|
+
expect(classe_bilan_dpe(600, 2, 2, 100)).toBe('G');
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Classe climat (émissions GES)
|
|
101
|
+
* @see : Methode_de_calcul_3CL_DPE_2021-338.pdf
|
|
102
|
+
*/
|
|
103
|
+
describe('classe_emission_ges - seuils de classe climat', () => {
|
|
104
|
+
test('émission nulle (null) : aucune classe', () => {
|
|
105
|
+
expect(classe_emission_ges(null, 1, 1, 100)).toBeNull();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test.each([
|
|
109
|
+
[0.5, 'A'],
|
|
110
|
+
[1.5, 'B'],
|
|
111
|
+
[2.5, 'C'],
|
|
112
|
+
[3.5, 'D'],
|
|
113
|
+
[55, 'E'],
|
|
114
|
+
[70, 'F'],
|
|
115
|
+
[95, 'G']
|
|
116
|
+
])('seuils personnalisés : émission %s => classe %s', (emission, classe) => {
|
|
117
|
+
expect(classe_emission_ges(emission, 1, 1, 100)).toBe(classe);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test('valeurs par défaut A-D quand la table ne fournit pas de seuil', () => {
|
|
121
|
+
expect(classe_emission_ges(3, 1, 2, 100)).toBe('A'); // < 6
|
|
122
|
+
expect(classe_emission_ges(10, 1, 2, 100)).toBe('B'); // < 11
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test('zone climatique standard : seuils E/F par défaut 70/100', () => {
|
|
126
|
+
expect(classe_emission_ges(60, 1, 2, 100)).toBe('E');
|
|
127
|
+
expect(classe_emission_ges(80, 1, 2, 100)).toBe('F');
|
|
128
|
+
expect(classe_emission_ges(120, 1, 2, 100)).toBe('G');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test('zone montagne (h1b, > 800m) : seuils E/F relevés à 80/110', () => {
|
|
132
|
+
expect(classe_emission_ges(70, 2, 2, 100)).toBe('E');
|
|
133
|
+
expect(classe_emission_ges(90, 2, 2, 100)).toBe('F');
|
|
134
|
+
expect(classe_emission_ges(120, 2, 2, 100)).toBe('G');
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Construction de la clef de la table `coef_ges` pour l'électricité (dépend de l'usage).
|
|
140
|
+
*/
|
|
141
|
+
describe('getCoefKey - clef du coefficient GES', () => {
|
|
142
|
+
test('énergie non électrique : le libellé est renvoyé tel quel', () => {
|
|
143
|
+
expect(getCoefKey('gaz naturel', 'ch')).toBe('gaz naturel');
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("électricité : suffixe d'usage ajouté", () => {
|
|
147
|
+
expect(getCoefKey('électricité', 'ch')).toBe('électricité ch');
|
|
148
|
+
expect(getCoefKey('électricité', 'ecs')).toBe('électricité ecs');
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test('électricité avec usage inconnu : erreur signalée mais clef construite', () => {
|
|
152
|
+
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
153
|
+
expect(getCoefKey('électricité', 'xxx')).toBe('électricité xxx');
|
|
154
|
+
expect(errorSpy).toHaveBeenCalledWith(expect.stringContaining('xxx'));
|
|
155
|
+
errorSpy.mockRestore();
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
/** Fabrique un générateur de chauffage. */
|
|
160
|
+
function genCh(energieId, di, deExtra = {}) {
|
|
161
|
+
return {
|
|
162
|
+
donnee_entree: { enum_type_energie_id: energieId, ...deExtra },
|
|
163
|
+
donnee_intermediaire: di
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** Fabrique une installation de chauffage. */
|
|
168
|
+
function installCh(deExtra, gens) {
|
|
169
|
+
return {
|
|
170
|
+
donnee_entree: {
|
|
171
|
+
enum_type_installation_id: '1',
|
|
172
|
+
enum_methode_calcul_conso_id: '1',
|
|
173
|
+
...deExtra
|
|
174
|
+
},
|
|
175
|
+
generateur_chauffage_collection: { generateur_chauffage: gens }
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** Fabrique un générateur ECS. */
|
|
180
|
+
function genEcs(energieId, di, deExtra = {}) {
|
|
181
|
+
return {
|
|
182
|
+
donnee_entree: { enum_type_energie_id: energieId, ...deExtra },
|
|
183
|
+
donnee_intermediaire: di
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** Fabrique une installation ECS. */
|
|
188
|
+
function installEcs(deExtra, gens) {
|
|
189
|
+
return {
|
|
190
|
+
donnee_entree: { ...deExtra },
|
|
191
|
+
donnee_intermediaire: {},
|
|
192
|
+
generateur_ecs_collection: { generateur_ecs: gens }
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const DATE_DPE = '2024-01-01';
|
|
197
|
+
|
|
198
|
+
describe('calc_conso - agrégation des consommations', () => {
|
|
199
|
+
let errorSpy;
|
|
200
|
+
|
|
201
|
+
beforeEach(() => {
|
|
202
|
+
errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
afterEach(() => {
|
|
206
|
+
errorSpy.mockRestore();
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
test('chauffage électrique individuel : EF, EP (×1,9), GES et coût déterministes', () => {
|
|
10
210
|
const ch = [
|
|
11
|
-
{
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
211
|
+
installCh({ cle_repartition_ch: 1 }, [
|
|
212
|
+
genCh('1', { conso_ch: 1000, conso_ch_depensier: 1200 })
|
|
213
|
+
])
|
|
214
|
+
];
|
|
215
|
+
|
|
216
|
+
const res = calc_conso(100, 1, 1, [], ch, [], [], 1, 1, DATE_DPE, coef_ep);
|
|
217
|
+
|
|
218
|
+
// EF : passe-plat (coefficient nul)
|
|
219
|
+
expect(res.ef_conso.conso_ch).toBe(1000);
|
|
220
|
+
// EP : coefficient électricité 1,9
|
|
221
|
+
expect(res.ep_conso.ep_conso_ch).toBeCloseTo(1900, 9);
|
|
222
|
+
// GES : coef_ges['électricité ch'] = 0,079
|
|
223
|
+
expect(res.emission_ges.emission_ges_ch).toBeCloseTo(79, 9);
|
|
224
|
+
// Coût : cout_electricite(1000) = 149 + 0,14066 * 1000
|
|
225
|
+
expect(res.cout.cout_ch).toBeCloseTo(149 + 0.14066 * 1000, 9);
|
|
226
|
+
// Classes calculées et injectées
|
|
227
|
+
expect(res.ep_conso.classe_bilan_dpe).toBeDefined();
|
|
228
|
+
expect(res.emission_ges.classe_emission_ges).toBeDefined();
|
|
229
|
+
// Éclairage = calc_conso_eclairage(zc) * Sh = 1 * 100 (passe-plat EF)
|
|
230
|
+
expect(res.ef_conso.conso_eclairage).toBe(100);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
test('installation collective (méthode 2) : clé de répartition appliquée à conso et distribution', () => {
|
|
234
|
+
const ch = [
|
|
235
|
+
installCh(
|
|
236
|
+
{
|
|
237
|
+
cle_repartition_ch: 2,
|
|
238
|
+
enum_type_installation_id: '2',
|
|
239
|
+
enum_methode_calcul_conso_id: '2'
|
|
22
240
|
},
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
]
|
|
241
|
+
[
|
|
242
|
+
genCh('1', {
|
|
243
|
+
conso_ch: 1000,
|
|
244
|
+
conso_ch_depensier: 1200,
|
|
245
|
+
conso_auxiliaire_distribution_ch: 100
|
|
246
|
+
})
|
|
247
|
+
]
|
|
248
|
+
)
|
|
249
|
+
];
|
|
250
|
+
|
|
251
|
+
const res = calc_conso(100, 1, 1, [], ch, [], [], 1, 1, DATE_DPE, coef_ep);
|
|
252
|
+
|
|
253
|
+
// conso_ch = 1000 * clé (2)
|
|
254
|
+
expect(res.ef_conso.conso_ch).toBe(2000);
|
|
255
|
+
// distribution = 100 * clé (2) (méthode 2 + clé présente)
|
|
256
|
+
expect(res.ef_conso.conso_auxiliaire_distribution_ch).toBe(200);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
test('installation avec clé absente (non collective) : répartition = prorata chauffage', () => {
|
|
260
|
+
const ch = [
|
|
261
|
+
installCh(
|
|
262
|
+
{
|
|
263
|
+
cle_repartition_ch: 0,
|
|
264
|
+
enum_type_installation_id: '1',
|
|
265
|
+
enum_methode_calcul_conso_id: '3'
|
|
51
266
|
},
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
267
|
+
[
|
|
268
|
+
genCh('1', {
|
|
269
|
+
conso_ch: 1000,
|
|
270
|
+
conso_ch_depensier: 1200,
|
|
271
|
+
conso_auxiliaire_distribution_ch: 50
|
|
272
|
+
})
|
|
273
|
+
]
|
|
274
|
+
)
|
|
275
|
+
];
|
|
276
|
+
|
|
277
|
+
const res = calc_conso(100, 1, 1, [], ch, [], [], 1, 1, DATE_DPE, coef_ep);
|
|
278
|
+
|
|
279
|
+
// clé 0 => prorataChauffage (1) ; distribution non multipliée (méthode 3)
|
|
280
|
+
expect(res.ef_conso.conso_ch).toBe(1000);
|
|
281
|
+
expect(res.ef_conso.conso_auxiliaire_distribution_ch).toBe(50);
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
test('clé de répartition nulle (prorata 0) : consommation de chauffage annulée', () => {
|
|
285
|
+
// cle===1 => value.cle = prorataChauffage(0) ; type collectif => répartition = 0
|
|
286
|
+
const ch = [
|
|
287
|
+
installCh({ cle_repartition_ch: 1, enum_type_installation_id: '2' }, [
|
|
288
|
+
genCh('1', { conso_ch: 1000, conso_ch_depensier: 1200 })
|
|
289
|
+
])
|
|
290
|
+
];
|
|
291
|
+
|
|
292
|
+
const res = calc_conso(100, 1, 1, [], ch, [], [], 1, 0, DATE_DPE, coef_ep);
|
|
293
|
+
expect(res.ef_conso.conso_ch).toBe(0);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
test('réseau de chaleur connu : le coefficient GES provient de la table réseau', () => {
|
|
297
|
+
const ch = [
|
|
298
|
+
installCh({ cle_repartition_ch: 1 }, [
|
|
299
|
+
genCh(
|
|
300
|
+
'3',
|
|
301
|
+
{ conso_ch: 1000, conso_ch_depensier: 1200 },
|
|
302
|
+
{ identifiant_reseau_chaleur: 'R1', date_arrete_reseau_chaleur: '2030-01-01' }
|
|
303
|
+
)
|
|
304
|
+
])
|
|
305
|
+
];
|
|
306
|
+
|
|
307
|
+
const res = calc_conso(100, 1, 1, [], ch, [], [], 1, 1, DATE_DPE, coef_ep);
|
|
308
|
+
// contenu_co2_acv = 0,15 (tv mocké) => émission = 1000 * 0,15
|
|
309
|
+
expect(res.emission_ges.emission_ges_ch).toBeCloseTo(150, 9);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
test('réseau de chaleur inconnu (identifiant sans ligne) : erreur signalée', () => {
|
|
313
|
+
const ch = [
|
|
314
|
+
installCh({ cle_repartition_ch: 1 }, [
|
|
315
|
+
genCh(
|
|
316
|
+
'3',
|
|
317
|
+
{ conso_ch: 1000, conso_ch_depensier: 1200 },
|
|
318
|
+
{ identifiant_reseau_chaleur: 'R2' }
|
|
319
|
+
)
|
|
320
|
+
])
|
|
321
|
+
];
|
|
322
|
+
|
|
323
|
+
calc_conso(100, 1, 1, [], ch, [], [], 1, 1, DATE_DPE, coef_ep);
|
|
324
|
+
expect(errorSpy).toHaveBeenCalledWith(expect.stringContaining('R2'));
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
test('réseau de chaleur sans identifiant : coefficient GES forfaitaire 0,385', () => {
|
|
328
|
+
const ch = [
|
|
329
|
+
installCh({ cle_repartition_ch: 1 }, [
|
|
330
|
+
genCh('3', { conso_ch: 1000, conso_ch_depensier: 1200 })
|
|
331
|
+
])
|
|
332
|
+
];
|
|
333
|
+
|
|
334
|
+
const res = calc_conso(100, 1, 1, [], ch, [], [], 1, 1, DATE_DPE, coef_ep);
|
|
335
|
+
// 1000 * 0,385
|
|
336
|
+
expect(res.emission_ges.emission_ges_ch).toBeCloseTo(385, 9);
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
test("date de DPE invalide (levée d'exception) : année de repli 2022", () => {
|
|
340
|
+
// date_arrete_reseau_chaleur = Symbol => new Date(...) lève => catch => 2022
|
|
341
|
+
const ch = [
|
|
342
|
+
installCh({ cle_repartition_ch: 1 }, [
|
|
343
|
+
genCh(
|
|
344
|
+
'1',
|
|
345
|
+
{ conso_ch: 1000, conso_ch_depensier: 1200 },
|
|
346
|
+
{ date_arrete_reseau_chaleur: Symbol('invalide') }
|
|
347
|
+
)
|
|
348
|
+
])
|
|
349
|
+
];
|
|
350
|
+
|
|
351
|
+
// Ne doit pas lever
|
|
352
|
+
expect(() => calc_conso(100, 1, 1, [], ch, [], [], 1, 1, DATE_DPE, coef_ep)).not.toThrow();
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
test('énergie inconnue : coefficient GES par défaut de 1', () => {
|
|
356
|
+
const ch = [
|
|
357
|
+
installCh({ cle_repartition_ch: 1 }, [
|
|
358
|
+
genCh('4', { conso_ch: 1000, conso_ch_depensier: 1200 })
|
|
359
|
+
])
|
|
360
|
+
];
|
|
361
|
+
|
|
362
|
+
const res = calc_conso(100, 1, 1, [], ch, [], [], 1, 1, DATE_DPE, coef_ep);
|
|
363
|
+
// coef_ges['inconnu'] absent => getGesCoeffForGenerateur renvoie 1 => émission = 1000
|
|
364
|
+
expect(res.emission_ges.emission_ges_ch).toBeCloseTo(1000, 9);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
test('coût du gaz naturel : trois paliers tarifaires couverts', () => {
|
|
368
|
+
// Trois générateurs gaz avec des consommations dans chaque palier tarifaire
|
|
369
|
+
const ch = [
|
|
370
|
+
installCh({ cle_repartition_ch: 1 }, [
|
|
371
|
+
genCh('2', { conso_ch: 3000, conso_ch_depensier: 3000 }), // < 5009
|
|
372
|
+
genCh('2', { conso_ch: 30000, conso_ch_depensier: 30000 }), // < 50055
|
|
373
|
+
genCh('2', { conso_ch: 60000, conso_ch_depensier: 60000 }) // else
|
|
374
|
+
])
|
|
375
|
+
];
|
|
376
|
+
|
|
377
|
+
const res = calc_conso(100, 1, 1, [], ch, [], [], 1, 1, DATE_DPE, coef_ep);
|
|
378
|
+
// Somme des trois paliers : 0,11121*3000 + (230+0,06533*30000) + (415+0,06164*60000)
|
|
379
|
+
const attendu = 0.11121 * 3000 + (230 + 0.06533 * 30000) + (415 + 0.06164 * 60000);
|
|
380
|
+
expect(res.cout.cout_ch).toBeCloseTo(attendu, 6);
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
test("coût de l'électricité : cinq paliers tarifaires couverts", () => {
|
|
384
|
+
const ch = [
|
|
385
|
+
installCh({ cle_repartition_ch: 1 }, [
|
|
386
|
+
genCh('1', { conso_ch: 500, conso_ch_depensier: 500 }), // < 1000
|
|
387
|
+
genCh('1', { conso_ch: 1500, conso_ch_depensier: 1500 }), // < 2500
|
|
388
|
+
genCh('1', { conso_ch: 3000, conso_ch_depensier: 3000 }), // < 5000
|
|
389
|
+
genCh('1', { conso_ch: 10000, conso_ch_depensier: 10000 }), // < 15000
|
|
390
|
+
genCh('1', { conso_ch: 20000, conso_ch_depensier: 20000 }) // else
|
|
391
|
+
])
|
|
392
|
+
];
|
|
393
|
+
|
|
394
|
+
const res = calc_conso(100, 1, 1, [], ch, [], [], 1, 1, DATE_DPE, coef_ep);
|
|
395
|
+
const attendu =
|
|
396
|
+
0.29007 * 500 +
|
|
397
|
+
(149 + 0.14066 * 1500) +
|
|
398
|
+
(122 + 0.15176 * 3000) +
|
|
399
|
+
(94 + 0.15735 * 10000) +
|
|
400
|
+
(56 + 0.15989 * 20000);
|
|
401
|
+
expect(res.cout.cout_ch).toBeCloseTo(attendu, 6);
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
test('ECS collective (prorataECS=1) : clé de répartition = clé × rdim', () => {
|
|
405
|
+
const ecs = [
|
|
406
|
+
installEcs({ cle_repartition_ecs: 2, rdim: 3 }, [
|
|
407
|
+
genEcs('1', { conso_ecs: 100, conso_ecs_depensier: 120 })
|
|
408
|
+
])
|
|
409
|
+
];
|
|
410
|
+
|
|
411
|
+
const res = calc_conso(100, 1, 1, [], [], ecs, [], 1, 1, DATE_DPE, coef_ep);
|
|
412
|
+
// clé = 2 * 3 = 6 => conso_ecs = 100 * 6
|
|
413
|
+
expect(res.ef_conso.conso_ecs).toBe(600);
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
test('ECS avec prorataECS différent de 1 : clé issue du prorata', () => {
|
|
417
|
+
// Quand prorataECS !== 1, la boucle ECS ne renseigne pas donnee_utilisateur :
|
|
418
|
+
// on la fournit en amont (coefficient GES déjà connu) pour refléter les données réelles.
|
|
419
|
+
const gen = genEcs('1', { conso_ecs: 100, conso_ecs_depensier: 120 });
|
|
420
|
+
gen.donnee_utilisateur = { coeffEmissionGes: 0.065 };
|
|
421
|
+
const ecs = [installEcs({}, [gen])];
|
|
422
|
+
|
|
423
|
+
const res = calc_conso(100, 1, 1, [], [], ecs, [], 0.5, 1, DATE_DPE, coef_ep);
|
|
424
|
+
// clé absente => prorataECS (0,5) => conso_ecs = 100 * 0,5
|
|
425
|
+
expect(res.ef_conso.conso_ecs).toBe(50);
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
test('ECS sans clé ni rdim, énergie non renseignée : valeurs de repli (1 et électricité)', () => {
|
|
429
|
+
// cle_repartition_ecs et rdim absents => 1 ; enum_type_energie_id absent => électricité (id 1)
|
|
430
|
+
const ecs = [installEcs({}, [genEcs(undefined, { conso_ecs: 100, conso_ecs_depensier: 120 })])];
|
|
431
|
+
|
|
432
|
+
const res = calc_conso(100, 1, 1, [], [], ecs, [], 1, 1, DATE_DPE, coef_ep);
|
|
433
|
+
// clé = 1 * 1 => conso_ecs = 100 ; EP électricité => 100 * 1,9
|
|
434
|
+
expect(res.ef_conso.conso_ecs).toBe(100);
|
|
435
|
+
expect(res.ep_conso.ep_conso_ecs).toBeCloseTo(190, 9);
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
test.each([
|
|
439
|
+
['absente', undefined],
|
|
440
|
+
['nulle', null],
|
|
441
|
+
['non tabulaire', { installation_ecs: [] }]
|
|
442
|
+
])('collection ECS %s : traitée comme une liste vide', (_libelle, ecs) => {
|
|
443
|
+
const chFixture = () => [
|
|
444
|
+
installCh({ cle_repartition_ch: 1 }, [
|
|
445
|
+
genCh('1', { conso_ch: 1000, conso_ch_depensier: 1200 })
|
|
446
|
+
])
|
|
447
|
+
];
|
|
448
|
+
|
|
449
|
+
const res = calc_conso(100, 1, 1, [], chFixture(), ecs, [], 1, 1, DATE_DPE, coef_ep);
|
|
450
|
+
|
|
451
|
+
// Identique à un appel avec une collection ECS vide : aucune conso ni auxiliaire d'ECS
|
|
452
|
+
expect(res).toEqual(calc_conso(100, 1, 1, [], chFixture(), [], [], 1, 1, DATE_DPE, coef_ep));
|
|
453
|
+
expect(res.ef_conso.conso_ecs).toBe(0);
|
|
454
|
+
expect(res.ef_conso.conso_auxiliaire_distribution_ecs).toBe(0);
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
test('ventilation et froid : auxiliaires et froid agrégés par énergie', () => {
|
|
458
|
+
const vt = [
|
|
459
|
+
{
|
|
460
|
+
donnee_entree: { cle_repartition_ventilation: 2 },
|
|
461
|
+
donnee_intermediaire: { conso_auxiliaire_ventilation: 20 }
|
|
462
|
+
},
|
|
463
|
+
// conso absente => 0 ; pas de clé de répartition
|
|
464
|
+
{ donnee_entree: {}, donnee_intermediaire: {} }
|
|
465
|
+
];
|
|
466
|
+
const fr = [
|
|
467
|
+
{
|
|
468
|
+
donnee_entree: { enum_type_energie_id: '1' },
|
|
469
|
+
donnee_intermediaire: { conso_fr: 200, conso_fr_depensier: 250 }
|
|
81
470
|
}
|
|
82
471
|
];
|
|
83
|
-
const ecs = [];
|
|
84
|
-
const fr = [];
|
|
85
472
|
|
|
86
|
-
const
|
|
473
|
+
const res = calc_conso(100, 1, 1, vt, [], [], fr, 1, 1, DATE_DPE, coef_ep);
|
|
474
|
+
|
|
475
|
+
// ventilation : 20 * 2 (clé) + 0 = 40
|
|
476
|
+
expect(res.ef_conso.conso_auxiliaire_ventilation).toBe(40);
|
|
477
|
+
expect(res.ef_conso.conso_fr).toBe(200);
|
|
478
|
+
// sortie par énergie pour l'électricité
|
|
479
|
+
const elec = res.sortie_par_energie_collection.sortie_par_energie.find(
|
|
480
|
+
(e) => e.enum_type_energie_id === '1'
|
|
481
|
+
);
|
|
482
|
+
expect(elec.conso_ch).toBeDefined();
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
test('sortie par énergie : électricité ajoutée même en son absence', () => {
|
|
486
|
+
// Seul le gaz est présent => l'électricité (id 1) est tout de même ajoutée
|
|
487
|
+
const ch = [
|
|
488
|
+
installCh({ cle_repartition_ch: 1 }, [
|
|
489
|
+
genCh('2', { conso_ch: 1000, conso_ch_depensier: 1200 })
|
|
490
|
+
])
|
|
491
|
+
];
|
|
87
492
|
|
|
88
|
-
|
|
89
|
-
|
|
493
|
+
const res = calc_conso(100, 1, 1, [], ch, [], [], 1, 1, DATE_DPE, coef_ep);
|
|
494
|
+
const ids = res.sortie_par_energie_collection.sortie_par_energie.map(
|
|
495
|
+
(e) => e.enum_type_energie_id
|
|
496
|
+
);
|
|
497
|
+
expect(ids).toContain('2');
|
|
498
|
+
expect(ids).toContain('1');
|
|
90
499
|
});
|
|
91
500
|
});
|