Source code for cfdibills.api

"""
Definition of the SAT's API used to verify CFDIs.
"""

from dataclasses import dataclass
from typing import Optional

import requests
import xmltodict


[docs]@dataclass class SATConsultaResponse: """ Encloses the response of the ConsultaCFDIService web service when called with a Consulta action See: https://consultaqr.facturaelectronica.sat.gob.mx/ConsultaCFDIService.svc?xsd=xsd2 """ #: Código estatus codigo_estatus: str #: Es Cancelable es_cancelable: str #: Estado estado: str #: Estatus cancelación estatus_cancelacion: Optional[str] #: Validación EFOS validacion_efos: str
def _call_sat(uuid: str, rfc_emisor: str, rfc_receptor: str, total_facturado: float) -> dict: """ Sends a SOAP request to SAT's web service to get the status of a CFDI """ body = f""" <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/"> <soapenv:Header/> <soapenv:Body> <tem:Consulta> <!--Optional:--> <tem:expresionImpresa> <![CDATA[?re={rfc_emisor}&rr={rfc_receptor}&tt={total_facturado}&id={uuid}]]> </tem:expresionImpresa> </tem:Consulta> </soapenv:Body> </soapenv:Envelope> """ url = "https://consultaqr.facturaelectronica.sat.gob.mx/ConsultaCFDIService.svc?wsdl" headers = { "content-type": 'text/xml;charset="utf-8"', "SOAPAction": "http://tempuri.org/IConsultaCFDIService/Consulta", } response = requests.post(url, data=body, headers=headers) if response.status_code != 200: raise ValueError(f"An error occurred when verifying with SAT. Response: {response.text}") return xmltodict.parse(response.content)
[docs]def consulta_cfdi_service(uuid: str, rfc_emisor: str, rfc_receptor: str, total_facturado: float) -> SATConsultaResponse: """ Gets the status of the given CFDI by calling SAT's web service. See: https://consultaqr.facturaelectronica.sat.gob.mx/ConsultaCFDIService.svc?wsdl Parameters ---------- uuid: str UUID of the CFDI to check rfc_emisor: str RFC if the issuer of the CFDI to check rfc_receptor: str RFC if the recipient of the CFDI to check total_facturado: float Total amount of money billed in the CFDI Returns ------- SATConsultaResponse Container of the result emmitted by SAT's web service """ data = _call_sat(uuid, rfc_emisor, rfc_receptor, total_facturado) try: result = data["s:Envelope"]["s:Body"]["ConsultaResponse"]["ConsultaResult"] return SATConsultaResponse( result["a:CodigoEstatus"], result["a:EsCancelable"], result["a:Estado"], result["a:EstatusCancelacion"], result["a:ValidacionEFOS"], ) except KeyError: raise ValueError(f"The response from SAT was not in a known format. Response: {data}")