refactor: organiza imports e simplifica funções em diversos arquivos

This commit is contained in:
2026-03-03 11:59:50 -03:00
parent 2c08f237e9
commit 0354ece935
14 changed files with 110 additions and 202 deletions
+10 -16
View File
@@ -1,11 +1,11 @@
use crate::domain::{
entities::{
nota::Nota,
resultado_analise::{IntervaloSerie, ResultadoAnalise, ResultadoPreAnalise},
resultado_analise::{ResultadoAnalise, ResultadoPreAnalise},
},
services::{
detector_duplicidade::duplicidades_por_serie,
detector_sequencia::{calcular_intervalo, detectar_faltantes, LIMITE_FALTANTES},
detector_sequencia::{LIMITE_FALTANTES, calcular_intervalo, detectar_faltantes},
},
};
use rust_decimal::Decimal;
@@ -55,9 +55,7 @@ pub fn pre_analisar(notas: &[Nota]) -> ResultadoPreAnalise {
/// Verifica se alguma série excede o limite de faltantes.
/// Retorna lista de séries que precisam de confirmação.
pub fn series_com_intervalo_excessivo(
pre: &ResultadoPreAnalise,
) -> Vec<(String, u64)> {
pub fn series_com_intervalo_excessivo(pre: &ResultadoPreAnalise) -> Vec<(String, u64)> {
pre.intervalos_por_serie
.iter()
.filter(|(_, iv)| iv.excede_limite(LIMITE_FALTANTES))
@@ -89,19 +87,18 @@ pub fn expandir_analise(pre: ResultadoPreAnalise, notas: &[Nota]) -> ResultadoAn
}
}
/// Executa análise completa sem verificar limites (use case simplificado).
/// Útil quando o caller já confirmou ou sabe que não há intervalos excessivos.
pub fn executar_analise(notas: &[Nota]) -> ResultadoAnalise {
let pre = pre_analisar(notas);
expandir_analise(pre, notas)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::domain::entities::nota::Nota;
use rust_decimal_macros::dec;
/// Executa análise completa sem verificar limites (atalho para testes).
fn executar_analise(notas: &[Nota]) -> ResultadoAnalise {
let pre = pre_analisar(notas);
expandir_analise(pre, notas)
}
fn nota(numero: u64, serie: &str, valor: Option<rust_decimal::Decimal>) -> Nota {
Nota::new(numero, serie.to_string(), valor, None)
}
@@ -133,10 +130,7 @@ mod tests {
#[test]
fn pre_analise_detecta_intervalo_excessivo() {
let notas = vec![
nota(1, "001", None),
nota(20_000, "001", None),
];
let notas = vec![nota(1, "001", None), nota(20_000, "001", None)];
let pre = pre_analisar(&notas);
let excessivos = series_com_intervalo_excessivo(&pre);
assert_eq!(excessivos.len(), 1);
+27 -14
View File
@@ -1,4 +1,4 @@
use crate::domain::entities::layout::{Layout, LayoutCsv, LayoutXlsx};
use crate::domain::entities::layout::{LayoutCsv, LayoutXlsx};
use crate::domain::entities::nota::Nota;
use crate::domain::entities::serie::validar_serie;
use crate::domain::errors::{ErroArquivo, ResumoAvisos};
@@ -24,7 +24,10 @@ pub fn listar_abas_xlsx(caminho: &Path) -> Result<InfoXlsx, ErroArquivo> {
}
/// Importa um arquivo CSV e retorna as notas válidas + avisos consolidados.
pub fn importar_csv(caminho: &Path, config: &LayoutCsv) -> Result<ResultadoImportacao, ErroArquivo> {
pub fn importar_csv(
caminho: &Path,
config: &LayoutCsv,
) -> Result<ResultadoImportacao, ErroArquivo> {
let resultado = csv_reader::ler_csv(
caminho,
config.delimitador as u8,
@@ -46,17 +49,21 @@ pub fn importar_csv(caminho: &Path, config: &LayoutCsv) -> Result<ResultadoImpor
}
/// Importa um arquivo XLSX e retorna as notas válidas + avisos consolidados.
pub fn importar_xlsx(caminho: &Path, config: &LayoutXlsx) -> Result<ResultadoImportacao, ErroArquivo> {
pub fn importar_xlsx(
caminho: &Path,
config: &LayoutXlsx,
) -> Result<ResultadoImportacao, ErroArquivo> {
// Determinar linha de início a partir de qualquer campo mapeado
let linha_inicio = {
let coord_num = xlsx_reader::parsear_letra_linha(&config.pos_numero)
.ok_or_else(|| ErroArquivo::ErroLeitura(format!(
"Posição de Numero inválida: '{}'", config.pos_numero
)))?;
let coord_ser = xlsx_reader::parsear_letra_linha(&config.pos_serie)
.ok_or_else(|| ErroArquivo::ErroLeitura(format!(
"Posição de Serie inválida: '{}'", config.pos_serie
)))?;
let coord_num = xlsx_reader::parsear_letra_linha(&config.pos_numero).ok_or_else(|| {
ErroArquivo::ErroLeitura(format!(
"Posição de Numero inválida: '{}'",
config.pos_numero
))
})?;
let coord_ser = xlsx_reader::parsear_letra_linha(&config.pos_serie).ok_or_else(|| {
ErroArquivo::ErroLeitura(format!("Posição de Serie inválida: '{}'", config.pos_serie))
})?;
coord_num.linha.min(coord_ser.linha)
};
@@ -113,7 +120,9 @@ fn mapear_linhas_para_notas(
Some(s) if !s.trim().is_empty() => s.trim().to_string(),
_ => {
avisos.numeros_invalidos += 1;
avisos.detalhes.push(format!("Linha {}: campo Numero ausente", linha_num));
avisos
.detalhes
.push(format!("Linha {}: campo Numero ausente", linha_num));
continue;
}
};
@@ -123,7 +132,9 @@ fn mapear_linhas_para_notas(
Ok(n) => n,
Err(msg) => {
avisos.numeros_invalidos += 1;
avisos.detalhes.push(format!("Linha {}: {}", linha_num, msg));
avisos
.detalhes
.push(format!("Linha {}: {}", linha_num, msg));
continue;
}
};
@@ -133,7 +144,9 @@ fn mapear_linhas_para_notas(
Some(s) => s.trim().to_string(),
None => {
avisos.series_invalidas += 1;
avisos.detalhes.push(format!("Linha {}: campo Serie ausente", linha_num));
avisos
.detalhes
.push(format!("Linha {}: campo Serie ausente", linha_num));
continue;
}
};
+6 -14
View File
@@ -2,7 +2,7 @@ use crate::domain::{
entities::layout::{Layout, LayoutJson},
errors::ErroLayout,
};
use crate::infrastructure::sqlite::{layout_repository, migrations};
use crate::infrastructure::sqlite::layout_repository;
use rusqlite::Connection;
/// Salva um layout no banco de dados.
@@ -14,12 +14,10 @@ pub fn salvar_layout(conn: &Connection, layout: &Layout) -> Result<i64, String>
}
if let Some(id) = layout.id() {
layout_repository::atualizar(conn, layout)
.map_err(|e| e.to_string())?;
layout_repository::atualizar(conn, layout).map_err(|e| e.to_string())?;
Ok(id)
} else {
layout_repository::salvar(conn, layout)
.map_err(|e| e.to_string())
layout_repository::salvar(conn, layout).map_err(|e| e.to_string())
}
}
@@ -28,11 +26,6 @@ pub fn listar_layouts(conn: &Connection) -> Result<Vec<Layout>, String> {
layout_repository::listar(conn).map_err(|e| e.to_string())
}
/// Carrega um layout pelo id.
pub fn carregar_layout(conn: &Connection, id: i64) -> Result<Option<Layout>, String> {
layout_repository::buscar_por_id(conn, id).map_err(|e| e.to_string())
}
/// Exclui um layout pelo id.
pub fn excluir_layout(conn: &Connection, id: i64) -> Result<(), String> {
layout_repository::excluir(conn, id).map_err(|e| e.to_string())
@@ -61,8 +54,8 @@ pub fn importar_layout_json(
novo_nome: Option<&str>,
) -> Result<i64, ErroLayout> {
// Deserializar
let json_repr: LayoutJson = serde_json::from_str(json)
.map_err(|e| ErroLayout::JsonMalformado(e.to_string()))?;
let json_repr: LayoutJson =
serde_json::from_str(json).map_err(|e| ErroLayout::JsonMalformado(e.to_string()))?;
let mut layout = Layout::try_from(json_repr)?;
@@ -105,6 +98,5 @@ pub fn importar_layout_json(
}
// Inserir novo
layout_repository::salvar(conn, &layout)
.map_err(|e| ErroLayout::JsonMalformado(e.to_string()))
layout_repository::salvar(conn, &layout).map_err(|e| ErroLayout::JsonMalformado(e.to_string()))
}