@open3cl/engine 1.0.11 → 1.0.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/features/dpe/domain/models/installation-ecs.model.ts +15 -2
- package/features/dpe/domain/models/type-habitation.model.js +1 -0
- package/features/dpe/domain/models/type-stockage.model.js +8 -0
- package/features/dpe/infrastructure/ecs/ecsTv.store.js +43 -0
- package/features/dpe/infrastructure/ecs/ecsTv.store.spec.js +36 -0
- package/features/engine/domain/apport_et_besoin/apport-et-besoin.service.js +28 -2
- package/features/engine/domain/apport_et_besoin/apport-et-besoin.service.spec.js +22 -1
- package/features/engine/domain/apport_et_besoin/ecs/perte-ecs-recup.service.js +123 -0
- package/features/engine/domain/apport_et_besoin/ecs/perte-ecs-recup.service.spec.js +205 -0
- package/features/engine/domain/contexte.builder.js +5 -1
- package/features/engine/domain/ecs/generateur-ecs.service.js +106 -0
- package/features/engine/domain/ecs/generateur-ecs.service.spec.js +136 -0
- package/features/engine/domain/ecs/installation-ecs.service.js +156 -0
- package/features/engine/domain/ecs/installation-ecs.service.spec.js +284 -0
- package/package.json +1 -1
|
@@ -3,6 +3,7 @@ import { DE } from './dpe.model';
|
|
|
3
3
|
export interface InstallationEcs {
|
|
4
4
|
donnee_entree?: InstallationEcsDE;
|
|
5
5
|
donnee_intermediaire?: InstallationEcsDI;
|
|
6
|
+
donnee_utilisateur?: InstallationEcsDU;
|
|
6
7
|
generateur_ecs_collection?: { generateur_ecs: GenerateurEcs[] };
|
|
7
8
|
}
|
|
8
9
|
|
|
@@ -35,8 +36,16 @@ export interface InstallationEcsDI {
|
|
|
35
36
|
conso_ecs_depensier: number;
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
export interface InstallationEcsDU {
|
|
40
|
+
QdwIndVc: { conventionnel: number; depensier: number };
|
|
41
|
+
QdwColVc: { conventionnel: number; depensier: number };
|
|
42
|
+
QdwColHVc: { conventionnel: number; depensier: number };
|
|
43
|
+
QgwRecuperable: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
38
46
|
export interface GenerateurEcs {
|
|
39
47
|
donnee_entree?: GenerateurEcsDE;
|
|
48
|
+
donnee_utilisateur?: GenerateurEcsDU;
|
|
40
49
|
donnee_intermediaire?: GenerateurEcsDI;
|
|
41
50
|
}
|
|
42
51
|
|
|
@@ -55,8 +64,8 @@ export interface GenerateurEcsDE extends DE {
|
|
|
55
64
|
date_arrete_reseau_chaleur?: string;
|
|
56
65
|
tv_reseau_chaleur_id?: number;
|
|
57
66
|
enum_type_stockage_ecs_id: number;
|
|
58
|
-
position_volume_chauffe:
|
|
59
|
-
position_volume_chauffe_stockage?:
|
|
67
|
+
position_volume_chauffe: number;
|
|
68
|
+
position_volume_chauffe_stockage?: number;
|
|
60
69
|
volume_stockage: number;
|
|
61
70
|
presence_ventouse?: boolean;
|
|
62
71
|
}
|
|
@@ -74,3 +83,7 @@ export interface GenerateurEcsDI {
|
|
|
74
83
|
conso_ecs_depensier: number;
|
|
75
84
|
rendement_stockage?: number;
|
|
76
85
|
}
|
|
86
|
+
|
|
87
|
+
export interface GenerateurEcsDU {
|
|
88
|
+
Qgw?: number;
|
|
89
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { tvs as tv } from '../../../../tv-v2.js';
|
|
2
2
|
import { TvStore } from './../tv.store.js';
|
|
3
|
+
import { logger } from '../../../../core/util/logger/log-service.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Accès aux données des tables de valeurs pour le besoin en eau chaude sanitaire
|
|
@@ -19,4 +20,46 @@ export class EcsTvStore extends TvStore {
|
|
|
19
20
|
getTefs(classeAltitude, zoneClimatique, mois) {
|
|
20
21
|
return tv['tefs'][classeAltitude][mois][zoneClimatique];
|
|
21
22
|
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Coefficient de perte du ballon de stockage
|
|
26
|
+
* @see 11.6.2 Pertes des ballons électriques
|
|
27
|
+
*
|
|
28
|
+
* @param enumTypeGenerateurEcsId {string}
|
|
29
|
+
* @param volumeStockage {number}
|
|
30
|
+
*
|
|
31
|
+
* @return {number|undefined}
|
|
32
|
+
*/
|
|
33
|
+
getPertesStockage(enumTypeGenerateurEcsId, volumeStockage) {
|
|
34
|
+
let volumeBallon;
|
|
35
|
+
if (volumeStockage <= 100) volumeBallon = '≤ 100';
|
|
36
|
+
else if (volumeStockage <= 200) volumeBallon = '100 < ≤ 200';
|
|
37
|
+
else if (volumeStockage <= 300) volumeBallon = '200 < ≤ 300';
|
|
38
|
+
else volumeBallon = '> 300';
|
|
39
|
+
|
|
40
|
+
const cr = tv['pertes_stockage'].find(
|
|
41
|
+
(v) =>
|
|
42
|
+
v.enum_type_generateur_ecs_id.split('|').includes(enumTypeGenerateurEcsId) &&
|
|
43
|
+
v.volume_ballon === volumeBallon
|
|
44
|
+
)?.cr;
|
|
45
|
+
|
|
46
|
+
if (!cr) {
|
|
47
|
+
logger.error(
|
|
48
|
+
`Pas de valeur forfaitaire cr pour enumTypeGenerateurEcsId:${enumTypeGenerateurEcsId}, volumeBallon:${volumeBallon}`
|
|
49
|
+
);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return parseFloat(cr);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Récupération des ids des générateurs électriques ECS
|
|
58
|
+
* @return {[number]}
|
|
59
|
+
*/
|
|
60
|
+
getElectriqueEcsGenerateurs() {
|
|
61
|
+
return tv['pertes_stockage'].flatMap((v) =>
|
|
62
|
+
v.enum_type_generateur_ecs_id.split('|').map(Number)
|
|
63
|
+
);
|
|
64
|
+
}
|
|
22
65
|
}
|
|
@@ -30,4 +30,40 @@ describe('Lecture des tables de valeurs', () => {
|
|
|
30
30
|
expect(ecsTvStore.getTefs(classeAltitude, zoneClimatique, mois)).toBe(expected);
|
|
31
31
|
});
|
|
32
32
|
});
|
|
33
|
+
|
|
34
|
+
describe('Lecture des valeurs de pertes_stockage', () => {
|
|
35
|
+
test.each([
|
|
36
|
+
{
|
|
37
|
+
label: 'Ballon électrique à accumulation horizontal < 100L',
|
|
38
|
+
enumTypeGenerateurEcsId: '68',
|
|
39
|
+
volumeStockage: 50,
|
|
40
|
+
expected: 0.39
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
label: 'Ballon électrique à accumulation horizontal entre 100L et 200L',
|
|
44
|
+
enumTypeGenerateurEcsId: '68',
|
|
45
|
+
volumeStockage: 150,
|
|
46
|
+
expected: 0.33
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
label: 'Ballon électrique à accumulation horizontal entre 200L et 300L',
|
|
50
|
+
enumTypeGenerateurEcsId: '68',
|
|
51
|
+
volumeStockage: 250,
|
|
52
|
+
expected: 0.3
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
label: 'Ballon électrique à accumulation horizontal > 300L',
|
|
56
|
+
enumTypeGenerateurEcsId: '68',
|
|
57
|
+
volumeStockage: 301,
|
|
58
|
+
expected: 0.3
|
|
59
|
+
}
|
|
60
|
+
])(`$label`, ({ enumTypeGenerateurEcsId, volumeStockage, expected }) => {
|
|
61
|
+
expect(ecsTvStore.getPertesStockage(enumTypeGenerateurEcsId, volumeStockage)).toBe(expected);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('pas de valeur de pertes_stockage', () => {
|
|
65
|
+
const pertes_stockage = ecsTvStore.getPertesStockage('298', 600);
|
|
66
|
+
expect(pertes_stockage).toBeUndefined();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
33
69
|
});
|
|
@@ -3,6 +3,8 @@ import { BesoinEcsService } from './ecs/besoin-ecs.service.js';
|
|
|
3
3
|
import { SurfaceSudEquivalenteService } from './surface-sud-equivalente.service.js';
|
|
4
4
|
import { BesoinFroidService } from './froid/besoin-froid.service.js';
|
|
5
5
|
import { ApportGratuitService } from './apport_gratuit/apport-gratuit.service.js';
|
|
6
|
+
import { InstallationEcsService } from '../ecs/installation-ecs.service.js';
|
|
7
|
+
import { PerteEcsRecupService } from './ecs/perte-ecs-recup.service.js';
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* Calcul des déperditions de l’enveloppe GV
|
|
@@ -19,6 +21,16 @@ export class ApportEtBesoinService {
|
|
|
19
21
|
*/
|
|
20
22
|
#besoinEcsService;
|
|
21
23
|
|
|
24
|
+
/**
|
|
25
|
+
* @type {InstallationEcsService}
|
|
26
|
+
*/
|
|
27
|
+
#installationEcsService;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @type {PerteEcsRecupService}
|
|
31
|
+
*/
|
|
32
|
+
#perteEcsRecupService;
|
|
33
|
+
|
|
22
34
|
/**
|
|
23
35
|
* @type {BesoinFroidService}
|
|
24
36
|
*/
|
|
@@ -31,17 +43,23 @@ export class ApportEtBesoinService {
|
|
|
31
43
|
|
|
32
44
|
/**
|
|
33
45
|
* @param besoinEcsService {BesoinEcsService}
|
|
46
|
+
* @param installationEcsService {InstallationEcsService}
|
|
47
|
+
* @param perteEcsRecupService {PerteEcsRecupService}
|
|
34
48
|
* @param besoinFroidService {BesoinFroidService}
|
|
35
49
|
* @param surfaceSudEquivalenteService {SurfaceSudEquivalenteService}
|
|
36
50
|
* @param apportGratuitService {ApportGratuitService}
|
|
37
51
|
*/
|
|
38
52
|
constructor(
|
|
39
53
|
besoinEcsService = inject(BesoinEcsService),
|
|
54
|
+
installationEcsService = inject(InstallationEcsService),
|
|
55
|
+
perteEcsRecupService = inject(PerteEcsRecupService),
|
|
40
56
|
besoinFroidService = inject(BesoinFroidService),
|
|
41
57
|
surfaceSudEquivalenteService = inject(SurfaceSudEquivalenteService),
|
|
42
58
|
apportGratuitService = inject(ApportGratuitService)
|
|
43
59
|
) {
|
|
44
60
|
this.#besoinEcsService = besoinEcsService;
|
|
61
|
+
this.#installationEcsService = installationEcsService;
|
|
62
|
+
this.#perteEcsRecupService = perteEcsRecupService;
|
|
45
63
|
this.#besoinFroidService = besoinFroidService;
|
|
46
64
|
this.#surfaceSudEquivalenteService = surfaceSudEquivalenteService;
|
|
47
65
|
this.#apportGratuitService = apportGratuitService;
|
|
@@ -55,8 +73,15 @@ export class ApportEtBesoinService {
|
|
|
55
73
|
* @return {ApportEtBesoin}
|
|
56
74
|
*/
|
|
57
75
|
execute(ctx, logement) {
|
|
76
|
+
const besoinEcs = this.#besoinEcsService.execute(ctx);
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Détermination des besoins et pertes des installations ECS
|
|
80
|
+
*/
|
|
81
|
+
this.#installationEcsService.execute(ctx, logement, besoinEcs);
|
|
82
|
+
|
|
58
83
|
return {
|
|
59
|
-
...
|
|
84
|
+
...besoinEcs,
|
|
60
85
|
...{
|
|
61
86
|
surface_sud_equivalente: this.#surfaceSudEquivalenteService.execute(
|
|
62
87
|
ctx,
|
|
@@ -68,7 +93,8 @@ export class ApportEtBesoinService {
|
|
|
68
93
|
},
|
|
69
94
|
...this.#besoinFroidService.execute(ctx, logement),
|
|
70
95
|
...this.#apportGratuitService.apportInterne(ctx, logement),
|
|
71
|
-
...this.#apportGratuitService.apportSolaire(ctx, logement)
|
|
96
|
+
...this.#apportGratuitService.apportSolaire(ctx, logement),
|
|
97
|
+
...this.#perteEcsRecupService.execute(ctx, logement)
|
|
72
98
|
};
|
|
73
99
|
}
|
|
74
100
|
}
|
|
@@ -5,6 +5,8 @@ import { ApportEtBesoinService } from './apport-et-besoin.service.js';
|
|
|
5
5
|
import { BesoinEcsService } from './ecs/besoin-ecs.service.js';
|
|
6
6
|
import { BesoinFroidService } from './froid/besoin-froid.service.js';
|
|
7
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';
|
|
8
10
|
|
|
9
11
|
/** @type {SurfaceSudEquivalenteService} **/
|
|
10
12
|
let surfaceSudEquivalenteService;
|
|
@@ -15,6 +17,12 @@ let besoinEcsService;
|
|
|
15
17
|
/** @type {BesoinFroidService} **/
|
|
16
18
|
let besoinFroidService;
|
|
17
19
|
|
|
20
|
+
/** @type {InstallationEcsService} **/
|
|
21
|
+
let installationEcsService;
|
|
22
|
+
|
|
23
|
+
/** @type {PerteEcsRecupService} **/
|
|
24
|
+
let perteEcsRecupService;
|
|
25
|
+
|
|
18
26
|
/** @type {ApportGratuitService} **/
|
|
19
27
|
let apportGratuitService;
|
|
20
28
|
|
|
@@ -30,9 +38,13 @@ describe('Calcul des apports et besoin du logement', () => {
|
|
|
30
38
|
surfaceSudEquivalenteService = new SurfaceSudEquivalenteService(tvStore);
|
|
31
39
|
besoinEcsService = new BesoinEcsService();
|
|
32
40
|
besoinFroidService = new BesoinFroidService();
|
|
41
|
+
installationEcsService = new InstallationEcsService();
|
|
42
|
+
perteEcsRecupService = new PerteEcsRecupService();
|
|
33
43
|
apportGratuitService = new ApportGratuitService();
|
|
34
44
|
service = new ApportEtBesoinService(
|
|
35
45
|
besoinEcsService,
|
|
46
|
+
installationEcsService,
|
|
47
|
+
perteEcsRecupService,
|
|
36
48
|
besoinFroidService,
|
|
37
49
|
surfaceSudEquivalenteService,
|
|
38
50
|
apportGratuitService
|
|
@@ -57,6 +69,12 @@ describe('Calcul des apports et besoin du logement', () => {
|
|
|
57
69
|
apport_interne_ch: 1236.9,
|
|
58
70
|
apport_interne_fr: 3345.2
|
|
59
71
|
});
|
|
72
|
+
vi.spyOn(installationEcsService, 'execute').mockReturnThis();
|
|
73
|
+
vi.spyOn(perteEcsRecupService, 'execute').mockReturnValue({
|
|
74
|
+
pertes_distribution_ecs_recup: 354.2,
|
|
75
|
+
pertes_distribution_ecs_recup_depensier: 532.6,
|
|
76
|
+
pertes_stockage_ecs_recup: 25.9
|
|
77
|
+
});
|
|
60
78
|
|
|
61
79
|
/** @type {Contexte} */
|
|
62
80
|
const ctx = { zoneClimatique: { id: 1 }, nadeq: 2.5 };
|
|
@@ -74,7 +92,10 @@ describe('Calcul des apports et besoin du logement', () => {
|
|
|
74
92
|
apport_interne_fr: 3345.2,
|
|
75
93
|
nadeq: 2.5,
|
|
76
94
|
v40_ecs_journalier: 140,
|
|
77
|
-
v40_ecs_journalier_depensier: 197.5
|
|
95
|
+
v40_ecs_journalier_depensier: 197.5,
|
|
96
|
+
pertes_distribution_ecs_recup: 354.2,
|
|
97
|
+
pertes_distribution_ecs_recup_depensier: 532.6,
|
|
98
|
+
pertes_stockage_ecs_recup: 25.9
|
|
78
99
|
});
|
|
79
100
|
expect(surfaceSudEquivalenteService.execute).toHaveBeenCalledWith(ctx, logement.enveloppe);
|
|
80
101
|
expect(besoinEcsService.execute).toHaveBeenCalledWith(ctx);
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { mois_liste } from '../../../../../utils.js';
|
|
2
|
+
import { inject } from 'dioma';
|
|
3
|
+
import { FrTvStore } from '../../../../dpe/infrastructure/froid/frTv.store.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Calcul des pertes récupérées de distribution et de stockage d'ECS
|
|
7
|
+
* Chapitre 9.1.1 Consommation de chauffage
|
|
8
|
+
*
|
|
9
|
+
* Données calculées
|
|
10
|
+
* — pertes_distribution_ecs_recup : pertes de distribution d'ECS récupérées(kWh)
|
|
11
|
+
* — pertes_distribution_ecs_recup_depensier : pertes de distribution d'ECS récupérées(kWh) pour le scénario dépensier
|
|
12
|
+
* — pertes_stockage_ecs_recup : pertes de stockage d'ECS récupérées(kWh)
|
|
13
|
+
*
|
|
14
|
+
* Methode_de_calcul_3CL_DPE_2021 - Page 57
|
|
15
|
+
* Octobre 2021
|
|
16
|
+
* @see consolide_anne…arrete_du_31_03_2021_relatif_aux_methodes_et_procedures_applicables.pdf
|
|
17
|
+
*/
|
|
18
|
+
export class PerteEcsRecupService {
|
|
19
|
+
/**
|
|
20
|
+
* @type {FrTvStore}
|
|
21
|
+
*/
|
|
22
|
+
#tvStore;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param tvStore {FrTvStore}
|
|
26
|
+
*/
|
|
27
|
+
constructor(tvStore = inject(FrTvStore)) {
|
|
28
|
+
this.#tvStore = tvStore;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param ctx {Contexte}
|
|
33
|
+
* @param logement {Logement}
|
|
34
|
+
* @return {{pertes_distribution_ecs_recup: number, pertes_distribution_ecs_recup_depensier: number, pertes_stockage_ecs_recup: number}}
|
|
35
|
+
*/
|
|
36
|
+
execute(ctx, logement) {
|
|
37
|
+
return {
|
|
38
|
+
pertes_distribution_ecs_recup: this.pertesDistributionEcsRecup(ctx, logement, false),
|
|
39
|
+
pertes_distribution_ecs_recup_depensier: this.pertesDistributionEcsRecup(ctx, logement, true),
|
|
40
|
+
pertes_stockage_ecs_recup: this.pertesStockageEcsRecup(ctx, logement)
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Pertes récupérées de distribution d’ECS pour le chauffage
|
|
46
|
+
* 9.1.1 Consommation de chauffage
|
|
47
|
+
*
|
|
48
|
+
* @param ctx {Contexte}
|
|
49
|
+
* @param logement {Logement}
|
|
50
|
+
* @param depensier {boolean}
|
|
51
|
+
* @returns {number}
|
|
52
|
+
*/
|
|
53
|
+
pertesDistributionEcsRecup(ctx, logement, depensier) {
|
|
54
|
+
const installationsEcs = logement.installation_ecs_collection?.installation_ecs || [];
|
|
55
|
+
|
|
56
|
+
const pertesDistribution = installationsEcs.reduce((acc, installation) => {
|
|
57
|
+
/** @type {InstallationEcsDU}*/
|
|
58
|
+
const installationEcsDU = installation.donnee_utilisateur;
|
|
59
|
+
|
|
60
|
+
const pertesDistributionIndividuelleVolumeChauffee = depensier
|
|
61
|
+
? installationEcsDU.QdwIndVc.depensier
|
|
62
|
+
: installationEcsDU.QdwIndVc.conventionnel;
|
|
63
|
+
const pertesDistributionCollectiveVolumeChauffee = depensier
|
|
64
|
+
? installationEcsDU.QdwColVc.depensier
|
|
65
|
+
: installationEcsDU.QdwColVc.conventionnel;
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
acc +
|
|
69
|
+
pertesDistributionIndividuelleVolumeChauffee +
|
|
70
|
+
pertesDistributionCollectiveVolumeChauffee
|
|
71
|
+
);
|
|
72
|
+
}, 0);
|
|
73
|
+
|
|
74
|
+
return mois_liste.reduce((acc, mois) => {
|
|
75
|
+
return (
|
|
76
|
+
acc +
|
|
77
|
+
(0.48 *
|
|
78
|
+
pertesDistribution *
|
|
79
|
+
this.#tvStore.getData(
|
|
80
|
+
depensier ? 'nref21' : 'nref19',
|
|
81
|
+
ctx.altitude.value,
|
|
82
|
+
ctx.zoneClimatique.value,
|
|
83
|
+
mois,
|
|
84
|
+
ctx.inertie.ilpa
|
|
85
|
+
)) /
|
|
86
|
+
8760
|
|
87
|
+
);
|
|
88
|
+
}, 0);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Pertes récupérées du stockage d’ECS pour le chauffage
|
|
93
|
+
* 9.1.1 Consommation de chauffage
|
|
94
|
+
*
|
|
95
|
+
* @param ctx {Contexte}
|
|
96
|
+
* @param logement {Logement}
|
|
97
|
+
* @returns {number}
|
|
98
|
+
*/
|
|
99
|
+
pertesStockageEcsRecup(ctx, logement) {
|
|
100
|
+
const installationsEcs = logement.installation_ecs_collection?.installation_ecs || [];
|
|
101
|
+
|
|
102
|
+
let pertesStockage = installationsEcs.reduce((acc, installation) => {
|
|
103
|
+
/** @type {InstallationEcsDU}*/
|
|
104
|
+
const installationEcsDU = installation.donnee_utilisateur;
|
|
105
|
+
|
|
106
|
+
return acc + (0.48 * installationEcsDU.QgwRecuperable) / 8760.0;
|
|
107
|
+
}, 0);
|
|
108
|
+
|
|
109
|
+
return mois_liste.reduce((acc, mois) => {
|
|
110
|
+
return (
|
|
111
|
+
acc +
|
|
112
|
+
pertesStockage *
|
|
113
|
+
this.#tvStore.getData(
|
|
114
|
+
'nref19',
|
|
115
|
+
ctx.altitude.value,
|
|
116
|
+
ctx.zoneClimatique.value,
|
|
117
|
+
mois,
|
|
118
|
+
ctx.inertie.ilpa
|
|
119
|
+
)
|
|
120
|
+
);
|
|
121
|
+
}, 0);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
|
2
|
+
import corpus from '../../../../../../test/corpus-sano.json';
|
|
3
|
+
import { expect_or, getAdemeFileJson } from '../../../../../../test/test-helpers.js';
|
|
4
|
+
import { DpeNormalizerService } from '../../../../normalizer/domain/dpe-normalizer.service.js';
|
|
5
|
+
import { ContexteBuilder } from '../../contexte.builder.js';
|
|
6
|
+
import { PerteEcsRecupService } from './perte-ecs-recup.service.js';
|
|
7
|
+
import { FrTvStore } from '../../../../dpe/infrastructure/froid/frTv.store.js';
|
|
8
|
+
import { mois_liste } from '../../../../../utils.js';
|
|
9
|
+
import { EcsTvStore } from '../../../../dpe/infrastructure/ecs/ecsTv.store.js';
|
|
10
|
+
import { GenerateurEcsService } from '../../ecs/generateur-ecs.service.js';
|
|
11
|
+
import { InstallationEcsService } from '../../ecs/installation-ecs.service.js';
|
|
12
|
+
|
|
13
|
+
/** @type {PerteEcsRecupService} **/
|
|
14
|
+
let service;
|
|
15
|
+
|
|
16
|
+
/** @type {FrTvStore} **/
|
|
17
|
+
let tvStore;
|
|
18
|
+
|
|
19
|
+
/** @type {InstallationEcsService} **/
|
|
20
|
+
let installationEcsService;
|
|
21
|
+
|
|
22
|
+
/** @type {DpeNormalizerService} **/
|
|
23
|
+
let normalizerService;
|
|
24
|
+
|
|
25
|
+
/** @type {ContexteBuilder} **/
|
|
26
|
+
let contexteBuilder;
|
|
27
|
+
|
|
28
|
+
describe('Calcul des pertes de distribution et stockage récupérées', () => {
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
tvStore = new FrTvStore();
|
|
31
|
+
service = new PerteEcsRecupService(tvStore);
|
|
32
|
+
installationEcsService = new InstallationEcsService(new GenerateurEcsService(new EcsTvStore()));
|
|
33
|
+
normalizerService = new DpeNormalizerService();
|
|
34
|
+
contexteBuilder = new ContexteBuilder();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test.each([
|
|
38
|
+
{
|
|
39
|
+
label: 'Installation ECS en mode conventionnel',
|
|
40
|
+
depensier: false,
|
|
41
|
+
expected: 0.36
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
label: 'Installation ECS en mode dépensier',
|
|
45
|
+
depensier: true,
|
|
46
|
+
expected: 0.72
|
|
47
|
+
}
|
|
48
|
+
])('Calcul des pertes de distribution récupérées pour $label', ({ depensier, expected }) => {
|
|
49
|
+
vi.spyOn(tvStore, 'getData').mockReturnValue(1.5);
|
|
50
|
+
|
|
51
|
+
/** @type {Contexte} */
|
|
52
|
+
const ctx = {
|
|
53
|
+
altitude: { value: '400-800m' },
|
|
54
|
+
zoneClimatique: { value: 'h1a' },
|
|
55
|
+
inertie: { ilpa: 1 }
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/** @type {Logement} */
|
|
59
|
+
const logement = {
|
|
60
|
+
installation_ecs_collection: {
|
|
61
|
+
installation_ecs: [
|
|
62
|
+
{
|
|
63
|
+
donnee_utilisateur: {
|
|
64
|
+
QdwIndVc: { conventionnel: 100, depensier: 200 },
|
|
65
|
+
QdwColVc: { conventionnel: 50, depensier: 120 }
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
donnee_utilisateur: {
|
|
70
|
+
QdwIndVc: { conventionnel: 150, depensier: 280 },
|
|
71
|
+
QdwColVc: { conventionnel: 65, depensier: 135 }
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
expect(service.pertesDistributionEcsRecup(ctx, logement, depensier)).toBeCloseTo(expected, 2);
|
|
79
|
+
for (const mois of mois_liste) {
|
|
80
|
+
expect(tvStore.getData).toHaveBeenCalledWith(
|
|
81
|
+
depensier ? 'nref21' : 'nref19',
|
|
82
|
+
'400-800m',
|
|
83
|
+
'h1a',
|
|
84
|
+
mois,
|
|
85
|
+
1
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('Calcul des pertes de stockage récupérées pour une installation ECS', () => {
|
|
91
|
+
vi.spyOn(tvStore, 'getData').mockReturnValue(1.5);
|
|
92
|
+
|
|
93
|
+
/** @type {Contexte} */
|
|
94
|
+
const ctx = {
|
|
95
|
+
altitude: { value: '400-800m' },
|
|
96
|
+
zoneClimatique: { value: 'h1a' },
|
|
97
|
+
inertie: { ilpa: 1 }
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/** @type {Logement} */
|
|
101
|
+
const logement = {
|
|
102
|
+
installation_ecs_collection: {
|
|
103
|
+
installation_ecs: [
|
|
104
|
+
{ donnee_utilisateur: { QgwRecuperable: 120 } },
|
|
105
|
+
{ donnee_utilisateur: { QgwRecuperable: 150 } }
|
|
106
|
+
]
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
expect(service.pertesStockageEcsRecup(ctx, logement)).toBeCloseTo(0.27);
|
|
111
|
+
for (const mois of mois_liste) {
|
|
112
|
+
expect(tvStore.getData).toHaveBeenCalledWith('nref19', '400-800m', 'h1a', mois, 1);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe("Test d'intégration des installations ECS", () => {
|
|
117
|
+
test.each(corpus)(
|
|
118
|
+
'vérification des pertes de distribution ecs recup des installations ECS pour dpe %s',
|
|
119
|
+
(ademeId) => {
|
|
120
|
+
let dpeRequest = getAdemeFileJson(ademeId);
|
|
121
|
+
dpeRequest = normalizerService.normalize(dpeRequest);
|
|
122
|
+
|
|
123
|
+
/** @type {Contexte} */
|
|
124
|
+
const ctx = contexteBuilder.fromDpe(dpeRequest);
|
|
125
|
+
|
|
126
|
+
installationEcsService.execute(ctx, dpeRequest.logement, {
|
|
127
|
+
besoin_ecs: dpeRequest.logement.sortie.apport_et_besoin.besoin_ecs,
|
|
128
|
+
besoin_ecs_depensier: dpeRequest.logement.sortie.apport_et_besoin.besoin_ecs_depensier
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const pertesStockage = service.execute(ctx, dpeRequest.logement);
|
|
132
|
+
|
|
133
|
+
expect_or(
|
|
134
|
+
() =>
|
|
135
|
+
expect(pertesStockage.pertes_distribution_ecs_recup).toBeCloseTo(
|
|
136
|
+
dpeRequest.logement.sortie.apport_et_besoin.pertes_distribution_ecs_recup
|
|
137
|
+
),
|
|
138
|
+
() =>
|
|
139
|
+
expect(pertesStockage.pertes_distribution_ecs_recup * 1000).toBeCloseTo(
|
|
140
|
+
dpeRequest.logement.sortie.apport_et_besoin.pertes_distribution_ecs_recup
|
|
141
|
+
)
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
);
|
|
145
|
+
test.each(corpus)(
|
|
146
|
+
'vérification des pertes de distribution ecs recup depensier des installations ECS pour dpe %s',
|
|
147
|
+
(ademeId) => {
|
|
148
|
+
let dpeRequest = getAdemeFileJson(ademeId);
|
|
149
|
+
dpeRequest = normalizerService.normalize(dpeRequest);
|
|
150
|
+
|
|
151
|
+
/** @type {Contexte} */
|
|
152
|
+
const ctx = contexteBuilder.fromDpe(dpeRequest);
|
|
153
|
+
|
|
154
|
+
installationEcsService.execute(ctx, dpeRequest.logement, {
|
|
155
|
+
besoin_ecs: dpeRequest.logement.sortie.apport_et_besoin.besoin_ecs,
|
|
156
|
+
besoin_ecs_depensier: dpeRequest.logement.sortie.apport_et_besoin.besoin_ecs_depensier
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const pertesStockage = service.execute(ctx, dpeRequest.logement);
|
|
160
|
+
|
|
161
|
+
expect_or(
|
|
162
|
+
() =>
|
|
163
|
+
expect(pertesStockage.pertes_distribution_ecs_recup_depensier).toBeCloseTo(
|
|
164
|
+
dpeRequest.logement.sortie.apport_et_besoin.pertes_distribution_ecs_recup_depensier
|
|
165
|
+
),
|
|
166
|
+
() =>
|
|
167
|
+
expect(pertesStockage.pertes_distribution_ecs_recup_depensier * 1000).toBeCloseTo(
|
|
168
|
+
dpeRequest.logement.sortie.apport_et_besoin.pertes_distribution_ecs_recup_depensier
|
|
169
|
+
)
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
);
|
|
173
|
+
test.each(corpus)(
|
|
174
|
+
'vérification des pertes de stockage ecs recup des installations ECS pour dpe %s',
|
|
175
|
+
(ademeId) => {
|
|
176
|
+
let dpeRequest = getAdemeFileJson(ademeId);
|
|
177
|
+
dpeRequest = normalizerService.normalize(dpeRequest);
|
|
178
|
+
|
|
179
|
+
/** @type {Contexte} */
|
|
180
|
+
const ctx = contexteBuilder.fromDpe(dpeRequest);
|
|
181
|
+
|
|
182
|
+
installationEcsService.execute(ctx, dpeRequest.logement, {
|
|
183
|
+
besoin_ecs: dpeRequest.logement.sortie.apport_et_besoin.besoin_ecs,
|
|
184
|
+
besoin_ecs_depensier: dpeRequest.logement.sortie.apport_et_besoin.besoin_ecs_depensier
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
const pertesStockage = service.execute(ctx, dpeRequest.logement);
|
|
188
|
+
expect_or(
|
|
189
|
+
() =>
|
|
190
|
+
expect(pertesStockage.pertes_stockage_ecs_recup).toBeCloseTo(
|
|
191
|
+
dpeRequest.logement.sortie.apport_et_besoin.pertes_stockage_ecs_recup
|
|
192
|
+
),
|
|
193
|
+
() =>
|
|
194
|
+
expect(pertesStockage.pertes_stockage_ecs_recup).toBeCloseTo(
|
|
195
|
+
dpeRequest.logement.sortie.apport_et_besoin.pertes_stockage_ecs_recup * 1000
|
|
196
|
+
),
|
|
197
|
+
() =>
|
|
198
|
+
expect(pertesStockage.pertes_stockage_ecs_recup * 1000).toBeCloseTo(
|
|
199
|
+
dpeRequest.logement.sortie.apport_et_besoin.pertes_stockage_ecs_recup
|
|
200
|
+
)
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
);
|
|
204
|
+
});
|
|
205
|
+
});
|
|
@@ -132,8 +132,12 @@ export class ContexteBuilder {
|
|
|
132
132
|
|
|
133
133
|
if ([1, 14, 18].includes(methodeApplication)) {
|
|
134
134
|
return TypeDpe.MAISON;
|
|
135
|
-
} else if (
|
|
135
|
+
} else if (
|
|
136
|
+
[2, 3, 4, 5, 15, 16, 19, 20, 22, 23, 24, 25, 31, 32, 35, 36, 37].includes(methodeApplication)
|
|
137
|
+
) {
|
|
136
138
|
return TypeDpe.APPARTEMENT;
|
|
139
|
+
} else if ([10, 11, 12, 13, 33, 34, 38, 39, 40].includes(methodeApplication)) {
|
|
140
|
+
return TypeDpe.APPARTEMENT_A_PARTIR_IMMEUBLE;
|
|
137
141
|
}
|
|
138
142
|
return TypeDpe.IMMEUBLE;
|
|
139
143
|
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { TypeStockage } from '../../../dpe/domain/models/type-stockage.model.js';
|
|
2
|
+
import { inject } from 'dioma';
|
|
3
|
+
import { EcsTvStore } from '../../../dpe/infrastructure/ecs/ecsTv.store.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Calcul des données de calcul pour chacun des générateurs
|
|
7
|
+
* Données calculées
|
|
8
|
+
* — Qgw : pertes liées au stockage de l'ECS pour chaque générateur
|
|
9
|
+
*/
|
|
10
|
+
export class GenerateurEcsService {
|
|
11
|
+
/**
|
|
12
|
+
* @type {EcsTvStore}
|
|
13
|
+
*/
|
|
14
|
+
#tvStore;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param tvStore {EcsTvStore}
|
|
18
|
+
*/
|
|
19
|
+
constructor(tvStore = inject(EcsTvStore)) {
|
|
20
|
+
this.#tvStore = tvStore;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Détermination des apports et besoins pour le bien concerné
|
|
25
|
+
*
|
|
26
|
+
* @param installationEcs {InstallationEcs}
|
|
27
|
+
*/
|
|
28
|
+
execute(installationEcs) {
|
|
29
|
+
const generateursEcs = installationEcs.generateur_ecs_collection.generateur_ecs || [];
|
|
30
|
+
|
|
31
|
+
generateursEcs.forEach((generateurEcs) => {
|
|
32
|
+
/** @type {GenerateurEcsDE}*/
|
|
33
|
+
const generateurEcsDE = generateurEcs.donnee_entree;
|
|
34
|
+
|
|
35
|
+
generateurEcs.donnee_utilisateur = {
|
|
36
|
+
Qgw: this.pertesStockage(generateurEcsDE)
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Pertes de stockage d'un générateur ECS.
|
|
43
|
+
* Seules les générateurs avec stockage indépendant et dissocié du générateur sont concernés
|
|
44
|
+
*
|
|
45
|
+
* 11.6.1 - Pertes de stockage des ballons d’accumulation
|
|
46
|
+
* 11.6.2 - Pertes des ballons électriques
|
|
47
|
+
*
|
|
48
|
+
* @param generateurEcsDE {GenerateurEcsDE}
|
|
49
|
+
* @return {number}
|
|
50
|
+
*/
|
|
51
|
+
pertesStockage(generateurEcsDE) {
|
|
52
|
+
const electrique = this.generateurElectrique(generateurEcsDE);
|
|
53
|
+
const typeStockage = this.typeStockage(generateurEcsDE);
|
|
54
|
+
|
|
55
|
+
if (typeStockage === TypeStockage.INSTANTANE) {
|
|
56
|
+
return 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
let Qgw;
|
|
60
|
+
let volumeStockage = generateurEcsDE.volume_stockage;
|
|
61
|
+
|
|
62
|
+
if (electrique) {
|
|
63
|
+
const cr = this.#tvStore.getPertesStockage(
|
|
64
|
+
generateurEcsDE.enum_type_generateur_ecs_id,
|
|
65
|
+
volumeStockage
|
|
66
|
+
);
|
|
67
|
+
// Les pertes de stockage des ballons électriques (Wh)
|
|
68
|
+
Qgw = ((8592 * 45) / 24) * volumeStockage * cr;
|
|
69
|
+
} else {
|
|
70
|
+
// La présence d’un ballon de préparation de l’ECS est responsable de pertes de stockage Qgw (Wh)
|
|
71
|
+
Qgw = 67662 * volumeStockage ** 0.55;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return Qgw;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Return true si le générateur ECS est électrique
|
|
79
|
+
*
|
|
80
|
+
* 1 - abscence de stockage d'ecs (production instantanée)
|
|
81
|
+
* 2 - stockage indépendant de la production
|
|
82
|
+
* 3 - stockage intégré à la production
|
|
83
|
+
*
|
|
84
|
+
* @param generateurEcsDE {GenerateurEcsDE}
|
|
85
|
+
* @return {boolean}
|
|
86
|
+
*/
|
|
87
|
+
generateurElectrique(generateurEcsDE) {
|
|
88
|
+
return this.#tvStore
|
|
89
|
+
.getElectriqueEcsGenerateurs()
|
|
90
|
+
.includes(parseInt(generateurEcsDE.enum_type_generateur_ecs_id));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Return le type de stockage d'ECS
|
|
95
|
+
*
|
|
96
|
+
* @param generateurEcsDE {GenerateurEcsDE}
|
|
97
|
+
* @return TypeStockage
|
|
98
|
+
*/
|
|
99
|
+
typeStockage(generateurEcsDE) {
|
|
100
|
+
return parseInt(generateurEcsDE.enum_type_stockage_ecs_id) === 1
|
|
101
|
+
? TypeStockage.INSTANTANE
|
|
102
|
+
: parseInt(generateurEcsDE.enum_type_stockage_ecs_id) === 2
|
|
103
|
+
? TypeStockage.INDEPENDANT
|
|
104
|
+
: TypeStockage.INTEGRE;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
|
2
|
+
import { GenerateurEcsService } from './generateur-ecs.service.js';
|
|
3
|
+
import { EcsTvStore } from '../../../dpe/infrastructure/ecs/ecsTv.store.js';
|
|
4
|
+
import { TypeStockage } from '../../../dpe/domain/models/type-stockage.model.js';
|
|
5
|
+
|
|
6
|
+
/** @type {GenerateurEcsService} **/
|
|
7
|
+
let service;
|
|
8
|
+
|
|
9
|
+
/** @type {EcsTvStore} **/
|
|
10
|
+
let tvStore;
|
|
11
|
+
|
|
12
|
+
describe('Calcul des informations techniques des générateurs ECS', () => {
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
tvStore = new EcsTvStore();
|
|
15
|
+
service = new GenerateurEcsService(tvStore);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe("Calcul des pertes de stockage d'un générateur", () => {
|
|
19
|
+
test.each([
|
|
20
|
+
{
|
|
21
|
+
label: 'Générateur ECS avec production instantanée',
|
|
22
|
+
enumTypeGenerateurEcsId: 1,
|
|
23
|
+
enumTypeStockageEcsId: 1,
|
|
24
|
+
volumeStockage: 100,
|
|
25
|
+
expected: 0
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
label: 'Générateur ECS avec stockage intégré au générateur',
|
|
29
|
+
enumTypeGenerateurEcsId: 1,
|
|
30
|
+
enumTypeStockageEcsId: 2,
|
|
31
|
+
volumeStockage: 100,
|
|
32
|
+
expected: 851814.11
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
label: 'Générateur ECS électrique avec stockage indépendant de 100L',
|
|
36
|
+
enumTypeGenerateurEcsId: 2,
|
|
37
|
+
enumTypeStockageEcsId: 3,
|
|
38
|
+
electrique: true,
|
|
39
|
+
volumeStockage: 250,
|
|
40
|
+
expected: 1288800
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
label: 'Générateur ECS à gaz avec stockage indépendant de 200L',
|
|
44
|
+
enumTypeGenerateurEcsId: 1,
|
|
45
|
+
enumTypeStockageEcsId: 3,
|
|
46
|
+
volumeStockage: 200,
|
|
47
|
+
expected: 1247128.86
|
|
48
|
+
}
|
|
49
|
+
])(
|
|
50
|
+
'$label',
|
|
51
|
+
({
|
|
52
|
+
enumTypeGenerateurEcsId,
|
|
53
|
+
volumeStockage,
|
|
54
|
+
enumTypeStockageEcsId,
|
|
55
|
+
electrique = false,
|
|
56
|
+
expected
|
|
57
|
+
}) => {
|
|
58
|
+
vi.spyOn(tvStore, 'getPertesStockage').mockReturnValue(0.32);
|
|
59
|
+
vi.spyOn(tvStore, 'getElectriqueEcsGenerateurs').mockReturnValue([2]);
|
|
60
|
+
|
|
61
|
+
/** @type {GenerateurEcsDE} */
|
|
62
|
+
const generateurEcsDE = {
|
|
63
|
+
enum_type_generateur_ecs_id: enumTypeGenerateurEcsId,
|
|
64
|
+
volume_stockage: volumeStockage,
|
|
65
|
+
enum_type_stockage_ecs_id: enumTypeStockageEcsId
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const pertesStockage = service.pertesStockage(generateurEcsDE);
|
|
69
|
+
|
|
70
|
+
if (electrique) {
|
|
71
|
+
expect(tvStore.getPertesStockage).toHaveBeenCalledWith(
|
|
72
|
+
enumTypeGenerateurEcsId,
|
|
73
|
+
volumeStockage
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
expect(pertesStockage).toBeCloseTo(expected, 2);
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
test('Ajout des données utilisateurs sur tous les générateurs', () => {
|
|
81
|
+
/** @type {InstallationEcs} */
|
|
82
|
+
const installationsEcs = {
|
|
83
|
+
generateur_ecs_collection: {
|
|
84
|
+
generateur_ecs: [
|
|
85
|
+
{
|
|
86
|
+
donnee_entree: {
|
|
87
|
+
enum_type_stockage_ecs_id: 2,
|
|
88
|
+
enum_type_energie_id: 2,
|
|
89
|
+
volume_stockage: 100
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
donnee_entree: {
|
|
94
|
+
enum_type_stockage_ecs_id: 2,
|
|
95
|
+
enum_type_energie_id: 2,
|
|
96
|
+
volume_stockage: 150
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
donnee_entree: {
|
|
101
|
+
enum_type_stockage_ecs_id: 1,
|
|
102
|
+
enum_type_energie_id: 2,
|
|
103
|
+
volume_stockage: 150
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
]
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
service.execute(installationsEcs);
|
|
111
|
+
|
|
112
|
+
expect(
|
|
113
|
+
installationsEcs.generateur_ecs_collection.generateur_ecs[0].donnee_utilisateur.Qgw
|
|
114
|
+
).toBeCloseTo(851814.112128, 2);
|
|
115
|
+
expect(
|
|
116
|
+
installationsEcs.generateur_ecs_collection.generateur_ecs[1].donnee_utilisateur.Qgw
|
|
117
|
+
).toBeCloseTo(1064620.98719, 2);
|
|
118
|
+
expect(
|
|
119
|
+
installationsEcs.generateur_ecs_collection.generateur_ecs[2].donnee_utilisateur.Qgw
|
|
120
|
+
).toBe(0);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test("Determination du type d'énergie électrique du générateur", () => {
|
|
125
|
+
vi.spyOn(tvStore, 'getElectriqueEcsGenerateurs').mockReturnValue([1]);
|
|
126
|
+
expect(service.generateurElectrique({ enum_type_generateur_ecs_id: 1 })).toBeTruthy();
|
|
127
|
+
expect(service.generateurElectrique({ enum_type_generateur_ecs_id: 2 })).toBeFalsy();
|
|
128
|
+
expect(tvStore.getElectriqueEcsGenerateurs).toHaveBeenCalled();
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test('Determination du type de stockage du générateur', () => {
|
|
132
|
+
expect(service.typeStockage({ enum_type_stockage_ecs_id: 1 })).toBe(TypeStockage.INSTANTANE);
|
|
133
|
+
expect(service.typeStockage({ enum_type_stockage_ecs_id: 2 })).toBe(TypeStockage.INDEPENDANT);
|
|
134
|
+
expect(service.typeStockage({ enum_type_stockage_ecs_id: 3 })).toBe(TypeStockage.INTEGRE);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { GenerateurEcsService } from './generateur-ecs.service.js';
|
|
2
|
+
import { inject } from 'dioma';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Calcul des besoins et pertes des installations ECS
|
|
6
|
+
* Données calculées
|
|
7
|
+
* — besoin_ecs : besoin en eau chaude sanitaire en mode conventionnel proratisé pour l'installation
|
|
8
|
+
* — besoin_ecs_depensier : besoin en eau chaude sanitaire en mode dépensier proratisé pour l'installation
|
|
9
|
+
* — besoin_ecs_depensier : pertes liées au stockage de l'ECS pour chaque générateur
|
|
10
|
+
* — QdwIndVc: pertes de la distribution individuelle en volume chauffé pour le mois j (Wh)
|
|
11
|
+
* — QdwColVc: pertes de la distribution collective en volume chauffé pour le mois j (Wh)
|
|
12
|
+
* — QdwColHVc: pertes de la distribution collective hors volume chauffé pour le mois j (Wh)
|
|
13
|
+
*
|
|
14
|
+
* @see Méthode de calcul 3CL-DPE 2021 (cotobre 2021) chapitre 3
|
|
15
|
+
*/
|
|
16
|
+
export class InstallationEcsService {
|
|
17
|
+
/**
|
|
18
|
+
* @type {GenerateurEcsService}
|
|
19
|
+
*/
|
|
20
|
+
#generateurEcsService;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param generateurEcsService {GenerateurEcsService}
|
|
24
|
+
*/
|
|
25
|
+
constructor(generateurEcsService = inject(GenerateurEcsService)) {
|
|
26
|
+
this.#generateurEcsService = generateurEcsService;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Détermination des besoins et pertes des installations ECS
|
|
31
|
+
*
|
|
32
|
+
* @param ctx {Contexte}
|
|
33
|
+
* @param logement {Logement}
|
|
34
|
+
* @param besoinEcs {{besoin_ecs: number, besoin_ecs_depensier: number}}
|
|
35
|
+
*/
|
|
36
|
+
execute(ctx, logement, besoinEcs) {
|
|
37
|
+
const installationsEcs = logement.installation_ecs_collection?.installation_ecs || [];
|
|
38
|
+
|
|
39
|
+
installationsEcs.forEach((installationEcs) => {
|
|
40
|
+
/**
|
|
41
|
+
* Calcul des données nécessaires au calcul pour chaque générateur (perteStockage)
|
|
42
|
+
*/
|
|
43
|
+
this.#generateurEcsService.execute(installationEcs);
|
|
44
|
+
|
|
45
|
+
const { besoinEcsInstallation, besoinEcsDepensierInstallation } = this.besoinEcsInstallation(
|
|
46
|
+
ctx,
|
|
47
|
+
installationEcs,
|
|
48
|
+
besoinEcs
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
installationEcs.donnee_intermediaire = {
|
|
52
|
+
besoin_ecs: besoinEcsInstallation,
|
|
53
|
+
besoin_ecs_depensier: besoinEcsDepensierInstallation
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Calcul des pertes de stockage et génération au niveau de l'installation
|
|
58
|
+
*/
|
|
59
|
+
this.pertesDistributionStockageEcsInstallation(
|
|
60
|
+
installationEcs,
|
|
61
|
+
besoinEcsInstallation,
|
|
62
|
+
besoinEcsDepensierInstallation
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Return true si l'installation est individuelle
|
|
69
|
+
* @param installationEcsDE {InstallationEcsDE}
|
|
70
|
+
*/
|
|
71
|
+
isInstallationIndividuelle(installationEcsDE) {
|
|
72
|
+
return parseInt(installationEcsDE.enum_type_installation_id) === 1;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Return le besoin rationalisé de l'installation par rapport au besoin glbal du logement
|
|
77
|
+
*
|
|
78
|
+
* @param ctx {Contexte}
|
|
79
|
+
* @param installationEcs {InstallationEcs}
|
|
80
|
+
* @param besoinEcs {{besoin_ecs: number, besoin_ecs_depensier: number}} besoin ECS total du logement
|
|
81
|
+
*
|
|
82
|
+
* @returns {{besoinEcsInstallation: number, besoinEcsDepensierInstallation: number}}
|
|
83
|
+
*/
|
|
84
|
+
besoinEcsInstallation(ctx, installationEcs, besoinEcs) {
|
|
85
|
+
/** @type {InstallationEcsDE} */
|
|
86
|
+
const installationEcsDE = installationEcs.donnee_entree;
|
|
87
|
+
|
|
88
|
+
let besoinEcsInstallation;
|
|
89
|
+
let besoinEcsDepensierInstallation;
|
|
90
|
+
|
|
91
|
+
const ratio =
|
|
92
|
+
(installationEcsDE.surface_habitable || ctx.surfaceHabitable) / ctx.surfaceHabitable;
|
|
93
|
+
besoinEcsInstallation = besoinEcs.besoin_ecs * ratio;
|
|
94
|
+
besoinEcsDepensierInstallation = besoinEcs.besoin_ecs_depensier * ratio;
|
|
95
|
+
|
|
96
|
+
return { besoinEcsInstallation, besoinEcsDepensierInstallation };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Pertes de distribution et stockage ECS au niveau de l'installation
|
|
101
|
+
* 15.2.3 - Consommation des auxiliaires de distribution d’ECS
|
|
102
|
+
*
|
|
103
|
+
* QdwIndVc: pertes de la distribution individuelle en volume chauffé pour le mois j (Wh)
|
|
104
|
+
* QdwColVc: pertes de la distribution collective en volume chauffé pour le mois j (Wh)
|
|
105
|
+
* QdwColHVc: pertes de la distribution collective hors volume chauffé pour le mois j (Wh)
|
|
106
|
+
*
|
|
107
|
+
* 11.6.1 - Pertes de stockage des ballons d’accumulation
|
|
108
|
+
* 11.6.2 - Pertes des ballons électriques
|
|
109
|
+
* Qgw: pertes brutes annuelles de stockage (Wh)
|
|
110
|
+
*
|
|
111
|
+
* @param installationEcs {InstallationEcs}
|
|
112
|
+
* @param besoinEcsInstallation {number}
|
|
113
|
+
* @param besoinEcsDepensierInstallation {number}
|
|
114
|
+
*/
|
|
115
|
+
pertesDistributionStockageEcsInstallation(
|
|
116
|
+
installationEcs,
|
|
117
|
+
besoinEcsInstallation,
|
|
118
|
+
besoinEcsDepensierInstallation
|
|
119
|
+
) {
|
|
120
|
+
/** @type {InstallationEcsDE}*/
|
|
121
|
+
const installationEcsDE = installationEcs.donnee_entree;
|
|
122
|
+
const installationIndividuelle = this.isInstallationIndividuelle(installationEcsDE);
|
|
123
|
+
|
|
124
|
+
installationEcs.donnee_utilisateur = {
|
|
125
|
+
QdwIndVc: {
|
|
126
|
+
conventionnel: 0.1 * besoinEcsInstallation,
|
|
127
|
+
depensier: 0.1 * besoinEcsDepensierInstallation
|
|
128
|
+
},
|
|
129
|
+
QdwColVc: {
|
|
130
|
+
conventionnel: installationIndividuelle ? 0 : 0.112 * besoinEcsInstallation,
|
|
131
|
+
depensier: installationIndividuelle ? 0 : 0.112 * besoinEcsDepensierInstallation
|
|
132
|
+
},
|
|
133
|
+
QdwColHVc: {
|
|
134
|
+
conventionnel: installationIndividuelle ? 0 : 0.028 * besoinEcsInstallation,
|
|
135
|
+
depensier: installationIndividuelle ? 0 : 0.028 * besoinEcsDepensierInstallation
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// 17.2.1.1 Calcul des consommations de chauffage, de refroidissement, d’ECS et d’auxiliaires
|
|
140
|
+
// Pour les installations ECS collectives, pas de récupération de stockage d'ECS
|
|
141
|
+
installationEcs.donnee_utilisateur.QgwRecuperable = 0;
|
|
142
|
+
if (installationIndividuelle) {
|
|
143
|
+
installationEcs.donnee_utilisateur.QgwRecuperable =
|
|
144
|
+
installationEcs.generateur_ecs_collection?.generateur_ecs
|
|
145
|
+
.filter(
|
|
146
|
+
(generateurEcs) =>
|
|
147
|
+
parseInt(generateurEcs.donnee_entree.position_volume_chauffe_stockage) === 1 ||
|
|
148
|
+
(generateurEcs.donnee_entree.position_volume_chauffe_stockage === undefined &&
|
|
149
|
+
parseInt(generateurEcs.donnee_entree.position_volume_chauffe) === 1)
|
|
150
|
+
)
|
|
151
|
+
.reduce((acc, generateurEcs) => {
|
|
152
|
+
return acc + generateurEcs.donnee_utilisateur.Qgw;
|
|
153
|
+
}, 0);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, test } from 'vitest';
|
|
2
|
+
import { GenerateurEcsService } from './generateur-ecs.service.js';
|
|
3
|
+
import { InstallationEcsService } from './installation-ecs.service.js';
|
|
4
|
+
import corpus from '../../../../../test/corpus-sano.json';
|
|
5
|
+
import { expect_or, getAdemeFileJson } from '../../../../../test/test-helpers.js';
|
|
6
|
+
import { DpeNormalizerService } from '../../../normalizer/domain/dpe-normalizer.service.js';
|
|
7
|
+
import { ContexteBuilder } from '../contexte.builder.js';
|
|
8
|
+
|
|
9
|
+
/** @type {InstallationEcsService} **/
|
|
10
|
+
let service;
|
|
11
|
+
|
|
12
|
+
/** @type {GenerateurEcsService} **/
|
|
13
|
+
let generateurEcsService;
|
|
14
|
+
|
|
15
|
+
/** @type {DpeNormalizerService} **/
|
|
16
|
+
let normalizerService;
|
|
17
|
+
|
|
18
|
+
/** @type {ContexteBuilder} **/
|
|
19
|
+
let contexteBuilder;
|
|
20
|
+
|
|
21
|
+
describe('Calcul des besoins et des pertes des installations ECS', () => {
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
generateurEcsService = new GenerateurEcsService();
|
|
24
|
+
service = new InstallationEcsService(generateurEcsService);
|
|
25
|
+
normalizerService = new DpeNormalizerService();
|
|
26
|
+
contexteBuilder = new ContexteBuilder();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test.each([
|
|
30
|
+
{
|
|
31
|
+
label: "Installation ECS sans surface habitable pour l'installation",
|
|
32
|
+
surfaceHabitableLogement: 40,
|
|
33
|
+
besoin_ecs: 850,
|
|
34
|
+
besoin_ecs_depensier: 1050,
|
|
35
|
+
expected: { besoinEcsDepensierInstallation: 1050, besoinEcsInstallation: 850 }
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
label: "Installation ECS avec surface habitable pour l'installation",
|
|
39
|
+
surfaceHabitableLogement: 40,
|
|
40
|
+
surfaceHabitableInstallation: 50,
|
|
41
|
+
besoin_ecs: 850,
|
|
42
|
+
besoin_ecs_depensier: 1050,
|
|
43
|
+
expected: { besoinEcsDepensierInstallation: 1312.5, besoinEcsInstallation: 1062.5 }
|
|
44
|
+
}
|
|
45
|
+
])(
|
|
46
|
+
'Calcul des besoins proratisés pour $label',
|
|
47
|
+
({
|
|
48
|
+
surfaceHabitableLogement,
|
|
49
|
+
surfaceHabitableInstallation = undefined,
|
|
50
|
+
besoin_ecs,
|
|
51
|
+
besoin_ecs_depensier,
|
|
52
|
+
expected
|
|
53
|
+
}) => {
|
|
54
|
+
/** @type {Contexte} */
|
|
55
|
+
const ctx = { surfaceHabitable: surfaceHabitableLogement };
|
|
56
|
+
|
|
57
|
+
/** @type {{besoin_ecs: number, besoin_ecs_depensier: number}} */
|
|
58
|
+
const besoinEcs = { besoin_ecs, besoin_ecs_depensier };
|
|
59
|
+
|
|
60
|
+
/** @type {InstallationEcs} */
|
|
61
|
+
const installationEcs = {
|
|
62
|
+
donnee_entree: { surface_habitable: surfaceHabitableInstallation }
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const besoinEcsInstallation = service.besoinEcsInstallation(ctx, installationEcs, besoinEcs);
|
|
66
|
+
|
|
67
|
+
expect(besoinEcsInstallation).toStrictEqual(expected);
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
test.each([
|
|
72
|
+
{
|
|
73
|
+
label: 'Installation individuelle avec générateur hors volume chauffé',
|
|
74
|
+
enumTypeInstallationId: 1,
|
|
75
|
+
positionVolumeChauffeStockage1: 0,
|
|
76
|
+
positionVolumeChauffeStockage2: 0,
|
|
77
|
+
positionVolumeChauffeStockage3: 0,
|
|
78
|
+
expected: {
|
|
79
|
+
QdwIndVc: { conventionnel: 15, depensier: 27 },
|
|
80
|
+
QdwColVc: { conventionnel: 0, depensier: 0 },
|
|
81
|
+
QdwColHVc: { conventionnel: 0, depensier: 0 },
|
|
82
|
+
QgwRecuperable: 0
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
label: 'Installation individuelle avec générateur hors volume chauffé',
|
|
87
|
+
enumTypeInstallationId: 1,
|
|
88
|
+
positionVolumeChauffeStockage2: 0,
|
|
89
|
+
positionVolumeChauffe2: 0,
|
|
90
|
+
positionVolumeChauffeStockage3: 0,
|
|
91
|
+
expected: {
|
|
92
|
+
QdwIndVc: { conventionnel: 15, depensier: 27 },
|
|
93
|
+
QdwColVc: { conventionnel: 0, depensier: 0 },
|
|
94
|
+
QdwColHVc: { conventionnel: 0, depensier: 0 },
|
|
95
|
+
QgwRecuperable: 0
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
label: 'Installation individuelle avec 1 générateur en volume chauffé',
|
|
100
|
+
enumTypeInstallationId: 1,
|
|
101
|
+
positionVolumeChauffeStockage1: 0,
|
|
102
|
+
positionVolumeChauffeStockage2: 1,
|
|
103
|
+
positionVolumeChauffeStockage3: 0,
|
|
104
|
+
expected: {
|
|
105
|
+
QdwIndVc: { conventionnel: 15, depensier: 27 },
|
|
106
|
+
QdwColVc: { conventionnel: 0, depensier: 0 },
|
|
107
|
+
QdwColHVc: { conventionnel: 0, depensier: 0 },
|
|
108
|
+
QgwRecuperable: 120
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
label: 'Installation individuelle avec 1 générateur en volume chauffé',
|
|
113
|
+
enumTypeInstallationId: 1,
|
|
114
|
+
positionVolumeChauffeStockage1: 0,
|
|
115
|
+
positionVolumeChauffe2: 1,
|
|
116
|
+
positionVolumeChauffeStockage3: 0,
|
|
117
|
+
expected: {
|
|
118
|
+
QdwIndVc: { conventionnel: 15, depensier: 27 },
|
|
119
|
+
QdwColVc: { conventionnel: 0, depensier: 0 },
|
|
120
|
+
QdwColHVc: { conventionnel: 0, depensier: 0 },
|
|
121
|
+
QgwRecuperable: 120
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
label: 'Installation individuelle avec 2 générateurs en volume chauffé',
|
|
126
|
+
enumTypeInstallationId: 1,
|
|
127
|
+
positionVolumeChauffeStockage1: 0,
|
|
128
|
+
positionVolumeChauffeStockage2: 1,
|
|
129
|
+
positionVolumeChauffeStockage3: 1,
|
|
130
|
+
expected: {
|
|
131
|
+
QdwIndVc: { conventionnel: 15, depensier: 27 },
|
|
132
|
+
QdwColVc: { conventionnel: 0, depensier: 0 },
|
|
133
|
+
QdwColHVc: { conventionnel: 0, depensier: 0 },
|
|
134
|
+
QgwRecuperable: 260
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
label: 'Installation collective avec générateur hors volume chauffé',
|
|
139
|
+
enumTypeInstallationId: 2,
|
|
140
|
+
positionVolumeChauffeStockage1: 0,
|
|
141
|
+
positionVolumeChauffeStockage2: 0,
|
|
142
|
+
positionVolumeChauffeStockage3: 0,
|
|
143
|
+
expected: {
|
|
144
|
+
QdwIndVc: { conventionnel: 15, depensier: 27 },
|
|
145
|
+
QdwColVc: { conventionnel: 16.8, depensier: 30.24 },
|
|
146
|
+
QdwColHVc: { conventionnel: 4.2, depensier: 7.56 },
|
|
147
|
+
QgwRecuperable: 0
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
label: 'Installation collective avec 1 générateur en volume chauffé',
|
|
152
|
+
enumTypeInstallationId: 2,
|
|
153
|
+
positionVolumeChauffeStockage1: 0,
|
|
154
|
+
positionVolumeChauffeStockage2: 0,
|
|
155
|
+
positionVolumeChauffeStockage3: 1,
|
|
156
|
+
expected: {
|
|
157
|
+
QdwIndVc: { conventionnel: 15, depensier: 27 },
|
|
158
|
+
QdwColVc: { conventionnel: 16.8, depensier: 30.24 },
|
|
159
|
+
QdwColHVc: { conventionnel: 4.2, depensier: 7.56 },
|
|
160
|
+
QgwRecuperable: 0
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
label: 'Installation collective avec 2 générateurs en volume chauffé',
|
|
165
|
+
enumTypeInstallationId: 2,
|
|
166
|
+
positionVolumeChauffeStockage1: 1,
|
|
167
|
+
positionVolumeChauffeStockage2: 1,
|
|
168
|
+
positionVolumeChauffeStockage3: 0,
|
|
169
|
+
expected: {
|
|
170
|
+
QdwIndVc: { conventionnel: 15, depensier: 27 },
|
|
171
|
+
QdwColVc: { conventionnel: 16.8, depensier: 30.24 },
|
|
172
|
+
QdwColHVc: { conventionnel: 4.2, depensier: 7.56 },
|
|
173
|
+
QgwRecuperable: 0
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
])(
|
|
177
|
+
'Calcul des pertes de distribution et de stockage $label',
|
|
178
|
+
({
|
|
179
|
+
enumTypeInstallationId,
|
|
180
|
+
positionVolumeChauffeStockage1,
|
|
181
|
+
positionVolumeChauffeStockage2,
|
|
182
|
+
positionVolumeChauffe2 = undefined,
|
|
183
|
+
positionVolumeChauffeStockage3,
|
|
184
|
+
expected
|
|
185
|
+
}) => {
|
|
186
|
+
/** @type {InstallationEcs} */
|
|
187
|
+
const installationEcs = {
|
|
188
|
+
donnee_entree: { enum_type_installation_id: enumTypeInstallationId },
|
|
189
|
+
generateur_ecs_collection: {
|
|
190
|
+
generateur_ecs: [
|
|
191
|
+
{
|
|
192
|
+
donnee_entree: { position_volume_chauffe_stockage: positionVolumeChauffeStockage1 },
|
|
193
|
+
donnee_utilisateur: { Qgw: 100 }
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
donnee_entree: {
|
|
197
|
+
position_volume_chauffe_stockage: positionVolumeChauffeStockage2,
|
|
198
|
+
position_volume_chauffe: positionVolumeChauffe2
|
|
199
|
+
},
|
|
200
|
+
donnee_utilisateur: { Qgw: 120 }
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
donnee_entree: { position_volume_chauffe_stockage: positionVolumeChauffeStockage3 },
|
|
204
|
+
donnee_utilisateur: { Qgw: 140 }
|
|
205
|
+
}
|
|
206
|
+
]
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
service.pertesDistributionStockageEcsInstallation(installationEcs, 150, 270);
|
|
211
|
+
|
|
212
|
+
expect(installationEcs.donnee_utilisateur.QdwIndVc.conventionnel).toBeCloseTo(
|
|
213
|
+
expected.QdwIndVc.conventionnel,
|
|
214
|
+
5
|
|
215
|
+
);
|
|
216
|
+
expect(installationEcs.donnee_utilisateur.QdwIndVc.depensier).toBeCloseTo(
|
|
217
|
+
expected.QdwIndVc.depensier,
|
|
218
|
+
5
|
|
219
|
+
);
|
|
220
|
+
expect(installationEcs.donnee_utilisateur.QdwColVc.conventionnel).toBeCloseTo(
|
|
221
|
+
expected.QdwColVc.conventionnel,
|
|
222
|
+
5
|
|
223
|
+
);
|
|
224
|
+
expect(installationEcs.donnee_utilisateur.QdwColVc.depensier).toBeCloseTo(
|
|
225
|
+
expected.QdwColVc.depensier,
|
|
226
|
+
5
|
|
227
|
+
);
|
|
228
|
+
expect(installationEcs.donnee_utilisateur.QdwColHVc.conventionnel).toBeCloseTo(
|
|
229
|
+
expected.QdwColHVc.conventionnel,
|
|
230
|
+
5
|
|
231
|
+
);
|
|
232
|
+
expect(installationEcs.donnee_utilisateur.QdwColHVc.depensier).toBeCloseTo(
|
|
233
|
+
expected.QdwColHVc.depensier,
|
|
234
|
+
5
|
|
235
|
+
);
|
|
236
|
+
expect(installationEcs.donnee_utilisateur.QgwRecuperable).toBeCloseTo(
|
|
237
|
+
expected.QgwRecuperable,
|
|
238
|
+
5
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
test("Determination du caractère individuelle de l'installation", () => {
|
|
244
|
+
expect(service.isInstallationIndividuelle({ enum_type_installation_id: 1 })).toBeTruthy();
|
|
245
|
+
expect(service.isInstallationIndividuelle({ enum_type_installation_id: 2 })).toBeFalsy();
|
|
246
|
+
expect(service.isInstallationIndividuelle({ enum_type_installation_id: 3 })).toBeFalsy();
|
|
247
|
+
expect(service.isInstallationIndividuelle({ enum_type_installation_id: 4 })).toBeFalsy();
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
describe("Test d'intégration des installations ECS", () => {
|
|
251
|
+
test.each(corpus)('vérification des DI des installations ECS pour dpe %s', (ademeId) => {
|
|
252
|
+
let dpeRequest = getAdemeFileJson(ademeId);
|
|
253
|
+
dpeRequest = normalizerService.normalize(dpeRequest);
|
|
254
|
+
|
|
255
|
+
/** @type {Contexte} */
|
|
256
|
+
const ctx = contexteBuilder.fromDpe(dpeRequest);
|
|
257
|
+
|
|
258
|
+
const installationsECS = structuredClone(
|
|
259
|
+
dpeRequest.logement.installation_ecs_collection?.installation_ecs || []
|
|
260
|
+
);
|
|
261
|
+
service.execute(ctx, dpeRequest.logement, {
|
|
262
|
+
besoin_ecs: dpeRequest.logement.sortie.apport_et_besoin.besoin_ecs,
|
|
263
|
+
besoin_ecs_depensier: dpeRequest.logement.sortie.apport_et_besoin.besoin_ecs_depensier
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
installationsECS.forEach((installationECS, i) => {
|
|
267
|
+
expect_or(
|
|
268
|
+
() =>
|
|
269
|
+
expect(installationECS.donnee_intermediaire.besoin_ecs).toBeCloseTo(
|
|
270
|
+
dpeRequest.logement.installation_ecs_collection.installation_ecs[i]
|
|
271
|
+
.donnee_intermediaire.besoin_ecs,
|
|
272
|
+
2
|
|
273
|
+
),
|
|
274
|
+
() =>
|
|
275
|
+
expect(installationECS.donnee_intermediaire.besoin_ecs).toBeCloseTo(
|
|
276
|
+
dpeRequest.logement.installation_ecs_collection.installation_ecs[i]
|
|
277
|
+
.donnee_intermediaire.besoin_ecs * 1000,
|
|
278
|
+
2
|
|
279
|
+
)
|
|
280
|
+
);
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
});
|