nfe_parser/base/item/imposto/ipi.rs
1//! IPI - Imposto sobre Produtos Industrializados
2//!
3//! Este módulo implementa as estruturas para representar o IPI na NF-e,
4//! conforme definido no layout 4.00 da SEFAZ.
5//!
6//! ## Códigos de Situação Tributária (CST) do IPI
7//!
8//! | CST | Descrição |
9//! |-----|-----------|
10//! | 00 | Entrada com recuperação de crédito |
11//! | 01 | Entrada tributada com alíquota zero |
12//! | 02 | Entrada isenta |
13//! | 03 | Entrada não tributada |
14//! | 04 | Entrada imune |
15//! | 05 | Entrada com suspensão |
16//! | 49 | Outras entradas |
17//! | 50 | Saída tributada |
18//! | 51 | Saída tributada com alíquota zero |
19//! | 52 | Saída isenta |
20//! | 53 | Saída não tributada |
21//! | 54 | Saída imune |
22//! | 55 | Saída com suspensão |
23//! | 99 | Outras saídas |
24
25use serde::{Deserialize, Serialize};
26
27/// Container para os grupos de IPI (tag `<IPI>`)
28///
29/// O IPI é informado através de grupos exclusivos, onde apenas UM grupo
30/// deve estar presente por item, dependendo do CST aplicável.
31#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
32pub struct IpiContainer {
33 /// Classe de enquadramento do IPI para Cigarros e Bebidas (opcional)
34 #[serde(rename = "$unflatten=clEnq")]
35 #[serde(skip_serializing_if = "Option::is_none")]
36 pub classe_enquadramento: Option<String>,
37
38 /// CNPJ do produtor da mercadoria, quando diferente do emitente
39 #[serde(rename = "$unflatten=CNPJProd")]
40 #[serde(skip_serializing_if = "Option::is_none")]
41 pub cnpj_produtor: Option<String>,
42
43 /// Código do selo de controle IPI
44 #[serde(rename = "$unflatten=cSelo")]
45 #[serde(skip_serializing_if = "Option::is_none")]
46 pub codigo_selo: Option<String>,
47
48 /// Quantidade de selo de controle
49 #[serde(rename = "$unflatten=qSelo")]
50 #[serde(skip_serializing_if = "Option::is_none")]
51 pub quantidade_selo: Option<u32>,
52
53 /// Código de Enquadramento Legal do IPI
54 #[serde(rename = "$unflatten=cEnq")]
55 pub codigo_enquadramento: String,
56
57 /// IPI tributado (CST 00, 49, 50, 99)
58 #[serde(rename = "IPITrib")]
59 #[serde(skip_serializing_if = "Option::is_none")]
60 pub ipi_trib: Option<IpiTrib>,
61
62 /// IPI não tributado (CST 01, 02, 03, 04, 05, 51, 52, 53, 54, 55)
63 #[serde(rename = "IPINT")]
64 #[serde(skip_serializing_if = "Option::is_none")]
65 pub ipi_nt: Option<IpiNt>,
66}
67
68/// IPI Tributado (tag `<IPITrib>`)
69///
70/// Usado para CSTs: 00, 49, 50, 99
71///
72/// ## Formas de Cálculo
73///
74/// **Por alíquota (ad valorem):**
75/// ```text
76/// vIPI = vBC × pIPI / 100
77/// ```
78///
79/// **Por quantidade (específico):**
80/// ```text
81/// vIPI = qUnid × vUnid
82/// ```
83#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
84pub struct IpiTrib {
85 /// Código de Situação Tributária do IPI
86 #[serde(rename = "$unflatten=CST")]
87 pub cst: String,
88
89 /// Valor da Base de Cálculo do IPI (cálculo por alíquota)
90 #[serde(rename = "$unflatten=vBC")]
91 #[serde(skip_serializing_if = "Option::is_none")]
92 pub valor_bc: Option<f32>,
93
94 /// Alíquota do IPI em percentual (cálculo por alíquota)
95 #[serde(rename = "$unflatten=pIPI")]
96 #[serde(skip_serializing_if = "Option::is_none")]
97 pub aliquota: Option<f32>,
98
99 /// Quantidade total na unidade padrão para tributação (cálculo por quantidade)
100 #[serde(rename = "$unflatten=qUnid")]
101 #[serde(skip_serializing_if = "Option::is_none")]
102 pub quantidade_unidade: Option<f32>,
103
104 /// Valor por unidade tributável (cálculo por quantidade)
105 #[serde(rename = "$unflatten=vUnid")]
106 #[serde(skip_serializing_if = "Option::is_none")]
107 pub valor_unidade: Option<f32>,
108
109 /// Valor do IPI
110 #[serde(rename = "$unflatten=vIPI")]
111 pub valor: f32,
112}
113
114/// IPI Não Tributado (tag `<IPINT>`)
115///
116/// Usado para CSTs: 01, 02, 03, 04, 05, 51, 52, 53, 54, 55
117#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
118pub struct IpiNt {
119 /// Código de Situação Tributária do IPI
120 #[serde(rename = "$unflatten=CST")]
121 pub cst: String,
122}
123
124impl Default for IpiContainer {
125 fn default() -> Self {
126 Self {
127 classe_enquadramento: None,
128 cnpj_produtor: None,
129 codigo_selo: None,
130 quantidade_selo: None,
131 codigo_enquadramento: "999".to_string(),
132 ipi_trib: None,
133 ipi_nt: None,
134 }
135 }
136}