# QBO Sync Agent

## Responsabilidad
Orquesta la sincronización de datos financieros desde QuickBooks Online hacia la cache local en MySQL.

## Trigger
- **Manual**: Usuario presiona "Sync" en el dashboard → `POST /api/sync/trigger`
- **Automático** (Fase 3): Cron job cada N horas

## Flujo

```
POST /api/sync/trigger
  │
  ├─ Para cada empresa en `companies` con qbo_realm_id != NULL:
  │   │
  │   ├─ 1. Verificar token
  │   │     └─ Si access_token expirado → refresh via QBO OAuth token endpoint
  │   │     └─ Si refresh_token expirado → marcar empresa como desconectada, skip
  │   │
  │   ├─ 2. Crear entrada en sync_log (status = 'running')
  │   │
  │   ├─ 3. Fetch P&L
  │   │     GET /v3/company/{realmId}/reports/ProfitAndLoss
  │   │       ?start_date=YYYY-01-01&end_date=YYYY-MM-DD
  │   │       &summarize_column_by=Month
  │   │     └─ Parse respuesta jerárquica → QboResponseParser
  │   │     └─ UPSERT en cached_reports
  │   │
  │   ├─ 4. Fetch Balance Sheet
  │   │     GET /v3/company/{realmId}/reports/BalanceSheet
  │   │       ?as_of=YYYY-MM-DD
  │   │     └─ Parse → UPSERT en cached_reports
  │   │
  │   ├─ 5. Fetch TransactionList
  │   │     GET /v3/company/{realmId}/reports/TransactionList
  │   │       ?start_date=...&end_date=...
  │   │       &columns=tx_date,txn_type,name,account_name,subt_nat_amount,memo
  │   │     └─ Parse cada fila → flat record
  │   │     └─ Batch UPSERT en cached_transactions (ON DUPLICATE KEY UPDATE)
  │   │
  │   ├─ 6. Actualizar sync_log (status = 'completed', records_synced = N)
  │   │
  │   └─ 7. Si error en cualquier paso → sync_log (status = 'failed', error_message)
  │
  └─ Retornar resumen { companies_synced, total_records, errors[] }
```

## Manejo de errores
- **429 Too Many Requests**: Backoff exponencial (1s, 2s, 4s, max 3 reintentos)
- **401 Unauthorized**: Intentar refresh token; si falla, marcar empresa como desconectada
- **5xx Server Error**: Reintentar 1 vez, luego fallar con error descriptivo
- **Timeout**: 30s por request a QBO API

## Dependencias
- `QboAuthService.php` — manejo de tokens
- `QboReportsService.php` — llamadas a QBO API
- `QboTransactionsService.php` — fetch de transacciones
- `QboResponseParser.php` — parser de respuestas jerárquicas
- `CachedReport` / `CachedTransaction` models — escritura a DB

## Rate limiting
- Respetar 500 req/min por realmId
- No más de 10 requests concurrentes por realmId
- En PHP síncrono esto rara vez es un problema, pero implementar sleep() si se hace batch grande
