price_cdr_with_unknown_version/
price_cdr_with_unknown_version.rs

1#![expect(clippy::expect_used, reason = "examples can panic")]
2#![expect(clippy::print_stderr, reason = "examples can log to stderr")]
3
4use ocpi_tariffs::{cdr, price, timezone, warning, Version};
5
6fn main() {
7    const CDR_JSON: &str =
8        include_str!("../test_data/v211/real_world/time_and_parking_time/cdr.json");
9
10    // First the raw JSON should be parsed into a `cdr::Versioned` object.
11    // The `cdr::Report` returned from calling `cdr::parse` contains a `cdr::Versioned` object
12    // and a potential list of unexpected fields based on the OCPI v221 spec.
13    let cdr = cdr::parse(CDR_JSON).expect("Unable to parse CDR JSON");
14
15    // The guessed Version can be either certain or uncertain.
16    // In this case we discard the CDR object and try to convert it into a version.
17    // If the version is uncertain then fallback to presuming the CDR is v211.
18    let cdr = cdr.certain_or(Version::V211);
19
20    // The timezone can be inferred or found in the CDR, but a versioned CDR is required.
21    let (timezone_source, warnings) = timezone::find_or_infer(&cdr).into_parts();
22
23    let Some(timezone_source) = timezone_source else {
24        eprintln!("Unable to infer timezone");
25        print_timezone_warnings(&cdr, &warnings);
26        return;
27    };
28
29    if !warnings.is_empty() {
30        print_timezone_warnings(&cdr, &warnings);
31    }
32
33    // We don't care whether the timezone was found or inferred.
34    let timezone = timezone_source.into_timezone();
35    let report = cdr::parse_with_version(CDR_JSON, Version::V211).expect("unable to parse CDR");
36    let cdr::ParseReport {
37        cdr,
38        unexpected_fields,
39    } = report;
40
41    if !unexpected_fields.is_empty() {
42        eprintln!("Strange... there are fields in the CDR that are not defined in the spec.");
43
44        for path in &unexpected_fields {
45            eprintln!("{path}");
46        }
47    }
48
49    let report =
50        cdr::price(&cdr, price::TariffSource::UseCdr, timezone).expect("unable to price CDR JSON");
51
52    // The various fields of the `price::Report` can be examined or converted to JSON.
53    let price::Report {
54        warnings: _,
55        periods: _,
56        tariff_used: _,
57        tariff_reports: _,
58        timezone: _,
59        billed_energy: _,
60        billed_parking_time: _,
61        total_charging_time: _,
62        billed_charging_time: _,
63        total_cost: _,
64        total_fixed_cost: _,
65        total_time: _,
66        total_time_cost: _,
67        total_energy: _,
68        total_energy_cost: _,
69        total_parking_time: _,
70        total_parking_cost: _,
71        total_reservation_cost: _,
72    } = report;
73}
74
75fn print_timezone_warnings(
76    cdr: &cdr::Versioned<'_>,
77    warnings: &warning::Set<timezone::WarningKind>,
78) {
79    if warnings.is_empty() {
80        return;
81    }
82
83    eprintln!("WARN: {} warnings from the timezone search", warnings.len());
84
85    eprintln!(
86        "WARN: {} warnings from the timezone search:\n {}",
87        warnings.len(),
88        warning::SetWriter::new(cdr.as_element(), warnings)
89    );
90}