use crate::{AnyMessage, EdiEnergyMessage, EdiEnergyReport, Release};
#[derive(Debug, Clone)]
pub struct InterchangeHeader {
pub sender_id: Box<str>,
pub sender_qualifier: Box<str>,
pub receiver_id: Box<str>,
pub receiver_qualifier: Box<str>,
pub transmission_datetime: Option<time::OffsetDateTime>,
pub control_ref: Box<str>,
pub syntax_id: Box<str>,
pub syntax_version: u8,
}
impl InterchangeHeader {
#[must_use]
pub fn transmission_date(&self) -> Option<time::Date> {
self.transmission_datetime.map(time::OffsetDateTime::date)
}
}
#[derive(Debug, Clone)]
pub struct ReceiptContext<'m> {
pub original_sender: &'m str,
pub original_receiver: &'m str,
pub message_ref: &'m str,
pub release: Release,
pub transmission_date: Option<time::Date>,
}
#[derive(Debug)]
pub struct MessageEnvelope {
pub message: AnyMessage,
pub header: InterchangeHeader,
pub message_index: usize,
}
impl MessageEnvelope {
pub fn validate(&self) -> Result<EdiEnergyReport, crate::Error> {
EdiEnergyMessage::validate(&self.message)
}
#[must_use]
pub fn is_wire_code_acceptable_on(
&self,
date: time::Date,
registry: &crate::registry::ReleaseRegistry,
) -> bool {
let Some(mt) = self.message.try_message_type() else {
return false;
};
let Ok(release) = EdiEnergyMessage::detect_release(&self.message) else {
return false;
};
registry.is_acceptable_on(mt, release, date)
}
#[must_use]
pub fn is_wire_code_acceptable_on_global(&self, date: time::Date) -> bool {
self.is_wire_code_acceptable_on(date, crate::registry::ReleaseRegistry::global())
}
#[must_use]
pub fn sender_party_id(&self) -> Option<&str> {
extract_13digit_party_id(&self.header.sender_id)
}
#[must_use]
pub fn receiver_party_id(&self) -> Option<&str> {
extract_13digit_party_id(&self.header.receiver_id)
}
#[must_use]
pub fn transmission_date(&self) -> Option<time::Date> {
self.header.transmission_date()
}
#[must_use]
pub fn receipt_context(&self) -> ReceiptContext<'_> {
let release = EdiEnergyMessage::detect_release(&self.message)
.cloned()
.unwrap_or_else(|_| Release::new(""));
ReceiptContext {
original_sender: &self.header.sender_id,
original_receiver: &self.header.receiver_id,
message_ref: EdiEnergyMessage::message_ref(&self.message),
release,
transmission_date: self.header.transmission_date(),
}
}
}
#[derive(Debug)]
pub struct ParsedInterchange {
pub header: InterchangeHeader,
pub messages: Vec<MessageEnvelope>,
pub trailer_ref: Box<str>,
pub declared_message_count: usize,
}
impl ParsedInterchange {
#[must_use]
pub fn message_count(&self) -> usize {
self.messages.len()
}
#[must_use]
pub fn count_matches_declared(&self) -> bool {
self.messages.len() == self.declared_message_count
}
#[must_use]
pub fn control_refs_match(&self) -> bool {
self.trailer_ref == self.header.control_ref
}
#[must_use]
pub fn is_structurally_valid(&self) -> bool {
self.count_matches_declared() && self.control_refs_match()
}
}
fn extract_13digit_party_id(id: &str) -> Option<&str> {
if id.len() == 13 && id.bytes().all(|b| b.is_ascii_digit()) {
Some(id)
} else {
None
}
}