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
|
|
|
|