예제 #1
0
파일: empleados.py 프로젝트: pacoqueen/ginn
 def comparar_campo(self, col, type_col):
     """
     Compara el contenido del widget cuyo nombre coincide con "col"
     con el valor del objeto para el campo "col".
     "type_col" es el tipo SQLObject del atributo, se usa para
     determinar cómo comparar los valores.
     """
     res = False
     if isinstance(type_col, pclases.SOStringCol):
         # Cadena: el widget es un entry
         res = self.comparar_string(col)
     elif isinstance(type_col, pclases.SOIntCol):
         # Entero: el widget es un entry
         res = self.comparar_int(col)
     elif isinstance(type_col, pclases.SOBoolCol):
         # Boolean: el widget es un checkbox
         res = self.comparar_bool(col)
     elif isinstance(type_col, pclases.SOForeignKey):
         # Entero-clave ajena: el widget es un comboboxentry
         res = self.comparar_ajena(col)
     elif isinstance(type_col, pclases.SOCol):
         # Clase base, casi seguro Float: el widget es un entry
         res = self.comparar_float(col)
     else:
         txterr = "empleados.py: No se pudo determinar el tipo de datos "\
                  "del campo %s." % col
         myprint(txterr)
         self.logger.error(txterr)
     return res
예제 #2
0
 def __init__(self, user=None, passwd=None, fconfig=None):
     """
     user: Usuario. Si es None se solicitará en la ventana de
     autentificación.
     passwd: Contraseña. Si es None, se solicitaré en la ventana de
     autentificación.
     Si user y passwd son distintos a None, no se mostrará la ventana de
     autentificación a no ser que sean incorrectos.
     """
     self.fconfig = fconfig
     from formularios import gestor_mensajes, autenticacion
     login = autenticacion.Autenticacion(user, passwd)
     if not login.loginvalido():
         sys.exit(1)
     self.logger = login.logger
     pclases.logged_user = self.usuario = login.loginvalido()
     # Informes de error por correo:
     install_bug_hook(self.usuario)
     # Continúo con el gestor de mensajes y resto de ventana menú.
     if pclases.VERBOSE:
         myprint("Cargando gestor de mensajes...")
     self.__gm = gestor_mensajes.GestorMensajes(self.usuario)
     # DONE: Dividir la ventana en expansores con los módulos del programa
     # (categorías) y dentro de ellos un IconView con los iconos de cada
     # ventana. Poner también en lo alto del VBox el icono de la aplicación.
     # (Ya va siendo hora de un poquito de eyecandy).
     if pclases.VERBOSE:
         myprint("Cargando menú principal...")
     self.construir_ventana()
     utils.escribir_barra_estado(self.statusbar,
                                 "Menú iniciado",
                                 self.logger,
                                 self.usuario.usuario)
예제 #3
0
 def nueva_partida(self, codigo):
     """
     Crea una nueva partida de carga y la hace activa en la ventana.
     """
     if self.usuario:
         try:
             ventana = pclases.Ventana.select(
                 pclases.Ventana.q.fichero == os.path.basename(__file__))[0]
         except IndexError:
             txt = "consumo_balas_partida::comprobar_permisos ->"\
                   " Ventana no encontrada en BD."
             self.logger.error(txt)
             myprint(txt)
         else:
             permiso = self.usuario.get_permiso(ventana)
             if not permiso.nuevo and self.usuario.nivel > 2:
                 utils.dialogo_info(titulo="NO TIENE PERMISOS",
                                    texto="No tiene permisos suficientes"
                                          " para crear partidas.",
                                    padre=self.wids['ventana'])
             else:
                 try:
                     numpartida = int(codigo.upper().replace("PC", ""))
                 except ValueError:
                     utils.dialogo_info(titulo="ERROR NÚMERO PARTIDA",
                                        texto="El número de partida debe"
                                              " ser un entero.",
                                        padre=self.wids['ventana'])
                     return
                 partida = pclases.PartidaCarga(numpartida=numpartida,
                                             codigo="PC%d" % (numpartida))
                 pclases.Auditoria.nuevo(partida, self.usuario, __file__)
                 self.objeto = partida
                 self.actualizar_ventana()
예제 #4
0
파일: empleados.py 프로젝트: pacoqueen/ginn
 def set_valor(self, w, nombrecampo, tipocampo):
     # valor = self.objeto._SO_getValue(nombrecampo)
     get_valor = getattr(self.objeto, "_SO_get_%s" % (nombrecampo))
     valor = get_valor()
     if isinstance(tipocampo, pclases.SOStringCol):  # Cadena: el widget es
                                                     # un entry
         if valor is not None:
             w.set_text(valor)
         else:
             w.set_text("")
     elif isinstance(tipocampo, pclases.SOIntCol):   # Entero: el widget es
                                                     # un entry
         try:
             w.set_text("%d" % valor)
         except TypeError:
             w.set_text("0")
     elif isinstance(tipocampo, pclases.SOBoolCol):  # Boolean: el widget
                                                     # es un checkbox
         w.set_active(valor)
     elif isinstance(tipocampo, pclases.SOForeignKey):  # Entero-clave
                                     # ajena: el widget es un comboboxentry
         utils.combo_set_from_db(w, valor)
     elif isinstance(tipocampo, pclases.SOCol):      # Clase base, casi
                                     # seguro Float: el widget es un entry
         if valor is not None:
             try:
                 w.set_text(utils.float2str(valor))
             except ValueError:
                 w.set_text('0')
     else:
         txt = "empleados.py: No se pudo establecer el valor %s "\
               "para %s." % (valor, w)
         myprint(txt)
         self.logger.error(txt)
예제 #5
0
 def crear_vencimientos_por_defecto(self):
     """
     Crea e inserta los vencimientos por defecto definidos por el cliente
     en la factura actual. Elimina los que tuviera previamente.
     """
     # Primero se intenta tirando del pedido. El último que tenga.
     try:
         pedido = self.get_pedidos()[-1]
         pedido.sync()
     except IndexError:
         vtos = None
     else:
         try:
             vtos = [pedido.formaDePago.plazo]
         except AttributeError:
             vtos = None
     # Si no, recurrimos a los vencimientos por defecto del cliente.
     cliente = self.cliente
     cliente.sync()
     if not vtos:
         if cliente.vencimientos != None and cliente.vencimientos != '':
             try:
                 vtos = cliente.get_vencimientos(self.fecha)
             except Exception, msg:
                 vtos = []  # Los vencimientos no son válidos o no tiene.
                 if DEBUG:
                     myprint("pclases::superfacturaventa -> Excepción"
                             "capturada al determinar vencimientos del"
                             "cliente:\n",
                             msg,
                             "\nSe asume que no tiene datos suficientes.")
예제 #6
0
 def enviar_correo_error_ventana(self):
     myprint("Se ha detectado un error")
     texto = ''
     for e in sys.exc_info():
         texto += "%s\n" % e
     tb = sys.exc_info()[2]
     texto += "Línea %s\n" % tb.tb_lineno
     info = MetaF()
     traceback.print_tb(tb, file = info)
     texto += "%s\n" % info
     enviar_correo(texto, self.get_usuario())
예제 #7
0
 def comprobar_permisos(self):
     """
     Comprueba si el usuario tiene permiso para escritura o nuevo y
     deshabilita o habilita los botones según sea el caso.
     """
     permiso = False     # 20171122 FIX initialization bug
     if self.usuario:
         try:
             ventana = pclases.Ventana.select(
                 pclases.Ventana.q.fichero == os.path.basename(__file__))[0]
         except IndexError:
             txt = "consumo_balas_partida::comprobar_permisos ->"\
                   " Ventana no encontrada en BD."
             self.logger.error(txt)
             myprint(txt)
         else:
             permiso = self.usuario.get_permiso(ventana)
             wids = ("b_add_partida_gtx", "b_drop_partida_gtx",
                     "b_add_balas", "b_add_producto", "b_drop_bala",
                     "b_phaser", "b_albaran", "e_fecha", "b_fecha",
                     "b_from_pdp", "b_from_albaran")
             if not permiso or (not permiso.escritura
                                and self.usuario.nivel > 2):
                 for wid in wids:
                     self.wids[wid].set_sensitive(False)
             else:
                 for wid in wids:
                     self.wids[wid].set_sensitive(True)
             self.wids['b_partida'].set_sensitive(bool(permiso and
                 not(not permiso.nuevo and not permiso.lectura)))
             if (self.usuario.nivel > 2 and
                     permiso and
                     permiso.nuevo and
                     pclases.PartidaCarga.select().count() > 0 and
                     self.objeto == pclases.PartidaCarga.select(
                             orderBy="-id")[0]):
                 for wid in wids:
                     self.wids[wid].set_sensitive(True)
             if self.usuario.nivel <= 2:
                 for wid in wids:
                     self.wids[wid].set_sensitive(True)
         self.wids['b_albaran'].set_sensitive(bool(
             self.objeto
             and len(self.objeto.get_balas_sin_albaran_interno()) > 0
             and permiso and (permiso.nuevo or permiso.escritura)))
     else:
         self.wids['b_albaran'].set_sensitive(
             self.objeto and
             len(self.objeto.get_balas_sin_albaran_interno()) > 0)
예제 #8
0
 def graficar_por_producto(self, partes):
     """
     Construye un gráfico de rendimiento por producto. Agrupa los partes
     de un mismo producto y calcula su productividad conjunta. Esos datos
     los envía a un gráfico para ver los productos que mejor le van
     a la línea.
     """
     vpro = VentanaProgreso(padre = self.wids['ventana'])
     vpro.mostrar()
     i = 0.0
     tot = len(partes)
     productos = defaultdict(lambda: [])
     for pdp in partes:
         i += 1
         vpro.set_valor(i / tot, "Analizando rendimiento por producto...")
         producto = pdp.productoVenta
         if not producto:
             txterr = "consulta_productividad.py::graficar_por_producto ->"\
                      " %s:%s sin producto de venta." % (pdp.puid,
                                                         pdp.get_info())
             myprint(txterr)
             self.logger.warning(txterr)
         else:
             productos[producto].append(pdp)
     data = OrderedDict()
     tot += len(productos)
     productos_ordenados = productos.keys()
     productos_ordenados.sort(key = lambda prod: prod.descripcion)
     for producto in productos_ordenados:
         i += 1
         vpro.set_valor(i / tot, "Analizando rendimiento por producto...")
         pdps = productos[producto]
         data[producto.descripcion] = calcular_productividad_conjunta(
                                                             tuple(pdps))
     try:
         plot = GtkCairoPlot(HORIZONTAL, data, self.wids['ventana'])
     except ValueError:
         plot = gtk.Label("<big>No hay datos suficientes.</big>")
         plot.set_use_markup(True)
     parent = self.wids['grafico'].parent
     parent.add(plot)
     parent.remove(self.wids['grafico'])
     self.wids['grafico'] = plot
     parent.show_all()
     vpro.ocultar()
예제 #9
0
 def get_str_estado(self, cache={}, fecha=mx.DateTime.today()):
     """
     Si la factura está en el diccionario de caché recibido (por su puid)
     entonces no consulta el estado en la BD.
     """
     ESTADOS = ("No documentada",
                "Documentada no vencida",
                "Impagada",
                "Cobrada",
                "Pendiente de abonar")
     try:
         estado = cache[self.puid]
         if VERBOSE:
             myprint("pclases.py::SuperFacturaVenta.get_str_estado -> HIT!")
     except KeyError:
         estado = self.get_estado(fecha)
     str_estado = ESTADOS[estado]
     return str_estado
예제 #10
0
파일: empleados.py 프로젝트: pacoqueen/ginn
 def comparar_bool(self, col):
     try:
         valor_ventana = self.wids[col].get_active()
     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 = False
     try:
         valor_campo = self.objeto._SO_getValue(col)
     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 = False
     res = valor_ventana == valor_campo
     return res
예제 #11
0
def main():
    # Si hay ficheros de estilo gtk, los cargo por orden: General de la
    # aplicación y específico del usuario en WIN y UNIX. Se machacan opciones
    # por ese orden.
    GTKRC2 = ".gtkrc-2.0" # Depende de la versión...
    GTKRC = "gtkrc"
    gtk.rc_parse(os.path.join(
        os.path.dirname(__file__), "..", GTKRC))
    gtk.rc_parse(os.path.join(
        os.path.dirname(__file__),"..", GTKRC2))    # Si no existe se ignora
                                                    # de manera silenciosa.
    if "HOME" in os.environ:
        gtk.rc_parse(os.path.join(os.environ["HOME"], GTKRC))
        gtk.rc_parse(os.path.join(os.environ["HOME"], GTKRC2))
    if "HOMEPATH" in os.environ:
        gtk.rc_parse(os.path.join(os.environ["HOMEPATH"], GTKRC))
        gtk.rc_parse(os.path.join(os.environ["HOMEPATH"], GTKRC2))
    # Ver http://www.pygtk.org/docs/pygtk/class-gtkrcstyle.html para la
    # referencia de estilos. Ejemplo:
    # bogado@cpus006:~/Geotexan/geotexinn02/formularios$ cat ../gtkrc
    # style 'blanco_y_negro' { bg[NORMAL] = '#FFFFFF'
    #                          fg[NORMAL] = '#000000'
    #                          base[NORMAL] = '#FFFFFF'
    #                          text[NORMAL] = '#000000'
    #                        }
    # class '*' style 'blanco_y_negro'
    ##
    user, passwd, modulo, clase, fconfig, verbose, debug, obj_puid = parse_params()
    #salida = MetaF()
    #sys.stdout = salida
    errores = MetaF()
    sys.stderr = errores
    m = Menu(user, passwd, fconfig)
    m.mostrar()
    if not errores.vacio() and not errores.contains(
            ["Logged from file menu.py", "Bad file descriptor"]):
        # Me quito de en medio los errores de volcado a log (IOError 9) que
        # aparecen a veces por... ¿Samba? ¿Clientes Windows? No lo sé.
        myprint("Se han detectado algunos errores en segundo plano durante "
                "la ejecución.")
        enviar_correo('Errores en segundo plano. La stderr contiene:\n%s'
                        % (errores),
                      m.get_usuario())
예제 #12
0
 def abrir_ventana_modulo_python(self, archivo, clase):
     try:
         self.ventana.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
         while gtk.events_pending(): gtk.main_iteration(False)
         # HACK: Debe haber una forma mejor de hacerlo. De momento me
         #       aprovecho de que el mainloop no va a atender al
         #       timeout aunque se cumpla el tiempo, ya que está
         #       ocupado en abrir la ventana, con lo que el cursor
         #       sale del "busy" justo cuando debe, al abrirse la
         #       ventana.
         v = None
         gobject.timeout_add(5000, self.volver_a_cursor_original)
         # NOTA: OJO: TODO: Usuario harcoded. Cambiar en cuanto sea
         #                  posible.
         if ((self.get_usuario().usuario == "geotextil" or
              self.get_usuario().usuario == "fibra" or
              self.get_usuario().nivel >= 3)
             and "partes_de_fabricacion" in archivo
             and self.get_usuario().usuario != "cemento"):
             exec "import %s" % archivo
             v = eval('%s.%s' % (archivo, clase))
             try:
                 v(permisos = "rx", usuario = self.get_usuario())
             except TypeError:   # La ventana no soporta el modelo
                                 # antiguo de permisos.
                 v(usuario = self.get_usuario())
             #v.wids['ventana'].set_icon_from_filename(icowindow)
         else:
             try:
                 #raise NotImplementedError, \
                 #        "Lanzador multiproceso en desarrollo..."
                 self.lanzar_ventana(archivo, clase)
             except Exception, e:
                 myprint(e)
                 sys.stderr.write(`e`)
                 self._lanzar_ventana(archivo, clase)
     except:
         self.ventana.window.set_cursor(None)
         utils.escribir_barra_estado(self.statusbar,
             "Error detectado. Iniciando informe por correo.",
             self.logger,
             self.usuario.usuario)
         self.enviar_correo_error_ventana()
예제 #13
0
파일: empleados.py 프로젝트: pacoqueen/ginn
 def comparar_ajena(self, col):
     try:
         valor_ventana = utils.combo_get_value(self.wids[col])
     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 = None
     try:
         valor_campo = self.objeto._SO_getValue(col) # Es un ID -es decir,
                                     # un entero-, no un objeto sqlobject.
     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 = None
     res = valor_ventana == valor_campo
     return res
예제 #14
0
파일: empleados.py 프로젝트: pacoqueen/ginn
 def comparar_string(self, col):
     res = False  # @UnusedVariable
     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 = ""
     try:
         valor_campo = self.objeto._SO_getValue(col)
     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 = ""
     res = valor_ventana == valor_campo
     return res
예제 #15
0
파일: empleados.py 프로젝트: pacoqueen/ginn
 def get_valor(self, w, nombrecampo, tipocampo):
     res = None
     if isinstance(tipocampo, pclases.SOStringCol):  # Cadena: el widget es
                                                     # un entry
         res = w.get_text()
     elif isinstance(tipocampo, pclases.SOIntCol):   # Entero: el widget es
                                                     # un entry
         res = w.get_text()
         try:
             res = int(res)
         except ValueError:
             txt = "El valor «%s» no es correcto. Introduzca un número"\
                   " entero." % (res)
             utils.dialogo_info(titulo="ERROR DE FORMATO", texto=txt,
                                padre=self.wids['ventana'])
             res = 0
     elif isinstance(tipocampo, pclases.SOBoolCol):
         # Boolean: el widget es un checkbox
         res = w.get_active()
     elif isinstance(tipocampo, pclases.SOForeignKey):
         # Entero-clave ajena: el widget es un comboboxentry
         res = utils.combo_get_value(w)
     elif isinstance(tipocampo, pclases.SOCol):
         # Clase base, casi seguro Float: el widget es un entry
         res = w.get_text()
         try:
             res = utils._float(res)
         except ValueError:
             txt = "El valor «%s» no es correcto. Introduzca un número." % (
                 res)
             utils.dialogo_info(titulo="ERROR DE FORMATO",
                                texto=txt,
                                padre=self.wids['ventana'])
             res = 0.0
     else:
         txt = "empleados.py: No se pudo obtener el valor de %s para "\
               "%s <%s>." % (w, nombrecampo, tipocampo)
         myprint(txt)
         self.logger.error(txt)
     return res
예제 #16
0
파일: empleados.py 프로젝트: pacoqueen/ginn
 def comparar_int(self, col):
     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 = ""
     try:
         valor_ventana = int(valor_ventana)
     except ValueError:
         txt_error = "empleados.py: No se pudo convertir %s a entero." % col
         myprint(txt_error)
         self.logger.error(txt_error)
         valor_ventana = 0
     try:
         valor_campo = self.objeto._SO_getValue(col)
     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
     res = valor_ventana == valor_campo
     return res
예제 #17
0
파일: empleados.py 프로젝트: pacoqueen/ginn
 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
예제 #18
0
파일: empleados.py 프로젝트: pacoqueen/ginn
 def rellenar_widgets(self):
     """
     Redimensiona «t» y crea dentro los widgets necesarios para
     mostrar y editar los campos de «objeto».
     """
     if pclases.DEBUG:
         myprint("empleados.py::rellenar_widgets -> Ready...")
         import time
         antes = time.time()
     # HACK: Es para evitar el campo precio hora extra, que ya no se usa.
     # Nómina ahora es el sueldo base a sumar al cálculo de la nomina
     # mensual.
     d = {}
     if pclases.DEBUG:
         myprint("empleados.py::rellenar_widgets -> Steady...",
                 time.time() - antes)
         antes = time.time()
     for c in self.objeto.sqlmeta.columns:
         if c != 'preciohora':
             d[c] = self.objeto.sqlmeta.columns[c]
     self.objeto.sqlmeta.columns = d
     # END OF HACK
     if pclases.DEBUG:
         myprint("empleados.py::rellenar_widgets -> GO!      ",
                 time.time() - antes)
         antes = time.time()
     numcampos = len(self.objeto.sqlmeta.columns)
     if numcampos % 2 != 0:
         numwidgets = numcampos + 1
     else:
         numwidgets = numcampos
     for child in self.wids['t'].get_children():
         child.destroy()
     if pclases.DEBUG:
         myprint("empleados.py::rellenar_widgets -> ",
                 time.time() - antes)
         antes = time.time()
     self.wids['t'].resize(numwidgets / 2, 4)
     icol = 0
     irow = 0
     if pclases.DEBUG:
         myprint("empleados.py::rellenar_widgets -> ",
                 time.time() - antes)
         antes = time.time()
     for col in self.objeto.sqlmeta.columns:
         if not isinstance(self.objeto.sqlmeta.columns[col],
                           pclases.SOBoolCol):
             # Los checkboxes llevan su propio label.
             label = self.build_label(col)
             self.wids['t'].attach(label, icol, icol+1, irow, irow+1)
         icol += 1
         child = self.build_child(col, self.objeto.sqlmeta.columns[col])
         self.set_valor(child, col, self.objeto.sqlmeta.columns[col])
         self.wids['t'].attach(child, icol, icol+1, irow, irow+1)
         icol += 1
         if icol == 4:
             icol = 0
             irow += 1
     if pclases.DEBUG:
         myprint("empleados.py::rellenar_widgets -> ",
                 time.time() - antes)
         antes = time.time()
     self.wids['t'].show_all()
     self.objeto.make_swap()
     # Añadido: Si el empleado no tiene alta como trabajador, deshabilito
     # el botón de permisos.
     self.wids['b_ausencias'].set_sensitive(self.objeto.activo)
     self.wids['b_categoria'].set_sensitive(
             self.objeto.categoriaLaboral != None)
     if pclases.DEBUG:
         myprint("empleados.py::rellenar_widgets -> WINTER!",
                 time.time() - antes)
         antes = time.time()
예제 #19
0
 def rellenar_tabla(self, partes, solobalas):
     """
     Rellena el model con los partes rescatados de la BD en `buscar`.
     PRERREQUISITO:
         Los partes vienen en una lista y deben estar ordenados por fecha y
         hora de inicio.
     """
     # Lo primero de todo. Si está activado el DEBUG, muestro las columnas.
     tv = self.wids['tv_datos']
     for ncol in range(7, len(tv.get_columns())):
         tv.get_column(ncol).set_property("visible", pclases.DEBUG)
     self.huecos = []    # Lista de los últimos partes tratados por línea.
     self.incidencias_horaini = []
     self.incidencias_horafin = []
     self.tiempo_faltante = mx.DateTime.TimeDeltaFrom(0)
     vpro = VentanaProgreso(padre = self.wids['ventana'])
     model = self.wids['tv_datos'].get_model()
     model.clear()
     total = 0
     kilosproducidos = 0
     kilosgranza = 0
     vector = []
     tot = len(partes)
     i = 0.0
     vpro.mostrar()
     e_personasturno = 0
     tiempototal = 0
     tiempo_sin_incidencias = 0  # Por si inicia una consulta sin resultados
     metrosproducidos = 0
     kilosconsumidos = kilosconsumidos_partidas_completas = 0
     tiempototaltotal = mx.DateTime.DateTimeDelta(0)
     #selffin = utils.parse_fecha('/'.join(self.fin.split('/')[::-1]))
     selffin = self.fin
     # ... WTF? Esto está hecho como el culo. ¡REFACTORIZAR!
     # XXX Primer intento de acelerar los treeview
     self.wids['tv_datos'].freeze_child_notify()
     self.wids['tv_datos'].set_model(None)
     # XXX
     personashora = []
     dia_actual = ""     # Estos tres parámetros son para medir la
                         # producción y productividad por día.
     produccion_actual = 0.0
     #productividad_actual = 0.0
     t_teorico_por_dia = 0
     t_real_por_dia = 0
     pdps_dia = []   # Ojo. Los partes deben venir ordenados para que
         # esta lista solo contenga los partes del día tratado en la
         # iteración por la que vaya. Se limpia al cambiar de un día al
         # siguiente mientras relleno los datos.
     #nodos_hijos_por_dia = 0
     balas_consumidas = []       # Lista con las balas consumidas por
         # todos los partes, así evito contar la misma dos veces si en dos
         # partes se ha usado la misma partida o dos partidas de la misma
         # partida de carga.
     padre = None # En una de las iteraciones se espera que padre se haya
         # instanciado en el final de la anterior. Inicializo para evitar
         # errores y errores en análisis sintáctico de algunos IDE en la
         # línea 342.
     for pdp in partes:
         if pdp.se_solapa():
             texto_warning = "%sconsulta_productividad::rellenar_tabla"\
                 " -> El parte ID %d se solapa con otros de la misma línea"\
                 ". Si estaba verificado, lo desbloqueo para que se vuelva"\
                 " a revisar y lo ignoro para el cálculo actual." % (
                  self.usuario and self.usuario.usuario + ": " or "", pdp.id)
             self.logger.warning(texto_warning)
             myprint(texto_warning)
             pdp.bloqueado = False
             continue
         vpro.set_valor(i/tot, 'Añadiendo parte %s...' % (
                                 utils.str_fecha(pdp.fecha)))
         delta_entre_partes, parte_anterior = detectar_hueco(pdp, self.huecos)
         if delta_entre_partes:
             self.marcar_hueco(parte_anterior, pdp)
         self.tiempo_faltante += delta_entre_partes
         kilosgranza_del_parte = 0.0
         (tiempototal,
          tiempo_sin_incidencias) = self.calcular_tiempo_trabajado(pdp)
         tiempototaltotal += tiempototal
         #productividad = pdp.calcular_productividad()
         # CWT: Ahora no se calcula así, sino como el antiguo rendimiento.
         productividad = pdp.calcular_rendimiento()
         # Tratamiento especial para partes de balas
         try:
             str_producto = pdp.productoVenta.descripcion
         except AttributeError:
             str_producto = "Sin producción"
         if (self.wids['r_balas'].get_active()
             or self.wids['r_ambos'].get_active()):   # Sólo balas o todos.
             if pdp.es_de_fibra():
                 balas = [a.bala for a in pdp.articulos if a.balaID != None]
                 bigbags = [a.bigbag for a in pdp.articulos if a.bigbagID != None]
                 for b in balas:
                     kilosproducidos += b.pesobala
                 for b in bigbags:
                     kilosproducidos += b.pesobigbag
                 kilosgranza_del_parte = pdp.get_granza_consumida()
                 kilosgranza += kilosgranza_del_parte
                 if pdp.get_produccion()[0] - kilosgranza_del_parte > 1000:
                                                                 # XXX DEBUG
                     self.logger.warning("El parte ID %d (%s) ha consumido "
                             "(%s) mucha menos granza que fibra ha "
                             "producido (%s) !!!" % (pdp.id,
                                 utils.str_fecha(pdp.fecha),
                                 utils.float2str(kilosgranza_del_parte),
                                 utils.float2str(pdp.get_produccion()[0])))
                                                                 # XXX DEBUG
         if (self.wids['r_cemento'].get_active()
             or self.wids['r_ambos'].get_active()):
             kilosproducidos += pdp.get_produccion()[0]
             kilosconsumidos += sum([bb.pesobigbag for bb in pdp.bigbags])
         if (self.wids['r_rollos'].get_active()
             or self.wids['r_ambos'].get_active()):  # Sólo rollos o todos.
             if pdp.es_de_geotextiles():
                 superficies_defectuosos = [a.superficie
                     for a in pdp.articulos if a.es_rollo_defectuoso()]
                 metrosproducidos += sum(superficies_defectuosos)
                 rollos = [a.rollo for a in pdp.articulos if a.rollo != None]
                 if len(rollos) > 0:     # Para que no intente hacer el
                     # cálculo con partes que tengan balas y/o no rollos.
                     pv = pdp.articulos[0].productoVenta
                     cer = pv.camposEspecificosRollo
                     metrosproducidos += (len(rollos)
                                          * cer.metros_cuadrados)
                     if pdp.articulos[0].es_rollo():
                         partida = pdp.articulos[0].rollo.partida
                     elif pdp.articulos[0].es_rollo_defectuoso():
                         partida = pdp.articulos[0].rolloDefectuoso.partida
                     else:
                         partida = None
                     if partida != None:
                         contar_kilosconsums_partidas_completas \
                                 = partida.entra_en_cota_superior(selffin)
                         for b in partida.balas:
                             if b not in balas_consumidas:   # Evito contar
                                                 # la misma bala dos veces.
                                 bpesobala = b.pesobala
                                 kilosconsumidos += bpesobala
                                 if contar_kilosconsums_partidas_completas:
                                     kilosconsumidos_partidas_completas \
                                             += bpesobala
                                 balas_consumidas.append(b)
         empleados = len(pdp.horasTrabajadas)
         e_personasturno += empleados
         tiempoparte = pdp.get_duracion().hours
         if tiempoparte > 0:
             personashora.append(empleados/tiempoparte)
         else:
             personashora.append(0.0)
         vector.append(productividad)
         produccion = pdp.get_produccion()
         # Resúmenes por día como nodos padre del TreeView.
         if not dia_actual:
             pdps_dia.append(pdp)
         if dia_actual == utils.str_fecha(pdp.fecha):
             pdps_dia.append(pdp)
         else:
             if dia_actual != "":  # Actualizo el padre
                 if not self.wids['r_ambos'].get_active():
                     model[padre][4] = "%s %s" % (
                             utils.float2str(produccion_actual),
                             produccion[1])
                 else:   # Evito mezclar kilos con metros
                     model[padre][4] = "-"
                 productividad_actual = calcular_productividad_conjunta(
                         tuple(pdps_dia))
                 model[padre][5] = "%s %%" % (
                         utils.float2str(productividad_actual))
                 model[padre][6] = min(productividad_actual, 100)
                 model[padre][7] = t_teorico_por_dia
                 model[padre][8] = t_real_por_dia
                 pdps_dia = [pdp] # He cambiado de día. Limpio.
                 t_teorico_por_dia = 0
                 t_real_por_dia = 0
             dia_actual = utils.str_fecha(pdp.fecha)
             produccion_actual = 0.0
             productividad_actual = 0.0
             #nodos_hijos_por_dia = 0
             padre = model.append(None,
                         (dia_actual,
                          "",
                          "",
                          "",
                          "",
                          "%s %%" % (utils.float2str(productividad_actual)),
                          min(productividad_actual, 100),
                          "", # t. teórico
                          "", # t. real
                          0))
         t_teorico_pdp = pdp.calcular_tiempo_teorico()
         t_teorico_por_dia += t_teorico_pdp
         t_real_pdp = pdp.calcular_tiempo_real()
         t_real_por_dia += t_real_pdp
         model.append(padre,
             (utils.str_fecha(pdp.fecha),
              str(pdp.horainicio)[:5],
              str(pdp.horafin)[:5],
              str_producto,
              "%s %s" % (utils.float2str(produccion[0]), produccion[1]),
              "%s %%" % (utils.float2str(productividad)),
              min(productividad, 100),
              t_teorico_pdp,
              t_real_pdp,
              pdp.id))
         produccion_actual += produccion[0]
         i+=1
     # Actualizo el padre de los últimos nodos:
     if dia_actual != "":  # Actualizo el padre
         if not self.wids['r_ambos'].get_active():
             model[padre][4] = "%s %s" % (
                     utils.float2str(produccion_actual), produccion[1])
         else:   # Evito mezclar kilos con metros
             model[padre][4] = "-"
         productividad_actual = calcular_productividad_conjunta(
                                                         tuple(pdps_dia))
         model[padre][5] = "%s %%" % (utils.float2str(productividad_actual))
         model[padre][6] = min(productividad_actual, 100)
         # Campos de depuración
         model[padre][7] = t_teorico_por_dia
         model[padre][8] = t_real_por_dia
     vpro.ocultar()
     # XXX Primer intento de acelerar los treeview
     self.wids['tv_datos'].set_model(model)
     self.wids['tv_datos'].thaw_child_notify()
     # XXX
     if partes != []:
         total = calcular_productividad_conjunta(tuple(partes))
         # Campos especiales de "Sólo balas"
         if self.wids['r_balas'].get_active():
             self.wids['label7'].set_text('Kilos producidos:')
             self.wids['label8'].set_text('Kilos granza consumidos:')
             self.wids['label9'].set_text('Kilos / Hora producción:')
             self.wids['e_kilosproducidos'].set_text(
                 "%s kg" % (utils.float2str(kilosproducidos)))
             self.wids['e_kilosgranza'].set_text(
                 "%s kg" % (utils.float2str(kilosgranza)))
             try:
                 e_kiloshora = (kilosproducidos
                                 /float(tiempototaltotal.hours))
             except ZeroDivisionError:
                 self.logger.warning(
                         "consulta_productividad.py::rellenar_tabla"
                         " -> tiempototaltotal = 0")
                 e_kiloshora = 0  # Cero por poner algo. Porque un parte
                                  # de tiempo transcurrido=0... se las trae.
             self.wids['e_kiloshora'].set_text("%s kg/h" % (
                                             utils.float2str(e_kiloshora)))
         elif self.wids['r_rollos'].get_active():
             tips = gtk.Tooltips()
             tips.set_tip(self.wids['e_kilosgranza'],
                          "Kilogramos consumidos contando partidas "
                          "completas por defecto y por exceso.\n(En un caso"
                          " se cuentan solo partidas de carga cuyas "
                          "partidas de geotextiles se hayan completado "
                          "estrictamente antes o en la cota superior.\n"
                          "En el otro, por exceso, se contabilizan "
                          "partidas completas aunque parte de su "
                          "producción se salga del rango de fechas.\n"
                          "En ambos casos el límite inferior es flexible "
                          "-por compensación-.)")
             tips.enable()
             self.wids['label7'].set_text('m² producidos:')
             self.wids['label8'].set_text('Kg fibra consumidos:')
             self.wids['label9'].set_text('m²/h producción:')
             try:
                 e_kiloshora = (metrosproducidos/float(tiempototaltotal.hours))
             except ZeroDivisionError:
                 self.logger.warning(
                         "consulta_productividad.py::rellenar_tabla -> "
                         "tiempototaltotal = 0")
                 e_kiloshora = 0
             self.wids['e_kilosproducidos'].set_text("%s m²" % (
                 utils.float2str(metrosproducidos)))
             if kilosconsumidos_partidas_completas != kilosconsumidos:
                 self.wids['e_kilosgranza'].set_text("%s kg ~ %s kg" % (
                     utils.float2str(kilosconsumidos_partidas_completas),
                     utils.float2str(kilosconsumidos)))
             else:
                 self.wids['e_kilosgranza'].set_text("%s kg" % (
                     utils.float2str(kilosconsumidos)))
             self.wids['e_kiloshora'].set_text("%s m²/h" % (
                 utils.float2str(e_kiloshora)))
         else:
             self.wids['label7'].set_text('Producido:')
             self.wids['label8'].set_text('Consumido:')
             self.wids['label9'].set_text('Producción combinada a la hora:')
             try:
                 e_kiloshora = (kilosproducidos/float(tiempototaltotal.hours))
                 metros_hora = (metrosproducidos/float(tiempototaltotal.hours))
             except ZeroDivisionError:
                 self.logger.warning("consulta_productividad.py::"
                         "rellenar_tabla -> tiempototaltotal = 0")
                 e_kiloshora = 0
                 metros_hora = 0
             self.wids['e_kilosproducidos'].set_text("%s m²; %s kg" % (
                 utils.float2str(metrosproducidos),
                 utils.float2str(kilosproducidos)))
             self.wids['e_kilosgranza'].set_text(
                     "%s kg fibra; %s kg granza" % (utils.float2str(
                         kilosconsumidos), utils.float2str(kilosgranza)))
             self.wids['e_kiloshora'].set_text("%s m²/h; %s kg/h" % (
                 utils.float2str(metros_hora),
                 utils.float2str(e_kiloshora)))
         # Fin campos especiales de "Sólo balas"
         self.wids['curva'].set_range(0, len(vector), 0, 100)
         self.wids['curva'].set_vector(vector)
         self.wids['curva'].set_curve_type(gtk.CURVE_TYPE_SPLINE)
         # self.wids['curva'].set_curve_type(gtk.CURVE_TYPE_LINEAR)
         self.wids['pb'].set_fraction(max(min(total, 100), 0) / 100.0)
     else:
         self.wids['curva'].set_range(0, 2, 0, 100)
         self.wids['curva'].set_vector((0, 0))
         self.wids['pb'].set_fraction(1 / 100.0)
         self.wids['e_kilosproducidos'].set_text('')
         self.wids['e_kilosgranza'].set_text('')
         self.wids['e_kiloshora'].set_text('')
     self.wids['e_total'].set_text("%s %%" % (utils.float2str(total)))
     try:
         personashora = sum(personashora)/len(personashora)
     except ZeroDivisionError:
         personashora = 0
     try:
         e_personasturno = float(e_personasturno) / len(partes)
     except ZeroDivisionError:
         e_personasturno = 0
     self.wids['e_personasturno'].set_text("%s (%s personas/h)" % (
         utils.float2str(e_personasturno), utils.float2str(personashora)))
     self.wids['e_tiempo_faltante'].set_text(
             self.tiempo_faltante
             and (str_horas(self.tiempo_faltante) + " h")
             or "")
     self.wids['e_tiempo_partes'].set_text(
             str_horas(tiempototaltotal) + " h")
예제 #20
0
 def rellenar_tabla(self, partidas_carga):
     """
     Rellena el model con los items de la consulta.
     partidas_carga es un diccionario... (mirar
     abajo, en "buscar").
     """
     model = self.wids['tv_datos'].get_model()
     model.clear()
     datachart = []
     for pc in partidas_carga:
         abuelo = model.append(None,
                   (pc.codigo,
                    utils.float2str(partidas_carga[pc]['kilos_consumidos']),
                    utils.float2str(partidas_carga[pc]['kilos_producidos']),
                    utils.float2str(partidas_carga[pc]['kilos_teoricos']),
                    str(partidas_carga[pc]['balas']),
                    str(partidas_carga[pc]['rollos']),
                    utils.float2str(partidas_carga[pc]['metros']),
                    pc.id))
         # Actualizo totales conforme relleno el _model_
         pcpc = partidas_carga[pc]
         self.totales['e_total_kg_consumidos'] += pcpc['kilos_consumidos']
         self.totales['e_total_kg_prod_real'] += pcpc['kilos_producidos']
         self.totales['e_total_kg_prod_teorico'] += pcpc['kilos_teoricos']
         self.totales['e_total_balas_consumidas'] += pcpc['balas']
         self.totales['e_total_rollos_producidos'] += pcpc['rollos']
         self.totales['e_total_m2_producidos'] += pcpc['metros']
         # Y sigo con el gráfico y tal
         datachart.append([pc.codigo,
                           partidas_carga[pc]['kilos_consumidos']])
         padre = model.append(abuelo,
                              ("Partidas de geotextiles producidas",
                               '',
                               '',
                               '',
                               '',
                               '',
                               '',
                               ''))
         for pgtx in partidas_carga[pc]['partidas']:
             model.append(padre,
                          ("%s: %s" % (pgtx['código'], pgtx['producto']),
                           "",
                           utils.float2str(pgtx['kilos']),
                           utils.float2str(pgtx['kilos_teoricos']),
                           "",
                           str(pgtx['rollos']),
                           utils.float2str(pgtx['metros']),
                           ''))
         padre = model.append(abuelo,
                              ("Lotes de fibra consumidos",
                               '',
                               '',
                               '',
                               '',
                               '',
                               '',
                               ''))
         for lote in partidas_carga[pc]['lotes']:
             model.append(padre,
                          ("%s: %s" % (lote['código'], lote['producto']),
                           utils.float2str(lote['kilos']),
                           '',
                           '',
                           str(lote['balas']),
                           '',
                           '',
                           '',
                           ))
     # Y ahora la gráfica.
     from lib import charting
     try:
         oldchart = self.wids['eventbox_chart'].get_child()
         if oldchart != None:
             #self.wids['eventbox_chart'].remove(oldchart)
             chart = oldchart
         else:
             chart = charting.Chart()
             self.wids['eventbox_chart'].add(chart)
         datachart.sort(lambda fila1, fila2: (fila1[0] < fila2[0] and -1)
                                             or (fila1[0] > fila2[0] and 1)
                                             or 0)
         for data in datachart:
             data.append(6)  # Barras de color rojo.
         chart.plot(datachart)
         self.wids['eventbox_chart'].show_all()
     except Exception, msg:
         txt = "consumo_fibra_por_partida_gtx.py::rellenar_tabla -> "\
               "Error al dibujar gráfica (charting): %s" % msg
         myprint(txt)
         self.logger.error(txt)
예제 #21
0
# 1.9b: Cuando cierre "todas" las incidencias, bugs y etiquetas TO-DO|FIX-ME.
#       (versión estable)
# 1.9.impar : Inestables.
# 1.9.par : Estables.
# 2.0rc: Versión 2.0 release candidate coincidiendo con la puesta en
#        producción.
# 2.0: Versión 2.0 cuando acabe fase de pruebas.
# 2.0.1: Tal vez debería hacer un fork para nuevas funcionalidades generales
#        (tickets, IRPF...) mientras congelo la RC, pero prefiero una sola
#        rama de código, que los merge de CVS son muy duros.

# os.environ['LANG'] = "es_ES"
# os.environ['LANGUAGE'] = 'es_ES'
# os.chdir(os.path.dirname(os.path.realpath(sys.argv[0])))
if pclases.DEBUG:
    myprint(os.environ)
    myprint(os.getcwd())
    myprint(os.path.realpath(sys.argv[0]))


class MetaF:
    """
    "Metafichero" para almacenar la salida de errores y poder
    enviar informes de error.
    """
    def __init__(self):
        self.t = ''

    def write(self, t):
        errores_a_ignorar = ("GtkWarning", "with become", "PangoWarning",
                             "main loop already active",
예제 #22
0
 def calcular_total(self, iva=True, redondeo=2):
     """
     Calcula el total de la factura, con descuentos, IVA y demás incluido.
     Devuelve un FixedPoint (a casi todos los efectos, se comporta como
     un FLOAT. De todas formas, pasa bien por el utils.float2str).
     """
     subtotal = self.calcular_subtotal()
     tot_dto = self.calcular_total_descuento(subtotal)
     abonos = sum([pa.importe for pa in self.pagosDeAbono])
     if iva:
         tot_iva = self.calcular_total_iva(subtotal, tot_dto, self.cargo,
                                           abonos)
     else:
         tot_iva = 0.0
     irpf = self.irpf * subtotal
     if redondeo is False:   # No redondea ANTES de hacer la suma. Pero el
         # resultado, al implicar un FixedPoint que viene del IVA, será
         # también un FixedPoint de 2 decimales.
         total = (subtotal
                  + float(self.cargo)    # Porque es de tipo Decimal
                  + tot_dto
                  + tot_iva
                  + abonos
                  + irpf)
     else:
         subtotales = (subtotal,
                       float(self.cargo),
                       tot_dto,
                       tot_iva,
                       abonos,
                       irpf)
         if DEBUG:
             myprint("pclases.py::SuperFacturaVenta.calcular_total "
                     "(antes de redondeo) -> ",
                     subtotales)
         if redondeo == 2:
             # El viejo truco, que no por viejo es impreciso. Por ejemplo:
             # In [33]: nums= (13425.705, 0.705, 1.705, 2.705, 3.705, 5.705, 425.705)
             # In [34]: for n in nums:
             #    ....:     print round(n, 2), myround(n)
             #    ....:
             # 13425.7 13425.71
             # 0.7 0.71
             # 1.71 1.71
             # 2.71 2.71
             # 3.71 3.71
             # 5.71 5.71
             # 425.7 425.71
             # myround = lambda x: int((float(x) + 0.005) * 100) / 100.0
             from formularios.utils import myround
             # testcase
             # i = (1.0, 1.001, 1.004, 1.049, 1.005, 1.006, 1.009, 1.0091, 1.949, 1.985, 1.994, 1.995, 2.0, 2.001, 2.675)
             # o = (1.0, 1.0,   1.0,   1.05,  1.01,  1.01,  1.01,  1.01,   1.95,  1.99,  1.99,  2.0,   2.0, 2.0,   2.68)
             # for x, y in zip(i, o):
             #     print x, "->", myround(x), "=", y
             #     assert myround(x) == y
             subtotales = map(lambda x: myround(x), subtotales)
         else:
             subtotales = map(lambda x: round(round(x, 6), redondeo),
                              subtotales)
         # La ley, que no es muy precisa, viene a decir que los cálculos
         # internos de precios y tal se hagan a 6 decimales los totales a 2.
         # También dice que TOTAL=BASE IMPONIBLE+IVA. Se supone que ya todo
         # bien redondeado al céntimo. El atajo de BI*1.21 es incorrecto.
         # Premature optimization is the root of all Evil, el demonio está
         # en los pequeños detalles y todas esas cosas se me han venido
         # encima de golpe.
         # El doble redondeo es por un caso curiosísimo:
         # Por calculadora, 0.6275*26730=16773.075. Sin embargo...
         # In [30]: 0.6275*26730
         # Out[30]: 16773.074999999997
         # In [35]: round(0.6275*26730, 2)
         # Out[35]: 16773.07
         # In [36]: round(round(0.6275*26730, 3), 2)
         # Out[36]: 16773.08
         # Al redondear a 2 decimales debería dar 16773.08 (0.75 -> 0.8)
         # Esto ya es conocido. Ver
         # https://docs.python.org/2/library/functions.html#round
         if DEBUG:
             myprint("pclases.py::SuperFacturaVenta.calcular_total "
                     "(tras redondeo) -> ",
                     subtotales)
         total = sum(subtotales)
     return total
예제 #23
0
 def buscar(self, boton):
     """
     Dadas fecha de inicio y de fin, busca los partes de
     producción de geotextiles entre esas fechas.
     Para cada parte de producción extrae las partidas de
     geotextiles fabricadas y las agrupa por partida de
     carga.
     Finalmente, de cada partida de carga cuenta los kilogramos
     de fibra y número de balas en ella. También divide las balas
     por lotes y cuenta los kg y bultos de cada lote que ha entrado
     en cada carga de cuarto.
     OJO: El criterio finalmente queda: en cada mes se cuenta el
     consumo y la producción de las partidas cuyas partidas de carga
     hayan sido terminadas. Una partida que comienza en un fin de
     mes (por ejemplo) y acaba en el mes siguiente (cualquier fecha, en
     general) cuenta para el mes siguiente. Esto es así porque hay que
     tomar las partidas de carga como una unidad, como un todo, si se
     quiere discernir bien los kg producidos y consumidos, ya que no hay
     relación directa entre rollo y bala consumida (se pierde definición
     al haber una tabla de una relación muchos a muchos entre medio).
     """
     self.inicio = utils.parse_fecha(self.wids['e_fechainicio'].get_text())
     self.fin = utils.parse_fecha(self.wids['e_fechafin'].get_text())
     self.totales = {'e_total_kg_consumidos': 0.0,
                     'e_total_kg_prod_real': 0.0,
                     'e_total_kg_prod_teorico': 0.0,
                     'e_total_balas_consumidas': 0,
                     'e_total_rollos_producidos': 0,
                     'e_total_m2_producidos': 0.0}
     PDP = pclases.ParteDeProduccion
     if not self.inicio:
         pdps = PDP.select(""" fecha < '%s'
                 AND observaciones NOT LIKE '%%;%%;%%;%%;%%;%%' """ % (
                     self.fin.strftime('%Y-%m-%d')))
     else:
         pdps = PDP.select(""" fecha >= '%s' AND fecha < '%s'
                 AND observaciones NOT LIKE '%%;%%;%%;%%;%%;%%' """ % (
                     self.inicio.strftime('%Y-%m-%d'),
                     self.fin.strftime('%Y-%m-%d')))
     vpro = ventana_progreso.VentanaProgreso(padre = self.wids['ventana'])
     tot = pdps.count()
     pdps = pdps.orderBy("fecha")
     i = 0.0
     vpro.mostrar()
     partidas_carga = {}
     # "Constantes" (nótense las comillas).
     PESOREAL = 1
     PESOTEORICO = 2
     PESOSIN = 3
     if self.wids['rb_pesoreal'].get_active():
         metodo = PESOREAL
     elif self.wids['rb_teorico'].get_active():
         metodo = PESOTEORICO
     elif self.wids['rb_pesosin'].get_active():
         metodo = PESOSIN
     else:
         txt = "consumo_fibra_por_partida_gtx.py::buscar -> ¡NO HAY SELEC"\
               "CIONADO NINGÚN RADIOBUTTON DEL GRUPO!"
         self.logger.error(txt)
         myprint(txt)
         return
     for pdp in pdps:
         vpro.set_valor(i/tot, 'Analizando producción %s...' % (
             utils.str_fecha(pdp.fecha)))
         if pdp.articulos:
             articulo = pdp.articulos[0]
             if articulo.es_rollo():
                 partida = articulo.rollo.partida
             elif articulo.es_rollo_defectuoso():
                 partida = articulo.rolloDefectuoso.partida
             else:
                 partida = None
             if partida and partida.entra_en_cota_superior(self.fin):
                 partida_carga = partida.partidaCarga
                 if partida_carga == None:   # Partidas sin partida de carga
                                             # ... eso es malo.
                     txt = "consumo_fibra_por_partida_gtx.py::buscar -> ¡P"\
                           "artida %s no tiene partida de carga!" % (
                             partida.get_info())
                     myprint(txt)
                     self.logger.error("%s%s" % (
                         self.usuario and self.usuario.usuario + ": "
                         or "", txt))
                 else:
                     if partida_carga not in partidas_carga: # Aquí ya se
                     # asegura que no se contará dos veces la misma
                     # bala -partida de carga-.
                         partidas_carga[partida_carga] = {
                             'partidas': [],
                             'lotes': [],
                             'kilos_consumidos': 0.0,
                             'balas': 0,
                             'kilos_producidos': 0.0,
                             'kilos_teoricos': 0.0,
                             'rollos': 0,
                             'metros': 0.0, }
                         for partida in partida_carga.partidas:
                             if metodo == PESOSIN:
                                 kilos_producidos = partida.get_kilos()
                             elif metodo == PESOTEORICO:
                                 kilos_producidos \
                                     = partida.get_kilos_teorico()
                             elif metodo == PESOREAL:
                                 kilos_producidos \
                                     = partida.get_kilos_totales()
                             else:
                                 txt = "consumo_fibra_por_partida_gtx.py "\
                                       "-> No se pudo determinar el métod"\
                                       "o de cálculo. Se usará el peso te"\
                                       "órico."
                                 self.logger.warning(txt)
                                 myprint(txt)
                                 kilos_producidos \
                                     = partida.get_kilos_teorico()
                             kilos_teoricos = partida.get_kilos_teorico()
                             metros_producidos = partida.get_metros()
                             producto = partida.get_producto()
                             partidas_carga[partida_carga]\
                               ['partidas'].append(
                                 {'código': partida.codigo,
                                  'kilos': kilos_producidos,
                                  'kilos_teoricos': kilos_teoricos,
                                  'metros': metros_producidos,
                                  'rollos': len(partida.rollos),
                                  'producto': producto
                                                 and producto.descripcion
                                                 or "SIN PRODUCCIÓN"
                                  })
                             partidas_carga[partida_carga]\
                                 ['kilos_producidos'] += kilos_producidos
                             partidas_carga[partida_carga]\
                                 ['kilos_teoricos'] += kilos_teoricos
                             partidas_carga[partida_carga]\
                                 ['rollos'] += len(partida.rollos)
                             partidas_carga[partida_carga]\
                                 ['metros'] += metros_producidos
                         lotes = partida_carga.get_lotes()
                         for lote in lotes:
                             balas = pclases.Bala.select(pclases.AND(
                                 pclases.Bala.q.loteID == lote.id,
                                 pclases.Bala.q.partidaCargaID
                                     == partida_carga.id))
                             kilos_consumidos = sum(
                                 [b.pesobala for b in balas])
                             partidas_carga[partida_carga]['lotes'].append(
                              {'código': lote.codigo,
                               'kilos': kilos_consumidos,
                               'balas': balas.count(),
                               'producto':
                                balas[0].articulo.productoVenta.descripcion
                               })
                                 # NOTA: el get_lotes() ya asegura que al
                                 # menos hay una bala en la consulta "balas"
                             partidas_carga[partida_carga]\
                                 ['kilos_consumidos'] += kilos_consumidos
                             partidas_carga[partida_carga]\
                                 ['balas'] += balas.count()
         i += 1
     vpro.ocultar()
     self.partidas_carga = partidas_carga
     self.rellenar_tabla(partidas_carga)
     self.rellenar_totales()
예제 #24
0
파일: empleados.py 프로젝트: pacoqueen/ginn
 def build_child(self, nombrecampo, tipocampo):
     """
     Construye el widget correspondiente al tipo de campo recibido y
     establece su valor por defecto.
     """
     res = gtk.Label('ERROR: N/A')
     if isinstance(tipocampo, pclases.SOStringCol):  # Cadena: el widget es
                                                     # un entry
         res = gtk.Entry()
         if (tipocampo.default is not None
                 and tipocampo.default != sqlobject.sqlbuilder.NoDefault):
             res.set_text("%s" % (tipocampo.default))
     elif isinstance(tipocampo, pclases.SOIntCol):   # Entero: el widget es
                                                     # un entry
         res = gtk.Entry()
         if (tipocampo.default is not None
                 and tipocampo.default != sqlobject.sqlbuilder.NoDefault):
             res.set_text("%s" % (tipocampo.default))
     elif isinstance(tipocampo, pclases.SOBoolCol):  # Boolean: el widget es
                                                     # un checkbox
         label = self.build_label(nombrecampo)
         res = gtk.CheckButton(label=label.get_text())
         if tipocampo.default:
             res.set_active(True)
     elif isinstance(tipocampo, pclases.SOForeignKey):  # Entero-clave
                                     # ajena: el widget es un comboboxentry
         res = gtk.ComboBoxEntry()
         ajena = tipocampo.foreignKey
         clase = getattr(pclases, ajena)
         COLUMNATEXTO = 'nombre'     # Cambiar si no tiene una columna
                                     # "nombre"
         try:
             if clase == pclases.CategoriaLaboral:
                 # HACK: Las categorías laborales ahora van con fechas y es
                 # una movida.
                 contenido = [(r.id,  # r._SO_getValue(COLUMNATEXTO))
                               r.get_info())
                              for r in clase.select(orderBy='id')
                              if not r.fecha]
             else:
                 contenido = [(r.id, r._SO_getValue(COLUMNATEXTO))
                              for r in clase.select(orderBy='id')]
         except KeyError:
             COLUMNATEXTO = 'puesto'     # Cambiar si no tiene una
                                         # columna "puesto"
             contenido = [(r.id, r._SO_getValue(COLUMNATEXTO))
                          for r in clase.select(orderBy='id')]
         utils.rellenar_lista(res, contenido)
     elif isinstance(tipocampo, pclases.SOCol):      # Clase base, casi
                                     # seguro Float: el widget es un entry
         res = gtk.Entry()
         if (tipocampo.default is not None
                 and tipocampo.default != sqlobject.sqlbuilder.NoDefault):
             res.set_text(utils.float2str("%s" % tipocampo.default))
     else:
         txt = "empleados.py: No se pudo construir el widget para %s." % (
                 nombrecampo)
         myprint(txt)
         self.logger.error(txt)
     res.set_name(nombrecampo)
     self.wids[nombrecampo] = res
     return res
예제 #25
0
    def create_menu(self):
        model = gtk.ListStore(str, gtk.gdk.Pixbuf)
        modulos = {}
        usuario = self.get_usuario()
        if pclases.VERBOSE:
            myprint("Analizando permisos (1/2)...")
        if pclases.VERBOSE:
            i = 0
            tot = pclases.Modulo.select().count()
        for m in pclases.Modulo.select(orderBy = "nombre"):
            if pclases.VERBOSE:
                i += 1
                myprint("Analizando permisos (1/2)... (%d/%d)" % (i, tot))
            modulos[m] = []
        if pclases.VERBOSE:
            i = 0
            tot = pclases.Permiso.select(
                pclases.Permiso.q.usuarioID == usuario.id).count()
        if pclases.VERBOSE:
            myprint("Analizando permisos (2/2)...")
        for permusu in usuario.permisos:
            if pclases.VERBOSE:
                i += 1
                myprint("Analizando permisos (2/2)... (%d/%d)" % (i, tot))
            if permusu.permiso:
                v = permusu.ventana
                m = v.modulo
                if m != None:
                    modulos[m].append(v)
        modulos_sorted = modulos.keys()
        def fsortalfabeticamente(m1, m2):
            if m1.nombre < m2.nombre:
                return -1
            if m1.nombre > m2.nombre:
                return 1
            return 0
        modulos_sorted.sort(fsortalfabeticamente)
        for modulo in modulos_sorted:
            if modulos[modulo]:
                fichicono = os.path.join(
                    os.path.dirname(os.path.realpath(__file__)),
                    '..', 'imagenes', modulo.icono)
                pixbuf = gtk.gdk.pixbuf_new_from_file(fichicono)
                model.append([modulo.nombre, pixbuf])
        # Módulo favoritos
        pixbuf = gtk.gdk.pixbuf_new_from_file(
            os.path.join(
                os.path.dirname(os.path.realpath(__file__)),
                '..', 'imagenes', "favoritos.png"))
        iterfav = model.append(("Favoritos", pixbuf))

        contenedor = gtk.ScrolledWindow()
        icon_view = gtk.IconView(model)
        icon_view.set_text_column(0)
        icon_view.set_pixbuf_column(1)
        icon_view.set_orientation(gtk.ORIENTATION_VERTICAL)
        icon_view.set_selection_mode(gtk.SELECTION_SINGLE)
        icon_view.connect('selection-changed', self.on_select, model)
        icon_view.set_columns(1)
        icon_view.set_item_width(110)
        icon_view.set_size_request(140, -1)

        contenedor.add(icon_view)
        self.content_box = gtk.HBox(False)
        self.content_box.pack_start(contenedor, fill=True, expand=False)
        #icon_view.select_path((0,))
        icon_view.select_path(model.get_path(iterfav))
            # Al seleccionar una categoría se creará el frame
        # Sanity check.
        if hasattr(icon_view, "scroll_to_path"):    # Si pygtk >= 2.8
            icon_view.scroll_to_path(model.get_path(iterfav), False, 0, 0)
        else:
            # ¿No hay equivalente en pyGTK 2.6?
            pass
        return self.content_box
예제 #26
0
    def imprimir(self, boton):
        """
        Prepara la vista preliminar para la impresión del informe
        """
        if self.partidas_carga  != {}:
            if self.wids['rb_pesoreal'].get_active():
                metodo = "reales tomados en la línea (incluyendo embalajes)."
            elif self.wids['rb_teorico'].get_active():
                metodo = "teóricos."  # @UnusedVariable
            elif self.wids['rb_pesosin'].get_active():
                metodo = "reales tomados en la línea (sin embalajes)."
            else:
                txt = "consumo_fibra_por_partida_gtx.py::imprimir -> "\
                      "¡NO HAY SELECCIONADO NINGÚN RADIOBUTTON DEL GRUPO!"
                self.logger.error(txt)
                myprint(txt)
                return
            partidas_carga = self.partidas_carga
            from formularios import reports
            datos = []
            total_kilos_consumidos = 0.0
            total_kilos_producidos = 0.0
            total_kilos_teoricos = 0.0
            total_balas_consumidas = 0
            total_rollos_producidos = 0
            total_metros_producidos = 0.0
            def cmp_codigo(pc1, pc2):
                if pc1.codigo < pc2.codigo:
                    return -1
                if pc1.codigo > pc2.codigo:
                    return 1
                return 0
            claves = partidas_carga.keys()
            claves.sort(cmp_codigo)
            for pc in claves:
                datos.append((pc.codigo,
                              utils.float2str(partidas_carga[pc]['kilos_consumidos']),
                              utils.float2str(partidas_carga[pc]['kilos_producidos']),
                              utils.float2str(partidas_carga[pc]['kilos_teoricos']),
                              str(partidas_carga[pc]['balas']),
                              str(partidas_carga[pc]['rollos']),
                              utils.float2str(partidas_carga[pc]['metros']),
                             ))
                total_kilos_producidos += partidas_carga[pc]['kilos_producidos']
                total_kilos_teoricos += partidas_carga[pc]['kilos_teoricos']
                total_kilos_consumidos += partidas_carga[pc]['kilos_consumidos']
                total_metros_producidos += partidas_carga[pc]['metros']
                total_balas_consumidas += partidas_carga[pc]['balas']
                total_rollos_producidos += partidas_carga[pc]['rollos']
                padre = datos.append(("     >>> Lotes de fibra consumidos", '', '', '', '', '', ''))  # @UnusedVariable
                for lote in partidas_carga[pc]['lotes']:
                    datos.append(("               %s: %s" % (lote['código'], lote['producto']),
                                  utils.float2str(lote['kilos']),
                                  '',
                                  '',
                                  str(lote['balas']),
                                  '',
                                  '',
                                 ))
                padre = datos.append(("     >>> Partidas de geotextiles producidas:", '', '', '', '', '', ''))  # @UnusedVariable
                for pgtx in partidas_carga[pc]['partidas']:
                    datos.append(("               %s: %s" % (pgtx['código'], pgtx['producto']),
                                  "",
                                  utils.float2str(pgtx['kilos']),
                                  utils.float2str(pgtx['kilos_teoricos']),
                                  "",
                                  str(pgtx['rollos']),
                                  utils.float2str(pgtx['metros']),
                                 ))
                datos.append(("---", ) * 7)
            datos.append(("", ) * 7)
            datos.append(("===", ) * 7)
            datos.append(("     TOTALES: ",
                          utils.float2str(total_kilos_consumidos),
                          utils.float2str(total_kilos_producidos),
                          utils.float2str(total_kilos_teoricos),
                          str(total_balas_consumidas),
                          str(total_rollos_producidos),
                          utils.float2str(total_metros_producidos)
                         ))
            datos.append(("", "", "", "", "", "", ""))
            datos.append(("", "", "", "", "", "", ""))

            if (self.inicio) == None:
                fechaInforme = 'Hasta '+utils.str_fecha(self.fin)
            else:
                fechaInforme = "%s - %s" % (utils.str_fecha(self.inicio),
                                            utils.str_fecha(self.fin))
            if datos != []:
                reports.abrir_pdf(
                        geninformes.consumo_fibra_produccion_gtx(datos,
                                                                 fechaInforme))