Files
LerNota/openspec/changes/archive/2026-07-24-competencia/tasks.md
T

6.8 KiB

1. Migração de Schema (Banco de Dados)

  • 1.1 Em app/database.py, implementar rebuild de fiscal_documents (tabela _new com mes INTEGER NOT NULL, ano INTEGER NOT NULL, demais colunas iguais, sem purchase_date), copiando dados existentes com mes = CAST(substr(purchase_date,6,2) AS INTEGER) e ano = CAST(substr(purchase_date,1,4) AS INTEGER), dentro de uma transação, guardado por checagem PRAGMA table_info (só roda se purchase_date ainda existir).
  • 1.2 Repetir o mesmo rebuild para detected_documents, com mes INTEGER e ano INTEGER nullable (mantendo o mesmo comportamento opcional que purchase_date tinha).
  • 1.3 Substituir o índice idx_fiscal_date por idx_fiscal_competencia ON fiscal_documents(ano, mes).
  • 1.4 Testar a migração rodando init_db() contra uma cópia do banco atual (com dados de purchase_date já existentes) e validar que mes/ano foram preenchidos corretamente e que rodar init_db() de novo não falha nem duplica/recria o rebuild.

2. Normalização de Competência (app/dates.py)

  • 2.1 Promover a lista _MESES (hoje em dashboard_routes.py) para app/dates.py como fonte única de abreviações de mês.
  • 2.2 Implementar resolve_competencia(date_raw, reference=None) -> tuple[int, int], substituindo resolve_purchase_date, com fallback para mês/ano corrente quando o valor for inválido/ausente.
  • 2.3 Implementar format_competencia(mes: int, ano: int) -> str no formato "Jun/26" (mês abreviado capitalizado + ano com 2 dígitos), substituindo format_br_date, e atualizar o filtro Jinja registrado em app/templating.py (brdate → filtro de competência).
  • 2.4 Ajustar _is_plausible_purchase_date (ou equivalente) para validar plausibilidade em termos de mês/ano (ex. não mais que alguns meses no futuro, ano não muito no passado), em vez de dias.

3. Extração (IA e OCR)

  • 3.1 Confirmar que app/ai_extraction.py e lernotafiscal/extraction.py continuam extraindo a data completa do documento sem alteração de prompt/regex (Decisão de design: descarte do dia acontece na normalização, não na extração).
  • 3.2 Renomear/ajustar RawExtraction.purchase_date_raw e DetectedDocumentCandidate.purchase_date apenas na camada de repasse (app/ingestion.py:_candidate_to_raw), garantindo que o valor bruto siga até resolve_competencia sem mudança de comportamento de extração.

4. Persistência e Consultas (app/database.py)

  • 4.1 Atualizar insert_detected e update_staged para gravar mes/ano (via resolve_competencia) em vez de purchase_date.
  • 4.2 Atualizar confirm_batch para exigir mes/ano válidos (em vez de purchase_date truthy) antes de promover um documento de staging para fiscal_documents.
  • 4.3 Atualizar create_fiscal e update_fiscal para receber mes/ano como parâmetros obrigatórios em vez de purchase_date.
  • 4.4 Atualizar _fiscal_where para filtrar por intervalo de competência usando a expressão (ano * 12 + mes) BETWEEN ? AND ?, substituindo o filtro por purchase_date >= / <=.
  • 4.5 Atualizar FISCAL_SORT_COLUMNS para expor ordenação por (ano, mes) no lugar de purchase_date.
  • 4.6 Atualizar monthly_totals para agrupar diretamente por ano, mes (GROUP BY ano, mes ORDER BY ano, mes), eliminando substr(purchase_date, 1, 7).
  • 4.7 Atualizar category_totals para filtrar por competência usando a mesma expressão (ano * 12 + mes).

5. Fluxo de Upload e Revisão (Staging)

  • 5.1 Em app/routes/upload_routes.py, atualizar o handler de upload (POST /upload) para gravar mes/ano (via resolve_competencia) em vez de purchase_date ao inserir em detected_documents.
  • 5.2 Atualizar app/templates/staging.html: substituir o <input type="date" name="purchase_date"> por dois <select> — Mês (Jan-Dez) e Ano (2026-2030) — pré-selecionados com o valor detectado quando disponível.
  • 5.3 Atualizar o handler POST /import/{batch_id}/update/{detected_id} para receber e persistir mes/ano do formulário de revisão.
  • 5.4 Garantir que o cálculo de summary["pendentes"] (usado para bloquear o botão de confirmação do lote) passe a considerar mes/ano ausentes/inválidos como pendência, em vez de purchase_date.

6. Cadastro Manual de Documento

  • 6.1 Atualizar app/templates/document_form.html: substituir o <input type="date" name="purchase_date"> pelos mesmos dois <select> de Mês/Ano usados na revisão, pré-preenchidos na edição.
  • 6.2 Atualizar os handlers de criação/edição em app/routes/documents_routes.py (/documents/new, /documents/{id}/edit) para ler mes/ano do formulário e repassar a create_fiscal/update_fiscal.

7. Listagem e Filtros (/documents)

  • 7.1 Atualizar app/templates/documents_list.html: substituir os filtros <input type="date" name="start">/name="end" por dois pares de <select> Mês/Ano ("De" e "Até").
  • 7.2 Atualizar o handler GET /documents em app/routes/documents_routes.py para ler os novos parâmetros de filtro de competência e repassá-los a list_fiscal/fiscal_summary.
  • 7.3 Atualizar a coluna "Data" em documents_list.html para exibir a competência formatada (format_competencia) e manter a ordenação por competência (sort_url apontando para ano/mes).

8. Dashboard

  • 8.1 Atualizar app/routes/dashboard_routes.py: _mes_label passa a usar format_competencia/_MESES centralizados em app/dates.py, consumindo ano/mes nativos vindos de monthly_totals.
  • 8.2 Atualizar app/templates/dashboard.html: tabela "Últimos documentos" exibe a competência (format_competencia) no lugar de d.purchase_date | brdate.

9. Scripts e Testes

  • 9.1 Atualizar scripts/migrate_notas.py para gravar mes/ano em vez de purchase_date ao chamar create_fiscal.
  • 9.2 Atualizar tests/test_app.py (usos de resolve_purchase_date, create_fiscal, update_fiscal com purchase_date=...) para o novo par de campos.
  • 9.3 Atualizar tests/test_ingestion.py (docs[0].purchase_date) para verificar mes/ano em vez de data completa.
  • 9.4 Atualizar tests/test_categorization.py (db.create_fiscal(..., purchase_date=...)) para o novo schema.
  • 9.5 Rodar a suíte de testes completa e corrigir quaisquer quebras remanescentes relacionadas a purchase_date.

10. Validação Manual

  • 10.1 Rodar a aplicação localmente, fazer upload de um documento de teste, confirmar que a tela de revisão exige seleção de Mês/Ano antes de habilitar a confirmação do lote, e validar que o documento aparece corretamente no Dashboard e em /documents após confirmado.
  • 10.2 Validar cadastro manual (criar/editar) de um documento fiscal usando os novos seletores de Mês/Ano.
  • 10.3 Validar o filtro por intervalo de competência em /documents e a ordenação pela coluna de competência.