# Histórico do Projeto — Fechamento de Caixa O Frangão ## Contexto **Dono:** Filipe.Tavares — O Frangão (lojas União e Aliança) **Problema original:** Planilhas manuais + webhooks n8n frágeis para registrar fechamento de caixa **Solução:** App desktop Tauri 2 + SQLite offline + Supabase cloud + impressão térmica 80mm --- ## Repositório ``` https://git.ofrangao.com.br/filipe/fechamento-caixa ``` --- ## Stack Técnica | Camada | Tecnologia | |--------|-----------| | Frontend | HTML5 + CSS + JavaScript vanilla (single-file `src/index.html`) | | Runtime | Tauri 2 (Rust + WebView2) | | Dados local | SQLite via `rusqlite` | | Dados cloud | Supabase — PostgreSQL + REST API | | Impressão | HTML → `window.print()` com CSS @media print (80mm) | | Build | Cross-compile Linux → Windows (`x86_64-pc-windows-gnu`) | --- ## Releases | Tag | Data | Descrição | |-----|------|-----------| | `v2.0.4-alianca` | 2026-07-05 | Fix preview modal re-open + sys_total recalc | | `v2.0.3-uniao` | 2026-07-05 | Fix diferença cálculo from array | | `v2.0.2-uniao` | 2026-07-05 | Fix buildPrintHTML sys_total | | `v2.0.1-uniao` | 2026-07-05 | Builds separadas + docs | | `v2.0.0-uniao/alianca/ambos` | 2026-07-04 | Lançamento — app completo com Tauri 2 | --- ## Bugs Corrigidos (desde v2.0.0) ### Preview + Modal (v2.0.4) - **237ceab** — `confirm-print` não fechava mais o modal antes de abrir o preview; `openPrintPreview` reabria o modal ao fechar se ele ainda estava aberto - **73c2027** — `closeConfirmModal()` era chamada antes de `openPrintPreview()` — preview cobria o modal, mas ao fechar voltava pro form - **56a2ed5** — `buildPrintHTML` usava `data.diferenca` (precomputado, stale) em vez de recalcular `sys_total - saldo_esperado - cancelamentos` inline ### Cálculo da Diferença (v2.0.3) - **acb90f0** — `diferenca` sempre recalculada da array de cancelamentos (não do escalar `total_cancelamentos`) - **6eb08b6** — mesmo fix em `buildReportHTML`, `buildPrintHTML`, `buildConfirmHTML` - **5a01264** — ignora `data.diferenca` pré-computado, recalcula sempre de `sys_total` ### Rust ESCPOS (v2.0.3) - **733519e** — Rust `to_escpos`: diferença = `sys_total - saldo_esperado - total_cancelamentos` (não mais `fechamento`) ### CSS / Layout (v2.0.2) - **6440b26** — `buildReportHTML`: diferença = `sysTotal - saldoEsp - cancelamentos` - **420e104** — `buildConfirmHTML` e `buildPrintHTML` usavam `sysTotal`/`total_cancelamentos` em vez de `sys_total`/`cancelamentos` - **b04e5ac** — `.main min-height:0` (footer invisível em resoluções pequenas) - **65c444a** — seletor loja escondia errado (caracteres asiáticos no DOM) - **2bfbf29** — values das options de loja sem acento (`Uniao`/`Alianca`) — alinhado com `LOJA_FIXA` do Rust ### Impressão (v2.0.1) - **b1585af / 155782f / 16972f4 / d3d5c4f** — fonte 18px→22px bold nos relatórios e preview - **5f1d9a4 / cc45ed9** — botão "Dia Anterior" agora exige senha antes de abrir ### Builds (v2.0.0) - **659d977** — `DOBRADO_LOJA` injetado via env no build — 3 binários: `fc-uniao.exe`, `fc-alianca.exe`, `fc-ambos.exe` --- ## Bugs Pendentes (conhecidos) | # | Bug | Prioridade | Status | |---|-----|-----------|--------| | #6 | `salvarEdicaoModal` reconstrói `id_fechamento` dos inputs em vez de usar `full.id_fechamento` — PATCH pode errar se operador mudar loja/data/operador | Média | Pendente | --- ## Arquitetura de Dados ### SQLite local (offline-first) ``` %LOCALAPPDATA%/FechamentoCaixa/fechamento.db ``` ### Supabase cloud ``` https://supabase.ofrangao.com.br Tabela: fechamentos_web ``` ### Fluxo de sync ``` App abre → carrega rascunho do SQLite → operador trabalha offline ↓ operador clica "Salvar/Sincronizar" ↓ 1. Salva em SQLite local 2. Envia para Supabase (se online) ↓ operador clica "Imprimir" ↓ window.print() → receipt 80mm ``` --- ## Comandos Tauri (frontend chama via `invoke`) | Comando | Descrição | |---------|-----------| | `salvar_fechamento` | Salva estado no SQLite local | | `carregar_rascunho` | Carrega rascunho por loja+data | | `sb_salvar_fechamento` | POST para Supabase | | `sb_listar_recentes` | Lista fechamentos recentes | | `sb_buscar_por_id` | Busca por ID numérico | | `sb_buscar_por_uuid` | Busca por UUID | | `detectar_impressora` | Detecta EPSON TM-T20 | | `imprimir_recibo` | Imprime via ESCPOS ou fallback window.print() | --- ## Builds — 3 versões | Binário | Loja | Seletor | |---------|------|---------| | `fc-uniao.exe` | Fixa: UNIÃO | Escondido | | `fc-alianca.exe` | Fixa: ALIANÇA | Escondido | | `fc-ambos.exe` | Livre | Dropdown visível | ### Como buildar ```bash cd src-tauri/ # UNIÃO DOBRADO_LOJA=Uniao cargo build --release --target x86_64-pc-windows-gnu # ALIANÇA DOBRADO_LOJA=Alianca cargo build --release --target x86_64-pc-windows-gnu # AMBOS cargo build --release --target x86_64-pc-windows-gnu ``` --- ## Lições Aprendidas 1. **Cálculos sempre inline** — nunca usar valores pré-computados (`data.diferenca`, `data.total_cancelamentos`) que podem estar stale. Sempre recalcular da fonte. 2. **Fechar modal ANTES de abrir overlay** — se um modal vai ser coberto por outro, fechar primeiro e reabrir depois (salvar estado). 3. **Cross-compile Linux→Windows** — funciona perfeitamente com `x86_64-pc-windows-gnu` target. 4. **Gitea API** — `Authorization: token {TOKEN}` (minúsculo `token`) funciona; `Token {TOKEN}` não. Upload de assets funciona; DELETE de assets retorna 404 (bug do Gitea?). --- ## Autores - **Filipe.Tavares** — dono das lojas / demandante - **Hermes Agent** — desenvolvimento + debugging