1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//! Pure multi-product retail energy billing for German markets.
//!
//! ## Architecture
//!
//! This crate is the **commercial billing engine for the Lieferant (LF)**. It
//! answers the question: *"What does the customer's invoice look like?"*
//!
//! The three-layer billing stack:
//!
//! ```text
//! metering — "What quantities are billable?"
//! ↓
//! eeg-billing — "What remuneration or statutory credits apply?" (NB-side)
//! ↓
//! energy-billing — "What does the customer's invoice look like?" (LF-side)
//! ↓
//! accountingd — Payments, Ledger, Dunning
//! ```
//!
//! ## Primary API
//!
//! Build a [`BillingEngine`] from one or more [`BillingProvider`]s, supply a
//! [`BillingContext`] and [`Quantities`], and receive an [`Invoice`]:
//!
//! ```rust
//! use energy_billing::*;
//! use rust_decimal_macros::dec;
//! use time::macros::date;
//!
//! let ctx = BillingContext {
//! malo_id: "51238696781".to_owned(),
//! lf_mp_id: "9900000000001".to_owned(),
//! rechnungsnummer: "R2026-001".to_owned(),
//! period_from: date!(2026-01-01),
//! period_to: date!(2026-01-31),
//! invoice_type: InvoiceType::Initial,
//! contract_id: None,
//! regulatory_rates: RegulatoryRates::default(),
//! };
//! let quantities = Quantities {
//! electricity: Some(MeterInput {
//! arbeitsmenge_kwh: dec!(500),
//! ..Default::default()
//! }),
//! ..Default::default()
//! };
//! let tariff: TariffInput =
//! serde_json::from_str(r#"{"category":"STROM","arbeitspreis_ct_per_kwh":30.0}"#).unwrap();
//! let invoice = BillingEngine::new()
//! .add(ElectricityProvider::from_tariff(&tariff, &GridInput::default()))
//! .add(MwStProvider::new(dec!(0.19)))
//! .bill(ctx, &quantities)
//! .unwrap();
//! assert!(invoice.brutto_eur > invoice.netto_eur);
//! ```
//!
//! ## Product categories
//!
//! | Category | Provider | Legal basis |
//! |---|---|---|
//! | `STROM` | [`ElectricityProvider`] | §41 EnWG |
//! | `WAERMEPUMPE` | [`ElectricityProvider`] + §14a | §14a EnWG |
//! | `WALLBOX` | [`ElectricityProvider`] + §14a | §14a EnWG |
//! | `GAS` | [`GasProvider`] | §41 EnWG |
//! | `WAERME` | [`HeatProvider`] | §41 EnWG |
//! | `SOLAR` | [`SolarProvider`] | §38a/§42a EEG 2023 |
//! | `EEG` | [`EegProvider`] (→ eeg-billing) | §§20–21 EEG 2023 |
//! | `EINSPEISUNG` | [`EinspeisungProvider`] | §20 EEG 2023 |
//! | `HEMS` | [`HemsProvider`] | — |
//! | `EMOBILITY` | [`EmobilityProvider`] | §41a EnWG |
//! | `ENERGIEDIENSTLEISTUNG` | [`ServiceProvider`] | — |
//! | `STROM` + `dynamic_epex` | [`DynamicElectricityProvider`] | §41a EnWG |
//!
//! ## Shortcut: `TariffInput::build_engine`
//!
//! For `billingd`'s dispatch path:
//! ```rust,ignore
//! let invoice = tariff
//! .build_engine(&grid, &rates)
//! .ok_or("unsupported category")?
//! .bill(ctx, &quantities)?;
//! ```
// ── Modules ───────────────────────────────────────────────────────────────────
// ── Primary API re-exports ────────────────────────────────────────────────────
// Core types
pub use ;
pub use BillingEngine;
pub use Invoice;
pub use ;
pub use ;
pub use ;
pub use RegulatoryRates;
pub use TariffInput;
// Concrete providers
pub use ;
// Error type (re-export from billing crate)
pub use BillingError;