use crate::Error;
#[derive(Debug, Clone)]
pub struct InterchangeBuilder {
sender: String,
receiver: String,
dar: String,
date: String,
time: String,
messages: Vec<Vec<u8>>,
}
impl InterchangeBuilder {
pub fn new(
sender: impl Into<String>,
receiver: impl Into<String>,
dar: impl Into<String>,
) -> Self {
Self {
sender: sender.into(),
receiver: receiver.into(),
dar: dar.into(),
date: "000000".to_owned(),
time: "0000".to_owned(),
messages: Vec::new(),
}
}
#[must_use]
pub fn transmission(mut self, date: impl Into<String>, time: impl Into<String>) -> Self {
self.date = date.into();
self.time = time.into();
self
}
#[must_use]
pub fn message(mut self, bytes: Vec<u8>) -> Self {
self.messages.push(bytes);
self
}
pub fn build(self) -> Result<Vec<u8>, Error> {
let payload_len: usize = self.messages.iter().map(Vec::len).sum();
let mut w = edifact_rs::Writer::new(Vec::with_capacity(payload_len + 96));
w.write_composites(
"UNB",
&[
&["UNOC", "3"],
&[&self.sender, unb_qualifier(&self.sender)],
&[&self.receiver, unb_qualifier(&self.receiver)],
&[&self.date, &self.time],
&[&self.dar],
],
)
.map_err(|e| Error::Serialize(format!("UNB envelope: {e}")))?;
let mut bytes = w
.finish()
.map_err(|e| Error::Serialize(format!("UNB envelope: {e}")))?;
for m in &self.messages {
bytes.extend_from_slice(m);
}
let count = self.messages.len().to_string();
let mut w = edifact_rs::Writer::new(bytes);
w.write_composites("UNZ", &[&[count.as_str()], &[&self.dar]])
.map_err(|e| Error::Serialize(format!("UNZ envelope: {e}")))?;
w.finish()
.map_err(|e| Error::Serialize(format!("UNZ envelope: {e}")))
}
}
#[must_use]
pub fn unb_qualifier(mp_id: &str) -> &'static str {
if mp_id.len() == 13 && mp_id.starts_with("99") {
"500"
} else if mp_id.len() == 13 && mp_id.starts_with("98") {
"502"
} else if mp_id.len() == 13 {
"14"
} else {
"500"
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn qualifier_per_af61d() {
assert_eq!(unb_qualifier("9900123456789"), "500");
assert_eq!(unb_qualifier("9870123456789"), "502");
assert_eq!(unb_qualifier("4012345000023"), "14");
assert_eq!(unb_qualifier("10XDE-EON-NETZ-I"), "500");
}
#[test]
fn unz_count_follows_the_payload() {
let wire = InterchangeBuilder::new("9900123456789", "9900987654321", "R1")
.message(b"UNH+1+X'UNT+2+1'".to_vec())
.message(b"UNH+2+X'UNT+2+2'".to_vec())
.build()
.unwrap();
let text = String::from_utf8(wire).unwrap();
assert!(text.ends_with("UNZ+2+R1'"), "{text}");
}
#[test]
fn empty_interchange_declares_zero_messages() {
let wire = InterchangeBuilder::new("9900123456789", "9900987654321", "R1")
.build()
.unwrap();
let text = String::from_utf8(wire).unwrap();
assert!(text.ends_with("UNZ+0+R1'"), "{text}");
}
}