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

generar_contabilidad()   B

Complexity

Conditions 1

Size

Total Lines 94
Code Lines 79

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 1.008

Importance

Changes 0
Metric Value
cc 1
eloc 79
nop 12
dl 0
loc 94
ccs 20
cts 25
cp 0.8
crap 1.008
rs 7.6872
c 0
b 0
f 0

How to fix   Long Method    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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