1use crate::sealed::private::Sealed;
4use crate::tax_element::{TaxElement, serialize_tax_element};
5use crate::tax_icms::{IcmsVariant, build_icms_xml, create_icms_totals};
6use crate::tax_is::{IsData, build_is_xml};
7use crate::tax_issqn::{IssqnData, build_issqn_xml};
8use crate::tax_pis_cofins_ipi::{
9 CofinsData, IiData, IpiData, PisData, build_cofins_xml, build_ii_xml, build_ipi_xml,
10 build_pis_xml,
11};
12
13pub trait TaxCalculation: Sealed {
20 fn build_xml(&self) -> String;
22}
23
24impl Sealed for IcmsVariant {}
25impl TaxCalculation for IcmsVariant {
26 fn build_xml(&self) -> String {
32 let mut totals = create_icms_totals();
33 build_icms_xml(self, &mut totals).unwrap_or_default()
34 }
35}
36
37impl Sealed for PisData {}
38impl TaxCalculation for PisData {
39 fn build_xml(&self) -> String {
41 build_pis_xml(self)
42 }
43}
44
45impl Sealed for CofinsData {}
46impl TaxCalculation for CofinsData {
47 fn build_xml(&self) -> String {
49 build_cofins_xml(self)
50 }
51}
52
53impl Sealed for IpiData {}
54impl TaxCalculation for IpiData {
55 fn build_xml(&self) -> String {
57 build_ipi_xml(self)
58 }
59}
60
61impl Sealed for IiData {}
62impl TaxCalculation for IiData {
63 fn build_xml(&self) -> String {
65 build_ii_xml(self)
66 }
67}
68
69impl Sealed for IssqnData {}
70impl TaxCalculation for IssqnData {
71 fn build_xml(&self) -> String {
73 build_issqn_xml(self)
74 }
75}
76
77impl Sealed for IsData {}
78impl TaxCalculation for IsData {
79 fn build_xml(&self) -> String {
81 build_is_xml(self)
82 }
83}
84
85pub trait XmlSerializable: Sealed {
91 fn to_xml(&self) -> String;
93}
94
95impl Sealed for TaxElement {}
96impl XmlSerializable for TaxElement {
97 fn to_xml(&self) -> String {
99 serialize_tax_element(self)
100 }
101}
102
103#[cfg(test)]
106mod tests {
107 use super::*;
108 use crate::newtypes::{Cents, Rate, Rate4};
109 use crate::tax_element::TaxField;
110 use crate::tax_icms::{IcmsCst, IcmsVariant};
111 use crate::tax_is::IsData;
112 use crate::tax_issqn::IssqnData;
113 use crate::tax_pis_cofins_ipi::{CofinsData, IiData, IpiData, PisData};
114
115 #[test]
118 fn icms_variant_trait_matches_free_fn() {
119 let cst = IcmsCst::Cst00 {
120 orig: "0".to_string(),
121 mod_bc: "3".to_string(),
122 v_bc: Cents(10000),
123 p_icms: Rate(1200),
124 v_icms: Cents(1200),
125 p_fcp: None,
126 v_fcp: None,
127 };
128 let variant = IcmsVariant::from(cst);
129
130 let mut totals = create_icms_totals();
131 let expected = build_icms_xml(&variant, &mut totals).unwrap();
132 let got = variant.build_xml();
133 assert_eq!(got, expected);
134 }
135
136 #[test]
139 fn pis_data_trait_matches_free_fn() {
140 let data = PisData::new("01")
141 .v_bc(Cents(10000))
142 .p_pis(Rate4(16500))
143 .v_pis(Cents(165));
144
145 assert_eq!(data.build_xml(), build_pis_xml(&data));
146 }
147
148 #[test]
151 fn cofins_data_trait_matches_free_fn() {
152 let data = CofinsData::new("01")
153 .v_bc(Cents(10000))
154 .p_cofins(Rate4(76000))
155 .v_cofins(Cents(760));
156
157 assert_eq!(data.build_xml(), build_cofins_xml(&data));
158 }
159
160 #[test]
163 fn ipi_data_trait_matches_free_fn() {
164 let data = IpiData::new("00", "999")
165 .v_bc(Cents(10000))
166 .p_ipi(Rate(500))
167 .v_ipi(Cents(500));
168
169 assert_eq!(data.build_xml(), build_ipi_xml(&data));
170 }
171
172 #[test]
175 fn ii_data_trait_matches_free_fn() {
176 let data = IiData::new(Cents(10000), Cents(200), Cents(1000), Cents(50));
177
178 assert_eq!(data.build_xml(), build_ii_xml(&data));
179 }
180
181 #[test]
184 fn issqn_data_trait_matches_free_fn() {
185 let data = IssqnData::new(10000, 500, 500, "4106902", "01.01");
186
187 assert_eq!(data.build_xml(), build_issqn_xml(&data));
188 }
189
190 #[test]
193 fn is_data_trait_matches_free_fn() {
194 let data = IsData::new("00", "1234", "5.00")
195 .v_bc_is("100.00")
196 .p_is("5.0000");
197
198 assert_eq!(data.build_xml(), build_is_xml(&data));
199 }
200
201 #[test]
204 fn tax_element_trait_matches_free_fn() {
205 let element = TaxElement {
206 outer_tag: Some("PIS".to_string()),
207 outer_fields: vec![],
208 variant_tag: "PISAliq".to_string(),
209 fields: vec![
210 TaxField::new("CST", "01"),
211 TaxField::new("vBC", "100.00"),
212 TaxField::new("pPIS", "1.6500"),
213 TaxField::new("vPIS", "1.65"),
214 ],
215 };
216
217 assert_eq!(element.to_xml(), serialize_tax_element(&element));
218 }
219}