feat: implementar estrutura Pessoa e funções de processamento de arquivos DMED
This commit is contained in:
@@ -3,6 +3,10 @@ name = "dmed"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "dmed"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1,76 @@
|
|||||||
|
// Exemplo de como usar a lib dmed em um comparador
|
||||||
|
|
||||||
|
use dmed::{processar_arquivo, Pessoa, buscar_por_cpf};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
fn main() -> std::io::Result<()> {
|
||||||
|
// Processa dois arquivos diferentes
|
||||||
|
println!("=== COMPARADOR DE ARQUIVOS DMED ===\n");
|
||||||
|
|
||||||
|
let arquivo1 = "LfsIssDmed068325.txt";
|
||||||
|
let pessoas1 = processar_arquivo(arquivo1)?;
|
||||||
|
|
||||||
|
println!("Arquivo 1: {} registros", pessoas1.len());
|
||||||
|
// let pessoas2 = processar_arquivo("arquivo2.txt")?;
|
||||||
|
// println!("Arquivo 2: {} registros\n", pessoas2.len());
|
||||||
|
|
||||||
|
// Cria um mapa de CPF -> Pessoa para busca rápida
|
||||||
|
let mapa1: HashMap<&str, &Pessoa> = pessoas1
|
||||||
|
.iter()
|
||||||
|
.map(|p| (p.cpf.as_str(), p))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Exemplo 1: Buscar CPF específico
|
||||||
|
println!("=== Busca de CPF ===");
|
||||||
|
let cpf_busca = "00276808860";
|
||||||
|
if let Some(pessoa) = buscar_por_cpf(&pessoas1, cpf_busca) {
|
||||||
|
println!("✓ CPF {} encontrado", cpf_busca);
|
||||||
|
println!(" Nome: {}", pessoa.nome);
|
||||||
|
println!(" Valor: R$ {:.2}", pessoa.valor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exemplo 2: Comparar valores de mesmos CPFs entre arquivos
|
||||||
|
println!("\n=== Comparação de valores ===");
|
||||||
|
// Simulando segundo arquivo com mesmos CPFs mas valores diferentes
|
||||||
|
let cpfs_exemplo = ["00276808860", "00633999032", "01133252826"];
|
||||||
|
|
||||||
|
for cpf in &cpfs_exemplo {
|
||||||
|
if let Some(p1) = mapa1.get(cpf) {
|
||||||
|
println!("\nCPF: {}", cpf);
|
||||||
|
println!(" Arquivo 1: R$ {:.2}", p1.valor);
|
||||||
|
// if let Some(p2) = mapa2.get(cpf) {
|
||||||
|
// let diferenca = p2.valor - p1.valor;
|
||||||
|
// println!(" Arquivo 2: R$ {:.2}", p2.valor);
|
||||||
|
// println!(" Diferença: R$ {:.2} ({:+.1}%)",
|
||||||
|
// diferenca,
|
||||||
|
// (diferenca / p1.valor) * 100.0
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exemplo 3: Encontrar divergências
|
||||||
|
println!("\n=== Análise de divergências ===");
|
||||||
|
let total_registros = pessoas1.len();
|
||||||
|
let com_valor = pessoas1.iter().filter(|p| p.valor > 0.0).count();
|
||||||
|
let sem_valor = total_registros - com_valor;
|
||||||
|
|
||||||
|
println!("Total de registros: {}", total_registros);
|
||||||
|
println!("Com valor: {}", com_valor);
|
||||||
|
println!("Sem valor: {}", sem_valor);
|
||||||
|
|
||||||
|
// Exemplo 4: Top 5 maiores valores
|
||||||
|
println!("\n=== Top 5 maiores valores ===");
|
||||||
|
let mut pessoas_sorted = pessoas1.clone();
|
||||||
|
pessoas_sorted.sort_by(|a, b| b.valor.partial_cmp(&a.valor).unwrap());
|
||||||
|
|
||||||
|
for (i, pessoa) in pessoas_sorted.iter().take(5).enumerate() {
|
||||||
|
println!("{}. {} - R$ {:.2}",
|
||||||
|
i + 1,
|
||||||
|
pessoa.nome,
|
||||||
|
pessoa.valor
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
+109
@@ -0,0 +1,109 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::fs;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||||
|
pub struct Pessoa {
|
||||||
|
pub cpf: String,
|
||||||
|
pub nome: String,
|
||||||
|
pub valor: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pessoa {
|
||||||
|
/// Cria uma Pessoa a partir de uma linha do arquivo
|
||||||
|
pub fn from_line(line: &str) -> Option<Self> {
|
||||||
|
let parts: Vec<&str> = line.split('|').collect();
|
||||||
|
|
||||||
|
// Verifica se a linha começa com RPPSS e tem pelo menos 4 campos
|
||||||
|
if parts.len() >= 4 && parts[0] == "RPPSS" {
|
||||||
|
let cpf = parts[1].to_string();
|
||||||
|
let nome = parts[2].to_string();
|
||||||
|
|
||||||
|
// Converte o valor: os 2 últimos dígitos são decimais
|
||||||
|
let valor_str = parts[3];
|
||||||
|
let valor = if !valor_str.is_empty() {
|
||||||
|
valor_str.parse::<f64>().unwrap_or(0.0) / 100.0
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
};
|
||||||
|
|
||||||
|
return Some(Pessoa { cpf, nome, valor });
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Processa um arquivo DMED e retorna um vetor de pessoas
|
||||||
|
pub fn processar_arquivo(caminho: &str) -> io::Result<Vec<Pessoa>> {
|
||||||
|
let conteudo = fs::read_to_string(caminho)?;
|
||||||
|
processar_conteudo(&conteudo)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Processa o conteúdo de um arquivo DMED (útil para testes ou strings)
|
||||||
|
pub fn processar_conteudo(conteudo: &str) -> io::Result<Vec<Pessoa>> {
|
||||||
|
let linhas: Vec<&str> = conteudo.lines().collect();
|
||||||
|
|
||||||
|
let mut pessoas = Vec::new();
|
||||||
|
|
||||||
|
// Pula as 4 primeiras linhas e processa o resto
|
||||||
|
for linha in linhas.iter().skip(4) {
|
||||||
|
if let Some(pessoa) = Pessoa::from_line(linha) {
|
||||||
|
pessoas.push(pessoa);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(pessoas)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converte um vetor de pessoas para JSON
|
||||||
|
pub fn para_json(pessoas: &[Pessoa]) -> Result<String, serde_json::Error> {
|
||||||
|
serde_json::to_string_pretty(pessoas)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Busca uma pessoa pelo CPF
|
||||||
|
pub fn buscar_por_cpf<'a>(pessoas: &'a [Pessoa], cpf: &str) -> Option<&'a Pessoa> {
|
||||||
|
pessoas.iter().find(|p| p.cpf == cpf)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Filtra pessoas com valor acima de um mínimo
|
||||||
|
pub fn filtrar_por_valor_minimo(pessoas: &[Pessoa], valor_minimo: f64) -> Vec<&Pessoa> {
|
||||||
|
pessoas.iter().filter(|p| p.valor >= valor_minimo).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_pessoa_from_line() {
|
||||||
|
let linha = "RPPSS|00276808860|MARCO ANTONIO MACHADO|2200000|";
|
||||||
|
let pessoa = Pessoa::from_line(linha).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(pessoa.cpf, "00276808860");
|
||||||
|
assert_eq!(pessoa.nome, "MARCO ANTONIO MACHADO");
|
||||||
|
assert_eq!(pessoa.valor, 22000.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_pessoa_from_line_invalida() {
|
||||||
|
let linha = "OUTRAS|123|TESTE|100|";
|
||||||
|
assert!(Pessoa::from_line(linha).is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_processar_conteudo() {
|
||||||
|
let conteudo = r#"Dmed|2026|2025|N|||
|
||||||
|
RESPO|21681939835|Anelisa Pirola Chalegre|17|35316200|205||anelisa@edegarpirolacontabilidade.com.br|
|
||||||
|
DECPJ|03364887000195|CLINICA DE CIRURGIA PLASTICA DR VIDAL LTDA|1|||01877281867|N|||
|
||||||
|
PSS|
|
||||||
|
RPPSS|00276808860|MARCO ANTONIO MACHADO|2200000|
|
||||||
|
RPPSS|00633999032|ELISANDRA BARBOSA TORRES|600000|
|
||||||
|
FIMDmed|"#;
|
||||||
|
|
||||||
|
let pessoas = processar_conteudo(conteudo).unwrap();
|
||||||
|
assert_eq!(pessoas.len(), 2);
|
||||||
|
assert_eq!(pessoas[0].cpf, "00276808860");
|
||||||
|
assert_eq!(pessoas[1].valor, 6000.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
-52
@@ -1,53 +1,6 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use dmed::{processar_arquivo, para_json, buscar_por_cpf, filtrar_por_valor_minimo};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::{self, BufRead};
|
use std::io;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
||||||
struct Pessoa {
|
|
||||||
cpf: String,
|
|
||||||
nome: String,
|
|
||||||
valor: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Pessoa {
|
|
||||||
fn from_line(line: &str) -> Option<Self> {
|
|
||||||
let parts: Vec<&str> = line.split('|').collect();
|
|
||||||
|
|
||||||
// Verifica se a linha começa com RPPSS e tem pelo menos 4 campos
|
|
||||||
if parts.len() >= 4 && parts[0] == "RPPSS" {
|
|
||||||
let cpf = parts[1].to_string();
|
|
||||||
let nome = parts[2].to_string();
|
|
||||||
|
|
||||||
// Converte o valor: os 2 últimos dígitos são decimais
|
|
||||||
let valor_str = parts[3];
|
|
||||||
let valor = if !valor_str.is_empty() {
|
|
||||||
valor_str.parse::<f64>().unwrap_or(0.0) / 100.0
|
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
};
|
|
||||||
|
|
||||||
return Some(Pessoa { cpf, nome, valor });
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn processar_arquivo(caminho: &str) -> io::Result<Vec<Pessoa>> {
|
|
||||||
let conteudo = fs::read_to_string(caminho)?;
|
|
||||||
let linhas: Vec<&str> = conteudo.lines().collect();
|
|
||||||
|
|
||||||
let mut pessoas = Vec::new();
|
|
||||||
|
|
||||||
// Pula as 4 primeiras linhas e processa o resto
|
|
||||||
for linha in linhas.iter().skip(4) {
|
|
||||||
if let Some(pessoa) = Pessoa::from_line(linha) {
|
|
||||||
pessoas.push(pessoa);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(pessoas)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> io::Result<()> {
|
fn main() -> io::Result<()> {
|
||||||
let arquivo = "LfsIssDmed068325.txt";
|
let arquivo = "LfsIssDmed068325.txt";
|
||||||
@@ -68,7 +21,7 @@ fn main() -> io::Result<()> {
|
|||||||
println!("\n=== Convertendo para JSON ===");
|
println!("\n=== Convertendo para JSON ===");
|
||||||
|
|
||||||
// Converte para JSON (formatado)
|
// Converte para JSON (formatado)
|
||||||
let json = serde_json::to_string_pretty(&pessoas)?;
|
let json = para_json(&pessoas).expect("Erro ao converter para JSON");
|
||||||
|
|
||||||
// Exibe primeiros caracteres do JSON
|
// Exibe primeiros caracteres do JSON
|
||||||
println!("JSON gerado ({} bytes):", json.len());
|
println!("JSON gerado ({} bytes):", json.len());
|
||||||
@@ -80,13 +33,21 @@ fn main() -> io::Result<()> {
|
|||||||
println!("\n✓ JSON salvo em output.json");
|
println!("\n✓ JSON salvo em output.json");
|
||||||
|
|
||||||
// Exemplo: buscar uma pessoa específica
|
// Exemplo: buscar uma pessoa específica
|
||||||
println!("\n=== Exemplo de busca ===");
|
println!("\n=== Exemplo de busca por CPF ===");
|
||||||
if let Some(pessoa) = pessoas.iter().find(|p| p.cpf == "00276808860") {
|
if let Some(pessoa) = buscar_por_cpf(&pessoas, "00276808860") {
|
||||||
println!("Pessoa encontrada:");
|
println!("Pessoa encontrada:");
|
||||||
println!(" CPF: {}", pessoa.cpf);
|
println!(" CPF: {}", pessoa.cpf);
|
||||||
println!(" Nome: {}", pessoa.nome);
|
println!(" Nome: {}", pessoa.nome);
|
||||||
println!(" Valor: R$ {:.2}", pessoa.valor);
|
println!(" Valor: R$ {:.2}", pessoa.valor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Exemplo: filtrar por valor mínimo
|
||||||
|
println!("\n=== Pessoas com valor >= R$ 10.000,00 ===");
|
||||||
|
let pessoas_alto_valor = filtrar_por_valor_minimo(&pessoas, 10000.0);
|
||||||
|
println!("Total: {} pessoas", pessoas_alto_valor.len());
|
||||||
|
for pessoa in pessoas_alto_valor.iter().take(3) {
|
||||||
|
println!(" {} - R$ {:.2}", pessoa.nome, pessoa.valor);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user