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
123
124
125
126
127
128
129
130
131
//! `BillingProvider` trait and `SpotPriceSource` abstraction.
//!
//! Every product type (electricity, gas, EEG feed-in, HEMS…) implements
//! `BillingProvider`. The `BillingEngine` orchestrates them in order.
//!
//! ## Execution order and tax computation
//!
//! Providers run in registration order. Each receives `prior_positions` — all
//! positions produced by earlier providers. Tax providers (MwSt) are typically
//! registered last and compute their amount from `prior_positions`.
//!
//! ```text
//! ElectricityProvider → commodity + grid + Stromsteuer positions
//! GridChargeProvider → NNE/KA positions (if not already in Electricity)
//! StromsteuerProvider → levy position (if separate from ElectricityProvider)
//! MwStProvider → tax position on sum(prior_positions)
//! ```
//!
//! The `is_tax_pass()` method marks tax providers so the engine knows to run them
//! in a second pass (after all commodity/levy providers have executed).
use BillingError;
use crateBillingContext;
use crateBillingPosition;
// ── Quantities ────────────────────────────────────────────────────────────────
pub use crateQuantities;
// ── SpotPriceSource ───────────────────────────────────────────────────────────
/// Abstraction over spot electricity price sources.
///
/// Decouples the §41a EnWG dynamic tariff implementation from any specific
/// exchange (EPEX, NordPool, Tibber, aWATTar, etc.).
///
/// ## Extension
///
/// Implement this trait to add:
/// - `NordPoolSource` (Nordic / Baltic day-ahead)
/// - `TibberSource` (real-time pricing)
/// - `aWATTarSource`
/// - `EntsoESource` (ENTSO-E transparency platform)
/// EPEX Spot Day-Ahead price lookup map.
///
/// Key: `(year, month, day, hour_CET)` — local German time (CET/CEST).
/// Value: spot price in ct/kWh.
// ── BillingProvider trait ─────────────────────────────────────────────────────
/// A product or service component that generates billing positions.
///
/// Implement this trait for each billable product type. The engine calls
/// `bill()` for each registered provider in order, passing the accumulated
/// positions from all earlier providers.
///
/// ## Tax providers
///
/// Override `is_tax_pass()` to return `true` when this provider computes taxes
/// on the accumulated positions (e.g. MwSt). The engine ensures all commodity/
/// levy providers run before any tax provider.
///
/// ## Example
///
/// ```rust,ignore
/// struct MyFlatFeeProvider { eur: Decimal }
///
/// impl BillingProvider for MyFlatFeeProvider {
/// fn bill(
/// &self,
/// _ctx: &BillingContext,
/// _quantities: &Quantities,
/// _prior: &[BillingPosition],
/// ) -> Result<Vec<BillingPosition>, BillingError> {
/// Ok(vec![
/// BillingPosition::debit("Service Fee", Decimal::ONE, "Pauschal", self.eur, PositionCategory::Fee)
/// .with_tag("service_fee"),
/// ])
/// }
/// }
/// ```