forked from jonathanf/gdimm2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwndDeclaracion.py
441 lines (346 loc) · 16.2 KB
/
wndDeclaracion.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
#!/usr/bin/env python
# -*- coding: utf-8 -*-
###
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
###
import os, sys
import ezGlade
try:
from lxml import etree
except:
print 'Se requiere lxml'
sys.exit(1)
try:
import pygtk
pygtk.require("2.0")
except:
pass
try:
import gtk
import gtk.glade
except:
sys.exit(1)
import configuration
from ref_data import RefData
from calc import Calculator
from val import Validator
from utils import *
ezGlade.set_file(configuration.GLADE_FILE)
class wndDeclaracion(ezGlade.BaseWindow):
widget_container = dict()
xml = None
declaracion = None
ref_data = None
calcs = None
validations = None
def set_declaracion(self, declaracion):
self.declaracion = declaracion
self.calcs = Calculator()
if not self.calcs.load_xml(self.declaracion.get_version()):
ezGlade.DialogBox("ERROR: No se pudo cargar el XML de cálculos para " + self.declaracion.get_version(), "error")
self.calcs = None
return
self.validations = Validator()
if not self.validations.load_xml(self.declaracion.get_version()):
ezGlade.DialogBox("ERROR: No se pudo cargar el XML de validaciones para " + self.declaracion.get_version(), "error")
self.validations = None
return
self.calcs.load_xsl('calculos.xsl')
self.validations.load_xsl('validaciones.xsl')
def load_widget_contribuyente(self, number, text, width, height, left, top, tooltip):
entry = gtk.Entry(max=0)
entry.set_size_request(width, height)
entry.set_tooltip_text(tooltip)
entry.set_editable(False)
entry.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse("#cccccc")) # color deshabilitado ;)
entry.set_text(text)
entry.set_property('xalign', 1)
self.fixed1.put(entry, left, top)
self.widget_container[number] = entry
entry.show()
def load_combo_custom_data(self, number, value, width, height, left, top, tooltip, lista_datos):
combo = gtk.combo_box_new_text()
combo.set_size_request(width, height)
combo.set_tooltip_text(tooltip)
list_store = gtk.ListStore(str, str)
combo.set_model(list_store)
for code, name in lista_datos:
if value == code :
list_store.append([name, code])
combo.set_active(0)
self.fixed1.put(combo, left, top)
self.widget_container[number] = combo
combo.show()
def load_combo_contribuyente(self, number, value, width, height, left, top, tooltip, ref_table):
combo = gtk.combo_box_new_text()
combo.set_size_request(width, height)
combo.set_tooltip_text(tooltip)
if ref_table != "-1":
list_store = gtk.ListStore(str, str)
combo.set_model(list_store)
lista_datos = self.ref_data.get_data_list(ref_table)
for code, name in lista_datos:
if value == code :
list_store.append([name, code])
combo.set_active(0)
self.fixed1.put(combo, left, top)
self.widget_container[number] = combo
combo.show()
def load_widgets_from_xml(self):
contribuyente = self.declaracion.get_contribuyente()
if contribuyente is None:
ezGlade.DialogBox("No existen datos del contribuyente", "error")
return
tree = etree.parse(os.path.join('XML','CMPFRM.xml'))
version = self.declaracion.get_codigo_version()
if version is None:
ezGlade.DialogBox("Código de formulario no definido", "error")
return
form = tree.find("version[@codigo='"+version+"']")
if form is None:
ezGlade.DialogBox("Error al cargar el formulario", "error")
return
self.widget_container = dict()
scale = 10
start_top = 1100
for c in form:
numero = str(int(c.attrib.get("numero"))) # se eliminan ceros de la izq
top = (int(c.attrib.get("top")) - start_top ) / scale
left = int(c.attrib.get("left")) / scale
width = int(c.attrib.get("width")) / scale
height = int(c.attrib.get("height")) / scale
label = c.attrib.get("etiqueta")
editable = c.attrib.get("editable")
tablaReferencial = c.attrib.get("tablaReferencial")
mensajeAyuda = c.attrib.get("mensajeAyuda")
tipoControl = c.attrib.get("tipoControl")
colorLetra = c.attrib.get("colorLetra")
# campos escritos desde la configuracion
if numero in [ '101', '102', '198', '199', '201', '202', '31', '104' ]:
if numero == '202': # razon social
self.load_widget_contribuyente(numero, contribuyente.get_nombre(), width, height, left, top, mensajeAyuda)
elif numero == '201': # RUC
self.load_widget_contribuyente(numero, contribuyente.get_ruc(), width, height, left, top, mensajeAyuda)
elif numero == '101': # mes
self.load_combo_contribuyente(numero, self.declaracion.get_mes(), width, height, left, top, mensajeAyuda, tablaReferencial)
elif numero == '102': # año
self.load_combo_contribuyente(numero, self.declaracion.get_anio(), width, height, left, top, mensajeAyuda, tablaReferencial)
elif numero == '198': # cedula rep. legal
self.load_widget_contribuyente(numero, contribuyente.get_documento(), width, height, left, top, mensajeAyuda)
elif numero == '199': # RUC contador NULO
self.load_widget_contribuyente(numero, "", width, height, left, top, mensajeAyuda)
elif numero == '31': # original o sustitutiva
self.load_combo_custom_data(numero, self.declaracion.get_original(), width, height, left, top, mensajeAyuda, self.ref_data.get_ori_sus())
elif numero == '104': # formulario sustituye
self.load_widget_contribuyente(numero, self.declaracion.get_sustituye(), width, height, left, top, mensajeAyuda)
continue
if tipoControl == "L": # etiqueta
lbl = gtk.Label(label)
color = RGBToHTMLColor(int(colorLetra))
lbl.set_markup('<span color="'+color+'">'+label+'</span>');
self.fixed1.put(lbl, left, top)
lbl.show()
elif tipoControl in ["T", 'M']: # caja de texto
entry = gtk.Entry(max=0)
entry.set_size_request(width, height)
entry.set_tooltip_text(mensajeAyuda)
if editable != "SI":
entry.set_editable(False)
entry.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse("#cccccc")) # color deshabilitado ;)
if tipoControl == "T":
entry.set_text("")
else:
entry.set_text("0")
entry.set_property('xalign', 1)
self.fixed1.put(entry, left, top)
entry.connect("key-release-event", self._onTabKeyReleased) # bind TAB event
self.widget_container[numero] = entry
entry.show()
elif tipoControl == "C":# combo
combo = gtk.combo_box_new_text()
combo.set_size_request(width, height)
combo.set_tooltip_text(mensajeAyuda)
if numero == '921':
combo.connect("changed", self._cmdBancos_changed) # binds change event
if tablaReferencial != "-1":
list_store = gtk.ListStore(str, str)
combo.set_model(list_store)
# llenar combo segun datos referenciales
if numero in ['238', '219', '222', '243'] :
lista_datos = self.ref_data.get_data_list_2(tablaReferencial)
else:
lista_datos = self.ref_data.get_data_list(tablaReferencial)
if not len(lista_datos):
ezGlade.DialogBox("Error al cargar tabla referencial " + str(tablaReferencial) + ' del campo ' + str(numero), "error")
for code, name in lista_datos:
list_store.append([name, code])
combo.set_active(0)
self.fixed1.put(combo, left, top)
self.widget_container[numero] = combo
combo.show()
# poner el titulo de la ventana
title = self.wndDeclaracion.get_title()
self.wndDeclaracion.set_title(title + self.declaracion.get_alias_formulario())
ezGlade.DialogBox("Use TAB para desplazarse por las celdas", "info", self.win)
def _cmdBancos_changed(self, widget, *args):
""" Metodo disparado al cambiar la seleccion de la forma de pago """
if not "922" in self.widget_container:
return
widget2 = self.widget_container["922"]
aiter = widget.get_active_iter()
model = widget.get_model()
if aiter is None:
return
if model.get_value(aiter, 1) != "3":
widget2.set_active(0)
return
# usar item codigo 89 = Declaraciones en cero
biter = widget2.get_active_iter()
bmodel = widget2.get_model()
index = 0
biter = bmodel.get_iter_first()
while biter :
if bmodel.get_value(biter, 1) == "89":
break
biter = bmodel.iter_next(biter)
index += 1
widget2.set_active(index)
def post_init(self):
self.ref_data = RefData()
self.wndDeclaracion.maximize()
def push_statusbar_info(self, text):
context_id = self.statusbar.get_context_id("Statusbar context")
self.statusbar.push(context_id, text)
def generate_xml_from_container(self):
self.xml = None
root = etree.Element("formulario")
root.set('version', '0.2' )
cabecera = etree.SubElement(root, "cabecera")
codigo_version_formulario = etree.SubElement(cabecera, "codigo_version_formulario")
codigo_version_formulario.text = self.declaracion.get_codigo_version()
ruc = etree.SubElement(cabecera, "ruc")
ruc.text = self.declaracion.get_contribuyente().get_ruc()
codigo_moneda = etree.SubElement(cabecera, "codigo_moneda")
codigo_moneda.text = '1'
detalle = etree.SubElement(root, "detalle")
for num, obj in self.widget_container.iteritems():
if obj.__class__ is gtk.Entry:
campo = etree.SubElement(detalle, "campo")
campo.set('numero', num )
campo.text = str(obj.get_text())
elif obj.__class__ is gtk.ComboBox:
campo = etree.SubElement(detalle, "campo")
campo.set('numero', num )
aiter = obj.get_active_iter()
model = obj.get_model()
if aiter is not None:
campo.text = str(model.get_value(aiter, 1))
else:
print 'Iterador nulo para', num
campo.text = '0'
self.xml = root
def do_validations(self):
if self.validations is None:
ezGlade.DialogBox("ERROR: El motor de validaciones no fué creado.", "error")
return
self.generate_xml_from_container()
self.do_calculations()
self.validations.validate(self.xml)
validations = self.validations.get_validations()
return validations
def update_container_from_xml(self, xml):
self.xml = xml
for num, obj in self.widget_container.iteritems():
if obj.__class__ is gtk.Entry:
campo = self.xml.find('detalle/campo[@numero="'+str(num)+'"]')
if campo.text is not None:
obj.set_text(campo.text)
def do_calculations(self):
if self.calcs is None:
ezGlade.DialogBox("ERROR: El motor de cálculos no fué creado.", "error")
return
self.calcs.calc(self.xml)
calculations = self.calcs.get_calculations()
# se modifica el valor del widget y el XML con el valor calculado por la XSLT
for item in calculations:
widget = self.widget_container[item['campo']]
campo = self.xml.find('detalle/campo[@numero="'+item['campo']+'"]')
campo.text = item['calculo']
if widget.__class__ is gtk.Entry:
widget.set_text(item['calculo'])
def _onTabKeyReleased(self, widget, event, *args):
if event.keyval == gtk.keysyms.Tab:
self.generate_xml_from_container()
self.do_calculations()
return True
def on_btnCancelar_clicked(self, widget, *args):
# verificar si se han guardado los cambios!!!
error_dlg = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, message_format="Los datos no guardados se perderán. Salir?", buttons=gtk.BUTTONS_OK_CANCEL)
if error_dlg.run() == gtk.RESPONSE_OK:
self.win.destroy()
error_dlg.destroy()
def _generar_nombre_archivo(self):
alias = self.declaracion.get_alias_formulario()
filename = alias
if self.declaracion.get_original():
filename += 'ORI_'
else:
filename += 'SUS_'
if self.declaracion.get_periodicidad() == "SEMESTRAL":
mes = self.ref_data.get_semestre_por_codigo(self.declaracion.get_mes())
elif self.declaracion.get_periodicidad() == "MENSUAL":
mes = self.ref_data.get_mes_por_codigo(self.declaracion.get_mes())
mes = mes[:3]
else:
mes = ''
filename += mes + str(self.declaracion.get_anio())
return filename
def on_btnGuardar_clicked(self, widget, *args):
validations = self.do_validations()
text = "El formulario presenta los siguientes errores: \n\n"
for item in validations:
text += item['severidad'] + ': ' + item['error'] + "\n"
text += "\nDesea continuar de todas formas? \n"
if len(validations):
error_dlg = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, message_format=text, buttons=gtk.BUTTONS_OK_CANCEL)
if error_dlg.run() != gtk.RESPONSE_OK:
error_dlg.destroy()
return
error_dlg.destroy()
if self.declaracion.get_archivo() is not None:
curr_file = self.declaracion.get_archivo()
f = open(curr_file, 'w+')
f.write(etree.tostring(self.xml, encoding='utf8', pretty_print=True))
f.close()
return
dialog = gtk.FileChooserDialog("Guardar ...", None, gtk.FILE_CHOOSER_ACTION_SAVE, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK))
dialog.set_default_response(gtk.RESPONSE_OK)
dialog.set_current_name(self._generar_nombre_archivo())
dialog.set_current_folder(os.path.join('XML_Declaraciones'))
filter = gtk.FileFilter()
filter.set_name("Archivos XML")
filter.add_mime_type("application/xml")
filter.add_pattern("*.xml")
dialog.add_filter(filter)
response = dialog.run()
if response == gtk.RESPONSE_OK:
outfile = dialog.get_filename() # archivo destino
outfile = outfile + '.xml'
f = open(outfile, 'w+')
f.write(etree.tostring(self.xml, encoding='utf8', pretty_print=True))
f.close()
self.declaracion.set_archivo(outfile)
dialog.destroy()