libredte-lib-sdk 0.6.1__tar.gz → 0.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/.gitignore +2 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/CLAUDE.md +0 -8
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/PKG-INFO +57 -9
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/README.rst +56 -8
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/book/validator.py +7 -3
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/common.py +10 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/document/dispatcher.py +46 -12
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/document/loader.py +2 -2
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/document/models.py +12 -13
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/document/validator.py +9 -4
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/exchange/document_response.py +7 -5
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/exchange/models.py +2 -2
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/identifier/models.py +12 -12
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/integration/__init__.py +25 -0
- libredte_lib_sdk-0.7.0/libredte_lib_sdk/billing/integration/models.py +631 -0
- libredte_lib_sdk-0.7.0/libredte_lib_sdk/billing/integration/request.py +51 -0
- libredte_lib_sdk-0.7.0/libredte_lib_sdk/billing/integration/sii_boleta.py +131 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/integration/sii_dte.py +20 -25
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/integration/sii_rcv.py +18 -20
- libredte_lib_sdk-0.7.0/libredte_lib_sdk/billing/integration/sii_rtc.py +150 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/ownership_transfer/aec.py +5 -3
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/trading_parties/mandatario_manager.py +2 -2
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/trading_parties/models.py +4 -4
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/client.py +29 -10
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/exceptions.py +93 -11
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/human_resources/integration/previred_provider.py +11 -1
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/sdk.py +3 -1
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/system/repository/catalog.py +3 -3
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/pyproject.toml +1 -1
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/integration/conftest.py +54 -1
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/integration/test_batch_processor.py +4 -2
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/integration/test_book.py +5 -2
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/integration/test_caf.py +1 -1
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/integration/test_document_loader.py +1 -1
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/integration/test_document_rendering.py +7 -3
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/integration/test_document_validation.py +24 -4
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/integration/test_exchange.py +2 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/integration/test_human_resources.py +1 -1
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/integration/test_operation_not_found.py +2 -2
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/integration/test_ownership_transfer.py +1 -0
- libredte_lib_sdk-0.7.0/tests/integration/test_sii_certification.py +456 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/test_client.py +114 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/test_exceptions.py +4 -4
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/test_models.py +30 -30
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/test_response_registry.py +25 -1
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/test_services.py +107 -107
- libredte_lib_sdk-0.7.0/tests/test_sii_boleta_and_rtc.py +551 -0
- libredte_lib_sdk-0.7.0/tests/test_sii_request_options.py +135 -0
- libredte_lib_sdk-0.6.1/libredte_lib_sdk/billing/integration/models.py +0 -285
- libredte_lib_sdk-0.6.1/libredte_lib_sdk/billing/integration/sii_rtc.py +0 -57
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/.github/workflows/ci.yml +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/.github/workflows/docs.yml +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/.readthedocs.yaml +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/LICENSE +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/Makefile +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/docs/Makefile +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/docs/conf.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/docs/index.rst +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/__init__.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/__init__.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/book/__init__.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/book/builder.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/book/loader.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/book/models.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/document/__init__.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/document/batch_processor.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/document/builder.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/document/examples.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/document/parser.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/document/renderer.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/enums.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/exchange/__init__.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/identifier/__init__.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/identifier/caf_faker.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/identifier/caf_loader.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/identifier/caf_validator.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/ownership_transfer/__init__.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/ownership_transfer/models.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/trading_parties/__init__.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/human_resources/__init__.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/human_resources/integration/__init__.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/human_resources/payroll/__init__.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/human_resources/payroll/calculator.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/human_resources/payroll/renderer.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/py.typed +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/response_registry.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/system/__init__.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/system/certificate/__init__.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/system/certificate/loader.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/system/repository/__init__.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/__init__.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/conftest.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/fixtures/certificate_112223339.p12 +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/integration/__init__.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/integration/test_certificate_loader.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/integration/test_document_parser.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/integration/test_examples.py +0 -0
- {libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/tests/integration/test_repository.py +0 -0
|
@@ -2,14 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
## Pendiente
|
|
4
4
|
|
|
5
|
-
- **Tests en vivo de `integration.sii_dte`/`sii_rcv`/`sii_rtc`** (10
|
|
6
|
-
operaciones): tienen test unitario (mockeado), pero ninguno en
|
|
7
|
-
`live`. A diferencia del resto de la suite `live` (que usa
|
|
8
|
-
`fake_certificate`, autofirmado), estas operaciones hablan con el SII
|
|
9
|
-
real y necesitan un certificado real vigente — no hay fixture para
|
|
10
|
-
eso hoy, y committear uno no correspondería. Falta decidir el
|
|
11
|
-
mecanismo (ej. certificado real vía variable de entorno, `skip` si
|
|
12
|
-
no está disponible) antes de poder escribirlos.
|
|
13
5
|
- **DTO `Liquidacion` sin construir.** `human_resources.payroll
|
|
14
6
|
.calculator::calculate()` recibe `empleado`/`contrato`/`contexto`
|
|
15
7
|
como `dict` (correcto — son entradas) pero **devuelve** la
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: libredte-lib-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: SDK Python para la API de LibreDTE Lib (facturacion electronica de Chile).
|
|
5
5
|
Project-URL: Homepage, https://www.libredte.cl
|
|
6
6
|
Project-URL: Source, https://github.com/libredte/libredte-lib-sdk-python
|
|
@@ -74,7 +74,11 @@ Uso
|
|
|
74
74
|
|
|
75
75
|
.. code-block:: python
|
|
76
76
|
|
|
77
|
+
import dataclasses
|
|
78
|
+
|
|
77
79
|
from libredte_lib_sdk import LibreDTE
|
|
80
|
+
from libredte_lib_sdk.billing.common import SII_RUT
|
|
81
|
+
from libredte_lib_sdk.billing.integration import SiiRequestOptions
|
|
78
82
|
from libredte_lib_sdk.billing.trading_parties import Mandatario
|
|
79
83
|
|
|
80
84
|
sdk = LibreDTE() # base_url y api_token también vía env vars, ver abajo
|
|
@@ -90,6 +94,7 @@ Uso
|
|
|
90
94
|
'RUTEmisor': '76192083-9',
|
|
91
95
|
'RznSoc': 'SASCO SpA',
|
|
92
96
|
'GiroEmis': 'Servicios',
|
|
97
|
+
'Acteco': 620200,
|
|
93
98
|
'DirOrigen': 'Santiago',
|
|
94
99
|
'CmnaOrigen': 'Santiago',
|
|
95
100
|
},
|
|
@@ -116,7 +121,7 @@ Uso
|
|
|
116
121
|
codigo_documento=33, folio_desde=1, folio_hasta=100,
|
|
117
122
|
)
|
|
118
123
|
certificate = b.trading_parties.mandatario_manager.create_fake_certificate(
|
|
119
|
-
Mandatario(
|
|
124
|
+
Mandatario(run='76192083-9', nombre='SASCO SpA', email='sasco@example.com'),
|
|
120
125
|
)
|
|
121
126
|
|
|
122
127
|
# En producción: cargar y validar el CAF real que el SII le entregó
|
|
@@ -132,17 +137,46 @@ Uso
|
|
|
132
137
|
input_data, caf_xml=caf.xml_base64, certificate=certificate,
|
|
133
138
|
)
|
|
134
139
|
|
|
135
|
-
# 3.
|
|
136
|
-
# `documento` ya trae
|
|
137
|
-
# pasarlos aparte
|
|
138
|
-
|
|
140
|
+
# 3. Sobres. El envío normal usa dos: uno para el SII y otro para el
|
|
141
|
+
# receptor del documento (el cliente). `documento` ya trae
|
|
142
|
+
# certificate/emisor incluidos — no hace falta pasarlos aparte, salvo
|
|
143
|
+
# `autorizacion_dte` del emisor (`fecha_resolucion` y
|
|
144
|
+
# `numero_resolucion`), que va en la carátula.
|
|
145
|
+
documento = dataclasses.replace(
|
|
146
|
+
documento,
|
|
147
|
+
emisor={
|
|
148
|
+
**documento.emisor,
|
|
149
|
+
'autorizacion_dte': {
|
|
150
|
+
'fecha_resolucion': '2019-12-23',
|
|
151
|
+
'numero_resolucion': 0,
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
# El sobre para el SII siempre tiene al SII como receptor.
|
|
157
|
+
sobre_sii = b.document.dispatcher.create(documento, receptor_rut=SII_RUT)
|
|
158
|
+
|
|
159
|
+
# El sobre para el cliente toma el receptor del documento.
|
|
160
|
+
sobre_cliente = b.document.dispatcher.create(documento)
|
|
161
|
+
|
|
162
|
+
# 4. Envío al SII y estado del envío, por Track ID.
|
|
139
163
|
envio = b.integration.sii_dte.send(
|
|
140
|
-
|
|
164
|
+
sobre_sii.xml_base64, certificate=certificate,
|
|
165
|
+
company_rut='76192083-9',
|
|
166
|
+
)
|
|
167
|
+
estado = b.integration.sii_dte.check_status(
|
|
168
|
+
envio.track_id, certificate=certificate, company_rut='76192083-9',
|
|
141
169
|
)
|
|
142
170
|
|
|
143
|
-
#
|
|
171
|
+
# Las boletas (tipos 39 y 41) se envían por otra API del SII, solo
|
|
172
|
+
# disponible en Lib Pro: `b.integration.sii_boleta` tiene `send()`,
|
|
173
|
+
# `check_status()` y `validate_document()` con la misma forma.
|
|
174
|
+
|
|
175
|
+
# Reintentos y tiempos de una llamada al SII (todos opcionales; la API
|
|
176
|
+
# usa los suyos si no se indican y los ajusta a su rango).
|
|
144
177
|
estado = b.integration.sii_dte.check_status(
|
|
145
178
|
envio.track_id, certificate=certificate, company_rut='76192083-9',
|
|
179
|
+
options=SiiRequestOptions(retries=3, timeout=20, max_duration=60),
|
|
146
180
|
)
|
|
147
181
|
|
|
148
182
|
# 5. HTML o PDF — misma forma de respuesta para ambos.
|
|
@@ -254,7 +288,10 @@ levanta ``libredte_lib_sdk.LibreDteApiError``, con ``.status_code``,
|
|
|
254
288
|
si la API la informó — ej. ``DocumentException``, o una excepción de
|
|
255
289
|
autenticación del SII). Un ``429`` de la API levanta
|
|
256
290
|
``LibreDteRateLimitError`` (subclase de lo anterior), con
|
|
257
|
-
``.retry_after
|
|
291
|
+
``.retry_after`` y ``.reset_at`` (cuándo se libera), ``.policy`` (cuál límite
|
|
292
|
+
se agotó), el cupo del usuario (``.limit``/``.remaining``, solo con
|
|
293
|
+
autenticación) y el límite por IP (``.ip_limit``/``.ip_remaining``). Cada
|
|
294
|
+
dato es ``None`` si la API no lo informa. Un problema de red levanta
|
|
258
295
|
``libredte_lib_sdk.LibreDteConnectionError``.
|
|
259
296
|
|
|
260
297
|
Desarrollo
|
|
@@ -270,6 +307,17 @@ Los tests unitarios no hacen red real: mockean la API con ``respx``. Los
|
|
|
270
307
|
de ``tests/integration/`` sí (marker ``live``), y están excluidos por
|
|
271
308
|
defecto de ``pytest``/``make test``/``make check``.
|
|
272
309
|
|
|
310
|
+
Los tests ``live`` usan ``LIBREDTE_LIB_SDK_BASE_URL`` y
|
|
311
|
+
``LIBREDTE_LIB_SDK_TOKEN``. Los de ``tests/integration/test_sii_certification.py``
|
|
312
|
+
envían documentos reales al ambiente de certificación del SII y se omiten si
|
|
313
|
+
faltan estas variables de entorno:
|
|
314
|
+
|
|
315
|
+
- ``LIBREDTE_CERTIFICATE_CERT`` y ``LIBREDTE_CERTIFICATE_PKEY``: certificado
|
|
316
|
+
digital y su clave privada, en PEM (un ``\n`` literal vale como salto de
|
|
317
|
+
línea).
|
|
318
|
+
- ``LIBREDTE_CAF_DIR``: directorio con los CAF de certificación, uno por tipo
|
|
319
|
+
de documento (``033.xml``, ``034.xml``, ``039.xml``, ...).
|
|
320
|
+
|
|
273
321
|
Términos y condiciones de uso
|
|
274
322
|
------------------------------
|
|
275
323
|
|
|
@@ -30,7 +30,11 @@ Uso
|
|
|
30
30
|
|
|
31
31
|
.. code-block:: python
|
|
32
32
|
|
|
33
|
+
import dataclasses
|
|
34
|
+
|
|
33
35
|
from libredte_lib_sdk import LibreDTE
|
|
36
|
+
from libredte_lib_sdk.billing.common import SII_RUT
|
|
37
|
+
from libredte_lib_sdk.billing.integration import SiiRequestOptions
|
|
34
38
|
from libredte_lib_sdk.billing.trading_parties import Mandatario
|
|
35
39
|
|
|
36
40
|
sdk = LibreDTE() # base_url y api_token también vía env vars, ver abajo
|
|
@@ -46,6 +50,7 @@ Uso
|
|
|
46
50
|
'RUTEmisor': '76192083-9',
|
|
47
51
|
'RznSoc': 'SASCO SpA',
|
|
48
52
|
'GiroEmis': 'Servicios',
|
|
53
|
+
'Acteco': 620200,
|
|
49
54
|
'DirOrigen': 'Santiago',
|
|
50
55
|
'CmnaOrigen': 'Santiago',
|
|
51
56
|
},
|
|
@@ -72,7 +77,7 @@ Uso
|
|
|
72
77
|
codigo_documento=33, folio_desde=1, folio_hasta=100,
|
|
73
78
|
)
|
|
74
79
|
certificate = b.trading_parties.mandatario_manager.create_fake_certificate(
|
|
75
|
-
Mandatario(
|
|
80
|
+
Mandatario(run='76192083-9', nombre='SASCO SpA', email='sasco@example.com'),
|
|
76
81
|
)
|
|
77
82
|
|
|
78
83
|
# En producción: cargar y validar el CAF real que el SII le entregó
|
|
@@ -88,17 +93,46 @@ Uso
|
|
|
88
93
|
input_data, caf_xml=caf.xml_base64, certificate=certificate,
|
|
89
94
|
)
|
|
90
95
|
|
|
91
|
-
# 3.
|
|
92
|
-
# `documento` ya trae
|
|
93
|
-
# pasarlos aparte
|
|
94
|
-
|
|
96
|
+
# 3. Sobres. El envío normal usa dos: uno para el SII y otro para el
|
|
97
|
+
# receptor del documento (el cliente). `documento` ya trae
|
|
98
|
+
# certificate/emisor incluidos — no hace falta pasarlos aparte, salvo
|
|
99
|
+
# `autorizacion_dte` del emisor (`fecha_resolucion` y
|
|
100
|
+
# `numero_resolucion`), que va en la carátula.
|
|
101
|
+
documento = dataclasses.replace(
|
|
102
|
+
documento,
|
|
103
|
+
emisor={
|
|
104
|
+
**documento.emisor,
|
|
105
|
+
'autorizacion_dte': {
|
|
106
|
+
'fecha_resolucion': '2019-12-23',
|
|
107
|
+
'numero_resolucion': 0,
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# El sobre para el SII siempre tiene al SII como receptor.
|
|
113
|
+
sobre_sii = b.document.dispatcher.create(documento, receptor_rut=SII_RUT)
|
|
114
|
+
|
|
115
|
+
# El sobre para el cliente toma el receptor del documento.
|
|
116
|
+
sobre_cliente = b.document.dispatcher.create(documento)
|
|
117
|
+
|
|
118
|
+
# 4. Envío al SII y estado del envío, por Track ID.
|
|
95
119
|
envio = b.integration.sii_dte.send(
|
|
96
|
-
|
|
120
|
+
sobre_sii.xml_base64, certificate=certificate,
|
|
121
|
+
company_rut='76192083-9',
|
|
122
|
+
)
|
|
123
|
+
estado = b.integration.sii_dte.check_status(
|
|
124
|
+
envio.track_id, certificate=certificate, company_rut='76192083-9',
|
|
97
125
|
)
|
|
98
126
|
|
|
99
|
-
#
|
|
127
|
+
# Las boletas (tipos 39 y 41) se envían por otra API del SII, solo
|
|
128
|
+
# disponible en Lib Pro: `b.integration.sii_boleta` tiene `send()`,
|
|
129
|
+
# `check_status()` y `validate_document()` con la misma forma.
|
|
130
|
+
|
|
131
|
+
# Reintentos y tiempos de una llamada al SII (todos opcionales; la API
|
|
132
|
+
# usa los suyos si no se indican y los ajusta a su rango).
|
|
100
133
|
estado = b.integration.sii_dte.check_status(
|
|
101
134
|
envio.track_id, certificate=certificate, company_rut='76192083-9',
|
|
135
|
+
options=SiiRequestOptions(retries=3, timeout=20, max_duration=60),
|
|
102
136
|
)
|
|
103
137
|
|
|
104
138
|
# 5. HTML o PDF — misma forma de respuesta para ambos.
|
|
@@ -210,7 +244,10 @@ levanta ``libredte_lib_sdk.LibreDteApiError``, con ``.status_code``,
|
|
|
210
244
|
si la API la informó — ej. ``DocumentException``, o una excepción de
|
|
211
245
|
autenticación del SII). Un ``429`` de la API levanta
|
|
212
246
|
``LibreDteRateLimitError`` (subclase de lo anterior), con
|
|
213
|
-
``.retry_after
|
|
247
|
+
``.retry_after`` y ``.reset_at`` (cuándo se libera), ``.policy`` (cuál límite
|
|
248
|
+
se agotó), el cupo del usuario (``.limit``/``.remaining``, solo con
|
|
249
|
+
autenticación) y el límite por IP (``.ip_limit``/``.ip_remaining``). Cada
|
|
250
|
+
dato es ``None`` si la API no lo informa. Un problema de red levanta
|
|
214
251
|
``libredte_lib_sdk.LibreDteConnectionError``.
|
|
215
252
|
|
|
216
253
|
Desarrollo
|
|
@@ -226,6 +263,17 @@ Los tests unitarios no hacen red real: mockean la API con ``respx``. Los
|
|
|
226
263
|
de ``tests/integration/`` sí (marker ``live``), y están excluidos por
|
|
227
264
|
defecto de ``pytest``/``make test``/``make check``.
|
|
228
265
|
|
|
266
|
+
Los tests ``live`` usan ``LIBREDTE_LIB_SDK_BASE_URL`` y
|
|
267
|
+
``LIBREDTE_LIB_SDK_TOKEN``. Los de ``tests/integration/test_sii_certification.py``
|
|
268
|
+
envían documentos reales al ambiente de certificación del SII y se omiten si
|
|
269
|
+
faltan estas variables de entorno:
|
|
270
|
+
|
|
271
|
+
- ``LIBREDTE_CERTIFICATE_CERT`` y ``LIBREDTE_CERTIFICATE_PKEY``: certificado
|
|
272
|
+
digital y su clave privada, en PEM (un ``\n`` literal vale como salto de
|
|
273
|
+
línea).
|
|
274
|
+
- ``LIBREDTE_CAF_DIR``: directorio con los CAF de certificación, uno por tipo
|
|
275
|
+
de documento (``033.xml``, ``034.xml``, ``039.xml``, ...).
|
|
276
|
+
|
|
229
277
|
Términos y condiciones de uso
|
|
230
278
|
------------------------------
|
|
231
279
|
|
{libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/book/validator.py
RENAMED
|
@@ -18,8 +18,10 @@ class BookValidatorService:
|
|
|
18
18
|
vacío en caso de éxito.
|
|
19
19
|
"""
|
|
20
20
|
|
|
21
|
-
_VALIDATE_SCHEMA_OPERATION = 'billing.book.validator::
|
|
22
|
-
_VALIDATE_SIGNATURE_OPERATION =
|
|
21
|
+
_VALIDATE_SCHEMA_OPERATION = 'billing.book.validator::validate_schema'
|
|
22
|
+
_VALIDATE_SIGNATURE_OPERATION = (
|
|
23
|
+
'billing.book.validator::validate_signature'
|
|
24
|
+
)
|
|
23
25
|
|
|
24
26
|
def __init__(self, client: ApiClient) -> None:
|
|
25
27
|
"""Guarda el `ApiClient` compartido usado para llamar a la API."""
|
|
@@ -40,7 +42,9 @@ class BookValidatorService:
|
|
|
40
42
|
Valida la firma electrónica del libro.
|
|
41
43
|
|
|
42
44
|
El libro tiene una sola firma — devuelve un único `dict`, no
|
|
43
|
-
una lista
|
|
45
|
+
una lista, con `{'valid': bool, 'error': str | None,
|
|
46
|
+
'signature': {...}}`. Una firma inválida no levanta error, hay
|
|
47
|
+
que revisar `valid`.
|
|
44
48
|
"""
|
|
45
49
|
return cast(
|
|
46
50
|
'dict[str, Any]',
|
|
@@ -8,6 +8,16 @@ from __future__ import annotations
|
|
|
8
8
|
import base64
|
|
9
9
|
from typing import Any
|
|
10
10
|
|
|
11
|
+
SII_RUT = '60803000-K'
|
|
12
|
+
"""
|
|
13
|
+
RUT del SII, receptor de la carátula de todo sobre que se envía al SII.
|
|
14
|
+
|
|
15
|
+
Un sobre para el SII (`SiiDteService.send`, `SiiBoletaService.send`) se
|
|
16
|
+
arma con `receptor_rut=SII_RUT`. Un sobre para el receptor real del
|
|
17
|
+
documento (el cliente) se arma sin `receptor_rut`: la carátula toma el
|
|
18
|
+
receptor del primer documento.
|
|
19
|
+
"""
|
|
20
|
+
|
|
11
21
|
|
|
12
22
|
def encode_content(content: str | bytes) -> str:
|
|
13
23
|
"""
|
{libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/document/dispatcher.py
RENAMED
|
@@ -17,34 +17,53 @@ class DocumentDispatcherService:
|
|
|
17
17
|
"""Arma y valida el sobre `EnvioDTE` (`billing.document.dispatcher`)."""
|
|
18
18
|
|
|
19
19
|
_CREATE_OPERATION = 'billing.document.dispatcher::create'
|
|
20
|
-
_CREATE_MANY_OPERATION = 'billing.document.dispatcher::
|
|
21
|
-
_LOAD_XML_OPERATION = 'billing.document.dispatcher::
|
|
20
|
+
_CREATE_MANY_OPERATION = 'billing.document.dispatcher::create_many'
|
|
21
|
+
_LOAD_XML_OPERATION = 'billing.document.dispatcher::load_xml'
|
|
22
22
|
_VALIDATE_OPERATION = 'billing.document.dispatcher::validate'
|
|
23
|
-
_VALIDATE_SCHEMA_OPERATION = 'billing.document.dispatcher::
|
|
23
|
+
_VALIDATE_SCHEMA_OPERATION = 'billing.document.dispatcher::validate_schema'
|
|
24
24
|
_VALIDATE_SIGNATURE_OPERATION = (
|
|
25
|
-
'billing.document.dispatcher::
|
|
25
|
+
'billing.document.dispatcher::validate_signature'
|
|
26
26
|
)
|
|
27
27
|
|
|
28
28
|
def __init__(self, client: ApiClient) -> None:
|
|
29
29
|
"""Guarda el `ApiClient` compartido usado para llamar a la API."""
|
|
30
30
|
self._client = client
|
|
31
31
|
|
|
32
|
-
def create(
|
|
32
|
+
def create(
|
|
33
|
+
self,
|
|
34
|
+
bag: DocumentBag,
|
|
35
|
+
*,
|
|
36
|
+
receptor_rut: str | None = None,
|
|
37
|
+
) -> DocumentEnvelope:
|
|
33
38
|
"""
|
|
34
|
-
Envuelve y firma un documento ya timbrado en un sobre
|
|
39
|
+
Envuelve y firma un documento ya timbrado en un sobre.
|
|
35
40
|
|
|
36
41
|
`bag` es el `DocumentBag` ya timbrado y firmado que devuelve
|
|
37
42
|
`DocumentBuilderService.build_signed()` — trae `certificate`/
|
|
38
43
|
`emisor` incluidos, no hace falta pasarlos aparte. El sobre
|
|
39
44
|
resultante es lo que se envía al SII (`SiiDteService.send`).
|
|
45
|
+
|
|
46
|
+
`receptor_rut` es el RUT del receptor de la carátula del sobre.
|
|
47
|
+
Sin indicarlo es el receptor del documento, que es el sobre para
|
|
48
|
+
enviar al cliente. El sobre que va al SII se arma con
|
|
49
|
+
`receptor_rut=SII_RUT` (`60803000-K`): el SII lo exige y rechaza
|
|
50
|
+
el envío con otro receptor. El envío normal usa dos sobres, uno
|
|
51
|
+
para el SII y otro para el cliente. Para enviar el sobre al SII
|
|
52
|
+
el emisor debe traer `autorizacion_dte`, con `fecha_resolucion` y
|
|
53
|
+
`numero_resolucion` de su autorización.
|
|
40
54
|
"""
|
|
41
55
|
response = self._client.call_response(
|
|
42
56
|
self._CREATE_OPERATION,
|
|
43
|
-
bag=self._bag_payload(bag),
|
|
57
|
+
bag=self._bag_payload(bag, receptor_rut),
|
|
44
58
|
)
|
|
45
59
|
return build_response(DocumentEnvelope, response)
|
|
46
60
|
|
|
47
|
-
def create_many(
|
|
61
|
+
def create_many(
|
|
62
|
+
self,
|
|
63
|
+
bags: Sequence[DocumentBag],
|
|
64
|
+
*,
|
|
65
|
+
receptor_rut: str | None = None,
|
|
66
|
+
) -> DocumentEnvelope:
|
|
48
67
|
"""
|
|
49
68
|
Envuelve y firma 2+ documentos ya timbrados en un sobre `EnvioDTE`.
|
|
50
69
|
|
|
@@ -53,15 +72,24 @@ class DocumentDispatcherService:
|
|
|
53
72
|
`emisor`. El sobre resultante queda firmado con el certificado
|
|
54
73
|
del PRIMER `DocumentBag` (el sobre en sí también se firma, no
|
|
55
74
|
solo cada documento).
|
|
75
|
+
|
|
76
|
+
`receptor_rut` funciona igual que en `create()`: es el receptor
|
|
77
|
+
de la carátula del sobre, y para el SII debe ser `SII_RUT`.
|
|
56
78
|
"""
|
|
57
79
|
response = self._client.call_response(
|
|
58
80
|
self._CREATE_MANY_OPERATION,
|
|
59
|
-
bags=[
|
|
81
|
+
bags=[
|
|
82
|
+
self._bag_payload(bag, receptor_rut if index == 0 else None)
|
|
83
|
+
for index, bag in enumerate(bags)
|
|
84
|
+
],
|
|
60
85
|
)
|
|
61
86
|
return build_response(DocumentEnvelope, response)
|
|
62
87
|
|
|
63
88
|
@staticmethod
|
|
64
|
-
def _bag_payload(
|
|
89
|
+
def _bag_payload(
|
|
90
|
+
bag: DocumentBag,
|
|
91
|
+
receptor_rut: str | None = None,
|
|
92
|
+
) -> dict[str, Any]:
|
|
65
93
|
if bag.certificate is None:
|
|
66
94
|
raise ValueError(
|
|
67
95
|
'Este DocumentBag no tiene certificado — ¿se firmó con '
|
|
@@ -73,11 +101,15 @@ class DocumentDispatcherService:
|
|
|
73
101
|
'`builder.build_draft/build_signed()` o se cargó con '
|
|
74
102
|
'`loader.load_xml()`?',
|
|
75
103
|
)
|
|
76
|
-
|
|
104
|
+
payload: dict[str, Any] = {
|
|
77
105
|
'xmlDocument': bag.xml_base64,
|
|
78
106
|
'certificate': bag.certificate.to_payload(),
|
|
79
107
|
'emisor': bag.emisor,
|
|
80
108
|
}
|
|
109
|
+
if receptor_rut is not None:
|
|
110
|
+
payload['receptor'] = {'rut': receptor_rut}
|
|
111
|
+
|
|
112
|
+
return payload
|
|
81
113
|
|
|
82
114
|
def load_xml(self, xml_base64: str) -> DocumentEnvelope:
|
|
83
115
|
"""
|
|
@@ -121,7 +153,9 @@ class DocumentDispatcherService:
|
|
|
121
153
|
|
|
122
154
|
Un sobre trae más de una firma (la del DTE y la del propio
|
|
123
155
|
`EnvioDTE`) — devuelve una lista, un ítem por firma. Cada ítem
|
|
124
|
-
es
|
|
156
|
+
es `{'valid': bool, 'error': str | None, 'signature': {...}}`,
|
|
157
|
+
igual que en `DocumentValidatorService.validate_signature()`: una
|
|
158
|
+
firma inválida no levanta error, hay que revisar `valid`.
|
|
125
159
|
"""
|
|
126
160
|
return cast(
|
|
127
161
|
'list[dict[str, Any]]',
|
{libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/document/loader.py
RENAMED
|
@@ -14,13 +14,13 @@ class DocumentLoaderService:
|
|
|
14
14
|
"""
|
|
15
15
|
Carga un documento tributario completo desde su XML.
|
|
16
16
|
|
|
17
|
-
Solo cubre `
|
|
17
|
+
Solo cubre `load_xml` — pensado para reconstruir los datos
|
|
18
18
|
normalizados de un DTE ya emitido (timbrado y firmado) a partir de
|
|
19
19
|
su XML, ej. un documento recibido de un tercero o recuperado de un
|
|
20
20
|
respaldo.
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
|
-
_LOAD_XML_OPERATION = 'billing.document.loader::
|
|
23
|
+
_LOAD_XML_OPERATION = 'billing.document.loader::load_xml'
|
|
24
24
|
|
|
25
25
|
def __init__(self, client: ApiClient) -> None:
|
|
26
26
|
"""Guarda el `ApiClient` compartido usado para llamar a la API."""
|
{libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/document/models.py
RENAMED
|
@@ -31,15 +31,15 @@ class DocumentBag:
|
|
|
31
31
|
"""
|
|
32
32
|
Bolsa de un documento tributario.
|
|
33
33
|
|
|
34
|
-
Devuelta por `document.builder::build`/`document.loader::
|
|
34
|
+
Devuelta por `document.builder::build`/`document.loader::load_xml`/
|
|
35
35
|
`document.parser::parse` — todas en esta misma forma, con los campos
|
|
36
36
|
que correspondan a cuánto se hizo con el documento. `document`
|
|
37
37
|
(`Encabezado`/`Detalle`, con el merge de `libredte_data.extra.dte`
|
|
38
38
|
si se pasó al renderizar) es la vista "de datos" limpia del
|
|
39
39
|
documento — SIN los campos opcionales no usados (se omiten, no
|
|
40
|
-
quedan en `
|
|
40
|
+
quedan en `None`). `document_normalized` es la data cruda tal como
|
|
41
41
|
la usa el builder internamente para generar el XML (con esos
|
|
42
|
-
campos opcionales en `
|
|
42
|
+
campos opcionales en `None` en vez de omitidos): es la que hay que
|
|
43
43
|
guardar para poder reconstruir el documento después con
|
|
44
44
|
`options={'normalizer': {'normalize': False}}` sin volver a
|
|
45
45
|
normalizar — usar `document` para eso corrompe la reconstrucción.
|
|
@@ -48,8 +48,8 @@ class DocumentBag:
|
|
|
48
48
|
puede ser un borrador, un documento timbrado, o timbrado y firmado,
|
|
49
49
|
no una subclase distinta: es el mismo recurso en distintos estados
|
|
50
50
|
según qué datos se le hayan pasado a `DocumentBuilderService`. Un
|
|
51
|
-
borrador sin folio asignado tiene folio `0` en `document_id`
|
|
52
|
-
|
|
51
|
+
borrador sin folio asignado tiene folio `0` en `document_id`
|
|
52
|
+
(criterio de la biblioteca), nunca lanza error.
|
|
53
53
|
|
|
54
54
|
`document_stamp_base64` es el TED — `None` si el documento aún no
|
|
55
55
|
está timbrado (ver `is_timbrado`). `document_extra` son los campos
|
|
@@ -64,7 +64,7 @@ class DocumentBag:
|
|
|
64
64
|
ninguna al construir/cargar el documento.
|
|
65
65
|
|
|
66
66
|
`certificate`/`caf` son `None` salvo que el documento se haya
|
|
67
|
-
construido con ellos (`build_signed`, o un `
|
|
67
|
+
construido con ellos (`build_signed`, o un `load_xml` de un XML ya
|
|
68
68
|
firmado/timbrado) — un borrador (`build_draft`) no los trae.
|
|
69
69
|
`emisor`/`receptor` sí están siempre que haya un documento
|
|
70
70
|
construido (`Encabezado.Emisor`/`Encabezado.Receptor` ya
|
|
@@ -209,8 +209,8 @@ class DocumentEnvelope(XmlPayloadMixin):
|
|
|
209
209
|
|
|
210
210
|
`documents` trae una bolsa (`DocumentBag`) por cada documento
|
|
211
211
|
tributario que el sobre contiene — uno solo si se armó con
|
|
212
|
-
`create()`, uno o más si se armó con `
|
|
213
|
-
con `
|
|
212
|
+
`create()`, uno o más si se armó con `create_many()` o si se cargó
|
|
213
|
+
con `load_xml()` un sobre que agrupaba varios documentos. `caratula`
|
|
214
214
|
es el `dict` con los datos de la carátula del sobre (`RutEmisor`,
|
|
215
215
|
`RutEnvia`, `RutReceptor`, `FchResol`, `NroResol`, `TmstFirmaEnv`,
|
|
216
216
|
`SubTotDTE`).
|
|
@@ -249,9 +249,8 @@ class RenderedDocument:
|
|
|
249
249
|
liquidación de sueldo, que siempre es un único archivo).
|
|
250
250
|
`copies`/`copy_number` identifican esta copia entre las pedidas de
|
|
251
251
|
ese mismo `label` (ej. `copies=2, copy_number=1` es la primera de
|
|
252
|
-
2 copias tributarias).
|
|
253
|
-
|
|
254
|
-
quedan en snake_case como el resto del SDK.
|
|
252
|
+
2 copias tributarias). La API entrega los campos como
|
|
253
|
+
`content`/`mime_type`/`filename`/`copy_number`.
|
|
255
254
|
"""
|
|
256
255
|
|
|
257
256
|
content_base64: str
|
|
@@ -271,11 +270,11 @@ class RenderedDocument:
|
|
|
271
270
|
"""Construye desde un ítem de `data.renderings`."""
|
|
272
271
|
return cls(
|
|
273
272
|
content_base64=data['content'],
|
|
274
|
-
mime_type=data['
|
|
273
|
+
mime_type=data['mime_type'],
|
|
275
274
|
filename=data['filename'],
|
|
276
275
|
label=data.get('label'),
|
|
277
276
|
copies=data['copies'],
|
|
278
|
-
copy_number=data['
|
|
277
|
+
copy_number=data['copy_number'],
|
|
279
278
|
)
|
|
280
279
|
|
|
281
280
|
|
{libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/document/validator.py
RENAMED
|
@@ -20,9 +20,9 @@ class DocumentValidatorService:
|
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
22
|
_VALIDATE_OPERATION = 'billing.document.validator::validate'
|
|
23
|
-
_VALIDATE_SCHEMA_OPERATION = 'billing.document.validator::
|
|
23
|
+
_VALIDATE_SCHEMA_OPERATION = 'billing.document.validator::validate_schema'
|
|
24
24
|
_VALIDATE_SIGNATURE_OPERATION = (
|
|
25
|
-
'billing.document.validator::
|
|
25
|
+
'billing.document.validator::validate_signature'
|
|
26
26
|
)
|
|
27
27
|
|
|
28
28
|
def __init__(self, client: ApiClient) -> None:
|
|
@@ -58,8 +58,13 @@ class DocumentValidatorService:
|
|
|
58
58
|
"""
|
|
59
59
|
Valida la firma electrónica del documento.
|
|
60
60
|
|
|
61
|
-
Devuelve
|
|
62
|
-
|
|
61
|
+
Devuelve `{'valid': bool, 'error': str | None, 'signature': {...}}`.
|
|
62
|
+
La API responde con éxito tanto si la firma es válida como si no
|
|
63
|
+
lo es: el resultado está en `valid`, y `error` explica el motivo
|
|
64
|
+
cuando es `False` (por ejemplo, que el contenido se modificó
|
|
65
|
+
después de firmarlo). `signature` trae los datos de la firma
|
|
66
|
+
(`reference`, `signature_method`, `digest_method`, el certificado
|
|
67
|
+
y `signer`, con los datos del certificado del firmante).
|
|
63
68
|
"""
|
|
64
69
|
return cast(
|
|
65
70
|
'dict[str, Any]',
|
|
@@ -23,16 +23,16 @@ class DocumentResponseService:
|
|
|
23
23
|
"""
|
|
24
24
|
|
|
25
25
|
_BUILD_ENVIO_RECIBOS_OPERATION = (
|
|
26
|
-
'billing.exchange.document_response::
|
|
26
|
+
'billing.exchange.document_response::build_envio_recibos'
|
|
27
27
|
)
|
|
28
28
|
_BUILD_RESPUESTA_ENVIO_OPERATION = (
|
|
29
|
-
'billing.exchange.document_response::
|
|
29
|
+
'billing.exchange.document_response::build_respuesta_envio'
|
|
30
30
|
)
|
|
31
31
|
_VALIDATE_SCHEMA_OPERATION = (
|
|
32
|
-
'billing.exchange.document_response::
|
|
32
|
+
'billing.exchange.document_response::validate_schema'
|
|
33
33
|
)
|
|
34
34
|
_VALIDATE_SIGNATURE_OPERATION = (
|
|
35
|
-
'billing.exchange.document_response::
|
|
35
|
+
'billing.exchange.document_response::validate_signature'
|
|
36
36
|
)
|
|
37
37
|
|
|
38
38
|
def __init__(self, client: ApiClient) -> None:
|
|
@@ -111,7 +111,9 @@ class DocumentResponseService:
|
|
|
111
111
|
`EnvioRecibos` trae múltiples firmas (una por recibo, más la
|
|
112
112
|
del `SetRecibos`); `RespuestaDTE` trae solo la del nodo
|
|
113
113
|
`Resultado`. En ambos casos se devuelve una lista, un ítem por
|
|
114
|
-
firma
|
|
114
|
+
firma, cada uno con `{'valid': bool, 'error': str | None,
|
|
115
|
+
'signature': {...}}`. Una firma inválida no levanta error, hay
|
|
116
|
+
que revisar `valid`.
|
|
115
117
|
"""
|
|
116
118
|
return cast(
|
|
117
119
|
'list[dict[str, Any]]',
|
{libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/exchange/models.py
RENAMED
|
@@ -18,7 +18,7 @@ from ..common import XmlPayloadMixin
|
|
|
18
18
|
@dataclass(frozen=True, slots=True)
|
|
19
19
|
class EnvioRecibos(XmlPayloadMixin):
|
|
20
20
|
"""
|
|
21
|
-
XML `EnvioRecibos` construido (`document_response::
|
|
21
|
+
XML `EnvioRecibos` construido (`document_response::build_envio_recibos`).
|
|
22
22
|
|
|
23
23
|
Recibo de mercaderías o servicios prestados por un proveedor.
|
|
24
24
|
`datos` es la estructura ya parseada, `xml_base64` el XML completo
|
|
@@ -43,7 +43,7 @@ class EnvioRecibos(XmlPayloadMixin):
|
|
|
43
43
|
@dataclass(frozen=True, slots=True)
|
|
44
44
|
class RespuestaEnvio(XmlPayloadMixin):
|
|
45
45
|
"""
|
|
46
|
-
XML `RespuestaDTE` construido (`document_response::
|
|
46
|
+
XML `RespuestaDTE` construido (`document_response::build_respuesta_envio`).
|
|
47
47
|
|
|
48
48
|
Acuse de recibo del envío (`RecepcionEnvio`) o resultado de
|
|
49
49
|
validación por documento (`ResultadoDTE`), según los datos
|
{libredte_lib_sdk-0.6.1 → libredte_lib_sdk-0.7.0}/libredte_lib_sdk/billing/identifier/models.py
RENAMED
|
@@ -62,13 +62,13 @@ class Caf(XmlPayloadMixin):
|
|
|
62
62
|
return cls(
|
|
63
63
|
id=data['id'],
|
|
64
64
|
emisor=data['emisor'],
|
|
65
|
-
tipo_documento=data['
|
|
66
|
-
folio_desde=data['
|
|
67
|
-
folio_hasta=data['
|
|
68
|
-
cantidad_folios=data['
|
|
69
|
-
fecha_autorizacion=data['
|
|
70
|
-
fecha_vencimiento=data.get('
|
|
71
|
-
meses_autorizacion=data['
|
|
65
|
+
tipo_documento=data['tipo_documento'],
|
|
66
|
+
folio_desde=data['folio_desde'],
|
|
67
|
+
folio_hasta=data['folio_hasta'],
|
|
68
|
+
cantidad_folios=data['cantidad_folios'],
|
|
69
|
+
fecha_autorizacion=data['fecha_autorizacion'],
|
|
70
|
+
fecha_vencimiento=data.get('fecha_vencimiento'),
|
|
71
|
+
meses_autorizacion=data['meses_autorizacion'],
|
|
72
72
|
vigente=data['vigente'],
|
|
73
73
|
vence=data['vence'],
|
|
74
74
|
idk=data['idk'],
|
|
@@ -76,12 +76,12 @@ class Caf(XmlPayloadMixin):
|
|
|
76
76
|
if ambiente is not None
|
|
77
77
|
else None,
|
|
78
78
|
# Mismo valor que `ambiente`, ya resuelto a `int` — la API lo
|
|
79
|
-
# entrega redundante así (
|
|
80
|
-
#
|
|
81
|
-
#
|
|
79
|
+
# entrega redundante así (en libredte-lib-core es literalmente
|
|
80
|
+
# el valor de `ambiente`), se mantiene igual acá para no diverger
|
|
81
|
+
# del shape real.
|
|
82
82
|
certificacion=data.get('certificacion'),
|
|
83
|
-
public_key=data['
|
|
84
|
-
private_key=data['
|
|
83
|
+
public_key=data['public_key'],
|
|
84
|
+
private_key=data['private_key'],
|
|
85
85
|
xml_base64=data['xml'],
|
|
86
86
|
raw=data,
|
|
87
87
|
)
|