obsidian-vault/Infra-Network/SPEC-CLOSING-TILL-CYCLE.md
itecnologys d882719549 docs: Rently cycle spec - autosave, stale, drafts cleanup, admin reopen
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 10:38:24 +00:00

147 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# SPEC — Ciclo EOD → Closing Till → Remittance Pack → HO (definitiva)
**Status:** DEFINITIVA — aprovada por Roger em 2026-10-07 (blocos 1 e 2)
**Rules version:** `CYCLE_RULES_VERSION = 2026-10-07-r1`
**Substitui:** `SPEC-CLOSING-TILL-FREEZE-ARCHIVE.md` (2026-10-01-r1), `RULE-CLOSING-TILL-AFTER-CUT-LOCKED.md`, `releases/011.2026.md` (2026-10-06-r1) e `.cursor/rules/eow-cycle-start-rules.mdc` naquilo que contradizem esta spec.
**Implementação:** ⏳ ainda não implementada — PRD corre `2026-10-01-r1`. Implementar em TEST, validar com Roger, depois PRD.
---
## 1. Visão geral
```
Dia a dia Dia de fecho EOW – Closing Till EOW Remittance Pack HO
Save statement ─▶ Save EOD for Closing Till ─▶ Cycle Start → Apply → Draft ─▶ Freeze TEMPORÁRIO ─▶ Pack → Official Draft ─▶ Approve ROI → Send to HO
(editável) (linha de corte) (nada trava) (trava valores, reversível) (CONGELADO DEFINITIVO)
```
O congelamento **definitivo** acontece **só** no **Send to HO**.
---
## 2. Regras
### R1 — Save statement (dia a dia, EOD Transactions)
- Ao fim do dia o operador clica **Save statement** → cria um ficheiro EOD (cards *Saved EOD file* e *Recent saved EOD files*).
- Pode salvar **várias vezes** no mesmo dia (correcções, lançamentos esquecidos).
- O ficheiro fica **editável** (não imutável) enquanto o ciclo a que pertence não foi enviado ao HO.
### R1a — Auto-save às 23:55 (se o operador esquecer)
- Um job diário às **23:55 (hora local, Europe/Dublin)** verifica o dia:
- se há movimentos e **nenhum** statement salvo, **ou** o último save está **desactualizado** (R3a) → faz o **Save statement automaticamente** (salvo por `system (auto 23:55)`);
- envia aviso para **admin@myvexx.com** com a lista do que foi salvo automaticamente (dia, nº do ficheiro, total, nº de movimentos).
- Assim cada dia começa com os ficheiros do dia anterior salvos.
- O auto-save **não** faz *Save EOD for Closing Till* (o corte é sempre um acto do operador).
- Implementação: timer systemd `rently-prod-eod-autosave.timer` (padrão dos jobs existentes), `OnCalendar=*-*-* 23:55 Europe/Dublin`.
### R2 — Save EOD for Closing Till (dia de fecho: quinta ou outro dia escolhido)
- Faz o mesmo que o Save statement **e** marca a hora do clique, colocando a **linha de corte** após o último lançamento:
- **before-cut** (00:00 → corte) = este ciclo;
- **after-cut** (corte → 23:59) = próximo ciclo.
- Um **Save statement** no dia de fecho **depois** do corte gera/actualiza o **after-cut** (próximo ciclo).
- **Segundo clique no mesmo dia:** avisar *"Já existe uma linha de corte neste dia (HH:MM). Deseja criar uma nova?"*
- Se o EOW **ainda não foi enviado**: o novo corte **substitui** o ficheiro final da semana no Cycle Start e o processo recomeça (drafts anteriores ficam desactualizados).
- Se existir **freeze temporário** activo: pedir primeiro para o libertar (R5).
- Se o EOW **já foi enviado**: bloquear.
### R3 — Week EOD files (Cycle Start) — EOW Closing Till
Lista **todos** os ficheiros do ciclo aberto:
1. o **after-cut** do último fecho (semana anterior);
2. o ficheiro de **cada dia** entre os fechos — **só o save mais recente** de cada dia;
3. o **before-cut** do dia de fecho actual (até à hora do clique).
- Ficheiros do ciclo aberto **nunca** aparecem como *used · immutable*.
- O dia de fecho dividido não mostra o ficheiro de dia inteiro (só before/after).
- Ficheiros de ciclos já enviados não aparecem.
- Nada vem pré-seleccionado; *used · applied* só depois de marcar + **Apply start & preview**.
### R3a — Ficheiro desactualizado
- Se houver lançamento ou correcção num dia **depois** do último save desse dia, o ficheiro aparece no Cycle Start com o selo **"desactualizado — salve de novo"** (com o nº de movimentos novos).
- O auto-save das 23:55 (R1a) re-salva automaticamente estes casos.
### R4 — Apply start & preview / Generate draft
- **Apply start & preview** une os ficheiros marcados num **ficheiro único** (preview). Pode repetir-se.
- **Generate draft** gera um draft a partir de uma selecção de cada vez.
- Pode haver **vários drafts**; **os drafts não trancam ficheiros** (os mesmos ficheiros podem estar em vários drafts). Só um será usado; os outros ficam para leitura e podem ser apagados.
### R4a — Limpeza de drafts não usados (card "Drafts" já existente no Closing Till)
- O card **Drafts (n)** passa a mostrar em cada draft o estado: **Em uso** (é o pacote em freeze temporário ou enviado) ou **Não usado**.
- Drafts **Não usados** têm **Delete** individual e um botão **"Apagar todos os não usados"** (com confirmação), para evitar lixo na base.
- Drafts **Em uso** não podem ser apagados.
- Depois do **Send to HO**, o card sugere apagar os drafts não usados daquele ciclo.
### R5 — Freeze temporário (Closing Till) — OBRIGATÓRIO antes do Remittance Pack
- O operador escolhe **um** draft e faz **Freeze** → estado **Temporarily frozen**.
- Trava os ficheiros e valores desse pacote, para que o envelope e o pack batam com o que vai ser enviado (edições nesses dias ficam bloqueadas com mensagem).
- **O operador pode libertar** (Unfreeze) enquanto não houver envio — volta a draft e terá de refazer as etapas seguintes.
- O Unfreeze **não apaga** a linha de corte (o corte pertence ao *Save EOD for Closing Till*, R2).
- Selo na UI: **"Temporarily frozen"** (nunca "FROZEN — immutable" antes do envio).
### R6 — EOW Remittance Pack
- **Pack Summary** mostra o montante do pacote em freeze temporário.
- Operador preenche os dados do **envelope** e gera **previews** da revisão (quantos quiser; os não usados podem ser apagados e não ficam congelados).
- **Create Official Draft** → fica disponível em **3. Approve selected ROI**.
- **Aviso obrigatório:** se não houver pacote em freeze temporário, mostrar no topo do Remittance Pack:
> *"Ainda não existe um Closing Till em Freeze temporário. Volte a EOW – Closing Till, escolha o draft e clique em Freeze antes de montar o pack."*
— e desactivar *Create Official Draft* até existir.
### R7 — Approve selected ROI → Send to HO (congelamento DEFINITIVO)
- Neste momento os ficheiros do pacote (incluindo o **before-cut**) passam a **Frozen · Sent**: imutáveis, indisponíveis para novos ciclos.
- O **after-cut** **não** fica congelado — pertence ao próximo ciclo (R3.1).
- Depois do envio **só o admin** pode reverter, como excepção:
- **motivo obrigatório**, registado em auditoria;
- fica um registo visível no **ROI Archive** e o pacote é marcado **"Re-aberto"**, para o HO saber que haverá reenvio;
- os ficheiros voltam ao estado *Temporarily frozen* (não a editáveis) até novo envio ou unfreeze.
- Só existe **um** pacote em freeze temporário por ciclo; para trocar de draft é preciso libertar o freeze primeiro.
### R8 — Lançamentos atrasados em dias enviados
- Por regra **nada entra** nos ficheiros imutáveis/enviados. Um lançamento num dia já enviado é bloqueado.
- **Futuro (fora desta entrega):** módulo / conta de **Correcção Contabilística** para registar esses casos no ciclo seguinte, com rasto.
---
## 3. Estados
| Estado | Onde | Ficheiros travados? | Quem reverte |
|--------|------|---------------------|--------------|
| Ficheiro EOD salvo | EOD Transactions | Não | — |
| Draft (vários) | Closing Till | Não | apagar draft |
| **Temporarily frozen** (1 por ciclo) | Closing Till | Sim (valores do pacote) | **operador** (Unfreeze) |
| Official draft / previews | Remittance Pack | Sim (herda o freeze) | operador (apagar / unfreeze) |
| **Frozen · Sent** | após Send to HO | **Sim, definitivo** | **só admin** (excepção auditada) |
---
## 4. Diferenças face ao sistema actual (2026-10-01-r1 em PRD)
| Ponto | Hoje | Esta spec |
|-------|------|-----------|
| Ficheiros no Cycle Start | só `for_eow=1` | todos os Save statement (mais recente por dia) + before/after-cut |
| Draft tranca ficheiros | sim (`eod_ids_held_by_draft_or_freeze`) | **não** |
| Freeze | "FROZEN — immutable" | **Temporarily frozen**, reversível pelo operador |
| Unfreeze | só admin; apaga a linha de corte | operador; **mantém** o corte |
| Imutável definitivo | no Freeze | no **Send to HO** |
| After-cut do fecho anterior | preso no freeze (ex.: EOD-20261001-37722C €129) | aberto para o próximo ciclo |
| Corte | carimbado pelo Freeze | carimbado pelo **Save EOD for Closing Till** |
| 2.º clique no dia de fecho | sem tratamento | aviso + substituir enquanto não enviado |
| Remittance Pack sem freeze | sem aviso | aviso + Create Official Draft desactivado |
| Dia sem statement salvo | dinheiro fica fora do Cycle Start | **auto-save 23:55** + email admin@myvexx.com |
| Statement desactualizado | sem aviso | selo "desactualizado — salve de novo" |
| Drafts não usados | Delete um a um | estado Em uso / Não usado + "Apagar todos os não usados" |
| Reversão após envio | impossível | só admin, motivo + ROI Archive "Re-aberto" |
---
## 5. Notas de implementação (TEST primeiro)
- `eow_report.list_eod_choices`: listar todos os EOD do ciclo aberto (último save por dia), excluir só os de ciclos **enviados**.
- `eod_ids_held_by_draft_or_freeze` → passa a "held by **sent**" (e "temporarily frozen" só para bloquear edição, não a listagem).
- `freeze_eow_draft`: não acrescentar o after-cut à lista do pacote; não carimbar corte (R2 já o fez).
- `unfreeze_eow_report`: permitir operador quando não enviado; não limpar `closing_till_cut`; admin com motivo depois do envio.
- `eod_report`: *Save EOD for Closing Till* gera before/after + aviso de 2.º clique.
- Remittance Pack (frontend + API): aviso R6 e bloqueio de *Create Official Draft*.
- Auto-save (R1a): job `app/jobs/eod_autosave.py` + `send_email` (já existe em `modules/users/service.py`) + timer systemd 23:55 Europe/Dublin (VM em UTC).
- Card Drafts (R4a): estado Em uso / Não usado + apagar em massa (API protege drafts em uso).
- Reversão admin (R7): motivo, evento de auditoria, marca "Re-aberto" no ROI Archive.
- Testes de regressão: reescrever `tests/test_eow_cycle_start_rules.py` para esta versão.
- Ao implementar: actualizar `.cursor/rules/eow-cycle-start-rules.mdc` para apontar para esta spec.