@open3cl/engine 1.8.10 → 1.8.12
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/13.2_generateur_combustion.js +33 -1
- package/13.2_generateur_combustion.spec.js +86 -2
- package/13.2_generateur_combustion_chaudiere.js +92 -32
- package/13.2_generateur_combustion_chaudiere.spec.js +83 -1
- package/14_generateur_ecs.js +13 -3
- package/14_generateur_ecs.spec.js +40 -0
- package/3.2.1_mur.js +71 -2
- package/3.2.1_mur.spec.js +83 -1
- package/9_generateur_ch.js +9 -3
- package/9_generateur_ch.spec.js +46 -0
- package/README.md +15 -15
- package/engine.js +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { bug_for_bug_compat, convertExpression, tv, tvColumnLines } from './utils.js';
|
|
2
2
|
import enums from './enums.js';
|
|
3
3
|
import { updateGenerateurBouilleurs } from './13.2_generateur_combustion_bouilleur.js';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
getChaudiereFioulDefautId,
|
|
6
|
+
updateGenerateurChaudieres
|
|
7
|
+
} from './13.2_generateur_combustion_chaudiere.js';
|
|
5
8
|
import { updateGenerateurPacs } from './13.2_generateur_pac.js';
|
|
6
9
|
import getFicheTechnique from './ficheTechnique.js';
|
|
7
10
|
import { evaluateFormula as evaluateTvFormula } from './formula.js';
|
|
@@ -128,6 +131,35 @@ export function tv_generateur_combustion(dpe, di, de, type, GV, tbase, methodeSa
|
|
|
128
131
|
enumTypeGenerateurId = checkEcsVsChauffageForMixteGeneration(dpe, de, typeGenerateurKey);
|
|
129
132
|
}
|
|
130
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Système collectif par défaut : chaudière fioul standard datant de la construction du bâtiment.
|
|
136
|
+
* Si tv_generateur_combustion_id pointe vers une chaudière fioul compatible avec le système par défaut,
|
|
137
|
+
* la période de la chaudière est déterminée à partir de l'année de construction du bâtiment.
|
|
138
|
+
* @see Methode_de_calcul_3CL_DPE_2021-338.pdf - §17.2.1.1
|
|
139
|
+
*/
|
|
140
|
+
if (
|
|
141
|
+
((type === 'ecs' && enumTypeGenerateurId === '84') ||
|
|
142
|
+
(type === 'ch' && enumTypeGenerateurId === '119')) &&
|
|
143
|
+
de.tv_generateur_combustion_id
|
|
144
|
+
) {
|
|
145
|
+
const rowDpe = tv('generateur_combustion', {
|
|
146
|
+
tv_generateur_combustion_id: de.tv_generateur_combustion_id
|
|
147
|
+
});
|
|
148
|
+
const chaudiereFioulDefautId = getChaudiereFioulDefautId(
|
|
149
|
+
dpe,
|
|
150
|
+
type,
|
|
151
|
+
rowDpe?.[typeGenerateurKey]?.split('|')[0]
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
if (
|
|
155
|
+
chaudiereFioulDefautId &&
|
|
156
|
+
rowDpe?.[typeGenerateurKey]?.split('|').includes(enumTypeGenerateurId)
|
|
157
|
+
) {
|
|
158
|
+
enumTypeGenerateurId = chaudiereFioulDefautId;
|
|
159
|
+
de[typeGenerateurKey] = chaudiereFioulDefautId;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
131
163
|
/**
|
|
132
164
|
* Si le type de générateur est
|
|
133
165
|
* 84 - ECS - système collectif par défaut en abscence d'information : chaudière fioul pénalisante
|
|
@@ -43,7 +43,8 @@ vi.mock('./13.2_generateur_combustion_bouilleur.js', () => ({
|
|
|
43
43
|
updateGenerateurBouilleurs: vi.fn()
|
|
44
44
|
}));
|
|
45
45
|
vi.mock('./13.2_generateur_combustion_chaudiere.js', () => ({
|
|
46
|
-
updateGenerateurChaudieres: vi.fn()
|
|
46
|
+
updateGenerateurChaudieres: vi.fn(),
|
|
47
|
+
getChaudiereFioulDefautId: vi.fn()
|
|
47
48
|
}));
|
|
48
49
|
vi.mock('./13.2_generateur_pac.js', () => ({
|
|
49
50
|
updateGenerateurPacs: vi.fn()
|
|
@@ -67,7 +68,8 @@ const {
|
|
|
67
68
|
const { tv, tvColumnLines } = await import('./utils.js');
|
|
68
69
|
const { conventionPuissanceNominale } = await import('./13.2_generateur_combustion_pn.js');
|
|
69
70
|
const { updateGenerateurBouilleurs } = await import('./13.2_generateur_combustion_bouilleur.js');
|
|
70
|
-
const { updateGenerateurChaudieres } =
|
|
71
|
+
const { updateGenerateurChaudieres, getChaudiereFioulDefautId } =
|
|
72
|
+
await import('./13.2_generateur_combustion_chaudiere.js');
|
|
71
73
|
const { updateGenerateurPacs } = await import('./13.2_generateur_pac.js');
|
|
72
74
|
const { default: getFicheTechnique } = await import('./ficheTechnique.js');
|
|
73
75
|
|
|
@@ -77,6 +79,7 @@ beforeEach(() => {
|
|
|
77
79
|
vi.mocked(tvColumnLines).mockReturnValue([]);
|
|
78
80
|
vi.mocked(updateGenerateurBouilleurs).mockReset();
|
|
79
81
|
vi.mocked(updateGenerateurChaudieres).mockReset();
|
|
82
|
+
vi.mocked(getChaudiereFioulDefautId).mockReset();
|
|
80
83
|
vi.mocked(updateGenerateurPacs).mockReset();
|
|
81
84
|
vi.mocked(getFicheTechnique).mockReset();
|
|
82
85
|
vi.mocked(conventionPuissanceNominale).mockReset();
|
|
@@ -317,6 +320,87 @@ describe('tv_generateur_combustion - compatibilité bug_for_bug_compat', () => {
|
|
|
317
320
|
vi.restoreAllMocks();
|
|
318
321
|
});
|
|
319
322
|
|
|
323
|
+
/**
|
|
324
|
+
* Système collectif par défaut : chaudière fioul standard datant de la construction du bâtiment.
|
|
325
|
+
* @see : Methode_de_calcul_3CL_DPE_2021-338.pdf - §17.2.1.1
|
|
326
|
+
*/
|
|
327
|
+
describe('système collectif par défaut : chaudière selon l’année de construction', () => {
|
|
328
|
+
test('CH 119 + ligne compatible : type et ligne de la période de construction retenus', () => {
|
|
329
|
+
vi.mocked(getChaudiereFioulDefautId).mockReturnValue('79');
|
|
330
|
+
tv.mockImplementation((table, matcher) => {
|
|
331
|
+
if (matcher.tv_generateur_combustion_id === '16') {
|
|
332
|
+
return { tv_generateur_combustion_id: '16', enum_type_generateur_ch_id: '75|119' };
|
|
333
|
+
}
|
|
334
|
+
return { ...ROW_DEFAUT, tv_generateur_combustion_id: '20' };
|
|
335
|
+
});
|
|
336
|
+
const dpe = { logement: {} };
|
|
337
|
+
const di = { pn: 20000 };
|
|
338
|
+
const de = {
|
|
339
|
+
enum_type_generateur_ch_id: '119',
|
|
340
|
+
tv_generateur_combustion_id: '16',
|
|
341
|
+
ratio_virtualisation: 1,
|
|
342
|
+
presence_ventouse: 0
|
|
343
|
+
};
|
|
344
|
+
tv_generateur_combustion(dpe, di, de, 'ch', 200, -9, 1);
|
|
345
|
+
|
|
346
|
+
expect(getChaudiereFioulDefautId).toHaveBeenCalledWith(dpe, 'ch', '75');
|
|
347
|
+
expect(de.enum_type_generateur_ch_id).toBe('79');
|
|
348
|
+
// La ligne est recherchée avec le type de la période de construction
|
|
349
|
+
expect(tv).toHaveBeenCalledWith(
|
|
350
|
+
'generateur_combustion',
|
|
351
|
+
expect.objectContaining({ enum_type_generateur_ch_id: '79' })
|
|
352
|
+
);
|
|
353
|
+
expect(de.tv_generateur_combustion_id).toBe(20);
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
test('ECS 84 + ligne compatible : type de la période de construction retenu', () => {
|
|
357
|
+
vi.mocked(getChaudiereFioulDefautId).mockReturnValue('39');
|
|
358
|
+
tv.mockImplementation((table, matcher) => {
|
|
359
|
+
if (matcher.tv_generateur_combustion_id === '16') {
|
|
360
|
+
return { tv_generateur_combustion_id: '16', enum_type_generateur_ecs_id: '35|84' };
|
|
361
|
+
}
|
|
362
|
+
return { ...ROW_DEFAUT, tv_generateur_combustion_id: '20' };
|
|
363
|
+
});
|
|
364
|
+
const de = {
|
|
365
|
+
enum_type_generateur_ecs_id: '84',
|
|
366
|
+
tv_generateur_combustion_id: '16',
|
|
367
|
+
ratio_virtualisation: 1,
|
|
368
|
+
presence_ventouse: 0
|
|
369
|
+
};
|
|
370
|
+
tv_generateur_combustion({}, { pn: 20000 }, de, 'ecs', 200, -9, 1);
|
|
371
|
+
|
|
372
|
+
expect(getChaudiereFioulDefautId).toHaveBeenCalledWith({}, 'ecs', '35');
|
|
373
|
+
expect(de.enum_type_generateur_ecs_id).toBe('39');
|
|
374
|
+
expect(de.tv_generateur_combustion_id).toBe(20);
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
test('ligne non compatible avec le système par défaut : type inchangé', () => {
|
|
378
|
+
vi.mocked(getChaudiereFioulDefautId).mockReturnValue('39');
|
|
379
|
+
tv.mockReturnValue({ ...ROW_DEFAUT, enum_type_generateur_ecs_id: '57|104' });
|
|
380
|
+
const de = {
|
|
381
|
+
enum_type_generateur_ecs_id: '84',
|
|
382
|
+
tv_generateur_combustion_id: '42',
|
|
383
|
+
ratio_virtualisation: 1,
|
|
384
|
+
presence_ventouse: 0
|
|
385
|
+
};
|
|
386
|
+
tv_generateur_combustion({}, { pn: 20000 }, de, 'ecs', 200, -9, 1);
|
|
387
|
+
expect(de.enum_type_generateur_ecs_id).toBe('84');
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
test('année de construction inconnue : type inchangé', () => {
|
|
391
|
+
vi.mocked(getChaudiereFioulDefautId).mockReturnValue(undefined);
|
|
392
|
+
tv.mockReturnValue({ ...ROW_DEFAUT, enum_type_generateur_ch_id: '75|119' });
|
|
393
|
+
const de = {
|
|
394
|
+
enum_type_generateur_ch_id: '119',
|
|
395
|
+
tv_generateur_combustion_id: '16',
|
|
396
|
+
ratio_virtualisation: 1,
|
|
397
|
+
presence_ventouse: 0
|
|
398
|
+
};
|
|
399
|
+
tv_generateur_combustion({}, { pn: 20000 }, de, 'ch', 200, -9, 1);
|
|
400
|
+
expect(de.enum_type_generateur_ch_id).toBe('119');
|
|
401
|
+
});
|
|
402
|
+
});
|
|
403
|
+
|
|
320
404
|
test('type 84 sans tv_generateur_combustion_id : retour au chemin forfaitaire nominal', () => {
|
|
321
405
|
state.bug = true;
|
|
322
406
|
tv.mockReturnValue({ ...ROW_DEFAUT });
|
|
@@ -1,5 +1,93 @@
|
|
|
1
1
|
import getFicheTechnique from './ficheTechnique.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Ids des chaudières fioul classiques / standard pour les différentes périodes d'installation
|
|
5
|
+
* (seuil = première année de la période)
|
|
6
|
+
*/
|
|
7
|
+
const CHAUDIERES_FIOUL_ECS = {
|
|
8
|
+
1948: '35',
|
|
9
|
+
1970: '36',
|
|
10
|
+
1976: '37',
|
|
11
|
+
1981: '38',
|
|
12
|
+
1991: '39',
|
|
13
|
+
2015: '40'
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const CHAUDIERES_FIOUL_CH = {
|
|
17
|
+
1948: '75',
|
|
18
|
+
1970: '76',
|
|
19
|
+
1976: '77',
|
|
20
|
+
1981: '78',
|
|
21
|
+
1991: '79',
|
|
22
|
+
2015: '80'
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Retourne l'identifiant associé au plus grand seuil inférieur ou égal à l'année donnée.
|
|
27
|
+
* Pour une année antérieure au premier seuil, l'identifiant du premier seuil est retenu.
|
|
28
|
+
* @param values {Record<string, string>}
|
|
29
|
+
* @param annee {number}
|
|
30
|
+
* @returns {string}
|
|
31
|
+
*/
|
|
32
|
+
export function findIdForAnnee(values, annee) {
|
|
33
|
+
const entries = Object.entries(values).sort((a, b) => b[0] - a[0]);
|
|
34
|
+
|
|
35
|
+
for (const [threshold, value] of entries) {
|
|
36
|
+
if (annee >= Number(threshold)) {
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return entries[entries.length - 1][1];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Système collectif par défaut en absence d'information : chaudière fioul pénalisante
|
|
46
|
+
* (enum_type_generateur_ch_id = 119 / enum_type_generateur_ecs_id = 84)
|
|
47
|
+
*
|
|
48
|
+
* "En présence d'une installation de production collective de chauffage et d'ECS, si aucune information n'est
|
|
49
|
+
* communiquée sur les équipements collectifs, un calcul par défaut se fera avec une chaudière atmosphérique mixte
|
|
50
|
+
* standard datant de la construction du bâtiment. L'énergie utilisée par le système sera du fioul."
|
|
51
|
+
* @see Methode_de_calcul_3CL_DPE_2021-338.pdf - §17.2.1.1
|
|
52
|
+
*
|
|
53
|
+
* Retourne l'identifiant de la chaudière fioul dont la période correspond à l'année de construction du bâtiment,
|
|
54
|
+
* ou undefined si l'année de construction n'est pas connue.
|
|
55
|
+
*
|
|
56
|
+
* Si la ligne tv_generateur_combustion_id saisie correspond à une chaudière fioul dont la période est
|
|
57
|
+
* postérieure ou égale à celle de la construction (chaudière remplacée), l'information est connue et
|
|
58
|
+
* doit être utilisée : "Dans le cas où certaines de ces informations sont connues sur l'installation
|
|
59
|
+
* collective, elles pourront être utilisées" (§17.2.1.1). Seule une période saisie antérieure à la
|
|
60
|
+
* construction, non crédible, est redressée.
|
|
61
|
+
*
|
|
62
|
+
* @param dpe {FullDpe}
|
|
63
|
+
* @param type {'ch' | 'ecs'}
|
|
64
|
+
* @param typeSaisiId {string|undefined} type de chaudière correspondant à la ligne tv saisie
|
|
65
|
+
* @returns {string|undefined}
|
|
66
|
+
*/
|
|
67
|
+
export function getChaudiereFioulDefautId(dpe, type, typeSaisiId) {
|
|
68
|
+
const anneeConstruction = parseInt(
|
|
69
|
+
dpe?.logement?.caracteristique_generale?.annee_construction,
|
|
70
|
+
10
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
if (Number.isNaN(anneeConstruction)) {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const chaudieres = type === 'ecs' ? CHAUDIERES_FIOUL_ECS : CHAUDIERES_FIOUL_CH;
|
|
78
|
+
const chaudiereConstructionId = findIdForAnnee(chaudieres, anneeConstruction);
|
|
79
|
+
const ids = Object.values(chaudieres);
|
|
80
|
+
|
|
81
|
+
if (
|
|
82
|
+
ids.includes(typeSaisiId) &&
|
|
83
|
+
ids.indexOf(typeSaisiId) >= ids.indexOf(chaudiereConstructionId)
|
|
84
|
+
) {
|
|
85
|
+
return typeSaisiId;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return chaudiereConstructionId;
|
|
89
|
+
}
|
|
90
|
+
|
|
3
91
|
/**
|
|
4
92
|
* Pour les générateurs "Autre système à combustion", les calculs sont faits comme pour les chaudières standard
|
|
5
93
|
* @param dpe {FullDpe}
|
|
@@ -27,14 +115,7 @@ export function updateGenerateurChaudieres(dpe, de, type) {
|
|
|
27
115
|
2001: '49',
|
|
28
116
|
2015: '50'
|
|
29
117
|
},
|
|
30
|
-
79:
|
|
31
|
-
1948: '35',
|
|
32
|
-
1970: '36',
|
|
33
|
-
1976: '37',
|
|
34
|
-
1981: '38',
|
|
35
|
-
1991: '39',
|
|
36
|
-
2015: '40'
|
|
37
|
-
},
|
|
118
|
+
79: CHAUDIERES_FIOUL_ECS,
|
|
38
119
|
80: {
|
|
39
120
|
1948: '15',
|
|
40
121
|
1978: '16',
|
|
@@ -44,14 +125,7 @@ export function updateGenerateurChaudieres(dpe, de, type) {
|
|
|
44
125
|
2018: '20',
|
|
45
126
|
2019: '21'
|
|
46
127
|
},
|
|
47
|
-
81:
|
|
48
|
-
1948: '35',
|
|
49
|
-
1970: '36',
|
|
50
|
-
1976: '37',
|
|
51
|
-
1981: '38',
|
|
52
|
-
1991: '39',
|
|
53
|
-
2015: '40'
|
|
54
|
-
}
|
|
128
|
+
81: CHAUDIERES_FIOUL_ECS
|
|
55
129
|
};
|
|
56
130
|
} else {
|
|
57
131
|
/**
|
|
@@ -71,14 +145,7 @@ export function updateGenerateurChaudieres(dpe, de, type) {
|
|
|
71
145
|
2001: '89',
|
|
72
146
|
2015: '90'
|
|
73
147
|
},
|
|
74
|
-
114:
|
|
75
|
-
1948: '75',
|
|
76
|
-
1970: '76',
|
|
77
|
-
1976: '77',
|
|
78
|
-
1981: '78',
|
|
79
|
-
1991: '79',
|
|
80
|
-
2015: '80'
|
|
81
|
-
},
|
|
148
|
+
114: CHAUDIERES_FIOUL_CH,
|
|
82
149
|
115: {
|
|
83
150
|
1948: '55',
|
|
84
151
|
1978: '56',
|
|
@@ -88,14 +155,7 @@ export function updateGenerateurChaudieres(dpe, de, type) {
|
|
|
88
155
|
2018: '60',
|
|
89
156
|
2019: '61'
|
|
90
157
|
},
|
|
91
|
-
116:
|
|
92
|
-
1948: '75',
|
|
93
|
-
1970: '76',
|
|
94
|
-
1976: '77',
|
|
95
|
-
1981: '78',
|
|
96
|
-
1991: '79',
|
|
97
|
-
2015: '80'
|
|
98
|
-
}
|
|
158
|
+
116: CHAUDIERES_FIOUL_CH
|
|
99
159
|
};
|
|
100
160
|
}
|
|
101
161
|
|
|
@@ -9,7 +9,8 @@ vi.mock('./ficheTechnique.js', () => ({
|
|
|
9
9
|
default: vi.fn()
|
|
10
10
|
}));
|
|
11
11
|
|
|
12
|
-
const { updateGenerateurChaudieres } =
|
|
12
|
+
const { updateGenerateurChaudieres, findIdForAnnee, getChaudiereFioulDefautId } =
|
|
13
|
+
await import('./13.2_generateur_combustion_chaudiere.js');
|
|
13
14
|
const { default: getFicheTechnique } = await import('./ficheTechnique.js');
|
|
14
15
|
|
|
15
16
|
beforeEach(() => {
|
|
@@ -83,3 +84,84 @@ describe('updateGenerateurChaudieres - substitution par une chaudière équivale
|
|
|
83
84
|
]);
|
|
84
85
|
});
|
|
85
86
|
});
|
|
87
|
+
|
|
88
|
+
describe('findIdForAnnee - sélection de la période', () => {
|
|
89
|
+
const values = { 1948: 'a', 1970: 'b', 1991: 'c' };
|
|
90
|
+
|
|
91
|
+
test('année égale à un seuil : période du seuil retenue', () => {
|
|
92
|
+
expect(findIdForAnnee(values, 1970)).toBe('b');
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test('année entre deux seuils : période du seuil inférieur retenue', () => {
|
|
96
|
+
expect(findIdForAnnee(values, 1990)).toBe('b');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('année postérieure au dernier seuil : période la plus récente', () => {
|
|
100
|
+
expect(findIdForAnnee(values, 2030)).toBe('c');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('année antérieure au premier seuil : période la plus ancienne', () => {
|
|
104
|
+
expect(findIdForAnnee(values, 1900)).toBe('a');
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Système collectif par défaut (ch 119 / ecs 84) : chaudière atmosphérique mixte standard
|
|
110
|
+
* datant de la construction du bâtiment, énergie fioul.
|
|
111
|
+
* @see : Methode_de_calcul_3CL_DPE_2021-338.pdf - §17.2.1.1
|
|
112
|
+
*/
|
|
113
|
+
describe('getChaudiereFioulDefautId - chaudière fioul par défaut selon l’année de construction', () => {
|
|
114
|
+
const dpe = (annee) => ({
|
|
115
|
+
logement: { caracteristique_generale: { annee_construction: annee } }
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test.each([
|
|
119
|
+
[1900, '75', '35'],
|
|
120
|
+
[1969, '75', '35'],
|
|
121
|
+
[1970, '76', '36'],
|
|
122
|
+
[1975, '76', '36'],
|
|
123
|
+
[1976, '77', '37'],
|
|
124
|
+
[1981, '78', '38'],
|
|
125
|
+
[1990, '78', '38'],
|
|
126
|
+
[1991, '79', '39'],
|
|
127
|
+
[2014, '79', '39'],
|
|
128
|
+
[2015, '80', '40'],
|
|
129
|
+
[2024, '80', '40']
|
|
130
|
+
])('construction %s : chaudière ch %s / ecs %s', (annee, chId, ecsId) => {
|
|
131
|
+
expect(getChaudiereFioulDefautId(dpe(annee), 'ch')).toBe(chId);
|
|
132
|
+
expect(getChaudiereFioulDefautId(dpe(annee), 'ecs')).toBe(ecsId);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test('année de construction sous forme de chaîne : prise en compte', () => {
|
|
136
|
+
expect(getChaudiereFioulDefautId(dpe('1995'), 'ch')).toBe('79');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* "Dans le cas où certaines de ces informations sont connues sur l'installation collective, elles
|
|
141
|
+
* pourront être utilisées et complétées par les valeurs par défaut" (§17.2.1.1).
|
|
142
|
+
* Une chaudière saisie d'une période postérieure ou égale à la construction (chaudière remplacée)
|
|
143
|
+
* est conservée ; une période antérieure à la construction, non crédible, est redressée.
|
|
144
|
+
*/
|
|
145
|
+
test.each([
|
|
146
|
+
// [annee, type saisi, attendu, type]
|
|
147
|
+
[1930, '77', '77', 'ch'], // 2162E1020576I : chaudière 1976-1980 dans un bâtiment de 1930
|
|
148
|
+
[1970, '78', '78', 'ch'], // 2262E0012158B : chaudière 1981-1990 dans un bâtiment de 1970
|
|
149
|
+
[1930, '39', '39', 'ecs'], // 2262E0038009I : chaudière 1991-2014 dans un bâtiment de 1930
|
|
150
|
+
[1995, '79', '79', 'ch'], // même période que la construction
|
|
151
|
+
[1996, '75', '79', 'ch'], // 2368E2119912U : chaudière < 1970 dans un bâtiment de 1996
|
|
152
|
+
[2000, '36', '39', 'ecs'], // chaudière 1970-1975 dans un bâtiment de 2000
|
|
153
|
+
[1996, '99', '79', 'ch'], // type saisi hors chaudières fioul standard
|
|
154
|
+
[1996, undefined, '79', 'ch']
|
|
155
|
+
])(
|
|
156
|
+
'construction %s, type saisi %s : chaudière %s retenue (%s)',
|
|
157
|
+
(annee, typeSaisi, attendu, type) => {
|
|
158
|
+
expect(getChaudiereFioulDefautId(dpe(annee), type, typeSaisi)).toBe(attendu);
|
|
159
|
+
}
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
test('année de construction absente : aucune chaudière par défaut', () => {
|
|
163
|
+
expect(getChaudiereFioulDefautId(dpe(undefined), 'ch')).toBeUndefined();
|
|
164
|
+
expect(getChaudiereFioulDefautId({}, 'ecs')).toBeUndefined();
|
|
165
|
+
expect(getChaudiereFioulDefautId(undefined, 'ecs')).toBeUndefined();
|
|
166
|
+
});
|
|
167
|
+
});
|
package/14_generateur_ecs.js
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
import { conso_aux_gen } from './15_conso_aux.js';
|
|
16
16
|
import { scopOrCop } from './12.4_pac.js';
|
|
17
17
|
import getFicheTechnique from './ficheTechnique.js';
|
|
18
|
+
import { getChaudiereFioulDefautId } from './13.2_generateur_combustion_chaudiere.js';
|
|
18
19
|
|
|
19
20
|
function tv_pertes_stockage(di, de, VsCollectif) {
|
|
20
21
|
let vb;
|
|
@@ -257,10 +258,19 @@ export default function calc_gen_ecs(dpe, gen_ecs, ecs_di, ecs_de, GV, ca_id, zc
|
|
|
257
258
|
});
|
|
258
259
|
|
|
259
260
|
if (row) {
|
|
260
|
-
// On prend par défaut le premier type de générateur pour effectuer les calculs de rendement
|
|
261
261
|
const typeGenerateurEcs = row.enum_type_generateur_ecs_id?.split('|');
|
|
262
|
-
|
|
263
|
-
|
|
262
|
+
// Chaudière fioul standard datant de la construction du bâtiment (§17.2.1.1)
|
|
263
|
+
const chaudiereFioulDefautId = getChaudiereFioulDefautId(
|
|
264
|
+
dpe,
|
|
265
|
+
'ecs',
|
|
266
|
+
typeGenerateurEcs?.[0]
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
if (chaudiereFioulDefautId && typeGenerateurEcs?.includes('84')) {
|
|
270
|
+
// La chaudière fioul par défaut dépend de l'année de construction du bâtiment
|
|
271
|
+
de.enum_type_generateur_ecs_id = chaudiereFioulDefautId;
|
|
272
|
+
} else if (typeGenerateurEcs && typeGenerateurEcs.length) {
|
|
273
|
+
// On prend par défaut le premier type de générateur pour effectuer les calculs de rendement
|
|
264
274
|
de.enum_type_generateur_ecs_id = typeGenerateurEcs[0];
|
|
265
275
|
}
|
|
266
276
|
}
|
|
@@ -61,6 +61,10 @@ vi.mock('./ficheTechnique.js', () => ({
|
|
|
61
61
|
default: vi.fn()
|
|
62
62
|
}));
|
|
63
63
|
|
|
64
|
+
vi.mock('./13.2_generateur_combustion_chaudiere.js', () => ({
|
|
65
|
+
getChaudiereFioulDefautId: vi.fn()
|
|
66
|
+
}));
|
|
67
|
+
|
|
64
68
|
const {
|
|
65
69
|
default: calc_gen_ecs,
|
|
66
70
|
rg_chauffe_eau_gaz,
|
|
@@ -73,6 +77,7 @@ const { tvColumnIDs, requestInput, requestInputID, tv, getVolumeStockageFromDesc
|
|
|
73
77
|
const { tv_generateur_combustion } = await import('./13.2_generateur_combustion.js');
|
|
74
78
|
const { scopOrCop } = await import('./12.4_pac.js');
|
|
75
79
|
const { default: getFicheTechnique } = await import('./ficheTechnique.js');
|
|
80
|
+
const { getChaudiereFioulDefautId } = await import('./13.2_generateur_combustion_chaudiere.js');
|
|
76
81
|
|
|
77
82
|
/**
|
|
78
83
|
* 14. Générateur d'ECS : rendements et consommations
|
|
@@ -632,6 +637,41 @@ describe('calc_gen_ecs - consommation par générateur', () => {
|
|
|
632
637
|
expect(g.donnee_intermediaire.conso_ecs).toBeCloseTo(37.03703703703703, 9);
|
|
633
638
|
});
|
|
634
639
|
|
|
640
|
+
/**
|
|
641
|
+
* Type 84 : chaudière fioul standard datant de la construction du bâtiment.
|
|
642
|
+
* @see : Methode_de_calcul_3CL_DPE_2021-338.pdf - §17.2.1.1
|
|
643
|
+
*/
|
|
644
|
+
test('type 84 combustion compatible 84 : chaudière de la période de construction retenue', () => {
|
|
645
|
+
vi.mocked(getChaudiereFioulDefautId).mockReturnValue('39');
|
|
646
|
+
vi.mocked(tv).mockReturnValue({ enum_type_generateur_ecs_id: '35|84' });
|
|
647
|
+
const dpe = { logement: {} };
|
|
648
|
+
const g = gen({
|
|
649
|
+
type_energie: 'fioul domestique',
|
|
650
|
+
enum_type_generateur_ecs_id: '84',
|
|
651
|
+
tv_generateur_combustion_id: '16',
|
|
652
|
+
enum_methode_saisie_carac_sys_id: '1'
|
|
653
|
+
});
|
|
654
|
+
calc_gen_ecs(dpe, g, ecs_di, ecs_de, 0, '1', '1', 'immeuble');
|
|
655
|
+
|
|
656
|
+
expect(getChaudiereFioulDefautId).toHaveBeenCalledWith(dpe, 'ecs', '35');
|
|
657
|
+
// 39 au lieu du premier type de la ligne (35)
|
|
658
|
+
expect(g.donnee_entree.enum_type_generateur_ecs_id).toBe('39');
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
test('type 84 combustion non compatible 84 (générateur décrit) : premier type conservé', () => {
|
|
662
|
+
vi.mocked(getChaudiereFioulDefautId).mockReturnValue('39');
|
|
663
|
+
vi.mocked(tv).mockReturnValue({ enum_type_generateur_ecs_id: '57|104' });
|
|
664
|
+
const g = gen({
|
|
665
|
+
type_energie: 'gaz naturel',
|
|
666
|
+
enum_type_generateur_ecs_id: '84',
|
|
667
|
+
tv_generateur_combustion_id: '13',
|
|
668
|
+
enum_methode_saisie_carac_sys_id: '1'
|
|
669
|
+
});
|
|
670
|
+
calc_gen_ecs({}, g, ecs_di, ecs_de, 0, '1', '1', 'immeuble');
|
|
671
|
+
|
|
672
|
+
expect(g.donnee_entree.enum_type_generateur_ecs_id).toBe('57');
|
|
673
|
+
});
|
|
674
|
+
|
|
635
675
|
/**
|
|
636
676
|
* Réseau de chaleur : redressement de reseau_distribution_isole (bug_for_bug_compat).
|
|
637
677
|
*/
|
package/3.2.1_mur.js
CHANGED
|
@@ -8,9 +8,78 @@ import {
|
|
|
8
8
|
getThicknessFromDescription
|
|
9
9
|
} from './utils.js';
|
|
10
10
|
import b from './3.1_b.js';
|
|
11
|
+
import tvs from './tv.js';
|
|
11
12
|
|
|
12
13
|
const scriptName = new URL(import.meta.url).pathname.split('/').pop();
|
|
13
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Ramène une épaisseur de structure sur une colonne de la table Umur0 du matériau déclaré.
|
|
17
|
+
*
|
|
18
|
+
* 3.2.1.2 Calcul des Umur0 : la valeur est lue dans le tableau du matériau de structure déclaré.
|
|
19
|
+
* Lorsque l'épaisseur saisie n'est pas une colonne de ce tableau (ex : 16 cm alors que la table
|
|
20
|
+
* propose 15 et 20), la recherche ne doit jamais basculer vers la ligne d'un autre matériau
|
|
21
|
+
* (cf. issue #138).
|
|
22
|
+
*
|
|
23
|
+
* La méthode ne précise pas la règle d'arrondi pour Umur0. Convention retenue (pratique des
|
|
24
|
+
* logiciels) : colonne la plus proche, et en cas d'égalité la colonne inférieure (la plus
|
|
25
|
+
* défavorable thermiquement). Les bornes ouvertes « ≤ x » / « ≥ x » sont ramenées à x.
|
|
26
|
+
*
|
|
27
|
+
* @see : Methode_de_calcul_3CL_DPE_2021-338.pdf - §3.2.1.2
|
|
28
|
+
*
|
|
29
|
+
* @param enumMateriauxStructureMurId {string|number}
|
|
30
|
+
* @param epaisseur {number|string}
|
|
31
|
+
* @returns {number|string} épaisseur d'une colonne de la table, ou la valeur initiale si la table
|
|
32
|
+
* ne propose pas d'épaisseur pour ce matériau ou si l'épaisseur n'est pas numérique
|
|
33
|
+
*/
|
|
34
|
+
export function epaisseurStructureTable(enumMateriauxStructureMurId, epaisseur) {
|
|
35
|
+
const ep = typeof epaisseur === 'number' ? epaisseur : Number(epaisseur);
|
|
36
|
+
if (!Number.isFinite(ep) || ep <= 0) return epaisseur;
|
|
37
|
+
|
|
38
|
+
const colonnes = tvs.umur0
|
|
39
|
+
.filter(
|
|
40
|
+
(row) =>
|
|
41
|
+
String(row.enum_materiaux_structure_mur_id) === String(enumMateriauxStructureMurId) &&
|
|
42
|
+
row.epaisseur_structure
|
|
43
|
+
)
|
|
44
|
+
.map((row) => {
|
|
45
|
+
const valeur = String(row.epaisseur_structure);
|
|
46
|
+
return {
|
|
47
|
+
valeur: parseFloat(valeur.replace(/[≤≥\s]/g, '')),
|
|
48
|
+
inf: valeur.includes('≤'),
|
|
49
|
+
sup: valeur.includes('≥')
|
|
50
|
+
};
|
|
51
|
+
})
|
|
52
|
+
.filter((colonne) => Number.isFinite(colonne.valeur));
|
|
53
|
+
|
|
54
|
+
if (colonnes.length === 0) return epaisseur;
|
|
55
|
+
|
|
56
|
+
const colonneOuverte = colonnes.find(
|
|
57
|
+
(c) => c.valeur === ep || (c.inf && ep <= c.valeur) || (c.sup && ep >= c.valeur)
|
|
58
|
+
);
|
|
59
|
+
if (colonneOuverte) return colonneOuverte.valeur;
|
|
60
|
+
|
|
61
|
+
return colonnes.reduce((best, c) => {
|
|
62
|
+
const d = Math.abs(c.valeur - ep);
|
|
63
|
+
const dBest = Math.abs(best.valeur - ep);
|
|
64
|
+
return d < dBest || (d === dBest && c.valeur < best.valeur) ? c : best;
|
|
65
|
+
}).valeur;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Copie du matcher umur0 dont l'épaisseur est ramenée sur une colonne de la table du matériau.
|
|
70
|
+
* @param matcher {{enum_materiaux_structure_mur_id: string, epaisseur_structure?: number}}
|
|
71
|
+
*/
|
|
72
|
+
function matcherEpaisseurTable(matcher) {
|
|
73
|
+
if (matcher.epaisseur_structure === undefined) return matcher;
|
|
74
|
+
return {
|
|
75
|
+
...matcher,
|
|
76
|
+
epaisseur_structure: epaisseurStructureTable(
|
|
77
|
+
matcher.enum_materiaux_structure_mur_id,
|
|
78
|
+
matcher.epaisseur_structure
|
|
79
|
+
)
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
14
83
|
function tv_umur0(di, de, du) {
|
|
15
84
|
const matcher = {
|
|
16
85
|
enum_materiaux_structure_mur_id: de.enum_materiaux_structure_mur_id
|
|
@@ -52,7 +121,7 @@ function tv_umur0(di, de, du) {
|
|
|
52
121
|
}
|
|
53
122
|
}
|
|
54
123
|
}
|
|
55
|
-
let row = tv('umur0', matcher);
|
|
124
|
+
let row = tv('umur0', matcherEpaisseurTable(matcher));
|
|
56
125
|
|
|
57
126
|
if (bug_for_bug_compat) {
|
|
58
127
|
if (
|
|
@@ -63,7 +132,7 @@ function tv_umur0(di, de, du) {
|
|
|
63
132
|
'Mauvais valeur de umur0 trouvé pour une epaisseur > 80, la valeur va être recalculée avec une epaisseur / 10. Il arrive que la valeur soit en millimètres dans le dpe'
|
|
64
133
|
);
|
|
65
134
|
matcher.epaisseur_structure /= 10;
|
|
66
|
-
row = tv('umur0', matcher);
|
|
135
|
+
row = tv('umur0', matcherEpaisseurTable(matcher));
|
|
67
136
|
if (Number(du.tv_umur0_id_avant) !== Number(row.tv_umur0_id)) {
|
|
68
137
|
row = undefined;
|
|
69
138
|
}
|
package/3.2.1_mur.spec.js
CHANGED
|
@@ -23,6 +23,25 @@ vi.mock('./3.1_b.js', () => ({
|
|
|
23
23
|
default: vi.fn()
|
|
24
24
|
}));
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Table `umur0` réduite (mockée) pour `epaisseurStructureTable` : matériau 26 (ossature bois avec
|
|
28
|
+
* isolant en remplissage < 2001) et matériau 2 (bornes ouvertes « ≤ » / « ≥ »).
|
|
29
|
+
*/
|
|
30
|
+
vi.mock('./tv.js', () => ({
|
|
31
|
+
default: {
|
|
32
|
+
umur0: [
|
|
33
|
+
{ tv_umur0_id: '1', enum_materiaux_structure_mur_id: '1', umur0: '2.5' },
|
|
34
|
+
{ tv_umur0_id: '2', enum_materiaux_structure_mur_id: '2', epaisseur_structure: '≤ 20' },
|
|
35
|
+
{ tv_umur0_id: '3', enum_materiaux_structure_mur_id: '2', epaisseur_structure: '25' },
|
|
36
|
+
{ tv_umur0_id: '4', enum_materiaux_structure_mur_id: '2', epaisseur_structure: '≥ 30' },
|
|
37
|
+
{ tv_umur0_id: '144', enum_materiaux_structure_mur_id: '26', epaisseur_structure: '10' },
|
|
38
|
+
{ tv_umur0_id: '145', enum_materiaux_structure_mur_id: '26', epaisseur_structure: '15' },
|
|
39
|
+
{ tv_umur0_id: '146', enum_materiaux_structure_mur_id: '26', epaisseur_structure: '20' },
|
|
40
|
+
{ tv_umur0_id: '151', enum_materiaux_structure_mur_id: '26', epaisseur_structure: '≥ 45' }
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
}));
|
|
44
|
+
|
|
26
45
|
vi.mock('./utils.js', () => ({
|
|
27
46
|
set_bug_for_bug_compat: vi.fn(),
|
|
28
47
|
tv: vi.fn(),
|
|
@@ -35,7 +54,7 @@ vi.mock('./utils.js', () => ({
|
|
|
35
54
|
}
|
|
36
55
|
}));
|
|
37
56
|
|
|
38
|
-
const { default: calc_mur } = await import('./3.2.1_mur.js');
|
|
57
|
+
const { default: calc_mur, epaisseurStructureTable } = await import('./3.2.1_mur.js');
|
|
39
58
|
const { tv, getThicknessFromDescription } = await import('./utils.js');
|
|
40
59
|
|
|
41
60
|
/** Table `umur0` figée : U0 forfaitaire de la paroi nue. */
|
|
@@ -924,3 +943,66 @@ describe('calc_mur - doublage et isolation ITE/ITI (#146)', () => {
|
|
|
924
943
|
expect(mur.donnee_intermediaire.umur0).toBeCloseTo(UMUR0_TABLE, 9);
|
|
925
944
|
});
|
|
926
945
|
});
|
|
946
|
+
|
|
947
|
+
/**
|
|
948
|
+
* 3.2.1.2 Calcul des Umur0 : l'épaisseur saisie est ramenée sur une colonne de la table du
|
|
949
|
+
* matériau déclaré, sans jamais basculer vers un autre matériau (issue #138).
|
|
950
|
+
* Convention (la méthode ne précise pas l'arrondi) : colonne la plus proche, égalité => inférieure.
|
|
951
|
+
* @see : Methode_de_calcul_3CL_DPE_2021-338.pdf - §3.2.1.2
|
|
952
|
+
*/
|
|
953
|
+
describe('epaisseurStructureTable - épaisseur hors table (issue #138)', () => {
|
|
954
|
+
test.each([
|
|
955
|
+
{ epaisseur: 16, attendu: 15, cas: '16 cm => colonne 15 (DPE 2673E0055842U)' },
|
|
956
|
+
{ epaisseur: 18, attendu: 20, cas: '18 cm => colonne 20 (la plus proche)' },
|
|
957
|
+
{ epaisseur: 12, attendu: 10, cas: '12 cm => colonne 10' },
|
|
958
|
+
{ epaisseur: 17.5, attendu: 15, cas: '17,5 cm (égalité) => colonne inférieure 15' },
|
|
959
|
+
{ epaisseur: 8, attendu: 10, cas: 'sous la borne basse => première colonne' },
|
|
960
|
+
{ epaisseur: 15, attendu: 15, cas: 'colonne exacte inchangée' },
|
|
961
|
+
{ epaisseur: 50, attendu: 45, cas: 'au-delà de « ≥ 45 » => 45' },
|
|
962
|
+
{ epaisseur: 40, attendu: 45, cas: '40 cm => « ≥ 45 » plus proche que 20' },
|
|
963
|
+
{ epaisseur: '16', attendu: 15, cas: 'épaisseur fournie en chaîne' }
|
|
964
|
+
])('matériau 26 : $cas', ({ epaisseur, attendu }) => {
|
|
965
|
+
expect(epaisseurStructureTable('26', epaisseur)).toBe(attendu);
|
|
966
|
+
});
|
|
967
|
+
|
|
968
|
+
test.each([
|
|
969
|
+
{ epaisseur: 12, attendu: 20, cas: '« ≤ 20 » couvre toutes les épaisseurs inférieures' },
|
|
970
|
+
{ epaisseur: 17.5, attendu: 20, cas: 'épaisseur décimale sous « ≤ 20 »' },
|
|
971
|
+
{ epaisseur: 22, attendu: 20, cas: '22 cm => 20 (plus proche que 25)' },
|
|
972
|
+
{ epaisseur: 24, attendu: 25, cas: '24 cm => 25' },
|
|
973
|
+
{ epaisseur: 98, attendu: 30, cas: '« ≥ 30 » couvre toutes les épaisseurs supérieures' }
|
|
974
|
+
])('matériau 2 (bornes ouvertes) : $cas', ({ epaisseur, attendu }) => {
|
|
975
|
+
expect(epaisseurStructureTable('2', epaisseur)).toBe(attendu);
|
|
976
|
+
});
|
|
977
|
+
|
|
978
|
+
test.each([
|
|
979
|
+
{ materiau: '1', epaisseur: 30, cas: 'matériau sans épaisseur dans la table' },
|
|
980
|
+
{ materiau: '99', epaisseur: 30, cas: 'matériau absent de la table' },
|
|
981
|
+
{ materiau: '26', epaisseur: 0, cas: 'épaisseur nulle' },
|
|
982
|
+
{ materiau: '26', epaisseur: 'abc', cas: 'épaisseur non numérique' }
|
|
983
|
+
])('valeur inchangée : $cas', ({ materiau, epaisseur }) => {
|
|
984
|
+
expect(epaisseurStructureTable(materiau, epaisseur)).toBe(epaisseur);
|
|
985
|
+
});
|
|
986
|
+
|
|
987
|
+
test('calc_mur : le matcher umur0 reçoit la colonne de la table du matériau déclaré', () => {
|
|
988
|
+
const mur = {
|
|
989
|
+
donnee_entree: {
|
|
990
|
+
methode_saisie_u: 'non isolé',
|
|
991
|
+
methode_saisie_u0:
|
|
992
|
+
'déterminé selon le matériau et épaisseur à partir de la table de valeur forfaitaire',
|
|
993
|
+
enum_materiaux_structure_mur_id: '26',
|
|
994
|
+
epaisseur_structure: 16,
|
|
995
|
+
enum_type_doublage_id: '2'
|
|
996
|
+
}
|
|
997
|
+
};
|
|
998
|
+
|
|
999
|
+
calc_mur(mur, 'h1a', '1', '0');
|
|
1000
|
+
|
|
1001
|
+
expect(tv).toHaveBeenCalledWith('umur0', {
|
|
1002
|
+
enum_materiaux_structure_mur_id: '26',
|
|
1003
|
+
epaisseur_structure: 15
|
|
1004
|
+
});
|
|
1005
|
+
// L'épaisseur saisie n'est pas modifiée dans les données d'entrée
|
|
1006
|
+
expect(mur.donnee_entree.epaisseur_structure).toBe(16);
|
|
1007
|
+
});
|
|
1008
|
+
});
|
package/9_generateur_ch.js
CHANGED
|
@@ -5,6 +5,7 @@ import { conso_ch } from './9_conso_ch.js';
|
|
|
5
5
|
import { calc_generateur_combustion_ch } from './13.2_generateur_combustion_ch.js';
|
|
6
6
|
import { scopOrCop } from './12.4_pac.js';
|
|
7
7
|
import { updateGenerateurCombustion } from './13.2_generateur_combustion.js';
|
|
8
|
+
import { getChaudiereFioulDefautId } from './13.2_generateur_combustion_chaudiere.js';
|
|
8
9
|
|
|
9
10
|
const ENUM_MATERIAUX_STRUCTURE_MUR_ANCIEN_IDS = ['2', '3', '4', '6', '8', '9', '14', '21'];
|
|
10
11
|
const ENUM_CLASSES_INERTIE_LOURDES_IDS = ['1', '2'];
|
|
@@ -161,10 +162,15 @@ export function checkForGeneratorType(dpe, de, di, du) {
|
|
|
161
162
|
});
|
|
162
163
|
|
|
163
164
|
if (row) {
|
|
164
|
-
// On prend par défaut le premier type de générateur pour effectuer les calculs de rendement
|
|
165
165
|
const typeGenerateurCh = row.enum_type_generateur_ch_id?.split('|');
|
|
166
|
-
|
|
167
|
-
|
|
166
|
+
// Chaudière fioul standard datant de la construction du bâtiment (§17.2.1.1)
|
|
167
|
+
const chaudiereFioulDefautId = getChaudiereFioulDefautId(dpe, 'ch', typeGenerateurCh?.[0]);
|
|
168
|
+
|
|
169
|
+
if (chaudiereFioulDefautId && typeGenerateurCh?.includes('119')) {
|
|
170
|
+
// La chaudière fioul par défaut dépend de l'année de construction du bâtiment
|
|
171
|
+
de.enum_type_generateur_ch_id = chaudiereFioulDefautId;
|
|
172
|
+
} else if (typeGenerateurCh && typeGenerateurCh.length) {
|
|
173
|
+
// On prend par défaut le premier type de générateur pour effectuer les calculs de rendement
|
|
168
174
|
de.enum_type_generateur_ch_id = typeGenerateurCh[0];
|
|
169
175
|
}
|
|
170
176
|
}
|
package/9_generateur_ch.spec.js
CHANGED
|
@@ -57,6 +57,10 @@ vi.mock('./13.2_generateur_combustion.js', () => ({
|
|
|
57
57
|
updateGenerateurCombustion: vi.fn()
|
|
58
58
|
}));
|
|
59
59
|
|
|
60
|
+
vi.mock('./13.2_generateur_combustion_chaudiere.js', () => ({
|
|
61
|
+
getChaudiereFioulDefautId: vi.fn()
|
|
62
|
+
}));
|
|
63
|
+
|
|
60
64
|
const {
|
|
61
65
|
calc_Qrec_gen_j,
|
|
62
66
|
calc_Qrec_gen_ecs_j,
|
|
@@ -72,6 +76,7 @@ const { conso_ch } = await import('./9_conso_ch.js');
|
|
|
72
76
|
const { calc_generateur_combustion_ch } = await import('./13.2_generateur_combustion_ch.js');
|
|
73
77
|
const { scopOrCop } = await import('./12.4_pac.js');
|
|
74
78
|
const { updateGenerateurCombustion } = await import('./13.2_generateur_combustion.js');
|
|
79
|
+
const { getChaudiereFioulDefautId } = await import('./13.2_generateur_combustion_chaudiere.js');
|
|
75
80
|
|
|
76
81
|
beforeEach(() => {
|
|
77
82
|
vi.mocked(requestInput).mockReset();
|
|
@@ -335,6 +340,47 @@ describe('checkForGeneratorType - classification du générateur', () => {
|
|
|
335
340
|
checkForGeneratorType({}, de, {}, du);
|
|
336
341
|
expect(de.enum_type_generateur_ch_id).toBe('119');
|
|
337
342
|
});
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Chaudière fioul par défaut : chaudière standard datant de la construction du bâtiment.
|
|
346
|
+
* @see : Methode_de_calcul_3CL_DPE_2021-338.pdf - §17.2.1.1
|
|
347
|
+
*/
|
|
348
|
+
describe('cas 119 : chaudière fioul par défaut selon l’année de construction', () => {
|
|
349
|
+
beforeEach(() => {
|
|
350
|
+
vi.mocked(getChaudiereFioulDefautId).mockReset();
|
|
351
|
+
vi.mocked(requestInputID).mockReturnValue('119');
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
test('ligne combustion compatible 119 : chaudière de la période de construction retenue', () => {
|
|
355
|
+
vi.mocked(getChaudiereFioulDefautId).mockReturnValue('79');
|
|
356
|
+
vi.mocked(tv).mockReturnValue({ enum_type_generateur_ch_id: '75|119' });
|
|
357
|
+
const dpe = { logement: {} };
|
|
358
|
+
const de = { tv_generateur_combustion_id: 16 };
|
|
359
|
+
const du = {};
|
|
360
|
+
checkForGeneratorType(dpe, de, {}, du);
|
|
361
|
+
|
|
362
|
+
expect(getChaudiereFioulDefautId).toHaveBeenCalledWith(dpe, 'ch', '75');
|
|
363
|
+
// 79 au lieu du premier type de la ligne (75)
|
|
364
|
+
expect(de.enum_type_generateur_ch_id).toBe('79');
|
|
365
|
+
expect(du.isCombustionGenerator).toBe(true);
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
test('ligne combustion non compatible 119 (générateur décrit) : premier type conservé', () => {
|
|
369
|
+
vi.mocked(getChaudiereFioulDefautId).mockReturnValue('79');
|
|
370
|
+
vi.mocked(tv).mockReturnValue({ enum_type_generateur_ch_id: '97|139' });
|
|
371
|
+
const de = { tv_generateur_combustion_id: 13 };
|
|
372
|
+
checkForGeneratorType({}, de, {}, {});
|
|
373
|
+
expect(de.enum_type_generateur_ch_id).toBe('97');
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
test('année de construction inconnue : premier type de la ligne conservé', () => {
|
|
377
|
+
vi.mocked(getChaudiereFioulDefautId).mockReturnValue(undefined);
|
|
378
|
+
vi.mocked(tv).mockReturnValue({ enum_type_generateur_ch_id: '75|119' });
|
|
379
|
+
const de = { tv_generateur_combustion_id: 16 };
|
|
380
|
+
checkForGeneratorType({}, de, {}, {});
|
|
381
|
+
expect(de.enum_type_generateur_ch_id).toBe('75');
|
|
382
|
+
});
|
|
383
|
+
});
|
|
338
384
|
});
|
|
339
385
|
|
|
340
386
|
/**
|
package/README.md
CHANGED
|
@@ -370,14 +370,14 @@ Ces résultats sont **générés automatiquement** à la fin de `npm run test:co
|
|
|
370
370
|
|
|
371
371
|
<!-- CORPUS:START -->
|
|
372
372
|
|
|
373
|
-
> **Version `1.8.
|
|
373
|
+
> **Version `1.8.10`** · à publier · branche `main` · généré le 2026-10-02
|
|
374
374
|
> Seuil de tolérance **5%**
|
|
375
375
|
|
|
376
376
|
<table>
|
|
377
377
|
<tr>
|
|
378
378
|
<td align="center"><strong>9</strong><br/><sub>corpus</sub></td>
|
|
379
379
|
<td align="center"><strong>89 990</strong><br/><sub>DPE analysés</sub></td>
|
|
380
|
-
<td align="center"><strong>59
|
|
380
|
+
<td align="center"><strong>59 881</strong><br/><sub>DPE conformes</sub></td>
|
|
381
381
|
<td align="center"><strong>66,54 %</strong><br/><sub>réussite globale</sub></td>
|
|
382
382
|
</tr>
|
|
383
383
|
</table>
|
|
@@ -390,7 +390,7 @@ Ces résultats sont **générés automatiquement** à la fin de `npm run test:co
|
|
|
390
390
|
| 🟢 | **Maison individuelle (2025)**<br/><sub>`dpe_maison_individuelle_2025.csv`</sub> | **88,40 %** | `██████████████████░░` | 8 840 / 10 000 |
|
|
391
391
|
| 🟡 | **Immeuble · chauffage individuel**<br/><sub>`dpe_immeuble_chauffage_individuel.csv`</sub> | **74,14 %** | `███████████████░░░░░` | 7 413 / 9 999 |
|
|
392
392
|
| 🟡 | **Appartement · chauffage collectif (2025)**<br/><sub>`dpe_appartement_individuel_chauffage_collectif_2025.csv`</sub> | **70,61 %** | `██████████████░░░░░░` | 7 061 / 10 000 |
|
|
393
|
-
| 🟡 | **Immeuble · chauffage collectif**<br/><sub>`dpe_immeuble_chauffage_collectif.csv`</sub> | **62,
|
|
393
|
+
| 🟡 | **Immeuble · chauffage collectif**<br/><sub>`dpe_immeuble_chauffage_collectif.csv`</sub> | **62,52 %** | `█████████████░░░░░░░` | 6 251 / 9 999 |
|
|
394
394
|
| 🔴 | **Immeuble · chauffage mixte**<br/><sub>`dpe_immeuble_chauffage_mixte.csv`</sub> | **49,06 %** | `██████████░░░░░░░░░░` | 4 906 / 10 000 |
|
|
395
395
|
| 🔴 | **Individuel généré depuis l'immeuble (2026)**<br/><sub>`dpe_individuel_a_partir_dpe_immeuble_2026.csv`</sub> | **27,39 %** | `█████░░░░░░░░░░░░░░░` | 2 739 / 10 000 |
|
|
396
396
|
|
|
@@ -403,24 +403,24 @@ Ces résultats sont **générés automatiquement** à la fin de `npm run test:co
|
|
|
403
403
|
|
|
404
404
|
<table>
|
|
405
405
|
<tr>
|
|
406
|
-
<td align="center"><strong>5,
|
|
407
|
-
<td align="center"><strong>4,
|
|
406
|
+
<td align="center"><strong>5,70 ms</strong><br/><sub>moyenne</sub></td>
|
|
407
|
+
<td align="center"><strong>4,90 ms</strong><br/><sub>médiane</sub></td>
|
|
408
408
|
<td align="center"><strong>0,12 ms</strong><br/><sub>min</sub></td>
|
|
409
|
-
<td align="center"><strong>
|
|
409
|
+
<td align="center"><strong>798,8 ms</strong><br/><sub>max</sub></td>
|
|
410
410
|
</tr>
|
|
411
411
|
</table>
|
|
412
412
|
|
|
413
413
|
| Corpus | Moyenne | Médiane | Min | Max | p95 | p99 |
|
|
414
414
|
| :--------------------------------------------- | ------: | ------: | ------: | -------: | ------: | ------: |
|
|
415
|
-
| **Généraliste** | 4,
|
|
416
|
-
| **Appartement · chauffage individuel (2025)** |
|
|
417
|
-
| **Logement individuel (2025)** |
|
|
418
|
-
| **Maison individuelle (2025)** |
|
|
419
|
-
| **Immeuble · chauffage individuel** |
|
|
420
|
-
| **Appartement · chauffage collectif (2025)** | 4,
|
|
421
|
-
| **Immeuble · chauffage collectif** | 5,
|
|
422
|
-
| **Immeuble · chauffage mixte** | 5,
|
|
423
|
-
| **Individuel généré depuis l'immeuble (2026)** |
|
|
415
|
+
| **Généraliste** | 4,45 ms | 3,97 ms | 0,21 ms | 28,3 ms | 8,17 ms | 12,3 ms |
|
|
416
|
+
| **Appartement · chauffage individuel (2025)** | 3,56 ms | 3,23 ms | 1,44 ms | 32,5 ms | 6,21 ms | 8,35 ms |
|
|
417
|
+
| **Logement individuel (2025)** | 5,38 ms | 4,83 ms | 1,58 ms | 40,8 ms | 9,99 ms | 13,4 ms |
|
|
418
|
+
| **Maison individuelle (2025)** | 9,51 ms | 7,86 ms | 1,74 ms | 102,7 ms | 21,7 ms | 32,8 ms |
|
|
419
|
+
| **Immeuble · chauffage individuel** | 7,00 ms | 6,01 ms | 0,12 ms | 104,2 ms | 14,2 ms | 21,8 ms |
|
|
420
|
+
| **Appartement · chauffage collectif (2025)** | 4,19 ms | 3,78 ms | 1,54 ms | 35,7 ms | 6,90 ms | 8,89 ms |
|
|
421
|
+
| **Immeuble · chauffage collectif** | 5,77 ms | 4,97 ms | 0,22 ms | 99,3 ms | 10,8 ms | 17,2 ms |
|
|
422
|
+
| **Immeuble · chauffage mixte** | 5,60 ms | 4,49 ms | 0,19 ms | 798,8 ms | 11,9 ms | 19,9 ms |
|
|
423
|
+
| **Individuel généré depuis l'immeuble (2026)** | 5,85 ms | 4,98 ms | 1,60 ms | 49,9 ms | 11,1 ms | 16,4 ms |
|
|
424
424
|
|
|
425
425
|
<sub>La moyenne est tirée vers le haut par les DPE collectifs, dont le coût atteint plusieurs
|
|
426
426
|
dizaines de fois la médiane : c’est la médiane qui décrit le cas courant, et p95/p99 le cas
|
package/engine.js
CHANGED
|
@@ -33,7 +33,7 @@ import getFicheTechnique from './ficheTechnique.js';
|
|
|
33
33
|
import { ProductionENR } from './16.2_production_enr.js';
|
|
34
34
|
import DpeSanitizerService from './dpe-sanitizer.service.js';
|
|
35
35
|
|
|
36
|
-
const LIB_VERSION = '1.8.
|
|
36
|
+
const LIB_VERSION = '1.8.12';
|
|
37
37
|
|
|
38
38
|
const dpeSanitizerService = new DpeSanitizerService();
|
|
39
39
|
|