Metadata-Version: 2.4
Name: folyo
Version: 0.1.0
Summary: SDK oficial de Python para la API de Folyo (facturacion electronica chilena, DTE + SII).
Project-URL: Homepage, https://folyo.cl
Project-URL: Documentation, https://api.folyo.cl/docs
Project-URL: Repository, https://github.com/SYCTecnologiaCo/Folyo
Project-URL: Issues, https://github.com/SYCTecnologiaCo/Folyo/issues
Author-email: Folyo <soporte@folyo.cl>
License: MIT
License-File: LICENSE
Keywords: boleta,chile,dte,factura-electronica,facturacion,folyo,sii
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Financial :: Accounting
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: httpx>=0.27
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: mypy>=1.11; extra == 'dev'
Requires-Dist: pip-audit>=2.7; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Requires-Dist: twine>=5.1; extra == 'dev'
Description-Content-Type: text/markdown

# Folyo — SDK oficial de Python

SDK de Python para la API de [Folyo](https://folyo.cl): facturacion electronica
chilena (DTE + SII) standalone. Del codigo al SII, sin escalas.

- Cliente tipado sobre `httpx` (unica dependencia de runtime).
- Errores tipados con mapeo de los codigos del servidor.
- Soporte del patron de emision asincrona (encolar + polling con backoff).
- Idempotencia, override de ambiente del SII y reintentos seguros ante 429/503.
- Redaccion de secretos (la API key/JWT nunca aparecen en `repr` ni en errores).

## Instalacion

```bash
pip install folyo
```

Requiere Python 3.9 o superior.

## Autenticacion

El cliente exige exactamente uno de los dos esquemas:

- **API key** (recomendada para integraciones server-side, no expira). Se envia
  como header `X-API-Key`. Fija el tenant y la empresa.
- **JWT Bearer** (sesion de usuario). Se envia como `Authorization: Bearer ...`.

```python
from folyo import Folyo

# Con API key
folyo = Folyo(api_key="<tu-api-key>")

# O con un token JWT
folyo = Folyo(token="eyJhbGciOi...")
```

Tambien funciona como context manager (cierra el cliente HTTP al salir):

```python
with Folyo(api_key="<tu-api-key>") as folyo:
    ...
```

## Quickstart: emitir una Factura Electronica (DTE 33)

La emision es **asincrona**: `emitir()` encola y devuelve un `job_id`; el helper
`emitir_y_esperar()` hace el polling por ti hasta que el job termina.

```python
import uuid
from folyo import Folyo, DTERequest, Receptor, DetalleLinea

with Folyo(api_key="<tu-api-key>") as folyo:
    req = DTERequest(
        tipo_dte=33,  # Factura Electronica
        receptor=Receptor(
            rut="12.345.678-9",
            razon_social="Cliente SpA",
            giro="Comercio",
        ),
        detalle=[
            DetalleLinea(nombre="Servicio de consultoria", monto=100000),
        ],
    )

    # Encolar y esperar el resultado (con Idempotency-Key para reintentar seguro)
    job = folyo.dte.emitir_y_esperar(req, idempotency_key=str(uuid.uuid4()))

    if job.estado == "completed" and job.result is not None:
        print("Folio:", job.result.folio)
        print("Track ID:", job.result.track_id)
        print("Total:", job.result.monto_total)

        # Descargar el PDF
        pdf = folyo.dte.descargar_pdf(33, job.result.folio)
        with open(f"factura-{job.result.folio}.pdf", "wb") as f:
            f.write(pdf)
    else:
        print("La emision fallo:", job.estado)
```

Si prefieres resolver el resultado por webhook o SSE, usa `emitir()` directo:

```python
encolada = folyo.dte.emitir(req)
print(encolada.job_id)  # resuelve luego via webhook dte.emitido o polling
```

## Manejo de errores

```python
from folyo import (
    Folyo,
    FolyoAuthError,
    FolyoQuotaError,
    FolyoRateLimitError,
    FolyoValidationError,
    FolyoSiiUnavailableError,
)

try:
    folyo.dte.emitir(req)
except FolyoRateLimitError as e:
    print("Reintentar en", e.retry_after, "segundos")
except FolyoQuotaError as e:
    print("Limite de plan o pago requerido:", e.code)
except FolyoAuthError:
    print("Credenciales invalidas o sin permisos")
except FolyoValidationError as e:
    print("Datos invalidos:", e.message)
except FolyoSiiUnavailableError:
    print("El SII no esta disponible, reintenta mas tarde")
```

El SDK reintenta automaticamente (con backoff exponencial y respetando
`Retry-After`) ante `429` y `503` en operaciones seguras: peticiones `GET` y
emisiones con `Idempotency-Key`.

## Recursos disponibles

| Recurso | Metodos principales |
|---|---|
| `folyo.dte` | `emitir`, `get_emision`, `emitir_y_esperar`, `listar_documentos`, `descargar_xml`, `descargar_pdf`, `regenerar_pdf`, `consultar_estado`, `consultar_envio`, `emitidos`, `recibidos`, `contribuyente`, `situacion_tributaria`, `enviar_rcof`, `resumen_rcof` |
| `folyo.folios` | `info`, `solicitar` |
| `folyo.rcv` | `periodos`, `periodo`, `sync`, `resumen_iva` |
| `folyo.clientes` | `listar`, `upsert`, `importar`, `buscar`, `actualizar`, `eliminar` |
| `folyo.empresa` | `listar`, `seleccionar` |
| `folyo.acuse` | `registrar`, `pendientes`, `estado` |
| `folyo.webhooks` | `listar`, `crear`, `actualizar`, `eliminar` |
| `folyo.api_keys` | `listar`, `crear`, `eliminar` |

Algunos endpoints (clientes, RCV, listado de documentos) requieren "panel
operativo" y responden `403` en planes solo-API.

## Seguridad

- La API key y el JWT nunca se incluyen en `repr(cliente)` ni en los errores.
- Los errores exponen solo el mensaje sanitizado del servidor, el codigo
  estable, el status HTTP y el `request_id`: nunca el cuerpo de la respuesta
  (que puede traer datos sensibles como el XML firmado o secrets de webhook).
- El SDK no escribe logs por defecto.

## Licencia

MIT. Ver [LICENSE](./LICENSE).
