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