Código fuente para apigatewaycl.api_client.sii.eboleta

#
# API Gateway: Cliente de API en Python.
# Copyright (C) API Gateway <https://www.apigateway.cl>
#
# Este programa es software libre: usted puede redistribuirlo y/o modificarlo
# bajo los términos de la GNU Lesser General Public License (LGPL) publicada
# por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia,
# o (a su elección) cualquier versión posterior de la misma.
#
# Este programa se distribuye con la esperanza de que sea útil, pero SIN
# GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD
# PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General
# Public License (LGPL) para obtener una información más detallada.
#
# Debería haber recibido una copia de la GNU Lesser General Public License
# (LGPL) junto a este programa. En caso contrario, consulte
# <http://www.gnu.org/licenses/lgpl.html>.
#

"""
Módulo para eBoleta (Boletas Electrónicas del SII, sistema propio).

Para más información sobre la API, consulte la `documentación completa
de eBoleta <https://www.apigateway.cl/docs>`_.
"""

from __future__ import annotations

from typing import Any

from .. import ApiBase, ApiResponse


[documentos] class EboletaContribuyente(ApiBase): """ Cliente para información de contribuyentes emisores de eBoleta. :param str identificador: Identificador del contribuyente. :param str clave: Clave del identificador. :param kwargs: Argumentos adicionales. """ def __init__( self, identificador: str, clave: str, **kwargs: str, ) -> None: """Autentica con `identificador`/`clave` del contribuyente.""" super().__init__( identificador=identificador, clave=clave, **kwargs, # type: ignore[arg-type] )
[documentos] def emisor(self, emisor: str) -> ApiResponse[dict[str, Any]]: """ Información del emisor de la boleta electrónica. Respuesta (ejemplo):: { "data": { "contribuyente": { "rut": 12345678, "razon_social": "RAZON SOCIAL DEL EMISOR", "dv": "9", "giro": "GIRO DEL EMISOR", "actividad_economica": "Actividad económica del emisor", "telefono": "1234567890", "email": "emisor@example.com", "direccion": "Dirección del emisor", "...": "..." }, "sucursales": [ { "rut": 12345678, "codigo": 12345678, "sucursal": null, "direccion": "ERRAZURIZ 827 ", "comuna": "Santa Cruz", "...": "..." } ], "usuarios": [ { "user": "12345678-9", "nombre": "NOMBRE DEL USUARIO 1", "es_representante": true, "permisos": 0, "total_records": 2 } ] }, "metadata": {"timestamp": "..."} } :param str emisor: RUT del emisor (formato 11222333-K). :return: Respuesta de la API, con `data` y `metadata`. En `data`, datos del contribuyente, sus sucursales y usuarios. :rtype: ApiResponse[dict[str, Any]] """ url = '/sii/eboleta/contribuyente/emisor/%(emisor)s' % { 'emisor': emisor, } body = {'auth': self._get_auth()} response = self.client.post(url, data=body) return self._json(response)
[documentos] def emisores_autorizados(self) -> ApiResponse[dict[str, Any]]: """ Lista de emisores autorizados de la boleta electrónica. Respuesta (ejemplo):: { "data": { "emisores": [ { "rut": 12345678, "dv": "9", "razon_social": "RAZON SOCIAL DEL EMISOR" } ] }, "metadata": {"timestamp": "..."} } :return: Respuesta de la API, con `data` y `metadata`. En `data`, listado de contribuyentes (RUT, DV y razón social). :rtype: ApiResponse[dict[str, Any]] """ body = {'auth': self._get_auth()} response = self.client.post( '/sii/eboleta/contribuyente/emisores_autorizados', data=body, ) return self._json(response)
[documentos] class EboletaEmitidas(ApiBase): """ Cliente para boletas electrónicas emitidas de eBoleta. :param str identificador: Identificador del contribuyente. :param str clave: Clave del identificador. :param kwargs: Argumentos adicionales. """ def __init__( self, identificador: str, clave: str, **kwargs: str, ) -> None: """Autentica con `identificador`/`clave` del contribuyente.""" super().__init__( identificador=identificador, clave=clave, **kwargs, # type: ignore[arg-type] ) def _body_documento( self, contribuyente: str, folio: int, dte: int, fecha: str, ) -> dict[str, Any]: """ Cuerpo que identifica un documento ya emitido. `documento()`, `pdf()` y `email()` apuntan al mismo documento con estos cuatro campos, todos en el cuerpo. :param str contribuyente: RUT del contribuyente. :param int folio: Folio del documento. :param int dte: Tipo de documento. :param str fecha: Fecha de emisión del documento (AAAA-MM-DD). :return: Cuerpo de la solicitud, con la autenticación incluida. :rtype: dict[str, Any] """ return { 'auth': self._get_auth(), 'contribuyente': contribuyente, 'folio': folio, 'dte': dte, 'fecha': fecha, }
[documentos] def documentos( self, contribuyente: str, date_from: str, date_to: str, page: int | None = None, items_per_page: int | None = None, estado: str | None = None, ) -> ApiResponse[list[dict[str, Any]]]: """ Listado de documentos emitidos de la boleta electrónica. Respuesta (ejemplo):: { "data": [ { "folio": 35, "neto": 4202, "iva": 798, "total": 5000, "exento": 0, "dte": 39, "revision_estado": "pendiente", "anulado": false, "...": "..." } ], "metadata": { "timestamp": "...", "total": "23390", "cantidad_emitida": "5" } } :param str contribuyente: RUT del contribuyente, sin puntos ni dígito verificador. :param str date_from: Fecha de inicio (AAAA-MM-DD). :param str date_to: Fecha de fin (AAAA-MM-DD). :param int page: Página a obtener (por defecto `1`). :param int items_per_page: Ítems por página (por defecto `10`). :param str estado: Estado del documento (por defecto `emitido`). :return: Respuesta de la API, con `data` y `metadata`. En `data`, el listado de documentos emitidos; en `metadata`, los datos de la consulta. :rtype: ApiResponse[list[dict[str, Any]]] """ # Todos los parámetros de esta API van en el cuerpo, no en la # ruta ni en la query string. Los opcionales no se envían si # no se indican, para que aplique el valor por defecto. opcionales = { 'page': page, 'items_per_page': items_per_page, 'estado': estado, } body: dict[str, Any] = { 'auth': self._get_auth(), 'contribuyente': contribuyente, 'date_from': date_from, 'date_to': date_to, } body.update( { clave: valor for clave, valor in opcionales.items() if valor is not None } ) response = self.client.post( '/sii/eboleta/emitidas/documentos', data=body, ) return self._json(response)
[documentos] def emitir(self, dte: dict[str, Any]) -> ApiResponse[dict[str, Any]]: """ Emite una Boleta Electrónica Afecta (39) o Exenta (41). Solo admite un ítem por documento. `dte['vendedor']` debe ser el mismo RUT usado para autenticar (`auth.pass.rut`). Respuesta (ejemplo):: { "data": { "pdf": "url del pdf", "pdf_base64": "data:application/pdf;base64,...", "dte": 39, "folio": 40 }, "metadata": {"timestamp": "..."} } :param dict dte: Datos de la boleta a emitir (`vendedor`, `Encabezado`, `Detalle`). :return: Respuesta de la API, con `data` y `metadata`. En `data`, folio y tipo de documento emitido, URL del PDF y PDF en base64. :rtype: ApiResponse[dict[str, Any]] """ body = {'auth': self._get_auth(), 'dte': dte} response = self.client.post('/sii/eboleta/emitidas/emitir', data=body) return self._json(response)
[documentos] def documento( self, contribuyente: str, folio: int, dte: int, fecha: str, ) -> ApiResponse[dict[str, Any]]: """ Detalle de un documento de la boleta electrónica. Respuesta (ejemplo):: { "data": { "folio": 35, "neto": 4202, "iva": 798, "total": 5000, "exento": 0, "dte": 39, "revision_estado": "pendiente", "anulado": false, "...": "..." }, "metadata": {"timestamp": "..."} } :param str contribuyente: RUT del contribuyente. :param int folio: Folio del documento. :param int dte: Tipo de documento. :param str fecha: Fecha de emisión del documento (AAAA-MM-DD). :return: Respuesta de la API, con `data` y `metadata`. En `data`, datos del documento (montos, estado, revisión, PDF). :rtype: ApiResponse[dict[str, Any]] """ response = self.client.post( '/sii/eboleta/emitidas/documento', data=self._body_documento(contribuyente, folio, dte, fecha), ) return self._json(response)
[documentos] def pdf( self, contribuyente: str, folio: int, dte: int, fecha: str, ) -> bytes: """ PDF de un documento de la boleta electrónica. :param str contribuyente: RUT del contribuyente. :param int folio: Folio del documento. :param int dte: Tipo de documento. :param str fecha: Fecha de emisión del documento (AAAA-MM-DD). :return: Contenido del PDF del documento. :rtype: bytes """ response = self.client.post( '/sii/eboleta/emitidas/pdf', data=self._body_documento(contribuyente, folio, dte, fecha), ) return response.content
[documentos] def email( self, contribuyente: str, folio: int, dte: int, fecha: str, to: str, ) -> ApiResponse[dict[str, Any]]: """ Envía por correo electrónico un documento de la boleta. Respuesta (ejemplo):: { "data": {"mensaje": "Email enviado con éxito"}, "metadata": {"timestamp": "..."} } :param str contribuyente: RUT del contribuyente. :param int folio: Folio del documento. :param int dte: Tipo de documento. :param str fecha: Fecha de emisión del documento (AAAA-MM-DD). :param str to: Dirección de correo de destino. :return: Respuesta de la API, con `data` y `metadata`. En `data`, mensaje de confirmación del envío. :rtype: ApiResponse[dict[str, Any]] """ body = self._body_documento(contribuyente, folio, dte, fecha) body['to'] = to response = self.client.post('/sii/eboleta/emitidas/email', data=body) return self._json(response)