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
//! `BillingEngine` — the composition root for multi-product invoice generation.
//!
//! Register one `BillingProvider` per product/service. Call `bill()` to run all
//! providers in order and assemble the `Invoice`.
//!
//! ## Execution model
//!
//! Providers run in two passes:
//!
//! **Pass 1 — commodity / levy providers** (`is_tax_pass() == false`):
//! Each receives the accumulated positions from all earlier providers.
//!
//! **Pass 2 — tax providers** (`is_tax_pass() == true`, typically `MwStProvider`):
//! Sees all commodity/levy positions as `prior`, computes tax on the net base.
//!
//! ## Example
//!
//! ```rust
//! use energy_billing::{
//! BillingContext, BillingEngine, ElectricityProvider, GasProvider,
//! InvoiceType, MwStProvider, Quantities, RegulatoryRates,
//! TariffInput, GridInput, MeterInput, GasMeterInput,
//! };
//! use rust_decimal_macros::dec;
//! use time::macros::date;
//!
//! let rates = RegulatoryRates::default();
//! 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: rates.clone(),
//! };
//! 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);
//! ```
use BillingError;
use crateBillingContext;
use crateInvoice;
use crateBillingPosition;
use crateBillingProvider;
use crateQuantities;
/// The composition root for multi-product invoice generation.