@open3cl/engine 1.6.2 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/10_besoin_fr.spec.js +1 -0
  2. package/10_clim.spec.js +1 -0
  3. package/11_besoin_ecs.spec.js +1 -0
  4. package/11_ecs.spec.js +1 -0
  5. package/12.4_pac.spec.js +1 -0
  6. package/13.2_generateur_combustion.spec.js +3 -3
  7. package/13.2_generateur_combustion_ch.spec.js +3 -3
  8. package/14_generateur_ecs.spec.js +1 -0
  9. package/15_conso_aux.js +121 -1
  10. package/15_conso_aux.spec.js +329 -4
  11. package/2021_04_13_confort_ete.spec.js +1 -0
  12. package/3.1_b.spec.js +1 -0
  13. package/3.2.1_mur.spec.js +1 -0
  14. package/3.2.2_plancher_bas.spec.js +1 -0
  15. package/3.2.3_plancher_haut.spec.js +1 -0
  16. package/3.3.1.4_porte.spec.js +1 -0
  17. package/3.3_baie_vitree.spec.js +1 -0
  18. package/3.4_pont_thermique.spec.js +1 -0
  19. package/4_ventilation.spec.js +1 -0
  20. package/5_conso_ventilation.spec.js +1 -0
  21. package/6.2_surface_sud_equivalente.js +2 -1
  22. package/6.2_surface_sud_equivalente.spec.js +1 -0
  23. package/9_besoin_ch.spec.js +1 -0
  24. package/9_chauffage.spec.js +3 -3
  25. package/9_conso_ch.spec.js +1 -0
  26. package/9_emetteur_ch.spec.js +1 -0
  27. package/9_generateur_ch.spec.js +1 -0
  28. package/README.md +412 -291
  29. package/conso.js +20 -6
  30. package/conso.spec.js +21 -0
  31. package/engine.js +19 -1
  32. package/engine.spec.js +96 -0
  33. package/package.json +15 -14
  34. package/features/engine/domain/apport_et_besoin/apport-et-besoin.service.spec.js +0 -222
  35. package/features/engine/domain/apport_et_besoin/ch/perte-ch-recup.service.spec.js +0 -345
  36. package/features/engine/domain/apport_et_besoin/ecs/besoin-ecs.service.spec.js +0 -87
  37. package/features/engine/domain/apport_et_besoin/ecs/perte-ecs-recup.service.spec.js +0 -260
  38. package/features/engine/domain/apport_et_besoin/froid/besoin-froid.service.spec.js +0 -272
  39. package/features/engine/domain/apport_et_besoin/surface-sud-equivalente.service.spec.js +0 -231
  40. package/features/engine/domain/ch/generateur-ch.service.spec.js +0 -849
  41. package/features/engine/domain/conso/froid/conso-froid.service.spec.js +0 -233
  42. package/features/engine/domain/ecs/installation-ecs.service.spec.js +0 -337
  43. package/features/engine/domain/enveloppe/baie_vitree/deperdition-baie-vitree.service.spec.js +0 -607
  44. package/features/engine/domain/enveloppe/deperdition-enveloppe.service.spec.js +0 -550
  45. package/features/engine/domain/enveloppe/espace_tampon/espace-tampon.service.spec.js +0 -82
  46. package/features/engine/domain/enveloppe/mur/deperdition-mur.service.spec.js +0 -542
  47. package/features/engine/domain/enveloppe/plancher_bas/deperdition-plancher-bas.service.spec.js +0 -430
  48. package/features/engine/domain/enveloppe/plancher_haut/deperdition-plancher-haut.service.spec.js +0 -411
  49. package/features/engine/domain/enveloppe/pont_thermique/deperdition-pont-thermique.service.spec.js +0 -653
  50. package/features/engine/domain/enveloppe/porte/deperdition-porte.service.spec.js +0 -117
  51. package/features/engine/domain/enveloppe/ventilation/deperdition-ventilation.service.spec.js +0 -508
package/conso.js CHANGED
@@ -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 = 0;
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
@@ -38,6 +38,7 @@ vi.mock('./tv.js', () => ({
38
38
  }));
39
39
 
40
40
  vi.mock('./utils.js', () => ({
41
+ set_bug_for_bug_compat: vi.fn(),
41
42
  tv: vi.fn((table, matcher) => {
42
43
  // Réseau de chaleur "R1" connu, "R2" inconnu
43
44
  if (matcher?.identifiant_reseau === 'R1') return { contenu_co2_acv: 0.15 };
@@ -188,6 +189,7 @@ function genEcs(energieId, di, deExtra = {}) {
188
189
  function installEcs(deExtra, gens) {
189
190
  return {
190
191
  donnee_entree: { ...deExtra },
192
+ donnee_intermediaire: {},
191
193
  generateur_ecs_collection: { generateur_ecs: gens }
192
194
  };
193
195
  }
@@ -434,6 +436,25 @@ describe('calc_conso - agrégation des consommations', () => {
434
436
  expect(res.ep_conso.ep_conso_ecs).toBeCloseTo(190, 9);
435
437
  });
436
438
 
439
+ test.each([
440
+ ['absente', undefined],
441
+ ['nulle', null],
442
+ ['non tabulaire', { installation_ecs: [] }]
443
+ ])('collection ECS %s : traitée comme une liste vide', (_libelle, ecs) => {
444
+ const chFixture = () => [
445
+ installCh({ cle_repartition_ch: 1 }, [
446
+ genCh('1', { conso_ch: 1000, conso_ch_depensier: 1200 })
447
+ ])
448
+ ];
449
+
450
+ const res = calc_conso(100, 1, 1, [], chFixture(), ecs, [], 1, 1, DATE_DPE, coef_ep);
451
+
452
+ // Identique à un appel avec une collection ECS vide : aucune conso ni auxiliaire d'ECS
453
+ expect(res).toEqual(calc_conso(100, 1, 1, [], chFixture(), [], [], 1, 1, DATE_DPE, coef_ep));
454
+ expect(res.ef_conso.conso_ecs).toBe(0);
455
+ expect(res.ef_conso.conso_auxiliaire_distribution_ecs).toBe(0);
456
+ });
457
+
437
458
  test('ventilation et froid : auxiliaires et froid agrégés par énergie', () => {
438
459
  const vt = [
439
460
  {
package/engine.js CHANGED
@@ -3,6 +3,7 @@ import calc_deperdition from './3_deperdition.js';
3
3
  import calc_apport_et_besoin from './apport_et_besoin.js';
4
4
  import calc_clim from './10_clim.js';
5
5
  import calc_ecs from './11_ecs.js';
6
+ import { conso_aux_distribution_ecs } from './15_conso_aux.js';
6
7
  import calc_besoin_ch from './9_besoin_ch.js';
7
8
  import calc_chauffage, { tauxChargeForGenerator } from './9_chauffage.js';
8
9
  import calc_confort_ete from './2021_04_13_confort_ete.js';
@@ -22,6 +23,7 @@ import {
22
23
  collectionCanBeEmpty,
23
24
  containsAnySubstring,
24
25
  isEffetJoule,
26
+ set_bug_for_bug_compat,
25
27
  use_enum_as_string,
26
28
  useEnumAsString,
27
29
  xmlParser
@@ -31,7 +33,7 @@ import getFicheTechnique from './ficheTechnique.js';
31
33
  import { ProductionENR } from './16.2_production_enr.js';
32
34
  import DpeSanitizerService from './dpe-sanitizer.service.js';
33
35
 
34
- const LIB_VERSION = '1.6.2';
36
+ const LIB_VERSION = '1.7.1';
35
37
 
36
38
  const dpeSanitizerService = new DpeSanitizerService();
37
39
 
@@ -70,6 +72,7 @@ export function calcul_3cl_xml(dpeXmlContent, options) {
70
72
  * @return {FullDpe}
71
73
  */
72
74
  export function calcul_3cl(inputDpe, options) {
75
+ set_bug_for_bug_compat();
73
76
  if (!options) options = { sanitize: true };
74
77
  let dpe;
75
78
  if (options.sanitize) {
@@ -90,6 +93,7 @@ export function calcul_3cl(inputDpe, options) {
90
93
 
91
94
  const cg = logement.caracteristique_generale;
92
95
  const map_id = cg.enum_methode_application_dpe_log_id;
96
+ const dpeGenereImmeuble = ['10', '11', '12', '13', '33', '34', '38', '39', '40'].includes(map_id);
93
97
  const th = calc_th(map_id);
94
98
 
95
99
  if (logement.enveloppe === undefined) {
@@ -435,6 +439,20 @@ export function calcul_3cl(inputDpe, options) {
435
439
  dpe.logement.caracteristique_generale.nombre_appartement,
436
440
  isImmeubleSystemEcsIndividuels
437
441
  );
442
+
443
+ if (!dpeGenereImmeuble) {
444
+ conso_aux_distribution_ecs(
445
+ ecs,
446
+ ecs.donnee_entree,
447
+ ecs.donnee_intermediaire,
448
+ Sh,
449
+ cg.surface_habitable_immeuble,
450
+ ca_id,
451
+ zc_id,
452
+ apport_et_besoin.nadeq,
453
+ dpe.logement.caracteristique_generale.nombre_niveau_immeuble
454
+ );
455
+ }
438
456
  });
439
457
 
440
458
  /**
package/engine.spec.js CHANGED
@@ -20,6 +20,7 @@ let bugForBugCompat = false;
20
20
  let useEnumAsStringFlag = false;
21
21
 
22
22
  vi.mock('./utils.js', () => ({
23
+ set_bug_for_bug_compat: vi.fn(),
23
24
  add_references: vi.fn(),
24
25
  get bug_for_bug_compat() {
25
26
  return bugForBugCompat;
@@ -65,6 +66,7 @@ vi.mock('./10_clim.js', () => ({ default: vi.fn() }));
65
66
  vi.mock('./11_ecs.js', () => ({ default: vi.fn() }));
66
67
  vi.mock('./9_besoin_ch.js', () => ({ default: vi.fn() }));
67
68
  vi.mock('./9_chauffage.js', () => ({ default: vi.fn(), tauxChargeForGenerator: vi.fn() }));
69
+ vi.mock('./15_conso_aux.js', () => ({ conso_aux_distribution_ecs: vi.fn() }));
68
70
  vi.mock('./2021_04_13_confort_ete.js', () => ({ default: vi.fn() }));
69
71
  vi.mock('./2021_04_13_qualite_isolation.js', () => ({ default: vi.fn() }));
70
72
  vi.mock('./ficheTechnique.js', () => ({ default: vi.fn() }));
@@ -102,6 +104,7 @@ const calc_clim = (await import('./10_clim.js')).default;
102
104
  const calc_ecs = (await import('./11_ecs.js')).default;
103
105
  const calc_besoin_ch = (await import('./9_besoin_ch.js')).default;
104
106
  const { default: calc_chauffage, tauxChargeForGenerator } = await import('./9_chauffage.js');
107
+ const { conso_aux_distribution_ecs } = await import('./15_conso_aux.js');
105
108
  const calc_confort_ete = (await import('./2021_04_13_confort_ete.js')).default;
106
109
  const calc_qualite_isolation = (await import('./2021_04_13_qualite_isolation.js')).default;
107
110
  const getFicheTechnique = (await import('./ficheTechnique.js')).default;
@@ -172,6 +175,7 @@ function makeDpe() {
172
175
  surface_habitable_logement: 80,
173
176
  surface_habitable_immeuble: 200,
174
177
  nombre_appartement: 4,
178
+ nombre_niveau_immeuble: 3,
175
179
  hsp: 2.5,
176
180
  annee_construction: 1990
177
181
  },
@@ -192,6 +196,7 @@ function makeDpe() {
192
196
  installation_ecs: [
193
197
  {
194
198
  donnee_entree: { enum_type_installation_id: '1' },
199
+ donnee_intermediaire: {},
195
200
  generateur_ecs_collection: { generateur_ecs: [] }
196
201
  }
197
202
  ]
@@ -455,6 +460,22 @@ describe('calcul_3cl - run intégral (maison)', () => {
455
460
  expect(calc_ecs.mock.calls[0][2]).toBe(100);
456
461
  expect(calc_ecs.mock.calls[0][11]).toBe(false);
457
462
 
463
+ // Auxiliaires de distribution ECS calculés pour l'installation (maison => map hors
464
+ // liste des DPE générés à partir des données d'immeuble).
465
+ const ecs = dpe.logement.installation_ecs_collection.installation_ecs[0];
466
+ expect(conso_aux_distribution_ecs).toHaveBeenCalledTimes(1);
467
+ expect(conso_aux_distribution_ecs).toHaveBeenCalledWith(
468
+ ecs,
469
+ ecs.donnee_entree,
470
+ ecs.donnee_intermediaire,
471
+ 80, // Sh (maison)
472
+ 200, // surface_habitable_immeuble
473
+ 'ca1',
474
+ 'zc1',
475
+ 2, // nadeq
476
+ 3 // nombre_niveau_immeuble
477
+ );
478
+
458
479
  // Climatisation présente : calc_clim appelé.
459
480
  expect(calc_clim).toHaveBeenCalledTimes(1);
460
481
  });
@@ -484,6 +505,7 @@ describe('calcul_3cl - run intégral (maison)', () => {
484
505
  expect(calc_apport_et_besoin.mock.calls[0][5]).toBe(1);
485
506
  // Pas d'ECS ni de clim à traiter.
486
507
  expect(calc_ecs).not.toHaveBeenCalled();
508
+ expect(conso_aux_distribution_ecs).not.toHaveBeenCalled();
487
509
  expect(calc_clim).not.toHaveBeenCalled();
488
510
  });
489
511
  });
@@ -538,6 +560,9 @@ describe('calcul_3cl - surfaces immeuble / appartement et prorata', () => {
538
560
  // isImmeubleSystemEcsIndividuels = true, besoin non divisé.
539
561
  expect(calc_ecs.mock.calls[0][11]).toBe(true);
540
562
  expect(calc_ecs.mock.calls[0][2]).toBe(100);
563
+ // Auxiliaires ECS calculés par installation, avec Sh = surface immeuble.
564
+ expect(conso_aux_distribution_ecs).toHaveBeenCalledTimes(2);
565
+ expect(conso_aux_distribution_ecs.mock.calls[0][3]).toBe(200);
541
566
  });
542
567
 
543
568
  test('immeuble : systèmes ECS non tous individuels => besoin divisé par deux', () => {
@@ -593,6 +618,77 @@ describe('calcul_3cl - surfaces immeuble / appartement et prorata', () => {
593
618
  expect(calc_conso.mock.calls[0][0]).toBe(80);
594
619
  expect(calc_conso.mock.calls[0][7]).toBeCloseTo(0.4, 9); // prorataECS
595
620
  expect(calc_conso.mock.calls[0][8]).toBeCloseTo(0.4, 9); // prorataChauffage
621
+ // Auxiliaires ECS : Sh = surface logement, ramenée à l'immeuble dans le calcul.
622
+ expect(conso_aux_distribution_ecs.mock.calls[0][3]).toBe(80);
623
+ expect(conso_aux_distribution_ecs.mock.calls[0][4]).toBe(200);
624
+ });
625
+ });
626
+
627
+ describe("calcul_3cl - auxiliaires de distribution d'ECS", () => {
628
+ // Méthodes d'application « appartement généré à partir des données DPE immeuble » :
629
+ // les auxiliaires de distribution d'ECS ne sont pas calculés pour ces DPE.
630
+ const MAP_IDS_GENERES_IMMEUBLE = ['10', '11', '12', '13', '33', '34', '38', '39', '40'];
631
+
632
+ test.each(MAP_IDS_GENERES_IMMEUBLE)(
633
+ "DPE appartement généré à partir des données d'immeuble (map %s) : auxiliaires non calculés",
634
+ (mapId) => {
635
+ enums.methode_application_dpe_log = {
636
+ [mapId]: 'dpe appartement généré à partir des données dpe immeuble chauffage collectif'
637
+ };
638
+ const dpe = makeDpe();
639
+ dpe.logement.caracteristique_generale.enum_methode_application_dpe_log_id = mapId;
640
+
641
+ calcul_3cl(dpe, { sanitize: false });
642
+
643
+ // L'installation est bien traitée par ailleurs, seul le calcul des auxiliaires est ignoré.
644
+ expect(calc_ecs).toHaveBeenCalledTimes(1);
645
+ expect(conso_aux_distribution_ecs).not.toHaveBeenCalled();
646
+ }
647
+ );
648
+
649
+ test('appartement non généré depuis un immeuble (map 15) : auxiliaires calculés', () => {
650
+ enums.methode_application_dpe_log = { 15: 'dpe appartement collectif' };
651
+ const dpe = makeDpe();
652
+ dpe.logement.caracteristique_generale.enum_methode_application_dpe_log_id = '15';
653
+
654
+ calcul_3cl(dpe, { sanitize: false });
655
+
656
+ expect(conso_aux_distribution_ecs).toHaveBeenCalledTimes(1);
657
+ });
658
+
659
+ test('une installation ECS par appel : chaque installation est traitée', () => {
660
+ const dpe = makeDpe();
661
+ const installations = [
662
+ {
663
+ donnee_entree: { enum_type_installation_id: '1' },
664
+ donnee_intermediaire: { tag: 'ecs1' },
665
+ generateur_ecs_collection: { generateur_ecs: [] }
666
+ },
667
+ {
668
+ donnee_entree: { enum_type_installation_id: '2' },
669
+ donnee_intermediaire: { tag: 'ecs2' },
670
+ generateur_ecs_collection: { generateur_ecs: [] }
671
+ }
672
+ ];
673
+ dpe.logement.installation_ecs_collection.installation_ecs = installations;
674
+
675
+ calcul_3cl(dpe, { sanitize: false });
676
+
677
+ expect(conso_aux_distribution_ecs).toHaveBeenCalledTimes(2);
678
+ installations.forEach((ecs, i) => {
679
+ expect(conso_aux_distribution_ecs.mock.calls[i][0]).toBe(ecs);
680
+ expect(conso_aux_distribution_ecs.mock.calls[i][1]).toBe(ecs.donnee_entree);
681
+ expect(conso_aux_distribution_ecs.mock.calls[i][2]).toBe(ecs.donnee_intermediaire);
682
+ });
683
+ });
684
+
685
+ test("nombre de niveaux de l'immeuble absent : transmis tel quel", () => {
686
+ const dpe = makeDpe();
687
+ dpe.logement.caracteristique_generale.nombre_niveau_immeuble = undefined;
688
+
689
+ calcul_3cl(dpe, { sanitize: false });
690
+
691
+ expect(conso_aux_distribution_ecs.mock.calls[0][8]).toBeUndefined();
596
692
  });
597
693
  });
598
694
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open3cl/engine",
3
- "version": "1.6.2",
3
+ "version": "1.7.1",
4
4
  "description": "Open Source 3CL-DPE engine",
5
5
  "main": "index.js",
6
6
  "directories": {
@@ -13,13 +13,11 @@
13
13
  },
14
14
  "scripts": {
15
15
  "http-server": "http-server",
16
- "test": "vitest run",
16
+ "test": "vitest run src",
17
17
  "test:unit": "vitest run src",
18
18
  "test:unit:ci": "vitest run src --coverage",
19
- "test:int": "vitest run test",
20
- "test:int:ci": "vitest run test --coverage",
21
19
  "test:corpus": "node test/corpus/run_all_corpus_checks.js",
22
- "test:corpus:all": "node test/corpus/run_all_corpus_checks.js",
20
+ "test:corpus:all": "node test/corpus/run_all_corpus_checks.js && npm run reports:readme",
23
21
  "test:corpus:all+database": "npm run test:corpus:all && node test/corpus/corpus_database.js",
24
22
  "qa:lint": "eslint .",
25
23
  "qa:lint:fix": "npm run qa:lint -- --fix",
@@ -30,7 +28,8 @@
30
28
  "prepare": "husky install",
31
29
  "assets:sync": "node scripts/synchronize_assets.js",
32
30
  "version:update": "node scripts/update_version.js",
33
- "reports:preview": "npm run http-server dist/reports/corpus -o"
31
+ "reports:preview": "npm run http-server dist/reports/corpus -o",
32
+ "reports:readme": "node scripts/generate_corpus_readme.js"
34
33
  },
35
34
  "repository": {
36
35
  "type": "git",
@@ -42,11 +41,12 @@
42
41
  ],
43
42
  "dependencies": {
44
43
  "dioma": "^0.4.6",
45
- "fast-xml-parser": "^4.5.0",
44
+ "fast-xml-parser": "^5.11.1",
46
45
  "http-server": "^14.1.1",
47
- "lodash-es": "4.17.21",
48
- "mathjs": "^15.1.0",
49
- "winston": "3.13.0"
46
+ "lodash-es": "^4.18.1",
47
+ "mathjs": "^15.2.0",
48
+ "winston": "^3.19.0",
49
+ "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@aws-sdk/client-s3": "^3.1013.0",
@@ -59,11 +59,10 @@
59
59
  "@semantic-release/git": "^10.0.1",
60
60
  "@semantic-release/github": "^12.0.2",
61
61
  "@types/node": "^20.12.4",
62
- "@vitest/coverage-v8": "^3.0.6",
62
+ "@vitest/coverage-v8": "^3.2.7",
63
63
  "ansi-colors": "^4.1.3",
64
64
  "cli-progress": "^3.12.0",
65
65
  "deep-object-diff": "^1.1.9",
66
- "duckdb": "^1.3.2",
67
66
  "eslint": "^8.57.0",
68
67
  "eslint-config-prettier": "^9.1.0",
69
68
  "eslint-config-standard": "^17.1.0",
@@ -78,11 +77,13 @@
78
77
  "prettier": "^3.2.5",
79
78
  "pretty-quick": "^4.0.0",
80
79
  "semantic-release": "^25.0.2",
81
- "vitest": "3.0.6",
82
- "xlsx": "0.18.5"
80
+ "vitest": "3.2.7"
83
81
  },
84
82
  "author": "Open3Cl",
85
83
  "license": "GPL-3.0",
84
+ "engines": {
85
+ "node": ">=24.14.1"
86
+ },
86
87
  "bugs": {
87
88
  "url": "https://github.com/Open3CL/engine/issues"
88
89
  },
@@ -1,222 +0,0 @@
1
- import { beforeEach, describe, expect, test, vi } from 'vitest';
2
- import { SurfaceSudEquivalenteService } from './surface-sud-equivalente.service.js';
3
- import { BaieVitreeTvStore } from '../../../dpe/infrastructure/enveloppe/baieVitreeTv.store.js';
4
- import { ApportEtBesoinService } from './apport-et-besoin.service.js';
5
- import { BesoinEcsService } from './ecs/besoin-ecs.service.js';
6
- import { BesoinFroidService } from './froid/besoin-froid.service.js';
7
- import { ApportGratuitService } from './apport_gratuit/apport-gratuit.service.js';
8
- import { PerteEcsRecupService } from './ecs/perte-ecs-recup.service.js';
9
- import { InstallationEcsService } from '../ecs/installation-ecs.service.js';
10
- import { PerteChRecupService } from './ch/perte-ch-recup.service.js';
11
- import { BesoinChService } from './ch/besoin-ch.service.js';
12
- import corpus from '../../../../../test/corpus-sano.json';
13
- import { getAdemeFileJson } from '../../../../../test/test-helpers.js';
14
- import { PRECISION_PERCENT } from '../../../../../test/constant.js';
15
- import { DpeNormalizerService } from '../../../normalizer/domain/dpe-normalizer.service.js';
16
- import { ContexteBuilder } from '../contexte.builder.js';
17
- import { InstallationChService } from '../ch/installation-ch.service.js';
18
- import { describeIntegration } from '../../../../../test/helpers/integration-test.js';
19
-
20
- /** @type {SurfaceSudEquivalenteService} **/
21
- let surfaceSudEquivalenteService;
22
-
23
- /** @type {BesoinEcsService} **/
24
- let besoinEcsService;
25
-
26
- /** @type {BesoinFroidService} **/
27
- let besoinFroidService;
28
-
29
- /** @type {InstallationEcsService} **/
30
- let installationEcsService;
31
-
32
- /** @type {InstallationChService} **/
33
- let installationChService;
34
-
35
- /** @type {PerteEcsRecupService} **/
36
- let perteEcsRecupService;
37
-
38
- /** @type {ApportGratuitService} **/
39
- let apportGratuitService;
40
-
41
- /** @type {PerteChRecupService} **/
42
- let perteChRecupService;
43
-
44
- /** @type {BesoinChService} **/
45
- let besoinChService;
46
-
47
- /** @type {DpeNormalizerService} **/
48
- let normalizerService;
49
-
50
- /** @type {ContexteBuilder} **/
51
- let contexteBuilder;
52
-
53
- /** @type {ApportEtBesoinService} **/
54
- let service;
55
-
56
- /** @type {BaieVitreeTvStore} **/
57
- let tvStore;
58
-
59
- describe('Calcul des apports et besoin du logement', () => {
60
- beforeEach(() => {
61
- tvStore = new BaieVitreeTvStore();
62
- surfaceSudEquivalenteService = new SurfaceSudEquivalenteService(tvStore);
63
- besoinEcsService = new BesoinEcsService();
64
- besoinChService = new BesoinChService();
65
- besoinFroidService = new BesoinFroidService();
66
- installationEcsService = new InstallationEcsService();
67
- installationChService = new InstallationChService();
68
- perteEcsRecupService = new PerteEcsRecupService();
69
- apportGratuitService = new ApportGratuitService();
70
- perteChRecupService = new PerteChRecupService();
71
- service = new ApportEtBesoinService(
72
- besoinEcsService,
73
- besoinChService,
74
- installationEcsService,
75
- installationChService,
76
- perteEcsRecupService,
77
- besoinFroidService,
78
- surfaceSudEquivalenteService,
79
- perteChRecupService,
80
- apportGratuitService
81
- );
82
- normalizerService = new DpeNormalizerService();
83
- contexteBuilder = new ContexteBuilder();
84
- });
85
-
86
- test('Determination des apports et besoin du logement', () => {
87
- vi.spyOn(surfaceSudEquivalenteService, 'execute').mockReturnValue(18.5);
88
- vi.spyOn(besoinEcsService, 'execute').mockReturnValue({
89
- besoin_ecs: 1526,
90
- besoin_ecs_depensier: 2685.3
91
- });
92
- vi.spyOn(besoinChService, 'execute').mockReturnValue({
93
- besoin_ch_hp: 2563,
94
- besoin_ch_depensier_hp: 3258.6
95
- });
96
- vi.spyOn(besoinFroidService, 'execute').mockReturnValue({
97
- besoin_fr: 896,
98
- besoin_fr_depensier: 1025.3
99
- });
100
- vi.spyOn(apportGratuitService, 'apportSolaire').mockReturnValue({
101
- apport_solaire_ch: 5236.9,
102
- apport_solaire_fr: 145.2
103
- });
104
- vi.spyOn(apportGratuitService, 'apportInterne').mockReturnValue({
105
- apport_interne_ch: 1236.9,
106
- apport_interne_fr: 3345.2
107
- });
108
- vi.spyOn(installationEcsService, 'execute').mockReturnThis();
109
- vi.spyOn(installationChService, 'execute').mockReturnThis();
110
- vi.spyOn(perteEcsRecupService, 'execute').mockReturnValue({
111
- pertes_distribution_ecs_recup: 354.2,
112
- pertes_distribution_ecs_recup_depensier: 532.6,
113
- pertes_stockage_ecs_recup: 25.9,
114
- pertes_stockage_ecs_recup_depensier: 12.9
115
- });
116
- vi.spyOn(perteChRecupService, 'execute').mockReturnValue({
117
- pertes_generateur_ch_recup: 102.2,
118
- pertes_generateur_ch_recup_depensier: 153.4
119
- });
120
-
121
- /** @type {Contexte} */
122
- const ctx = { zoneClimatique: { id: 1 }, nadeq: 2.5 };
123
- /** @type { Logement } **/
124
- const logement = { enveloppe: {} };
125
- expect(service.execute(ctx, logement)).toStrictEqual({
126
- surface_sud_equivalente: 18.5,
127
- besoin_ecs: 1526,
128
- besoin_ecs_depensier: 2685.3,
129
- besoin_ch: 2080.7000000000003,
130
- besoin_ch_depensier: 2559.7,
131
- besoin_fr: 896,
132
- besoin_fr_depensier: 1025.3,
133
- apport_solaire_ch: 5236.9,
134
- apport_solaire_fr: 145.2,
135
- apport_interne_ch: 1236.9,
136
- apport_interne_fr: 3345.2,
137
- nadeq: 2.5,
138
- v40_ecs_journalier: 140,
139
- v40_ecs_journalier_depensier: 197.5,
140
- pertes_distribution_ecs_recup: 354.2,
141
- pertes_distribution_ecs_recup_depensier: 532.6,
142
- pertes_generateur_ch_recup: 102.2,
143
- pertes_generateur_ch_recup_depensier: 153.4,
144
- pertes_stockage_ecs_recup: 25.9,
145
- pertes_stockage_ecs_recup_depensier: 12.9
146
- });
147
- expect(surfaceSudEquivalenteService.execute).toHaveBeenCalledWith(ctx, logement.enveloppe);
148
- expect(besoinEcsService.execute).toHaveBeenCalledWith(ctx);
149
- expect(besoinFroidService.execute).toHaveBeenCalledWith(ctx, logement);
150
- expect(apportGratuitService.apportSolaire).toHaveBeenCalledWith(ctx, logement);
151
- expect(apportGratuitService.apportInterne).toHaveBeenCalledWith(ctx, logement);
152
- expect(perteEcsRecupService.execute).toHaveBeenCalledWith(ctx, logement);
153
- expect(perteChRecupService.execute).toHaveBeenCalledWith(ctx, logement);
154
- expect(installationEcsService.execute).toHaveBeenCalledWith(ctx, logement, {
155
- besoin_ecs: 1526,
156
- besoin_ecs_depensier: 2685.3
157
- });
158
- expect(installationChService.execute).toHaveBeenCalledWith(ctx, logement);
159
- });
160
-
161
- describeIntegration("Test d'intégration pour les besoins en chauffage", () => {
162
- test.each(corpus)(
163
- 'Vérification de la DI besoin_ch des besoins en chauffage pour dpe %s',
164
- (ademeId) => {
165
- /**
166
- * @type {Dpe}
167
- */
168
- let dpeRequest = getAdemeFileJson(ademeId);
169
- dpeRequest = normalizerService.normalize(dpeRequest);
170
-
171
- dpeRequest.logement.donnees_de_calcul = {
172
- apportsInterneDepensier: [],
173
- apportsInterneCh: [],
174
- apportsSolaire: [],
175
- besoinChauffageHP: [],
176
- besoinChauffageDepensierHP: []
177
- };
178
-
179
- /** @type {Contexte} */
180
- const ctx = contexteBuilder.fromDpe(dpeRequest);
181
- const apportEtBesoin = service.execute(ctx, dpeRequest.logement);
182
-
183
- expect(
184
- Math.abs(
185
- apportEtBesoin.besoin_ch - dpeRequest.logement.sortie.apport_et_besoin.besoin_ch
186
- ) / (dpeRequest.logement.sortie.apport_et_besoin.besoin_ch || 1)
187
- ).toBeLessThan(PRECISION_PERCENT);
188
- }
189
- );
190
-
191
- test.each(corpus)(
192
- 'Vérification de la DI besoin_ch_depensier des besoins en chauffage pour dpe %s',
193
- (ademeId) => {
194
- /**
195
- * @type {Dpe}
196
- */
197
- let dpeRequest = getAdemeFileJson(ademeId);
198
- dpeRequest = normalizerService.normalize(dpeRequest);
199
-
200
- dpeRequest.logement.donnees_de_calcul = {
201
- apportsInterneDepensier: [],
202
- apportsInterneCh: [],
203
- apportsSolaire: [],
204
- besoinChauffageHP: [],
205
- besoinChauffageDepensierHP: []
206
- };
207
-
208
- /** @type {Contexte} */
209
- const ctx = contexteBuilder.fromDpe(dpeRequest);
210
-
211
- const apportEtBesoin = service.execute(ctx, dpeRequest.logement);
212
-
213
- expect(
214
- Math.abs(
215
- apportEtBesoin.besoin_ch_depensier -
216
- dpeRequest.logement.sortie.apport_et_besoin.besoin_ch_depensier
217
- ) / (dpeRequest.logement.sortie.apport_et_besoin.besoin_ch_depensier || 1)
218
- ).toBeLessThan(PRECISION_PERCENT);
219
- }
220
- );
221
- });
222
- });