# Fechamento de Caixa — O Frangão App desktop nativo para fechamento de caixa com impressão em impressora térmica 80mm. ## Stack - **Backend:** Tauri 2 + Rust - **Frontend:** HTML + CSS + JavaScript (vanilla, ~1700 linhas) - **Storage local:** SQLite (rusqlite) — funciona offline - **Sync:** Supabase REST API - **Impressão:** ESC/POS via USB (TM-T20 e compatíveis, Windows) ## Estrutura do Projeto ``` fechamento-caixa/ ├── src/ │ └── index.html # Frontend completo (HTML + CSS + JS inline) ├── src-tauri/ │ ├── Cargo.toml # Dependências Rust │ ├── tauri.conf.json # Config do app Tauri │ └── src/ │ ├── main.rs # Entry point — registra comandos Tauri │ └── plugins/ │ ├── supabase.rs # Integração Supabase (REST API) │ ├── printer.rs # Geração ESC/POS + envio USB │ ├── storage.rs # SQLite local │ ├── app.rs # Config da app (loja, operador default) │ └── escpos.rs # Helpers ESC/POS (INIT, CUT, divider, etc.) └── README.md ``` ## Pré-requisitos - Rust 1.70+ (`rustup install stable`) - Node.js 18+ (para build do frontend Tauri) - Windows 10/11 (impressão USB só funciona no Windows) ## Setup ### 1. Clonar o repositório ```bash git clone https://git.ofrangao.com.br/filipe/fechamento-caixa.git cd fechamento-caixa ``` ### 2. Configurar chaves do Supabase Crie o arquivo `config.json` em `%LOCALAPPDATA%\FechamentoCaixa\config.json` (Windows): ```json { "SUPABASE_ANON_KEY": "sua_chave_anon_aqui", "SUPABASE_SERVICE_KEY": "sua_chave_service_role_aqui" } ``` O app procura esse arquivo na inicialização. Sem ele, tenta ler das variáveis de ambiente `SUPABASE_ANON_KEY` e `SUPABASE_SERVICE_KEY`. ### 3. Build ```bash cd src-tauri cargo build --release --target x86_64-pc-windows-gnu ``` O executável fica em: ``` src-tauri/target/x86_64-pc-windows-gnu/release/fechamento-caixa.exe ``` Para gerar o pacote de distribuição: ```bash cp src-tauri/target/x86_64-pc-windows-gnu/release/fechamento-caixa.exe . cp src-tauri/target/x86_64-pc-windows-gnu/release/WebView2Loader.dll . tar -czf fechamento-caixa-vX.X.X.tar.gz fechamento-caixa.exe WebView2Loader.dll ``` ## Códigos de comando Tauri O frontend chama esses comandos via `window.__TAURI__.core.invoke()`: | Comando | Arquivo | Descrição | |---------|---------|-----------| | `salvar_fechamento` | storage.rs | Salva no SQLite local | | `carregar_rascunho` | storage.rs | Busca rascunho por loja+data | | `listar_fechamentos` | storage.rs | Lista histórico do SQLite | | `buscar_fechamento_por_id` | storage.rs | Busca por ID no SQLite | | `sb_salvar_fechamento` | supabase.rs | Envia para Supabase | | `sb_carregar_rascunho` | supabase.rs | Busca rascunho no Supabase | | `sb_listar_recentes` | supabase.rs | Lista fechamentos recentes | | `sb_buscar_por_id` | supabase.rs | Busca por ID no Supabase | | `sb_salvar_listas` | supabase.rs | Salva operadores/gerentes | | `sb_carregar_listas` | supabase.rs | Carrega listas do servidor | | `sb_online` | supabase.rs | Verifica conectividade | | `imprimir_recibo` | printer.rs | Envia bytes ESC/POS pra USB | | `detectar_impressora` | printer.rs | Detecta porta USB | | `configurar_impressora` | printer.rs | Define porta manual | | `teste_impressora` | printer.rs | Imprime página de teste | | `get_loja` / `set_loja` | app.rs | Loja atual | | `get_config` / `set_config` | app.rs | Config completo | ## Fluxo de dados ``` [Usuário preenche formulário] │ ▼ (auto-save a cada 1.5s) SQLite local (fechamento.db) │ ├── [Botão Enviar] ──► Supabase (fechamentos_web) │ └── [Botão Recibo] ──► printer.rs ──► to_escpos() ──► USB │ ├── Sucesso: imprime └── Falha: openPrintPreview() ──► iframe ──► window.print() ``` ## Campos do formulário | Campo | Tabela Supabase | Notas | |-------|----------------|-------| | uuid, loja, data, operador, turno | fechamentos_web | PK composto | | saldo_troco, saldo_esperado, fechamento, diferenca | fechamentos_web | diferenca = fechamento - saldo_esperado | | despesas[], sangrias[], vales[], receber[], pixcnpj[], cancelamentos[] | dados (JSON) | Arrays de {desc/nome, valor, ...} | | cartoes{credito[],debito[],alimentacao[],pix[]} | dados (JSON) | Arrays de {valor} | | operadores[], gerentes[], despesas_custom[], clientes[] | listas_personalizadas | Listas por loja | ## Problemas conhecidos - Impressão USB só funciona no Windows - `service_role_key` no cliente desktop é risco de segurança — usar apenas anon_key + RLS - Sem testes automatizados ## Version History - **v1.2.7** — 2026-06-24: 4 bugs críticos concertados (impressão, enviar, dia anterior, localStorage) - **v1.2.6** — 2026-06-24: WebView2Loader.dll incluso; init() restaura operador+turno - **v1.2.5** — 2026-06-24: diferenca = fechamento - esperado (não mais saldo_troco - esperado)