def parse_consumos(fconsumos): """ Abre el fichero y parsea los consumos devolviendo un diccionario de productos y la cantidad de cada uno que ha salido del almacén para consumirse en la línea. """ res = {} for qlty in ("A", "B", "C", "total"): res[qlty] = defaultdict(lambda: 0.0) f_in = open(fconsumos) data_in = reader(f_in, delimiter=";", lineterminator="\n") cabecera = True # La primera fila son los títulos de columnas for linea in data_in: if cabecera: cabecera = False continue producto, cantidad, cant_a, cant_b, cant_c = linea[:5] try: cons_a = utils.parse_float(cant_a) cons_b = utils.parse_float(cant_b) cons_c = utils.parse_float(cant_c) except ValueError: # No aplicable. Son productos de compra. cons_a = cons_b = cons_c = 0.0 consumos = utils.parse_float(cantidad) res["A"][producto] += cons_a res["B"][producto] += cons_b res["C"][producto] += cons_c res["total"][producto] += consumos f_in.close() return res
def cell_func2(column, cell, model, itr): p = utils.parse_float(model[itr][2]) m = utils.parse_float(model[itr][4]) if p < m: color = "red" elif p > m: color = "green" else: color = "blue" cell.set_property("foreground", color)
def cambiar_peso(self, cell, path, texto): """ Cambia el peso de la bala editada. """ try: peso = utils._float(texto) except ValueError: utils.dialogo_info(titulo = "ERROR", texto = "El valor tecleado %s no es correcto." % (peso), padre = self.wids['ventana']) else: model = self.wids['tv_balas'].get_model() try: bala = pclases.BalaCable.get(model[path][-1]) except: utils.dialogo_info(titulo = "ERROR", texto = "No se pudo acceder a la bala.", padre = self.wids['ventana']) self.actualizar_tabla() else: difpeso = bala.peso - peso bala.peso = peso bala.syncUpdate() model[path][2] = utils.float2str(bala.peso, 1) try: totpantalla = utils.parse_float( self.wids['e_pantalla'].get_text()) except: totpantalla = 0.0 totpantalla -= difpeso self.rellenar_totales(totpantalla)
def to_float(t, sensibilidad = 2): """ Si t es una cadena de texto con el símbolo del euro o de metros cuadrados, convierte todo lo que puede a flotante con técnica "greedy". En otro caso lanza una excepción ValueError al igual que hace el _float de utils. sensibilidad es un parámetro para evitar falsos positivos. Si en la cadena hay un cierto número de palabras (2 por defecto) entonces no convierte a número flotante. """ if isinstance(t, (int, float)): return float(t) from string import digits as numeros palabras = [] for p in t.split(): if p[0] not in numeros: palabras.append(p) if len(palabras) >= sensibilidad: raise ValueError simbolos = ("€", "m²", " m", " kg", " k") for s in simbolos: if s in t: res = utils.parse_float(t[:t.index(s)]) return res raise ValueError
def build_gdata(model_fibra, model_gtx, model_otros): """ Devuelve una lista de días y la demanda de los productos previstos para esa fecha. La demanda se calcula como las existencias iniciales menos las cantidades pedidas acumuladas por los pedidos de la consulta. La cifra final es la suma de la demanda de todos los productos para ese día. """ # PLAN: Para que esto fuera útil de verdad necesitaría que los pedidos # llevaran fecha de entrega y que la planificación de las líneas se # metiera en el programa. from collections import defaultdict res = defaultdict(lambda: 0) productos = {} # Existencias iniciales de los productos actualizada # con la demanda de cada pedido. for model, ffecha, fproducto, fcantidad in ((model_fibra, 1, 3, 4), (model_gtx, 1, 3, 5), (model_otros, 1, 3, 4)): for fila in model: # Debería ordenaro por día... ¿no? fecha = utils.parse_fecha(fila[1]) producto = fila[3] while (producto.startswith("-") or producto.startswith(">") or producto.startswith(" ")): producto = producto[1:] try: cantidad = utils.parse_float(fila[5]) except ValueError: # caso "-4.848." ¿punto como unidad? WTF? cantidad = utils.parse_float(fila[5][:-1]) try: demanda = productos[producto] - cantidad except KeyError: try: productodb = pclases.ProductoVenta.selectBy( descripcion=producto)[0] stockdb = productodb.get_stock_A() except IndexError: # Es producto "de compra" productodb = pclases.ProductoCompra.selectBy( descripcion=producto)[0] stockdb = productodb.get_stock() productos[producto] = stockdb - cantidad res[fecha] += productos[producto] fechas = res.keys() fechas.sort() gdata = [] for f in fechas: gdata.append("[ new Date(%d, %d, %d), %f ]" % (f.year, f.month, f.day, res[f])) return gdata
def parse_existencias(fexistencias_ini, res=None): """ Abre el CSV de existencias y devuelve un diccionario de productos con sus existencias. """ if not res: res = {} for qlty in ("A", "B", "C", "total"): res[qlty] = defaultdict(lambda: 0.0) f_in = open(fexistencias_ini) data_in = reader(f_in, delimiter=";", lineterminator="\n") cabecera = True # La primera fila son los títulos de columnas for linea in data_in: if cabecera: cabecera = False continue try: (producto, kg_a, m_a, b_a, kg_b, m_b, b_b, kg_c, m_c, b_c, kg_total, m_total, b_total) = linea stock_a = utils.parse_float(m_a) stock_b = utils.parse_float(m_b) try: stock_c = utils.parse_float(m_c) except ValueError: # No lleva metros de C. Geotextiles C en kg. stock_c = m_c total = utils.parse_float(m_total) if total == 0.0: # Puede que sea un producto C. No lo puedo # saber únicamente por los datos de la hoja de cálculo. Uso # como total los kg. En el caso de los geotextiles normales # será también cero. No pasa nada. Solo habré perdido tiempo # parseando el valor. Pero si se mide en kg como los C, # entonces es el valor que me interesa. total = utils.parse_float(kg_total) except ValueError: # Es el listado de fibra. No lleva metros. (producto, kg_a, b_a, kg_b, b_b, kg_c, b_c, kg_total, b_total) = linea stock_a = utils.parse_float(kg_a) stock_b = utils.parse_float(kg_b) stock_c = utils.parse_float(kg_c) total = utils.parse_float(kg_total) res["A"][producto] += stock_a res["B"][producto] += stock_b try: res["C"][producto] += stock_c except TypeError: # Viene un "No Aplicable" pass res["total"][producto] += total f_in.close() return res
def volcar_a_tv(self, filas, vpro, padres, model): i = 0.0 nodos_conceptos = {} for concepto in filas: vpro.set_valor(i / len(filas.keys()), "Montando matriz...") pa = concepto.presupuestoAnual nodo_padre = padres[pa] fila = [concepto.descripcion] + filas[concepto] + [concepto.puid] nodos_conceptos[concepto] = model.append(nodo_padre, fila) for mes_matriz in range(1, 13): try: model[nodo_padre][mes_matriz] = utils.float2str( utils.parse_float(model[nodo_padre][mes_matriz]) + utils.parse_float(fila[mes_matriz])) except (TypeError, ValueError): model[nodo_padre][mes_matriz] = utils.float2str( utils.parse_float(fila[mes_matriz])) i += 1
def crear_fake_treeview(tvorig, filtro = lambda fila: fila[4] == "-" and fila or None): """ Crea un TreeView idéntico al recibido (model clonado, mismas columnas y cabeceras, etc.). «filtro» debe ser una función que devuelve la fila filtrada o None si no debe incluirse en el nuevo TreeView. """ tv = gtk.TreeView() tv.set_name(tvorig.get_name()) modelorig = tvorig.get_model() cols = [] origcols = tvorig.get_columns() colsnulas = [] anchos = [] aligns = [] for col, i in zip(origcols, range(len(origcols))): cols.append((col.get_title(), "gobject.TYPE_STRING", # STRING se lo traga todo. Premio # especial del jurado de los AVN Awards 2015. False, False, False, None)) anchos.append(col.get_width()) aligns.append(col.get_cell_renderers()[0].get_property("xalign")) cols.append(("ID", "gobject.TYPE_STRING", False, False, False, None)) utils.preparar_treeview(tv, cols) for col, align in zip(tv.get_columns(), aligns): col.get_cell_renderers()[0].set_property("xalign", align) model = tv.get_model() for padre in modelorig: producto = pclases.ProductoVenta.get(padre[-1]) try: ancho_estandar = producto.camposEspecificosRollo.ancho except AttributeError: ancho_estandar = 1 iterpadre = model.append(None, padre) total_metros = 0.0 for fila in modelorig[padre.iter].iterchildren(): _fila = filtro(fila) if _fila: model.append(iterpadre, fila) total_metros += utils.parse_float(fila[5]) model[iterpadre][5] = total_metros * ancho_estandar return tv
def crear_bala(self, boton = None, peso = None): """ Crea una bala del producto mostrado en pantalla e introduce su información en el TreeView. El peso lo solicita en una ventana de diálogo. Si se recibe peso, debe ser un float. """ # TODO: Hacer que el peso lo tome del puerto serie y se le pase a # esta función. producto = utils.combo_get_value(self.wids['cbe_producto']) if producto == None: utils.dialogo_info(titulo = "SELECCIONE UN PRODUCTO", texto = "Debe seleccionar un producto en el desplegable.", padre = self.wids['ventana']) else: if peso == None: peso = utils.dialogo_entrada(titulo = "PESO", texto = "Introduzca peso:", padre = self.wids['ventana'], valor_por_defecto = "0") try: peso = utils._float(peso) except ValueError: utils.dialogo_info(titulo = "ERROR", texto = "El valor tecleado %s no es correcto." % peso, padre = self.wids['ventana']) peso = 0 except TypeError: # Ha cancelado return nueva_bala = self.crear_objeto_bala(producto, peso) if nueva_bala == None: utils.dialogo_info(titulo = "ERROR", texto = "La bala no se pudo crear. Verifique el peso " "e inténtelo de nuevo.", padre = self.wids['ventana']) else: self.add_nueva_bala_tv(nueva_bala) try: totpantalla = utils.parse_float( self.wids['e_pantalla'].get_text()) except: totpantalla = 0.0 totpantalla += peso self.rellenar_totales(totpantalla)
def cambiar_precio_defecto(self, cell, path, texto): # Chequeo permiso de escritura para camibar precios, existencias y demás: try: ventana = pclases.Ventana.select(pclases.Ventana.q.fichero == "productos.py")[0] if self.usuario and (not self.usuario.get_permiso(ventana).escritura or self.usuario.nivel >= 2): utils.dialogo_info(titulo = "USUARIO SIN PRIVILEGIOS", texto = "Necesita permiso de escritura para modificar el precio.", padre = self.wids['ventana']) return except IndexError: if self.usuario and self.usuario.nivel >= 2: utils.dialogo_info(titulo = "USUARIO SIN PRIVILEGIOS", texto = "No tiene permisos suficientes para modificar el precio.", padre = self.wids['ventana']) return model = self.wids['tv_datos'].get_model() ide = model[path][-1] try: precio = utils.parse_float(texto) except ValueError: utils.dialogo_info(titulo = "ERROR DE FORMATO", texto = "El texto %s no es correcto." % (texto), padre = self.wids['ventana']) else: if "PC" in model[path][0]: producto = pclases.ProductoCompra.get(ide) elif "PV" in model[path][0]: producto = pclases.ProductoVenta.get(ide) else: return for numcol in range(5, 5 + len(self.__tarifas)): tarifa = self.__tarifas[numcol - 5] porcentaje = tarifa.get_porcentaje(producto, True) precio_tarifa = precio * (1 + porcentaje) tarifa.asignarTarifa(producto, precio_tarifa) precio_tarifa *= 1.21 porcentaje *= 100.0 model[path][numcol] = "%s (%s %%)" % (utils.float2str(precio_tarifa), utils.float2str(porcentaje, 1)) producto.sync() producto.precioDefecto = precio producto.syncUpdate() model[path][4] = utils.float2str(producto.precioDefecto)
def edit_float(cell, path, newtext, tv, numcol, clase, atributo): """ Cambia el texto del model[path][numcol] y del objeto relacionado que saca a partir del ID de la última columna del model. """ try: numero = utils.parse_float(newtext) except (ValueError, TypeError): parent = tv.parent while parent != None: parent = parent.parent utils.dialogo_info(titulo = "ERROR EN NÚMERO", texto = "El texto «%s» no es un número válido." % (newtext), padre = parent) else: model = tv.get_model() ide = model[path][-1] objeto = clase.get(ide) setattr(objeto, atributo, numero) objeto.syncUpdate() model[path][numcol] = utils.float2str(getattr(objeto, atributo), autodec = True)
def cambiar_existencias(self, cell, path, texto): # Chequeo permiso de escritura para camibar precios, existencias y # demás: try: ventana = pclases.Ventana.select( pclases.Ventana.q.fichero == "productos.py")[0] if self.usuario and ( not self.usuario.get_permiso(ventana).escritura or self.usuario.nivel >= 2): utils.dialogo_info(titulo = "USUARIO SIN PRIVILEGIOS", texto = "Necesita permiso de escritura " "para modificar las existencias.", padre = self.wids['ventana']) return except IndexError: if self.usuario and self.usuario.nivel >= 2: utils.dialogo_info(titulo = "USUARIO SIN PRIVILEGIOS", texto = "No tiene permisos suficientes " "para modificar las existencias.", padre = self.wids['ventana']) return model = self.wids['tv_datos'].get_model() ide = model[path][-1] try: existencias = utils.parse_float(texto) except ValueError: utils.dialogo_info(titulo = "ERROR DE FORMATO", texto = "El texto %s no es correcto." % (texto), padre = self.wids['ventana']) else: if "PC" in model[path][0]: producto = pclases.ProductoCompra.get(ide) producto.sync() #producto.existencias = existencias producto.set_existencias(existencias) producto.syncUpdate() model[path][3] = utils.float2str(producto.existencias)
def comparar_float(self, col): res = 0.0 try: valor_ventana = self.wids[col].get_text() except KeyError: txt_error = "empleados.py: No se pudo obtener el valor de la "\ "ventana para %s." % col myprint(txt_error) self.logger.error(txt_error) valor_ventana = 0.0 try: valor_ventana = utils.parse_float(valor_ventana) except ValueError: txt_error = "empleados.py: No se pudo convertir %s(%s) a "\ "float." % (col, valor_ventana) myprint(txt_error) self.logger.error(txt_error) valor_ventana = 0.0 try: valor_campo = self.objeto._SO_getValue(col) if not isinstance(valor_campo, type(0.0)): # Porque es posible # que el SOCol no contenga un float. El SOCol es la clase # base. Se asume flotante por eliminación. O, escucha que te # diga, o que sea un decimal.Decimal try: valor_campo = utils._float(valor_campo) except TypeError: res = False res = valor_ventana == valor_campo except KeyError: txt_error = "empleados.py: No se pudo obtener el valor del "\ "objeto para %s." % col myprint(txt_error) self.logger.error(txt_error) valor_campo = 0.0 return res
def guardar(self, widget): """ Guarda el contenido de los entry y demás widgets de entrada de datos en el objeto y lo sincroniza con la BD. """ producto = self.objeto codigo = self.wids['e_codigo'].get_text() if len(codigo) < 12: utils.dialogo_info(titulo = "CÓDIGO DEMASIADO CORTO", texto = "El código debe tener 13 dígitos para ajustarse al formato EAN-13.\nSe va a completar con ceros.", padre = self.wids['ventana']) codigo += "0" * (12 - len(codigo)) # Completo hasta 12 para que después se le haga la suma de control. if len(codigo) == 12: codigo = codigo + self.calcular_digitoc(codigo) if len(codigo) > 13: utils.dialogo_info(titulo = "CÓDIGO INCORRECTO", texto = "Código EAN-13 incorrecto. Debe tener exactamente 13 dígitos.\nPuede introducir 12 y dejar que se calcule atomáticamente el dígito de control, si le es más cómodo.\n\nA continuación se va a recortar el código a 13 dígitos y se intentará comprobar la suma de control.", padre = self.wids['ventana']) codigo = codigo[:13] if len(codigo) == 13: digitocontrol = self.calcular_digitoc(codigo[:12]) if codigo[12] != digitocontrol: utils.dialogo_info(titulo = "FALLÓ SUMA DE COMPROBACIÓN", texto = "El dígito de control no es correcto. Se corregirá automáticamente.", padre = self.wids['ventana']) codigo = codigo[:12] + digitocontrol descripcion = self.wids['e_descripcion'].get_text() # idlinea Un producto pertenece a una línea, no se puede cambiar nombre = self.wids['e_nombre'].get_text() arancel = self.wids['e_arancel'].get_text() try: precio = utils.parse_float(self.wids['e_precio'].get_text()) except ValueError: precio = producto.preciopordefecto try: minimo = utils.parse_float(self.wids['e_minimo'].get_text()) except ValueError: minimo = producto.minimo try: stock = utils.parse_float(self.wids['e_stock'].get_text()) except ValueError: stock = producto.camposEspecificosEspecial.stock try: existencias = int(self.wids['e_existencias'].get_text()) except: existencias = producto.camposEspecificosEspecial.existencias # TODO: Falta ajustar los almacenes a la nueva cantidad en existencias. unidad = self.wids['e_unidad'].get_text() observaciones = self.wids['e_observaciones'].get_text() # Desactivo el notificador momentáneamente producto.notificador.activar(lambda: None) producto.camposEspecificosEspecial.notificador.activar(lambda: None) # Actualizo los datos del objeto try: producto.codigo = codigo except psycopg_ProgrammingError: try: producto_asignado = pclases.ProductoVenta.select(pclases.ProductoVenta.q.codigo == codigo)[0] producto_asignado = producto_asignado.descripcion except IndexError: producto_asignado = "?" utils.dialogo_info(titulo = "CÓDIGO DUPLICADO", texto = "El código EAN %s no se encuentra disponible.\nActualmente está asignado a: %s" % (codigo, producto_asignado), padre = self.wids['ventana']) producto.descripcion = descripcion producto.nombre = nombre producto.preciopordefecto = precio producto.minimo = minimo producto.arancel = arancel producto.camposEspecificosEspecial.stock = stock producto.camposEspecificosEspecial.unidad = unidad producto.camposEspecificosEspecial.observaciones = observaciones producto.camposEspecificosEspecial.existencias = existencias try: self.objeto.obsoleto = self.wids['ch_obsoleto'].get_active() except (KeyError, AttributeError): pass # Versión antigua de la base de datos. # Fuerzo la actualización de la BD y no espero a que SQLObject lo haga por mí: producto.syncUpdate() # Vuelvo a activar el notificador producto.notificador.activar(self.aviso_actualizacion) producto.camposEspecificosEspecial.notificador.activar(self.aviso_actualizacion) self.actualizar_ventana() self.wids['b_guardar'].set_sensitive(False)
def parse_salidas(fsalidas_fib, fsalidas_gtx, fsalidas_cem): """ Abre cada fichero y parsea las salidas de almacén devolviendo un diccionario de productos y las salidas de cada uno EN SUS UNIDADES: kg para fibra y metros cuadrados para geotextiles. """ res = {} for qlty in ("A", "B", "C", "total"): res[qlty] = defaultdict(lambda: 0.0) for fname in fsalidas_fib, fsalidas_gtx, fsalidas_cem: f_in = open(fname) data_in = reader(f_in, delimiter=";", lineterminator="\n") cabecera = True # La primera fila son los títulos de columnas for linea in data_in: if cabecera: cabecera = False continue try: (producto, m_a, kg_a, b_a, m_b, kg_b, b_c, m_c, kg_c, b_c, m_total, kg_total, b_total) = linea es_gtx = True except ValueError: # Hay valores de menos. No es geotextiles. (producto, kg_a, b_a, kg_b, b_b, kg_c, b_c, kg_total, b_total) = linea es_gtx = False if es_gtx: salidas = utils.parse_float(m_total) # Caso especial para producto C. Se mide en Kg. En m_total # tendrá un cero. Otros productos normales también pueden # tener un cero en producción de metros, pero también lo # tendrán en la columna de kg producidos. So... if not salidas: sals_a = utils.parse_float(kg_a) sals_b = utils.parse_float(kg_b) sals_c = utils.parse_float(kg_c) salidas = utils.parse_float(kg_total) else: sals_a = utils.parse_float(m_a) sals_b = utils.parse_float(m_b) sals_c = utils.parse_float(m_c) else: sals_a = utils.parse_float(kg_a) sals_b = utils.parse_float(kg_b) sals_c = utils.parse_float(kg_c) salidas = utils.parse_float(kg_total) res["A"][producto] += sals_a res["B"][producto] += sals_b res["C"][producto] += sals_c res["total"][producto] += salidas f_in.close() return res
def parse_produccion(fproduccion_fib, fproduccion_gtx, fproduccion_cem): """ Abre el fichero y devuelve un diccionario de productos con la producción. """ res = {} for qlty in ("A", "B", "C", "total"): res[qlty] = defaultdict(lambda: 0.0) for fproduccion in (fproduccion_fib, fproduccion_gtx, fproduccion_cem): f_in = open(fproduccion) data_in = reader(f_in, delimiter=";", lineterminator="\n") cabecera = True # La primera fila son los títulos de columnas for linea in data_in: if cabecera: cabecera = False continue try: (producto, m_a, m_b, m_c, m_total, kg_a, kg_teorico_a, kg_b, kg_teorico_b, kg_c, kg_total, b_a, b_b, b_c, b_total, t_teorico, t_real) = linea es_gtx = True except ValueError: # Hay valores de menos. No es geotextiles. (producto, kg_a, kg_b, kg_c, kg_total, b_a, b_b, b_c, b_total, t_teorico, t_real) = linea es_gtx = False if producto.startswith(">"): continue # Es un desglose. No me interesa. if producto == "Sin producción".encode("latin1"): continue # Es un resumen de tiempo sin producir. if es_gtx: try: prod_a = utils.parse_float(m_a) prod_b = utils.parse_float(m_b) prod_c = utils.parse_float(m_c) producido = utils.parse_float(m_total) # Caso especial para producto C. Se mide en Kg. En m_total # tendrá un cero. Otros productos normales también pueden # tener un cero en producción de metros, pero también lo # tendrán en la columna de kg producidos. So... if not producido: prod_a = utils.parse_float(kg_a) prod_b = utils.parse_float(kg_b) prod_c = utils.parse_float(kg_c) producido = utils.parse_float(kg_total) except ValueError: # Es una línea de resumen. continue else: prod_a = utils.parse_float(kg_a) prod_b = utils.parse_float(kg_b) prod_c = utils.parse_float(kg_c) producido = utils.parse_float(kg_total) res["A"][producto] += prod_a res["B"][producto] += prod_b res["C"][producto] += prod_c res["total"][producto] += producido f_in.close() return res
def treeview2pdf(tv, titulo = None, fecha = None, apaisado = None, pijama = False, graficos = [], numcols_a_totalizar = [], extra_data = []): """ A partir de un TreeView crea un PDF con su contenido. 1.- Asigna un nombre de archivo en función del nombre del TreeView. 2.- Si titulo es None, asigna como título el nombre del TreeView. 3.- El ancho de los campos será el ancho relativo en porcentaje que ocupa el ancho de la columna (get_width) a la que correspondería. El título del campo será el título (get_title) de la columna. 4.- Si fecha no es None debe ser una cadena de texto. Si es None, se usará la fecha actual del sistema. 5.- Si la suma del ancho de las columnas del TreeView es superior a 800 píxeles el PDF generado será apaisado, a no ser que se fuerce mediante el parámetro "apaisado" que recibe la función. numcols_a_totalizar es una lista de índices (empezando por 0) de las columnas a las que se va a intentar convertir a número y sumar para mostrar una última línea con el texto "TOTAL" o "TOTALES" si hay más de una. extra_data son líneas que se añadirán a las que tiene el TreeView *al final* del informe (incluso detrás de los totales, si los hubiera). """ archivo = get_nombre_archivo_from_tv(tv) if titulo == None: titulo = get_titulo_from_tv(tv) campos, pdf_apaisado, cols_a_derecha, cols_centradas=get_campos_from_tv(tv) datos = get_datos_from_tv(tv) totales = dict(zip(numcols_a_totalizar, len(numcols_a_totalizar) * [0])) for fila in datos: # Si es un TreeView solo sumaré los totales de primer # nivel. Los hijos se marcan con ">" al inicio del texto. try: if (fila and (fila[0].startswith(">") or ("]" in fila[0] and fila[0].split("]")[1].startswith(">")))): continue except (AttributeError, IndexError): pass # Aquí no ha pasado nada. for numcol in totales: # Primero hay que limpiar de formato el texto. valor_a_parsear = fila[numcol] try: valor_a_parsear = valor_a_parsear.split("]")[1] except IndexError: pass if valor_a_parsear in ("---", "==="): continue try: valor_a_sumar = utils.parse_float(valor_a_parsear) except ValueError: # ¿No hay dato en esa fila? Entonces cuento # instancias. valor_a_sumar = 1 #print fila, numcol, fila[numcol] if pclases.DEBUG: print "+", fila[numcol], "=", valor_a_sumar totales[numcol] += valor_a_sumar if totales and datos: last_i = len(datos) - 1 # Apuntará a la última línea no nula while (last_i > 0 and reduce(lambda x, y: str(x) + str(y), datos[last_i]) == ""): last_i -= 1 if (datos[last_i] and not reduce(lambda x, y: x == y == "---" and "---", datos[last_i])): datos.append(("---", ) * len(campos)) fila = ["TOTAL"] + [""] * (len(campos) - 1) if len(totales) > 1: fila[0] = "TOTALES" for total in totales: fila[total] = utils.float2str(totales[total]) #, precision = 2, autodec = True) datos.append(fila) if extra_data and not isinstance(extra_data[0], (tuple, list)): extra_data = [extra_data] for extra in extra_data: dif_len = len(campos) - len(extra) if dif_len <> 0 and not isinstance(extra, list): extra = list(extra) if dif_len > 0: extra += [""] * dif_len elif dif_len < 0: extra = extra[:len(campos)] datos.append(extra) if not fecha: fecha = utils.str_fecha(mx.DateTime.localtime()) if apaisado != None: pdf_apaisado = apaisado return geninformes.imprimir2(archivo, titulo, campos, datos, fecha, apaisado = pdf_apaisado, cols_a_derecha = cols_a_derecha, cols_centradas = cols_centradas, pijama = pijama, graficos = graficos)
def guardar(self, widget): """ Guarda el contenido de los entry y demás widgets de entrada de datos en el objeto y lo sincroniza con la BD. """ producto = self.objeto codigo = self.wids['e_codigo'].get_text() descripcion = self.wids['e_descripcion'].get_text() # idlinea Un producto pertenece a una línea, no se puede cambiar nombre = self.wids['e_nombre'].get_text() arancel = self.wids['e_arancel'].get_text() try: precio = utils.parse_float(self.wids['e_precio'].get_text().replace(',','.')) except ValueError: precio = producto.precio try: minimo = utils.parse_float(self.wids['e_minimo'].get_text()) except ValueError: minimo = producto.minimo try: gramos = int(self.wids['e_gramos'].get_text()) except ValueError: gramos = producto.camposEspecificosRollo.gramos try: ancho = utils.parse_float(self.wids['e_ancho'].get_text()) except ValueError: ancho = producto.camposEspecificosRollo.ancho try: diametro = int(self.wids['e_diametro'].get_text()) except ValueError: diametro = producto.camposEspecificosRollo.diametro try: metrosLineales = int(self.wids['e_metros_lineales'].get_text()) except: metrosLineales = producto.camposEspecificosRollo.metrosLineales try: rolloCamion = int(self.wids['e_rollo_camion'].get_text()) except ValueError: rolloCamion = producto.camposEspecificosRollo.rollosPorCamion composan = self.wids['e_composan'].get_text() # Desactivo el notificador momentáneamente producto.notificador.activar(lambda: None) # Actualizo los datos del objeto producto.codigo = codigo producto.descripcion = descripcion producto.nombre = nombre producto.preciopordefecto = precio producto.minimo = minimo producto.arancel = arancel producto.camposEspecificosRollo.gramos = gramos producto.camposEspecificosRollo.ancho = ancho producto.camposEspecificosRollo.diametro = diametro producto.camposEspecificosRollo.codigoComposan = composan producto.camposEspecificosRollo.rollosPorCamion = rolloCamion producto.camposEspecificosRollo.metrosLineales = metrosLineales try: self.objeto.obsoleto = self.wids['ch_obsoleto'].get_active() except (KeyError, AttributeError): pass # Versión antigua de la base de datos. # Fuerzo la actualización de la BD y no espero a que SQLObject lo haga por mí: producto.syncUpdate() # Vuelvo a activar el notificador producto.notificador.activar(self.aviso_actualizacion) self.actualizar_ventana() self.wids['b_guardar'].set_sensitive(False)
def guardar(self, widget): """ Guarda el contenido de los entry y demás widgets de entrada de datos en el objeto y lo sincroniza con la BD. """ producto = self.objeto codigo = self.wids['e_codigo'].get_text() if len(codigo) < 12: utils.dialogo_info(titulo = "CÓDIGO DEMASIADO CORTO", texto = "El código debe tener 13 dígitos para ajustarse al formato EAN-13.\nSe va a completar con ceros.", padre = self.wids['ventana']) codigo += "0" * (12 - len(codigo)) # Completo hasta 12 para que después se le haga la suma de control. if len(codigo) == 12: codigo = codigo + self.calcular_digitoc(codigo) if len(codigo) > 13: utils.dialogo_info(titulo = "CÓDIGO INCORRECTO", texto = "Código EAN-13 incorrecto. Debe tener exactamente 13 dígitos.\nPuede introducir 12 y dejar que se calcule atomáticamente el dígito de control, si le es más cómodo.\n\nA continuación se va a recortar el código a 13 dígitos y se intentará comprobar la suma de control.", padre = self.wids['ventana']) codigo = codigo[:13] if len(codigo) == 13: digitocontrol = self.calcular_digitoc(codigo[:12]) if codigo[12] != digitocontrol: utils.dialogo_info(titulo = "FALLÓ SUMA DE COMPROBACIÓN", texto = "El dígito de control no es correct" "o. Se corregirá automáticamente.", padre = self.wids['ventana']) codigo = codigo[:12] + digitocontrol descripcion = self.wids['e_descripcion'].get_text() linea = pclases.LineaDeProduccion.select( pclases.LineaDeProduccion.q.nombre.contains('fibra'))[0] lineaembol = pclases.LineaDeProduccion.select( pclases.LineaDeProduccion.q.nombre.contains('bolsa'))[0] nombre = self.wids['e_nombre'].get_text() arancel = self.wids['e_arancel'].get_text() try: precio = utils.parse_float(self.wids['e_precio'].get_text().replace(',','.')) except ValueError: precio = producto.preciopordefecto try: minimo = utils.parse_float(self.wids['e_minimo'].get_text()) except ValueError: minimo = producto.minimo try: dtex = utils.parse_float(self.wids['e_dtex'].get_text()) except ValueError: dtex = producto.camposEspecificosBala.dtex try: corte = int(self.wids['e_corte'].get_text()) except ValueError: dtex = producto.camposEspecificosBala.dtex gramosBolsa = utils.parse_numero(self.wids['e_gramosBolsa'].get_text()) producto.camposEspecificosBala.gramosBolsa = gramosBolsa bolsasCaja = utils.parse_numero(self.wids['e_bolsasCaja'].get_text()) producto.camposEspecificosBala.bolsasCaja = bolsasCaja cajasPale = utils.parse_numero(self.wids['e_cajasPale'].get_text()) producto.camposEspecificosBala.cajasPale = cajasPale color = self.wids['e_color'].get_text() antiuv = self.wids['chk_antiuv'].get_active() reciclada = self.wids['ch_reciclada'].get_active() idtipoMaterialBala = utils.combo_get_value(self.wids['cb_material']) prodestandar = self.wids['e_prodestandar'].get_text() try: prodestandar = utils.parse_float(prodestandar) except ValueError: prodestandar = 0.0 # Desactivo el notificador momentáneamente producto.notificador.activar(lambda: None) # Actualizo los datos del objeto producto.prodestandar = prodestandar try: producto.codigo = codigo except psycopg_ProgrammingError: try: producto_asignado = pclases.ProductoVenta.select( pclases.ProductoVenta.q.codigo == codigo)[0] producto_asignado = producto_asignado.descripcion except IndexError: producto_asignado = "?" utils.dialogo_info(titulo = "CÓDIGO DUPLICADO", texto = "El código EAN %s no se encuentra " "disponible.\nActualmente está asignado a:" " %s" % (codigo, producto_asignado), padre = self.wids['ventana']) producto.descripcion = descripcion if producto.camposEspecificosBala.gramosBolsa: producto.lineaDeProduccionID = lineaembol.id else: producto.lineaDeProduccionID = linea.id producto.nombre = nombre producto.preciopordefecto = precio producto.minimo = minimo producto.arancel = arancel producto.camposEspecificosBala.dtex = dtex producto.camposEspecificosBala.corte = corte producto.camposEspecificosBala.color = color producto.camposEspecificosBala.antiuv = antiuv producto.camposEspecificosBala.reciclada = reciclada producto.camposEspecificosBala.tipoMaterialBalaID = idtipoMaterialBala producto.dni = self.wids['e_dni'].get_text() producto.uso = self.wids['e_uso'].get_text() if self.wids['ch_no_anno_cert'].get_active(): producto.annoCertificacion = None else: producto.annoCertificacion \ = self.wids['sp_anno_certificacion'].get_value_as_int() cliente = utils.combo_get_value(self.wids['cbe_cliente']) if cliente == 0: cliente = None producto.camposEspecificosBala.clienteID = cliente try: self.objeto.obsoleto = self.wids['ch_obsoleto'].get_active() except (KeyError, AttributeError): pass # Versión antigua de la base de datos. # Fuerzo la actualización de la BD y no espero a que SQLObject lo # haga por mí: producto.syncUpdate() # Vuelvo a activar el notificador producto.notificador.activar(self.aviso_actualizacion) self.wids['b_guardar'].set_sensitive(False) self.actualizar_ventana()