@golemio/energetics 1.13.1-dev.2791580222 → 1.13.1-dev.2809036872
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/db/migrations/postgresql/20260827090000-enapo-gid-mapping-pk.js +53 -0
- package/db/migrations/postgresql/sqls/20260821090000-enapo-gid-mapping-sync-comment-up.sql +1 -1
- package/db/migrations/postgresql/sqls/20260827090000-enapo-gid-mapping-pk-down.sql +4 -0
- package/db/migrations/postgresql/sqls/20260827090000-enapo-gid-mapping-pk-up.sql +17 -0
- package/db/scripts/ded_gid_mapping_mock_import.sql +3 -3
- package/dist/integration-engine/enapo/helpers/EnapoGidMappingNormalizer.d.ts +2 -2
- package/dist/integration-engine/enapo/helpers/EnapoGidMappingNormalizer.js +10 -20
- package/dist/integration-engine/enapo/helpers/EnapoGidMappingNormalizer.js.map +1 -1
- package/dist/integration-engine/enapo/repositories/EnapoGidMappingRepository.d.ts +3 -3
- package/dist/integration-engine/enapo/repositories/EnapoGidMappingRepository.js +3 -3
- package/dist/schema-definitions/models/enapo/EnapoGidMappingModel.js +0 -1
- package/dist/schema-definitions/models/enapo/EnapoGidMappingModel.js.map +1 -1
- package/docs/implementation_documentation.md +6 -6
- package/package.json +1 -1
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var dbm;
|
|
4
|
+
var type;
|
|
5
|
+
var seed;
|
|
6
|
+
var fs = require('fs');
|
|
7
|
+
var path = require('path');
|
|
8
|
+
var Promise;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* We receive the dbmigrate dependency from dbmigrate initially.
|
|
12
|
+
* This enables us to not have to rely on NODE_PATH.
|
|
13
|
+
*/
|
|
14
|
+
exports.setup = function(options, seedLink) {
|
|
15
|
+
dbm = options.dbmigrate;
|
|
16
|
+
type = dbm.dataType;
|
|
17
|
+
seed = seedLink;
|
|
18
|
+
Promise = options.Promise;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
exports.up = function(db) {
|
|
22
|
+
var filePath = path.join(__dirname, 'sqls', '20260827090000-enapo-gid-mapping-pk-up.sql');
|
|
23
|
+
return new Promise( function( resolve, reject ) {
|
|
24
|
+
fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){
|
|
25
|
+
if (err) return reject(err);
|
|
26
|
+
console.log('received data: ' + data);
|
|
27
|
+
|
|
28
|
+
resolve(data);
|
|
29
|
+
});
|
|
30
|
+
})
|
|
31
|
+
.then(function(data) {
|
|
32
|
+
return db.runSql(data);
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
exports.down = function(db) {
|
|
37
|
+
var filePath = path.join(__dirname, 'sqls', '20260827090000-enapo-gid-mapping-pk-down.sql');
|
|
38
|
+
return new Promise( function( resolve, reject ) {
|
|
39
|
+
fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){
|
|
40
|
+
if (err) return reject(err);
|
|
41
|
+
console.log('received data: ' + data);
|
|
42
|
+
|
|
43
|
+
resolve(data);
|
|
44
|
+
});
|
|
45
|
+
})
|
|
46
|
+
.then(function(data) {
|
|
47
|
+
return db.runSql(data);
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
exports._meta = {
|
|
52
|
+
"version": 1
|
|
53
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
-- The mapping table is no longer mock-only: EnapoGidMappingSyncTask fills it daily from the
|
|
2
2
|
-- ded_gid_mapping CSV export. Only the table comment changes, no data or structure is touched.
|
|
3
3
|
|
|
4
|
-
COMMENT ON TABLE enapo_gid_mapping IS 'Mapping of consumption points (EAN/EIC) to ENO building GIDs. Module-owned contract, filled daily by EnapoGidMappingSyncTask from the ded_gid_mapping CSV export (link_source = ''
|
|
4
|
+
COMMENT ON TABLE enapo_gid_mapping IS 'Mapping of consumption points (EAN/EIC) to ENO building GIDs. Module-owned contract, filled daily by EnapoGidMappingSyncTask from the ded_gid_mapping CSV export (every synced row gets link_source = ''manual_entry''); electricity and gas only, water/heat (''eb_cis_odb_mista'') is out of scope. Upsert-only keyed on (place_id, gid): nothing is ever deleted, so a mapping missing from a later export stays. A synced row overwrites a manual mock row (link_source = ''mock'') for the same (place_id, gid).';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
-- Restores the original three-column primary key. Rows collapsed by the up migration are not restored
|
|
2
|
+
-- (the data is gone); this only rebuilds the constraint shape.
|
|
3
|
+
ALTER TABLE enapo_gid_mapping DROP CONSTRAINT enapo_gid_mapping_pk;
|
|
4
|
+
ALTER TABLE enapo_gid_mapping ADD CONSTRAINT enapo_gid_mapping_pk PRIMARY KEY (place_id, gid, link_source);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
-- Drops link_source from the enapo_gid_mapping primary key. A consumption point (place_id) maps to a
|
|
2
|
+
-- building (gid) regardless of which source produced the link, so (place_id, gid) is the real identity.
|
|
3
|
+
-- The CSV sync now stores a single link_source ('manual_entry'), so several source rows for one
|
|
4
|
+
-- (place_id, gid) collapse to a single row that would otherwise violate the old three-column key.
|
|
5
|
+
|
|
6
|
+
-- Collapse rows that become duplicate under the new key before the constraint is added, so ADD
|
|
7
|
+
-- CONSTRAINT cannot fail on existing data. Per (place_id, gid) keep an active mapping (valid_to IS NULL)
|
|
8
|
+
-- and then the newest valid_from, matching EnapoGidMappingNormalizer.isPreferred.
|
|
9
|
+
DELETE FROM enapo_gid_mapping t
|
|
10
|
+
WHERE t.ctid NOT IN (
|
|
11
|
+
SELECT DISTINCT ON (place_id, gid) ctid
|
|
12
|
+
FROM enapo_gid_mapping
|
|
13
|
+
ORDER BY place_id, gid, (valid_to IS NULL) DESC, valid_from DESC NULLS LAST, ctid
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
ALTER TABLE enapo_gid_mapping DROP CONSTRAINT enapo_gid_mapping_pk;
|
|
17
|
+
ALTER TABLE enapo_gid_mapping ADD CONSTRAINT enapo_gid_mapping_pk PRIMARY KEY (place_id, gid);
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
-- script can be re-run any time and never touches future non-mock (sync task) rows.
|
|
11
11
|
-- - The dbt table has no primary key; DISTINCT ON collapses duplicates per (place_id, gid),
|
|
12
12
|
-- preferring an active mapping (valid_to IS NULL) and then the newest valid_from. This script
|
|
13
|
-
-- writes
|
|
14
|
-
-- (
|
|
15
|
-
--
|
|
13
|
+
-- writes link_source = 'mock'; the sync task (EnapoGidMappingSyncTask) writes link_source =
|
|
14
|
+
-- 'manual_entry'. Both deduplicate on (place_id, gid) — the table primary key — so a synced row
|
|
15
|
+
-- and a mock row for the same point collapse to one (the sync run wins, being the later upsert).
|
|
16
16
|
-- - id_type / commodity are resolved from each other so a row survives when only one of the
|
|
17
17
|
-- two columns is filled: an explicit value wins, the other column is the fallback.
|
|
18
18
|
-- commodity uses EB codes ('1' -> electricity, '2' -> gas) as well as the DeD names.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { IEnapoGidMappingCsvRow } from "../../../schema-definitions/datasources/enapo/gid-mapping/interfaces/IEnapoGidMappingCsvRow";
|
|
2
2
|
import { IEnapoGidMapping } from "../../../schema-definitions/models/enapo/interfaces/IEnapoGidMapping";
|
|
3
|
-
type EnapoGidMappingSkipReason = "missing_required" | "place_id_too_long" | "
|
|
3
|
+
type EnapoGidMappingSkipReason = "missing_required" | "place_id_too_long" | "invalid_date" | "contradicting_pair" | "unresolvable_commodity";
|
|
4
4
|
export interface IEnapoGidMappingSkipReport {
|
|
5
5
|
total: number;
|
|
6
6
|
byReason: Record<EnapoGidMappingSkipReason, number>;
|
|
@@ -18,7 +18,7 @@ interface IEnapoGidMappingNormalizeResult {
|
|
|
18
18
|
export declare class EnapoGidMappingNormalizer {
|
|
19
19
|
private static readonly EB_PLACEHOLDER_DATE;
|
|
20
20
|
private static readonly MAX_PLACE_ID_LENGTH;
|
|
21
|
-
private static readonly
|
|
21
|
+
private static readonly LINK_SOURCE;
|
|
22
22
|
private static readonly ISO_DATE_PATTERN;
|
|
23
23
|
private static readonly EXCLUDED_LINK_SOURCE;
|
|
24
24
|
private static readonly ELECTRICITY_CODES;
|
|
@@ -27,7 +27,7 @@ let EnapoGidMappingNormalizer = EnapoGidMappingNormalizer_1 = class EnapoGidMapp
|
|
|
27
27
|
if (!mapping) {
|
|
28
28
|
continue;
|
|
29
29
|
}
|
|
30
|
-
const key = `${mapping.place_id}|${mapping.gid}
|
|
30
|
+
const key = `${mapping.place_id}|${mapping.gid}`;
|
|
31
31
|
const current = byKey.get(key);
|
|
32
32
|
if (!current || this.isPreferred(mapping, current)) {
|
|
33
33
|
byKey.set(key, mapping);
|
|
@@ -45,17 +45,12 @@ let EnapoGidMappingNormalizer = EnapoGidMappingNormalizer_1 = class EnapoGidMapp
|
|
|
45
45
|
normalizeRow(row, skipped) {
|
|
46
46
|
const placeId = (row.place_id ?? "").trim();
|
|
47
47
|
const gid = (row.gid ?? "").trim();
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if (!placeId || !gid || !linkSource) {
|
|
51
|
-
return this.skip(skipped, "missing_required", this.describeMissing(placeId, gid, linkSource));
|
|
48
|
+
if (!placeId || !gid) {
|
|
49
|
+
return this.skip(skipped, "missing_required", this.describeMissing(placeId, gid));
|
|
52
50
|
}
|
|
53
51
|
if (placeId.length > EnapoGidMappingNormalizer_1.MAX_PLACE_ID_LENGTH) {
|
|
54
52
|
return this.skip(skipped, "place_id_too_long", placeId);
|
|
55
53
|
}
|
|
56
|
-
if (linkSource.length > EnapoGidMappingNormalizer_1.MAX_LINK_SOURCE_LENGTH) {
|
|
57
|
-
return this.skip(skipped, "link_source_too_long", linkSource);
|
|
58
|
-
}
|
|
59
54
|
const idTypeRaw = (row.id_type ?? "").trim().toLowerCase();
|
|
60
55
|
const commodityRaw = (row.commodity ?? "").trim().toLowerCase();
|
|
61
56
|
const idType = this.resolveIdType(idTypeRaw, commodityRaw);
|
|
@@ -78,13 +73,13 @@ let EnapoGidMappingNormalizer = EnapoGidMappingNormalizer_1 = class EnapoGidMapp
|
|
|
78
73
|
commodity,
|
|
79
74
|
gid,
|
|
80
75
|
is_first_gid: EnapoGidMappingNormalizer_1.TRUE_VALUES.includes((row.is_first_gid ?? "").trim().toLowerCase()),
|
|
81
|
-
link_source:
|
|
76
|
+
link_source: EnapoGidMappingNormalizer_1.LINK_SOURCE,
|
|
82
77
|
valid_from: validFrom.value,
|
|
83
78
|
valid_to: validTo.value === EnapoGidMappingNormalizer_1.EB_PLACEHOLDER_DATE ? null : validTo.value,
|
|
84
79
|
};
|
|
85
80
|
}
|
|
86
81
|
// Names the missing columns and keeps whatever identifier the row still has, so the logged sample says what is wrong.
|
|
87
|
-
describeMissing(placeId, gid
|
|
82
|
+
describeMissing(placeId, gid) {
|
|
88
83
|
const missing = [];
|
|
89
84
|
if (!placeId) {
|
|
90
85
|
missing.push("place_id");
|
|
@@ -92,14 +87,7 @@ let EnapoGidMappingNormalizer = EnapoGidMappingNormalizer_1 = class EnapoGidMapp
|
|
|
92
87
|
if (!gid) {
|
|
93
88
|
missing.push("gid");
|
|
94
89
|
}
|
|
95
|
-
|
|
96
|
-
missing.push("link_source");
|
|
97
|
-
}
|
|
98
|
-
const present = [
|
|
99
|
-
placeId ? `place_id=${placeId}` : null,
|
|
100
|
-
gid ? `gid=${gid}` : null,
|
|
101
|
-
linkSource ? `link_source=${linkSource}` : null,
|
|
102
|
-
].filter((part) => part !== null);
|
|
90
|
+
const present = [placeId ? `place_id=${placeId}` : null, gid ? `gid=${gid}` : null].filter((part) => part !== null);
|
|
103
91
|
return `missing ${missing.join("+")}${present.length > 0 ? ` (${present.join(", ")})` : ""}`;
|
|
104
92
|
}
|
|
105
93
|
emptyReport() {
|
|
@@ -180,7 +168,10 @@ let EnapoGidMappingNormalizer = EnapoGidMappingNormalizer_1 = class EnapoGidMapp
|
|
|
180
168
|
exports.EnapoGidMappingNormalizer = EnapoGidMappingNormalizer;
|
|
181
169
|
EnapoGidMappingNormalizer.EB_PLACEHOLDER_DATE = "1900-01-01";
|
|
182
170
|
EnapoGidMappingNormalizer.MAX_PLACE_ID_LENGTH = 50;
|
|
183
|
-
|
|
171
|
+
// link_source is not part of the primary key anymore and the CSV value is not stored: every synced
|
|
172
|
+
// mapping is written with a single fixed link_source, so downstream can tell sync rows from the
|
|
173
|
+
// manual mock import (link_source = "mock") and from the Porsenna view branch (link_source = "porsenna").
|
|
174
|
+
EnapoGidMappingNormalizer.LINK_SOURCE = "manual_entry";
|
|
184
175
|
EnapoGidMappingNormalizer.ISO_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
|
|
185
176
|
// Water/heat mapping, out of scope until the source codes are cleaned up (separate issue).
|
|
186
177
|
EnapoGidMappingNormalizer.EXCLUDED_LINK_SOURCE = "eb_cis_odb_mista";
|
|
@@ -192,7 +183,6 @@ EnapoGidMappingNormalizer.MAX_SAMPLES_PER_REASON = 5;
|
|
|
192
183
|
EnapoGidMappingNormalizer.SKIP_REASONS = [
|
|
193
184
|
"missing_required",
|
|
194
185
|
"place_id_too_long",
|
|
195
|
-
"link_source_too_long",
|
|
196
186
|
"invalid_date",
|
|
197
187
|
"contradicting_pair",
|
|
198
188
|
"unresolvable_commodity",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EnapoGidMappingNormalizer.js","sourceRoot":"","sources":["../../../../src/integration-engine/enapo/helpers/EnapoGidMappingNormalizer.ts"],"names":[],"mappings":";;;;;;;;;;AAEA,iEAAgE;
|
|
1
|
+
{"version":3,"file":"EnapoGidMappingNormalizer.js","sourceRoot":"","sources":["../../../../src/integration-engine/enapo/helpers/EnapoGidMappingNormalizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,9 +2,9 @@ import { IModel } from "@golemio/core/dist/integration-engine/models/IModel";
|
|
|
2
2
|
import { PostgresModel } from "@golemio/core/dist/integration-engine/models/PostgresModel";
|
|
3
3
|
/**
|
|
4
4
|
* Writes the ded_gid_mapping rows into energetics.enapo_gid_mapping. Uses insertOrUpdate so a run only
|
|
5
|
-
* ever inserts new mappings or updates existing ones (keyed on place_id + gid
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* ever inserts new mappings or updates existing ones (keyed on place_id + gid) and never deletes: a
|
|
6
|
+
* mapping that disappears from a later export stays in the table, and re-running over the same input is
|
|
7
|
+
* idempotent.
|
|
8
8
|
*/
|
|
9
9
|
export declare class EnapoGidMappingRepository extends PostgresModel implements IModel {
|
|
10
10
|
static REPOSITORY_NAME: string;
|
|
@@ -18,9 +18,9 @@ const golemio_validator_1 = require("@golemio/core/dist/shared/golemio-validator
|
|
|
18
18
|
const tsyringe_1 = require("@golemio/core/dist/shared/tsyringe");
|
|
19
19
|
/**
|
|
20
20
|
* Writes the ded_gid_mapping rows into energetics.enapo_gid_mapping. Uses insertOrUpdate so a run only
|
|
21
|
-
* ever inserts new mappings or updates existing ones (keyed on place_id + gid
|
|
22
|
-
*
|
|
23
|
-
*
|
|
21
|
+
* ever inserts new mappings or updates existing ones (keyed on place_id + gid) and never deletes: a
|
|
22
|
+
* mapping that disappears from a later export stays in the table, and re-running over the same input is
|
|
23
|
+
* idempotent.
|
|
24
24
|
*/
|
|
25
25
|
let EnapoGidMappingRepository = EnapoGidMappingRepository_1 = class EnapoGidMappingRepository extends PostgresModel_1.PostgresModel {
|
|
26
26
|
constructor() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EnapoGidMappingModel.js","sourceRoot":"","sources":["../../../../src/schema-definitions/models/enapo/EnapoGidMappingModel.ts"],"names":[],"mappings":";;;AACA,mEAAwF;AAGxF,MAAa,oBAAqB,SAAQ,iBAAuB;;AAAjE,
|
|
1
|
+
{"version":3,"file":"EnapoGidMappingModel.js","sourceRoot":"","sources":["../../../../src/schema-definitions/models/enapo/EnapoGidMappingModel.ts"],"names":[],"mappings":";;;AACA,mEAAwF;AAGxF,MAAa,oBAAqB,SAAQ,iBAAuB;;AAAjE,oDAkEC;AAjEiB,+BAAU,GAAG,mBAAmB,CAAC;AACjC,oCAAe,GAAG,2BAA2B,CAAC;AAW9C,mCAAc,GAA4D;IACpF,QAAQ,EAAE;QACN,IAAI,EAAE,qBAAS,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,SAAS,EAAE,KAAK;QAChB,UAAU,EAAE,IAAI;KACnB;IACD,OAAO,EAAE;QACL,IAAI,EAAE,qBAAS,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,SAAS,EAAE,KAAK;KACnB;IACD,SAAS,EAAE;QACP,IAAI,EAAE,qBAAS,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,SAAS,EAAE,KAAK;KACnB;IACD,GAAG,EAAE;QACD,IAAI,EAAE,qBAAS,CAAC,MAAM;QACtB,SAAS,EAAE,KAAK;QAChB,UAAU,EAAE,IAAI;KACnB;IACD,YAAY,EAAE;QACV,IAAI,EAAE,qBAAS,CAAC,OAAO;QACvB,SAAS,EAAE,KAAK;QAChB,YAAY,EAAE,KAAK;KACtB;IACD,WAAW,EAAE;QACT,IAAI,EAAE,qBAAS,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,SAAS,EAAE,KAAK;KACnB;IACD,UAAU,EAAE;QACR,IAAI,EAAE,qBAAS,CAAC,QAAQ;KAC3B;IACD,QAAQ,EAAE;QACN,IAAI,EAAE,qBAAS,CAAC,QAAQ;KAC3B;CACJ,CAAC;AAEY,+BAAU,GAAuC;IAC3D,IAAI,EAAE,OAAO;IACb,KAAK,EAAE;QACH,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACR,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC5B,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE;YACjD,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;YAC5E,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACvB,YAAY,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;YACjC,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC/B,UAAU,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE;YAC7E,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE;SAC9E;QACD,QAAQ,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,EAAE,cAAc,EAAE,aAAa,CAAC;KACvF;CACJ,CAAC"}
|
|
@@ -710,9 +710,9 @@ Task denně synchronizuje mapování odběrných míst (EAN/EIC) na GID budov z
|
|
|
710
710
|
- CSV dodává datový tým (výstup z dbt), modul ho jen konzumuje; za obsah a denní obnovu odpovídá producent
|
|
711
711
|
- formát: UTF-8, delimiter `,`, hlavička na prvním řádku
|
|
712
712
|
- CSV kontrakt (sloupce = `enapo_gid_mapping` bez vody/tepla)
|
|
713
|
-
- `place_id` (EAN/EIC, ≤ 50 znaků), `id_type` (`ean` = elektřina / `eic` = plyn), `commodity` (`electricity` / `gas`), `gid` (GID budovy/stavby), `is_first_gid` (bool), `link_source` (např. `eb_ean_eic`), `valid_from` a `valid_to` (date `YYYY-MM-DD`, případná časová část se zahazuje; u `valid_to` je `1900-01-01` nebo prázdno = nezrušeno = NULL)
|
|
713
|
+
- `place_id` (EAN/EIC, ≤ 50 znaků), `id_type` (`ean` = elektřina / `eic` = plyn), `commodity` (`electricity` / `gas`), `gid` (GID budovy/stavby), `is_first_gid` (bool), `link_source` (v CSV např. `eb_ean_eic`; slouží už jen k odfiltrování vody/tepla přes `eb_cis_odb_mista`, do tabulky se neukládá), `valid_from` a `valid_to` (date `YYYY-MM-DD`, případná časová část se zahazuje; u `valid_to` je `1900-01-01` nebo prázdno = nezrušeno = NULL)
|
|
714
714
|
- normalizaci a validaci provádí [EnapoGidMappingNormalizer](../src/integration-engine/enapo/helpers/EnapoGidMappingNormalizer.ts) podle [ded_gid_mapping_mock_import.sql](../db/scripts/ded_gid_mapping_mock_import.sql): dopočet `id_type`↔`commodity`, zahození rozporných párů, `1900-01-01`→NULL, výběr aktivního a nejnovějšího mapování mezi duplicitami
|
|
715
|
-
-
|
|
715
|
+
- dedupuje na PK (`place_id`, `gid`) a `link_source` u všech řádků nastavuje na `manual_entry` (hodnota z CSV se neukládá)
|
|
716
716
|
- vstupní rabbitmq fronta
|
|
717
717
|
- název: dataplatform.enapoenergetics.syncEnapoGidMapping
|
|
718
718
|
- TTL: 30 minut (starší zpráva už je překonaná novější)
|
|
@@ -723,10 +723,10 @@ Task denně synchronizuje mapování odběrných míst (EAN/EIC) na GID budov z
|
|
|
723
723
|
- prod `0 15 3 * * *`
|
|
724
724
|
- samotná definice cronu je vedena mimo tento repozitář (deployment konfigurace); hodnoty výše jsou zamýšlený rozvrh
|
|
725
725
|
- data modely
|
|
726
|
-
- [EnapoGidMappingRepository](../src/integration-engine/enapo/repositories/EnapoGidMappingRepository.ts) — `savingType: "insertOrUpdate"` nad `enapo_gid_mapping` (PK `place_id` + `gid`
|
|
726
|
+
- [EnapoGidMappingRepository](../src/integration-engine/enapo/repositories/EnapoGidMappingRepository.ts) — `savingType: "insertOrUpdate"` nad `enapo_gid_mapping` (PK `place_id` + `gid`)
|
|
727
727
|
- funkce
|
|
728
728
|
- **upsert-only, nic se nemaže**: nové mapování se vloží, existující aktualizuje, chybějící v tabulce zůstane. Opakovaný běh nad stejnými vstupy dá stejný výsledek bez duplicit
|
|
729
|
-
- **robustní vůči nečistým datům**: producenta k čistému exportu nedonutíme, takže co task neumí zpracovat, přeskočí a **zaloguje warning** se souhrnem (počet a pár vzorků na každý důvod: `missing_required`, `place_id_too_long`, `
|
|
729
|
+
- **robustní vůči nečistým datům**: producenta k čistému exportu nedonutíme, takže co task neumí zpracovat, přeskočí a **zaloguje warning** se souhrnem (počet a pár vzorků na každý důvod: `missing_required`, `place_id_too_long`, `invalid_date`, `contradicting_pair`, `unresolvable_commodity`). Jeden vadný řádek běh neshodí — délkové a datové limity chrání typované cílové sloupce před hodnotou, která by jinak shodila celou dávku
|
|
730
730
|
- **voda a teplo nejsou chyba, jen mimo rozsah**: filtrují se jako první a pouze se spočítají. Jejich počet jde do `logger.info`, `logger.warn` zůstává vyhrazený pro skutečné defekty, aby velký očekávaný objem nepřehlušil pár reálných anomálií
|
|
731
731
|
- zápis běží v jedné transakci po dávkách 5 000 řádků — jeden `INSERT` nad celým exportem by narazil na limit 65535 bind parametrů Postgresu. Dedup před zápisem je nutný i technicky (`insertOrUpdate` nesmí v jedné dávce zasáhnout stejný PK dvakrát); selhání kterékoli dávky rolluje celý běh
|
|
732
732
|
- join na měření: `enapo_gid_mapping.place_id` je kód EAN/EIC (`enapo_measurements.place_id` je naopak interní PPAS place id — viz [Sémantika `var`](#sémantika-var-v-enapo_measurements-ověřeno-proti-produkci-2026-08-13))
|
|
@@ -1023,8 +1023,8 @@ Přehled endpointů a parametru `accessLimit`:
|
|
|
1023
1023
|
- `v_enapo_building_porsenna_devices` — měřidla Porsenny s budovou (`enapo_porsenna_devices` × `enapo_porsenna_buildings` přes `(source, building_id)`); slouží pro obohacení OM o blok `porsenna` (měřidlo + podružná měřidla) a pro blok `energy_management` na úrovni budovy; spotřeby Porsenny blok nenese — jdou přes `mv_enapo_om_consumption` do `consumption_history` daného OM, kde mají navíc pokrytí a počty přispěvatelů
|
|
1024
1024
|
- `enapo_ppas_distribution_invoice_device` / `_price`, `enapo_ppas_commercial_invoice_device` / `_price` — dotahované podle id faktury a filtrované podle `place_id` instalace (jedna faktura může účtovat více OM, bez filtru by se řádky mísily)
|
|
1025
1025
|
- mapovací tabulka `enapo_gid_mapping`
|
|
1026
|
-
- vlastní kontrakt modulu; plněná denně synchronizačním taskem [EnapoGidMappingSyncTask](#task-enapogidmappingsynctask) z CSV exportu (`link_source = '
|
|
1027
|
-
- mock data (`link_source = 'mock'`) z ruční přípravy zůstávají, dokud je sync
|
|
1026
|
+
- vlastní kontrakt modulu; plněná denně synchronizačním taskem [EnapoGidMappingSyncTask](#task-enapogidmappingsynctask) z CSV exportu (synchronizované řádky mají `link_source = 'manual_entry'`)
|
|
1027
|
+
- PK je (`place_id`, `gid`); mock data (`link_source = 'mock'`) z ruční přípravy zůstávají, dokud je sync nepřepíše — synchronizovaný řádek pro stejné (`place_id`, `gid`) mock řádek přepíše
|
|
1028
1028
|
- sloupec `is_active` v pohledu je odvozený z `valid_to` (NULL nebo v budoucnu = aktivní); expirovaná mapování se vracejí s příznakem
|
|
1029
1029
|
- struktura odpovědi
|
|
1030
1030
|
- komoditně specifická data jsou vnořená pod klíči `electricity` / `gas` u každého OM; v odpovědi je pouze klíč odpovídající poli `commodity`, ostatní jsou zcela vynechány
|