pub(crate) mod core;
#[cfg(any(
feature = "utilmd",
feature = "mscons",
feature = "aperak",
feature = "contrl",
feature = "invoic",
feature = "remadv",
feature = "orders",
feature = "iftsta",
feature = "insrpt",
feature = "reqote",
feature = "partin",
feature = "ordchg",
feature = "ordrsp",
feature = "quotes",
feature = "comdis",
feature = "pricat",
feature = "utilts",
))]
macro_rules! impl_edi_energy_message {
($ty:ty) => {
impl crate::EdiEnergyMessage for $ty {
fn try_message_type(&self) -> Option<crate::MessageType> {
Some(self.core.message_type())
}
fn detect_release(&self) -> Result<&crate::Release, crate::Error> {
self.core.detect_release()
}
fn message_ref(&self) -> &str {
&self.core.message_ref
}
fn detect_pruefidentifikator(&self) -> Result<crate::Pruefidentifikator, crate::Error> {
self.core.detect_pruefidentifikator()
}
fn validate(&self) -> Result<crate::EdiEnergyReport, crate::Error> {
let release = self.core.detect_release()?;
self.core.validate_against_with_semantic(&release, None)
}
fn validate_against(
&self,
release: &crate::Release,
) -> Result<crate::EdiEnergyReport, crate::Error> {
self.core.validate_against_with_semantic(release, None)
}
fn validate_with_pack(
&self,
extra: crate::CustomRulePack,
) -> Result<crate::EdiEnergyReport, crate::Error> {
self.core.validate_with_extra_pack(None, extra.into_inner())
}
fn validate_on_date(
&self,
reference_date: time::Date,
) -> Result<crate::EdiEnergyReport, crate::Error> {
let release = self.core.detect_release()?;
self.core
.validate_against_with_semantic_and_registry_on_date(
&release,
None,
crate::registry::ReleaseRegistry::global(),
Some(reference_date),
)
}
fn serialize(&self) -> Result<Vec<u8>, crate::Error> {
self.core.serialize()
}
fn segments(&self) -> &[edifact_rs::OwnedSegment] {
&self.core.segments
}
}
};
($ty:ty, sem = $pack:expr) => {
impl crate::EdiEnergyMessage for $ty {
fn try_message_type(&self) -> Option<crate::MessageType> {
Some(self.core.message_type())
}
fn detect_release(&self) -> Result<&crate::Release, crate::Error> {
self.core.detect_release()
}
fn message_ref(&self) -> &str {
&self.core.message_ref
}
fn detect_pruefidentifikator(&self) -> Result<crate::Pruefidentifikator, crate::Error> {
self.core.detect_pruefidentifikator()
}
fn validate(&self) -> Result<crate::EdiEnergyReport, crate::Error> {
let release = self.core.detect_release()?;
self.core
.validate_against_with_semantic(&release, Some($pack))
}
fn validate_against(
&self,
release: &crate::Release,
) -> Result<crate::EdiEnergyReport, crate::Error> {
self.core
.validate_against_with_semantic(release, Some($pack))
}
fn validate_with_pack(
&self,
extra: crate::CustomRulePack,
) -> Result<crate::EdiEnergyReport, crate::Error> {
self.core
.validate_with_extra_pack(Some($pack), extra.into_inner())
}
fn validate_on_date(
&self,
reference_date: time::Date,
) -> Result<crate::EdiEnergyReport, crate::Error> {
let release = self.core.detect_release()?;
self.core
.validate_against_with_semantic_and_registry_on_date(
&release,
Some($pack),
crate::registry::ReleaseRegistry::global(),
Some(reference_date),
)
}
fn serialize(&self) -> Result<Vec<u8>, crate::Error> {
self.core.serialize()
}
fn segments(&self) -> &[edifact_rs::OwnedSegment] {
&self.core.segments
}
}
};
}
#[cfg(any(
feature = "utilmd",
feature = "mscons",
feature = "aperak",
feature = "contrl",
feature = "invoic",
feature = "remadv",
feature = "orders",
feature = "iftsta",
feature = "insrpt",
feature = "reqote",
feature = "partin",
feature = "ordchg",
feature = "ordrsp",
feature = "quotes",
feature = "comdis",
feature = "pricat",
feature = "utilts",
))]
pub mod segments;
#[cfg(feature = "aperak")]
pub mod aperak;
#[cfg(feature = "comdis")]
pub mod comdis;
#[cfg(feature = "contrl")]
pub mod contrl;
#[cfg(feature = "iftsta")]
pub mod iftsta;
#[cfg(feature = "insrpt")]
pub mod insrpt;
#[cfg(feature = "invoic")]
pub mod invoic;
#[cfg(feature = "mscons")]
pub mod mscons;
#[cfg(feature = "ordchg")]
pub mod ordchg;
#[cfg(feature = "orders")]
pub mod orders;
#[cfg(feature = "ordrsp")]
pub mod ordrsp;
#[cfg(feature = "partin")]
pub mod partin;
#[cfg(feature = "pricat")]
pub mod pricat;
#[cfg(feature = "quotes")]
pub mod quotes;
#[cfg(feature = "remadv")]
pub mod remadv;
#[cfg(feature = "reqote")]
pub mod reqote;
#[cfg(feature = "utilmd")]
pub mod utilmd;
#[cfg(feature = "utilts")]
pub mod utilts;
#[cfg(any(
feature = "mscons",
feature = "utilmd",
feature = "orders",
feature = "insrpt",
feature = "invoic",
feature = "remadv",
))]
pub(super) mod common {
#[inline]
pub(super) fn is_valid_malo_id(id: &str) -> bool {
id.len() == 11
&& id
.bytes()
.all(|b| b.is_ascii_uppercase() || b.is_ascii_digit())
}
#[inline]
pub(super) fn is_valid_melo_id(id: &str) -> bool {
id.len() == 33
&& id.bytes().take(2).all(|b| b.is_ascii_uppercase())
&& id.bytes().skip(2).all(|b| b.is_ascii_alphanumeric())
}
#[inline]
pub(super) fn is_valid_location_id(id: &str) -> bool {
is_valid_malo_id(id) || is_valid_melo_id(id)
}
#[cfg(any(
feature = "insrpt",
feature = "remadv",
feature = "orders",
feature = "invoic",
))]
pub(super) fn check_period_order(
segments: &[edifact_rs::Segment<'_>],
rule_id: &'static str,
issues: &mut Vec<edifact_rs::ValidationIssue>,
) {
let mut start: Option<(&str, edifact_rs::Span)> = None;
let mut end: Option<(&str, edifact_rs::Span)> = None;
for seg in segments.iter().filter(|s| s.tag == "DTM") {
let Some(c507) = seg.get_element(0) else {
continue;
};
let qualifier = c507.get_component(0).unwrap_or("");
let value = c507.get_component(1).unwrap_or("");
match qualifier {
"163" => start = Some((value, seg.span)),
"164" => end = Some((value, seg.span)),
_ => {}
}
}
if let (Some((start_val, start_span)), Some((end_val, _))) = (start, end) {
if !start_val.is_empty() && !end_val.is_empty() && start_val > end_val {
issues.push(
edifact_rs::ValidationIssue::new(
edifact_rs::ValidationSeverity::Error,
"DTM: period-start (qualifier 163) is after period-end (qualifier 164)"
.to_owned(),
)
.with_span(start_span)
.with_rule_id(rule_id)
.with_segment("DTM")
.with_suggestion(
"Ensure DTM+163 (Beginn Lieferzeitraum) is not later than \
DTM+164 (Ende Lieferzeitraum) \u{2014} date values must be in \
ascending chronological order",
),
);
}
}
}
}