use std::marker::PhantomData;
use edifact_rs::Writer;
use crate::AgencyCode;
use crate::utilmd_codes::{
AntwortStatus, IDE_VORGANG, Produktpaket, STS_STATUS_ANTWORT, STS_TRANSAKTIONSGRUND,
Transaktionsgrund,
};
use crate::{Error, Lokationstyp, Pruefidentifikator, Release};
use super::{Set, Unset, bytes_to_segments};
#[derive(Debug, Clone, Default)]
struct UtilmdTransactionSpec {
ide_qualifier: String,
vorgangsnummer: String,
process_dates: Vec<(String, String)>,
transaktionsgrund: Option<Transaktionsgrund>,
antwort: Option<AntwortStatus>,
antwort_dritter: Option<crate::utilmd_codes::DritterAntwortStatus>,
free_texts: Vec<(String, String)>,
agr: Option<(String, String)>,
locations: Vec<(String, String)>,
summenzeitreihe_version: Option<String>,
references: Vec<(String, String)>,
referenz_vorgangsnummer: Option<String>,
dated_references: Vec<(String, String, String, String, String)>,
imd: Option<(String, String)>,
stammdaten: Vec<Sg8Block>,
addressed_nads: Vec<Anschrift>,
produktpakete: Vec<Produktpaket>,
merkmale: Vec<(String, String)>,
customer_nads: Vec<(String, String)>,
named_nads: Vec<(String, Vec<String>, String)>,
}
#[derive(Debug, Clone)]
struct Anschrift {
qualifier: String,
name_parts: Vec<String>,
name_format: String,
strasse: String,
ort: String,
plz: String,
land: String,
}
#[derive(Debug, Clone, Default)]
pub struct Sg8Block {
seq: String,
items: Vec<Sg8Item>,
}
#[derive(Debug, Clone)]
enum Sg8Item {
Cci { klassentyp: String, merkmal: String },
Cav {
code: String,
wert: String,
beschreibung: String,
zusatz: String,
},
Qty {
qualifier: String,
menge: String,
einheit: String,
},
Rff { qualifier: String, referenz: String },
}
#[derive(Debug, Clone)]
struct UtilmdBuilderInner {
release: Release,
pruefidentifikator: Option<Pruefidentifikator>,
sender_id: Option<String>,
receiver_id: Option<String>,
sender_agency: Option<AgencyCode>,
receiver_agency: Option<AgencyCode>,
message_ref: String,
document_code: String,
document_number: Option<String>,
gueltigkeit_beginn: Option<String>,
document_date: Option<String>,
rff_entries: Vec<(String, String)>,
transactions: Vec<UtilmdTransactionSpec>,
}
#[derive(Debug, Clone)]
#[must_use = "Builder must be consumed via .build() or .serialize()"]
pub struct UtilmdBuilder<S = Unset, R = Unset> {
_ph: PhantomData<fn() -> (S, R)>,
inner: UtilmdBuilderInner,
}
impl UtilmdBuilder<Unset, Unset> {
pub fn new(release: Release) -> Self {
Self {
_ph: PhantomData,
inner: UtilmdBuilderInner {
release,
pruefidentifikator: None,
sender_id: None,
receiver_id: None,
sender_agency: None,
receiver_agency: None,
message_ref: "1".to_owned(),
document_code: "E01".to_owned(),
document_number: None,
gueltigkeit_beginn: None,
document_date: None,
rff_entries: Vec::new(),
transactions: Vec::new(),
},
}
}
}
impl<S, R> UtilmdBuilder<S, R> {
fn transition<S2, R2>(self) -> UtilmdBuilder<S2, R2> {
UtilmdBuilder {
_ph: PhantomData,
inner: self.inner,
}
}
pub fn sender(mut self, id: impl Into<String>) -> UtilmdBuilder<Set, R> {
self.inner.sender_id = Some(id.into());
self.transition()
}
pub fn receiver(mut self, id: impl Into<String>) -> UtilmdBuilder<S, Set> {
self.inner.receiver_id = Some(id.into());
self.transition()
}
pub fn sender_agency(mut self, agency: crate::AgencyCode) -> Self {
self.inner.sender_agency = Some(agency);
self
}
pub fn receiver_agency(mut self, agency: crate::AgencyCode) -> Self {
self.inner.receiver_agency = Some(agency);
self
}
pub fn pruefidentifikator(mut self, pid: Pruefidentifikator) -> Self {
self.inner.pruefidentifikator = Some(pid);
self
}
pub fn message_ref(mut self, reference: impl Into<String>) -> Self {
self.inner.message_ref = reference.into();
self
}
pub fn document_code(mut self, code: impl Into<String>) -> Self {
self.inner.document_code = code.into();
self
}
pub fn document_number(mut self, number: impl Into<String>) -> Self {
self.inner.document_number = Some(number.into());
self
}
pub fn document_date(mut self, date: impl Into<String>) -> Self {
self.inner.document_date = Some(date.into());
self
}
pub fn rff(mut self, qualifier: impl Into<String>, reference: impl Into<String>) -> Self {
self.inner
.rff_entries
.push((qualifier.into(), reference.into()));
self
}
pub fn transaction(self, vorgangsnummer: impl Into<String>) -> UtilmdTransactionBuilder<S, R> {
self.transaction_with_qualifier(IDE_VORGANG, vorgangsnummer)
}
pub fn gueltigkeit_beginn(mut self, ccyymm: impl Into<String>) -> Self {
self.inner.gueltigkeit_beginn = Some(ccyymm.into());
self
}
pub fn list_transaction(self, list_id: impl Into<String>) -> UtilmdTransactionBuilder<S, R> {
self.transaction_with_qualifier(crate::utilmd_codes::IDE_LISTE, list_id)
}
pub fn transaction_with_qualifier(
self,
ide_qualifier: impl Into<String>,
vorgangsnummer: impl Into<String>,
) -> UtilmdTransactionBuilder<S, R> {
UtilmdTransactionBuilder {
parent: self,
spec: UtilmdTransactionSpec {
ide_qualifier: ide_qualifier.into(),
vorgangsnummer: vorgangsnummer.into(),
..Default::default()
},
}
}
}
fn emit_sg6<W: std::io::Write>(
w: &mut Writer<W>,
pid_str: &str,
tx: &UtilmdTransactionSpec,
carries_pid: bool,
) -> Result<(), Error> {
if carries_pid && !pid_str.is_empty() {
emit_comp!(w, "RFF", ["Z13", pid_str]);
}
if let Some(referenz) = &tx.referenz_vorgangsnummer {
emit_comp!(w, "RFF", ["TN", referenz]);
}
for (rff_q, rff_ref) in &tx.references {
if carries_pid && rff_q == "Z13" && rff_ref == pid_str {
continue;
}
emit_comp!(w, "RFF", [rff_q, rff_ref]);
}
for (rff_q, rff_ref, dtm_q, value, format) in &tx.dated_references {
emit_comp!(w, "RFF", [rff_q, rff_ref]);
emit_comp!(w, "DTM", [dtm_q, value, format]);
}
Ok(())
}
fn emit_sg8_block<W: std::io::Write>(w: &mut Writer<W>, block: &Sg8Block) -> Result<(), Error> {
emit_seg!(w, "SEQ", &block.seq);
for item in &block.items {
match item {
Sg8Item::Cci {
klassentyp,
merkmal,
} => emit_seg!(w, "CCI", klassentyp, "", merkmal),
Sg8Item::Cav {
code,
wert,
beschreibung,
zusatz,
} if wert.is_empty() && beschreibung.is_empty() && zusatz.is_empty() => {
emit_seg!(w, "CAV", code);
}
Sg8Item::Cav {
code,
wert,
beschreibung,
zusatz,
} if wert.is_empty() && zusatz.is_empty() => {
emit_comp!(w, "CAV", [code, "", "", beschreibung]);
}
Sg8Item::Cav {
code,
wert,
beschreibung,
zusatz,
} if beschreibung.is_empty() && zusatz.is_empty() => {
emit_comp!(w, "CAV", [code, wert]);
}
Sg8Item::Cav {
code,
wert,
beschreibung,
zusatz,
} if zusatz.is_empty() => emit_comp!(w, "CAV", [code, wert, "", beschreibung]),
Sg8Item::Cav {
code,
wert,
beschreibung,
zusatz,
} => emit_comp!(w, "CAV", [code, wert, "", beschreibung, zusatz]),
Sg8Item::Qty {
qualifier,
menge,
einheit,
} if einheit.is_empty() => {
emit_comp!(w, "QTY", [qualifier, menge]);
}
Sg8Item::Qty {
qualifier,
menge,
einheit,
} => emit_comp!(w, "QTY", [qualifier, menge, einheit]),
Sg8Item::Rff {
qualifier,
referenz,
} => emit_comp!(w, "RFF", [qualifier, referenz]),
}
}
Ok(())
}
fn sg8_ranks(release: &Release) -> std::collections::HashMap<String, usize> {
let mut ranks = std::collections::HashMap::new();
let Some(profile) = crate::ReleaseRegistry::global()
.profiles_for(crate::MessageType::Utilmd)
.find(|p| p.release() == release)
else {
return ranks;
};
for (rank, layout) in profile
.structure
.layouts
.iter()
.filter(|l| l.tag == "SEQ")
.enumerate()
{
if let Some(el) = layout.elements.first() {
for code in &el.codes {
ranks.entry(code.code.clone()).or_insert(rank);
}
}
}
ranks
}
fn emit_sg8_produktpakete<W: std::io::Write>(
w: &mut Writer<W>,
tx: &UtilmdTransactionSpec,
) -> Result<(), Error> {
use crate::utilmd_codes::produkt;
if let Some(version) = &tx.summenzeitreihe_version {
emit_seg!(w, "SEQ", crate::utilmd_codes::SEQ_SUMMENZEITREIHE);
emit_comp!(w, "RFF", [crate::utilmd_codes::RFF_ZEITREIHE, version]);
}
for paket in &tx.produktpakete {
for p in &paket.produkte {
emit_seg!(
w,
"SEQ",
produkt::SEQ_PRODUKTPAKET,
&paket.paket_id.to_string()
);
emit_comp!(
w,
"PIA",
[produkt::PIA_ERFORDERLICHES_PRODUKT],
[&p.produkt_code, produkt::PIA_TYP_PRODUKT]
);
emit_seg!(w, "CCI", produkt::CCI_PRODUKTEIGENSCHAFT);
if let Some(eigenschaft) = &p.eigenschaft {
emit_comp!(w, "CAV", [produkt::CAV_EIGENSCHAFT, "", "", eigenschaft]);
}
if let Some(wert) = &p.wert {
emit_comp!(w, "CAV", [produkt::CAV_WERT, "", "", wert]);
}
}
}
for (idx, paket) in tx.produktpakete.iter().enumerate() {
emit_seg!(
w,
"SEQ",
produkt::SEQ_PRIORISIERUNG,
&paket.paket_id.to_string()
);
emit_seg!(
w,
"CCI",
produkt::CCI_UMSETZUNGSGRAD,
"",
"",
paket.umsetzung.code()
);
if tx.produktpakete.len() > 1
&& let Some(prio) = produkt::PRIORITAET.get(idx)
{
emit_seg!(w, "CAV", prio);
}
}
Ok(())
}
fn emit_sg4<W: std::io::Write>(
w: &mut Writer<W>,
pid_str: &str,
tx: &UtilmdTransactionSpec,
carries_pid: bool,
ranks: &std::collections::HashMap<String, usize>,
) -> Result<(), Error> {
emit_seg!(w, "IDE", &tx.ide_qualifier, &tx.vorgangsnummer);
if let Some((produkt, beschreibung)) = &tx.imd {
emit_comp!(w, "IMD", [""], [produkt], [beschreibung]);
}
for (qualifier, date_val) in &tx.process_dates {
let fmt = sg4_dtm_format(qualifier);
let value = if fmt == "303" {
super::ccyymmddhhmm_utc(date_val)
} else {
date_val.clone()
};
emit_comp!(w, "DTM", [qualifier, &value, fmt]);
}
if let Some(grund) = &tx.transaktionsgrund {
let ergaenzung = grund.ergaenzung.as_deref().unwrap_or("");
match grund.befristet.as_deref() {
Some(befristet) => emit_seg!(
w,
"STS",
STS_TRANSAKTIONSGRUND,
"",
&grund.grund,
ergaenzung,
befristet
),
None if !ergaenzung.is_empty() => {
emit_seg!(
w,
"STS",
STS_TRANSAKTIONSGRUND,
"",
&grund.grund,
ergaenzung
);
}
None => emit_seg!(w, "STS", STS_TRANSAKTIONSGRUND, "", &grund.grund),
}
}
if let Some(antwort) = &tx.antwort {
if let Some(cl) = antwort.codeliste.as_deref() {
emit_comp!(w, "STS", [STS_STATUS_ANTWORT], [""], [&antwort.code, cl]);
} else {
emit_seg!(w, "STS", STS_STATUS_ANTWORT, "", &antwort.code);
}
}
if let Some(dritter) = &tx.antwort_dritter {
let referenz = dritter.referenz_lokation.as_deref().unwrap_or("");
if let Some(objekt) = dritter.objekt.as_deref() {
emit_comp!(
w,
"STS",
[crate::utilmd_codes::STS_ANTWORT_DRITTER],
[referenz],
[&dritter.code, &dritter.codeliste],
[objekt]
);
} else {
emit_comp!(
w,
"STS",
[crate::utilmd_codes::STS_ANTWORT_DRITTER],
[referenz],
[&dritter.code, &dritter.codeliste]
);
}
}
for (ftx_q, ftx_text) in &tx.free_texts {
emit_comp!(w, "FTX", [ftx_q], [""], [""], [ftx_text]);
}
if let Some((svc_req, resp_type)) = &tx.agr {
emit_comp!(w, "AGR", [svc_req, resp_type]);
}
for (loc_q, loc_id) in &tx.locations {
emit_comp!(w, "LOC", [loc_q], [loc_id]);
}
emit_sg6(w, pid_str, tx, carries_pid)?;
emit_sg8(w, tx, ranks)?;
emit_sg12(w, tx)?;
Ok(())
}
fn emit_sg12<W: std::io::Write>(
w: &mut Writer<W>,
tx: &UtilmdTransactionSpec,
) -> Result<(), Error> {
for (nad_q, parts, format) in &tx.named_nads {
let mut c080: Vec<&str> = parts.iter().map(String::as_str).take(5).collect();
c080.resize(5, "");
c080.push(format.as_str());
w.write_composites(
"NAD",
&[&[nad_q.as_str()][..], &[""][..], &[""][..], &c080[..]],
)
.map_err(Error::Parse)?;
}
for a in &tx.addressed_nads {
let mut c080: Vec<&str> = a.name_parts.iter().map(String::as_str).take(5).collect();
c080.resize(5, "");
c080.push(a.name_format.as_str());
w.write_composites(
"NAD",
&[
&[a.qualifier.as_str()][..],
&[""][..],
&[""][..],
&c080[..],
&[a.strasse.as_str()][..],
&[a.ort.as_str()][..],
&[""][..],
&[a.plz.as_str()][..],
&[a.land.as_str()][..],
],
)
.map_err(Error::Parse)?;
}
for (nad_q, nad_id) in &tx.customer_nads {
emit_comp!(
w,
"NAD",
[nad_q],
[nad_id, "", super::agency_for(None, nad_id)]
);
}
Ok(())
}
fn emit_sg8<W: std::io::Write>(
w: &mut Writer<W>,
tx: &UtilmdTransactionSpec,
ranks: &std::collections::HashMap<String, usize>,
) -> Result<(), Error> {
use crate::utilmd_codes::produkt;
let rank = |code: &str| ranks.get(code).copied().unwrap_or(usize::MAX);
let mut blocks: Vec<(usize, usize, Sg8Block)> = Vec::new();
let mut z01 = Sg8Block {
seq: crate::utilmd_codes::SEQ_DATEN_DER_MARKTLOKATION.to_owned(),
items: Vec::new(),
};
for (klassentyp, wert) in &tx.merkmale {
z01.items.push(Sg8Item::Cci {
klassentyp: klassentyp.clone(),
merkmal: wert.clone(),
});
}
for block in &tx.stammdaten {
if block.seq == z01.seq {
z01.items.extend(block.items.iter().cloned());
} else {
blocks.push((rank(&block.seq), blocks.len(), block.clone()));
}
}
if !z01.items.is_empty() {
blocks.push((rank(&z01.seq), blocks.len(), z01));
}
let produkt_rank =
rank(produkt::SEQ_PRODUKTPAKET).min(rank(crate::utilmd_codes::SEQ_SUMMENZEITREIHE));
blocks.sort_by_key(|(r, i, _)| (*r, *i));
let mut produkte_done = false;
for (r, _, block) in &blocks {
if !produkte_done && *r >= produkt_rank {
emit_sg8_produktpakete(w, tx)?;
produkte_done = true;
}
emit_sg8_block(w, block)?;
}
if !produkte_done {
emit_sg8_produktpakete(w, tx)?;
}
Ok(())
}
impl<S, R> UtilmdBuilder<S, R> {
fn to_bytes(&self) -> Result<Vec<u8>, Error> {
let pid_str = self
.inner
.pruefidentifikator
.map(|p| format!("{:05}", p.as_u32()))
.unwrap_or_default();
let dtm_val = self
.inner
.document_date
.as_deref()
.map_or_else(super::now_ccyymmddhhmm, str::to_owned);
let mut buf = Vec::new();
let mut w = Writer::new(&mut buf);
emit_comp!(
w,
"UNH",
[&self.inner.message_ref],
["UTILMD", "D", "11A", "UN", self.inner.release.as_str()]
);
let document_number = self
.inner
.document_number
.as_deref()
.unwrap_or(&self.inner.message_ref);
emit_seg!(w, "BGM", &self.inner.document_code, document_number);
emit_comp!(w, "DTM", ["137", &super::ccyymmddhhmm_utc(&dtm_val), "303"]);
if let Some(monat) = &self.inner.gueltigkeit_beginn {
emit_comp!(w, "DTM", ["157", monat, "610"]);
}
for (qualifier, reference) in &self.inner.rff_entries {
emit_comp!(w, "RFF", [qualifier, reference]);
}
if let Some(id) = &self.inner.sender_id {
emit_comp!(
w,
"NAD",
["MS"],
[id, "", super::agency_for(self.inner.sender_agency, id)]
);
}
if let Some(id) = &self.inner.receiver_id {
emit_comp!(
w,
"NAD",
["MR"],
[id, "", super::agency_for(self.inner.receiver_agency, id)]
);
}
let ist_liste = self
.inner
.transactions
.iter()
.any(|tx| tx.ide_qualifier == crate::utilmd_codes::IDE_LISTE);
let ranks = sg8_ranks(&self.inner.release);
for tx in &self.inner.transactions {
let carries_pid = !ist_liste || tx.ide_qualifier == crate::utilmd_codes::IDE_LISTE;
emit_sg4(&mut w, &pid_str, tx, carries_pid, &ranks)?;
}
w.finish_unt(&self.inner.message_ref)
.map_err(Error::Parse)?;
Ok(buf)
}
pub fn serialize(self) -> Result<Vec<u8>, Error> {
self.to_bytes()
}
}
impl UtilmdBuilder<Set, Set> {
pub fn build(self) -> Result<crate::messages::utilmd::UtilmdMessage, Error> {
let pid = self
.inner
.pruefidentifikator
.map(super::super::pruefidentifikator::Pruefidentifikator::as_u32);
let message_ref = self.inner.message_ref.clone();
let assoc_code = self.inner.release.as_str().to_owned();
let segments = bytes_to_segments(&self.to_bytes()?)?;
Ok(crate::messages::utilmd::UtilmdMessage::from_parts(
segments,
message_ref.as_str(),
assoc_code.as_str(),
pid,
))
}
}
#[derive(Debug)]
#[must_use = "Sub-builder must be finalized with .done()"]
pub struct UtilmdTransactionBuilder<S = Unset, R = Unset> {
parent: UtilmdBuilder<S, R>,
spec: UtilmdTransactionSpec,
}
impl<S, R> UtilmdTransactionBuilder<S, R> {
pub fn transaktionsgrund(mut self, grund: Transaktionsgrund) -> Self {
self.spec.transaktionsgrund = Some(grund);
self
}
pub fn antwort(mut self, antwort: AntwortStatus) -> Self {
self.spec.antwort = Some(antwort);
self
}
pub fn date(mut self, qualifier: impl Into<String>, value: impl Into<String>) -> Self {
self.spec
.process_dates
.push((qualifier.into(), value.into()));
self
}
pub fn location(mut self, lokationstyp: Lokationstyp, id: impl Into<String>) -> Self {
self.spec
.locations
.push((lokationstyp.qualifier_code().to_owned(), id.into()));
self
}
pub fn marktlokation(self, malo_id: impl Into<String>) -> Self {
self.location(Lokationstyp::Marktlokation, malo_id)
}
pub fn messlokation(self, melo_id: impl Into<String>) -> Self {
self.location(Lokationstyp::Messlokation, melo_id)
}
pub fn summenzeitreihe_version(mut self, version: impl Into<String>) -> Self {
self.spec.summenzeitreihe_version = Some(version.into());
self
}
pub fn referenz_vorgangsnummer(mut self, vorgangsnummer: impl Into<String>) -> Self {
self.spec.referenz_vorgangsnummer = Some(vorgangsnummer.into());
self
}
pub fn merkmal(mut self, klassentyp: impl Into<String>, wert: impl Into<String>) -> Self {
self.spec.merkmale.push((klassentyp.into(), wert.into()));
self
}
pub fn imd(mut self, produkt: impl Into<String>, beschreibung: impl Into<String>) -> Self {
self.spec.imd = Some((produkt.into(), beschreibung.into()));
self
}
pub fn reference_dated(
mut self,
qualifier: impl Into<String>,
referenz: impl Into<String>,
dtm_qualifier: impl Into<String>,
value: impl Into<String>,
format: impl Into<String>,
) -> Self {
self.spec.dated_references.push((
qualifier.into(),
referenz.into(),
dtm_qualifier.into(),
value.into(),
format.into(),
));
self
}
pub fn stammdaten(self, seq: impl Into<String>) -> Sg8Builder<S, R> {
Sg8Builder {
parent: self,
block: Sg8Block {
seq: seq.into(),
items: Vec::new(),
},
}
}
#[allow(clippy::too_many_arguments)]
pub fn anschrift(
mut self,
party_qualifier: impl Into<String>,
name_parts: impl IntoIterator<Item = String>,
name_format: impl Into<String>,
strasse: impl Into<String>,
ort: impl Into<String>,
plz: impl Into<String>,
land: impl Into<String>,
) -> Self {
self.spec.addressed_nads.push(Anschrift {
qualifier: party_qualifier.into(),
name_parts: name_parts.into_iter().collect(),
name_format: name_format.into(),
strasse: strasse.into(),
ort: ort.into(),
plz: plz.into(),
land: land.into(),
});
self
}
pub fn produktpaket(mut self, paket: Produktpaket) -> Self {
self.spec.produktpakete.push(paket);
self
}
pub fn geplantes_produktpaket(self, paket_id: impl Into<String>) -> Self {
self.reference(crate::utilmd_codes::rff::GEPLANTES_PRODUKTPAKET, paket_id)
}
pub fn reference(mut self, qualifier: impl Into<String>, ref_id: impl Into<String>) -> Self {
self.spec.references.push((qualifier.into(), ref_id.into()));
self
}
pub fn customer(mut self, party_qualifier: impl Into<String>, id: impl Into<String>) -> Self {
self.spec
.customer_nads
.push((party_qualifier.into(), id.into()));
self
}
pub fn named_party(
mut self,
party_qualifier: impl Into<String>,
name_parts: impl IntoIterator<Item = String>,
name_format: impl Into<String>,
) -> Self {
self.spec.named_nads.push((
party_qualifier.into(),
name_parts.into_iter().collect(),
name_format.into(),
));
self
}
pub fn kunde_des_lf(
self,
name_parts: impl IntoIterator<Item = String>,
name_format: impl Into<String>,
) -> Self {
self.named_party(
crate::utilmd_codes::nad::KUNDE_DES_LF,
name_parts,
name_format,
)
}
pub fn beteiligter_marktpartner(self, mp_id: impl Into<String>) -> Self {
self.customer(crate::utilmd_codes::nad::ZUGEHOERIGE_PARTEI, mp_id)
}
pub fn antwort_dritter(mut self, dritter: crate::utilmd_codes::DritterAntwortStatus) -> Self {
self.spec.antwort_dritter = Some(dritter);
self
}
pub fn free_text(mut self, text_function: impl Into<String>, text: impl Into<String>) -> Self {
self.spec
.free_texts
.push((text_function.into(), text.into()));
self
}
pub fn agr(
mut self,
service_requirement: impl Into<String>,
response_type: impl Into<String>,
) -> Self {
self.spec.agr = Some((service_requirement.into(), response_type.into()));
self
}
pub fn done(mut self) -> UtilmdBuilder<S, R> {
self.parent.inner.transactions.push(self.spec);
self.parent
}
}
fn sg4_dtm_format(qualifier: &str) -> &'static str {
match qualifier {
"154" => "102",
"Z10" => "106",
_ => "303",
}
}
#[derive(Debug)]
#[must_use = "Sub-builder must be finalized with .done()"]
pub struct Sg8Builder<S = Unset, R = Unset> {
parent: UtilmdTransactionBuilder<S, R>,
block: Sg8Block,
}
impl<S, R> Sg8Builder<S, R> {
pub fn cci(mut self, klassentyp: impl Into<String>, merkmal: impl Into<String>) -> Self {
self.block.items.push(Sg8Item::Cci {
klassentyp: klassentyp.into(),
merkmal: merkmal.into(),
});
self
}
pub fn cav(self, code: impl Into<String>) -> Self {
self.cav_wert(code, "")
}
pub fn zugeordneter_msb(
self,
mp_id: impl Into<String>,
rolle: impl Into<String>,
grundlage: impl Into<String>,
) -> Self {
self.cci("", crate::utilmd_codes::cci::ZUGEORDNETER_MARKTPARTNER)
.cav_msb(crate::utilmd_codes::cav::MSB, mp_id, rolle, grundlage)
}
pub fn grundzustaendiger_msb(self, mp_id: impl Into<String>) -> Self {
self.cav_wert_de1131(crate::utilmd_codes::cav::GMSB, mp_id)
}
pub fn cav_msb(
mut self,
code: impl Into<String>,
mp_id: impl Into<String>,
wert1: impl Into<String>,
wert2: impl Into<String>,
) -> Self {
self.block.items.push(Sg8Item::Cav {
code: code.into(),
wert: mp_id.into(),
beschreibung: wert1.into(),
zusatz: wert2.into(),
});
self
}
pub fn cav_wert_de1131(mut self, code: impl Into<String>, wert: impl Into<String>) -> Self {
self.block.items.push(Sg8Item::Cav {
code: code.into(),
wert: wert.into(),
beschreibung: String::new(),
zusatz: String::new(),
});
self
}
pub fn cav_components(
mut self,
code: impl Into<String>,
wert: impl Into<String>,
beschreibung: impl Into<String>,
) -> Self {
self.block.items.push(Sg8Item::Cav {
code: code.into(),
wert: wert.into(),
beschreibung: beschreibung.into(),
zusatz: String::new(),
});
self
}
pub fn cav_wert(mut self, code: impl Into<String>, wert: impl Into<String>) -> Self {
self.block.items.push(Sg8Item::Cav {
code: code.into(),
wert: String::new(),
beschreibung: wert.into(),
zusatz: String::new(),
});
self
}
pub fn qty(
mut self,
qualifier: impl Into<String>,
menge: impl Into<String>,
einheit: impl Into<String>,
) -> Self {
self.block.items.push(Sg8Item::Qty {
qualifier: qualifier.into(),
menge: menge.into(),
einheit: einheit.into(),
});
self
}
pub fn rff(mut self, qualifier: impl Into<String>, referenz: impl Into<String>) -> Self {
self.block.items.push(Sg8Item::Rff {
qualifier: qualifier.into(),
referenz: referenz.into(),
});
self
}
pub fn done(mut self) -> UtilmdTransactionBuilder<S, R> {
self.parent.spec.stammdaten.push(self.block);
self.parent
}
}