Commit inicial - upload de todos os arquivos da pasta

This commit is contained in:
2026-07-24 23:55:21 -03:00
commit 9d4d395881
88 changed files with 9484 additions and 0 deletions
+74
View File
@@ -0,0 +1,74 @@
"""Resolução de competência (mês/ano) com fallback único e compartilhado.
Requisito: quando a competência do documento está ilegível/ausente, atribuir o
**mês/ano corrente** (o mês da importação/lançamento) — mesma semântica que o
antigo "primeiro dia do mês corrente", um passo mais simples (não precisa mais
inventar um dia fictício). Tanto a extração por IA/OCR quanto o cadastro
manual passam por aqui, para nunca divergirem.
"""
from __future__ import annotations
import re
from datetime import date
_ISO_RE = re.compile(r"^(\d{4})-(\d{2})-(\d{2})$")
_BR_RE = re.compile(r"^([0-3]?\d)[/.\-]([01]?\d)[/.\-]((?:19|20)?\d{2})$")
MESES = ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"]
# Intervalo de anos oferecido nos seletores de competência da UI.
ANOS_COMPETENCIA = list(range(2026, 2031))
def current_competencia(reference: date | None = None) -> tuple[int, int]:
ref = reference or date.today()
return ref.month, ref.year
def _valid_date(year: int, month: int, day: int) -> tuple[int, int] | None:
try:
parsed = date(year, month, day)
except ValueError:
return None
return parsed.month, parsed.year
def parse_competencia(value: str | None) -> tuple[int, int] | None:
"""Tenta interpretar uma data em ISO (YYYY-MM-DD) ou BR (dd/mm/aaaa) e
devolve apenas o (mês, ano) correspondente, descartando o dia.
Retorna None (sem fallback) se o valor não for uma data válida — usado
quando a ausência de competência deve ficar visível (ex. staging).
"""
if not value:
return None
text = value.strip()
m = _ISO_RE.match(text)
if m:
return _valid_date(int(m.group(1)), int(m.group(2)), int(m.group(3)))
m = _BR_RE.match(text)
if m:
day, month, year = m.groups()
year_i = int(year)
if year_i < 100:
year_i += 2000
return _valid_date(year_i, int(month), int(day))
return None
def resolve_competencia(value: str | None, *, reference: date | None = None) -> tuple[int, int]:
"""(mês, ano) válidos a partir de `value`, ou o mês/ano corrente quando
ilegível/ausente."""
parsed = parse_competencia(value)
if parsed:
return parsed
return current_competencia(reference)
def format_competencia(mes: int | None, ano: int | None) -> str:
"""Formata mês/ano para exibição, ex. `(6, 2026)` -> "Jun/26"."""
if not mes or not ano or not (1 <= mes <= 12):
return ""
return f"{MESES[mes - 1]}/{ano % 100:02d}"