""" 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 }