teste_laudos / utils /formatters.py
gui-sparim's picture
Upload 44 files
8d6c767 verified
"""
Formatadores de texto e valores monetários.
"""
import re
from typing import Tuple, List, Dict
def numero_para_extenso(valor: float) -> str:
"""Converte um valor numérico para sua representação por extenso em português."""
if valor == 0:
return "zero reais"
unidades = ['', 'um', 'dois', 'três', 'quatro', 'cinco', 'seis', 'sete', 'oito', 'nove']
especiais = ['dez', 'onze', 'doze', 'treze', 'quatorze', 'quinze', 'dezesseis', 'dezessete', 'dezoito', 'dezenove']
dezenas = ['', '', 'vinte', 'trinta', 'quarenta', 'cinquenta', 'sessenta', 'setenta', 'oitenta', 'noventa']
centenas = ['', 'cento', 'duzentos', 'trezentos', 'quatrocentos', 'quinhentos', 'seiscentos', 'setecentos', 'oitocentos', 'novecentos']
def converter_grupo(n):
if n == 0:
return ''
if n == 100:
return 'cem'
resultado = ''
if n >= 100:
resultado += centenas[n // 100]
n %= 100
if n > 0:
resultado += ' e '
if n >= 20:
resultado += dezenas[n // 10]
n %= 10
if n > 0:
resultado += ' e ' + unidades[n]
elif n >= 10:
resultado += especiais[n - 10]
elif n > 0:
resultado += unidades[n]
return resultado
parte_inteira = int(valor)
centavos = round((valor - parte_inteira) * 100)
resultado = ''
if parte_inteira >= 1000000:
milhoes = parte_inteira // 1000000
if milhoes == 1:
resultado += 'um milhão'
else:
resultado += converter_grupo(milhoes) + ' milhões'
parte_inteira %= 1000000
if parte_inteira > 0:
resultado += ' e '
if parte_inteira >= 1000:
milhares = parte_inteira // 1000
if milhares == 1:
resultado += 'mil'
else:
resultado += converter_grupo(milhares) + ' mil'
parte_inteira %= 1000
if parte_inteira > 0:
resultado += ' e '
if parte_inteira > 0:
resultado += converter_grupo(parte_inteira)
if resultado:
if int(valor) == 1:
resultado += ' real'
else:
resultado += ' reais'
if centavos > 0:
if resultado:
resultado += ' e '
resultado += converter_grupo(centavos)
if centavos == 1:
resultado += ' centavo'
else:
resultado += ' centavos'
return resultado
def parse_valor_monetario(valor_str: str) -> float:
"""Converte string de valor monetário para float."""
if not valor_str:
return 0.0
valor_limpo = re.sub(r'[^\d,.]', '', valor_str)
valor_limpo = valor_limpo.replace('.', '').replace(',', '.')
try:
return float(valor_limpo)
except ValueError:
return 0.0
def formatar_valor_monetario(valor_str: str) -> Tuple[str, str]:
"""Formata valor monetário e retorna tupla (valor_formatado, extenso)."""
valor_float = parse_valor_monetario(valor_str)
if valor_float == 0:
return valor_str, ""
valor_formatado = f"R$ {valor_float:,.2f}".replace(',', 'X').replace('.', ',').replace('X', '.')
extenso = numero_para_extenso(valor_float)
return valor_formatado, extenso
def aplicar_mascara_monetaria(valor: str) -> str:
"""Aplica máscara monetária brasileira a um valor."""
if not valor:
return ""
valor = valor.strip()
if re.match(r'^R\$\s*[\d\.]+,\d{2}$', valor):
return valor
if re.search(r'[a-zA-ZáéíóúãõâêîôûàèìòùçÁÉÍÓÚÃÕÂÊÎÔÛÀÈÌÒÙÇ]', valor):
return valor
valor_limpo = re.sub(r'R\$\s*', '', valor)
if ',' in valor_limpo and '.' in valor_limpo:
valor_limpo = valor_limpo.replace('.', '').replace(',', '.')
elif ',' in valor_limpo:
valor_limpo = valor_limpo.replace(',', '.')
try:
valor_float = float(valor_limpo)
except ValueError:
return valor
return f"R$ {valor_float:,.2f}".replace(',', 'X').replace('.', ',').replace('X', '.')
def formatar_lista_para_documento(items: List[str]) -> str:
"""Formata lista de itens para inclusão no documento."""
items_limpos = [i.strip() for i in items if i and i.strip()]
if not items_limpos:
return ""
return "\n".join([f"- {i};" for i in items_limpos])
def formatar_valores_mercado_para_documento(anos: List[str], valores: List[str]) -> str:
"""Formata lista de valores de mercado por ano para inclusão no documento."""
linhas = []
for ano, valor in zip(anos, valores):
if ano and valor:
try:
ano_str = str(int(float(ano))) if ano else ""
except (ValueError, TypeError):
ano_str = str(ano) if ano else ""
valor_float = parse_valor_monetario(valor)
if valor_float > 0:
extenso = numero_para_extenso(valor_float)
linhas.append(f"{ano_str} - {valor} ({extenso})")
else:
linhas.append(f"{ano_str} - {valor}")
if not linhas:
return ""
return "\n".join(linhas)
def formatar_motivos_desvalorizantes(motivos: List[Dict]) -> Dict:
"""Formata a lista unificada de motivos desvalorizantes."""
if not motivos:
return {
'alegados': [],
'confirmados': [],
'todos': [],
'alegados_texto': '',
'confirmados_texto': '',
'secoes': []
}
alegados = []
confirmados = []
todos = []
secoes = []
for i, motivo in enumerate(motivos, 1):
descricao = motivo.get('descricao', '').strip()
foi_alegado = motivo.get('alegado', False)
foi_confirmado = motivo.get('confirmado', False)
if not descricao:
continue
item = {
'numero': i,
'descricao': descricao,
'alegado': foi_alegado,
'confirmado': foi_confirmado
}
todos.append(item)
if foi_alegado:
alegados.append(descricao)
if foi_confirmado:
confirmados.append(descricao)
status = []
if foi_alegado:
status.append("alegado pelo contribuinte")
else:
status.append("não alegado pelo contribuinte")
if foi_confirmado:
status.append("e confirmado na análise")
else:
status.append("e não confirmado na análise")
secoes.append({
'numero': i,
'titulo': descricao,
'status': ", ".join(status) if status else "identificado na vistoria",
'confirmado': foi_confirmado
})
alegados_texto = formatar_lista_para_documento(alegados)
confirmados_texto = formatar_lista_para_documento(confirmados)
return {
'alegados': alegados,
'confirmados': confirmados,
'todos': todos,
'alegados_texto': alegados_texto,
'confirmados_texto': confirmados_texto,
'secoes': secoes
}