1#[cfg(test)]
2mod tests;
3
4#[cfg(test)]
5mod tests_ir;
6
7#[cfg(test)]
8mod tests_cdr_ir;
9
10use super::{
11 build, ir_object, ocpi_enum, BuilderKind, Enum, Field, HasElement, Integrity, List, Number,
12 Object, Scalar, Schema, Str, Warning,
13};
14
15use crate::{json, Caveat};
16
17const MAX_LEN_IDENTIFIER: usize = 36;
22const MAX_LEN_LONG_IDENTIFIER: usize = 39;
23const MAX_LEN_EVSE_ID: usize = 48;
24
25const MAX_LEN_CURRENCY: usize = 3;
27const MAX_LEN_PARTY_ID: usize = 3;
28const MAX_LEN_COUNTRY: usize = 3;
29const MAX_LEN_COUNTRY_CODE: usize = 2;
30const MAX_LEN_LANGUAGE: usize = 2;
31
32const MAX_LEN_LATITUDE: usize = 10;
34const MAX_LEN_LONGITUDE: usize = 11;
35const MAX_LEN_POSTAL_CODE: usize = 10;
36const MAX_LEN_ADDRESS: usize = 45;
37const MAX_LEN_CITY: usize = 45;
38const MAX_LEN_STATE: usize = 20;
39
40const MAX_LEN_TIME_ZONE: usize = 255;
44const MAX_LEN_NAME: usize = 255;
45const MAX_LEN_URL: usize = 255;
46const MAX_LEN_METER_ID: usize = 255;
47const MAX_LEN_REMARK: usize = 255;
48const MAX_LEN_ENERGY_MIX_NAME: usize = 64;
49const MAX_LEN_DISPLAY_TEXT: usize = 512;
50
51const MAX_LEN_NATURE: usize = 32;
53const MAX_LEN_PLAIN_DATA: usize = 512;
54const MAX_LEN_SIGNED_DATA: usize = 5000;
55const MAX_LEN_PUBLIC_KEY: usize = 512;
56const MAX_LEN_SIGNED_DATA_URL: usize = 512;
57
58ocpi_enum!(TokenType {
65 AdHocUser = "AD_HOC_USER",
66 AppUser = "APP_USER",
67 Other = "OTHER",
68 Rfid = "RFID",
69});
70
71ocpi_enum!(ConnectorFormat {
73 Socket = "SOCKET",
74 Cable = "CABLE",
75});
76
77ocpi_enum!(PowerType {
79 Ac1Phase = "AC_1_PHASE",
80 Ac2Phase = "AC_2_PHASE",
81 Ac2PhaseSplit = "AC_2_PHASE_SPLIT",
82 Ac3Phase = "AC_3_PHASE",
83 Dc = "DC",
84});
85
86ocpi_enum!(ConnectorType {
88 Chademo = "CHADEMO",
89 Chaoji = "CHAOJI",
90 DomesticA = "DOMESTIC_A",
91 DomesticB = "DOMESTIC_B",
92 DomesticC = "DOMESTIC_C",
93 DomesticD = "DOMESTIC_D",
94 DomesticE = "DOMESTIC_E",
95 DomesticF = "DOMESTIC_F",
96 DomesticG = "DOMESTIC_G",
97 DomesticH = "DOMESTIC_H",
98 DomesticI = "DOMESTIC_I",
99 DomesticJ = "DOMESTIC_J",
100 DomesticK = "DOMESTIC_K",
101 DomesticL = "DOMESTIC_L",
102 DomesticM = "DOMESTIC_M",
103 DomesticN = "DOMESTIC_N",
104 DomesticO = "DOMESTIC_O",
105 GbtAc = "GBT_AC",
106 GbtDc = "GBT_DC",
107 Iec603092Single16 = "IEC_60309_2_single_16",
108 Iec603092Three16 = "IEC_60309_2_three_16",
109 Iec603092Three32 = "IEC_60309_2_three_32",
110 Iec603092Three64 = "IEC_60309_2_three_64",
111 Iec62196T1 = "IEC_62196_T1",
112 Iec62196T1Combo = "IEC_62196_T1_COMBO",
113 Iec62196T2 = "IEC_62196_T2",
114 Iec62196T2Combo = "IEC_62196_T2_COMBO",
115 Iec62196T3A = "IEC_62196_T3A",
116 Iec62196T3C = "IEC_62196_T3C",
117 Nema520 = "NEMA_5_20",
118 Nema630 = "NEMA_6_30",
119 Nema650 = "NEMA_6_50",
120 Nema1030 = "NEMA_10_30",
121 Nema1050 = "NEMA_10_50",
122 Nema1430 = "NEMA_14_30",
123 Nema1450 = "NEMA_14_50",
124 PantographBottomUp = "PANTOGRAPH_BOTTOM_UP",
125 PantographTopDown = "PANTOGRAPH_TOP_DOWN",
126 TeslaR = "TESLA_R",
127 TeslaS = "TESLA_S",
128});
129
130ocpi_enum!(AuthMethod {
132 AuthRequest = "AUTH_REQUEST",
133 Command = "COMMAND",
134 Whitelist = "WHITELIST",
135});
136
137ocpi_enum!(CdrDimensionType {
139 Current = "CURRENT",
140 Energy = "ENERGY",
141 EnergyExport = "ENERGY_EXPORT",
142 EnergyImport = "ENERGY_IMPORT",
143 MaxCurrent = "MAX_CURRENT",
144 MinCurrent = "MIN_CURRENT",
145 MaxPower = "MAX_POWER",
146 MinPower = "MIN_POWER",
147 ParkingTime = "PARKING_TIME",
148 Power = "POWER",
149 ReservationTime = "RESERVATION_TIME",
150 StateOfCharge = "STATE_OF_CHARGE",
151 Time = "TIME",
152});
153
154ocpi_enum!(TariffDimensionType {
156 Energy = "ENERGY",
157 Flat = "FLAT",
158 ParkingTime = "PARKING_TIME",
159 Time = "TIME",
160});
161
162ocpi_enum!(DayOfWeek {
164 Monday = "MONDAY",
165 Tuesday = "TUESDAY",
166 Wednesday = "WEDNESDAY",
167 Thursday = "THURSDAY",
168 Friday = "FRIDAY",
169 Saturday = "SATURDAY",
170 Sunday = "SUNDAY",
171});
172
173ocpi_enum!(ReservationRestrictionType {
175 Reservation = "RESERVATION",
176 ReservationExpires = "RESERVATION_EXPIRES",
177});
178
179ocpi_enum!(TariffType {
181 AdHocPayment = "AD_HOC_PAYMENT",
182 ProfileCheap = "PROFILE_CHEAP",
183 ProfileFast = "PROFILE_FAST",
184 ProfileGreen = "PROFILE_GREEN",
185 Regular = "REGULAR",
186});
187
188ocpi_enum!(EnergySourceCategory {
190 Nuclear = "NUCLEAR",
191 GeneralFossil = "GENERAL_FOSSIL",
192 Coal = "COAL",
193 Gas = "GAS",
194 GeneralGreen = "GENERAL_GREEN",
195 Solar = "SOLAR",
196 Wind = "WIND",
197 Water = "WATER",
198});
199
200ocpi_enum!(EnvironmentalImpactCategory {
202 NuclearWaste = "NUCLEAR_WASTE",
203 CarbonDioxide = "CARBON_DIOXIDE",
204});
205
206static DAY_OF_WEEK: Schema = Schema::Scalar(Scalar::Enum(DayOfWeek::VARIANTS));
208
209static PRICE_OBJ: Object = Object {
210 fields: &[
211 Field::required("excl_vat", Scalar::Number),
212 Field::optional("incl_vat", Scalar::Number),
213 ],
214 kind: BuilderKind::V221Price,
215};
216
217static GEO_LOCATION_OBJ: Object = Object {
218 fields: &[
220 Field::required("latitude", Scalar::StringMax(MAX_LEN_LATITUDE)),
221 Field::required("longitude", Scalar::StringMax(MAX_LEN_LONGITUDE)),
222 ],
223 kind: BuilderKind::Ignore,
224};
225
226static CDR_TOKEN_OBJ: Object = Object {
227 fields: &[
228 Field::required("contract_id", Scalar::StringMax(MAX_LEN_IDENTIFIER)),
229 Field::required("country_code", Scalar::StringMax(MAX_LEN_COUNTRY_CODE)),
230 Field::required("party_id", Scalar::StringMax(MAX_LEN_PARTY_ID)),
231 Field::required("type", Scalar::Enum(TokenType::VARIANTS)),
232 Field::required("uid", Scalar::StringMax(MAX_LEN_IDENTIFIER)),
233 ],
234 kind: BuilderKind::Ignore,
235};
236
237static CDR_LOCATION_OBJ: Object = Object {
238 fields: &[
239 Field::required("address", Scalar::StringMax(MAX_LEN_ADDRESS)),
240 Field::required("city", Scalar::StringMax(MAX_LEN_CITY)),
241 Field::required("connector_format", Scalar::Enum(ConnectorFormat::VARIANTS)),
242 Field::required("connector_id", Scalar::StringMax(MAX_LEN_IDENTIFIER)),
243 Field::required("connector_power_type", Scalar::Enum(PowerType::VARIANTS)),
244 Field::required("connector_standard", Scalar::Enum(ConnectorType::VARIANTS)),
245 Field::required_object("coordinates", &GEO_LOCATION_OBJ),
246 Field::required("country", Scalar::StringMax(MAX_LEN_COUNTRY)),
247 Field::required("evse_id", Scalar::StringMax(MAX_LEN_EVSE_ID)),
248 Field::required("evse_uid", Scalar::StringMax(MAX_LEN_IDENTIFIER)),
249 Field::required("id", Scalar::StringMax(MAX_LEN_IDENTIFIER)),
250 Field::optional("name", Scalar::StringMax(MAX_LEN_NAME)),
251 Field::optional("postal_code", Scalar::StringMax(MAX_LEN_POSTAL_CODE)),
252 Field::optional("state", Scalar::StringMax(MAX_LEN_STATE)),
253 Field::non_spec("time_zone", Scalar::StringMax(MAX_LEN_TIME_ZONE)),
256 ],
257 kind: BuilderKind::V221CdrLocation,
258};
259
260static NON_SPEC_LOCATION_OBJ: Object = Object {
267 fields: &[
268 Field::required("country", Scalar::StringMax(MAX_LEN_COUNTRY)),
269 Field::optional("time_zone", Scalar::StringMax(MAX_LEN_TIME_ZONE)),
270 ],
271 kind: BuilderKind::V221CdrLocation,
272};
273
274static CDR_DIMENSION_OBJ: Object = Object {
275 fields: &[
276 Field::required("type", Scalar::Enum(CdrDimensionType::VARIANTS)),
277 Field::required("volume", Scalar::Number),
278 ],
279 kind: BuilderKind::V221CdrDimension,
280};
281static CDR_DIMENSION: Schema = Schema::Object(&CDR_DIMENSION_OBJ);
282
283static CHARGING_PERIOD_OBJ: Object = Object {
284 fields: &[
285 Field::required_array("dimensions", &CDR_DIMENSION),
286 Field::required("start_date_time", Scalar::String),
287 Field::optional("tariff_id", Scalar::StringMax(MAX_LEN_IDENTIFIER)),
288 ],
289 kind: BuilderKind::V221ChargingPeriod,
290};
291static CHARGING_PERIOD: Schema = Schema::Object(&CHARGING_PERIOD_OBJ);
292
293static SIGNED_VALUE_OBJ: Object = Object {
294 fields: &[
295 Field::required("nature", Scalar::StringMax(MAX_LEN_NATURE)),
296 Field::required("plain_data", Scalar::StringMax(MAX_LEN_PLAIN_DATA)),
297 Field::required("signed_data", Scalar::StringMax(MAX_LEN_SIGNED_DATA)),
298 ],
299 kind: BuilderKind::Ignore,
300};
301static SIGNED_VALUE: Schema = Schema::Object(&SIGNED_VALUE_OBJ);
302
303static SIGNED_DATA_OBJ: Object = Object {
307 fields: &[
308 Field::required("encoding_method", Scalar::StringMax(MAX_LEN_IDENTIFIER)),
309 Field::optional("encoding_method_version", Scalar::String),
310 Field::optional("public_key", Scalar::StringMax(MAX_LEN_PUBLIC_KEY)),
311 Field::required_array("signed_values", &SIGNED_VALUE),
312 Field::optional("url", Scalar::StringMax(MAX_LEN_SIGNED_DATA_URL)),
313 ],
314 kind: BuilderKind::Ignore,
315};
316
317static DISPLAY_TEXT_OBJ: Object = Object {
318 fields: &[
319 Field::required("language", Scalar::StringMax(MAX_LEN_LANGUAGE)),
320 Field::required("text", Scalar::StringMax(MAX_LEN_DISPLAY_TEXT)),
321 ],
322 kind: BuilderKind::Ignore,
323};
324static DISPLAY_TEXT: Schema = Schema::Object(&DISPLAY_TEXT_OBJ);
325
326static ENERGY_SOURCE_OBJ: Object = Object {
327 fields: &[
328 Field::required("percentage", Scalar::Number),
329 Field::required("source", Scalar::Enum(EnergySourceCategory::VARIANTS)),
330 ],
331 kind: BuilderKind::Ignore,
332};
333static ENERGY_SOURCE: Schema = Schema::Object(&ENERGY_SOURCE_OBJ);
334
335static ENVIRONMENTAL_IMPACT_OBJ: Object = Object {
336 fields: &[
337 Field::required("amount", Scalar::Number),
338 Field::required(
339 "category",
340 Scalar::Enum(EnvironmentalImpactCategory::VARIANTS),
341 ),
342 ],
343 kind: BuilderKind::Ignore,
344};
345static ENVIRONMENTAL_IMPACT: Schema = Schema::Object(&ENVIRONMENTAL_IMPACT_OBJ);
346
347static ENERGY_MIX_OBJ: Object = Object {
348 fields: &[
349 Field::optional(
350 "energy_product_name",
351 Scalar::StringMax(MAX_LEN_ENERGY_MIX_NAME),
352 ),
353 Field::optional_array("energy_sources", &ENERGY_SOURCE),
354 Field::optional_array("environ_impact", &ENVIRONMENTAL_IMPACT),
355 Field::required("is_green_energy", Scalar::Boolean),
356 Field::optional("supplier_name", Scalar::StringMax(MAX_LEN_ENERGY_MIX_NAME)),
357 ],
358 kind: BuilderKind::Ignore,
359};
360
361static PRICE_COMPONENT_OBJ: Object = Object {
362 fields: &[
363 Field::required("price", Scalar::Number),
364 Field::required("step_size", Scalar::Number),
365 Field::required("type", Scalar::Enum(TariffDimensionType::VARIANTS)),
366 Field::optional("vat", Scalar::Number),
367 ],
368 kind: BuilderKind::V221PriceComponent,
369};
370static PRICE_COMPONENT: Schema = Schema::Object(&PRICE_COMPONENT_OBJ);
371
372static TARIFF_RESTRICTIONS_OBJ: Object = Object {
373 fields: &[
374 Field::optional_array("day_of_week", &DAY_OF_WEEK),
375 Field::optional("end_date", Scalar::String),
376 Field::optional("end_time", Scalar::String),
377 Field::optional("max_current", Scalar::Number),
378 Field::optional("max_duration", Scalar::Number),
379 Field::optional("max_kwh", Scalar::Number),
380 Field::optional("max_power", Scalar::Number),
381 Field::optional("min_current", Scalar::Number),
382 Field::optional("min_duration", Scalar::Number),
383 Field::optional("min_kwh", Scalar::Number),
384 Field::optional("min_power", Scalar::Number),
385 Field::optional(
386 "reservation",
387 Scalar::Enum(ReservationRestrictionType::VARIANTS),
388 ),
389 Field::optional("start_date", Scalar::String),
390 Field::optional("start_time", Scalar::String),
391 ],
392 kind: BuilderKind::V221Restrictions,
393};
394
395static TARIFF_ELEMENT_OBJ: Object = Object {
396 fields: &[
397 Field::required_array("price_components", &PRICE_COMPONENT),
398 Field::optional_object("restrictions", &TARIFF_RESTRICTIONS_OBJ),
399 ],
400 kind: BuilderKind::V221Element,
401};
402static TARIFF_ELEMENT: Schema = Schema::Object(&TARIFF_ELEMENT_OBJ);
403
404static TARIFF_OBJ: Object = Object {
407 fields: &[
408 Field::required("country_code", Scalar::StringMax(MAX_LEN_COUNTRY_CODE)),
409 Field::required("currency", Scalar::StringMax(MAX_LEN_CURRENCY)),
410 Field::required_array("elements", &TARIFF_ELEMENT),
411 Field::optional("end_date_time", Scalar::String),
412 Field::optional_object("energy_mix", &ENERGY_MIX_OBJ),
413 Field::required("id", Scalar::StringMax(MAX_LEN_IDENTIFIER)),
414 Field::required("last_updated", Scalar::String),
415 Field::optional_price("max_price", &PRICE_OBJ),
416 Field::optional_price("min_price", &PRICE_OBJ),
417 Field::required("party_id", Scalar::StringMax(MAX_LEN_PARTY_ID)),
418 Field::optional("start_date_time", Scalar::String),
419 Field::optional_array("tariff_alt_text", &DISPLAY_TEXT),
420 Field::optional("tariff_alt_url", Scalar::StringMax(MAX_LEN_URL)),
421 Field::optional("type", Scalar::Enum(TariffType::VARIANTS)),
422 ],
423 kind: BuilderKind::V221Tariff,
424};
425
426static TARIFF: Schema = Schema::Object(&TARIFF_OBJ);
431
432static CDR_OBJ: Object = Object {
435 fields: &[
436 Field::required("auth_method", Scalar::Enum(AuthMethod::VARIANTS)),
437 Field::optional(
438 "authorization_reference",
439 Scalar::StringMax(MAX_LEN_IDENTIFIER),
440 ),
441 Field::required_object("cdr_location", &CDR_LOCATION_OBJ),
442 Field::required_object("cdr_token", &CDR_TOKEN_OBJ),
443 Field::required_array("charging_periods", &CHARGING_PERIOD),
444 Field::required("country_code", Scalar::StringMax(MAX_LEN_COUNTRY_CODE)),
445 Field::optional("credit", Scalar::Boolean),
446 Field::optional(
447 "credit_reference_id",
448 Scalar::StringMax(MAX_LEN_LONG_IDENTIFIER),
449 ),
450 Field::required("currency", Scalar::StringMax(MAX_LEN_CURRENCY)),
451 Field::required("end_date_time", Scalar::String),
452 Field::optional("home_charging_compensation", Scalar::Boolean),
453 Field::required("id", Scalar::StringMax(MAX_LEN_LONG_IDENTIFIER)),
454 Field::optional(
455 "invoice_reference_id",
456 Scalar::StringMax(MAX_LEN_LONG_IDENTIFIER),
457 ),
458 Field::required("last_updated", Scalar::String),
459 Field::non_spec_object("location", &NON_SPEC_LOCATION_OBJ),
462 Field::optional("meter_id", Scalar::StringMax(MAX_LEN_METER_ID)),
463 Field::required("party_id", Scalar::StringMax(MAX_LEN_PARTY_ID)),
464 Field::optional("remark", Scalar::StringMax(MAX_LEN_REMARK)),
465 Field::optional("session_id", Scalar::StringMax(MAX_LEN_IDENTIFIER)),
466 Field::optional_object("signed_data", &SIGNED_DATA_OBJ),
467 Field::required("start_date_time", Scalar::String),
468 Field::optional_array("tariffs", &TARIFF),
469 Field::required_price("total_cost", &PRICE_OBJ),
470 Field::required("total_energy", Scalar::Number),
471 Field::optional_price("total_energy_cost", &PRICE_OBJ),
472 Field::optional_price("total_fixed_cost", &PRICE_OBJ),
473 Field::optional_price("total_parking_cost", &PRICE_OBJ),
474 Field::optional("total_parking_time", Scalar::Number),
475 Field::optional_price("total_reservation_cost", &PRICE_OBJ),
476 Field::required("total_time", Scalar::Number),
477 Field::optional_price("total_time_cost", &PRICE_OBJ),
478 ],
479 kind: BuilderKind::V221Cdr,
480};
481
482static CDR: Schema = Schema::Object(&CDR_OBJ);
488
489#[derive(Clone, Debug)]
501pub(crate) struct Cdr<'buf> {
502 pub country_code: Integrity<Str<'buf>>,
503 pub party_id: Integrity<Str<'buf>>,
504 pub currency: Integrity<Str<'buf>>,
505 pub start_date_time: Integrity<Str<'buf>>,
506 pub end_date_time: Integrity<Str<'buf>>,
507 pub charging_periods: Integrity<List<'buf, ChargingPeriod<'buf>>>,
508 pub total_cost: Integrity<Price<'buf>>,
509 pub total_energy: Integrity<Number<'buf>>,
510 pub total_time: Integrity<Number<'buf>>,
511 pub total_parking_time: Integrity<Option<Number<'buf>>>,
512 pub total_energy_cost: Integrity<Option<Price<'buf>>>,
513 pub total_fixed_cost: Integrity<Option<Price<'buf>>>,
514 pub total_parking_cost: Integrity<Option<Price<'buf>>>,
515 pub total_reservation_cost: Integrity<Option<Price<'buf>>>,
516 pub total_time_cost: Integrity<Option<Price<'buf>>>,
517 pub tariffs: Integrity<Option<List<'buf, Tariff<'buf>>>>,
518 #[expect(
519 clippy::struct_field_names,
520 reason = "every IR field is named after the OCPI field it holds"
521 )]
522 pub cdr_location: Integrity<CdrLocation<'buf>>,
523 pub location: Integrity<CdrLocation<'buf>>,
526}
527
528#[derive(Clone, Debug)]
534pub(crate) struct CdrLocation<'buf> {
535 pub country: Integrity<Str<'buf>>,
536 pub time_zone: Integrity<Option<Str<'buf>>>,
537}
538
539#[derive(Clone, Debug)]
541pub(crate) struct ChargingPeriod<'buf> {
542 pub start_date_time: Integrity<Str<'buf>>,
543 pub dimensions: Integrity<List<'buf, Dimension<'buf>>>,
544}
545
546#[derive(Clone, Debug)]
548pub(crate) struct Dimension<'buf> {
549 pub dimension_type: Integrity<Enum<'buf, CdrDimensionType>>,
550 pub volume: Integrity<Number<'buf>>,
551}
552
553#[derive(Clone, Debug)]
555pub(crate) struct Tariff<'buf> {
556 pub country_code: Integrity<Str<'buf>>,
557 pub currency: Integrity<Str<'buf>>,
558 pub id: Integrity<Str<'buf>>,
559 pub party_id: Integrity<Str<'buf>>,
560 pub min_price: Integrity<Option<Price<'buf>>>,
561 pub max_price: Integrity<Option<Price<'buf>>>,
562 pub start_date_time: Integrity<Option<Str<'buf>>>,
563 pub end_date_time: Integrity<Option<Str<'buf>>>,
564 pub elements: Integrity<List<'buf, Element<'buf>>>,
565}
566
567#[derive(Clone, Debug)]
569pub(crate) struct Element<'buf> {
570 pub price_components: Integrity<List<'buf, PriceComponent<'buf>>>,
571 pub restrictions: Integrity<Option<Restrictions<'buf>>>,
572}
573
574#[derive(Clone, Debug)]
576pub(crate) struct PriceComponent<'buf> {
577 pub dimension_type: Integrity<Enum<'buf, TariffDimensionType>>,
578 pub vat: Integrity<Option<Number<'buf>>>,
579 pub price: Integrity<Number<'buf>>,
580 pub step_size: Integrity<Number<'buf>>,
581}
582
583#[derive(Clone, Debug)]
590pub(crate) enum Price<'buf> {
591 Object {
593 elem: json::Element<'buf>,
596 excl_vat: Integrity<Number<'buf>>,
597 incl_vat: Integrity<Option<Number<'buf>>>,
598 },
599 Number(Number<'buf>),
601}
602
603impl<'buf> Price<'buf> {
604 pub(super) fn new(elem: json::Element<'buf>) -> Self {
607 Self::Object {
608 excl_vat: Integrity::Missing(crate::warning::Element::from_json(&elem)),
609 incl_vat: Integrity::Missing(crate::warning::Element::from_json(&elem)),
610 elem,
611 }
612 }
613
614 pub(super) fn from_number(elem: json::Element<'buf>, digits: &'buf str) -> Self {
618 Self::Number(Number::Number { elem, digits })
619 }
620}
621
622impl<'buf> HasElement<'buf> for Price<'buf> {
623 fn element(&self) -> &json::Element<'buf> {
624 match self {
625 Self::Object { elem, .. } => elem,
626 Self::Number(number) => number.element(),
627 }
628 }
629}
630
631#[derive(Clone, Debug)]
633pub(crate) struct Restrictions<'buf> {
634 pub start_time: Integrity<Option<Str<'buf>>>,
635 pub end_time: Integrity<Option<Str<'buf>>>,
636 pub start_date: Integrity<Option<Str<'buf>>>,
637 pub end_date: Integrity<Option<Str<'buf>>>,
638 pub min_kwh: Integrity<Option<Number<'buf>>>,
639 pub max_kwh: Integrity<Option<Number<'buf>>>,
640 pub min_current: Integrity<Option<Number<'buf>>>,
641 pub max_current: Integrity<Option<Number<'buf>>>,
642 pub min_power: Integrity<Option<Number<'buf>>>,
643 pub max_power: Integrity<Option<Number<'buf>>>,
644 pub min_duration: Integrity<Option<Number<'buf>>>,
645 pub max_duration: Integrity<Option<Number<'buf>>>,
646 pub day_of_week: Integrity<Option<List<'buf, Enum<'buf, DayOfWeek>>>>,
647 pub reservation: Integrity<Option<Enum<'buf, ReservationRestrictionType>>>,
648}
649
650ir_object!(Cdr {
653 country_code,
654 party_id,
655 currency,
656 start_date_time,
657 end_date_time,
658 charging_periods,
659 total_cost,
660 total_energy,
661 total_time,
662 total_parking_time,
663 total_energy_cost,
664 total_fixed_cost,
665 total_parking_cost,
666 total_reservation_cost,
667 total_time_cost,
668 tariffs,
669 cdr_location,
670 location,
671});
672ir_object!(CdrLocation { country, time_zone });
673ir_object!(ChargingPeriod {
674 start_date_time,
675 dimensions,
676});
677ir_object!(Dimension {
678 dimension_type,
679 volume,
680});
681ir_object!(Tariff {
682 country_code,
683 currency,
684 id,
685 party_id,
686 min_price,
687 max_price,
688 start_date_time,
689 end_date_time,
690 elements,
691});
692ir_object!(Element {
693 price_components,
694 restrictions,
695});
696ir_object!(PriceComponent {
697 dimension_type,
698 vat,
699 price,
700 step_size,
701});
702ir_object!(Restrictions {
703 start_time,
704 end_time,
705 start_date,
706 end_date,
707 min_kwh,
708 max_kwh,
709 min_current,
710 max_current,
711 min_power,
712 max_power,
713 min_duration,
714 max_duration,
715 day_of_week,
716 reservation,
717});
718
719pub(crate) fn build_tariff<'buf>(doc: &json::Document<'buf>) -> Caveat<Tariff<'buf>, Warning> {
724 let (node, warnings) = super::walk(doc, &TARIFF).into_parts();
725
726 let tariff = if let build::Node::Tariff(tariff) = node {
729 tariff
730 } else {
731 Tariff::new(doc.root())
732 };
733
734 Caveat::new(tariff, warnings)
735}
736
737pub(crate) fn build_cdr<'buf>(doc: &json::Document<'buf>) -> Caveat<Cdr<'buf>, Warning> {
742 let (node, warnings) = super::walk(doc, &CDR).into_parts();
743
744 let cdr = if let build::Node::Cdr(cdr) = node {
747 cdr
748 } else {
749 Cdr::new(doc.root())
750 };
751
752 Caveat::new(cdr, warnings)
753}