dvgw_edi/lib.rs
1//! `dvgw-edi` — DVGW EDIFACT for the German gas transport and balancing market.
2//!
3//! Parses, validates and writes the DVGW-governed formats used in gas balancing
4//! (`GaBi` Gas 2.1, `BNetzA` BK7-24-01-008). The DVGW counterpart to `edi-energy`,
5//! which covers the BDEW EDI@Energy retail layer.
6//!
7//! # The one thing to know first
8//!
9//! **A DVGW message does not name itself in `UNH`.** Every format is a subset of
10//! a UN/EDIFACT D.07A message, so `UNH` carries the *carrier* — `ORDERS` or
11//! `ORDRSP` — and `BGM` C002 DE 1001 carries the message:
12//!
13//! ```text
14//! UNH+1+ORDERS:D:07A:UN:DVGW18' ← the carrier
15//! BGM+01G::332+NOMINT00052' ← *this* says NOMINT
16//! DTM+Z05:0:805' ← timestamps below are UTC
17//! DTM+137:201801042056:203' ← message date/time
18//! DTM+Z01:201801050400201801060400:719' ← Gültigkeitszeitraum = the gas day
19//! RFF+Z13:70030' ← Prüfidentifikator
20//! ```
21//!
22//! Matching `UNH` against `"NOMINT"` therefore rejects every conformant message.
23//! Identity here is resolved from [`DvgwDocument`], with the carrier as a
24//! cross-check.
25//!
26//! # Supported formats
27//!
28//! | Message | Carrier | Document codes (`BGM` DE 1001) | Prüfidentifikatoren |
29//! |---|---|---|---|
30//! | **ALOCAT** — Allokationsnachricht | `ORDRSP` | `X1G X2G X3G X4G X5G X6G X7G XBG` | 70001–70023 |
31//! | **NOMINT** — Nominierung | `ORDERS` | `01G 55G Y1G Y6G Y7G` | 70030–70034 |
32//! | **NOMRES** — Nominierungsantwort | `ORDRSP` | `07G 08G 19G 20G Y2G` | 70035–70039 |
33//! | **SSQNOT** — Mehr-/Mindermengenmeldung | `ORDRSP` | `BAG` | 70095–70096 |
34//!
35//! `CONTRL` and `APERAK` acknowledge DVGW interchanges but are BDEW formats;
36//! they live in `edi-energy` and are not reimplemented here.
37//!
38//! # Quick start
39//!
40//! ```rust,no_run
41//! use dvgw_edi::{DvgwMessageType, DvgwPlatform};
42//!
43//! # let raw: &[u8] = b"";
44//! let platform = DvgwPlatform::default();
45//! for result in platform.parse_interchange(raw) {
46//! let msg = result?;
47//! println!("{} ({})", msg.message_type, msg.document.description());
48//!
49//! // The gas day is DTM+Z01, decoded through its own format code.
50//! if let Some(period) = msg.validity_period {
51//! println!(" Gastag {period}");
52//! }
53//! // A LOC group carries a time series, not one value.
54//! for qty in msg.quantities() {
55//! println!(" {:?} {:?}", qty.value, qty.period);
56//! }
57//! if msg.message_type == DvgwMessageType::Nomint {
58//! // RFF+AGO — the nomination a re-nomination corrects. A NOMRES has no
59//! // such reference and is paired on the business key instead.
60//! println!(" korrigiert {:?}", msg.original_nomination_ref());
61//! }
62//!
63//! let report = DvgwPlatform::validate_message(&msg);
64//! for issue in report.errors() {
65//! eprintln!(" {issue}");
66//! }
67//! }
68//! # Ok::<(), dvgw_edi::Error>(())
69//! ```
70//!
71//! # Market roles
72//!
73//! | Role | Abbreviation |
74//! |---|---|
75//! | Fernleitungsnetzbetreiber | FNB |
76//! | Verteilnetzbetreiber | VNB |
77//! | Bilanzkreisverantwortlicher | BKV |
78//! | Marktgebietsverantwortlicher | MGV |
79//!
80//! # Regulatory references
81//!
82//! - **§ 20 Abs. 3 `EnWG`** — Festlegungskompetenz for gas network access and balancing
83//! - **`BNetzA` BK7-24-01-008** — `GaBi` Gas 2.1
84//! - **Kooperationsvereinbarung Gas (`KoV`)** — nomination and allocation deadlines
85//! - DVGW-Nachrichtenbeschreibungen: <https://www.dvgw-sc.de/leistungen/it-dienstleistungen/datenaustausch-gas>
86//!
87//! # Relationship to other crates
88//!
89//! | Crate | Layer |
90//! |---|---|
91//! | `dvgw-edi` | EDIFACT parsing / validation / writing — **this crate** |
92//! | `mako-gabi-gas` | `GaBi` Gas process engine (workflows, deadlines) |
93//! | `edi-energy` | BDEW EDI@Energy formats (UTILMD, MSCONS, APERAK, …) |
94
95#![deny(unsafe_code)]
96#![deny(missing_docs)]
97#![warn(clippy::pedantic)]
98#![allow(clippy::module_name_repetitions)]
99#![allow(clippy::must_use_candidate)]
100#![allow(clippy::return_self_not_must_use)]
101
102mod builder;
103mod datetime;
104mod document;
105mod error;
106mod message;
107mod platform;
108mod pruefidentifikator;
109mod report;
110mod validate;
111mod version;
112mod zuordnung;
113
114/// The typed message model: positions, locations, quantities and parties.
115pub mod model;
116/// SSQNOT read as one Mehr-/Mindermengen record.
117pub mod ssqnot;
118
119pub use builder::{MessageBuilder, Position};
120pub use datetime::{DtmFormat, DtmValue, DvgwPeriod};
121pub use document::{Carrier, DVGW_AGENCY_CODE, DvgwDocument, DvgwMessageType};
122pub use error::Error;
123pub use message::DvgwMessage;
124pub use model::{
125 EnergyByQualifier, ItemDescription, LineItem, LocationGroup, Party, Quantity, Reference,
126};
127pub use platform::{DvgwPlatform, sniff};
128pub use pruefidentifikator::{
129 PID_MAX, PID_MIN, PidInfo, Pruefidentifikator, SSQNOT_RLM_CUTOFF, catalogue, catalogue_for,
130};
131pub use report::{DvgwIssue, DvgwReport, Severity};
132pub use version::DvgwVersion;
133pub use zuordnung::{CorrelationKey, Zuordnung, assigned_pids};