193 lines
7.6 KiB
Markdown
193 lines
7.6 KiB
Markdown
# Fechamento de Caixa — O Frangão
|
||
|
||
## O que é
|
||
|
||
App desktop nativo para registrar o fechamento de caixa diário das lojas **União** e **Aliança** do O Frangão. Cada fechamento registra: saldo em dinheiro, cartões de crédito/débito/alimentação/PIX, vales, sangrias, despesas, PIX CNPJ, e itens a receber.
|
||
|
||
## Ideia central
|
||
|
||
O app é um **formulário inteligente** que:
|
||
|
||
1. Captura todos os dados de fechamento de caixa (dinheiro, cartões, despesas, etc.)
|
||
2. Salva localmente em **SQLite** (funciona offline)
|
||
3. Envia automaticamente para o **Supabase** (cloud) quando há conexão
|
||
4. Gera um **recibo térmico 80mm** para impressão
|
||
|
||
O objetivo é substituir planilhas manuais e webhooks frágeis, dando uma fonte única de verdade para os dados de caixa.
|
||
|
||
---
|
||
|
||
## Arquitetura geral
|
||
|
||
```
|
||
┌─────────────────┐ ┌──────────────────┐ ┌────────────────────┐
|
||
│ HTML/JS │────▶│ Tauri (Rust) │────▶│ SQLite (local) │
|
||
│ (frontend) │◀────│ plugins: │◀────│ fechamentos.db │
|
||
│ │ │ app, storage, │ │ - funciona offline │
|
||
│ - formulário │ │ supabase, │ │ - sync automático │
|
||
│ - impressão │ │ printer │ └────────────────────┘
|
||
│ - estado JS │ └────────┬─────────┘ │
|
||
└─────────────────┘ │ ▼
|
||
│ ┌────────────────────┐
|
||
│ │ Supabase Cloud │
|
||
│ │ (supabase. │
|
||
└─────────────▶│ ofrangao.com.br) │
|
||
│ - PostgreSQL │
|
||
│ - RLS + JWT auth │
|
||
│ - API REST │
|
||
└────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## Stack técnica
|
||
|
||
| Camada | Tecnologia |
|
||
|--------|-----------|
|
||
| Frontend | HTML5 + CSS + JavaScript vanilla (single-file `src/index.html`) |
|
||
| Runtime | [Tauri 2](https://tauri.app/) (Rust + WebView2) |
|
||
| Dados local | SQLite via `rusqlite` |
|
||
| Dados cloud | [Supabase](https://supabase.com/) — PostgreSQL + REST API |
|
||
| Impressão | HTML → `window.print()` com CSS @media print (80mm) |
|
||
| Build | Cross-compile Linux → Windows (`x86_64-pc-windows-gnu`) |
|
||
|
||
---
|
||
|
||
## Repositório
|
||
|
||
```
|
||
https://git.ofrangao.com.br/filipe/fechamento-caixa
|
||
```
|
||
|
||
### Estrutura de arquivos
|
||
|
||
```
|
||
fechamento-caixa/
|
||
├── src/
|
||
│ └── index.html ← Frontend completo (HTML + CSS + JS)
|
||
├── src-tauri/
|
||
│ ├── src/
|
||
│ │ ├── main.rs ← Entry point + plugin initialization
|
||
│ │ └── plugins/
|
||
│ │ ├── app.rs ← Config da app (loja, PDV, sync)
|
||
│ │ ├── storage.rs ← SQLite local
|
||
│ │ ├── supabase.rs ← Sync com Supabase
|
||
│ │ ├── printer.rs ← Impressão
|
||
│ │ └── escpos.rs ← Helpers ESCPOS
|
||
│ └── tauri.conf.json ← Config Tauri (janela, bundle, etc.)
|
||
├── SPEC.md ← Este arquivo
|
||
├── SUPABASE_SCHEMA.md ← Schema do banco de dados
|
||
├── API_INTEGRATION.md ← Como o frontend se comunica com Supabase
|
||
└── BUILS_FARM.md ← Como gerar fc-uniao.exe, fc-alianca.exe, fc-ambos.exe
|
||
```
|
||
|
||
---
|
||
|
||
## Builds — 3 versões do app
|
||
|
||
O mesmo código gera 3 binários diferentes conforme a variável de ambiente `DOBRADO_LOJA`:
|
||
|
||
## Downloads
|
||
|
||
| Binário | Loja | Download |
|
||
|---------|------|----------|
|
||
| `fc-uniao.exe` | **Travada: UNIÃO** | [Baixar](https://git.ofrangao.com.br/filipe/fechamento-caixa/releases/download/v2.0.0-uniao/fc-uniao.exe) |
|
||
| `fc-alianca.exe` | **Travada: ALIANÇA** | [Baixar](https://git.ofrangao.com.br/filipe/fechamento-caixa/releases/download/v2.0.0-alianca/fc-alianca.exe) |
|
||
| `fc-ambos.exe` | **Seletor livre** | [Baixar](https://git.ofrangao.com.br/filipe/fechamento-caixa/releases/download/v2.0.0-ambos/fc-ambos.exe) |
|
||
|
||
Quando a loja é fixa, o seletor de loja no formulário é **escondido via JavaScript** e tentativas de mudar via API retornam erro.
|
||
|
||
---
|
||
|
||
## Fluxo de um fechamento
|
||
|
||
```
|
||
1. Operador abre o app
|
||
↓
|
||
2. Seleciona Data, Operador, Turno, Loja (se não for fixa)
|
||
↓
|
||
3. Preenche os campos:
|
||
- Saldo de Troy
|
||
- Cartões (crédito, débito, alimentação, PIX) — um valor por vez
|
||
- Despesas (descrição + valor)
|
||
- Sangrias (hora + gerente + valor)
|
||
- PIX CNPJ (nome + valor)
|
||
- Vales (nome + observação + valor)
|
||
- A Receber (nome + valor)
|
||
- Cancelamentos (número + motivo + valor)
|
||
↓
|
||
4. App calcula:
|
||
TOTAL SISTEMA = soma de todos os campos acima
|
||
DIFERENÇA = TOTAL SISTEMA − Saldo Esperado − Cancelamentos
|
||
↓
|
||
5. Operador clica "💾 Salvar / Sincronizar"
|
||
→ Salva em SQLite local
|
||
→ Envia para Supabase (se online)
|
||
↓
|
||
6. Operador clica "🖨️ Imprimir"
|
||
→ Abre preview do recibo 80mm
|
||
→ window.print() para impressora térmica
|
||
```
|
||
|
||
---
|
||
|
||
## Tauri — o runtime desktop
|
||
|
||
O app roda como **Tauri 2**, um runtime que embute um navegador WebView2 (Windows) dentro de um processo Rust.
|
||
|
||
### O que o Tauri fornece
|
||
|
||
| Recurso | Como é usado |
|
||
|---------|-------------|
|
||
| **Janela nativa** | A janela do app com barra de título, controls de redimensionar, ícone |
|
||
| **Sistema de arquivos** | Lê/escreve `config.json` e `fechamento.db` em `%LOCALAPPDATA%/FechamentoCaixa/` |
|
||
| **Invocação de comandos Rust** | Frontend JS chama `invoke('nome_comando', args)` → Rust executa e retorna |
|
||
| **HTTP client** | Plugin `supabase.rs` usa `reqwest` para falar com o Supabase |
|
||
| **Shell** | Abre diálogo de impressoras, executa `cmd /C copy` para impressão |
|
||
| **Diálogos nativos** | `tauri_plugin_dialog` para escolher arquivos, pastas, impressora |
|
||
|
||
### Comandos Tauri (Rust → JS)
|
||
|
||
O frontend **nunca acessa** Supabase, SQLite ou impressora diretamente. Tudo passa por `invoke`:
|
||
|
||
```javascript
|
||
// Salvar fechamento (SQLite + Supabase)
|
||
await invoke('salvar_fechamento', { estado });
|
||
|
||
// Sync com Supabase
|
||
await invoke('sb_salvar_fechamento', { estado });
|
||
|
||
// Detectar impressora
|
||
await invoke('detectar_impressora');
|
||
|
||
// Imprimir
|
||
await invoke('imprimir_recibo', { html: reciboHTML });
|
||
```
|
||
|
||
### Estrutura dos plugins Rust
|
||
|
||
```
|
||
src-tauri/src/plugins/
|
||
├── app.rs — Config da app (loja, operador default, sync)
|
||
├── storage.rs — SQLite local (fonte primária offline)
|
||
├── supabase.rs — Cliente HTTP para Supabase (service_role JWT)
|
||
├── printer.rs — Detecção EPSON TM-T20, fallback para window.print()
|
||
└── escpos.rs — Helpers ESCPOS (alinhamento, negrito, corte)
|
||
```
|
||
|
||
### Onde os dados ficam
|
||
|
||
| Dado | Local |
|
||
|------|-------|
|
||
| Config (SUPABASE keys, loja default) | `%LOCALAPPDATA%/FechamentoCaixa/config.json` |
|
||
| Banco SQLite (fechamentos) | `%LOCALAPPDATA%/FechamentoCaixa/fechamento.db` |
|
||
| Rascunho auto-save | `%LOCALAPPDATA%/FechamentoCaixa/fechamento_rascunho.db` |
|
||
|
||
---
|
||
|
||
## Autores & Contexto
|
||
|
||
- **Desenvolvedor:** Filipe.Tavares
|
||
- **Dono das lojas:** O Frangão — União e Aliança
|
||
- **Objetivo:** Substituir planilhas manuais e webhooks n8n por um sistema de fechamento de caixa confiável e offline-first
|