1use super::emit::build_address_fields;
5use super::tax_id::TaxId;
6use crate::format_utils::format_cents;
7use crate::types::*;
8use crate::xml_utils::{TagContent, tag};
9
10pub fn build_cobr(billing: &BillingData) -> String {
12 let fc2 = |c: i64| format_cents(c, 2);
13 let mut children = Vec::new();
14
15 if let Some(ref inv) = billing.invoice {
16 let mut fat_children = vec![
17 tag("nFat", &[], TagContent::Text(&inv.number)),
18 tag("vOrig", &[], TagContent::Text(&fc2(inv.original_value.0))),
19 ];
20 if let Some(disc) = inv.discount_value {
21 fat_children.push(tag("vDesc", &[], TagContent::Text(&fc2(disc.0))));
22 }
23 fat_children.push(tag("vLiq", &[], TagContent::Text(&fc2(inv.net_value.0))));
24 children.push(tag("fat", &[], TagContent::Children(fat_children)));
25 }
26
27 if let Some(ref installments) = billing.installments {
28 for inst in installments {
29 children.push(tag(
30 "dup",
31 &[],
32 TagContent::Children(vec![
33 tag("nDup", &[], TagContent::Text(&inst.number)),
34 tag("dVenc", &[], TagContent::Text(&inst.due_date)),
35 tag("vDup", &[], TagContent::Text(&fc2(inst.value.0))),
36 ]),
37 ));
38 }
39 }
40
41 tag("cobr", &[], TagContent::Children(children))
42}
43
44pub(crate) fn build_inf_adic(data: &InvoiceBuildData) -> String {
46 let mut notes: Vec<String> = Vec::new();
47
48 if let Some(ref cont) = data.contingency {
49 notes.push(format!(
50 "Emitida em contingencia ({}). Motivo: {}",
51 cont.contingency_type.as_str(),
52 cont.reason
53 ));
54 }
55
56 if data.environment == SefazEnvironment::Homologation {
57 notes.push("EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL".to_string());
58 }
59
60 let add_info = data.additional_info.as_ref();
61 let has_additional = add_info.is_some_and(|a| {
62 a.taxpayer_note.is_some()
63 || a.tax_authority_note.is_some()
64 || a.contributor_obs.as_ref().is_some_and(|v| !v.is_empty())
65 || a.fiscal_obs.as_ref().is_some_and(|v| !v.is_empty())
66 || a.process_refs.as_ref().is_some_and(|v| !v.is_empty())
67 });
68
69 if notes.is_empty() && !has_additional {
70 return String::new();
71 }
72
73 let mut children = Vec::new();
74
75 if let Some(note) = add_info.and_then(|a| a.tax_authority_note.as_ref()) {
77 children.push(tag("infAdFisco", &[], TagContent::Text(note)));
78 }
79
80 if let Some(tn) = add_info.and_then(|a| a.taxpayer_note.as_ref()) {
82 notes.push(tn.to_string());
83 }
84 if !notes.is_empty() {
85 children.push(tag("infCpl", &[], TagContent::Text(¬es.join("; "))));
86 }
87
88 if let Some(obs_list) = add_info.and_then(|a| a.contributor_obs.as_ref()) {
90 for obs in obs_list.iter().take(10) {
91 children.push(tag(
92 "obsCont",
93 &[("xCampo", &obs.field)],
94 TagContent::Children(vec![tag("xTexto", &[], TagContent::Text(&obs.text))]),
95 ));
96 }
97 }
98
99 if let Some(obs_list) = add_info.and_then(|a| a.fiscal_obs.as_ref()) {
101 for obs in obs_list.iter().take(10) {
102 children.push(tag(
103 "obsFisco",
104 &[("xCampo", &obs.field)],
105 TagContent::Children(vec![tag("xTexto", &[], TagContent::Text(&obs.text))]),
106 ));
107 }
108 }
109
110 if let Some(procs) = add_info.and_then(|a| a.process_refs.as_ref()) {
112 for p in procs.iter().take(100) {
113 children.push(tag(
114 "procRef",
115 &[],
116 TagContent::Children(vec![
117 tag("nProc", &[], TagContent::Text(&p.number)),
118 tag("indProc", &[], TagContent::Text(&p.origin)),
119 ]),
120 ));
121 }
122 }
123
124 tag("infAdic", &[], TagContent::Children(children))
125}
126
127pub fn build_intermediary(intermed: &IntermediaryData) -> String {
129 let mut children = vec![tag("CNPJ", &[], TagContent::Text(&intermed.tax_id))];
130 if let Some(ref id) = intermed.id_cad_int_tran {
131 children.push(tag("idCadIntTran", &[], TagContent::Text(id)));
132 }
133 tag("infIntermed", &[], TagContent::Children(children))
134}
135
136pub fn build_tech_responsible(tech: &TechResponsibleData) -> String {
138 let mut children = vec![
139 tag("CNPJ", &[], TagContent::Text(&tech.tax_id)),
140 tag("xContato", &[], TagContent::Text(&tech.contact)),
141 tag("email", &[], TagContent::Text(&tech.email)),
142 ];
143 if let Some(ref phone) = tech.phone {
144 children.push(tag("fone", &[], TagContent::Text(phone)));
145 }
146 tag("infRespTec", &[], TagContent::Children(children))
147}
148
149pub fn build_purchase(purchase: &PurchaseData) -> String {
151 let mut children = Vec::new();
152 if let Some(ref note) = purchase.purchase_note {
153 children.push(tag("xNEmp", &[], TagContent::Text(note)));
154 }
155 if let Some(ref order) = purchase.order_number {
156 children.push(tag("xPed", &[], TagContent::Text(order)));
157 }
158 if let Some(ref contract) = purchase.contract_number {
159 children.push(tag("xCont", &[], TagContent::Text(contract)));
160 }
161 tag("compra", &[], TagContent::Children(children))
162}
163
164pub fn build_export(exp: &ExportData) -> String {
166 let mut children = vec![
167 tag("UFSaidaPais", &[], TagContent::Text(&exp.exit_state)),
168 tag("xLocExporta", &[], TagContent::Text(&exp.export_location)),
169 ];
170 if let Some(ref dispatch) = exp.dispatch_location {
171 children.push(tag("xLocDespacho", &[], TagContent::Text(dispatch)));
172 }
173 tag("exporta", &[], TagContent::Children(children))
174}
175
176pub fn build_withdrawal(w: &LocationData) -> String {
178 let tid = TaxId::new(&w.tax_id);
179 let padded = tid.padded();
180 let mut children = vec![tag(tid.tag_name(), &[], TagContent::Text(&padded))];
181 if let Some(ref name) = w.name {
182 children.push(tag("xNome", &[], TagContent::Text(name)));
183 }
184 children.extend(build_address_fields(
185 &w.street,
186 &w.number,
187 w.complement.as_deref(),
188 &w.district,
189 &w.city_code.0,
190 &w.city_name,
191 &w.state_code,
192 w.zip_code.as_deref(),
193 false,
194 ));
195 tag("retirada", &[], TagContent::Children(children))
196}
197
198pub fn build_delivery(d: &LocationData) -> String {
200 let tid = TaxId::new(&d.tax_id);
201 let padded = tid.padded();
202 let mut children = vec![tag(tid.tag_name(), &[], TagContent::Text(&padded))];
203 if let Some(ref name) = d.name {
204 children.push(tag("xNome", &[], TagContent::Text(name)));
205 }
206 children.extend(build_address_fields(
207 &d.street,
208 &d.number,
209 d.complement.as_deref(),
210 &d.district,
211 &d.city_code.0,
212 &d.city_name,
213 &d.state_code,
214 d.zip_code.as_deref(),
215 false,
216 ));
217 tag("entrega", &[], TagContent::Children(children))
218}
219
220pub fn build_aut_xml(entry: &AuthorizedXml) -> String {
222 let tid = TaxId::new(&entry.tax_id);
223 let padded = tid.padded();
224 tag(
225 "autXML",
226 &[],
227 TagContent::Children(vec![tag(tid.tag_name(), &[], TagContent::Text(&padded))]),
228 )
229}