# ICEBERG App POS — Contexto
#app #pos #customtkinter #auth #entry-point #python

## Proposito
Capa de escritorio (GUI) del sistema POS. Maneja autenticacion (cloud + local + cache offline), navegacion por vistas (sin tabs), comunicacion con el servidor y el agente, tracker en memoria de pulseras activas, y operaciones de supervisor con PIN.

## Archivos del modulo `app/`
| Archivo | Funcion |
|---------|---------|
| `main.py` | Punto de entrada — AppWindow (unica ventana), ciclo login → main → login |
| `auth.py` | Autenticacion: cloud → servidor local → cache offline |
| `api.py` | Cliente HTTP (httpx) para server :8000 y agent :5555 |
| `config.py` | Constantes globales (TEST_MODE, tiempos, DEFAULT_PACKAGES) |
| `session.py` | Estado global de sesion (usuario, permisos, venue, offline) |
| `wristband_tracker.py` | Estado en memoria de pulseras (fases + stats) |
| `sync_worker.py` | Worker background para subir ventas offline al servidor |
| `offline_queue.py` | Cola SQLite de ventas offline |
| `printing.py` | Modulo de impresion termica |

## Iniciar la app
```bash
cd app
python main.py
```

## Flujo principal (`main.py`)
```
AppWindow(ctk.CTk)  — ventana unica fullscreen
  ├─ _show_login()   → LoginScreen (CTkFrame via place())
  │     └─ auth: cloud → server local → cache offline
  │     └─ USB check: bloquea si programador no conectado
  ├─ _show_main()    → MainWindow (CTkFrame via place())
  │     └─ Vistas: packages | config | activas | printer
  │     └─ Reloj, polling hardware, polling USB
  └─ _on_logout()    → ReportDialog → _show_login()
```
- **Ventana unica**: `AppWindow(ctk.CTk)`, un solo `mainloop()`
- **Kiosk**: auto fullscreen via `attributes("-fullscreen", True)` tras 1.5s o primer clic
- **F11**: toggle fullscreen
- `LoginScreen` y `MainWindow` son `CTkFrame` embebidos via `place()`

## Auth (`auth.py` + `session.py`)
### Prioridad de autenticacion
1. **Cloud**: POST `https://icebergecuador.com/Cuenca/Operator/api.php?action=auth_app`
   - Body: `{email, password, app_key: "iceberg-sync-2026"}`
   - Retorna: user, permissions, venues
2. **Servidor local**: POST `/api/auth` (username corto)
3. **Cache offline**: `app/data/auth_cache.json` (SHA256, TTL 7 dias)

### Permisos
| Permiso | Descripcion |
|---------|-------------|
| `all` | Acceso total |
| `lb_vender` | Puede realizar ventas |
| `lb_paquetes` | Puede gestionar paquetes/combos |
| `lb_config_servidor` | Puede abrir configuracion del servidor |
| `lb_reporte_local` | Puede ver reportes |
| `lb_sobreventa` | Puede vender sin stock disponible |
| `lb_dispositivos` | Acceso a gestion de dispositivos |

### Session global (`session.py`)
```python
set_session(user, permissions, venues, offline)
clear_session()
get_user() → dict
tiene_permiso("lb_vender") → bool  # "all" = acceso total
```

## `config.py`
| Constante | Valor | Descripcion |
|-----------|-------|-------------|
| `TEST_MODE` | `True` | Bypasa servidor, va directo al agent |
| `GRACE_MINUTES` | `1` | Fase verde (1 test, 5 produccion) |
| `TEST_PLAY_MINUTES` | `1` | Fase azul en modo prueba |
| `TEST_RED_MINUTES` | `1` | Fase roja en modo prueba |
| `RED_MINUTES` | `8` | Fase roja en produccion |
| `DEFAULT_PACKAGES` | `[]` | Vacio — combos solo desde custom_combos.json |

## `api.py` — Cliente HTTP
Carga URLs dinamicamente desde `data/config.json` en cada llamada.

### Funciones de configuracion
```python
load_config() / save_config(cfg)
get_stock_total() / set_stock_total(n)
get_venue_id() / set_venue_id(v)
get_agent_id()
```

### Endpoints que envuelve
| Funcion | Destino | Descripcion |
|---------|---------|-------------|
| `get_hardware_status()` | `GET /api/hardware/status` | Estado agent + programmer |
| `get_agent_status()` | `GET :5555/status` | Estado USB directo al agente |
| `get_packages()` | `GET /api/packages` + custom_combos.json | **Solo muestra combos locales** |
| `get_terminal_packages()` | `GET /api/terminals/{id}/packages` | Combos asignados por admin |
| `register_combo(id)` | `POST /api/combos/register` | Registra combo en servidor |
| `sell(...)` | `POST /api/sell` | Venta + programa (bloquea 35s) |
| `retry_sell(session_id)` | `POST /api/sell/{id}/retry` | Reintento de programacion |
| `cortesia(...)` | `POST /api/cortesia` | Cortesia con PIN supervisor |
| `anular_venta(...)` | `POST /api/sell/{id}/anular` | Anulacion con PIN supervisor |
| `validar_pin_supervisor(...)` | `POST /api/supervisor/validar-pin` | Valida PIN antes de operacion |
| `get_sessions()` | `GET /api/sessions` | Sesiones del dia |
| `get_daily_report()` | `GET /api/reports/daily` | Reporte diario |
| `get_deactivations()` | `GET :5555/deactivations` | Contador desactivaciones |
| `program_via_agent(...)` | `POST :5555/program` | Programacion directa |
| `sync_upload(...)` | `POST /api/sync/upload` | Subir ventas offline |

### Combos: fuente de datos
`get_packages()` **solo muestra combos de custom_combos.json**. Los fusiona con datos del servidor (nombre, precio, assigned=True) si hay match por ID. Si no hay match, el combo aparece como no asignado (assigned=False, deshabilitado).

**IMPORTANTE**: `sell()` y `program_via_agent()` bloquean hasta 35s → **siempre llamar desde `threading.Thread`**

## `wristband_tracker.py` — Tracker en memoria
### Fases de tiempo
```
VERDE (grace)   → AZUL (playing)   → ROJO (expired)   → devuelta (returned)
```

### API del tracker
| Funcion | Descripcion |
|---------|-------------|
| `add(name, reference, session_id, package_id, package_name, real_play_minutes)` | Registra nueva pulsera |
| `get_active()` | Lista de pulseras NO devueltas |
| `get_all()` | Todas incluidas las devueltas |
| `mark_returned(id)` | Marca pulsera como devuelta |
| `get_phase(entry)` | `(phase_str, progress_float)` |
| `get_stats()` | `{total_active, playing, expired, returned_today}` |

## Relacionado
- [→ CONTEXTO.md](../CONTEXTO.md) — Arquitectura general #root
- [→ CONTEXTO_UI.md](ui/CONTEXTO_UI.md) — Interfaz grafica #ui
- [→ CONTEXTO_DATA.md](data/CONTEXTO_DATA.md) — Archivos de datos #data
- [→ CONTEXTO_AGENT.md](../agent/CONTEXTO_AGENT.md) — Agent que programa hardware #agent
- [→ CONTEXTO_SERVER.md](../server/CONTEXTO_SERVER.md) — Server FastAPI #server

## Tags de navegacion
#app #pos #python #customtkinter #auth #cloud #cache #api-client #wristband-tracker #test-mode #config #supervisor-pin #session
