Files
dmed/examples/comparador_completo.rs
T
FelipeCN 3a888a058f feat: add DMED comparador library with TXT and XLS processing
- Implemented TXT processor for DMED files, extracting RPPSS records.
- Added XLS processor for Prosoft reports, supporting both XLS and XLSX formats.
- Created a comparison tool to identify discrepancies between TXT and XLS data.
- Developed a GUI using eframe for user-friendly interaction.
- Included detailed README documentation for setup and usage instructions.
- Added error handling for file processing and improved data extraction methods.
- Implemented tests for data processing functions and utilities.
- Introduced a build script for Windows resource management.
- Added example scripts for basic and complete comparisons.
- Included a report generation feature for discrepancies found during comparisons.
2026-01-30 10:42:23 -03:00

201 lines
7.6 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Comparador completo: TXT (DMED) vs XLS (Prosoft)
use dmed::{processar_arquivo, xls::processar_xls, Pessoa};
use std::collections::{HashMap, HashSet};
#[derive(Debug)]
struct Divergencia {
cpf: String,
nome: String,
valor_txt: f64,
valor_xls: f64,
diferenca: f64,
percentual: f64,
}
fn main() -> std::io::Result<()> {
println!("═══════════════════════════════════════════════");
println!(" COMPARADOR DMED (TXT) vs PROSOFT (XLS)");
println!("═══════════════════════════════════════════════\n");
// Processa arquivo TXT (DMED)
println!("📄 Processando arquivo TXT (DMED)...");
let arquivo_txt = "LfsIssDmed008425.txt";
let pessoas_txt = processar_arquivo(arquivo_txt)?;
println!(" ✓ {} registros encontrados\n", pessoas_txt.len());
// Processa arquivo XLS (Prosoft)
println!("📊 Processando arquivo XLS (Prosoft)...");
let arquivo_xls = "RELATORIO_PROSOFT_MOD_51.xls";
let pessoas_xls = match processar_xls(arquivo_xls) {
Ok(p) => {
println!(" ✓ {} registros únicos encontrados\n", p.len());
p
},
Err(e) => {
println!(" ✗ Erro ao processar XLS: {}", e);
println!(" ️ Coloque o arquivo RELATORIO_PROSOFT_MOD_51.xls na pasta do projeto\n");
return Ok(());
}
};
// Cria mapas para comparação
let mapa_txt: HashMap<&str, &Pessoa> = pessoas_txt
.iter()
.map(|p| (p.cpf.as_str(), p))
.collect();
let mapa_xls: HashMap<&str, &Pessoa> = pessoas_xls
.iter()
.map(|p| (p.cpf.as_str(), p))
.collect();
// Conjunto de todos os CPFs
let todos_cpfs: HashSet<&str> = mapa_txt.keys()
.chain(mapa_xls.keys())
.copied()
.collect();
println!("═══════════════════════════════════════════════");
println!(" ANÁLISE");
println!("═══════════════════════════════════════════════\n");
// Estatísticas
let cpfs_ambos = todos_cpfs.iter()
.filter(|cpf| mapa_txt.contains_key(**cpf) && mapa_xls.contains_key(**cpf))
.count();
let cpfs_so_txt = todos_cpfs.iter()
.filter(|cpf| mapa_txt.contains_key(**cpf) && !mapa_xls.contains_key(**cpf))
.count();
let cpfs_so_xls = todos_cpfs.iter()
.filter(|cpf| !mapa_txt.contains_key(**cpf) && mapa_xls.contains_key(**cpf))
.count();
println!("📊 Estatísticas:");
println!(" Total de CPFs únicos: {}", todos_cpfs.len());
println!(" Presentes em ambos: {}", cpfs_ambos);
println!(" Apenas no TXT: {}", cpfs_so_txt);
println!(" Apenas no XLS: {}", cpfs_so_xls);
// Encontra divergências
let mut divergencias = Vec::new();
let margem_tolerancia = 0.01; // R$ 0,01
for cpf in todos_cpfs.iter() {
if let (Some(p_txt), Some(p_xls)) = (mapa_txt.get(*cpf), mapa_xls.get(*cpf)) {
let diferenca = (p_txt.valor - p_xls.valor).abs();
if diferenca > margem_tolerancia {
let percentual = if p_xls.valor != 0.0 {
((p_txt.valor - p_xls.valor) / p_xls.valor) * 100.0
} else {
0.0
};
divergencias.push(Divergencia {
cpf: cpf.to_string(),
nome: p_txt.nome.clone(),
valor_txt: p_txt.valor,
valor_xls: p_xls.valor,
diferenca,
percentual,
});
}
}
}
// Ordena divergências por diferença (maior primeiro)
divergencias.sort_by(|a, b| b.diferenca.abs().partial_cmp(&a.diferenca.abs()).unwrap());
println!("\n📈 Divergências de valores:");
println!(" Total: {} registros com diferenças\n", divergencias.len());
if !divergencias.is_empty() {
println!("═══════════════════════════════════════════════");
println!(" TOP 10 DIVERGÊNCIAS");
println!("═══════════════════════════════════════════════\n");
for (i, div) in divergencias.iter().take(10).enumerate() {
println!("{}. CPF: {}", i + 1, div.cpf);
if !div.nome.is_empty() {
println!(" Nome: {}", div.nome);
}
println!(" TXT (DMED): R$ {:>12.2}", div.valor_txt);
println!(" XLS (Prosoft): R$ {:>12.2}", div.valor_xls);
println!(" Diferença: R$ {:>12.2} ({:+.1}%)", div.diferenca, div.percentual);
println!();
}
// Salva relatório completo
salvar_relatorio(&divergencias, &mapa_txt, &mapa_xls, cpfs_so_txt, cpfs_so_xls)?;
} else {
println!(" ✓ Todos os valores conferem!\n");
}
// CPFs que estão apenas em um dos arquivos
if cpfs_so_txt > 0 {
println!("⚠️ CPFs apenas no TXT (primeiros 5):");
for cpf in todos_cpfs.iter().filter(|c| mapa_txt.contains_key(**c) && !mapa_xls.contains_key(**c)).take(5) {
if let Some(p) = mapa_txt.get(*cpf) {
println!(" {} - {} - R$ {:.2}", cpf, p.nome, p.valor);
}
}
println!();
}
if cpfs_so_xls > 0 {
println!("⚠️ CPFs apenas no XLS (primeiros 5):");
for cpf in todos_cpfs.iter().filter(|c| !mapa_txt.contains_key(**c) && mapa_xls.contains_key(**c)).take(5) {
if let Some(p) = mapa_xls.get(*cpf) {
println!(" {} - R$ {:.2}", cpf, p.valor);
}
}
println!();
}
Ok(())
}
fn salvar_relatorio(
divergencias: &[Divergencia],
mapa_txt: &HashMap<&str, &Pessoa>,
mapa_xls: &HashMap<&str, &Pessoa>,
cpfs_so_txt: usize,
cpfs_so_xls: usize,
) -> std::io::Result<()> {
use std::fs::File;
use std::io::Write;
let mut arquivo = File::create("relatorio_divergencias.txt")?;
writeln!(arquivo, "RELATÓRIO DE DIVERGÊNCIAS - DMED vs PROSOFT")?;
writeln!(arquivo, "Data: {}", chrono::Local::now().format("%d/%m/%Y %H:%M:%S"))?;
writeln!(arquivo, "=")?;
writeln!(arquivo)?;
writeln!(arquivo, "RESUMO:")?;
writeln!(arquivo, "Total de divergências: {}", divergencias.len())?;
writeln!(arquivo, "CPFs apenas no TXT: {}", cpfs_so_txt)?;
writeln!(arquivo, "CPFs apenas no XLS: {}", cpfs_so_xls)?;
writeln!(arquivo)?;
writeln!(arquivo, "DETALHAMENTO DAS DIVERGÊNCIAS:")?;
writeln!(arquivo, "{:-<100}", "")?;
for (i, div) in divergencias.iter().enumerate() {
writeln!(arquivo, "\n{}. CPF: {}", i + 1, div.cpf)?;
if !div.nome.is_empty() {
writeln!(arquivo, " Nome: {}", div.nome)?;
}
writeln!(arquivo, " TXT (DMED): R$ {:>12.2}", div.valor_txt)?;
writeln!(arquivo, " XLS (Prosoft): R$ {:>12.2}", div.valor_xls)?;
writeln!(arquivo, " Diferença: R$ {:>12.2} ({:+.1}%)", div.diferenca, div.percentual)?;
}
println!("✓ Relatório completo salvo em relatorio_divergencias.txt");
Ok(())
}