Skip to main content

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}