Passed
Push — main ( c3988a...3503ff )
by Sat CFDI
03:11
created

satdigitalinvoice.gui_functions.pago_factura()   B

Complexity

Conditions 6

Size

Total Lines 24
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 19
dl 0
loc 24
rs 8.5166
c 0
b 0
f 0
cc 6
nop 3
1
import logging
2
import uuid
3
from datetime import datetime
4
from uuid import UUID
5
6
from satcfdi.create.cfd import cfdi40
7
from satcfdi.create.cfd.cfdi40 import Comprobante
8
9
from . import SERIE, EMISOR, LUGAR_EXPEDICION
10
from .file_data_managers import FacturasManager
11
from .mycfdi import notifications, clients, get_all_cfdi
12
13
logging.basicConfig(level=logging.ERROR)
14
logger = logging.getLogger()
15
16
17
def create_cfdi(factura_details, serie, folio):
18
    cliente = clients.get(factura_details['Rfc'])
19
    if not cliente:
20
        logger.error(f"{factura_details['Rfc']}: client not found")
21
        return None
22
23
    invoice = cfdi40.Comprobante(
24
        emisor=EMISOR,
25
        lugar_expedicion=LUGAR_EXPEDICION,
26
        receptor=cfdi40.Receptor(
27
            rfc=factura_details['Rfc'],
28
            nombre=cliente['RazonSocial'],
29
            uso_cfdi=factura_details['UsoCFDI'],
30
            domicilio_fiscal_receptor=cliente['CodigoPostal'],
31
            regimen_fiscal_receptor=cliente['RegimenFiscal']
32
        ),
33
        metodo_pago=factura_details['MetodoPago'],
34
        forma_pago=factura_details['FormaPago'],
35
        serie=serie,
36
        folio=folio,
37
        conceptos=factura_details["Conceptos"]
38
    ).process()
39
40
    if factura_details['Total'] != invoice['Total']:
41
        logger.error(f"{factura_details['Rfc']}: Total '{factura_details['Total']}' is invalid, expected '{invoice['Total']}'")
42
        return None
43
44
    if invoice["MetodoPago"] == "PPD" and invoice["FormaPago"] != "99":
45
        logger.error(f"{factura_details['Rfc']}: FormaPago '{invoice['FormaPago']}' is invalid, expected '99' for PPD")
46
        return None
47
48
    return invoice
49
50
51
def generate_ingresos(values):
52
    facturas_manager = FacturasManager(values)
53
    facturas = facturas_manager["Facturas"]
54
55
    inicio = int(values["inicio"])
56
    if inicio <= 0:
57
        logger.error("Inicio no Valido")
58
59
    final = int(values["final"])
60
    if final <= 0 or final < inicio:
61
        logger.error("Final no Valido")
62
63
    facturas = facturas[inicio - 1:final]
64
    cfdis = [create_cfdi(f, SERIE, str(notifications.folio(SERIE) + i)) for i, f in enumerate(facturas)]
65
66
    if None in cfdis:
67
        return
68
69
    return cfdis
70
71
72
def find_factura(factura):
73
    if not factura:
74
        logger.error("Especificar factura a pagar")
75
        return
76
77
    try:
78
        factura_uuid = uuid.UUID(factura)
79
    except:
80
        factura_uuid = None
81
82
    all_invoices = get_all_cfdi()
83
    for i in all_invoices.values():
84
        if (i.name == factura or i.uuid == factura_uuid) and i["Emisor"]["Rfc"] == EMISOR.rfc:
85
            logger.info(f"Factura Encontrada: {i['Receptor']['Rfc']}  {i.name}  {i.uuid}  {i['Fecha']}")
86
            return i
87
88
    logger.info(f"Factura No Encontrada {factura}")
89
90
91
def parse_fecha_pago(fecha_pago):
92
    fecha_pago = datetime.fromisoformat(fecha_pago)
93
    if fecha_pago > datetime.now():
94
        logger.error("Fecha de Pago esta en el futuro")
95
        return
96
97
    if fecha_pago.replace(hour=12) > datetime.now():
98
        fecha_pago = datetime.now()
99
    else:
100
        fecha_pago = fecha_pago.replace(hour=12)
101
102
    dif = datetime.now() - fecha_pago
103
    if dif.days > 30:
104
        logger.error("!!! FECHA DE PAGO ES MAYOR A 30 DIAS !!!")
105
106
    return fecha_pago
107
108
109
def pago_factura(factura_pagar, fecha_pago, forma_pago):
110
    if not (fecha_pago := parse_fecha_pago(fecha_pago)):
111
        return
112
113
    if i := find_factura(factura_pagar):
114
        if i["TipoDeComprobante"] != "I":
115
            logger.error("Comprobante a pagar no es de Ingreso")
116
            return
117
118
        if i["MetodoPago"] != "PPD":
119
            logger.error("Comprobante a pagar no es de Metodo Pago PPD")
120
            return
121
122
        if i.saldo_pendiente != i["Total"]:
123
            logger.error("Comprobante ya tiene pago anterior")
124
            logger.error(f"Saldo Pendiente: {i.saldo_pendiente}")
125
            return
126
127
        if i.estatus != "1":
128
            logger.error("Comprobante ya esta cancelado")
129
            return
130
131
        return generar_pago(cfdi=i, fecha_pago=fecha_pago, forma_pago=forma_pago)
132
133
134
def generar_pago(cfdi, fecha_pago, forma_pago="03"):
135
    pago = Comprobante.pago_comprobantes(
136
        emisor=EMISOR,
137
        lugar_expedicion=LUGAR_EXPEDICION,
138
        comprobantes=cfdi,
139
        fecha_pago=fecha_pago,
140
        forma_pago=forma_pago,
141
        serie=SERIE,
142
        folio=str(notifications.folio(SERIE)),
143
    ).process()
144
    return pago
145
146
# Pago Parcial
147
# comprobantes = [PagoComprobante(
148
#     comprobante=c,
149
#     num_parcialidad=c.ultima_num_parcialidad + 1,
150
#     imp_saldo_ant=c.saldo_pendiente,
151
#     imp_pagado=Decimal(imp_pagado)
152
# ) for c, imp_pagado in cfdis],
153