satcfdi.pacs   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 226
Duplicated Lines 0 %

Test Coverage

Coverage 94.2%

Importance

Changes 0
Metric Value
eloc 81
dl 0
loc 226
ccs 65
cts 69
cp 0.942
rs 10
c 0
b 0
f 0
wmc 15

13 Methods

Rating   Name   Duplication   Size   Complexity  
A Document.cfdi() 0 3 1
A PAC.status() 0 6 1
A PAC.stamp() 0 9 1
A PAC.recover() 0 8 1
A PAC.cancel_comprobante() 0 5 1
A PAC.list_69b() 0 5 1
A PAC.issue() 0 8 1
A PAC.accept_reject() 0 5 1
A PAC.cancel() 0 10 1
A PAC.__init__() 0 2 1
A PAC.pending() 0 5 1
A PAC.cancel_retencion() 0 5 1
A PAC.validate() 0 2 1

1 Function

Rating   Name   Duplication   Size   Complexity  
A _enum_value() 0 4 2
1 1
from dataclasses import dataclass
2 1
from enum import Flag, auto, Enum
3 1
from ..cfdi import CFDI
4 1
from ..models import Signer
5 1
from ..create.cancela import cancelacion
6 1
from ..create.cancela import cancelacionretencion
7 1
from ..create.cancela.aceptacionrechazo import SolicitudAceptacionRechazo
8
9 1
__all__ = [
10
    'PAC',
11
    'Accept',
12
    'Document',
13
    'CancelationAcknowledgment',
14
    'AcceptRejectAcknowledgment',
15
    'CancelReason',
16
    'TaxpayerStatus',
17
    'Environment'
18
]
19
20
21 1
class Accept(Flag):
22 1
    NOTHING = 0
23 1
    XML = auto()
24 1
    PDF = auto()
25 1
    XML_PDF = XML | PDF
26
27
28 1
@dataclass(init=True)
29 1
class Document:
30 1
    document_id: str
31 1
    xml: bytes = None
32 1
    pdf: bytes = None
33
34 1
    @property
35 1
    def cfdi(self) -> CFDI:
36
        return CFDI.from_string(self.xml)
37
38
39 1
@dataclass(init=True)
40 1
class CancelationAcknowledgment:
41 1
    code: str | dict
42 1
    acuse: bytes = None
43
44
45 1
@dataclass(init=True)
46 1
class AcceptRejectAcknowledgment:
47 1
    folios: dict
48 1
    acuse: bytes = None
49
50
51 1
def _enum_value(val):
52
    if isinstance(val, Enum):
53
        return val.value
54
    return val
55
56
57 1
class CancelReason(Enum):
58 1
    COMPROBANTE_EMITIDO_CON_ERRORES_CON_RELACION = "01"
59 1
    """
60
    -- Comprobante emitido con errores con relación --
61
    
62
    Este supuesto aplica cuando la factura generada contiene un error en
63
    la clave del producto, valor unitario, descuento o cualquier otro dato, por lo que se
64
    debe reexpedir. En este caso, primero se sustituye la factura y cuando se solicita la
65
    cancelación, se incorpora el folio de la factura que sustituye a la cancelada.
66
67
    ¿Qué debo hacer si uso el motivo de cancelación “01” Comprobantes emitidos con
68
    errores con relación y el comprobante no se cancela o presenta error?
69
70
    Se podrá utilizar la clave 02 para realizar la cancelación de los CFDI
71
    relacionados incluyendo el que sustituye al CFDI a cancelar, esto con la finalidad de
72
    que no se genere un estatus de “No cancelable”
73
74
    En los casos en los que subsista la operación, se deberá emitir un nuevo comprobante
75
    con la información correcta y la clave de tipo relación 04 sustitución de CFDI previos
76
    relacionando el folio fiscal del comprobante que se sustituye    
77
    """
78
79 1
    COMPROBANTE_EMITIDO_CON_ERRORES_SIN_RELACION = "02"
80 1
    """
81
    -- Comprobante emitido con errores sin relación --
82
    
83
    Este supuesto aplica cuando la factura generada contiene un error en
84
    la clave del producto, valor unitario, descuento o cualquier otro dato y no se requiera
85
    relacionar con otra factura generada.
86
    """
87
88 1
    NO_SE_LLEVO_A_CABO_LA_OPERACION = "03"
89 1
    """
90
    -- No se llevó a cabo la operación --
91
    
92
    Este supuesto aplica cuando se facturó una operación que no se
93
    concreta.
94
    """
95 1
    OPERACION_NORMATIVA_RELACIONADA_EN_LA_FACTURA_GLOBAL = "04"
96 1
    """
97
    -- Operación nominativa relacionada en la factura global --
98
    
99
    Este supuesto aplica cuando se incluye una venta en la factura global
100
    de operaciones con el público en general y posterior a ello, el cliente solicita su factura
101
    nominativa, lo que conlleva a cancelar la factura global y reexpedirla, así como
102
    generar la factura nominativa al cliente.
103
    """
104
105
106 1
class TaxpayerStatus(Enum):
107 1
    PRESUNTO = 'Presunto'
108 1
    """
109
    PRESUNTO: Cuando la autoridad fiscal detecta que un contribuyente ha estado emitiendo comprobantes de manera irregular,
110
    se presumirá la inexistencia de las operaciones amparadas en tales comprobantes.
111
112
    En este supuesto, procederá a notificar a los contribuyentes que se encuentren en dicha situación a través de su buzón
113
    tributario, de la página de internet del Servicio de Administración Tributaria, así como mediante una publicación en el
114
    Diario Oficial de la Federación.
115
    """
116
117 1
    SENTENCIA_FAVORABLE = 'Sentencia Favorable'
118 1
    """
119
    SENTENCIA FAVORABLE: El contribuyente tiene treinta días para acreditar que efectivamente sus operaciones son reales, si 
120
    logra corregir su situación se publica este estado.
121
    """
122
123 1
    DEFINITIVO = 'Definitivo'
124 1
    """
125
    DEFINITIVO: Si el contribuyente no atiende el llamado de la autoridad en quince días a partir de la última de las
126
    notificaciones o el contribuyente no pueda desvirtuar la existencia de sus operaciones se publica este estado.
127
    """
128
129 1
    DESVIRTUADO = 'Desvirtuado'
130 1
    """
131
    DESVIRTUADO: Cuando el contribuyente aporte a la autoridad fiscal la documentación e información que consideren 
132
    pertinentes para desvirtuar los hechos que llevaron a notificarlos con un plazo de quince días contados a partir de la
133
    última de las notificaciones que se hayan efectuado.
134
    """
135
136
137 1
class Environment(Enum):
138 1
    PRODUCTION = auto()
139 1
    TEST = auto()
140
141
142 1
class PAC:
143 1
    RFC = None
144
145 1
    def __init__(self, environment: Environment):
146 1
        self.environment = environment
147
148 1
    def status(self, cfdi: CFDI) -> dict:
149
        """
150
        Consulta el estado de un CFDI
151
        :return: Respuesta de la consulta
152
        """
153
        raise NotImplementedError()
154
155 1
    def validate(self, cfdi: CFDI):
156
        raise NotImplementedError()
157
158 1
    def issue(self, cfdi: CFDI, accept: Accept = Accept.XML) -> Document:
159
        """
160
        Operation to request CFDI be sealed and stamped by PAC
161
        :param accept:
162
        :param cfdi:
163
        :return:
164
        """
165
        raise NotImplementedError()
166
167 1
    def stamp(self, cfdi: CFDI, accept: Accept = Accept.XML) -> Document:
168
        """
169
        Operation to request sealed CFDI be stamped by PAC
170
        :param accept:
171
        :param cfdi:
172
        :return:
173
        document_id and bytes of stamped xml
174
        """
175
        raise NotImplementedError()
176
177 1
    def recover(self, document_id: str, accept: Accept = Accept.XML) -> Document:
178
        """
179
180
        :param accept:
181
        :param document_id:
182
        :return:
183
        """
184
        raise NotImplementedError()
185
186 1
    def cancel(self, cfdi: CFDI, reason: CancelReason, substitution_id: str = None, signer: Signer = None) -> CancelationAcknowledgment:
187
        """
188
        Operation to request single cfdi to be canceled
189
        :param signer:
190
        :param cfdi:
191
        :param substitution_id:
192
        :param reason:
193
        :return:
194
        """
195
        raise NotImplementedError()
196
197 1
    def cancel_comprobante(self, cancelation: cancelacion.Cancelacion) -> CancelationAcknowledgment:
198
        """
199
        Operation to Cancel a Comprobante
200
        """
201
        raise NotImplementedError()
202
203 1
    def cancel_retencion(self, cancelation: cancelacionretencion.Cancelacion) -> CancelationAcknowledgment:
204
        """
205
        Operation to Cancel a Retencion
206
        """
207
        raise NotImplementedError()
208
209 1
    def accept_reject(self, request: SolicitudAceptacionRechazo) -> AcceptRejectAcknowledgment:
210
        """
211
        Operation to Accept Reject a Cancellation Request
212
        """
213
        raise NotImplementedError()
214
215 1
    def pending(self, rfc: str) -> list[str]:
216
        """
217
        Operation to get pending cancellations
218
        """
219
        raise NotImplementedError()
220
221 1
    def list_69b(self, rfc: str) -> TaxpayerStatus | None:
222
        """
223
        Operation to get list69b status
224
        """
225
        raise NotImplementedError()
226