Skip to content

Commit db1e20c

Browse files
committed
Update Contabilidad
1 parent 476fed7 commit db1e20c

13 files changed

+199
-128
lines changed

satcfdi/accounting/contabilidad.py

+96-69
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import os
22
from typing import Sequence
33

4+
from satcfdi.zip import zip_create, ZipData, zip_file
5+
6+
from satcfdi.catalogs import select, catalog_code
7+
48
from satcfdi.utils import iterate
59

610
from satcfdi.create.contabilidad.AuxiliarCtas13 import AuxiliarCtas, Cuenta, DetalleAux
@@ -29,21 +33,28 @@ def filename(file):
2933
raise ValueError(f"Unknown file type: {file.tag}")
3034

3135

32-
def output_file(file, folder, fiel=None, generate_pdf=False):
36+
def output_file(file, folder, fiel=None, generate_pdf=False, zip_xml=False):
3337
if fiel:
3438
file.sign(fiel)
3539

3640
output_file = os.path.join(folder, filename(file))
37-
file.xml_write(
38-
output_file,
39-
pretty_print=True,
40-
xml_declaration=True
41-
)
41+
if zip_xml:
42+
zip_file(output_file[:-4] + '.zip', [
43+
ZipData(
44+
filename(file),
45+
file.xml_bytes(xml_declaration=True)
46+
)
47+
])
48+
else:
49+
file.xml_write(
50+
output_file,
51+
pretty_print=True,
52+
xml_declaration=True
53+
)
54+
4255
if generate_pdf:
43-
# render.html_write(file, output_file[:-4] + ".html")
4456
render.pdf_write(file, output_file[:-4] + ".pdf")
4557
else:
46-
# delete file
4758
try:
4859
os.remove(output_file[:-4] + ".pdf")
4960
except FileNotFoundError:
@@ -52,40 +63,6 @@ def output_file(file, folder, fiel=None, generate_pdf=False):
5263
return output_file
5364

5465

55-
def calcular_saldos(cuentas, polizas):
56-
max_level = 1
57-
for c in cuentas.values():
58-
# c['SaldoIni'] = 0
59-
c['Debe'] = 0
60-
c['Haber'] = 0
61-
c['SaldoFin'] = 0
62-
max_level = max(max_level, c['Nivel'])
63-
64-
for p in polizas:
65-
for t in p["Transaccion"]:
66-
num_cta = t["NumCta"]
67-
cuenta = cuentas[num_cta]
68-
cuenta["Debe"] += t["Debe"]
69-
cuenta["Haber"] += t["Haber"]
70-
71-
# Fill Parents
72-
for level in range(max_level, 1, -1):
73-
for k, v in cuentas.items():
74-
if v['Nivel'] == level:
75-
parent = v['SubCtaDe']
76-
if parent:
77-
p_cuenta = cuentas[parent]
78-
p_cuenta['Debe'] += v['Debe']
79-
p_cuenta['Haber'] += v['Haber']
80-
81-
# Fill SaldoFin
82-
for c in cuentas.values():
83-
if c["Natur"] == "D":
84-
c["SaldoFin"] += c["SaldoIni"] + c["Debe"] - c["Haber"]
85-
else:
86-
c["SaldoFin"] += c["SaldoIni"] + c["Haber"] - c["Debe"]
87-
88-
8966
def generar_contabilidad(
9067
dp: DatePeriod,
9168
rfc_emisor: str,
@@ -98,8 +75,10 @@ def generar_contabilidad(
9875
numero_tramite=None,
9976
folder=None,
10077
fiel=None,
101-
generate_pdf=False):
102-
78+
generate_pdf=False,
79+
zip_xml=False
80+
):
81+
validate_cuentas(cuentas)
10382
validate_polizas(polizas)
10483
calcular_saldos(cuentas, polizas)
10584

@@ -112,15 +91,15 @@ def generar_contabilidad(
11291
num_tramite=numero_tramite,
11392
poliza=polizas
11493
)
115-
output_file(plz, folder, fiel, generate_pdf=generate_pdf)
94+
output_file(plz, folder, fiel, generate_pdf=generate_pdf, zip_xml=zip_xml)
11695

11796
cat = Catalogo(
11897
rfc=rfc_emisor,
11998
mes=str(dp.month).zfill(2),
12099
anio=dp.year,
121100
ctas=[
122101
Ctas(
123-
cod_agrup=v["CodAgrup"].split("_")[0],
102+
cod_agrup=v["CodAgrup"],
124103
num_cta=k,
125104
desc=v["Desc"],
126105
nivel=v["Nivel"],
@@ -129,7 +108,7 @@ def generar_contabilidad(
129108
) for k, v in cuentas.items()
130109
]
131110
)
132-
cato = output_file(cat, folder, fiel)
111+
output_file(cat, folder, fiel, zip_xml=zip_xml)
133112

134113
ban = Balanza(
135114
rfc=rfc_emisor,
@@ -142,7 +121,7 @@ def generar_contabilidad(
142121
**v,
143122
} for k, v in cuentas.items() if v["SaldoIni"] or v["Debe"] or v["Haber"] or v["SaldoFin"]],
144123
)
145-
bano = output_file(ban, folder, fiel)
124+
output_file(ban, folder, fiel, zip_xml=zip_xml)
146125

147126
aux_detalles = group_aux_cuentas(polizas)
148127
aux = AuxiliarCtas(
@@ -162,7 +141,7 @@ def generar_contabilidad(
162141
) for k, v in cuentas.items() if k in aux_detalles
163142
]
164143
)
165-
output_file(aux, folder, fiel, generate_pdf=generate_pdf)
144+
output_file(aux, folder, fiel, generate_pdf=generate_pdf, zip_xml=zip_xml)
166145

167146
auxf = RepAuxFol(
168147
rfc=rfc_emisor,
@@ -173,11 +152,11 @@ def generar_contabilidad(
173152
num_tramite=numero_tramite,
174153
det_aux_fol=list(group_aux_folios(polizas))
175154
)
176-
output_file(auxf, folder, fiel, generate_pdf=generate_pdf)
155+
output_file(auxf, folder, fiel, generate_pdf=generate_pdf, zip_xml=zip_xml)
177156

178157
imprimir_contablidad(
179-
catalogo_cuentas=cato,
180-
balanza_comprobacion=bano,
158+
catalogo_cuentas=cat,
159+
balanza_comprobacion=ban,
181160
archivo_excel=os.path.join(folder, filename(ban)[:-4] + ".xlsx")
182161
)
183162

@@ -230,30 +209,45 @@ def group_aux_folios(polizas):
230209
)
231210

232211

212+
def validate_cuentas(cuentas):
213+
# validar cuentas
214+
for k, v in cuentas.items():
215+
assert k
216+
v['_Lowest'] = True
217+
assert v['Natur'] in ['A', 'D']
218+
if v['SubCtaDe']:
219+
assert v['SubCtaDe'] in cuentas, f"Parent account {v['SubCtaDe']} not found for {k}"
220+
v['Nivel'] = cuentas[v['SubCtaDe']]['Nivel'] + 1
221+
else:
222+
v['Nivel'] = 1
223+
224+
v['CodAgrup'] = catalog_code('Cb9f_c_CodAgrup', v['CodAgrup'])
225+
assert v['CodAgrup'].description, f"Unknown CodAgrup: {v['CodAgrup']}"
226+
227+
for k, v in cuentas.items():
228+
if v['SubCtaDe']:
229+
cuentas[v['SubCtaDe']]['_Lowest'] = False
230+
231+
232+
def sign(cta):
233+
if cta['Natur'] == 'D':
234+
return 1
235+
return -1
236+
237+
233238
def validate_saldos(cuentas):
234-
total = 0
235239
totales = {}
236240
for k, v in cuentas.items():
237-
if v['Nivel'] == 1:
238-
if v['Natur'] == 'D':
239-
total += v['SaldoFin']
240-
else:
241-
total -= v['SaldoFin']
242-
else:
243-
totales.setdefault(v['SubCtaDe'], 0)
244-
if v['Natur'] == 'D':
245-
totales[v['SubCtaDe']] += v['SaldoFin']
246-
else:
247-
totales[v['SubCtaDe']] -= v['SaldoFin']
241+
sub_cta = v.get('SubCtaDe')
242+
totales.setdefault(sub_cta, 0)
243+
totales[sub_cta] += v['SaldoFin'] * sign(v)
248244

249-
assert total == 0
250245
for k, v in totales.items():
251-
if cuentas[k]['Natur'] == 'D':
252-
if v != cuentas[k]['SaldoFin']:
246+
if k:
247+
if v != cuentas[k]['SaldoFin'] * sign(cuentas[k]):
253248
raise ValueError(f"Error in {k}: {v} != {cuentas[k]['SaldoFin']}")
254249
else:
255-
if v != -cuentas[k]['SaldoFin']:
256-
raise ValueError(f"Error in {k}: {v} != {cuentas[k]['SaldoFin']}")
250+
assert v == 0
257251

258252

259253
def validate_polizas(polizas):
@@ -263,3 +257,36 @@ def validate_polizas(polizas):
263257
if u in num_un:
264258
raise ValueError(f"Repeated NumUnIdenPol: {u}")
265259
num_un.add(u)
260+
261+
262+
def calcular_saldos(cuentas, polizas):
263+
max_level = 1
264+
for c in cuentas.values():
265+
# c['SaldoIni'] = 0
266+
c['Debe'] = 0
267+
c['Haber'] = 0
268+
c['SaldoFin'] = 0
269+
max_level = max(max_level, c['Nivel'])
270+
271+
for p in polizas:
272+
for t in p["Transaccion"]:
273+
num_cta = t["NumCta"]
274+
cuenta = cuentas[num_cta]
275+
assert cuenta["_Lowest"], f"Account {num_cta} is not a lowest level account"
276+
cuenta["Debe"] += t["Debe"]
277+
cuenta["Haber"] += t["Haber"]
278+
279+
# Fill Parents
280+
for level in range(max_level, 1, -1):
281+
for k, v in cuentas.items():
282+
if v['Nivel'] == level:
283+
parent = v['SubCtaDe']
284+
if parent:
285+
p_cuenta = cuentas[parent]
286+
p_cuenta['Debe'] += v['Debe']
287+
p_cuenta['Haber'] += v['Haber']
288+
289+
# Fill SaldoFin
290+
for c in cuentas.values():
291+
s = sign(c)
292+
c["SaldoFin"] += c["SaldoIni"] + c["Debe"] * s - c["Haber"] * s

satcfdi/accounting/contabilidad_print.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,8 @@ def imprimir_contablidad(
2222
balanza_comprobacion,
2323
archivo_excel
2424
):
25-
ct = CFDI.from_file(catalogo_cuentas)
26-
bc = CFDI.from_file(balanza_comprobacion)
27-
# ct = catalogo_cuentas
28-
# bc = balanza_comprobacion
25+
ct = catalogo_cuentas
26+
bc = balanza_comprobacion
2927

3028
ctas = {
3129
c['NumCta']: {

satcfdi/zip.py

+18-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
def zip_create(target: io.BytesIO, files: list[ZipData]):
99
p = target.tell()
1010

11-
for f in files:
12-
with ZipFile(target, "w") as myzip:
11+
with ZipFile(target, "w") as myzip:
12+
for f in files:
1313
zinfo = ZipInfo(
1414
filename=f.filename
1515
)
@@ -24,3 +24,19 @@ def zip_create(target: io.BytesIO, files: list[ZipData]):
2424

2525
with target.getbuffer() as view: # change zip flag bytes
2626
view[p + 6:p + 8] = b"\x08\x08"
27+
28+
29+
def zip_file(zipfile, files: list[ZipData]):
30+
# Create a ZipFile object in write mode
31+
with ZipFile(zipfile, 'w') as zipf:
32+
# Add the input file to the zip archive with its base name
33+
for f in files:
34+
zinfo = ZipInfo(
35+
filename=f.filename,
36+
# date_time=datetime_to_tuple(datetime.now())
37+
)
38+
zinfo.compress_type = 8
39+
zinfo.create_system = 0
40+
41+
with zipf.open(zinfo, 'w') as stream:
42+
stream.write(f.data)

tests/contabilidad_electronica/cuentas.yaml

-7
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
Desc: Activos
44
Natur: D
55
CodAgrup: '100' # Activo
6-
Nivel: 1
76
SubCtaDe:
87
SaldoIni: 0
98

@@ -13,21 +12,18 @@
1312
Desc: Bancos
1413
Natur: D
1514
CodAgrup: '102' # Bancos nacionales
16-
Nivel: 2
1715
SubCtaDe: '1000'
1816
SaldoIni: 0
1917
'1020.01':
2018
Desc: Bancos Nacionales
2119
Natur: D
2220
CodAgrup: '102.01' # Bancos nacionales
23-
Nivel: 2
2421
SubCtaDe: '1020'
2522
SaldoIni: 0
2623
'1020.02':
2724
Desc: Bancos Extranjeros
2825
Natur: D
2926
CodAgrup: '102.02' # Bancos extranjeros
30-
Nivel: 2
3127
SubCtaDe: '1020'
3228
SaldoIni: 0
3329

@@ -36,20 +32,17 @@
3632
Desc: Clientes
3733
Natur: D
3834
CodAgrup: '105' # Clientes
39-
Nivel: 2
4035
SubCtaDe: '1000'
4136
SaldoIni: 0
4237
'1050.01':
4338
Desc: Clientes Nacionales
4439
Natur: D
4540
CodAgrup: '105.01' # Clientes nacionales
46-
Nivel: 2
4741
SubCtaDe: '1050'
4842
SaldoIni: 0
4943
'1050.02':
5044
Desc: Clientes Extranjeros
5145
Natur: D
5246
CodAgrup: '105.02' # Clientes extranjeros
53-
Nivel: 2
5447
SubCtaDe: '1050'
5548
SaldoIni: 0

0 commit comments

Comments
 (0)