from dataclasses import dataclass
from enum import Flag, auto, Enum
from .. import CFDI, Signer
from ..create.cancela import cancelacion
from ..create.cancela import cancelacionretencion
from ..create.cancela.aceptacionrechazo import SolicitudAceptacionRechazo
__all__ = [
'PAC',
'Accept',
'Document',
'CancelationAcknowledgment',
'AcceptRejectAcknowledgment',
'CancelReason',
'TaxpayerStatus',
'Environment'
]
[docs]class Accept(Flag):
NOTHING = 0
XML = auto()
PDF = auto()
XML_PDF = XML | PDF
[docs]@dataclass(init=True)
class Document:
document_id: str
xml: bytes = None
pdf: bytes = None
@property
def cfdi(self) -> CFDI:
return CFDI.from_string(self.xml)
[docs]@dataclass(init=True)
class CancelationAcknowledgment:
code: str | dict
acuse: bytes = None
[docs]@dataclass(init=True)
class AcceptRejectAcknowledgment:
folios: dict
acuse: bytes = None
def _enum_value(val):
if isinstance(val, Enum):
return val.value
return val
[docs]class CancelReason(Enum):
COMPROBANTE_EMITIDO_CON_ERRORES_CON_RELACION = "01"
"""
-- Comprobante emitido con errores con relación --
Este supuesto aplica cuando la factura generada contiene un error en
la clave del producto, valor unitario, descuento o cualquier otro dato, por lo que se
debe reexpedir. En este caso, primero se sustituye la factura y cuando se solicita la
cancelación, se incorpora el folio de la factura que sustituye a la cancelada.
¿Qué debo hacer si uso el motivo de cancelación “01” Comprobantes emitidos con
errores con relación y el comprobante no se cancela o presenta error?
Se podrá utilizar la clave 02 para realizar la cancelación de los CFDI
relacionados incluyendo el que sustituye al CFDI a cancelar, esto con la finalidad de
que no se genere un estatus de “No cancelable”
En los casos en los que subsista la operación, se deberá emitir un nuevo comprobante
con la información correcta y la clave de tipo relación 04 sustitución de CFDI previos
relacionando el folio fiscal del comprobante que se sustituye
"""
COMPROBANTE_EMITIDO_CON_ERRORES_SIN_RELACION = "02"
"""
-- Comprobante emitido con errores sin relación --
Este supuesto aplica cuando la factura generada contiene un error en
la clave del producto, valor unitario, descuento o cualquier otro dato y no se requiera
relacionar con otra factura generada.
"""
NO_SE_LLEVO_A_CABO_LA_OPERACION = "03"
"""
-- No se llevó a cabo la operación --
Este supuesto aplica cuando se facturó una operación que no se
concreta.
"""
OPERACION_NORMATIVA_RELACIONADA_EN_LA_FACTURA_GLOBAL = "04"
"""
-- Operación nominativa relacionada en la factura global --
Este supuesto aplica cuando se incluye una venta en la factura global
de operaciones con el público en general y posterior a ello, el cliente solicita su factura
nominativa, lo que conlleva a cancelar la factura global y reexpedirla, así como
generar la factura nominativa al cliente.
"""
[docs]class TaxpayerStatus(Enum):
PRESUNTO = 'Presunto'
"""
PRESUNTO: Cuando la autoridad fiscal detecta que un contribuyente ha estado emitiendo comprobantes de manera irregular,
se presumirá la inexistencia de las operaciones amparadas en tales comprobantes.
En este supuesto, procederá a notificar a los contribuyentes que se encuentren en dicha situación a través de su buzón
tributario, de la página de internet del Servicio de Administración Tributaria, así como mediante una publicación en el
Diario Oficial de la Federación.
"""
SENTENCIA_FAVORABLE = 'Sentencia Favorable'
"""
SENTENCIA FAVORABLE: El contribuyente tiene treinta días para acreditar que efectivamente sus operaciones son reales, si
logra corregir su situación se publica este estado.
"""
DEFINITIVO = 'Definitivo'
"""
DEFINITIVO: Si el contribuyente no atiende el llamado de la autoridad en quince días a partir de la última de las
notificaciones o el contribuyente no pueda desvirtuar la existencia de sus operaciones se publica este estado.
"""
DESVIRTUADO = 'Desvirtuado'
"""
DESVIRTUADO: Cuando el contribuyente aporte a la autoridad fiscal la documentación e información que consideren
pertinentes para desvirtuar los hechos que llevaron a notificarlos con un plazo de quince días contados a partir de la
última de las notificaciones que se hayan efectuado.
"""
[docs]class Environment(Enum):
PRODUCTION = auto()
TEST = auto()
[docs]class PAC:
RFC = None
def __init__(self, environment):
self.environment = environment
[docs] def status(self, cfdi: CFDI) -> dict:
"""
Consulta el estado de un CFDI
:return: Respuesta de la consulta
"""
raise NotImplementedError()
[docs] def validate(self, cfdi: CFDI):
raise NotImplementedError()
[docs] def issue(self, cfdi: CFDI, accept: Accept = Accept.XML) -> Document:
"""
Operation to request CFDI be sealed and stamped by PAC
:param accept:
:param cfdi:
:return:
"""
raise NotImplementedError()
[docs] def stamp(self, cfdi: CFDI, accept: Accept = Accept.XML) -> Document:
"""
Operation to request sealed CFDI be stamped by PAC
:param accept:
:param cfdi:
:return:
document_id and bytes of stamped xml
"""
raise NotImplementedError()
[docs] def recover(self, document_id: str, accept: Accept = Accept.XML) -> Document:
"""
:param accept:
:param document_id:
:return:
"""
raise NotImplementedError()
[docs] def cancel(self, cfdi: CFDI, reason: CancelReason, substitution_id: str = None, signer: Signer = None) -> CancelationAcknowledgment:
"""
Operation to request single cfdi to be canceled
:param signer:
:param cfdi:
:param substitution_id:
:param reason:
:return:
"""
raise NotImplementedError()
[docs] def cancel_comprobante(self, cancelation: cancelacion.Cancelacion) -> CancelationAcknowledgment:
raise NotImplementedError()
[docs] def cancel_retencion(self, cancelation: cancelacionretencion.Cancelacion) -> CancelationAcknowledgment:
raise NotImplementedError()
[docs] def accept_reject(self, request: SolicitudAceptacionRechazo) -> AcceptRejectAcknowledgment:
raise NotImplementedError()
[docs] def pending(self, rfc: str) -> list[str]:
raise NotImplementedError()
[docs] def list_69b(self, rfc: str) -> TaxpayerStatus | None:
raise NotImplementedError()