예제 #1
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()
예제 #2
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")