Skip to main content

fiscal_core/xml_builder/
emit.rs

1//! Build the `<emit>` (issuer/emitter) group of the NF-e XML.
2
3use super::tax_id::TaxId;
4use crate::types::InvoiceBuildData;
5use crate::xml_utils::{TagContent, tag};
6
7/// Build the `<emit>` element with issuer data and address.
8pub(crate) fn build_emit(data: &InvoiceBuildData) -> String {
9    let iss = &data.issuer;
10    let tid = TaxId::new(&iss.tax_id);
11
12    let mut children = vec![
13        tag(tid.tag_name(), &[], TagContent::Text(&iss.tax_id)),
14        tag("xNome", &[], TagContent::Text(&iss.company_name)),
15    ];
16
17    if let Some(ref trade_name) = iss.trade_name {
18        children.push(tag("xFant", &[], TagContent::Text(trade_name)));
19    }
20
21    children.push(tag(
22        "enderEmit",
23        &[],
24        TagContent::Children(build_address_fields(
25            &iss.street,
26            &iss.street_number,
27            iss.address_complement.as_deref(),
28            &iss.district,
29            &iss.city_code.0,
30            &iss.city_name,
31            &iss.state_code,
32            Some(&iss.zip_code),
33            true,
34            iss.phone.as_deref(),
35        )),
36    ));
37    children.push(tag("IE", &[], TagContent::Text(&iss.state_tax_id)));
38
39    if let Some(ref iest) = iss.iest {
40        children.push(tag("IEST", &[], TagContent::Text(iest)));
41    }
42    if let Some(ref im) = iss.im {
43        children.push(tag("IM", &[], TagContent::Text(im)));
44        if let Some(ref cnae) = iss.cnae {
45            children.push(tag("CNAE", &[], TagContent::Text(cnae)));
46        }
47    }
48
49    children.push(tag(
50        "CRT",
51        &[],
52        TagContent::Text(&(iss.tax_regime as u8).to_string()),
53    ));
54
55    tag("emit", &[], TagContent::Children(children))
56}
57
58/// Build address child tags (xLgr … fone), reused for emit/dest/retirada/entrega.
59#[allow(clippy::too_many_arguments)]
60pub fn build_address_fields(
61    street: &str,
62    number: &str,
63    complement: Option<&str>,
64    district: &str,
65    city_code: &str,
66    city_name: &str,
67    state_code: &str,
68    zip_code: Option<&str>,
69    include_country: bool,
70    phone: Option<&str>,
71) -> Vec<String> {
72    let mut fields = vec![
73        tag("xLgr", &[], TagContent::Text(street)),
74        tag("nro", &[], TagContent::Text(number)),
75    ];
76    if let Some(cpl) = complement {
77        fields.push(tag("xCpl", &[], TagContent::Text(cpl)));
78    }
79    fields.extend([
80        tag("xBairro", &[], TagContent::Text(district)),
81        tag("cMun", &[], TagContent::Text(city_code)),
82        tag("xMun", &[], TagContent::Text(city_name)),
83        tag("UF", &[], TagContent::Text(state_code)),
84    ]);
85    if let Some(cep) = zip_code {
86        fields.push(tag("CEP", &[], TagContent::Text(cep)));
87    }
88    if include_country {
89        fields.push(tag("cPais", &[], TagContent::Text("1058")));
90        fields.push(tag("xPais", &[], TagContent::Text("Brasil")));
91    }
92    if let Some(fone) = phone {
93        fields.push(tag("fone", &[], TagContent::Text(fone)));
94    }
95    fields
96}