@open3cl/engine 1.6.1 → 1.6.2
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.spec.js +225 -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.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 +1 -1
- package/conso.spec.js +471 -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 +4 -1
- package/engine.spec.js +854 -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
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Dépendances mockées pour isoler `calc_ph` :
|
|
5
|
+
* - `enums` : mapping minimal période de construction / période d'isolation ;
|
|
6
|
+
* - `b` (3.1_b.js) : simple espion (le coefficient b n'intervient pas dans le calcul de Uph ici) ;
|
|
7
|
+
* - `tv` : accès aux tables `uph0` / `uph`, on contrôle la ligne retournée par table ;
|
|
8
|
+
* - `requestInput` : passe-plat renvoyant la donnée d'entrée demandée ;
|
|
9
|
+
* - `getKeyByValue` : implémentation déterministe (pas de dépendance aux vraies enums) ;
|
|
10
|
+
* - `bug_for_bug_compat` : exposé via un getter afin de pouvoir le basculer par test.
|
|
11
|
+
*/
|
|
12
|
+
let bugForBugCompat = false;
|
|
13
|
+
|
|
14
|
+
vi.mock('./enums.js', () => ({
|
|
15
|
+
default: {
|
|
16
|
+
periode_construction: { 1: 'avant 1948', 3: '1948-1974', 5: '1989-2000' },
|
|
17
|
+
periode_isolation: { 2: '1975-1977', 6: '2006-2012' }
|
|
18
|
+
}
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
vi.mock('./3.1_b.js', () => ({
|
|
22
|
+
default: vi.fn()
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
vi.mock('./utils.js', () => ({
|
|
26
|
+
tv: vi.fn(),
|
|
27
|
+
requestInput: (de, du, field) => de[field],
|
|
28
|
+
getKeyByValue: (object, value) => Object.keys(object).find((key) => object[key] === value),
|
|
29
|
+
get bug_for_bug_compat() {
|
|
30
|
+
return bugForBugCompat;
|
|
31
|
+
}
|
|
32
|
+
}));
|
|
33
|
+
|
|
34
|
+
const { default: calc_ph } = await import('./3.2.3_plancher_haut.js');
|
|
35
|
+
const { tv } = await import('./utils.js');
|
|
36
|
+
|
|
37
|
+
/** Table `uph0` figée : U0 forfaitaire de la paroi nue. */
|
|
38
|
+
const ROW_UPH0 = { uph0: '2', tv_uph0_id: '5' };
|
|
39
|
+
/** Table `uph` figée : U forfaitaire de la paroi isolée. */
|
|
40
|
+
const ROW_UPH = { uph: '0.3', tv_uph_id: '7' };
|
|
41
|
+
|
|
42
|
+
beforeEach(() => {
|
|
43
|
+
bugForBugCompat = false;
|
|
44
|
+
tv.mockReset();
|
|
45
|
+
tv.mockImplementation((table) => {
|
|
46
|
+
if (table === 'uph0') return { ...ROW_UPH0 };
|
|
47
|
+
if (table === 'uph') return { ...ROW_UPH };
|
|
48
|
+
return null;
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 3.2.3 Coefficient de transmission des planchers hauts (Uph)
|
|
54
|
+
* @see : Methode_de_calcul_3CL_DPE_2021-338.pdf - §3.2.3
|
|
55
|
+
*/
|
|
56
|
+
describe('calc_ph - plancher non isolé', () => {
|
|
57
|
+
test('Uph égal à Uph0 (paroi nue)', () => {
|
|
58
|
+
const ph = {
|
|
59
|
+
donnee_entree: {
|
|
60
|
+
methode_saisie_u: 'non isolé',
|
|
61
|
+
methode_saisie_u0: 'type de paroi inconnu (valeur par défaut)',
|
|
62
|
+
type_plancher_haut: 'terrasse'
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
calc_ph(ph, 'h1a', '1', '0');
|
|
67
|
+
|
|
68
|
+
expect(ph.donnee_intermediaire.uph0).toBe(2);
|
|
69
|
+
expect(ph.donnee_intermediaire.uph).toBe(2);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('Uph0 initialisé depuis une donnée intermédiaire préexistante', () => {
|
|
73
|
+
const ph = {
|
|
74
|
+
donnee_entree: {
|
|
75
|
+
methode_saisie_u: 'non isolé',
|
|
76
|
+
methode_saisie_u0: 'u0 non saisi car le u est saisi connu et justifié.'
|
|
77
|
+
},
|
|
78
|
+
donnee_intermediaire: { uph0: 1.5 }
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
calc_ph(ph, 'h1a', '1', '0');
|
|
82
|
+
|
|
83
|
+
// Aucune méthode ne recalcule Uph0 ici : la valeur préexistante est conservée
|
|
84
|
+
expect(ph.donnee_intermediaire.uph0).toBe(1.5);
|
|
85
|
+
expect(ph.donnee_intermediaire.uph).toBe(1.5);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('Uph0 introuvable dans la table : erreur émise et uph0 non défini', () => {
|
|
89
|
+
tv.mockReturnValue(null);
|
|
90
|
+
const error = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
91
|
+
const ph = {
|
|
92
|
+
donnee_entree: {
|
|
93
|
+
methode_saisie_u: 'non isolé',
|
|
94
|
+
methode_saisie_u0:
|
|
95
|
+
'déterminé selon le matériau et épaisseur à partir de la table de valeur forfaitaire',
|
|
96
|
+
type_plancher_haut: 'terrasse'
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
calc_ph(ph, 'h1a', '1', '0');
|
|
101
|
+
|
|
102
|
+
expect(ph.donnee_intermediaire.uph0).toBeUndefined();
|
|
103
|
+
expect(error).toHaveBeenCalledWith(expect.stringContaining('uph0'));
|
|
104
|
+
error.mockRestore();
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
describe('calc_ph - calcul de Uph0 (calc_uph0)', () => {
|
|
109
|
+
test('saisie directe de Uph0 : valeur reprise depuis uph0_saisi sans accès table', () => {
|
|
110
|
+
const ph = {
|
|
111
|
+
donnee_entree: {
|
|
112
|
+
methode_saisie_u: 'non isolé',
|
|
113
|
+
methode_saisie_u0:
|
|
114
|
+
'saisie direct u0 justifiée à partir des documents justificatifs autorisés',
|
|
115
|
+
uph0_saisi: 0.9
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
calc_ph(ph, 'h1a', '1', '0');
|
|
120
|
+
|
|
121
|
+
expect(tv).not.toHaveBeenCalled();
|
|
122
|
+
expect(ph.donnee_intermediaire.uph0).toBe(0.9);
|
|
123
|
+
expect(ph.donnee_intermediaire.uph).toBe(0.9);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test('Uph0 non saisi car U est saisi : ni accès table, ni valeur Uph0', () => {
|
|
127
|
+
const ph = {
|
|
128
|
+
donnee_entree: {
|
|
129
|
+
methode_saisie_u: 'non isolé',
|
|
130
|
+
methode_saisie_u0: 'u0 non saisi car le u est saisi connu et justifié.'
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
calc_ph(ph, 'h1a', '1', '0');
|
|
135
|
+
|
|
136
|
+
expect(tv).not.toHaveBeenCalled();
|
|
137
|
+
expect(ph.donnee_intermediaire.uph0).toBeUndefined();
|
|
138
|
+
expect(ph.donnee_intermediaire.uph).toBeUndefined();
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test('methode_saisie_u0 inconnue : avertissement émis et Uph0 non calculé', () => {
|
|
142
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
143
|
+
const ph = {
|
|
144
|
+
donnee_entree: {
|
|
145
|
+
methode_saisie_u: 'non isolé',
|
|
146
|
+
methode_saisie_u0: 'valeur inexistante'
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
calc_ph(ph, 'h1a', '1', '0');
|
|
151
|
+
|
|
152
|
+
expect(warn).toHaveBeenCalledWith('methode_saisie_u0 inconnue:', 'valeur inexistante');
|
|
153
|
+
expect(ph.donnee_intermediaire.uph0).toBeUndefined();
|
|
154
|
+
warn.mockRestore();
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
describe("calc_ph - ajout d'une isolation par épaisseur ou résistance", () => {
|
|
159
|
+
test("épaisseur d'isolation saisie : Uph = 1 / (1/Uph0 + e/0,04)", () => {
|
|
160
|
+
const ph = {
|
|
161
|
+
donnee_entree: {
|
|
162
|
+
methode_saisie_u: 'epaisseur isolation saisie justifiée par mesure ou observation',
|
|
163
|
+
methode_saisie_u0: 'type de paroi inconnu (valeur par défaut)',
|
|
164
|
+
type_plancher_haut: 'terrasse',
|
|
165
|
+
epaisseur_isolation: 10
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
calc_ph(ph, 'h1a', '1', '0');
|
|
170
|
+
|
|
171
|
+
// Uph0 = 2 ; e = 10 * 0,01 = 0,1 m ; Uph = 1 / (1/2 + 0,1/0,04) = 1/3
|
|
172
|
+
// valeur de référence de régression
|
|
173
|
+
expect(ph.donnee_intermediaire.uph).toBeCloseTo(0.3333333333333333, 9);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test("résistance d'isolation saisie : Uph = 1 / (1/Uph0 + R)", () => {
|
|
177
|
+
const ph = {
|
|
178
|
+
donnee_entree: {
|
|
179
|
+
methode_saisie_u:
|
|
180
|
+
"resistance isolation saisie justifiée observation de l'isolant installé et mesure de son épaisseur",
|
|
181
|
+
methode_saisie_u0: 'type de paroi inconnu (valeur par défaut)',
|
|
182
|
+
type_plancher_haut: 'terrasse',
|
|
183
|
+
resistance_isolation: 1
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
calc_ph(ph, 'h1a', '1', '0');
|
|
188
|
+
|
|
189
|
+
// Uph0 = 2 ; R = 1 ; Uph = 1 / (1/2 + 1) = 2/3
|
|
190
|
+
// valeur de référence de régression
|
|
191
|
+
expect(ph.donnee_intermediaire.uph).toBeCloseTo(0.6666666666666666, 9);
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
describe('calc_ph - saisie directe de Uph', () => {
|
|
196
|
+
test('Uph pris depuis la valeur saisie, sans accès aux tables', () => {
|
|
197
|
+
const ph = {
|
|
198
|
+
donnee_entree: {
|
|
199
|
+
methode_saisie_u:
|
|
200
|
+
'saisie direct u justifiée (à partir des documents justificatifs autorisés)',
|
|
201
|
+
uph_saisi: 0.18
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
calc_ph(ph, 'h1a', '1', '0');
|
|
206
|
+
|
|
207
|
+
expect(tv).not.toHaveBeenCalled();
|
|
208
|
+
expect(ph.donnee_intermediaire.uph).toBe(0.18);
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
describe('calc_ph - isolation inconnue (table forfaitaire)', () => {
|
|
213
|
+
test('Uph = min(Uph table, Uph0) : la paroi isolée ne peut être plus déperditive que nue', () => {
|
|
214
|
+
const ph = {
|
|
215
|
+
donnee_entree: {
|
|
216
|
+
methode_saisie_u: 'isolation inconnue (table forfaitaire)',
|
|
217
|
+
methode_saisie_u0: 'type de paroi inconnu (valeur par défaut)',
|
|
218
|
+
type_adjacence: 'extérieur',
|
|
219
|
+
type_plancher_haut: 'terrasse'
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
calc_ph(ph, 'h1a', '1', '0');
|
|
224
|
+
|
|
225
|
+
// min(0,3 ; 2) = 0,3
|
|
226
|
+
expect(ph.donnee_intermediaire.uph).toBe(0.3);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
test('Uph introuvable dans la table : erreur émise et uph non défini par tv_uph', () => {
|
|
230
|
+
tv.mockImplementation((table) => (table === 'uph0' ? { ...ROW_UPH0 } : null));
|
|
231
|
+
const error = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
232
|
+
const ph = {
|
|
233
|
+
donnee_entree: {
|
|
234
|
+
methode_saisie_u: 'isolation inconnue (table forfaitaire)',
|
|
235
|
+
methode_saisie_u0: 'type de paroi inconnu (valeur par défaut)',
|
|
236
|
+
type_adjacence: 'extérieur',
|
|
237
|
+
type_plancher_haut: 'terrasse'
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
calc_ph(ph, 'h1a', '1', '0');
|
|
242
|
+
|
|
243
|
+
expect(error).toHaveBeenCalledWith(expect.stringContaining('uph'));
|
|
244
|
+
// di.uph vaut undefined avant le Math.min => min(undefined, 2) = NaN
|
|
245
|
+
expect(ph.donnee_intermediaire.uph).toBeNaN();
|
|
246
|
+
error.mockRestore();
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Détermination du type de toiture (matcher de la table `uph`) selon l'adjacence.
|
|
251
|
+
* @see : Methode_de_calcul_3CL_DPE_2021-338.pdf - page 21
|
|
252
|
+
*/
|
|
253
|
+
test.each([
|
|
254
|
+
['locaux non chauffés non accessible', 'terrasse', 'terrasse'],
|
|
255
|
+
['garage', 'terrasse', 'combles'],
|
|
256
|
+
['extérieur', 'combles aménagés sous rampant', 'combles'],
|
|
257
|
+
['extérieur', 'terrasse', 'terrasse']
|
|
258
|
+
])(
|
|
259
|
+
'adjacence "%s" + type "%s" => type_toiture "%s" dans le matcher',
|
|
260
|
+
(typeAdjacence, typePlancherHaut, typeToitureAttendu) => {
|
|
261
|
+
const ph = {
|
|
262
|
+
donnee_entree: {
|
|
263
|
+
methode_saisie_u: 'isolation inconnue (table forfaitaire)',
|
|
264
|
+
methode_saisie_u0: 'type de paroi inconnu (valeur par défaut)',
|
|
265
|
+
type_adjacence: typeAdjacence,
|
|
266
|
+
type_plancher_haut: typePlancherHaut
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
calc_ph(ph, 'h1a', '1', '0');
|
|
271
|
+
|
|
272
|
+
expect(tv).toHaveBeenCalledWith('uph', {
|
|
273
|
+
enum_periode_construction_id: '1',
|
|
274
|
+
enum_zone_climatique_id: 'h1a',
|
|
275
|
+
effet_joule: '0',
|
|
276
|
+
type_toiture: typeToitureAttendu
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
test("la période d'isolation, si présente, prime sur la période de construction", () => {
|
|
282
|
+
const ph = {
|
|
283
|
+
donnee_entree: {
|
|
284
|
+
methode_saisie_u: 'isolation inconnue (table forfaitaire)',
|
|
285
|
+
methode_saisie_u0: 'type de paroi inconnu (valeur par défaut)',
|
|
286
|
+
type_adjacence: 'extérieur',
|
|
287
|
+
type_plancher_haut: 'terrasse',
|
|
288
|
+
enum_periode_isolation_id: '6'
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
calc_ph(ph, 'h1a', '1', '0');
|
|
293
|
+
|
|
294
|
+
expect(tv).toHaveBeenCalledWith(
|
|
295
|
+
'uph',
|
|
296
|
+
expect.objectContaining({ enum_periode_construction_id: '6' })
|
|
297
|
+
);
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Compatibilité "bug for bug" : lorsque le DPE fournit un `tv_uph_id`, on relit la ligne
|
|
303
|
+
* de la table `uph` pour, le cas échéant, corriger le type de toiture et l'effet Joule.
|
|
304
|
+
*/
|
|
305
|
+
describe('calc_ph - compatibilité bug for bug (récupération depuis tv_uph_id)', () => {
|
|
306
|
+
beforeEach(() => {
|
|
307
|
+
bugForBugCompat = true;
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
test('type_toiture "combles" du DPE : la valeur du DPE prime sur celle calculée', () => {
|
|
311
|
+
const error = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
312
|
+
// La ligne relue via tv_uph_id impose type_toiture = 'combles' et effet_joule = '0'
|
|
313
|
+
tv.mockImplementation((table, matcher) => {
|
|
314
|
+
if (table === 'uph0') return { ...ROW_UPH0 };
|
|
315
|
+
if (table === 'uph' && matcher.tv_uph_id) {
|
|
316
|
+
return { type_toiture: 'combles', effet_joule: '0' };
|
|
317
|
+
}
|
|
318
|
+
if (table === 'uph') {
|
|
319
|
+
// On vérifie ici que le matcher final utilise bien type_toiture = 'combles'
|
|
320
|
+
return matcher.type_toiture === 'combles' ? { ...ROW_UPH } : null;
|
|
321
|
+
}
|
|
322
|
+
return null;
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
const ph = {
|
|
326
|
+
donnee_entree: {
|
|
327
|
+
methode_saisie_u: 'isolation inconnue (table forfaitaire)',
|
|
328
|
+
methode_saisie_u0: 'type de paroi inconnu (valeur par défaut)',
|
|
329
|
+
type_adjacence: 'extérieur', // calcul => 'terrasse'
|
|
330
|
+
type_plancher_haut: 'terrasse',
|
|
331
|
+
tv_uph_id: 7,
|
|
332
|
+
description: 'PH test'
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
calc_ph(ph, 'h1a', '1', '0');
|
|
337
|
+
|
|
338
|
+
expect(error).toHaveBeenCalled();
|
|
339
|
+
expect(tv).toHaveBeenCalledWith('uph', expect.objectContaining({ type_toiture: 'combles' }));
|
|
340
|
+
expect(ph.donnee_intermediaire.uph).toBe(0.3);
|
|
341
|
+
error.mockRestore();
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
test('effet_joule du DPE différent : la valeur du DPE est conservée dans le matcher', () => {
|
|
345
|
+
const error = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
346
|
+
tv.mockImplementation((table, matcher) => {
|
|
347
|
+
if (table === 'uph0') return { ...ROW_UPH0 };
|
|
348
|
+
if (table === 'uph' && matcher.tv_uph_id) {
|
|
349
|
+
// type_toiture 'terrasse' => pas de correction du type ; effet_joule différent => correction
|
|
350
|
+
return { type_toiture: 'terrasse', effet_joule: '1' };
|
|
351
|
+
}
|
|
352
|
+
if (table === 'uph') return { ...ROW_UPH };
|
|
353
|
+
return null;
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
const ph = {
|
|
357
|
+
donnee_entree: {
|
|
358
|
+
methode_saisie_u: 'isolation inconnue (table forfaitaire)',
|
|
359
|
+
methode_saisie_u0: 'type de paroi inconnu (valeur par défaut)',
|
|
360
|
+
type_adjacence: 'extérieur',
|
|
361
|
+
type_plancher_haut: 'terrasse',
|
|
362
|
+
tv_uph_id: 7,
|
|
363
|
+
description: 'PH test'
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
calc_ph(ph, 'h1a', '1', '0');
|
|
368
|
+
|
|
369
|
+
expect(error).toHaveBeenCalled();
|
|
370
|
+
expect(tv).toHaveBeenCalledWith('uph', expect.objectContaining({ effet_joule: '1' }));
|
|
371
|
+
error.mockRestore();
|
|
372
|
+
});
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
describe('calc_ph - année de construction saisie (table forfaitaire)', () => {
|
|
376
|
+
test("période d'isolation renseignée : elle est utilisée comme période de la table", () => {
|
|
377
|
+
const ph = {
|
|
378
|
+
donnee_entree: {
|
|
379
|
+
methode_saisie_u: 'année de construction saisie (table forfaitaire)',
|
|
380
|
+
methode_saisie_u0: 'type de paroi inconnu (valeur par défaut)',
|
|
381
|
+
type_adjacence: 'extérieur',
|
|
382
|
+
type_plancher_haut: 'terrasse',
|
|
383
|
+
enum_periode_isolation_id: '6'
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
calc_ph(ph, 'h1a', '5', '0');
|
|
388
|
+
|
|
389
|
+
expect(tv).toHaveBeenCalledWith(
|
|
390
|
+
'uph',
|
|
391
|
+
expect.objectContaining({ enum_periode_construction_id: '6' })
|
|
392
|
+
);
|
|
393
|
+
expect(ph.donnee_intermediaire.uph).toBe(0.3);
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
test.each([
|
|
397
|
+
['1', 'avant 1948'],
|
|
398
|
+
['3', '1948-1974']
|
|
399
|
+
])(
|
|
400
|
+
"période de construction ancienne (%s = %s) sans année d'isolation : isolation forcée à 1975-1977",
|
|
401
|
+
(pcId) => {
|
|
402
|
+
const ph = {
|
|
403
|
+
donnee_entree: {
|
|
404
|
+
methode_saisie_u: 'année de construction saisie (table forfaitaire)',
|
|
405
|
+
methode_saisie_u0: 'type de paroi inconnu (valeur par défaut)',
|
|
406
|
+
type_adjacence: 'extérieur',
|
|
407
|
+
type_plancher_haut: 'terrasse'
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
calc_ph(ph, 'h1a', pcId, '0');
|
|
412
|
+
|
|
413
|
+
// getKeyByValue(periode_isolation, '1975-1977') = '2'
|
|
414
|
+
expect(tv).toHaveBeenCalledWith(
|
|
415
|
+
'uph',
|
|
416
|
+
expect.objectContaining({ enum_periode_construction_id: '2' })
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
);
|
|
420
|
+
|
|
421
|
+
test("période de construction récente sans année d'isolation : période de construction conservée", () => {
|
|
422
|
+
const ph = {
|
|
423
|
+
donnee_entree: {
|
|
424
|
+
methode_saisie_u: 'année de construction saisie (table forfaitaire)',
|
|
425
|
+
methode_saisie_u0: 'type de paroi inconnu (valeur par défaut)',
|
|
426
|
+
type_adjacence: 'extérieur',
|
|
427
|
+
type_plancher_haut: 'terrasse'
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
calc_ph(ph, 'h1a', '5', '0');
|
|
432
|
+
|
|
433
|
+
// pc = '1989-2000' => pas de forçage, la période de construction '5' est conservée
|
|
434
|
+
expect(tv).toHaveBeenCalledWith(
|
|
435
|
+
'uph',
|
|
436
|
+
expect.objectContaining({ enum_periode_construction_id: '5' })
|
|
437
|
+
);
|
|
438
|
+
});
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
describe('calc_ph - méthode de saisie inconnue', () => {
|
|
442
|
+
test('aucun calcul de Uph et avertissement émis', () => {
|
|
443
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
444
|
+
const ph = { donnee_entree: { methode_saisie_u: 'valeur inexistante' } };
|
|
445
|
+
|
|
446
|
+
calc_ph(ph, 'h1a', '1', '0');
|
|
447
|
+
|
|
448
|
+
expect(ph.donnee_intermediaire.uph).toBeUndefined();
|
|
449
|
+
expect(warn).toHaveBeenCalled();
|
|
450
|
+
warn.mockRestore();
|
|
451
|
+
});
|
|
452
|
+
});
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Dépendances mockées pour isoler `calc_porte` :
|
|
5
|
+
* - `b` (3.1_b.js) : calcul du coefficient de réduction des déperditions, ici un simple espion ;
|
|
6
|
+
* - `tv` : accès à la table de valeurs `uporte` (on contrôle la ligne retournée) ;
|
|
7
|
+
* - `requestInput` : passe-plat qui renvoie la donnée d'entrée demandée.
|
|
8
|
+
*/
|
|
9
|
+
vi.mock('./3.1_b.js', () => ({
|
|
10
|
+
default: vi.fn()
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
vi.mock('./utils.js', () => ({
|
|
14
|
+
tv: vi.fn(),
|
|
15
|
+
requestInput: (de, du, field) => de[field]
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
const { default: calc_porte } = await import('./3.3.1.4_porte.js');
|
|
19
|
+
const { default: b } = await import('./3.1_b.js');
|
|
20
|
+
const { tv } = await import('./utils.js');
|
|
21
|
+
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
vi.mocked(b).mockReset();
|
|
24
|
+
vi.mocked(tv).mockReset();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 3.3.1.4 Coefficient de transmission surfacique des portes (Uporte)
|
|
29
|
+
* @see : Methode_de_calcul_3CL_DPE_2021-338.pdf - §3.3.1.4
|
|
30
|
+
*/
|
|
31
|
+
describe('calc_porte - coefficient de transmission des portes', () => {
|
|
32
|
+
test('valeur forfaitaire : Uporte lu dans la table via le type de porte', () => {
|
|
33
|
+
tv.mockReturnValue({ uporte: '2.4', tv_uporte_id: '15' });
|
|
34
|
+
const porte = {
|
|
35
|
+
donnee_entree: {
|
|
36
|
+
surface_porte: 2,
|
|
37
|
+
methode_saisie_uporte: 'valeur forfaitaire',
|
|
38
|
+
enum_type_porte_id: '3'
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
calc_porte(porte, 1);
|
|
43
|
+
|
|
44
|
+
expect(tv).toHaveBeenCalledWith('uporte', { enum_type_porte_id: '3' }, porte.donnee_entree);
|
|
45
|
+
expect(porte.donnee_intermediaire.uporte).toBe(2.4);
|
|
46
|
+
expect(porte.donnee_entree.tv_uporte_id).toBe(15);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('saisie directe : Uporte pris depuis la valeur saisie, sans accès table', () => {
|
|
50
|
+
const porte = {
|
|
51
|
+
donnee_entree: {
|
|
52
|
+
surface_porte: 2,
|
|
53
|
+
methode_saisie_uporte: 'saisie directe',
|
|
54
|
+
uporte_saisi: 1.8
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
calc_porte(porte, 1);
|
|
59
|
+
|
|
60
|
+
expect(tv).not.toHaveBeenCalled();
|
|
61
|
+
expect(porte.donnee_intermediaire.uporte).toBe(1.8);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('le coefficient b est calculé avec la zone climatique fournie', () => {
|
|
65
|
+
tv.mockReturnValue({ uporte: '2.4', tv_uporte_id: '15' });
|
|
66
|
+
const porte = {
|
|
67
|
+
donnee_entree: {
|
|
68
|
+
surface_porte: 2,
|
|
69
|
+
methode_saisie_uporte: 'valeur forfaitaire',
|
|
70
|
+
enum_type_porte_id: '3'
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
calc_porte(porte, 8);
|
|
75
|
+
|
|
76
|
+
expect(b).toHaveBeenCalledWith(
|
|
77
|
+
porte.donnee_intermediaire,
|
|
78
|
+
porte.donnee_entree,
|
|
79
|
+
porte.donnee_utilisateur,
|
|
80
|
+
8
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test('aucune valeur forfaitaire trouvée : Uporte reste indéfini', () => {
|
|
85
|
+
tv.mockReturnValue(null);
|
|
86
|
+
const porte = {
|
|
87
|
+
donnee_entree: {
|
|
88
|
+
surface_porte: 2,
|
|
89
|
+
methode_saisie_uporte: 'valeur forfaitaire',
|
|
90
|
+
enum_type_porte_id: '3'
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
calc_porte(porte, 1);
|
|
95
|
+
|
|
96
|
+
expect(porte.donnee_intermediaire.uporte).toBeUndefined();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('les objets donnee_utilisateur et donnee_intermediaire sont attachés à la porte', () => {
|
|
100
|
+
tv.mockReturnValue({ uporte: '2.4', tv_uporte_id: '15' });
|
|
101
|
+
const porte = {
|
|
102
|
+
donnee_entree: {
|
|
103
|
+
surface_porte: 2,
|
|
104
|
+
methode_saisie_uporte: 'valeur forfaitaire',
|
|
105
|
+
enum_type_porte_id: '3'
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
calc_porte(porte, 1);
|
|
110
|
+
|
|
111
|
+
expect(porte.donnee_utilisateur).toBeDefined();
|
|
112
|
+
expect(porte.donnee_intermediaire).toBeDefined();
|
|
113
|
+
});
|
|
114
|
+
});
|