libredte-lib-sdk 0.5.2__tar.gz → 0.5.3__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.
Files changed (87) hide show
  1. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/PKG-INFO +15 -3
  2. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/README.rst +14 -2
  3. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/client.py +13 -1
  4. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/sdk.py +7 -0
  5. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/pyproject.toml +1 -1
  6. libredte_lib_sdk-0.5.3/tests/fixtures/certificate_112223339.p12 +0 -0
  7. libredte_lib_sdk-0.5.3/tests/integration/test_certificate_loader.py +55 -0
  8. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/tests/integration/test_operation_not_found.py +8 -4
  9. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/tests/test_client.py +15 -0
  10. libredte_lib_sdk-0.5.2/.claude/scheduled_tasks.lock +0 -1
  11. libredte_lib_sdk-0.5.2/tests/integration/test_certificate_loader.py +0 -74
  12. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/.github/workflows/ci.yml +0 -0
  13. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/.github/workflows/docs.yml +0 -0
  14. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/.gitignore +0 -0
  15. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/.readthedocs.yaml +0 -0
  16. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/CLAUDE.md +0 -0
  17. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/LICENSE +0 -0
  18. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/Makefile +0 -0
  19. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/docs/Makefile +0 -0
  20. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/docs/conf.py +0 -0
  21. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/docs/index.rst +0 -0
  22. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/__init__.py +0 -0
  23. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/__init__.py +0 -0
  24. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/book/__init__.py +0 -0
  25. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/book/builder.py +0 -0
  26. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/book/loader.py +0 -0
  27. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/book/models.py +0 -0
  28. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/book/validator.py +0 -0
  29. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/common.py +0 -0
  30. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/document/__init__.py +0 -0
  31. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/document/builder.py +0 -0
  32. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/document/dispatcher.py +0 -0
  33. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/document/examples.py +0 -0
  34. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/document/loader.py +0 -0
  35. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/document/models.py +0 -0
  36. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/document/renderer.py +0 -0
  37. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/document/validator.py +0 -0
  38. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/enums.py +0 -0
  39. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/exchange/__init__.py +0 -0
  40. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/exchange/document_response.py +0 -0
  41. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/exchange/models.py +0 -0
  42. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/identifier/__init__.py +0 -0
  43. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/identifier/caf_faker.py +0 -0
  44. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/identifier/caf_loader.py +0 -0
  45. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/identifier/caf_validator.py +0 -0
  46. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/identifier/models.py +0 -0
  47. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/integration/__init__.py +0 -0
  48. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/integration/models.py +0 -0
  49. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/integration/sii_dte.py +0 -0
  50. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/integration/sii_rcv.py +0 -0
  51. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/integration/sii_rtc.py +0 -0
  52. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/ownership_transfer/__init__.py +0 -0
  53. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/ownership_transfer/aec.py +0 -0
  54. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/ownership_transfer/models.py +0 -0
  55. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/trading_parties/__init__.py +0 -0
  56. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/trading_parties/mandatario_manager.py +0 -0
  57. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/billing/trading_parties/models.py +0 -0
  58. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/exceptions.py +0 -0
  59. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/human_resources/__init__.py +0 -0
  60. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/human_resources/integration/__init__.py +0 -0
  61. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/human_resources/integration/previred_provider.py +0 -0
  62. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/human_resources/payroll/__init__.py +0 -0
  63. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/human_resources/payroll/calculator.py +0 -0
  64. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/human_resources/payroll/renderer.py +0 -0
  65. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/py.typed +0 -0
  66. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/system/__init__.py +0 -0
  67. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/system/certificate/__init__.py +0 -0
  68. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/system/certificate/loader.py +0 -0
  69. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/system/repository/__init__.py +0 -0
  70. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/libredte_lib_sdk/system/repository/catalog.py +0 -0
  71. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/tests/__init__.py +0 -0
  72. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/tests/conftest.py +0 -0
  73. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/tests/integration/__init__.py +0 -0
  74. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/tests/integration/conftest.py +0 -0
  75. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/tests/integration/test_book.py +0 -0
  76. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/tests/integration/test_caf.py +0 -0
  77. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/tests/integration/test_document_loader.py +0 -0
  78. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/tests/integration/test_document_rendering.py +0 -0
  79. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/tests/integration/test_document_validation.py +0 -0
  80. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/tests/integration/test_examples.py +0 -0
  81. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/tests/integration/test_exchange.py +0 -0
  82. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/tests/integration/test_human_resources.py +0 -0
  83. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/tests/integration/test_ownership_transfer.py +0 -0
  84. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/tests/integration/test_repository.py +0 -0
  85. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/tests/test_exceptions.py +0 -0
  86. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/tests/test_models.py +0 -0
  87. {libredte_lib_sdk-0.5.2 → libredte_lib_sdk-0.5.3}/tests/test_services.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: libredte-lib-sdk
3
- Version: 0.5.2
3
+ Version: 0.5.3
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
@@ -187,14 +187,26 @@ entorno ``LIBREDTE_LIB_SDK_BASE_URL``:
187
187
  ``core.libredte.cl`` y ``pro.libredte.cl`` exponen el mismo contrato con
188
188
  límites de solicitudes distintos; ambos aceptan la variante ``LibreDTE
189
189
  (base_url=..., ...)`` con el resto de los parámetros de configuración
190
- (``api_token``, ``timeout``, ``http_client``).
190
+ (``api_token``, ``auth_scheme``, ``timeout``, ``http_client``).
191
191
 
192
192
  Autenticación
193
193
  ~~~~~~~~~~~~~
194
194
 
195
195
  ``LibreDTE(api_token=...)`` o la variable de entorno
196
196
  ``LIBREDTE_LIB_SDK_TOKEN`` — si está presente, se manda como header
197
- ``Authorization: Bearer <token>``.
197
+ ``Authorization: <esquema> <token>``. El esquema es ``Bearer`` por
198
+ defecto (lo que espera ``core.libredte.cl``/``pro.libredte.cl``);
199
+ configurable con ``LibreDTE(auth_scheme=...)`` o la variable de entorno
200
+ ``LIBREDTE_LIB_SDK_AUTH_SCHEME`` para hablar con otra API que use un
201
+ esquema distinto (ej. ``'Token'``):
202
+
203
+ .. code-block:: python
204
+
205
+ sdk = LibreDTE(
206
+ base_url='https://app.apigateway.cl/api/v2/libredte',
207
+ api_token='...',
208
+ auth_scheme='Token',
209
+ )
198
210
 
199
211
  Recursos de ``system``
200
212
  -----------------------
@@ -143,14 +143,26 @@ entorno ``LIBREDTE_LIB_SDK_BASE_URL``:
143
143
  ``core.libredte.cl`` y ``pro.libredte.cl`` exponen el mismo contrato con
144
144
  límites de solicitudes distintos; ambos aceptan la variante ``LibreDTE
145
145
  (base_url=..., ...)`` con el resto de los parámetros de configuración
146
- (``api_token``, ``timeout``, ``http_client``).
146
+ (``api_token``, ``auth_scheme``, ``timeout``, ``http_client``).
147
147
 
148
148
  Autenticación
149
149
  ~~~~~~~~~~~~~
150
150
 
151
151
  ``LibreDTE(api_token=...)`` o la variable de entorno
152
152
  ``LIBREDTE_LIB_SDK_TOKEN`` — si está presente, se manda como header
153
- ``Authorization: Bearer <token>``.
153
+ ``Authorization: <esquema> <token>``. El esquema es ``Bearer`` por
154
+ defecto (lo que espera ``core.libredte.cl``/``pro.libredte.cl``);
155
+ configurable con ``LibreDTE(auth_scheme=...)`` o la variable de entorno
156
+ ``LIBREDTE_LIB_SDK_AUTH_SCHEME`` para hablar con otra API que use un
157
+ esquema distinto (ej. ``'Token'``):
158
+
159
+ .. code-block:: python
160
+
161
+ sdk = LibreDTE(
162
+ base_url='https://app.apigateway.cl/api/v2/libredte',
163
+ api_token='...',
164
+ auth_scheme='Token',
165
+ )
154
166
 
155
167
  Recursos de ``system``
156
168
  -----------------------
@@ -18,6 +18,7 @@ from .exceptions import (
18
18
  )
19
19
 
20
20
  DEFAULT_BASE_URL = 'https://core.libredte.cl/api'
21
+ DEFAULT_AUTH_SCHEME = 'Bearer'
21
22
  DEFAULT_TIMEOUT = 30.0
22
23
  _HTTP_TOO_MANY_REQUESTS = 429
23
24
  _OPERATION_NOT_FOUND_PHP_CLASS = (
@@ -50,6 +51,7 @@ class ApiClient:
50
51
  base_url: str | None = None,
51
52
  *,
52
53
  api_token: str | None = None,
54
+ auth_scheme: str | None = None,
53
55
  timeout: float = DEFAULT_TIMEOUT,
54
56
  http_client: httpx.Client | None = None,
55
57
  ) -> None:
@@ -62,9 +64,19 @@ class ApiClient:
62
64
  self._api_token = api_token or os.environ.get(
63
65
  'LIBREDTE_LIB_SDK_TOKEN',
64
66
  )
67
+ self._auth_scheme = (
68
+ auth_scheme
69
+ or os.environ.get('LIBREDTE_LIB_SDK_AUTH_SCHEME')
70
+ or DEFAULT_AUTH_SCHEME
71
+ )
65
72
  self._client = http_client or httpx.Client(timeout=timeout)
66
73
  self._owns_client = http_client is None
67
74
 
75
+ @property
76
+ def base_url(self) -> str:
77
+ """URL base configurada (`core.libredte.cl`, `pro.libredte.cl`)."""
78
+ return self._base_url
79
+
68
80
  def close(self) -> None:
69
81
  """Cierra la conexión HTTP, si este cliente es dueño de ella."""
70
82
  if self._owns_client:
@@ -105,7 +117,7 @@ class ApiClient:
105
117
  def _headers(self) -> dict[str, str]:
106
118
  headers = {'Accept': 'application/json'}
107
119
  if self._api_token:
108
- headers['Authorization'] = f'Bearer {self._api_token}'
120
+ headers['Authorization'] = f'{self._auth_scheme} {self._api_token}'
109
121
  return headers
110
122
 
111
123
  @staticmethod
@@ -60,6 +60,7 @@ class LibreDTE:
60
60
  base_url: str | None = None,
61
61
  *,
62
62
  api_token: str | None = None,
63
+ auth_scheme: str | None = None,
63
64
  timeout: float = DEFAULT_TIMEOUT,
64
65
  http_client: httpx.Client | None = None,
65
66
  ) -> None:
@@ -67,6 +68,7 @@ class LibreDTE:
67
68
  self._client = ApiClient(
68
69
  base_url,
69
70
  api_token=api_token,
71
+ auth_scheme=auth_scheme,
70
72
  timeout=timeout,
71
73
  http_client=http_client,
72
74
  )
@@ -74,6 +76,11 @@ class LibreDTE:
74
76
  self.system = SystemPackage(self._client)
75
77
  self.human_resources = HumanResourcesPackage(self._client)
76
78
 
79
+ @property
80
+ def base_url(self) -> str:
81
+ """URL base configurada del `ApiClient` compartido."""
82
+ return self._client.base_url
83
+
77
84
  def close(self) -> None:
78
85
  """Cierra la conexión HTTP subyacente."""
79
86
  self._client.close()
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "libredte-lib-sdk"
7
- version = "0.5.2"
7
+ version = "0.5.3"
8
8
  description = "SDK Python para la API de LibreDTE Lib (facturacion electronica de Chile)."
9
9
  readme = "README.rst"
10
10
  license = { file = "LICENSE" }
@@ -0,0 +1,55 @@
1
+ # Copyright (C) 2026 LibreDTE <https://www.libredte.cl>
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ """
5
+ Tests en vivo para `CertificateLoaderService` (`system.certificate.loader`).
6
+
7
+ Usa un `.p12` fijo (`tests/fixtures/certificate_112223339.p12`,
8
+ contraseña `i_love_libredte`) en vez de generar uno en cada corrida —
9
+ así el test no necesita ninguna librería de certificados: solo lee los
10
+ bytes del archivo y se los pasa tal cual a la API, igual que subiría el
11
+ archivo una persona real.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from pathlib import Path
17
+
18
+ import pytest
19
+
20
+ pytestmark = pytest.mark.live
21
+
22
+ _FIXTURE_PATH = (
23
+ Path(__file__).parent.parent / 'fixtures' / 'certificate_112223339.p12'
24
+ )
25
+ _PASSWORD = 'i_love_libredte'
26
+
27
+
28
+ @pytest.fixture
29
+ def fake_pkcs12() -> bytes:
30
+ """Bytes crudos del `.p12` de prueba."""
31
+ return _FIXTURE_PATH.read_bytes()
32
+
33
+
34
+ def test_load_extracts_the_holder_and_a_usable_certificate(
35
+ fake_pkcs12: bytes,
36
+ real_sdk,
37
+ ):
38
+ loaded = real_sdk.system.certificate.loader.load(fake_pkcs12, _PASSWORD)
39
+
40
+ assert loaded.id == '11222333-9'
41
+ assert loaded.name == 'Usuario de LibreDTE'
42
+ assert loaded.email == 'correo@example.com'
43
+ assert loaded.is_active is True
44
+ assert loaded.certificate.startswith('-----BEGIN CERTIFICATE-----')
45
+
46
+
47
+ def test_create_from_certificate_matches_load(fake_pkcs12: bytes, real_sdk):
48
+ loaded = real_sdk.system.certificate.loader.load(fake_pkcs12, _PASSWORD)
49
+
50
+ mandatario_manager = real_sdk.billing.trading_parties.mandatario_manager
51
+ mandatario = mandatario_manager.create_from_certificate(loaded)
52
+
53
+ assert mandatario.run == loaded.id
54
+ assert mandatario.nombre == loaded.name
55
+ assert mandatario.email == loaded.email
@@ -4,16 +4,17 @@
4
4
  """
5
5
  Test en vivo para `LibreDteOperationNotFoundError`.
6
6
 
7
- Corre contra el ambiente por defecto (Lib Core, ver `real_sdk` en
8
- `conftest.py`) a propósito: `human_resources.*` no existe ahí — es
9
- justo el caso real que motivó la excepción, y no necesita apuntar a
10
- Lib Pro para confirmarlo.
7
+ Pensado para Lib Core: `human_resources.*` no existe ahí — es justo el
8
+ caso real que motivó la excepción. Se salta a sí mismo si `real_sdk`
9
+ apunta a otro ambiente (ej. Lib Pro, vía `LIBREDTE_LIB_SDK_BASE_URL`),
10
+ donde `human_resources.*` sí existe y no aplica.
11
11
  """
12
12
 
13
13
  from __future__ import annotations
14
14
 
15
15
  import pytest
16
16
 
17
+ from libredte_lib_sdk.client import DEFAULT_BASE_URL
17
18
  from libredte_lib_sdk.exceptions import LibreDteOperationNotFoundError
18
19
 
19
20
  pytestmark = pytest.mark.live
@@ -22,6 +23,9 @@ pytestmark = pytest.mark.live
22
23
  def test_human_resources_operation_raises_operation_not_found_on_core(
23
24
  real_sdk,
24
25
  ):
26
+ if real_sdk.base_url != DEFAULT_BASE_URL:
27
+ pytest.skip('human_resources.* no existe solo en Lib Core.')
28
+
25
29
  with pytest.raises(LibreDteOperationNotFoundError) as exc_info:
26
30
  real_sdk.human_resources.integration.previred_provider.get_indicadores(
27
31
  202412,
@@ -39,6 +39,21 @@ def test_api_token_falls_back_to_the_env_var(monkeypatch):
39
39
  assert client._headers()['Authorization'] == 'Bearer secret-token'
40
40
 
41
41
 
42
+ def test_auth_scheme_param_overrides_the_default():
43
+ client = ApiClient(api_token='secret-token', auth_scheme='Token')
44
+
45
+ assert client._headers()['Authorization'] == 'Token secret-token'
46
+
47
+
48
+ def test_auth_scheme_falls_back_to_the_env_var(monkeypatch):
49
+ monkeypatch.setenv('LIBREDTE_LIB_SDK_TOKEN', 'secret-token')
50
+ monkeypatch.setenv('LIBREDTE_LIB_SDK_AUTH_SCHEME', 'Token')
51
+
52
+ client = ApiClient()
53
+
54
+ assert client._headers()['Authorization'] == 'Token secret-token'
55
+
56
+
42
57
  def test_operation_path_translates_dotted_operation_to_a_rest_path():
43
58
  path = ApiClient._operation_path('billing.document.builder::build')
44
59
 
@@ -1 +0,0 @@
1
- {"sessionId":"64edfb1a-a3db-44cc-af25-6c7405269fdf","pid":73057,"procStart":"Mon Sep 7 03:13:55 2026","acquiredAt":1789224889985}
@@ -1,74 +0,0 @@
1
- # Copyright (C) 2026 LibreDTE <https://www.libredte.cl>
2
- # SPDX-License-Identifier: MIT
3
-
4
- """
5
- Tests en vivo para `CertificateLoaderService` (`system.certificate.loader`).
6
-
7
- Arma un PKCS12 en memoria (mismo enfoque que `tests/test_utils.py`, sin
8
- depender de un archivo `.p12` real) a partir de un certificado ficticio
9
- ya generado por `create_fake_certificate` — así el certificado sí trae
10
- RUT/nombre/correo real (el fake de `create_fake_certificate` los
11
- codifica), que es lo que `system.certificate.loader::load` debe poder
12
- extraer.
13
- """
14
-
15
- from __future__ import annotations
16
-
17
- import pytest
18
- from cryptography import x509
19
- from cryptography.hazmat.primitives import serialization
20
- from cryptography.hazmat.primitives.serialization import pkcs12
21
-
22
- from libredte_lib_sdk.billing.trading_parties import Mandatario
23
-
24
- pytestmark = pytest.mark.live
25
-
26
- _MANDATARIO = Mandatario(
27
- run='76192083-9',
28
- nombre='SASCO SpA',
29
- email='demo@sasco.example',
30
- )
31
- _PASSWORD = 'clave1234'
32
-
33
-
34
- @pytest.fixture
35
- def fake_pkcs12(real_sdk):
36
- """Un `.p12` en memoria, con RUT/nombre/correo reales embebidos."""
37
- mandatario_manager = real_sdk.billing.trading_parties.mandatario_manager
38
- certificate = mandatario_manager.create_fake_certificate(_MANDATARIO)
39
- key = serialization.load_pem_private_key(
40
- certificate.private_key.encode(),
41
- password=None,
42
- )
43
- cert = x509.load_pem_x509_certificate(certificate.certificate.encode())
44
- return pkcs12.serialize_key_and_certificates(
45
- b'demo',
46
- key,
47
- cert,
48
- None,
49
- serialization.BestAvailableEncryption(_PASSWORD.encode()),
50
- )
51
-
52
-
53
- def test_load_extracts_the_mandatario_and_a_usable_certificate(
54
- fake_pkcs12,
55
- real_sdk,
56
- ):
57
- loaded = real_sdk.system.certificate.loader.load(fake_pkcs12, _PASSWORD)
58
-
59
- assert loaded.id == '76192083-9'
60
- assert loaded.name == 'SASCO SpA'
61
- assert loaded.email == 'demo@sasco.example'
62
- assert loaded.is_active is True
63
- assert loaded.certificate.startswith('-----BEGIN CERTIFICATE-----')
64
-
65
-
66
- def test_create_from_certificate_matches_load(fake_pkcs12, real_sdk):
67
- loaded = real_sdk.system.certificate.loader.load(fake_pkcs12, _PASSWORD)
68
-
69
- mandatario_manager = real_sdk.billing.trading_parties.mandatario_manager
70
- mandatario = mandatario_manager.create_from_certificate(loaded)
71
-
72
- assert mandatario.run == loaded.id
73
- assert mandatario.nombre == loaded.name
74
- assert mandatario.email == loaded.email