Test Failed
Push — main ( b5f93a...b20cbc )
by Sat CFDI
05:30
created

generar_contabilidad()   B

Complexity

Conditions 1

Size

Total Lines 93
Code Lines 78

Duplication

Lines 0
Ratio 0 %

Importance

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