mod common;
use fiscal::newtypes::{Cents, IbgeCode, Rate, Rate4};
use fiscal::tax_icms::{
IcmsCsosn, IcmsCst, IcmsPartData, IcmsStData, IcmsTotals, IcmsUfDestData, IcmsVariant,
build_icms_part_xml, build_icms_st_xml, build_icms_uf_dest_xml, build_icms_xml,
};
use fiscal::tax_pis_cofins_ipi::{
CofinsData, IiData, IpiData, PisData, build_cofins_xml, build_ii_xml, build_ipi_xml,
build_pis_xml,
};
use fiscal::types::{AccessKeyParams, EmissionType, InvoiceModel};
use fiscal::xml_builder::build_access_key;
use fiscal::xml_utils::{TagContent, tag};
use common::{expect_wrapped_in, expect_xml_tag_values as expect_xml_contains};
mod tag_utility_ported_from_taginfnfe {
use super::*;
#[test]
fn test_taginfnfe_builds_infnfe_with_id_and_versao_attributes() {
let id = "35170358716523000119550010000000301000000300";
let xml = tag(
"infNFe",
&[("Id", &format!("NFe{id}")), ("versao", "4.00")],
"content".into(),
);
assert!(xml.contains(&format!("Id=\"NFe{id}\"")));
assert!(xml.contains("versao=\"4.00\""));
}
#[test]
fn test_taginfnfe_com_pk_nitem_builds_infnfe_with_pk_nitem_attribute() {
let id = "35170358716523000119550010000000301000000300";
let xml = tag(
"infNFe",
&[
("Id", &format!("NFe{id}")),
("versao", "4.00"),
("pk_nItem", "1"),
],
"content".into(),
);
assert!(xml.contains("pk_nItem=\"1\""));
}
#[test]
fn test_taginfnfe_sem_chave_de_acesso_builds_infnfe_without_access_key() {
let xml = tag(
"infNFe",
&[("Id", "NFe"), ("versao", "4.00")],
"content".into(),
);
assert!(xml.contains("Id=\"NFe\""));
assert!(xml.contains("versao=\"4.00\""));
}
}
mod tagide_ported {
use super::*;
#[test]
fn test_tagide_model_55_ide_fields() {
let xml = tag(
"ide",
&[],
TagContent::Children(vec![
tag("cUF", &[], "50".into()),
tag("cNF", &[], "80070008".into()),
tag("natOp", &[], "VENDA".into()),
tag("mod", &[], "55".into()),
tag("serie", &[], "1".into()),
tag("nNF", &[], "1".into()),
tag("dhEmi", &[], "2018-06-23T17:45:49-03:00".into()),
tag("dhSaiEnt", &[], "2018-06-23T17:45:49-03:00".into()),
tag("tpNF", &[], "1".into()),
tag("idDest", &[], "1".into()),
tag("cMunFG", &[], "5002704".into()),
tag("tpImp", &[], "1".into()),
tag("tpEmis", &[], "1".into()),
tag("cDV", &[], "2".into()),
tag("tpAmb", &[], "2".into()),
tag("finNFe", &[], "1".into()),
tag("indFinal", &[], "0".into()),
tag("indPres", &[], "1".into()),
tag("procEmi", &[], "0".into()),
tag("verProc", &[], "5.0".into()),
]),
);
expect_xml_contains(
&xml,
&[
("cUF", "50"),
("cNF", "80070008"),
("natOp", "VENDA"),
("mod", "55"),
("serie", "1"),
("nNF", "1"),
("dhEmi", "2018-06-23T17:45:49-03:00"),
("dhSaiEnt", "2018-06-23T17:45:49-03:00"),
("tpNF", "1"),
("idDest", "1"),
("cMunFG", "5002704"),
("cDV", "2"),
("tpAmb", "2"),
("finNFe", "1"),
("indFinal", "0"),
("indPres", "1"),
("procEmi", "0"),
("verProc", "5.0"),
],
);
assert!(!xml.contains("<indPag>"));
assert!(!xml.contains("<dhCont>"));
assert!(!xml.contains("<xJust>"));
}
#[test]
fn test_tagide_contingency_fields() {
let xml = tag(
"ide",
&[],
TagContent::Children(vec![
tag("dhCont", &[], "2018-06-26T17:45:49-03:00".into()),
tag("xJust", &[], "SEFAZ INDISPONIVEL".into()),
]),
);
expect_xml_contains(
&xml,
&[
("dhCont", "2018-06-26T17:45:49-03:00"),
("xJust", "SEFAZ INDISPONIVEL"),
],
);
}
#[test]
fn test_tagide_model_65_ide_fields() {
let xml = tag(
"ide",
&[],
TagContent::Children(vec![
tag("cUF", &[], "50".into()),
tag("cNF", &[], "80070008".into()),
tag("natOp", &[], "VENDA".into()),
tag("mod", &[], "65".into()),
tag("serie", &[], "1".into()),
tag("nNF", &[], "1".into()),
tag("dhEmi", &[], "2018-06-23T17:45:49-03:00".into()),
tag("tpNF", &[], "1".into()),
tag("idDest", &[], "1".into()),
tag("cMunFG", &[], "5002704".into()),
tag("tpImp", &[], "4".into()),
tag("tpEmis", &[], "1".into()),
tag("cDV", &[], "2".into()),
tag("tpAmb", &[], "2".into()),
tag("finNFe", &[], "1".into()),
tag("indFinal", &[], "0".into()),
tag("indPres", &[], "4".into()),
tag("procEmi", &[], "0".into()),
tag("verProc", &[], "5.0".into()),
]),
);
expect_xml_contains(&xml, &[("mod", "65"), ("tpImp", "4"), ("indPres", "4")]);
assert!(!xml.contains("<indPag>"));
assert!(!xml.contains("<dhSaiEnt>"));
assert!(!xml.contains("<dhCont>"));
assert!(!xml.contains("<xJust>"));
}
}
mod reference_document_tags {
use super::*;
#[test]
fn test_tagref_nfe_builds_refnfe_tag() {
let ref_nfe = "35150271780456000160550010000253101000253101";
let xml = tag("refNFe", &[], ref_nfe.into());
assert_eq!(xml, format!("<refNFe>{ref_nfe}</refNFe>"));
}
#[test]
fn test_tagref_nf_builds_refnf_group() {
let xml = tag(
"refNF",
&[],
TagContent::Children(vec![
tag("cUF", &[], "35".into()),
tag("AAMM", &[], "1412".into()),
tag("CNPJ", &[], "52297850000105".into()),
tag("mod", &[], "01".into()),
tag("serie", &[], "3".into()),
tag("nNF", &[], "587878".into()),
]),
);
expect_xml_contains(
&xml,
&[
("cUF", "35"),
("AAMM", "1412"),
("CNPJ", "52297850000105"),
("mod", "01"),
("serie", "3"),
("nNF", "587878"),
],
);
}
#[test]
fn test_tagref_nfp_builds_refnfp_group_with_cnpj() {
let xml = tag(
"refNFP",
&[],
TagContent::Children(vec![
tag("cUF", &[], "35".into()),
tag("AAMM", &[], "1502".into()),
tag("CNPJ", &[], "00940734000150".into()),
tag("IE", &[], "ISENTO".into()),
tag("mod", &[], "04".into()),
tag("serie", &[], "0".into()),
tag("nNF", &[], "5578".into()),
]),
);
expect_xml_contains(
&xml,
&[
("cUF", "35"),
("CNPJ", "00940734000150"),
("IE", "ISENTO"),
("mod", "04"),
],
);
}
#[test]
fn test_tagref_nfp_builds_refnfp_group_with_cpf() {
let xml = tag(
"refNFP",
&[],
TagContent::Children(vec![
tag("cUF", &[], "35".into()),
tag("AAMM", &[], "1502".into()),
tag("CPF", &[], "08456452009".into()),
tag("IE", &[], "ISENTO".into()),
tag("mod", &[], "04".into()),
tag("serie", &[], "0".into()),
tag("nNF", &[], "5578".into()),
]),
);
assert!(xml.contains("<CPF>08456452009</CPF>"));
assert!(!xml.contains("<CNPJ>"));
}
#[test]
fn test_tagref_cte_builds_refcte_tag() {
let ref_cte = "35150268252816000146570010000016161002008472";
let xml = tag("refCTe", &[], ref_cte.into());
assert_eq!(xml, format!("<refCTe>{ref_cte}</refCTe>"));
}
#[test]
fn test_tagref_ecf_builds_refecf_group() {
let xml = tag(
"refECF",
&[],
TagContent::Children(vec![
tag("mod", &[], "2C".into()),
tag("nECF", &[], "788".into()),
tag("nCOO", &[], "114".into()),
]),
);
expect_xml_contains(&xml, &[("mod", "2C"), ("nECF", "788"), ("nCOO", "114")]);
}
#[test]
fn test_tagref_nfe_sig_builds_refnfesig_tag() {
let ref_nfe_sig = "35150271780456000160550010000253101000253101";
let xml = tag("refNFeSig", &[], ref_nfe_sig.into());
assert_eq!(xml, format!("<refNFeSig>{ref_nfe_sig}</refNFeSig>"));
}
}
mod retirada_entrega_tags {
use super::*;
fn address_fields() -> Vec<String> {
vec![
tag("xLgr", &[], "Rua Um".into()),
tag("nro", &[], "123".into()),
tag("xCpl", &[], "sobreloja".into()),
tag("xBairro", &[], "centro".into()),
tag("cMun", &[], "3550308".into()),
tag("xMun", &[], "Sao Paulo".into()),
tag("UF", &[], "SP".into()),
tag("CEP", &[], "01023000".into()),
tag("cPais", &[], "1058".into()),
tag("xPais", &[], "BRASIL".into()),
tag("fone", &[], "1122225544".into()),
tag("email", &[], "contato@beltrano.com.br".into()),
]
}
#[test]
fn test_tagretirada_builds_retirada_with_cnpj() {
let mut children = vec![
tag("CNPJ", &[], "12345678901234".into()),
tag("IE", &[], "12345678901".into()),
tag("xNome", &[], "Beltrano e Cia Ltda".into()),
];
children.extend(address_fields());
let xml = tag("retirada", &[], TagContent::Children(children));
expect_wrapped_in(&xml, "retirada");
expect_xml_contains(
&xml,
&[
("CNPJ", "12345678901234"),
("IE", "12345678901"),
("xNome", "Beltrano e Cia Ltda"),
("xLgr", "Rua Um"),
("nro", "123"),
("xCpl", "sobreloja"),
("xBairro", "centro"),
("cMun", "3550308"),
("xMun", "Sao Paulo"),
("UF", "SP"),
("CEP", "01023000"),
("cPais", "1058"),
("xPais", "BRASIL"),
("fone", "1122225544"),
("email", "contato@beltrano.com.br"),
],
);
}
#[test]
fn test_tagretirada_builds_retirada_with_cpf() {
let mut children = vec![tag("CPF", &[], "06563904092".into())];
children.extend(address_fields());
let xml = tag("retirada", &[], TagContent::Children(children));
assert!(xml.contains("<CPF>06563904092</CPF>"));
}
#[test]
fn test_tagentrega_builds_entrega_with_cnpj() {
let mut children = vec![
tag("CNPJ", &[], "12345678901234".into()),
tag("IE", &[], "12345678901".into()),
tag("xNome", &[], "Beltrano e Cia Ltda".into()),
];
children.extend(address_fields());
let xml = tag("entrega", &[], TagContent::Children(children));
expect_wrapped_in(&xml, "entrega");
expect_xml_contains(
&xml,
&[
("CNPJ", "12345678901234"),
("xLgr", "Rua Um"),
("nro", "123"),
("xCpl", "sobreloja"),
("xBairro", "centro"),
("cMun", "3550308"),
("xMun", "Sao Paulo"),
("UF", "SP"),
("CEP", "01023000"),
("cPais", "1058"),
("xPais", "BRASIL"),
("fone", "1122225544"),
("email", "contato@beltrano.com.br"),
],
);
}
#[test]
fn test_tagentrega_builds_entrega_with_cpf() {
let mut children = vec![tag("CPF", &[], "06563904092".into())];
children.extend(address_fields());
let xml = tag("entrega", &[], TagContent::Children(children));
assert!(xml.contains("<CPF>06563904092</CPF>"));
}
}
mod autxml_ported {
use super::*;
#[test]
fn test_tagautxml_builds_autxml_with_cnpj() {
let xml = tag(
"autXML",
&[],
TagContent::Children(vec![tag("CNPJ", &[], "12345678901234".into())]),
);
expect_wrapped_in(&xml, "autXML");
assert!(xml.contains("<CNPJ>12345678901234</CNPJ>"));
}
#[test]
fn test_tagautxml_builds_autxml_with_cpf() {
let xml = tag(
"autXML",
&[],
TagContent::Children(vec![tag("CPF", &[], "06563904092".into())]),
);
assert!(xml.contains("<CPF>06563904092</CPF>"));
}
}
mod inf_ad_prod_ported {
use super::*;
#[test]
fn test_taginfadprod_builds_additional_product_info_tag() {
let xml = tag("infAdProd", &[], "informacao adicional do item".into());
assert_eq!(xml, "<infAdProd>informacao adicional do item</infAdProd>");
}
}
mod gcred_ported {
use super::*;
#[test]
fn test_tag_credito_presumido_prod_builds_gcred_tag() {
let xml = tag(
"gCred",
&[],
TagContent::Children(vec![
tag("cCredPresumido", &[], "2222211234".into()),
tag("pCredPresumido", &[], "4.0000".into()),
tag("vCredPresumido", &[], "4.00".into()),
]),
);
expect_xml_contains(
&xml,
&[
("cCredPresumido", "2222211234"),
("pCredPresumido", "4.0000"),
("vCredPresumido", "4.00"),
],
);
}
}
mod obs_item_ported {
use super::*;
#[test]
fn test_tagprod_obscont_builds_obsitem_with_obscont() {
let xml = tag(
"obsItem",
&[],
TagContent::Children(vec![tag(
"obsCont",
&[("xCampo", "abc")],
TagContent::Children(vec![tag("xTexto", &[], "123".into())]),
)]),
);
expect_wrapped_in(&xml, "obsItem");
assert!(xml.contains("xCampo=\"abc\""));
assert!(xml.contains("<xTexto>123</xTexto>"));
}
#[test]
fn test_tagprod_obsfisco_builds_obsitem_with_obsfisco() {
let xml = tag(
"obsItem",
&[],
TagContent::Children(vec![tag(
"obsFisco",
&[("xCampo", "abc")],
TagContent::Children(vec![tag("xTexto", &[], "123".into())]),
)]),
);
expect_wrapped_in(&xml, "obsItem");
assert!(xml.contains("xCampo=\"abc\""));
assert!(xml.contains("<xTexto>123</xTexto>"));
}
}
mod veic_prod_ported {
use super::*;
#[test]
fn test_tagveicprod_builds_vehicle_product_tag() {
let xml = tag(
"veicProd",
&[],
TagContent::Children(vec![
tag("tpOp", &[], "1".into()),
tag("chassi", &[], "9BGRX4470AG745440".into()),
tag("cCor", &[], "121".into()),
tag("xCor", &[], "PRATA".into()),
tag("pot", &[], "0078".into()),
tag("cilin", &[], "1000".into()),
tag("pesoL", &[], "000008900".into()),
tag("pesoB", &[], "000008900".into()),
tag("nSerie", &[], "AAA123456".into()),
tag("tpComb", &[], "16".into()),
tag("nMotor", &[], "BBB123456".into()),
tag("CMT", &[], "460.0000".into()),
tag("dist", &[], "2443".into()),
tag("anoMod", &[], "2010".into()),
tag("anoFab", &[], "2011".into()),
tag("tpPint", &[], "M".into()),
tag("tpVeic", &[], "06".into()),
tag("espVeic", &[], "1".into()),
tag("VIN", &[], "N".into()),
tag("condVeic", &[], "1".into()),
tag("cMod", &[], "123456".into()),
tag("cCorDENATRAN", &[], "10".into()),
tag("lota", &[], "5".into()),
tag("tpRest", &[], "0".into()),
]),
);
expect_wrapped_in(&xml, "veicProd");
expect_xml_contains(
&xml,
&[
("tpOp", "1"),
("chassi", "9BGRX4470AG745440"),
("cCor", "121"),
("xCor", "PRATA"),
("pot", "0078"),
("cilin", "1000"),
("nSerie", "AAA123456"),
("tpComb", "16"),
("nMotor", "BBB123456"),
("CMT", "460.0000"),
("dist", "2443"),
("anoMod", "2010"),
("anoFab", "2011"),
("tpPint", "M"),
("tpVeic", "06"),
("espVeic", "1"),
("VIN", "N"),
("condVeic", "1"),
("cMod", "123456"),
("cCorDENATRAN", "10"),
("lota", "5"),
("tpRest", "0"),
],
);
}
}
mod med_ported {
use super::*;
#[test]
fn test_tagmed_builds_medicine_tag() {
let xml = tag(
"med",
&[],
TagContent::Children(vec![
tag("cProdANVISA", &[], "1234567890123".into()),
tag("xMotivoIsencao", &[], "RDC 238".into()),
tag("vPMC", &[], "102.22".into()),
]),
);
expect_xml_contains(
&xml,
&[
("cProdANVISA", "1234567890123"),
("xMotivoIsencao", "RDC 238"),
("vPMC", "102.22"),
],
);
}
}
mod arma_ported {
use super::*;
#[test]
fn test_tagarma_builds_weapon_tag() {
let xml = tag(
"arma",
&[],
TagContent::Children(vec![
tag("tpArma", &[], "0".into()),
tag("nSerie", &[], "1234567890".into()),
tag("nCano", &[], "987654321".into()),
tag("descr", &[], "Fuzil AK-47".into()),
]),
);
expect_xml_contains(
&xml,
&[
("tpArma", "0"),
("nSerie", "1234567890"),
("nCano", "987654321"),
("descr", "Fuzil AK-47"),
],
);
}
}
mod comb_ported {
use super::*;
#[test]
fn test_tagcomb_builds_fuel_tag_with_cide() {
let xml = tag(
"comb",
&[],
TagContent::Children(vec![
tag("cProdANP", &[], "012345678".into()),
tag("descANP", &[], "Gasolina C Comum".into()),
tag("pGLP", &[], "90.0000".into()),
tag("pGNn", &[], "10.0000".into()),
tag("pGNi", &[], "25.0000".into()),
tag("vPart", &[], "12.50".into()),
tag("CODIF", &[], "45346546".into()),
tag("qTemp", &[], "123.0000".into()),
tag("UFCons", &[], "RS".into()),
tag(
"CIDE",
&[],
TagContent::Children(vec![
tag("qBCProd", &[], "12.5000".into()),
tag("vAliqProd", &[], "1.0000".into()),
tag("vCIDE", &[], "0.13".into()),
]),
),
]),
);
expect_xml_contains(
&xml,
&[
("cProdANP", "012345678"),
("descANP", "Gasolina C Comum"),
("pGLP", "90.0000"),
("pGNn", "10.0000"),
("pGNi", "25.0000"),
("vPart", "12.50"),
("CODIF", "45346546"),
("qTemp", "123.0000"),
("UFCons", "RS"),
],
);
assert!(xml.contains("<CIDE>"));
assert!(xml.contains("<qBCProd>12.5000</qBCProd>"));
assert!(xml.contains("<vAliqProd>1.0000</vAliqProd>"));
assert!(xml.contains("<vCIDE>0.13</vCIDE>"));
}
}
mod encerrante_ported {
use super::*;
#[test]
fn test_tagencerrante_builds_closing_meter_reading_tag() {
let xml = tag(
"encerrante",
&[],
TagContent::Children(vec![
tag("nBico", &[], "1".into()),
tag("nBomba", &[], "2".into()),
tag("nTanque", &[], "3".into()),
tag("vEncIni", &[], "100.000".into()),
tag("vEncFin", &[], "200.000".into()),
]),
);
expect_xml_contains(
&xml,
&[
("nBico", "1"),
("nBomba", "2"),
("nTanque", "3"),
("vEncIni", "100.000"),
("vEncFin", "200.000"),
],
);
}
}
mod orig_comb_ported {
use super::*;
#[test]
fn test_tagorigcomb_builds_fuel_origin_tag() {
let xml = tag(
"origComb",
&[],
TagContent::Children(vec![
tag("indImport", &[], "1".into()),
tag("cUFOrig", &[], "11".into()),
tag("pOrig", &[], "200.0000".into()),
]),
);
expect_xml_contains(
&xml,
&[("indImport", "1"), ("cUFOrig", "11"), ("pOrig", "200.0000")],
);
}
}
mod tag_icms_cst_ported {
use super::*;
#[test]
fn test_tagicms_cst_00_fully_taxed() {
let v = IcmsVariant::from(IcmsCst::Cst00 {
orig: "0".into(),
mod_bc: "3".into(),
v_bc: Cents(20000),
p_icms: Rate(1800),
v_icms: Cents(3600),
p_fcp: Some(Rate(100)),
v_fcp: Some(Cents(200)),
});
let mut totals = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut totals).unwrap();
expect_wrapped_in(&xml, "ICMS");
expect_wrapped_in(&xml, "ICMS00");
expect_xml_contains(
&xml,
&[
("orig", "0"),
("CST", "00"),
("modBC", "3"),
("vBC", "200.00"),
("pICMS", "18.0000"),
("vICMS", "36.00"),
("pFCP", "1.0000"),
("vFCP", "2.00"),
],
);
assert_eq!(totals.v_bc, Cents(20000));
assert_eq!(totals.v_icms, Cents(3600));
assert_eq!(totals.v_fcp, Cents(200));
}
#[test]
fn test_tagicms_cst_02_monofasico() {
let v = IcmsVariant::from(IcmsCst::Cst02 {
orig: "0".into(),
q_bc_mono: Some(20000),
ad_rem_icms: Rate(2500),
v_icms_mono: Cents(5000),
});
let mut totals = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut totals).unwrap();
expect_wrapped_in(&xml, "ICMS02");
expect_xml_contains(
&xml,
&[
("orig", "0"),
("CST", "02"),
("qBCMono", "200.0000"),
("adRemICMS", "25.0000"),
("vICMSMono", "50.00"),
],
);
assert_eq!(totals.q_bc_mono, 20000);
assert_eq!(totals.v_icms_mono, Cents(5000));
}
#[test]
fn test_tagicms_cst_15_monofasico_with_retention() {
let v = IcmsVariant::from(IcmsCst::Cst15 {
orig: "0".into(),
q_bc_mono: Some(20000),
ad_rem_icms: Rate(2500),
v_icms_mono: Cents(5000),
q_bc_mono_reten: Some(10000),
ad_rem_icms_reten: Rate(2000),
v_icms_mono_reten: Cents(2000),
p_red_ad_rem: Some(Rate(100)),
mot_red_ad_rem: Some("1".into()),
});
let mut totals = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut totals).unwrap();
expect_wrapped_in(&xml, "ICMS15");
expect_xml_contains(
&xml,
&[
("orig", "0"),
("CST", "15"),
("qBCMono", "200.0000"),
("adRemICMS", "25.0000"),
("vICMSMono", "50.00"),
("qBCMonoReten", "100.0000"),
("adRemICMSReten", "20.0000"),
("vICMSMonoReten", "20.00"),
("pRedAdRem", "1.0000"),
("motRedAdRem", "1"),
],
);
assert_eq!(totals.q_bc_mono, 20000);
assert_eq!(totals.v_icms_mono, Cents(5000));
assert_eq!(totals.q_bc_mono_reten, 10000);
assert_eq!(totals.v_icms_mono_reten, Cents(2000));
}
#[test]
fn test_tagicms_cst_20_with_base_reduction() {
let v = IcmsVariant::from(IcmsCst::Cst20 {
orig: "0".into(),
mod_bc: "3".into(),
p_red_bc: Rate(500),
v_bc: Cents(18000),
p_icms: Rate(1800),
v_icms: Cents(3240),
v_bc_fcp: Some(Cents(20000)),
p_fcp: Some(Rate(100)),
v_fcp: Some(Cents(200)),
v_icms_deson: Some(Cents(360)),
mot_des_icms: Some("9".into()),
ind_deduz_deson: None,
});
let mut totals = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut totals).unwrap();
expect_wrapped_in(&xml, "ICMS20");
expect_xml_contains(
&xml,
&[
("orig", "0"),
("CST", "20"),
("modBC", "3"),
("pRedBC", "5.0000"),
("vBC", "180.00"),
("pICMS", "18.0000"),
("vICMS", "32.40"),
("vBCFCP", "200.00"),
("pFCP", "1.0000"),
("vFCP", "2.00"),
("vICMSDeson", "3.60"),
("motDesICMS", "9"),
],
);
assert_eq!(totals.v_icms_deson, Cents(360));
assert_eq!(totals.v_bc, Cents(18000));
assert_eq!(totals.v_icms, Cents(3240));
assert_eq!(totals.v_fcp, Cents(200));
}
#[test]
fn test_tagicms_cst_30_exempt_with_st() {
let v = IcmsVariant::from(IcmsCst::Cst30 {
orig: "0".into(),
mod_bc_st: "4".into(),
p_mva_st: Some(Rate(3000)),
p_red_bc_st: Some(Rate(100)),
v_bc_st: Cents(100),
p_icms_st: Rate(100),
v_icms_st: Cents(100),
v_bc_fcp_st: Some(Cents(100)),
p_fcp_st: Some(Rate(100)),
v_fcp_st: Some(Cents(100)),
v_icms_deson: Some(Cents(360)),
mot_des_icms: Some("9".into()),
ind_deduz_deson: Some("0".into()),
});
let mut totals = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut totals).unwrap();
expect_wrapped_in(&xml, "ICMS30");
expect_xml_contains(
&xml,
&[
("orig", "0"),
("CST", "30"),
("modBCST", "4"),
("pMVAST", "30.0000"),
("pRedBCST", "1.0000"),
("vBCST", "1.00"),
("pICMSST", "1.0000"),
("vICMSST", "1.00"),
("vBCFCPST", "1.00"),
("pFCPST", "1.0000"),
("vFCPST", "1.00"),
("vICMSDeson", "3.60"),
("motDesICMS", "9"),
("indDeduzDeson", "0"),
],
);
assert_eq!(totals.v_icms_deson, Cents(360));
assert_eq!(totals.v_bc_st, Cents(100));
assert_eq!(totals.v_st, Cents(100));
assert_eq!(totals.v_fcp_st, Cents(100));
}
#[test]
fn test_tagicms_cst_40_exempt() {
let v = IcmsVariant::from(IcmsCst::Cst40 {
orig: "0".into(),
v_icms_deson: Some(Cents(360)),
mot_des_icms: Some("9".into()),
ind_deduz_deson: Some("0".into()),
});
let mut totals = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut totals).unwrap();
expect_wrapped_in(&xml, "ICMS40");
expect_xml_contains(
&xml,
&[
("orig", "0"),
("CST", "40"),
("vICMSDeson", "3.60"),
("motDesICMS", "9"),
("indDeduzDeson", "0"),
],
);
assert_eq!(totals.v_icms_deson, Cents(360));
}
#[test]
fn test_tagicms_cst_41_non_taxed() {
let v = IcmsVariant::from(IcmsCst::Cst41 {
orig: "0".into(),
v_icms_deson: Some(Cents(360)),
mot_des_icms: Some("9".into()),
ind_deduz_deson: Some("0".into()),
});
let mut totals = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut totals).unwrap();
expect_wrapped_in(&xml, "ICMS40");
expect_xml_contains(
&xml,
&[
("orig", "0"),
("CST", "41"),
("vICMSDeson", "3.60"),
("motDesICMS", "9"),
("indDeduzDeson", "0"),
],
);
}
#[test]
fn test_tagicms_cst_50_suspended() {
let v = IcmsVariant::from(IcmsCst::Cst50 {
orig: "0".into(),
v_icms_deson: Some(Cents(360)),
mot_des_icms: Some("9".into()),
ind_deduz_deson: Some("0".into()),
});
let mut totals = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut totals).unwrap();
expect_wrapped_in(&xml, "ICMS40");
expect_xml_contains(
&xml,
&[("orig", "0"), ("CST", "50"), ("vICMSDeson", "3.60")],
);
}
#[test]
fn test_tagicms_cst_51_deferral() {
let v = IcmsVariant::from(IcmsCst::Cst51 {
orig: "0".into(),
mod_bc: Some("3".into()),
p_red_bc: Some(Rate(1000)),
c_benef_rbc: None,
v_bc: Some(Cents(10000)),
p_icms: Some(Rate(1700)),
v_icms_op: Some(Cents(1700)),
p_dif: Some(Rate(100)),
v_icms_dif: Some(Cents(100)),
v_icms: Some(Cents(1700)),
v_bc_fcp: Some(Cents(10000)),
p_fcp: Some(Rate(200)),
v_fcp: Some(Cents(200)),
p_fcp_dif: None,
v_fcp_dif: None,
v_fcp_efet: None,
});
let mut totals = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut totals).unwrap();
expect_wrapped_in(&xml, "ICMS51");
expect_xml_contains(
&xml,
&[
("orig", "0"),
("CST", "51"),
("modBC", "3"),
("pRedBC", "10.0000"),
("vBC", "100.00"),
("pICMS", "17.0000"),
("vICMSOp", "17.00"),
("pDif", "1.0000"),
("vICMSDif", "1.00"),
("vICMS", "17.00"),
("vBCFCP", "100.00"),
("pFCP", "2.0000"),
("vFCP", "2.00"),
],
);
assert_eq!(totals.v_bc, Cents(10000));
assert_eq!(totals.v_icms, Cents(1700));
assert_eq!(totals.v_fcp, Cents(200));
}
#[test]
fn test_tagicms_cst_53_monofasico_deferred() {
let v = IcmsVariant::from(IcmsCst::Cst53 {
orig: "0".into(),
q_bc_mono: Some(20000),
ad_rem_icms: Some(Rate(1700)),
v_icms_mono_op: Some(Cents(3400)),
p_dif: Some(Rate(100)),
v_icms_mono_dif: Some(Cents(200)),
v_icms_mono: Some(Cents(200)),
});
let mut totals = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut totals).unwrap();
expect_wrapped_in(&xml, "ICMS53");
expect_xml_contains(
&xml,
&[
("orig", "0"),
("CST", "53"),
("qBCMono", "200.0000"),
("adRemICMS", "17.0000"),
("vICMSMonoOp", "34.00"),
("pDif", "1.0000"),
("vICMSMonoDif", "2.00"),
("vICMSMono", "2.00"),
],
);
assert_eq!(totals.q_bc_mono, 20000);
assert_eq!(totals.v_icms_mono, Cents(200));
}
#[test]
fn test_tagicms_cst_60_previously_charged_st() {
let v = IcmsVariant::from(IcmsCst::Cst60 {
orig: "0".into(),
v_bc_st_ret: Some(Cents(10000)),
p_st: Some(Rate(1200)),
v_icms_substituto: Some(Cents(1200)),
v_icms_st_ret: Some(Cents(4000)),
v_bc_fcp_st_ret: Some(Cents(5000)),
p_fcp_st_ret: Some(Rate(1000)),
v_fcp_st_ret: Some(Cents(1500)),
p_red_bc_efet: Some(Rate(1400)),
v_bc_efet: Some(Cents(10000)),
p_icms_efet: Some(Rate(1000)),
v_icms_efet: Some(Cents(1000)),
});
let mut totals = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut totals).unwrap();
expect_wrapped_in(&xml, "ICMS60");
expect_xml_contains(
&xml,
&[
("orig", "0"),
("CST", "60"),
("vBCSTRet", "100.00"),
("pST", "12.0000"),
("vICMSSubstituto", "12.00"),
("vICMSSTRet", "40.00"),
("vBCFCPSTRet", "50.00"),
("pFCPSTRet", "10.0000"),
("vFCPSTRet", "15.00"),
("pRedBCEfet", "14.0000"),
("vBCEfet", "100.00"),
("pICMSEfet", "10.0000"),
("vICMSEfet", "10.00"),
],
);
assert_eq!(totals.v_fcp_st_ret, Cents(1500));
}
#[test]
fn test_tagicms_cst_61_monofasico_previously_charged() {
let v = IcmsVariant::from(IcmsCst::Cst61 {
orig: "0".into(),
q_bc_mono_ret: Some(30000),
ad_rem_icms_ret: Rate(200),
v_icms_mono_ret: Cents(600),
});
let mut totals = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut totals).unwrap();
expect_wrapped_in(&xml, "ICMS61");
expect_xml_contains(
&xml,
&[
("orig", "0"),
("CST", "61"),
("qBCMonoRet", "300.0000"),
("adRemICMSRet", "2.0000"),
("vICMSMonoRet", "6.00"),
],
);
assert_eq!(totals.q_bc_mono_ret, 30000);
assert_eq!(totals.v_icms_mono_ret, Cents(600));
}
#[test]
fn test_tagicms_cst_70_reduction_with_st() {
let v = IcmsVariant::from(IcmsCst::Cst70 {
orig: "0".into(),
mod_bc: "3".into(),
p_red_bc: Rate(1000),
v_bc: Cents(20000),
p_icms: Rate(1000),
v_icms: Cents(2000),
v_bc_fcp: Some(Cents(20000)),
p_fcp: Some(Rate(200)),
v_fcp: Some(Cents(400)),
mod_bc_st: "4".into(),
p_mva_st: Some(Rate(3000)),
p_red_bc_st: Some(Rate(0)),
v_bc_st: Cents(6000),
p_icms_st: Rate(1000),
v_icms_st: Cents(2000),
v_bc_fcp_st: Some(Cents(100)),
p_fcp_st: Some(Rate(100)),
v_fcp_st: Some(Cents(100)),
v_icms_deson: Some(Cents(1000)),
mot_des_icms: Some("9".into()),
ind_deduz_deson: None,
v_icms_st_deson: None,
mot_des_icms_st: None,
});
let mut totals = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut totals).unwrap();
expect_wrapped_in(&xml, "ICMS70");
expect_xml_contains(
&xml,
&[
("orig", "0"),
("CST", "70"),
("modBC", "3"),
("pRedBC", "10.0000"),
("vBC", "200.00"),
("pICMS", "10.0000"),
("vICMS", "20.00"),
("vBCFCP", "200.00"),
("pFCP", "2.0000"),
("vFCP", "4.00"),
("modBCST", "4"),
("pMVAST", "30.0000"),
("pRedBCST", "0.0000"),
("vBCST", "60.00"),
("pICMSST", "10.0000"),
("vICMSST", "20.00"),
("vBCFCPST", "1.00"),
("pFCPST", "1.0000"),
("vFCPST", "1.00"),
("vICMSDeson", "10.00"),
("motDesICMS", "9"),
],
);
assert_eq!(totals.v_icms_deson, Cents(1000));
assert_eq!(totals.v_bc, Cents(20000));
assert_eq!(totals.v_icms, Cents(2000));
assert_eq!(totals.v_bc_st, Cents(6000));
assert_eq!(totals.v_st, Cents(2000));
assert_eq!(totals.v_fcp_st, Cents(100));
assert_eq!(totals.v_fcp, Cents(400));
}
#[test]
fn test_tagicms_cst_90_others() {
let v = IcmsVariant::from(IcmsCst::Cst90 {
orig: "0".into(),
mod_bc: Some("3".into()),
v_bc: Some(Cents(20000)),
p_red_bc: Some(Rate(1000)),
c_benef_rbc: None,
p_icms: Some(Rate(1000)),
v_icms_op: None,
p_dif: None,
v_icms_dif: None,
v_icms: Some(Cents(2000)),
v_bc_fcp: Some(Cents(20000)),
p_fcp: Some(Rate(200)),
v_fcp: Some(Cents(400)),
p_fcp_dif: None,
v_fcp_dif: None,
v_fcp_efet: None,
mod_bc_st: Some("4".into()),
p_mva_st: Some(Rate(3000)),
p_red_bc_st: Some(Rate(0)),
v_bc_st: Some(Cents(6000)),
p_icms_st: Some(Rate(1000)),
v_icms_st: Some(Cents(2000)),
v_bc_fcp_st: Some(Cents(100)),
p_fcp_st: Some(Rate(100)),
v_fcp_st: Some(Cents(100)),
v_icms_deson: Some(Cents(1000)),
mot_des_icms: Some("9".into()),
ind_deduz_deson: None,
v_icms_st_deson: None,
mot_des_icms_st: None,
});
let mut totals = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut totals).unwrap();
expect_wrapped_in(&xml, "ICMS90");
expect_xml_contains(
&xml,
&[
("orig", "0"),
("CST", "90"),
("modBC", "3"),
("pRedBC", "10.0000"),
("vBC", "200.00"),
("pICMS", "10.0000"),
("vICMS", "20.00"),
("vBCFCP", "200.00"),
("pFCP", "2.0000"),
("vFCP", "4.00"),
("modBCST", "4"),
("pMVAST", "30.0000"),
("pRedBCST", "0.0000"),
("vBCST", "60.00"),
("pICMSST", "10.0000"),
("vICMSST", "20.00"),
("vBCFCPST", "1.00"),
("pFCPST", "1.0000"),
("vFCPST", "1.00"),
("vICMSDeson", "10.00"),
("motDesICMS", "9"),
],
);
assert_eq!(totals.v_icms_deson, Cents(1000));
assert_eq!(totals.v_bc, Cents(20000));
assert_eq!(totals.v_icms, Cents(2000));
assert_eq!(totals.v_bc_st, Cents(6000));
assert_eq!(totals.v_st, Cents(2000));
assert_eq!(totals.v_fcp_st, Cents(100));
assert_eq!(totals.v_fcp, Cents(400));
}
}
mod di_adi_det_export_rastro_ported {
use super::*;
#[test]
fn test_tagdi_builds_di_tag_with_cnpj() {
let xml = tag(
"DI",
&[],
TagContent::Children(vec![
tag("nDI", &[], "456".into()),
tag("dDI", &[], "2024-03-01".into()),
tag("xLocDesemb", &[], "Porto".into()),
tag("UFDesemb", &[], "SP".into()),
tag("dDesemb", &[], "2024-03-02".into()),
tag("tpViaTransp", &[], "1".into()),
tag("vAFRMM", &[], "150.45".into()),
tag("tpIntermedio", &[], "1".into()),
tag("CNPJ", &[], "08489068000198".into()),
tag("UFTerceiro", &[], "RS".into()),
tag("cExportador", &[], "123".into()),
]),
);
expect_wrapped_in(&xml, "DI");
expect_xml_contains(
&xml,
&[
("nDI", "456"),
("dDI", "2024-03-01"),
("xLocDesemb", "Porto"),
("UFDesemb", "SP"),
("dDesemb", "2024-03-02"),
("tpViaTransp", "1"),
("vAFRMM", "150.45"),
("tpIntermedio", "1"),
("CNPJ", "08489068000198"),
("UFTerceiro", "RS"),
("cExportador", "123"),
],
);
}
#[test]
fn test_tagdi_builds_di_tag_with_cpf() {
let xml = tag(
"DI",
&[],
TagContent::Children(vec![
tag("nDI", &[], "456".into()),
tag("dDI", &[], "2024-03-01".into()),
tag("xLocDesemb", &[], "Porto".into()),
tag("UFDesemb", &[], "SP".into()),
tag("dDesemb", &[], "2024-03-02".into()),
tag("tpViaTransp", &[], "1".into()),
tag("vAFRMM", &[], "150.45".into()),
tag("tpIntermedio", &[], "1".into()),
tag("CPF", &[], "10318797062".into()),
tag("UFTerceiro", &[], "RS".into()),
tag("cExportador", &[], "123".into()),
]),
);
assert!(xml.contains("<CPF>10318797062</CPF>"));
assert!(!xml.contains("<CNPJ>"));
}
#[test]
fn test_tagadi_builds_adi_tag() {
let xml = tag(
"adi",
&[],
TagContent::Children(vec![
tag("nAdicao", &[], "1".into()),
tag("nSeqAdic", &[], "1".into()),
tag("cFabricante", &[], "abc123".into()),
tag("vDescDI", &[], "12.48".into()),
tag("nDraw", &[], "11111111111".into()),
]),
);
expect_wrapped_in(&xml, "adi");
expect_xml_contains(
&xml,
&[
("nAdicao", "1"),
("nSeqAdic", "1"),
("cFabricante", "abc123"),
("vDescDI", "12.48"),
("nDraw", "11111111111"),
],
);
}
#[test]
fn test_tagdet_export_builds_det_export_tag() {
let xml = tag(
"detExport",
&[],
TagContent::Children(vec![tag("nDraw", &[], "123".into())]),
);
expect_wrapped_in(&xml, "detExport");
assert!(xml.contains("<nDraw>123</nDraw>"));
}
#[test]
fn test_tagdet_export_ind_builds_export_ind_tag() {
let xml = tag(
"exportInd",
&[],
TagContent::Children(vec![
tag("nRE", &[], "123".into()),
tag(
"chNFe",
&[],
"12345678901234567890123456789012345678901234".into(),
),
tag("qExport", &[], "45.1".into()),
]),
);
expect_wrapped_in(&xml, "exportInd");
expect_xml_contains(
&xml,
&[
("nRE", "123"),
("chNFe", "12345678901234567890123456789012345678901234"),
("qExport", "45.1"),
],
);
}
#[test]
fn test_tagrastro_builds_rastro_traceability_tag() {
let xml = tag(
"rastro",
&[],
TagContent::Children(vec![
tag("nLote", &[], "1".into()),
tag("qLote", &[], "1".into()),
tag("dFab", &[], "2024-01-01".into()),
tag("dVal", &[], "2024-01-01".into()),
tag("cAgreg", &[], "1234".into()),
]),
);
expect_wrapped_in(&xml, "rastro");
expect_xml_contains(
&xml,
&[
("nLote", "1"),
("qLote", "1"),
("dFab", "2024-01-01"),
("dVal", "2024-01-01"),
("cAgreg", "1234"),
],
);
}
}
mod tag_icms_uf_dest_ported {
use super::*;
#[test]
fn test_tagicmsufdest_builds_icms_uf_dest_group() {
let (xml, totals) = build_icms_uf_dest_xml(
&IcmsUfDestData::new(Cents(100), Rate(100), Rate(100), Cents(100))
.v_bc_fcp_uf_dest(Cents(100))
.p_fcp_uf_dest(Rate(100))
.v_fcp_uf_dest(Cents(100))
.v_icms_uf_remet(Cents(100)),
)
.unwrap();
expect_wrapped_in(&xml, "ICMSUFDest");
expect_xml_contains(
&xml,
&[
("vBCUFDest", "1.00"),
("vBCFCPUFDest", "1.00"),
("pFCPUFDest", "1.0000"),
("pICMSUFDest", "1.0000"),
("pICMSInter", "1.0000"),
("pICMSInterPart", "100.0000"),
("vFCPUFDest", "1.00"),
("vICMSUFDest", "1.00"),
("vICMSUFRemet", "1.00"),
],
);
assert_eq!(totals.v_icms_uf_dest, Cents(100));
assert_eq!(totals.v_fcp_uf_dest, Cents(100));
assert_eq!(totals.v_icms_uf_remet, Cents(100));
}
}
mod tag_ii_ported {
use super::*;
#[test]
fn test_tagii_builds_ii_group() {
let xml = build_ii_xml(&IiData::new(
Cents(10000),
Cents(100),
Cents(100),
Cents(100),
));
expect_wrapped_in(&xml, "II");
expect_xml_contains(
&xml,
&[
("vBC", "100.00"),
("vDespAdu", "1.00"),
("vII", "1.00"),
("vIOF", "1.00"),
],
);
}
}
mod tag_issqn_ported {
use super::*;
#[test]
fn test_tagissqn_builds_issqn_tag_structure() {
let xml = tag(
"ISSQN",
&[],
TagContent::Children(vec![
tag("vBC", &[], "1".into()),
tag("vAliq", &[], "1".into()),
tag("vISSQN", &[], "1".into()),
tag("cMunFG", &[], "1234567".into()),
tag("cListServ", &[], "10.10".into()),
tag("vDeducao", &[], "1".into()),
tag("vOutro", &[], "1".into()),
tag("vDescIncond", &[], "1".into()),
tag("vDescCond", &[], "1".into()),
tag("vISSRet", &[], "1".into()),
tag("indISS", &[], "1".into()),
tag("cServico", &[], "1".into()),
tag("cMun", &[], "123456".into()),
tag("cPais", &[], "55".into()),
tag("nProcesso", &[], "123".into()),
tag("indIncentivo", &[], "12".into()),
]),
);
expect_wrapped_in(&xml, "ISSQN");
expect_xml_contains(
&xml,
&[
("vBC", "1"),
("vAliq", "1"),
("vISSQN", "1"),
("cMunFG", "1234567"),
("cListServ", "10.10"),
("vDeducao", "1"),
("vOutro", "1"),
("vDescIncond", "1"),
("vDescCond", "1"),
("vISSRet", "1"),
("indISS", "1"),
("cServico", "1"),
("cMun", "123456"),
("cPais", "55"),
("nProcesso", "123"),
("indIncentivo", "12"),
],
);
}
}
mod inf_resp_tec_ported {
use super::*;
#[test]
fn test_taginfresptec_builds_inf_resp_tec_tag() {
let xml = tag(
"infRespTec",
&[],
TagContent::Children(vec![
tag("CNPJ", &[], "76038276000120".into()),
tag("xContato", &[], "Fulano de Tal".into()),
tag("email", &[], "fulano@email.com".into()),
tag("fone", &[], "51999999999".into()),
tag("idCSRT", &[], "123".into()),
]),
);
expect_wrapped_in(&xml, "infRespTec");
expect_xml_contains(
&xml,
&[
("CNPJ", "76038276000120"),
("xContato", "Fulano de Tal"),
("email", "fulano@email.com"),
("fone", "51999999999"),
("idCSRT", "123"),
],
);
assert!(!xml.contains("<CSRT>"));
}
}
mod agropecuario_ported {
use super::*;
#[test]
fn test_tagagropecuario_defensivo_builds_defensivo_tag() {
let xml = tag(
"defensivo",
&[],
TagContent::Children(vec![
tag("nReceituario", &[], "1234567890ABCDEFGHIJ".into()),
tag("CPFRespTec", &[], "12345678901".into()),
]),
);
expect_wrapped_in(&xml, "defensivo");
expect_xml_contains(
&xml,
&[
("nReceituario", "1234567890ABCDEFGHIJ"),
("CPFRespTec", "12345678901"),
],
);
}
#[test]
fn test_tagagropecuario_guia_builds_guia_transito_tag() {
let xml = tag(
"guiaTransito",
&[],
TagContent::Children(vec![
tag("tpGuia", &[], "1".into()),
tag("UFGuia", &[], "MG".into()),
tag("serieGuia", &[], "A12345678".into()),
tag("nGuia", &[], "123456789".into()),
]),
);
expect_wrapped_in(&xml, "guiaTransito");
expect_xml_contains(
&xml,
&[
("UFGuia", "MG"),
("serieGuia", "A12345678"),
("nGuia", "123456789"),
],
);
}
}
mod tag_icms_part_ported {
use super::*;
#[test]
fn test_tagicmspart_builds_icms_part_group() {
let (xml, totals) = build_icms_part_xml(
&IcmsPartData::new(
"0",
"90",
"1",
Cents(20000),
Rate(1000),
Cents(2000),
"4",
Cents(6000),
Rate(100),
Cents(100),
Rate(100),
"EX",
)
.p_red_bc(Rate(500))
.p_mva_st(Rate(3000))
.p_red_bc_st(Rate(0))
.v_bc_fcp_st(Cents(100))
.p_fcp_st(Rate(100))
.v_fcp_st(Cents(100)),
)
.unwrap();
expect_wrapped_in(&xml, "ICMS");
expect_wrapped_in(&xml, "ICMSPart");
expect_xml_contains(
&xml,
&[
("orig", "0"),
("CST", "90"),
("modBC", "1"),
("vBC", "200.00"),
("pRedBC", "5.0000"),
("pICMS", "10.0000"),
("vICMS", "20.00"),
("modBCST", "4"),
("pMVAST", "30.0000"),
("pRedBCST", "0.0000"),
("vBCST", "60.00"),
("pICMSST", "1.0000"),
("vICMSST", "1.00"),
("vBCFCPST", "1.00"),
("pFCPST", "1.0000"),
("vFCPST", "1.00"),
("pBCOp", "1.0000"),
("UFST", "EX"),
],
);
assert_eq!(totals.v_bc, Cents(20000));
assert_eq!(totals.v_icms, Cents(2000));
assert_eq!(totals.v_bc_st, Cents(6000));
assert_eq!(totals.v_st, Cents(100));
}
}
mod tag_icms_st_ported {
use super::*;
#[test]
fn test_tagicmsst_builds_icmsst_repasse_group() {
let (xml, totals) = build_icms_st_xml(
&IcmsStData::new(
"0",
"41",
Cents(20000),
Cents(2000),
Cents(3000),
Cents(200),
)
.v_bc_fcp_st_ret(Cents(200))
.p_fcp_st_ret(Rate(200))
.v_fcp_st_ret(Cents(200))
.p_st(Rate(200))
.v_icms_substituto(Cents(200))
.p_red_bc_efet(Rate(200))
.v_bc_efet(Cents(200))
.p_icms_efet(Rate(200))
.v_icms_efet(Cents(200)),
)
.unwrap();
expect_wrapped_in(&xml, "ICMS");
expect_wrapped_in(&xml, "ICMSST");
expect_xml_contains(
&xml,
&[
("orig", "0"),
("CST", "41"),
("vBCSTRet", "200.00"),
("vICMSSTRet", "20.00"),
("vBCSTDest", "30.00"),
("vICMSSTDest", "2.00"),
("vBCFCPSTRet", "2.00"),
("pFCPSTRet", "2.0000"),
("vFCPSTRet", "2.00"),
("pST", "2.0000"),
("vICMSSubstituto", "2.00"),
("pRedBCEfet", "2.0000"),
("vBCEfet", "2.00"),
("pICMSEfet", "2.0000"),
("vICMSEfet", "2.00"),
],
);
assert_eq!(totals.v_fcp_st_ret, Cents(200));
}
}
mod tag_icmssn_ported {
use super::*;
#[test]
fn test_tagicmssn_101_with_credit() {
let v = IcmsVariant::from(IcmsCsosn::Csosn101 {
orig: "0".into(),
csosn: "101".into(),
p_cred_sn: Rate(300),
v_cred_icms_sn: Cents(400),
});
let mut t = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut t).unwrap();
expect_wrapped_in(&xml, "ICMS");
expect_wrapped_in(&xml, "ICMSSN101");
expect_xml_contains(
&xml,
&[
("orig", "0"),
("CSOSN", "101"),
("pCredSN", "3.0000"),
("vCredICMSSN", "4.00"),
],
);
}
#[test]
fn test_tagicmssn_102_without_credit() {
let v = IcmsVariant::from(IcmsCsosn::Csosn102 {
orig: "0".into(),
csosn: "102".into(),
});
let mut t = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut t).unwrap();
expect_wrapped_in(&xml, "ICMS");
expect_wrapped_in(&xml, "ICMSSN102");
expect_xml_contains(&xml, &[("CSOSN", "102")]);
}
#[test]
fn test_tagicmssn_103_uses_same_wrapper() {
let v = IcmsVariant::from(IcmsCsosn::Csosn103 {
orig: "0".into(),
csosn: "103".into(),
});
let mut t = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut t).unwrap();
expect_wrapped_in(&xml, "ICMS");
expect_wrapped_in(&xml, "ICMSSN102");
expect_xml_contains(&xml, &[("CSOSN", "103")]);
}
#[test]
fn test_tagicmssn_300_uses_same_wrapper() {
let v = IcmsVariant::from(IcmsCsosn::Csosn300 {
orig: "0".into(),
csosn: "300".into(),
});
let mut t = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut t).unwrap();
expect_wrapped_in(&xml, "ICMS");
expect_wrapped_in(&xml, "ICMSSN102");
expect_xml_contains(&xml, &[("CSOSN", "300")]);
}
#[test]
fn test_tagicmssn_400_uses_same_wrapper() {
let v = IcmsVariant::from(IcmsCsosn::Csosn400 {
orig: "0".into(),
csosn: "400".into(),
});
let mut t = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut t).unwrap();
expect_wrapped_in(&xml, "ICMS");
expect_wrapped_in(&xml, "ICMSSN102");
expect_xml_contains(&xml, &[("CSOSN", "400")]);
}
#[test]
fn test_tagicmssn_201_with_credit_and_st() {
let v = IcmsVariant::from(IcmsCsosn::Csosn201 {
orig: "0".into(),
csosn: "201".into(),
mod_bc_st: "4".into(),
p_mva_st: Some(Rate(1000)),
p_red_bc_st: Some(Rate(2000)),
v_bc_st: Cents(30000),
p_icms_st: Rate(100),
v_icms_st: Cents(100),
v_bc_fcp_st: Some(Cents(100)),
p_fcp_st: Some(Rate(100)),
v_fcp_st: Some(Cents(100)),
p_cred_sn: Some(Rate(100)),
v_cred_icms_sn: Some(Cents(100)),
});
let mut totals = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut totals).unwrap();
expect_wrapped_in(&xml, "ICMS");
expect_wrapped_in(&xml, "ICMSSN201");
expect_xml_contains(
&xml,
&[
("orig", "0"),
("CSOSN", "201"),
("modBCST", "4"),
("pMVAST", "10.0000"),
("pRedBCST", "20.0000"),
("vBCST", "300.00"),
("pICMSST", "1.0000"),
("vICMSST", "1.00"),
("vBCFCPST", "1.00"),
("pFCPST", "1.0000"),
("vFCPST", "1.00"),
("pCredSN", "1.0000"),
("vCredICMSSN", "1.00"),
],
);
assert_eq!(totals.v_bc_st, Cents(30000));
assert_eq!(totals.v_st, Cents(100));
}
#[test]
fn test_tagicmssn_202_without_credit_with_st() {
let v = IcmsVariant::from(IcmsCsosn::Csosn202 {
orig: "0".into(),
csosn: "202".into(),
mod_bc_st: "4".into(),
p_mva_st: Some(Rate(1000)),
p_red_bc_st: Some(Rate(2000)),
v_bc_st: Cents(30000),
p_icms_st: Rate(100),
v_icms_st: Cents(100),
v_bc_fcp_st: Some(Cents(100)),
p_fcp_st: Some(Rate(100)),
v_fcp_st: Some(Cents(100)),
});
let mut totals = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut totals).unwrap();
expect_wrapped_in(&xml, "ICMS");
expect_wrapped_in(&xml, "ICMSSN202");
expect_xml_contains(
&xml,
&[
("orig", "0"),
("CSOSN", "202"),
("modBCST", "4"),
("pMVAST", "10.0000"),
("pRedBCST", "20.0000"),
("vBCST", "300.00"),
("pICMSST", "1.0000"),
("vICMSST", "1.00"),
("vBCFCPST", "1.00"),
("pFCPST", "1.0000"),
("vFCPST", "1.00"),
],
);
assert_eq!(totals.v_bc_st, Cents(30000));
assert_eq!(totals.v_st, Cents(100));
}
#[test]
fn test_tagicmssn_203_uses_same_wrapper() {
let v = IcmsVariant::from(IcmsCsosn::Csosn203 {
orig: "0".into(),
csosn: "203".into(),
mod_bc_st: "4".into(),
p_mva_st: Some(Rate(1000)),
p_red_bc_st: Some(Rate(2000)),
v_bc_st: Cents(30000),
p_icms_st: Rate(100),
v_icms_st: Cents(100),
v_bc_fcp_st: Some(Cents(100)),
p_fcp_st: Some(Rate(100)),
v_fcp_st: Some(Cents(100)),
});
let mut t = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut t).unwrap();
expect_wrapped_in(&xml, "ICMS");
expect_wrapped_in(&xml, "ICMSSN202");
expect_xml_contains(&xml, &[("CSOSN", "203")]);
}
#[test]
fn test_tagicmssn_500_previously_charged() {
let v = IcmsVariant::from(IcmsCsosn::Csosn500 {
orig: "0".into(),
csosn: "500".into(),
v_bc_st_ret: Some(Cents(100)),
p_st: Some(Rate(100)),
v_icms_substituto: Some(Cents(100)),
v_icms_st_ret: Some(Cents(100)),
v_bc_fcp_st_ret: Some(Cents(100)),
p_fcp_st_ret: Some(Rate(100)),
v_fcp_st_ret: Some(Cents(100)),
p_red_bc_efet: Some(Rate(100)),
v_bc_efet: Some(Cents(100)),
p_icms_efet: Some(Rate(100)),
v_icms_efet: Some(Cents(100)),
});
let mut t = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut t).unwrap();
expect_wrapped_in(&xml, "ICMS");
expect_wrapped_in(&xml, "ICMSSN500");
expect_xml_contains(
&xml,
&[
("orig", "0"),
("CSOSN", "500"),
("vBCSTRet", "1.00"),
("pST", "1.0000"),
("vICMSSubstituto", "1.00"),
("vICMSSTRet", "1.00"),
("vBCFCPSTRet", "1.00"),
("pFCPSTRet", "1.0000"),
("vFCPSTRet", "1.00"),
("pRedBCEfet", "1.0000"),
("vBCEfet", "1.00"),
("pICMSEfet", "1.0000"),
("vICMSEfet", "1.00"),
],
);
}
#[test]
fn test_tagicmssn_900_others() {
let v = IcmsVariant::from(IcmsCsosn::Csosn900 {
orig: "0".into(),
csosn: "900".into(),
mod_bc: Some("3".into()),
v_bc: Some(Cents(10000)),
p_red_bc: Some(Rate(100)),
p_icms: Some(Rate(100)),
v_icms: Some(Cents(100)),
p_cred_sn: Some(Rate(300)),
v_cred_icms_sn: Some(Cents(400)),
mod_bc_st: Some("3".into()),
p_mva_st: Some(Rate(100)),
p_red_bc_st: Some(Rate(100)),
v_bc_st: Some(Cents(100)),
p_icms_st: Some(Rate(100)),
v_icms_st: Some(Cents(100)),
v_bc_fcp_st: Some(Cents(100)),
p_fcp_st: Some(Rate(100)),
v_fcp_st: Some(Cents(100)),
});
let mut totals = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut totals).unwrap();
expect_wrapped_in(&xml, "ICMS");
expect_wrapped_in(&xml, "ICMSSN900");
expect_xml_contains(
&xml,
&[
("CSOSN", "900"),
("modBC", "3"),
("vBC", "100.00"),
("pRedBC", "1.0000"),
("pICMS", "1.0000"),
("vICMS", "1.00"),
("pCredSN", "3.0000"),
("vCredICMSSN", "4.00"),
("modBCST", "3"),
("pMVAST", "1.0000"),
("pRedBCST", "1.0000"),
("vBCST", "1.00"),
("pICMSST", "1.0000"),
("vICMSST", "1.00"),
("vBCFCPST", "1.00"),
("pFCPST", "1.0000"),
("vFCPST", "1.00"),
],
);
assert_eq!(totals.v_bc, Cents(10000));
assert_eq!(totals.v_icms, Cents(100));
assert_eq!(totals.v_bc_st, Cents(100));
assert_eq!(totals.v_st, Cents(100));
}
#[test]
fn test_tagicmssn_should_accept_empty_orig_when_crt_is_4() {
let v = IcmsVariant::from(IcmsCsosn::Csosn900 {
orig: String::new(),
csosn: "900".into(),
mod_bc: Some("3".into()),
v_bc: Some(Cents(10000)),
p_red_bc: Some(Rate(100)),
p_icms: Some(Rate(100)),
v_icms: Some(Cents(100)),
p_cred_sn: Some(Rate(300)),
v_cred_icms_sn: Some(Cents(400)),
mod_bc_st: Some("3".into()),
p_mva_st: Some(Rate(100)),
p_red_bc_st: Some(Rate(100)),
v_bc_st: Some(Cents(100)),
p_icms_st: Some(Rate(100)),
v_icms_st: Some(Cents(100)),
v_bc_fcp_st: Some(Cents(100)),
p_fcp_st: Some(Rate(100)),
v_fcp_st: Some(Cents(100)),
});
let mut t = IcmsTotals::default();
let xml = build_icms_xml(&v, &mut t).unwrap();
expect_wrapped_in(&xml, "ICMS");
expect_wrapped_in(&xml, "ICMSSN900");
assert!(!xml.contains("<orig>"));
}
}
mod build_access_key_ported {
use super::*;
#[test]
fn builds_a_44_digit_access_key_with_valid_check_digit() {
let key = build_access_key(&AccessKeyParams::new(
IbgeCode("35".to_string()),
"1703",
"58716523000119",
InvoiceModel::Nfe,
1,
30,
EmissionType::Normal,
"00000030",
))
.unwrap();
assert_eq!(key.len(), 44);
assert!(key.starts_with("35"));
assert_eq!(&key[6..20], "58716523000119");
assert_eq!(&key[20..22], "55");
assert_eq!(&key[22..25], "001");
assert_eq!(&key[25..34], "000000030");
assert_eq!(&key[34..35], "1");
assert_eq!(&key[35..43], "00000030");
}
}
mod pis_builders_ported {
use super::*;
#[test]
fn pis_aliq_cst_01_with_percentage() {
let xml = build_pis_xml(
&PisData::new("01")
.v_bc(Cents(10000))
.p_pis(Rate4(16500))
.v_pis(Cents(165)),
);
expect_wrapped_in(&xml, "PIS");
expect_wrapped_in(&xml, "PISAliq");
expect_xml_contains(
&xml,
&[
("CST", "01"),
("vBC", "100.00"),
("pPIS", "1.6500"),
("vPIS", "1.65"),
],
);
}
#[test]
fn pis_aliq_cst_02() {
let xml = build_pis_xml(
&PisData::new("02")
.v_bc(Cents(20000))
.p_pis(Rate4(16500))
.v_pis(Cents(330)),
);
expect_wrapped_in(&xml, "PISAliq");
expect_xml_contains(&xml, &[("CST", "02")]);
}
#[test]
fn pis_qtde_cst_03_with_quantity() {
let xml = build_pis_xml(
&PisData::new("03")
.q_bc_prod(10000)
.v_aliq_prod(50000)
.v_pis(Cents(500)),
);
expect_wrapped_in(&xml, "PISQtde");
expect_xml_contains(
&xml,
&[
("CST", "03"),
("qBCProd", "1.0000"),
("vAliqProd", "5.0000"),
("vPIS", "5.00"),
],
);
}
#[test]
fn pis_nt_cst_04_non_taxed() {
let xml = build_pis_xml(&PisData::new("04"));
expect_wrapped_in(&xml, "PISNT");
expect_xml_contains(&xml, &[("CST", "04")]);
assert!(!xml.contains("<vBC>"));
}
#[test]
fn pis_nt_cst_05_06_07_08_09() {
for cst in &["05", "06", "07", "08", "09"] {
let xml = build_pis_xml(&PisData::new(*cst));
expect_wrapped_in(&xml, "PISNT");
expect_xml_contains(&xml, &[("CST", cst)]);
}
}
#[test]
fn pis_outr_cst_49_with_percentage() {
let xml = build_pis_xml(
&PisData::new("49")
.v_bc(Cents(10000))
.p_pis(Rate4(16500))
.v_pis(Cents(165)),
);
expect_wrapped_in(&xml, "PISOutr");
expect_xml_contains(
&xml,
&[
("CST", "49"),
("vBC", "100.00"),
("pPIS", "1.6500"),
("vPIS", "1.65"),
],
);
}
#[test]
fn pis_outr_cst_99_with_quantity() {
let xml = build_pis_xml(
&PisData::new("99")
.q_bc_prod(10000)
.v_aliq_prod(50000)
.v_pis(Cents(500)),
);
expect_wrapped_in(&xml, "PISOutr");
expect_xml_contains(
&xml,
&[
("CST", "99"),
("qBCProd", "1.0000"),
("vAliqProd", "5.0000"),
("vPIS", "5.00"),
],
);
}
}
mod cofins_builders_ported {
use super::*;
#[test]
fn cofins_aliq_cst_01_with_percentage() {
let xml = build_cofins_xml(
&CofinsData::new("01")
.v_bc(Cents(10000))
.p_cofins(Rate4(76000))
.v_cofins(Cents(760)),
);
expect_wrapped_in(&xml, "COFINS");
expect_wrapped_in(&xml, "COFINSAliq");
expect_xml_contains(
&xml,
&[
("CST", "01"),
("vBC", "100.00"),
("pCOFINS", "7.6000"),
("vCOFINS", "7.60"),
],
);
}
#[test]
fn cofins_qtde_cst_03_with_quantity() {
let xml = build_cofins_xml(
&CofinsData::new("03")
.q_bc_prod(10000)
.v_aliq_prod(50000)
.v_cofins(Cents(500)),
);
expect_wrapped_in(&xml, "COFINSQtde");
expect_xml_contains(
&xml,
&[
("CST", "03"),
("qBCProd", "1.0000"),
("vAliqProd", "5.0000"),
("vCOFINS", "5.00"),
],
);
}
#[test]
fn cofins_nt_cst_04_non_taxed() {
let xml = build_cofins_xml(&CofinsData::new("04"));
expect_wrapped_in(&xml, "COFINSNT");
expect_xml_contains(&xml, &[("CST", "04")]);
}
#[test]
fn cofins_nt_cst_05_06_07_08_09() {
for cst in &["05", "06", "07", "08", "09"] {
let xml = build_cofins_xml(&CofinsData::new(*cst));
expect_wrapped_in(&xml, "COFINSNT");
}
}
#[test]
fn cofins_outr_cst_99_with_percentage() {
let xml = build_cofins_xml(
&CofinsData::new("99")
.v_bc(Cents(10000))
.p_cofins(Rate4(76000))
.v_cofins(Cents(760)),
);
expect_wrapped_in(&xml, "COFINSOutr");
expect_xml_contains(
&xml,
&[
("CST", "99"),
("vBC", "100.00"),
("pCOFINS", "7.6000"),
("vCOFINS", "7.60"),
],
);
}
#[test]
fn cofins_outr_cst_49_with_quantity() {
let xml = build_cofins_xml(
&CofinsData::new("49")
.q_bc_prod(20000)
.v_aliq_prod(30000)
.v_cofins(Cents(600)),
);
expect_wrapped_in(&xml, "COFINSOutr");
expect_xml_contains(
&xml,
&[
("CST", "49"),
("qBCProd", "2.0000"),
("vAliqProd", "3.0000"),
("vCOFINS", "6.00"),
],
);
}
}
mod ipi_builders_ported {
use super::*;
#[test]
fn ipi_trib_cst_50_with_percentage() {
let xml = build_ipi_xml(
&IpiData::new("50", "999")
.v_bc(Cents(10000))
.p_ipi(Rate(500))
.v_ipi(Cents(500)),
);
expect_wrapped_in(&xml, "IPI");
expect_wrapped_in(&xml, "IPITrib");
expect_xml_contains(
&xml,
&[
("cEnq", "999"),
("CST", "50"),
("vBC", "100.00"),
("pIPI", "5.0000"),
("vIPI", "5.00"),
],
);
}
#[test]
fn ipi_trib_cst_00_with_percentage() {
let xml = build_ipi_xml(
&IpiData::new("00", "999")
.v_bc(Cents(20000))
.p_ipi(Rate(1000))
.v_ipi(Cents(2000)),
);
expect_wrapped_in(&xml, "IPITrib");
expect_xml_contains(&xml, &[("CST", "00"), ("pIPI", "10.0000")]);
}
#[test]
fn ipi_trib_cst_49_with_unit_based() {
let xml = build_ipi_xml(
&IpiData::new("49", "999")
.q_unid(10000)
.v_unid(50000)
.v_ipi(Cents(500)),
);
expect_wrapped_in(&xml, "IPITrib");
expect_xml_contains(
&xml,
&[
("CST", "49"),
("qUnid", "1.0000"),
("vUnid", "5.0000"),
("vIPI", "5.00"),
],
);
}
#[test]
fn ipi_trib_cst_99_with_percentage() {
let xml = build_ipi_xml(
&IpiData::new("99", "311")
.v_bc(Cents(50000))
.p_ipi(Rate(1500))
.v_ipi(Cents(7500)),
);
expect_wrapped_in(&xml, "IPITrib");
expect_xml_contains(
&xml,
&[
("cEnq", "311"),
("CST", "99"),
("vBC", "500.00"),
("pIPI", "15.0000"),
("vIPI", "75.00"),
],
);
}
#[test]
fn ipi_nt_cst_01_non_taxed() {
let xml = build_ipi_xml(&IpiData::new("01", "999"));
expect_wrapped_in(&xml, "IPI");
expect_wrapped_in(&xml, "IPINT");
expect_xml_contains(&xml, &[("CST", "01")]);
assert!(!xml.contains("<IPITrib>"));
}
#[test]
fn ipi_nt_cst_02_03_04_05_non_taxed() {
for cst in &["02", "03", "04", "05"] {
let xml = build_ipi_xml(&IpiData::new(*cst, "999"));
expect_wrapped_in(&xml, "IPINT");
expect_xml_contains(&xml, &[("CST", cst)]);
}
}
#[test]
fn ipi_with_optional_header_fields_cnpj_prod_cselo_qselo() {
let xml = build_ipi_xml(
&IpiData::new("50", "999")
.cnpj_prod("12345678901234")
.c_selo("SELO123")
.q_selo(10)
.v_bc(Cents(10000))
.p_ipi(Rate(500))
.v_ipi(Cents(500)),
);
expect_xml_contains(
&xml,
&[
("CNPJProd", "12345678901234"),
("cSelo", "SELO123"),
("qSelo", "10"),
],
);
}
}
mod ii_builders_additional {
use super::*;
#[test]
fn builds_ii_with_all_zero_values() {
let xml = build_ii_xml(&IiData::new(Cents(0), Cents(0), Cents(0), Cents(0)));
expect_xml_contains(
&xml,
&[
("vBC", "0.00"),
("vDespAdu", "0.00"),
("vII", "0.00"),
("vIOF", "0.00"),
],
);
}
#[test]
fn builds_ii_with_large_values() {
let xml = build_ii_xml(&IiData::new(
Cents(1000000),
Cents(50000),
Cents(150000),
Cents(25000),
));
expect_xml_contains(
&xml,
&[
("vBC", "10000.00"),
("vDespAdu", "500.00"),
("vII", "1500.00"),
("vIOF", "250.00"),
],
);
}
}