from __future__ import annotations import hashlib from datetime import date from decimal import Decimal from pathlib import Path from typing import Any def _fmt_data(d: date | None) -> str: if d is None: return "" return d.strftime("%d%m%Y") def _fmt_decimal(v: Decimal | None, casas: int = 2) -> str: if v is None or v == 0: return "" return f"{v:.{casas}f}".replace(".", ",") def _fmt_str(v: Any) -> str: if v is None: return "" return str(v).strip() class RegistroSPED: def __init__(self, tipo: str): self.tipo = tipo self._campos: list[str] = [] def add(self, valor: Any, tipo_campo: str = "str", casas: int = 2) -> "RegistroSPED": if valor is None or valor == "": self._campos.append("") elif tipo_campo == "data": self._campos.append(_fmt_data(valor)) elif tipo_campo == "decimal": self._campos.append(_fmt_decimal(Decimal(str(valor)), casas)) elif tipo_campo == "int": self._campos.append(str(int(valor))) else: self._campos.append(str(valor).strip()) return self def to_line(self) -> str: campos = [self.tipo] + self._campos return "|" + "|".join(campos) + "|\n" class ArquivoSPED: def __init__(self, nome_arquivo: str): self.nome_arquivo = nome_arquivo self._linhas: list[str] = [] self._contadores: dict[str, int] = {} def _add_linha(self, linha: str) -> None: self._linhas.append(linha) tipo = linha.split("|")[1] if "|" in linha else "" self._contadores[tipo] = self._contadores.get(tipo, 0) + 1 def adicionar_registro(self, reg: RegistroSPED) -> None: self._add_linha(reg.to_line()) def adicionar_linha_raw(self, linha: str) -> None: if not linha.endswith("\n"): linha += "\n" self._add_linha(linha) def total_linhas(self) -> int: return len(self._linhas) def conteudo(self) -> str: return "".join(self._linhas) def salvar(self, diretorio: str | Path = ".") -> Path: caminho = Path(diretorio) / self.nome_arquivo caminho.parent.mkdir(parents=True, exist_ok=True) caminho.write_text(self.conteudo(), encoding="utf-8") return caminho def hash_md5(self) -> str: return hashlib.md5(self.conteudo().encode("utf-8")).hexdigest() def criar_registro(tipo: str, *campos) -> str: partes = [tipo] for campo in campos: if campo is None: partes.append("") elif isinstance(campo, date): partes.append(_fmt_data(campo)) elif isinstance(campo, Decimal): partes.append(_fmt_decimal(campo)) elif isinstance(campo, float): partes.append(_fmt_decimal(Decimal(str(campo)))) else: partes.append(str(campo).strip()) return "|" + "|".join(partes) + "|\n"