feat: implementar estrutura Pessoa e funções de processamento de arquivos DMED

This commit is contained in:
FelipeCN
2026-01-30 09:22:21 -03:00
parent 5148ad89ff
commit fab1c26445
5 changed files with 202 additions and 52 deletions
+109
View File
@@ -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
View File
@@ -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::io::{self, BufRead};
#[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)
}
use std::io;
fn main() -> io::Result<()> {
let arquivo = "LfsIssDmed068325.txt";
@@ -68,7 +21,7 @@ fn main() -> io::Result<()> {
println!("\n=== Convertendo para JSON ===");
// 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
println!("JSON gerado ({} bytes):", json.len());
@@ -80,13 +33,21 @@ fn main() -> io::Result<()> {
println!("\n✓ JSON salvo em output.json");
// Exemplo: buscar uma pessoa específica
println!("\n=== Exemplo de busca ===");
if let Some(pessoa) = pessoas.iter().find(|p| p.cpf == "00276808860") {
println!("\n=== Exemplo de busca por CPF ===");
if let Some(pessoa) = buscar_por_cpf(&pessoas, "00276808860") {
println!("Pessoa encontrada:");
println!(" CPF: {}", pessoa.cpf);
println!(" Nome: {}", pessoa.nome);
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(())
}