portal_publico/portal_api/planos_saude/leiaute_sistema.py

74 lines
2.9 KiB
Python

"""
Leitura do arquivo padrão (leiaute) que o sistema (Questor) importa
mensalmente, e escrita no mesmo formato. Formato: CSV separado por ';',
sempre com este cabeçalho:
CODIGOEMPRESA;NOMEFUNC;CPFFUNC;CODIGOOUTEMP;DATAINICIAL;NOMEDEPENDENTE;
CPFDEPENDENTE;VALOREMPRESA;VALOR;DESCRICAO
Porta de projects/project/core/leiaute_sistema.py.
"""
import csv
import io
from typing import List
from portal_api.planos_saude.modelos import LinhaSistema
CABECALHO = [
"CODIGOEMPRESA", "NOMEFUNC", "CPFFUNC", "CODIGOOUTEMP", "DATAINICIAL",
"NOMEDEPENDENTE", "CPFDEPENDENTE", "VALOREMPRESA", "VALOR", "DESCRICAO",
]
def _decodifica_planilha(caminho_csv: str) -> str:
"""A planilha padrão do Questor às vezes sai em UTF-8 (com ou sem BOM),
às vezes em Windows-1252/ANSI — descobrimos isso na prática quando um
nome com acento (ex.: "GONÇALVES") quebrava a leitura com
UnicodeDecodeError, sempre tratado genericamente como "arquivo não é a
planilha padrão" por quem chama esta função. Tenta UTF-8 primeiro (não
muda nada pro caso comum, sem acentos, onde os dois formatos coincidem
byte a byte) e cai pra cp1252 só se a decodificação falhar — mesmo
espírito do `encoding="latin-1"` já usado pelo parser CSV da Unimed."""
with open(caminho_csv, "rb") as f:
conteudo = f.read()
try:
return conteudo.decode("utf-8-sig")
except UnicodeDecodeError:
return conteudo.decode("cp1252")
def le_planilha_padrao(caminho_csv: str) -> List[LinhaSistema]:
linhas = []
texto = _decodifica_planilha(caminho_csv)
with io.StringIO(texto, newline="") as f:
leitor = csv.DictReader(f, delimiter=";")
for row in leitor:
linhas.append(LinhaSistema(
codigo_empresa=row["CODIGOEMPRESA"].strip(),
nome_func=row["NOMEFUNC"].strip(),
cpf_func=row["CPFFUNC"].strip(),
codigo_out_emp=row["CODIGOOUTEMP"].strip(),
data_inicial=row["DATAINICIAL"].strip(),
nome_dependente=row["NOMEDEPENDENTE"].strip(),
cpf_dependente=row["CPFDEPENDENTE"].strip(),
valor_empresa=row["VALOREMPRESA"].strip(),
valor=row["VALOR"].strip(),
descricao=row["DESCRICAO"].strip(),
))
return linhas
def formata_valor_br(valor: float) -> str:
"""0 -> '0' 83.38 -> '83,38' (mantém o padrão já usado na planilha)"""
if valor == 0:
return "0"
return f"{valor:.2f}".replace(".", ",")
def parse_valor_br(texto: str) -> float:
"""Inverso de formata_valor_br — '83,38' -> 83.38 '1.234,56' -> 1234.56.
Usado pra interpretar o "limite de valor"/"% de custeio" digitados pelo
usuário no formulário de nova importação (ver serializers.py)."""
texto = (texto or "").strip().replace(".", "").replace(",", ".")
return float(texto) if texto else 0.0