@golemio/energetics 1.13.0 → 1.13.1-dev.2769672204
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/example/07_enapo_om_detail.sql +15 -10
- package/db/example/09_enapo_consumption_history.sql +196 -0
- package/db/migrations/postgresql/20260813090000-enapo-consumption-history.js +53 -0
- package/db/migrations/postgresql/sqls/20260813090000-enapo-consumption-history-down.sql +12 -0
- package/db/migrations/postgresql/sqls/20260813090000-enapo-consumption-history-up.sql +504 -0
- package/dist/integration-engine/enapo/ioc/Di.js +5 -1
- package/dist/integration-engine/enapo/ioc/Di.js.map +1 -1
- package/dist/integration-engine/enapo/ioc/EnapoWorkerContainerToken.d.ts +2 -0
- package/dist/integration-engine/enapo/ioc/EnapoWorkerContainerToken.js +2 -0
- package/dist/integration-engine/enapo/ioc/EnapoWorkerContainerToken.js.map +1 -1
- package/dist/integration-engine/enapo/repositories/AbstractMaterializedViewIndexRepository.d.ts +8 -0
- package/dist/integration-engine/enapo/repositories/AbstractMaterializedViewIndexRepository.js +25 -0
- package/dist/integration-engine/enapo/repositories/AbstractMaterializedViewIndexRepository.js.map +1 -0
- package/dist/integration-engine/enapo/repositories/DedSearchIndexRepository.d.ts +2 -3
- package/dist/integration-engine/enapo/repositories/DedSearchIndexRepository.js +3 -23
- package/dist/integration-engine/enapo/repositories/DedSearchIndexRepository.js.map +1 -1
- package/dist/integration-engine/enapo/repositories/EnapoConsumptionHistoryIndexRepository.d.ts +6 -0
- package/dist/integration-engine/enapo/repositories/EnapoConsumptionHistoryIndexRepository.js +30 -0
- package/dist/integration-engine/enapo/repositories/EnapoConsumptionHistoryIndexRepository.js.map +1 -0
- package/dist/integration-engine/enapo/repositories/interfaces/IEnapoConsumptionHistoryIndexRepository.d.ts +7 -0
- package/dist/integration-engine/enapo/repositories/interfaces/IEnapoConsumptionHistoryIndexRepository.js +3 -0
- package/dist/integration-engine/enapo/repositories/interfaces/IEnapoConsumptionHistoryIndexRepository.js.map +1 -0
- package/dist/integration-engine/enapo/workers/EnapoWorker.js +1 -0
- package/dist/integration-engine/enapo/workers/EnapoWorker.js.map +1 -1
- package/dist/integration-engine/enapo/workers/task/EnapoConsumptionHistoryRefreshTask.d.ts +10 -0
- package/dist/integration-engine/enapo/workers/task/EnapoConsumptionHistoryRefreshTask.js +47 -0
- package/dist/integration-engine/enapo/workers/task/EnapoConsumptionHistoryRefreshTask.js.map +1 -0
- package/dist/output-gateway/constants/ConsumptionHistory.d.ts +2 -0
- package/dist/output-gateway/constants/ConsumptionHistory.js +6 -0
- package/dist/output-gateway/constants/ConsumptionHistory.js.map +1 -0
- package/dist/output-gateway/controllers/v2/EnoBuildingsController.js +3 -3
- package/dist/output-gateway/controllers/v2/EnoBuildingsController.js.map +1 -1
- package/dist/output-gateway/helpers/ConsumptionHistoryWindow.d.ts +12 -0
- package/dist/output-gateway/helpers/ConsumptionHistoryWindow.js +30 -0
- package/dist/output-gateway/helpers/ConsumptionHistoryWindow.js.map +1 -0
- package/dist/output-gateway/models/EnapoOmConsumptionViewModel.d.ts +23 -0
- package/dist/output-gateway/models/EnapoOmConsumptionViewModel.js +48 -0
- package/dist/output-gateway/models/EnapoOmConsumptionViewModel.js.map +1 -0
- package/dist/output-gateway/models/interfaces/IEnapoOmConsumptionView.d.ts +20 -0
- package/dist/output-gateway/models/interfaces/IEnapoOmConsumptionView.js +3 -0
- package/dist/output-gateway/models/interfaces/IEnapoOmConsumptionView.js.map +1 -0
- package/dist/output-gateway/repositories/EnapoOmConsumptionRepository.d.ts +8 -0
- package/dist/output-gateway/repositories/EnapoOmConsumptionRepository.js +59 -0
- package/dist/output-gateway/repositories/EnapoOmConsumptionRepository.js.map +1 -0
- package/dist/output-gateway/repositories/EnoBuildingDetailRepository.d.ts +2 -1
- package/dist/output-gateway/repositories/EnoBuildingDetailRepository.js +13 -3
- package/dist/output-gateway/repositories/EnoBuildingDetailRepository.js.map +1 -1
- package/dist/output-gateway/repositories/EnoConsumptionPointsRepository.d.ts +2 -0
- package/dist/output-gateway/repositories/EnoConsumptionPointsRepository.js +34 -0
- package/dist/output-gateway/repositories/EnoConsumptionPointsRepository.js.map +1 -1
- package/dist/output-gateway/repositories/interfaces/IEnoBuildingDetailAggregate.d.ts +6 -1
- package/dist/output-gateway/repositories/interfaces/IEnoSharedPointRow.d.ts +5 -0
- package/dist/output-gateway/repositories/interfaces/IEnoSharedPointRow.js +3 -0
- package/dist/output-gateway/repositories/interfaces/IEnoSharedPointRow.js.map +1 -0
- package/dist/output-gateway/routers/interfaces/IEnoBuildingDetailResponse.d.ts +43 -18
- package/dist/output-gateway/routers/v2/V2EnoBuildingsRouter.js +2 -1
- package/dist/output-gateway/routers/v2/V2EnoBuildingsRouter.js.map +1 -1
- package/dist/output-gateway/transformations/EnoBuildingDetailTransformation.d.ts +6 -0
- package/dist/output-gateway/transformations/EnoBuildingDetailTransformation.js +53 -14
- package/dist/output-gateway/transformations/EnoBuildingDetailTransformation.js.map +1 -1
- package/dist/output-gateway/transformations/helpers/ConsumptionHistoryBuilder.d.ts +16 -0
- package/dist/output-gateway/transformations/helpers/ConsumptionHistoryBuilder.js +133 -0
- package/dist/output-gateway/transformations/helpers/ConsumptionHistoryBuilder.js.map +1 -0
- package/dist/output-gateway/transformations/helpers/PorsennaCoverage.d.ts +5 -0
- package/dist/output-gateway/transformations/helpers/PorsennaCoverage.js +40 -0
- package/dist/output-gateway/transformations/helpers/PorsennaCoverage.js.map +1 -0
- package/docs/implementation_documentation.md +67 -1
- package/docs/openapi-output.yaml +663 -43
- package/package.json +1 -1
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PorsennaCoverage = void 0;
|
|
4
|
+
const luxon_1 = require("@golemio/core/dist/shared/luxon");
|
|
5
|
+
const PERIOD_FORMAT = {
|
|
6
|
+
yearly: "yyyy",
|
|
7
|
+
monthly: "yyyy-MM",
|
|
8
|
+
daily: "yyyy-MM-dd",
|
|
9
|
+
};
|
|
10
|
+
const PERIOD_LENGTH = {
|
|
11
|
+
yearly: { years: 1 },
|
|
12
|
+
monthly: { months: 1 },
|
|
13
|
+
daily: { days: 1 },
|
|
14
|
+
};
|
|
15
|
+
class PorsennaCoverage {
|
|
16
|
+
static dataTo(rows) {
|
|
17
|
+
const covered = rows
|
|
18
|
+
.map((row) => PorsennaCoverage.lastCoveredDay(row))
|
|
19
|
+
.filter((day) => day !== null)
|
|
20
|
+
.sort();
|
|
21
|
+
return covered.length === 0 ? null : covered[covered.length - 1];
|
|
22
|
+
}
|
|
23
|
+
static lastCoveredDay(row) {
|
|
24
|
+
const format = PERIOD_FORMAT[row.var];
|
|
25
|
+
if (format === undefined) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const start = luxon_1.DateTime.fromFormat(row.period, format, { zone: "utc" });
|
|
29
|
+
if (!start.isValid) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
const periodEnd = start.plus(PERIOD_LENGTH[row.var]).minus({ days: 1 });
|
|
33
|
+
// count clamped into [start, periodEnd]: a missing/nonsensical count is treated as fully covered.
|
|
34
|
+
const days = row.count === null || row.count < 1 ? Number.MAX_SAFE_INTEGER : row.count;
|
|
35
|
+
const reached = days >= periodEnd.diff(start, "days").days + 1 ? periodEnd : start.plus({ days: days - 1 });
|
|
36
|
+
return reached.toFormat("yyyy-MM-dd");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.PorsennaCoverage = PorsennaCoverage;
|
|
40
|
+
//# sourceMappingURL=PorsennaCoverage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PorsennaCoverage.js","sourceRoot":"","sources":["../../../../src/output-gateway/transformations/helpers/PorsennaCoverage.ts"],"names":[],"mappings":";;;AACA,2DAA2D;AAE3D,MAAM,aAAa,GAA2B;IAC1C,MAAM,EAAE,MAAM;IACd,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,YAAY;CACtB,CAAC;AAEF,MAAM,aAAa,GAAuE;IACtF,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE;IACpB,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE;IACtB,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE;CACrB,CAAC;AAEF,MAAa,gBAAgB;IAClB,MAAM,CAAC,MAAM,CAAC,IAAoB;QACrC,MAAM,OAAO,GAAG,IAAI;aACf,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,gBAAgB,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;aAClD,MAAM,CAAC,CAAC,GAAG,EAAiB,EAAE,CAAC,GAAG,KAAK,IAAI,CAAC;aAC5C,IAAI,EAAE,CAAC;QAEZ,OAAO,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrE,CAAC;IAEO,MAAM,CAAC,cAAc,CAAC,GAAiB;QAC3C,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACtC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,MAAM,KAAK,GAAG,gBAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACvE,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;QACxE,kGAAkG;QAClG,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,KAAK,IAAI,IAAI,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;QACvF,MAAM,OAAO,GAAG,IAAI,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC;QAE5G,OAAO,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IAC1C,CAAC;CACJ;AA5BD,4CA4BC"}
|
|
@@ -675,6 +675,56 @@ Task přegeneruje materializovaný pohled `mv_ded_building_search`, nad kterým
|
|
|
675
675
|
- unit testy
|
|
676
676
|
- [DedSearchIndexRefreshTask.test.ts](../test/integration-engine/enapo/task/DedSearchIndexRefreshTask.test.ts)
|
|
677
677
|
|
|
678
|
+
#### _task: EnapoConsumptionHistoryRefreshTask_
|
|
679
|
+
|
|
680
|
+
Task přegeneruje materializovaný pohled `mv_enapo_om_consumption`, ze kterého se plní blok `consumption_history` v detailu budovy `/v2/energetics/ded/buildings/{gid}` (měsíční a roční spotřeba za odběrné místo a zdroj).
|
|
681
|
+
|
|
682
|
+
- vstupní rabbitmq fronta
|
|
683
|
+
- název: dataplatform.enapoenergetics.refreshConsumptionHistory
|
|
684
|
+
- TTL: 30 minut (starší zpráva už je překonaná novější, nemá smysl ji zpracovávat)
|
|
685
|
+
- parametry: žádné — refresh vždy přestaví celý pohled, takže není co validovat a `schema` je záměrně `undefined`
|
|
686
|
+
- cron definice
|
|
687
|
+
- cron.dataplatform.enapoenergetics.refreshConsumptionHistory — noční běh po okně stahování odečtů
|
|
688
|
+
- rabin `0 45 3 * * *`
|
|
689
|
+
- prod `0 45 3 * * *`
|
|
690
|
+
- samotná definice cronu je vedena mimo tento repozitář (deployment konfigurace)
|
|
691
|
+
- spouštění na základě událostí
|
|
692
|
+
- žádné, a to záměrně: [EnapoPpasTask](#task-enapoppastask) stahuje po pětidenních intervalech a spouštěl by desítky refreshů za jeden běh, přičemž endpoint stejně garantuje svěžest jen na 6 hodin (cache hlavičky)
|
|
693
|
+
- data modely
|
|
694
|
+
- [EnapoConsumptionHistoryIndexRepository](../src/integration-engine/enapo/repositories/EnapoConsumptionHistoryIndexRepository.ts) — `REFRESH MATERIALIZED VIEW CONCURRENTLY energetics.mv_enapo_om_consumption`, kontrakt [IEnapoConsumptionHistoryIndexRepository](../src/integration-engine/enapo/repositories/interfaces/IEnapoConsumptionHistoryIndexRepository.ts)
|
|
695
|
+
- funkce
|
|
696
|
+
- **CONCURRENTLY**: refresh neblokuje čtenáře; vyžaduje unikátní index nad `(gid, place_id, commodity, source, unit, period_type, period_start)` (vytvořen migrací) a **nesmí běžet v transakci**
|
|
697
|
+
- pohled je omezen na posledních 48 měsíců, aby refresh nemusel procházet celou historii; endpoint standardně vrací 36 (`?months=`, max 48)
|
|
698
|
+
- sloupec `invoice_ids` nese doklady, ze kterých bylo období rozpočteno (prázdné pole u měřených a Porsenna řad). Roční řádky ho neskládají z měsíčních polí — `array_agg` nad poli různé délky spadne a sjednocovací agregát nad polem v PG není — ale rollupem přímo z fakturačních řádků (CTE `invoice_device_month` → `invoice_month` / `invoice_year`)
|
|
699
|
+
- `enapo_measurements` má ~45 mil. řádků a jediný index byl primární klíč, jehož vedoucí sloupec je pro tento průchod nepoužitelný — migrace proto přidává `enapo_measurements_source_var_ts_idx (source, var, timestamp)`; bez něj trval elektroměrový agregát 5 min 45 s a plynový 1 min 24 s
|
|
700
|
+
- unit testy
|
|
701
|
+
- [EnapoConsumptionHistoryRefreshTask.test.ts](../test/integration-engine/enapo/task/EnapoConsumptionHistoryRefreshTask.test.ts)
|
|
702
|
+
|
|
703
|
+
#### _Sémantika `var` v `enapo_measurements` (ověřeno proti produkci 2026-08-13)_
|
|
704
|
+
|
|
705
|
+
Sloupec `value` míchá **kumulativní stavy měřidla** a **rozdíly za interval**, rozlišené pouze podle `(source, var)`. Agregace bez tohoto rozlišení dává nesmysly.
|
|
706
|
+
|
|
707
|
+
| `source` | komodita | `var` | granularita | význam | jednotka | agregace |
|
|
708
|
+
| -------------- | ----------- | ---------------------------------- | ----------- | -------------------------------------------------- | -------- | --------------------------------------------------- |
|
|
709
|
+
| `ppas_ave_api` | plyn | `corediff` | hodinová | **rozdíl** (`OperatingDifference`) | m³ | `sum` ← **primární** |
|
|
710
|
+
| `ppas_ave_api` | plyn | `core2` | hodinová | **rozdíl**, přepočtený (`ConvertDifference`) | Nm³ | `sum`, ale v 81 % řádků nula → jen fallback |
|
|
711
|
+
| `ppas_ave_api` | plyn | `core` | hodinová | **kumulativní** stav měřidla (`OperatingAmount`) | m³ | **nepoužívat** (viz níže) |
|
|
712
|
+
| `predi_input` | elektřina | `EActi_VT_NT_DaySum` | denní | **odvozený součet** VT+NT | **kWh** | `sum` ← **primární** |
|
|
713
|
+
| `predi_input` | elektřina | `EActi_VT_DaySum` / `_NT_DaySum` | denní | denní energie; NT je dnes všude nulové | **kWh** | `sum` (jen fallback) |
|
|
714
|
+
| `predi_input` | elektřina | `EFwActi_VT` / `_NT` | 15 min | průměrný **výkon**, tedy 4× energie | kW | **nepoužívat** (`sum / 4` by byly kWh) |
|
|
715
|
+
|
|
716
|
+
Tři pasti, které je potřeba mít zakódované v SQL, ne v hlavě reviewera:
|
|
717
|
+
|
|
718
|
+
1. **Nikdy nesčítat `EActi_VT_NT_DaySum` společně s `EActi_VT_DaySum` + `EActi_NT_DaySum`** — první je součtem druhých dvou (ověřeno: podíl je 1.0000 na p05, mediánu i p95).
|
|
719
|
+
2. **Nikdy nemíchat `EFwActi_*` s `EActi_*_DaySum`** — tatáž energie dvakrát, a navíc bez dělení čtyřmi (ověřeno: podíl 4.0000).
|
|
720
|
+
3. **Jednotka je kWh, ne Wh**, přes to, že se zdrojové pole jmenuje `T1_Wh_total`. Doloženo přes `enapo_pre_metadata_history.circuit_breaker`: odběrná místa s vyplněným jističem vycházejí na 63–130 kW průměrného výkonu proti 173–277 kW kapacity přípojky, což jako Wh nedává smysl.
|
|
721
|
+
|
|
722
|
+
Další ověřené vlastnosti dat, na které agregace spoléhá:
|
|
723
|
+
|
|
724
|
+
- `id_type` **není spolehlivý** — v produkci je aspoň jedno elektroměrové EAN uložené s `id_type = 'eic'`, takže join na měření jde výhradně přes `enapo_measurements.id` a `id_type` se nefiltruje
|
|
725
|
+
- `enapo_gid_mapping.place_id` je **kód EAN/EIC**, zatímco `enapo_measurements.place_id` je interní PPAS place id — join `place_id = place_id` vrací nula řádků a vypadá jako „nejsou data“
|
|
726
|
+
- jedno EIC může mít několik `place_id`. Pokud jejich počet přesahuje počet různých `device_serial_number`, jde o dvě živé registrace jednoho fyzického měřidla a sečtení by spotřebu zdvojilo — agregace proto pracuje na granularitě `(id, device_serial_number)`. Ze stejného důvodu je `max(core) - min(core)` nepoužitelné: rozpětí mezi dvěma nesouvisejícími počítadly.
|
|
727
|
+
|
|
678
728
|
#### _PPAS Distribution API_
|
|
679
729
|
|
|
680
730
|
- zdroj dat
|
|
@@ -686,6 +736,15 @@ Task přegeneruje materializovaný pohled `mv_ded_building_search`, nad kterým
|
|
|
686
736
|
- accessToken header: module.energetics.enapo.ppas.distribution.accessToken
|
|
687
737
|
- API dokumentace: interní dokumentace PPAS
|
|
688
738
|
- Kdyz jsou hodnoty v consumptionKwh negativni tak se jedna o storno označeno jako CORRECTION pokud ne označeno jako STANDARD, pokud prijdou dve nulove hodnoty za sebou, nazváno zero rows, tak je první brána jako STANDARD a druhá CORRECTION
|
|
739
|
+
- `kind` je sada SAP kódů, které vyjadřují **tentýž plyn v různých dimenzích**, takže součet přes všechny `kind` nadhodnocuje 2–3×. Ověřeno proti produkci 2026-08-13:
|
|
740
|
+
- `ZIZWC` (M3, 434 EIC) — hlavní objemová řada, **používá se**
|
|
741
|
+
- `ZIABN3` (KWH, 22 EIC) — denní kWh velkých odběratelů, **používá se**; těchto 22 EIC je průkazně disjunktní se 434 výše (jejich Nm³ převyšuje celkový součet `ZIZWC`)
|
|
742
|
+
- `ZSATN3` (NM3, 22 EIC) — **tentýž plyn jako `ZIABN3`** (Nm³ součty jsou shodné na cifru), vyloučeno
|
|
743
|
+
- `ZSCBM3` (M3, 49 EIC) — nese 92 % objemu `ZIZWC` z devítiny jeho EIC; vyloučeno jako bezpečnější strana otevřené otázky (chybějící řada se vrací jako `null`, zdvojené číslo by se tvářilo jako platné)
|
|
744
|
+
- sloupec `consumption` je denominovaný podle `unit` (M3 / NM3 / KWH), **není to vždy m³**
|
|
745
|
+
- `combustion_heat` a `volume_coefficient` s hodnotou 0 znamenají „nedodáno“, ne nulu — bez `NULLIF` by se z odvozených kWh stala nula, která se na grafu kreslí jako skutečný odečet
|
|
746
|
+
- existují **duplicitní faktury bez vazby přes `preceding_id`** nesoucí bajtově shodné řádky pro totéž EIC a období; deduplikace proto musí jít podle obsahu řádku `(eic, place_id, device_serial_number, date_from, date_to, kind, reading_type, unit)`, nikoli podle návaznosti faktur
|
|
747
|
+
- `mv_enapo_om_consumption` zatím bere jen `reading_type = 'STANDARD'`. Protože CORRECTION je storno (viz výše, negativní consumptionKwh), znamená to, že se storna neodečítají a spotřeba je **nadhodnocená o ~0,68 %**. Vědomé zjednodušení první verze: znaménko nese pouze `gas_consumption_kwh`, `consumption` zůstává pozitivní, takže naivní součet by v jednom sloupci odečítal a ve druhém přičítal
|
|
689
748
|
- formát dat
|
|
690
749
|
- protokol: https (REST API)
|
|
691
750
|
- datový typ: json
|
|
@@ -927,7 +986,7 @@ Přehled endpointů a parametru `accessLimit`:
|
|
|
927
986
|
- `enapo_ppas_distribution_invoice(_installation)` — poslední nestornovaná distribuční faktura (jen EIC / plyn, join přes `eic` v tabulce instalací)
|
|
928
987
|
- `enapo_ppas_commercial_invoice(_installations)` — poslední nestornovaná obchodní faktura (jen EIC / plyn, join přes `eic`)
|
|
929
988
|
- `UNION ALL` větev pro OM známá pouze z Porsenny (e-manažer): hlavní měřidla (`level = main`) z `enapo_porsenna_devices`, jejichž `identifier` není namapován na daný GID v `enapo_gid_mapping`; `commodity` z typu měřidla (v reálných datech existují pouze `electricity_meter` / `gasometer` / `heat_meter` / `water_meter`), `id_type` odvozen přímo z komodity (elektřina → ean, plyn → eic, teplo a voda → `om` — standardní identifikátor nemají), `link_source = 'porsenna'`, `is_active` z `disabled_at`
|
|
930
|
-
- `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
|
|
989
|
+
- `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ů
|
|
931
990
|
- `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)
|
|
932
991
|
- mapovací tabulka `enapo_gid_mapping`
|
|
933
992
|
- vlastní kontrakt modulu; aktuálně plněná mock daty (`link_source = 'mock'`)
|
|
@@ -937,4 +996,11 @@ Přehled endpointů a parametru `accessLimit`:
|
|
|
937
996
|
- 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
|
|
938
997
|
- detail existuje, pokud pro GID máme jakákoli data — zná ho alespoň jeden zdroj (`eno_budova`, `eno_adresa`, `enapo_gid_mapping`, nebo Porsenna): pokud GID není v `eno_budova`, ale má adresy, namapovaná OM či měřidla, vrací se 200 s `building: null` a chybějící části jako `null` / prázdná pole (cca 29 % GIDů z mapování nemá záznam v ENO); 404 pouze pokud GID nezná žádný zdroj
|
|
939
998
|
- OM známé z obou zdrojů (mapování i Porsenna) je v odpovědi jednou — data Porsenny jsou vnořená jako blok `porsenna` v příslušném komoditním klíči; duplicitní záznamy nevznikají
|
|
999
|
+
- `monthly` řada zdroje, který reportuje jen roční agregáty (Porsenna), je prázdné pole, ne 36 `null` položek — spina samých `null` by tvrdila, že zdroj měsíce zná a nemá je, což pro zdroj bez měsíční granularity neplatí; roční data jsou v `yearly`
|
|
940
1000
|
- budoucí komodity (teplo, voda) se přidají jako nové klíče bez breaking change
|
|
1001
|
+
- `name` / `address` na nejvyšší úrovni: `building` je pro cca 29 % GIDů `null`, ale kartu je pořád potřeba nadepsat — název se proto řeší stejným fallbackem jako ve vyhledávání (`eno_budova.nazev` → název budovy z Porsenny → `null`), adresa jako první popsaná `eno_adresa` (řazené hlavní adresou napřed) → adresa z Porsenny → `null`. Kdyby to zůstalo na klientech, každý si řetězec poskládá jinak.
|
|
1002
|
+
- provenience agregátů (aby klient nemusel sečtené číslo vydávat za přesné)
|
|
1003
|
+
- `points_total` / `points_with_data` u každého období: kolik OM do něj přispělo a kolik z nich mělo hodnotu. Rozdíl proti `points` celé řady je to, co odliší „budova spotřebovala míň“ od „chybí jedno OM“; u prázdného období spiny jsou obě nuly, nikdy `null`
|
|
1004
|
+
- `invoice_ids` u každého období: doklady, ze kterých bylo období rozpočteno; prázdné pole u měřených a Porsenna řad. Na úrovni budovy může být období rozpočteno z několika faktur (jedna na OM), roční agregát skoro vždy — proto pole, ne jedno id
|
|
1005
|
+
- `shared_with` u OM: ostatní budovy, na které je totéž OM namapované (z `enapo_gid_mapping`, název stejným fallbackem jako `name`). Součty počítají takové OM v plné výši — to je to, co měřidla naměřila — takže tohle je jediný způsob, jak se klient dozví, s kým je číslo sdílené. Platí pro obě strany sdíleného OM, tedy i pro tu s `is_first_gid = true`; `has_shared_points` na úrovni budovy se odvozuje odsud, ne z `is_first_gid`
|
|
1006
|
+
- `energy_management.data_to`: kam sahají data e-manažera. Porsenna neposílá čas posledního odečtu, jen počet pokrytých dní za období, takže se datum odvozuje jako začátek období + pokryté dny, oříznuté koncem období ([PorsennaCoverage](../src/output-gateway/transformations/helpers/PorsennaCoverage.ts))
|