Metadata-Version: 2.4
Name: sincpro-siat-soap
Version: 8.0.0
Summary: Bridge SOAP Services for SIAT Bolivia
License: SINCPRO S.R.L.
License-File: LICENSE.md
Author: Gutierrez, Andres
Author-email: andru1236@gmail.com
Requires-Python: >=3.12,<4.0
Classifier: License :: Other/Proprietary License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Dist: python-dotenv (>=1.2.2,<2.0.0)
Requires-Dist: signxml (>=4.4.0,<5.0.0)
Requires-Dist: sincpro-framework (>=3.1.0,<4.0.0)
Requires-Dist: xmltodict (>=1.0.4,<2.0.0)
Requires-Dist: zeep (>=4.3.2,<5.0.0)
Description-Content-Type: text/markdown

# Sincpro SIAT SOAP SDK

[![Python Version](https://img.shields.io/badge/python-3.12%2B-blue.svg)](https://www.python.org/downloads/)
[![License](https://img.shields.io/badge/license-SINCPRO%20S.R.L.-red.svg)](LICENSE.md)
[![Framework](https://img.shields.io/badge/framework-Sincpro%203.0-green.svg)](https://github.com/Sincpro-SRL/sincpro_framework)

SDK para consumir servicios SOAP del **SIAT (Sistema Integral de Facturación)** de Bolivia. Implementado con **Sincpro Framework 3.0** siguiendo arquitectura hexagonal y el patrón Unified Bus.

## 📋 Sobre el Proyecto

Este SDK proporciona una interfaz Python completa para interactuar con los servicios de facturación electrónica del SIAT de Bolivia, cubriendo:

- ✅ Facturación electrónica y computarizada
- ✅ Múltiples sectores (compra-venta, hotel, hospital, educativo, alquiler, etc.)
- ✅ Gestión de contingencias y eventos significativos
- ✅ Notas de crédito y débito
- ✅ Sincronización de catálogos
- ✅ Validación y firma digital de documentos XML
- ✅ Facturación masiva

### Características principales

- **Arquitectura modular**: Basado en Sincpro Framework con arquitectura hexagonal
- **Type-safe**: Validación completa con Pydantic DTOs
- **Gestión automática**: CUFD (renovación diaria) y CUIS por punto de venta
- **Context manager**: Propagación automática de metadatos (token, ambiente, etc.)
- **Multi-ambiente**: Soporte para entornos de producción y piloto
- **Tests completos**: Suite de tests siguiendo las 9 etapas de certificación SIAT

## 📄 Licencia

Este proyecto está licenciado bajo **LICENCIA EMPRESARIAL DE USO DE SOFTWARE** de Sincpro S.R.L.

### Resumen de términos

- ✅ Licencia **no exclusiva e intransferible**
- ✅ Uso limitado según contrato de licencia
- ❌ **Prohibido**: copiar, modificar o distribuir sin autorización
- ⚠️ El uso no autorizado activa mecanismos de seguridad
- ⚖️ Protegido por leyes de propiedad intelectual

**Importante:** El uso del Software requiere una licencia válida emitida por Sincpro S.R.L. El uso no autorizado puede resultar en sanciones legales y activación de medidas de protección.

Para más detalles, consulta el archivo [LICENSE.md](LICENSE.md).

---

# Pre-Requirements

- Python 3.12+
- [Poetry](https://python-poetry.org/docs/) para gestión de dependencias
- Virtualenv configurado (el proyecto usa virtualenv in-project)

## Configuración de Poetry

El proyecto incluye un `poetry.toml` para crear el virtualenv dentro del proyecto:

```toml
[virtualenvs]
create = true
in-project = true
```

Esto crea el entorno virtual en `.venv/` dentro del directorio del proyecto, facilitando la gestión y el aislamiento de dependencias.

# Instalación

```bash
# Verificar que Poetry está instalado
poetry --version

# Instalar dependencias
poetry install
```

# Configuración de Variables de Entorno

## Códigos de Sistema (System Codes)

| Código                   | Sectores Soportados                                   |
|--------------------------|-------------------------------------------------------|
| 7C3121D9A5A00BCE7B6A8DF  | Prevalorado, Alquiler, Prevalorado sin crédito fiscal |
| 7755D817B7935A52BC1A8DF  | Hotel, Hospital, Educativo                            |
| 721CDB813A795709E2128DF  | Computarizada, Electrónica, Nota de crédito/débito   |
| 353274141204F512BD7F     | Tasa cero, Educativo                                  |

## Variables Requeridas

```bash
# Token de autenticación SIAT
export SIAT_TOKEN="<tu_token_aqui>"

# Ambiente: 1=producción, 2=piloto/testing
export SIAT_ENVIRONMENT=2

# Modalidad: 1=electrónica, 2=computarizada
export SIAT_MODALITY=1

# Password para certificados de firma digital
export KEY_PASSWORD="<password_certificado>"

# Nivel de logging (opcional)
export SP_SIAT_LOG_LEVEL="INFO"

# Timeout para sincronización (opcional, en segundos)
export SYNC_OBJ_TIMEOUT=300
```

---

# Uso del SDK

Este SDK está construido sobre **Sincpro Framework 3.0.1** utilizando el patrón **Unified Bus**. El punto de entrada principal es `siat_soap_sdk`, que ejecuta Features y ApplicationServices del SDK.

## Uso básico

Por defecto, el SDK utiliza el `SIAT_TOKEN` y `SIAT_ENVIRONMENT` configurados en las variables de entorno:

```python
from sincpro_siat_soap import siat_soap_sdk
from sincpro_siat_soap.services.auth_permissions import (
    CommandGenerateCUIS,
    ResponseGenerateCUIS,
)
from sincpro_siat_soap.global_definitions import SIATEnvironment, SIATModality

# Ejecutar una operación (Feature)
response = siat_soap_sdk(
    CommandGenerateCUIS(
        nit=412158028,
        system_code="353274141204F512BD7F",
        point_of_sale=1,
        branch_office=0,
        billing_type=SIATModality.ELECTRONICA,
        environment=SIATEnvironment.TEST,
    ),
    ResponseGenerateCUIS,
)

print(f"CUIS generado: {response.cuis}")
```

## Uso con contexto personalizado

Si necesitas usar un token o ambiente diferente al configurado por defecto, puedes usar el **context manager**:

```python
from sincpro_siat_soap import siat_soap_sdk
from sincpro_siat_soap.global_definitions import SIATEnvironment
from sincpro_siat_soap.services.billing import (
    CommandCheckHealth,
    ResponseCheckHealth,
)

# Ejecutar con contexto personalizado usando context manager
with siat_soap_sdk.context({
    "TOKEN": "tu_token_personalizado_aqui",
    "SIAT_ENV": SIATEnvironment.PRODUCTION,  # o SIATEnvironment.TEST
}) as sdk_with_context:
    response = sdk_with_context(
        CommandCheckHealth(),
        ResponseCheckHealth,
    )
    print(f"Estado del servicio: {response.raw_response}")
```

El context manager del framework Sincpro permite:
- **Thread-safe**: Aislamiento de contexto por hilo
- **Nested contexts**: Soporta contextos anidados con capacidad de override
- **Automatic propagation**: El contexto se propaga automáticamente a Features y ApplicationServices internos

## Servicios disponibles

El SDK organiza las operaciones en módulos por tipo de servicio:

```python
from sincpro_siat_soap import siat_soap_sdk

# Autenticación y permisos
from sincpro_siat_soap.services.auth_permissions import (
    CommandGenerateCUIS,
    CommandGenerateCUFD,
)

# Sincronización de datos (catálogos)
from sincpro_siat_soap.services.synchronization_data import (
    CommandGenerateSyncDataDict,
    CommandCreateOrLoadSyncObj,
)

# Operaciones (puntos de venta, eventos significativos)
from sincpro_siat_soap.services.operations import (
    CommandCreatePointOfSale,
    CommandRegisterSignificantEvent,
)

# Archivos digitales (envío, verificación, anulación)
from sincpro_siat_soap.services.digital_files import (
    CmdSendDocumentToSiat,
    CmdVerifyDocument,
    CmdCancelDocument,
)

# Facturación
from sincpro_siat_soap.services.billing import (
    CommandCheckHealth,
    CommandMasiveInvoceReception,
)
```

## Ejemplo completo: Flujo de facturación

```python
from sincpro_siat_soap import siat_soap_sdk
from sincpro_siat_soap.global_definitions import (
    SIATEnvironment,
    SIATModality,
    SIATApprovedDocumentId,
    SIATEmissionType,
    SIATInvoiceType,
)
from sincpro_siat_soap.services.auth_permissions import (
    CommandGenerateCUIS,
    ResponseGenerateCUIS,
)
from sincpro_siat_soap.services.synchronization_data import (
    CommandCreateOrLoadSyncObj,
    ResponseCreateOrLoadSyncObj,
)
from sincpro_siat_soap.services.digital_files import (
    CmdSendDocumentToSiat,
    ResSendDocumentToSiat,
)

# 1. Generar CUIS (una vez por punto de venta)
cuis_response = siat_soap_sdk(
    CommandGenerateCUIS(
        nit=412158028,
        system_code="353274141204F512BD7F",
        point_of_sale=1,
        branch_office=0,
        billing_type=SIATModality.ELECTRONICA,
        environment=SIATEnvironment.TEST,
    ),
    ResponseGenerateCUIS,
)

# 2. Crear/cargar objeto de sincronización (gestiona CUFD y catálogos)
sync_response = siat_soap_sdk(
    CommandCreateOrLoadSyncObj(
        nit=412158028,
        cuis=cuis_response.cuis,
        branch_office=0,
        point_of_sale=1,
        system_code="353274141204F512BD7F",
        path_serialized="./sync_data",
        environment=SIATEnvironment.TEST,
        modality=SIATModality.ELECTRONICA,
    ),
    ResponseCreateOrLoadSyncObj,
)

sync_obj = sync_response.sync_obj

# 3. Enviar factura (con XML firmado previamente)
invoice_response = siat_soap_sdk(
    CmdSendDocumentToSiat(
        nit=sync_obj.nit,
        cuis=sync_obj.cuis,
        cufd=sync_obj.cufd,
        sector_document=SIATApprovedDocumentId.COMPRA_VENTA,
        emission_code=SIATEmissionType.ONLINE,
        sent_date="2025-02-25T10:30:00.000",
        hash_invoice_file="hash_del_archivo",
        branch_office=sync_obj.branch_office,
        system_code=sync_obj.system_code,
        point_of_sale=sync_obj.point_of_sale,
        xml="xml_comprimido_y_firmado",
        type_invoice=SIATInvoiceType.CREDITO_FISCAL,
        environment=SIATEnvironment.TEST,
        modality=SIATModality.ELECTRONICA,
    ),
    ResSendDocumentToSiat,
)

print(f"Factura enviada: {invoice_response.raw_response}")
```

## Manejo de errores

El SDK lanza excepciones `SIATException` cuando hay errores en las operaciones:

```python
from sincpro_siat_soap import siat_soap_sdk
from sincpro_siat_soap.shared.core_exceptions import SIATException

try:
    response = siat_soap_sdk(command, ResponseType)
except SIATException as e:
    print(f"Error SIAT: {e}")
    # Manejar el error según tu lógica de negocio
```

# Tests

```bash
poetry run pytest
```

## SIAT Integration Tests (`test/siat_test`)

El directorio `test/siat_test` contiene tests de integración que validan el flujo completo de facturación electrónica con el sistema SIAT (Sistema de Facturación de Bolivia). Estos tests simulan el proceso real de certificación y operación con SIAT.

### Estructura de tests por etapas

Los tests están organizados siguiendo las **etapas de certificación SIAT**:

#### **Etapa 1: Obtención de CUIS** (`test_etapa_1.py`)
Valida la generación del **Código Único de Inicio de Sistemas (CUIS)** para cada punto de venta.

```python
from sincpro_siat_soap import siat_soap_sdk
from sincpro_siat_soap.services.auth_permissions import (
    CommandGenerateCUIS,
    ResponseGenerateCUIS,
)

# Generar CUIS para punto de venta
response = siat_soap_sdk(
    CommandGenerateCUIS(
        nit=customer_nit,
        system_code=customer_system_code,
        point_of_sale=1,
        branch_office=0,
        billing_type=SIATModality.ELECTRONICA,
        environment=SIATEnvironment.TEST,
    ),
    ResponseGenerateCUIS,
)
```

**Conceptos clave:**
- Cada punto de venta requiere su propio CUIS
- El CUIS se genera una sola vez por punto de venta
- Es necesario para todas las operaciones posteriores

#### **Etapa 2: Sincronización de catálogos** (`test_etapa_2.py`)
Sincroniza los catálogos de códigos del SIAT (tipos de documento, monedas, unidades de medida, etc.).

```python
from sincpro_siat_soap.services.synchronization_data import (
    CommandGenerateSyncDataDict,
    ResponseGenerateSyncDataDict,
)

# Sincronizar catálogos
response = siat_soap_sdk(
    CommandGenerateSyncDataDict(
        nit=nit,
        cuis=cuis,
        system_code=system_code,
        environment=environment,
        point_of_sale=point_of_sale,
        branch_office=branch_office,
    ),
    ResponseGenerateSyncDataDict,
)
```

#### **Etapa 3: Generación de CUFD** (`test_etapa_3.py`)
El **Código Único de Factura Diaria (CUFD)** debe renovarse diariamente.

```python
# Renovar CUFD (se hace automáticamente con el SynchronizationObject)
sync_obj.request_new_cufd()
```

#### **Etapa 4, 7, 8: Facturación en línea** (`test_etapa_4_7_8_v2.py`)
Tests de emisión, verificación, anulación y reversión de facturas **en línea**.

```python
from sincpro_siat_soap.services.digital_files import (
    CmdSendDocumentToSiat,
    CmdVerifyDocument,
    CmdCancelDocument,
    CmdRevertCancelledDocument,
)

# 1. Enviar factura
res_send = siat_soap_sdk(
    CmdSendDocumentToSiat(
        nit=nit,
        cuis=cuis,
        cufd=cufd,
        sector_document=SIATApprovedDocumentId.COMPRA_VENTA,
        emission_code=SIATEmissionType.ONLINE,
        xml=invoice_xml.compressed_xml,
        # ... otros parámetros
    ),
    ResSendDocumentToSiat,
)

# 2. Verificar estado de la factura
res_verify = siat_soap_sdk(
    CmdVerifyDocument(
        cuf_or_reception_code=cuf,
        # ... otros parámetros
    ),
    ResVerifyDocument,
)

# 3. Anular factura
res_cancel = siat_soap_sdk(
    CmdCancelDocument(
        cuf=cuf,
        cancellation_reason=cancellation_type,
        # ... otros parámetros
    ),
    ResCancelDocument,
)

# 4. Revertir anulación
res_revert = siat_soap_sdk(
    CmdRevertCancelledDocument(
        cuf=cuf,
        # ... otros parámetros
    ),
    ResRevertCancelledDocument,
)
```

**Sectores soportados:**
- Compra y venta (COMPRA_VENTA)
- Notas de crédito/débito
- Sector educativo
- Sector hotelero
- Sector hospitalario
- Alquiler de bienes
- Prevalorada
- Tasa cero

#### **Etapa 5, 6: Facturación fuera de línea (Contingencia)** (`test_etapa_5_6_v2.py`)
Tests de emisión de facturas en **modo offline** con eventos significativos.

```python
from sincpro_siat_soap.services.operations import (
    CommandRegisterSignificantEvent,
)

# 1. Registrar evento significativo (corte de internet, luz, etc.)
significant_event_response = siat_soap_sdk(
    CommandRegisterSignificantEvent(
        event_type=significant_event[0],
        description=significant_event[1],
        start_datetime_event=start_datetime.isoformat(),
        end_datetime_event=end_datetime.isoformat(),
        # ... otros parámetros
    ),
    ResponseRegisterSignificantEvent,
)

# 2. Enviar paquete de facturas offline
package = siat_soap_sdk(
    CmdSendDocumentPackage(
        xml_list=signed_invoice,
        cafc=cafc,  # Código de Autorización de Facturas de Contingencia
        with_significant_event_type=significant_event[0],
        emission_code=SIATEmissionType.OFFLINE,
        # ... otros parámetros
    ),
    ResSendDocumentPackage,
)
```

**Eventos significativos soportados:**
- Corte de internet (`SE_CORTE_INTERNET`)
- Corte de electricidad (`SE_CORTE_ELECTRICIDAD`)
- Falla de hardware (`SE_FALLA_HARDWARE`)
- Virus informático (`SE_VIRUS_INFORMATICO`)
- Problemas con Administración Tributaria (`SE_ADMINISTRACION_TRIBUTARIA`)
- Zonas sin internet (`SE_ZONAS_SIN_INTERNET`)
- Despliegue a zonas sin internet (`SE_DEPLIEGUE_A_ZONAS_SIN_INTERNET`)

#### **Etapa 9: Facturación masiva** (`test_etapa_9.py`)
Tests de envío de múltiples facturas en un solo paquete.

```python
from sincpro_siat_soap.services.billing import (
    CommandMasiveInvoceReception,
    CommandVerifyMassiveInvoice,
)

# Enviar paquete masivo
massive_response = siat_soap_sdk(
    CommandMasiveInvoceReception(
        xml=compressed_files.zip_file,
        count_invoice=len(invoice_list),
        # ... otros parámetros
    ),
    ResponseMasiveInvoiceReception,
)

# Verificar procesamiento
validation = siat_soap_sdk(
    CommandVerifyMassiveInvoice(
        reception_code=massive_response.reception_code,
        # ... otros parámetros
    ),
    ResponseVerifyMassiveInvoice,
)
```

### Objeto de sincronización (`SynchronizationObject`)

El **SynchronizationObject** es una utilidad central que encapsula y gestiona automáticamente:
- CUIS (Código Único de Inicio de Sistemas)
- CUFD (Código Único de Factura Diaria) con renovación automática
- Catálogos sincronizados del SIAT
- Configuración de punto de venta y sucursal

```python
from sincpro_siat_soap.services.synchronization_data import (
    CommandCreateOrLoadSyncObj,
    ResponseCreateOrLoadSyncObj,
)

# Crear o cargar objeto de sincronización
response = siat_soap_sdk(
    CommandCreateOrLoadSyncObj(
        nit=nit,
        cuis=cuis,
        branch_office=0,
        point_of_sale=1,
        system_code=system_code,
        path_serialized=".",  # Ruta para persistir el objeto
        environment=SIATEnvironment.TEST,
        modality=SIATModality.ELECTRONICA,
    ),
    ResponseCreateOrLoadSyncObj,
)

sync_obj = response.sync_obj

# Renovar CUFD cuando sea necesario
sync_obj.request_new_cufd()
```

### Configuración de tests

Los tests utilizan fixtures definidas en `conftest.py`:

```python
# Variables necesarias
customer_nit = 412158028
customer_system_code = "353274141204F512BD7F"
customer_default_branch_office = 0
point_of_sale = 1

# Certificados para firma digital
certs_path = "certs_guide/siat_pilot"
cert = open(f"{certs_path}/certificate.crt", "r").read()
key = open(f"{certs_path}/private.key", "r").read()
```

### Ejecutar tests SIAT

```bash
# Todos los tests SIAT
make test_one t=test/siat_test

# Test específico por etapa
poetry run pytest test/siat_test/test_etapa_1.py -v

# Con output detallado
poetry run pytest test/siat_test/test_etapa_4_7_8_v2.py -vvs
```

### Importante antes de ejecutar

1. **Configurar variables de entorno:**
```bash
export SIAT_TOKEN="<tu_token_siat>"
export SIAT_ENVIRONMENT=2  # 1=producción, 2=piloto
export SIAT_MODALITY=1     # 1=electronica, 2=computarizada
export KEY_PASSWORD="<password_certificado>"
```

2. **Tener certificados válidos en** `certs_guide/siat_pilot/`

3. **Ejecutar primero** `test_only_run_at_the_beggining.py` para crear puntos de venta si es necesario

4. **Los tests de contingencia (etapa 5-6)** requieren configuración especial y deben ejecutarse en orden

### Notas sobre las etapas

- **Etapa 1**: Ejecutar una sola vez por punto de venta
- **Etapa 2**: Ejecutar periódicamente para actualizar catálogos
- **Etapa 3**: El CUFD se renueva automáticamente cada 24 horas
- **Etapas 4-8**: Tests de flujo completo en línea (pueden ejecutarse múltiples veces)
- **Etapas 5-6**: Requieren registro previo de eventos significativos
- **Etapa 9**: Tests de alto volumen (facturación masiva)

# Uso Interactivo con IPython

Para usar el SDK de forma interactiva:

```bash
poetry run ipython
```

Esto te permite probar comandos y explorar el SDK en un entorno REPL.

---

# Instalación en Otros Proyectos

## Generar el Wheel

Para distribuir e instalar esta librería en otros proyectos:

```bash
# Construir el paquete wheel
poetry build

# Esto crea un directorio `dist/` con el archivo .whl
```

## Instalar el Wheel

```bash
# Con pip
pip install dist/sincpro_siat_soap-7.2.1-py3-none-any.whl

# Con poetry en otro proyecto
poetry add /path/to/sincpro_siat_soap-7.2.1-py3-none-any.whl
```

---

## 📚 Documentación Adicional

Para más información sobre el SDK:
- Ver tests de ejemplo en `test/siat_test/`
- Consultar documentación generada en `generated_docs/`
- Revisar contexto AI en `generated_docs/ai_context/`

## 🤝 Soporte

Para soporte técnico o consultas sobre licencias, contactar a Sincpro S.R.L.

---

**© 2025 Sincpro S.R.L. - Todos los derechos reservados**


