edifact-mapper 0.8.0

EDIFACT to BO4E bidirectional conversion for the German energy market
Documentation
//! One-off forward-mapping audit: read a list of EDIFACT fixtures, run the full
//! tokenize → assemble → forward-map pipeline, and dump the resulting BO4E JSON
//! to /tmp/forward_map_output/ for inspection.
//!
//! Run with:
//!   cargo run -p edifact-mapper --example forward_map_audit

use edifact_mapper::{DataDir, Mapper};
use mig_bo4e::DynamicInterchange;
use std::path::Path;

#[derive(Debug, Clone, Copy)]
struct FixtureCase {
    fv: &'static str,
    variant: &'static str,
    pid: &'static str,
    rel_path: &'static str, // relative to example_market_communication_bo4e_transactions/
}

const CASES: &[FixtureCase] = &[
    FixtureCase {
        fv: "FV2504",
        variant: "UTILMD_Strom",
        pid: "55001",
        rel_path: "UTILMD/FV2504/55001_UTILMD_S2.1_ALEXANDE121980.edi",
    },
    FixtureCase {
        fv: "FV2504",
        variant: "UTILMD_Strom",
        pid: "55002",
        rel_path: "UTILMD/FV2504/55002_UTILMD_S2.1_ALEXANDE104683.edi",
    },
    FixtureCase {
        fv: "FV2504",
        variant: "UTILMD_Strom",
        pid: "55013",
        rel_path: "UTILMD/FV2504/55013_UTILMD_S2.1_ALEXANDE982717998.edi",
    },
    FixtureCase {
        fv: "FV2504",
        variant: "UTILMD_Strom",
        pid: "55035",
        rel_path: "UTILMD/FV2504/55035_UTILMD_S2.1_ALEXANDE195836.edi",
    },
    FixtureCase {
        fv: "FV2504",
        variant: "UTILTS",
        pid: "25005",
        rel_path: "UTILTS/FV2504/25005_UTILTS_1.1e_DEV-93678.edi",
    },
    FixtureCase {
        fv: "FV2504",
        variant: "PRICAT",
        pid: "27002",
        rel_path: "PRICAT/FV2504/27002_PRICAT_2.0d_DEV-80749.edi",
    },
    FixtureCase {
        fv: "FV2504",
        variant: "MSCONS",
        pid: "13017",
        rel_path: "MSCONS/FV2504/13017_MSCONS_2.4c_010408950588_exCOM_SMV.edi",
    },
    FixtureCase {
        fv: "FV2504",
        variant: "INVOIC",
        pid: "31001",
        rel_path: "INVOIC/FV2504/31001_INVOIC_2.8d_ALEXANDE436887BGM.edi",
    },
    FixtureCase {
        fv: "FV2504",
        variant: "ORDERS",
        pid: "17009",
        rel_path: "ORDERS/FV2504/17009_ORDERS_1.4a_WIM65000000632.edi",
    },
    FixtureCase {
        fv: "FV2504",
        variant: "APERAK",
        pid: "92001",
        rel_path: "APERAK/FV2504/92001_APERAK_2.1i_DEV-99155.edi",
    },
    FixtureCase {
        fv: "FV2504",
        variant: "COMDIS",
        pid: "29001",
        rel_path: "COMDIS/FV2504/29001_COMDIS_1.0e_ALEXANDE361352BGM.edi",
    },
    FixtureCase {
        fv: "FV2504",
        variant: "REMADV",
        pid: "33001",
        rel_path: "REMADV/FV2504/33001_REMADV_2.9c_ALEXANDE822199BGM.edi",
    },
];

fn main() {
    let bundle_dir = std::path::Path::new("/tmp/edifact-bundles");
    let mapper =
        Mapper::from_data_dir(DataDir::path(bundle_dir).eager(&["FV2504"])).expect("load bundles");

    let out_dir = Path::new("/tmp/forward_map_output");
    std::fs::create_dir_all(out_dir).expect("mkdir output");

    let workspace_root = Path::new(env!("CARGO_MANIFEST_DIR"))
        .parent()
        .unwrap()
        .parent()
        .unwrap();
    let fixtures_root = workspace_root.join("example_market_communication_bo4e_transactions");

    let mut summary = Vec::new();

    for case in CASES {
        let fixture_path = fixtures_root.join(case.rel_path);
        if !fixture_path.exists() {
            eprintln!("[SKIP] missing fixture: {}", fixture_path.display());
            summary.push(format!(
                "[SKIP] {} ({}): fixture missing",
                case.pid, case.variant
            ));
            continue;
        }
        let edifact = std::fs::read_to_string(&fixture_path).expect("read fixture");

        let interchange: DynamicInterchange = match mapper
            .from_edifact::<serde_json::Value, mig_bo4e::DynamicTransaktion>(
                &edifact,
                case.fv,
                case.variant,
                case.pid,
            ) {
            Ok(i) => i,
            Err(e) => {
                eprintln!("[ERR] forward-map {} ({}): {e}", case.pid, case.variant);
                summary.push(format!("[ERR ] {} ({}): {e}", case.pid, case.variant));
                continue;
            }
        };

        let json = serde_json::to_string_pretty(&interchange).unwrap();
        let out_file = out_dir.join(format!(
            "{}_{}_{}.bo4e.json",
            case.variant,
            case.pid,
            Path::new(case.rel_path)
                .file_stem()
                .unwrap()
                .to_string_lossy()
        ));
        std::fs::write(&out_file, &json).expect("write output");
        summary.push(format!(
            "[ OK ] {} ({}): wrote {} ({} bytes)",
            case.pid,
            case.variant,
            out_file.file_name().unwrap().to_string_lossy(),
            json.len()
        ));
        println!(
            "[OK] {} ({})  →  {}",
            case.pid,
            case.variant,
            out_file.display()
        );
    }

    println!("\n--- SUMMARY ---");
    for line in &summary {
        println!("{line}");
    }
}