mod b2b;
mod cancellation;
mod event;
mod helpers;
mod inutilizacao;
mod protocol;
pub use b2b::attach_b2b;
pub use cancellation::attach_cancellation;
pub use event::attach_event_protocol;
pub use inutilizacao::attach_inutilizacao;
pub use protocol::attach_protocol;
use crate::FiscalError;
use helpers::contains_xml_tag;
pub fn to_authorize(request_xml: &str, response_xml: &str) -> Result<String, FiscalError> {
if request_xml.is_empty() {
return Err(FiscalError::XmlParsing(
"Erro ao protocolar: o XML a protocolar está vazio.".into(),
));
}
if response_xml.is_empty() {
return Err(FiscalError::XmlParsing(
"Erro ao protocolar: o retorno da SEFAZ está vazio.".into(),
));
}
if contains_xml_tag(request_xml, "NFe") {
attach_protocol(request_xml, response_xml)
} else if contains_xml_tag(request_xml, "envEvento") {
attach_event_protocol(request_xml, response_xml)
} else if contains_xml_tag(request_xml, "inutNFe") {
attach_inutilizacao(request_xml, response_xml)
} else {
Err(FiscalError::XmlParsing(
"Tipo de documento não reconhecido para protocolação".into(),
))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn to_authorize_empty_request_returns_error() {
let err = to_authorize("", "<retEnviNFe/>").unwrap_err();
assert!(matches!(err, FiscalError::XmlParsing(_)));
}
#[test]
fn to_authorize_empty_response_returns_error() {
let err = to_authorize("<NFe/>", "").unwrap_err();
assert!(matches!(err, FiscalError::XmlParsing(_)));
}
#[test]
fn to_authorize_unrecognized_document_returns_error() {
let err = to_authorize("<other>data</other>", "<response/>").unwrap_err();
let msg = format!("{err}");
assert!(
msg.contains("não reconhecido"),
"should mention unrecognized type: {msg}"
);
}
#[test]
fn to_authorize_dispatches_nfe() {
let request = concat!(
r#"<NFe><infNFe versao="4.00" Id="NFe35260112345678000199550010000000011123456780">"#,
r#"<DigestValue>abc</DigestValue>"#,
r#"</infNFe></NFe>"#
);
let response = concat!(
r#"<protNFe versao="4.00"><infProt>"#,
r#"<cStat>100</cStat><xMotivo>OK</xMotivo>"#,
r#"<digVal>abc</digVal>"#,
r#"<chNFe>35260112345678000199550010000000011123456780</chNFe>"#,
r#"</infProt></protNFe>"#
);
let result = to_authorize(request, response).unwrap();
assert!(result.contains("<nfeProc"));
}
#[test]
fn to_authorize_dispatches_env_evento() {
let request = concat!(
r#"<envEvento><idLote>1</idLote>"#,
r#"<evento versao="1.00"><infEvento>"#,
r#"<tpEvento>110110</tpEvento>"#,
r#"</infEvento></evento></envEvento>"#
);
let response = concat!(
r#"<retEnvEvento><idLote>1</idLote>"#,
r#"<retEvento versao="1.00"><infEvento>"#,
r#"<cStat>135</cStat><xMotivo>OK</xMotivo>"#,
r#"<tpEvento>110110</tpEvento>"#,
r#"</infEvento></retEvento></retEnvEvento>"#
);
let result = to_authorize(request, response).unwrap();
assert!(result.contains("<procEventoNFe"));
}
#[test]
fn to_authorize_dispatches_inut_nfe() {
let request = concat!(
r#"<inutNFe versao="4.00"><infInut>"#,
r#"<tpAmb>2</tpAmb><cUF>35</cUF><ano>26</ano>"#,
r#"<CNPJ>12345678000199</CNPJ><mod>55</mod><serie>1</serie>"#,
r#"<nNFIni>1</nNFIni><nNFFin>10</nNFFin>"#,
r#"</infInut></inutNFe>"#
);
let response = concat!(
r#"<retInutNFe versao="4.00"><infInut>"#,
r#"<cStat>102</cStat><xMotivo>Inutilizacao homologada</xMotivo>"#,
r#"<tpAmb>2</tpAmb><cUF>35</cUF><ano>26</ano>"#,
r#"<CNPJ>12345678000199</CNPJ><mod>55</mod><serie>1</serie>"#,
r#"<nNFIni>1</nNFIni><nNFFin>10</nNFFin>"#,
r#"</infInut></retInutNFe>"#
);
let result = to_authorize(request, response).unwrap();
assert!(result.contains("<ProcInutNFe"));
}
}