5.7 KiB
Why
Hoje o LerNotaFiscal extrai e persiste uma data completa (purchase_date, YYYY-MM-DD) do documento fiscal via OCR/IA, mas o valor real de negócio para o usuário é apenas o mês de referência do gasto (competência), não o dia exato. A extração de dia é frequentemente a fonte de baixa confiança/ilegibilidade no OCR (regex DATE_RE e checagem _is_plausible_purchase_date), o dashboard já converte a data para "mês/ano" para exibição (_mes_label, substr(purchase_date, 1, 7)), e o formulário manual já reforça a convenção "1º dia do mês corrente" como fallback. Trocar o campo de data por competência (mês/ano) simplifica a extração, elimina uma fonte de erro/ilegibilidade desnecessária e alinha o dado armazenado com o que o Dashboard e os relatórios realmente precisam.
What Changes
- BREAKING: Remover a coluna
purchase_date(data completa) defiscal_documentsedetected_documents, substituindo por dois campos:mes(inteiro 1-12) eano(inteiro, ex. 2026). - Atualizar a extração via IA (
app/ai_extraction.py) e o fallback OCR (lernotafiscal/extraction.py) para não mais extrair dia — apenas identificar mês/ano do documento quando possível (ex. a partir da mesma data encontrada no texto, descartando o dia). - Adicionar uma etapa de confirmação obrigatória antes do botão "Enviar/Revisar": perguntar explicitamente a Competência: Mês/Ano de cada documento na tela de revisão (
staging.html), com dois campos<select>— Mês (Jan, Fev, Mar, Abr, Mai, Jun, Jul, Ago, Set, Out, Nov, Dez) e Ano (2026, 2027, 2028, 2029, 2030) — pré-selecionados com o valor detectado quando disponível, permitindo correção manual antes de confirmar o lote. - Aplicar o mesmo par de selects (Mês/Ano) no formulário manual de documento (
document_form.html), substituindo o<input type="date">atual. - Atualizar
confirm_batch/create_fiscal/update_fiscalpara gravarmes/anoem vez depurchase_date, commeseanoobrigatórios (mesma garantia de não-nulo quepurchase_datetinha). - Atualizar todas as agregações e filtros que hoje dependem de
purchase_date:monthly_totals(Dashboard: "Gastos por mês") passa a agrupar diretamente porano/mesem vez desubstr(purchase_date, 1, 7).category_totals,_fiscal_where,FISCAL_SORT_COLUMNSe a listagem/documents(documents_list.html) passam a filtrar/ordenar porano/mesem vez de intervalo de datas (start/enddo tipo date).- Exibição de "Competência" (ex.
Jun/2026) substitui a coluna/célula "Data" no Dashboard e em/documents.
- Atualizar scripts e testes que hoje gravam/leem
purchase_datediretamente (scripts/migrate_notas.py,tests/test_app.py,tests/test_ingestion.py,tests/test_categorization.py) para o novo par de campos.
Capabilities
New Capabilities
document-competencia: Cobre a captura, revisão, persistência, exibição e filtragem da competência (mês/ano) de um documento fiscal, substituindo o conceito de data completa de compra em todo o fluxo (upload → revisão → confirmação → dashboard → listagem/filtros).
Modified Capabilities
(nenhuma — não há specs existentes em openspec/specs/; o item acima é tratado como nova capability, que substitui integralmente o comportamento de data hoje implícito no código)
Impact
- Banco de dados (
app/database.py): remoção depurchase_date(e do índiceidx_fiscal_date) defiscal_documentsedetected_documents; novas colunasmes INTEGER NOT NULLeano INTEGER NOT NULL(com índice equivalenteidx_fiscal_competenciaem(ano, mes)); rebuild de tabela (SQLite não remove coluna comALTER TABLEem todas as versões-alvo) com backfill dos dados existentes a partir dopurchase_dateatual antes de descartá-lo. - Extração (
app/ai_extraction.py,lernotafiscal/extraction.py,app/ingestion.py): prompt de IA e regex OCR passam a reportar mês/ano em vez de dia completo;RawExtraction/DetectedDocumentCandidatetrocampurchase_date_raw/purchase_datepormes_raw/ano_raw. - Normalização (
app/dates.py):resolve_purchase_date/parse_date/format_br_datesão substituídos ou adaptados para resolver/validar/formatar competência (mes/ano→ "Jun/2026"), reaproveitando a lógica de fallback "mês corrente" já existente. - Rotas e templates de upload/revisão (
app/routes/upload_routes.py,app/templates/staging.html): novo par de<select>Mês/Ano por linha, com pergunta explícita de competência antes de habilitar "Enviar"/confirmar lote. - Rotas e templates de CRUD manual (
app/routes/documents_routes.py,app/templates/document_form.html): mesmo par de<select>Mês/Ano substituindo<input type="date">. - Dashboard (
app/routes/dashboard_routes.py,app/templates/dashboard.html):monthly_totalse exibição de "Últimos documentos" passam a usarano/mesnativos;_mes_labeldeixa de derivar de string e passa a formatar diretamente a partir das colunas. - Listagem/filtros (
app/routes/documents_routes.py,app/templates/documents_list.html): filtrosstart/end(datas) são substituídos por filtro de competência (mês/ano ou intervalo de competência); ordenação porpurchase_datesubstituída por ordenação por(ano, mes). - Scripts e testes:
scripts/migrate_notas.py,tests/test_app.py,tests/test_ingestion.py,tests/test_categorization.pyprecisam ser atualizados para o novo schema/campos. - Compatibilidade: mudança é destrutiva para dados existentes no formato antigo — exige migração/backfill de
purchase_dateparames/anoantes da remoção da coluna; documentos sem data reconhecível hoje (fallback "1º dia do mês corrente") migram diretamente para o mês/ano correspondente.