Skip to main content

nfe_parser/base/
totais.rs

1//! Totalização dos produtos e serviços
2//!
3//! Este módulo contém as estruturas para totalização dos valores da NF-e,
4//! incluindo todos os impostos e valores adicionais conforme layout 4.00.
5
6use super::Error;
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8use std::str::FromStr;
9
10/// Totalização da nota fiscal
11///
12/// Contém todos os totais calculados da NF-e, incluindo:
13/// - Totais de ICMS (próprio, ST, desonerado, FCP)
14/// - Totais de IPI
15/// - Totais de PIS/COFINS
16/// - Totais de Importação
17/// - Totais de DIFAL (partilha interestadual)
18/// - Totais de serviços (ISSQN)
19#[derive(Debug, PartialEq, Clone)]
20pub struct Totalizacao {
21    /// Base de cálculo do ICMS
22    pub valor_base_calculo: f32,
23    /// Valor total do ICMS
24    pub valor_icms: f32,
25    /// Valor total do ICMS desonerado
26    pub valor_icms_desonerado: f32,
27    /// Valor total do FCP (Fundo de Combate à Pobreza)
28    pub valor_fcp: f32,
29    /// Base de cálculo do ICMS ST
30    pub valor_base_calculo_st: f32,
31    /// Valor total do ICMS ST
32    pub valor_icms_st: f32,
33    /// Valor total do FCP retido por ST
34    pub valor_fcp_st: f32,
35    /// Valor total do FCP retido anteriormente por ST
36    pub valor_fcp_st_retido: f32,
37    /// Valor total dos produtos e serviços
38    pub valor_produtos: f32,
39    /// Valor total do frete
40    pub valor_frete: f32,
41    /// Valor total do seguro
42    pub valor_seguro: f32,
43    /// Valor total do desconto
44    pub valor_desconto: f32,
45    /// Outras despesas acessórias
46    pub valor_outros: f32,
47    /// Valor total do IPI
48    pub valor_ipi: f32,
49    /// Valor total do IPI devolvido
50    pub valor_ipi_devolvido: f32,
51    /// Valor total do Imposto de Importação
52    pub valor_ii: f32,
53    /// Valor total do PIS
54    pub valor_pis: f32,
55    /// Valor total do COFINS
56    pub valor_cofins: f32,
57    /// Valor total da nota
58    pub valor_total: f32,
59    /// Valor aproximado total de tributos (Lei 12.741/2012)
60    pub valor_aproximado_tributos: f32,
61
62    // Campos de DIFAL (partilha interestadual EC 87/2015)
63    /// Valor total do FCP UF Destino
64    pub valor_fcp_uf_dest: f32,
65    /// Valor total do ICMS UF Destino
66    pub valor_icms_uf_dest: f32,
67    /// Valor total do ICMS UF Remetente
68    pub valor_icms_uf_remet: f32,
69}
70
71impl FromStr for Totalizacao {
72    type Err = Error;
73
74    fn from_str(s: &str) -> Result<Self, Self::Err> {
75        quick_xml::de::from_str(s).map_err(|e| e.into())
76    }
77}
78
79impl ToString for Totalizacao {
80    fn to_string(&self) -> String {
81        quick_xml::se::to_string(self).expect("Falha ao serializar a totalização")
82    }
83}
84
85impl Default for Totalizacao {
86    fn default() -> Self {
87        Self {
88            valor_base_calculo: 0.0,
89            valor_icms: 0.0,
90            valor_icms_desonerado: 0.0,
91            valor_fcp: 0.0,
92            valor_base_calculo_st: 0.0,
93            valor_icms_st: 0.0,
94            valor_fcp_st: 0.0,
95            valor_fcp_st_retido: 0.0,
96            valor_produtos: 0.0,
97            valor_frete: 0.0,
98            valor_seguro: 0.0,
99            valor_desconto: 0.0,
100            valor_outros: 0.0,
101            valor_ipi: 0.0,
102            valor_ipi_devolvido: 0.0,
103            valor_ii: 0.0,
104            valor_pis: 0.0,
105            valor_cofins: 0.0,
106            valor_total: 0.0,
107            valor_aproximado_tributos: 0.0,
108            valor_fcp_uf_dest: 0.0,
109            valor_icms_uf_dest: 0.0,
110            valor_icms_uf_remet: 0.0,
111        }
112    }
113}
114
115impl Serialize for Totalizacao {
116    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
117    where
118        S: Serializer,
119    {
120        let icms = IcmsTot {
121            valor_base_calculo: self.valor_base_calculo,
122            valor_icms: self.valor_icms,
123            valor_icms_desonerado: self.valor_icms_desonerado,
124            valor_fcp: if self.valor_fcp > 0.0 {
125                Some(self.valor_fcp)
126            } else {
127                None
128            },
129            valor_base_calculo_st: self.valor_base_calculo_st,
130            valor_icms_st: self.valor_icms_st,
131            valor_fcp_st: if self.valor_fcp_st > 0.0 {
132                Some(self.valor_fcp_st)
133            } else {
134                None
135            },
136            valor_fcp_st_retido: if self.valor_fcp_st_retido > 0.0 {
137                Some(self.valor_fcp_st_retido)
138            } else {
139                None
140            },
141            valor_produtos: self.valor_produtos,
142            valor_frete: self.valor_frete,
143            valor_seguro: self.valor_seguro,
144            valor_desconto: self.valor_desconto,
145            valor_outros: self.valor_outros,
146            valor_ipi: self.valor_ipi,
147            valor_ipi_devolvido: if self.valor_ipi_devolvido > 0.0 {
148                Some(self.valor_ipi_devolvido)
149            } else {
150                None
151            },
152            valor_ii: self.valor_ii,
153            valor_pis: self.valor_pis,
154            valor_cofins: self.valor_cofins,
155            valor_total: self.valor_total,
156            valor_aproximado_tributos: self.valor_aproximado_tributos,
157            valor_fcp_uf_dest: if self.valor_fcp_uf_dest > 0.0 {
158                Some(self.valor_fcp_uf_dest)
159            } else {
160                None
161            },
162            valor_icms_uf_dest: if self.valor_icms_uf_dest > 0.0 {
163                Some(self.valor_icms_uf_dest)
164            } else {
165                None
166            },
167            valor_icms_uf_remet: if self.valor_icms_uf_remet > 0.0 {
168                Some(self.valor_icms_uf_remet)
169            } else {
170                None
171            },
172        };
173
174        let total = TotalContainer { icms };
175
176        total.serialize(serializer)
177    }
178}
179
180impl<'de> Deserialize<'de> for Totalizacao {
181    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
182    where
183        D: Deserializer<'de>,
184    {
185        let helper = TotalContainer::deserialize(deserializer)?;
186        Ok(Totalizacao {
187            valor_base_calculo: helper.icms.valor_base_calculo,
188            valor_icms: helper.icms.valor_icms,
189            valor_icms_desonerado: helper.icms.valor_icms_desonerado,
190            valor_fcp: helper.icms.valor_fcp.unwrap_or(0.0),
191            valor_base_calculo_st: helper.icms.valor_base_calculo_st,
192            valor_icms_st: helper.icms.valor_icms_st,
193            valor_fcp_st: helper.icms.valor_fcp_st.unwrap_or(0.0),
194            valor_fcp_st_retido: helper.icms.valor_fcp_st_retido.unwrap_or(0.0),
195            valor_produtos: helper.icms.valor_produtos,
196            valor_frete: helper.icms.valor_frete,
197            valor_seguro: helper.icms.valor_seguro,
198            valor_desconto: helper.icms.valor_desconto,
199            valor_outros: helper.icms.valor_outros,
200            valor_ipi: helper.icms.valor_ipi,
201            valor_ipi_devolvido: helper.icms.valor_ipi_devolvido.unwrap_or(0.0),
202            valor_ii: helper.icms.valor_ii,
203            valor_pis: helper.icms.valor_pis,
204            valor_cofins: helper.icms.valor_cofins,
205            valor_total: helper.icms.valor_total,
206            valor_aproximado_tributos: helper.icms.valor_aproximado_tributos,
207            valor_fcp_uf_dest: helper.icms.valor_fcp_uf_dest.unwrap_or(0.0),
208            valor_icms_uf_dest: helper.icms.valor_icms_uf_dest.unwrap_or(0.0),
209            valor_icms_uf_remet: helper.icms.valor_icms_uf_remet.unwrap_or(0.0),
210        })
211    }
212}
213
214#[derive(Deserialize, Serialize)]
215#[serde(rename = "total")]
216struct TotalContainer {
217    #[serde(rename = "ICMSTot")]
218    icms: IcmsTot,
219}
220
221#[derive(Deserialize, Serialize)]
222struct IcmsTot {
223    #[serde(rename = "$unflatten=vBC")]
224    valor_base_calculo: f32,
225
226    #[serde(rename = "$unflatten=vICMS")]
227    valor_icms: f32,
228
229    #[serde(rename = "$unflatten=vICMSDeson")]
230    #[serde(default)]
231    valor_icms_desonerado: f32,
232
233    #[serde(rename = "$unflatten=vFCP")]
234    #[serde(skip_serializing_if = "Option::is_none")]
235    valor_fcp: Option<f32>,
236
237    #[serde(rename = "$unflatten=vBCST")]
238    #[serde(default)]
239    valor_base_calculo_st: f32,
240
241    #[serde(rename = "$unflatten=vST")]
242    #[serde(default)]
243    valor_icms_st: f32,
244
245    #[serde(rename = "$unflatten=vFCPST")]
246    #[serde(skip_serializing_if = "Option::is_none")]
247    valor_fcp_st: Option<f32>,
248
249    #[serde(rename = "$unflatten=vFCPSTRet")]
250    #[serde(skip_serializing_if = "Option::is_none")]
251    valor_fcp_st_retido: Option<f32>,
252
253    #[serde(rename = "$unflatten=vProd")]
254    valor_produtos: f32,
255
256    #[serde(rename = "$unflatten=vFrete")]
257    valor_frete: f32,
258
259    #[serde(rename = "$unflatten=vSeg")]
260    valor_seguro: f32,
261
262    #[serde(rename = "$unflatten=vDesc")]
263    valor_desconto: f32,
264
265    #[serde(rename = "$unflatten=vOutro")]
266    valor_outros: f32,
267
268    #[serde(rename = "$unflatten=vII")]
269    #[serde(default)]
270    valor_ii: f32,
271
272    #[serde(rename = "$unflatten=vIPI")]
273    #[serde(default)]
274    valor_ipi: f32,
275
276    #[serde(rename = "$unflatten=vIPIDevol")]
277    #[serde(skip_serializing_if = "Option::is_none")]
278    valor_ipi_devolvido: Option<f32>,
279
280    #[serde(rename = "$unflatten=vPIS")]
281    valor_pis: f32,
282
283    #[serde(rename = "$unflatten=vCOFINS")]
284    valor_cofins: f32,
285
286    #[serde(rename = "$unflatten=vNF")]
287    valor_total: f32,
288
289    #[serde(rename = "$unflatten=vTotTrib")]
290    valor_aproximado_tributos: f32,
291
292    // Campos de DIFAL
293    #[serde(rename = "$unflatten=vFCPUFDest")]
294    #[serde(skip_serializing_if = "Option::is_none")]
295    valor_fcp_uf_dest: Option<f32>,
296
297    #[serde(rename = "$unflatten=vICMSUFDest")]
298    #[serde(skip_serializing_if = "Option::is_none")]
299    valor_icms_uf_dest: Option<f32>,
300
301    #[serde(rename = "$unflatten=vICMSUFRemet")]
302    #[serde(skip_serializing_if = "Option::is_none")]
303    valor_icms_uf_remet: Option<f32>,
304}