Test Failed
Push — main ( 4ba94d...aae238 )
by Sat CFDI
04:05
created

satcfdi.accounting.contabilidad.output_file()   A

Complexity

Conditions 4

Size

Total Lines 21
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 4.074

Importance

Changes 0
Metric Value
cc 4
eloc 15
nop 4
dl 0
loc 21
ccs 10
cts 12
cp 0.8333
crap 4.074
rs 9.65
c 0
b 0
f 0
1 1
import os
2 1
from typing import Sequence
3
4 1
from satcfdi.create.contabilidad.AuxiliarCtas13 import AuxiliarCtas, Cuenta, DetalleAux
5 1
from satcfdi.create.contabilidad.BCE13 import Balanza
6 1
from satcfdi.create.contabilidad.PLZ13 import Polizas, CompNal, Poliza
7 1
from satcfdi.create.contabilidad.RepAux13 import RepAuxFol, DetAuxFol
8 1
from satcfdi.create.contabilidad.catalogocuentas13 import Catalogo, Ctas
9 1
from .contabilidad_print import imprimir_contablidad
10
11 1
from .. import render
12
13 1
from ..models import DatePeriod
14
15
16 1
def filename(file):
17 1
    if file.tag == '{http://www.sat.gob.mx/esquemas/ContabilidadE/1_3/BalanzaComprobacion}Balanza':
18 1
        return file["RFC"] + str(file["Anio"]) + file["Mes"] + "B" + file["TipoEnvio"] + ".xml"
19 1
    if file.tag == '{http://www.sat.gob.mx/esquemas/ContabilidadE/1_3/CatalogoCuentas}Catalogo':
20 1
        return file["RFC"] + str(file["Anio"]) + file["Mes"] + "CT.xml"
21 1
    if file.tag == '{http://www.sat.gob.mx/esquemas/ContabilidadE/1_3/AuxiliarCtas}AuxiliarCtas':
22 1
        return file["RFC"] + str(file["Anio"]) + file["Mes"] + "XC.xml"
23 1
    if file.tag == '{http://www.sat.gob.mx/esquemas/ContabilidadE/1_3/PolizasPeriodo}Polizas':
24 1
        return file["RFC"] + str(file["Anio"]) + file["Mes"] + "PL.xml"
25 1
    if file.tag == '{http://www.sat.gob.mx/esquemas/ContabilidadE/1_3/AuxiliarFolios}RepAuxFol':
26 1
        return file["RFC"] + str(file["Anio"]) + file["Mes"] + "XF.xml"
27
    raise ValueError(f"Unknown file type: {file.tag}")
28
29
30 1
def output_file(file, folder, fiel=None, generate_pdf=False):
31 1
    if fiel:
32
        file.sign(fiel)
33
34 1
    output_file = os.path.join(folder, filename(file))
35 1
    file.xml_write(
36
        output_file,
37
        pretty_print=True,
38
        xml_declaration=True
39
    )
40 1
    if generate_pdf:
41
        # render.html_write(file, output_file[:-4] + ".html")
42
        render.pdf_write(file, output_file[:-4] + ".pdf")
43
    else:
44
        # delete file
45 1
        try:
46 1
            os.remove(output_file[:-4] + ".pdf")
47 1
        except FileNotFoundError:
48 1
            pass
49
50 1
    return output_file
51
52
53 1
def calcular_saldos(cuentas, polizas):
54
    for c in cuentas.values():
55
        # c['SaldoIni'] = 0
56
        c['Debe'] = 0
57
        c['Haber'] = 0
58
        c['SaldoFin'] = 0
59
60
    for p in polizas:
61
        for t in p["Transaccion"]:
62
            num_cta = t["NumCta"]
63
            cuenta = cuentas[num_cta]
64
            cuenta["Debe"] += t["Debe"]
65
            cuenta["Haber"] += t["Haber"]
66
67 1
    # Fill Parents
68
    for level in range(4, 1, -1):
69
        for k, v in cuentas.items():
70
            if v['Nivel'] == level:
71
                parent = v['SubCtaDe']
72
                if parent:
73
                    p_cuenta = cuentas[parent]
74
                    p_cuenta['Debe'] += v['Debe']
75
                    p_cuenta['Haber'] += v['Haber']
76 1
77
    # Fill SaldoFin
78 1
    for c in cuentas.values():
79
        if c["Natur"] == "D":
80
            c["SaldoFin"] += c["SaldoIni"] + c["Debe"] - c["Haber"]
81
        else:
82
            c["SaldoFin"] += c["SaldoIni"] + c["Haber"] - c["Debe"]
83
84
85
def generar_contabilidad(
86
        dp: DatePeriod,
87
        rfc_emisor: str,
88
        cuentas: dict,
89
        polizas: Sequence[Poliza],
90
        tipo_envio='N',
91
        fecha_mod_bal=None,
92
        tipo_solicitud='',
93 1
        numero_orden=None,
94
        numero_tramite=None,
95 1
        folder=None,
96
        fiel=None,
97
        generate_pdf=False):
98
    calcular_saldos(cuentas, polizas)
99
100
    plz = Polizas(
101
        rfc=rfc_emisor,
102
        mes=str(dp.month).zfill(2),
103
        anio=dp.year,
104
        tipo_solicitud=tipo_solicitud,
105
        num_orden=numero_orden,
106 1
        num_tramite=numero_tramite,
107
        poliza=polizas
108 1
    )
109 1
    output_file(plz, folder, fiel, generate_pdf=generate_pdf)
110
111
    cat = Catalogo(
112
        rfc=rfc_emisor,
113
        mes=str(dp.month).zfill(2),
114
        anio=dp.year,
115
        ctas=[
116
            Ctas(
117
                cod_agrup=v["CodAgrup"].split("_")[0],
118
                num_cta=k,
119
                desc=v["Desc"],
120
                nivel=v["Nivel"],
121
                natur=v["Natur"],
122
                sub_cta_de=v['SubCtaDe'],
123
            ) for k, v in cuentas.items()
124
        ]
125
    )
126 1
    output_file(cat, folder, fiel)
127
128 1
    ban = Balanza(
129
        rfc=rfc_emisor,
130
        mes=str(dp.month).zfill(2),
131
        anio=dp.year,
132
        tipo_envio=tipo_envio,
133
        fecha_mod_bal=fecha_mod_bal,
134
        ctas=[{
135
            "NumCta": k,
136
            **v,
137 1
        } for k, v in cuentas.items() if v["SaldoIni"] or v["Debe"] or v["Haber"] or v["SaldoFin"]],
138
    )
139 1
    output_file(ban, folder, fiel)
140
141
    aux_detalles = group_aux_cuentas(polizas)
142
    aux = AuxiliarCtas(
143
        rfc=rfc_emisor,
144
        mes=str(dp.month).zfill(2),
145 1
        anio=dp.year,
146
        tipo_solicitud=tipo_solicitud,
147
        num_orden=numero_orden,
148 1
        num_tramite=numero_tramite,
149 1
        cuenta=[
150 1
            Cuenta(
151
                num_cta=k,
152
                des_cta=v["Desc"],
153
                saldo_ini=v["SaldoIni"],
154
                saldo_fin=v["SaldoFin"],
155
                detalle_aux=aux_detalles[k]
156
            ) for k, v in cuentas.items() if k in aux_detalles
157
        ]
158
    )
159
    output_file(aux, folder, fiel, generate_pdf=generate_pdf)
160
161
    auxf = RepAuxFol(
162 1
        rfc=rfc_emisor,
163
        mes=str(dp.month).zfill(2),
164
        anio=dp.year,
165 1
        tipo_solicitud=tipo_solicitud,
166 1
        num_orden=numero_orden,
167
        num_tramite=numero_tramite,
168
        det_aux_fol=list(group_aux_folios(polizas))
169
    )
170
    output_file(auxf, folder, fiel, generate_pdf=generate_pdf)
171
172
    imprimir_contablidad(
173
        catalogo_cuentas=cat,
174 1
        balanza_comprobacion=ban,
175 1
        archivo_excel=filename(ban)[:-4] + ".xlsx"
176 1
    )
177 1
178
    validate_saldos(cuentas)
179
180
181
def group_aux_cuentas(polizas):
182
    cta_polizas = {}
183
    for p in polizas:
184
        for t in p["Transaccion"]:
185
            detalles = cta_polizas.setdefault(t["NumCta"], [])
186
            detalles.append(
187
                DetalleAux(
188
                    fecha=p["Fecha"],
189
                    num_un_iden_pol=p["NumUnIdenPol"],
190 1
                    concepto=t["Concepto"],
191 1
                    debe=t["Debe"],
192
                    haber=t["Haber"],
193
                )
194
            )
195
    return cta_polizas
196
197
198
def group_aux_folios(polizas):
199
    for p in polizas:
200
        yield DetAuxFol(
201
            num_un_iden_pol=p["NumUnIdenPol"],
202
            fecha=p["Fecha"],
203
            compr_nal=p.comp_nal,
204
        )
205
206
207
def validate_saldos(cuentas):
208
    total = 0
209
    totales = {}
210
    for k, v in cuentas.items():
211
        if v['Nivel'] == 1:
212
            if v['Natur'] == 'D':
213
                total += v['SaldoFin']
214
            else:
215
                total -= v['SaldoFin']
216
        else:
217
            totales.setdefault(v['SubCtaDe'], 0)
218
            if v['Natur'] == 'D':
219
                totales[v['SubCtaDe']] += v['SaldoFin']
220
            else:
221
                totales[v['SubCtaDe']] -= v['SaldoFin']
222
223
    assert total == 0
224
    for k, v in totales.items():
225
        if cuentas[k]['Natur'] == 'D':
226
            assert v == cuentas[k]['SaldoFin']
227
        else:
228
            assert v == -cuentas[k]['SaldoFin']
229