@open3cl/engine 1.8.10 → 1.8.11
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/3.2.1_mur.js +71 -2
- package/3.2.1_mur.spec.js +83 -1
- package/engine.js +1 -1
- package/package.json +1 -1
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/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.11';
|
|
37
37
|
|
|
38
38
|
const dpeSanitizerService = new DpeSanitizerService();
|
|
39
39
|
|