Example #1
0
 def buscar(self):
     """
     Inicia la consulta para el año indicado en el widget y 
     rellena las tablas con la información obtenida.
     """
     #import time
     #antes = time.time()
     cuantas = int(self.wids['sp_ver'].get_value())
     balas = []
     n = 0
     qbalas = pclases.BalaCable.select(orderBy = "-id")
     vpro = VentanaProgreso(padre = self.wids['ventana'])
     vpro.mostrar()
     if cuantas == 0:
         tot = qbalas.count() * 1.0
     else:
         tot = cuantas * 1.0
     for b in qbalas:
         b.sync()        
             # Con 999 balas se gana únicamente 1 segundo si omito 
             # la sincronización.
         try:
             balas.insert(0, (b, b.productoVenta))       
                 # Para optimizar los accesos a la BD cacheo los datos aquí.
         except:     # ¿Bala sin producto de venta? Mal asunto
             balas.insert(0, (b, None))
         vpro.set_valor(n/tot, 'Recuperando bala %s' % (b.codigo))
         n += 1
         if n == cuantas:
             break
     vpro.set_valor(1, 'Actualizando ventana...')
     vpro.ocultar()
     #print time.time() - antes
     return balas
Example #2
0
 def leer_datos_cargas_descargas(self, silo):
     """
     Devuelve las cargas y descargas (consumo) del silo 
     agrupadas por fecha en un diccionario de la forma:
     {fecha1: {'cargas': [cargaSilo1, cargaSilo2...], 
               'descargas': [consumo1, consumo2...]}, 
      fecha2: {'cargas': [], 
               'descargas': [consumo3, ...]}
     }
     """
     vpro = VentanaProgreso(padre = self.wids['ventana'])
     vpro.mostrar()
     i = 0.0
     tot = len(silo.cargasSilo) + len(silo.consumos)
     datos = {}
     for carga in silo.cargasSilo:
         vpro.set_valor(i/tot, 'Analizando cargas...')
         i += 1
         if carga.fechaCarga not in datos:
             datos[carga.fechaCarga] = {'cargas': [carga, ], 'descargas': []}
         else:
             datos[carga.fechaCarga]['cargas'].append(carga)
     for descarga in silo.consumos:
         vpro.set_valor(i/tot, 'Analizando consumos...')
         i += 1
         if descarga.parteDeProduccionID != None:
             fecha = descarga.parteDeProduccion.fecha
         else:
             fecha = None
         if fecha not in datos:
             datos[fecha] = {'cargas': [], 'descargas': [descarga, ]}
         else:
             datos[fecha]['descargas'].append(descarga)
     vpro.ocultar()
     return datos
 def buscar(self, boton):
     """
     Dadas fecha de inicio y de fin, devuelve todos los vencimientos 
     no pagados al completo.
     """
     vpro = VentanaProgreso(padre=self.wids["ventana"])
     vpro.mostrar()
     if not self.inicio:
         pagos = pclases.Pago.select(pclases.Pago.q.fecha <= self.fin, orderBy="fecha")
         pagares = pclases.PagarePago.select(pclases.PagarePago.q.fechaEmision <= self.fin, orderBy="fechaEmision")
     else:
         pagos = pclases.Pago.select(
             pclases.AND(pclases.Pago.q.fecha >= self.inicio, pclases.Pago.q.fecha <= self.fin), orderBy="fecha"
         )
         pagares = pclases.PagarePago.select(
             pclases.AND(
                 pclases.PagarePago.q.fechaEmision >= self.inicio, pclases.PagarePago.q.fechaEmision <= self.fin
             ),
             orderBy="fechaEmision",
         )
     i = 0.0
     tot = pagos.count() + pagares.count()
     proveedor = None
     idproveedor = utils.combo_get_value(self.wids["cmbe_proveedor"])
     if idproveedor != None:
         idproveedor = utils.combo_get_value(self.wids["cmbe_proveedor"])
         proveedor = pclases.Proveedor.get(idproveedor)
     self.resultado = []
     filtrar_por_formapago = self.wids["ch_formapago"].get_active()
     formapago = utils.combo_get_value(self.wids["cb_formapago"])
     for pago in pagos:
         i += 1
         vpro.set_valor(i / tot, "Buscando pagos... (%d/%d)" % (i, tot))
         # Si es un pagaré, se trata en el siguiente bucle.
         if pago.pagarePago:
             continue
         if not proveedor or (proveedor and pago.facturaCompra and pago.facturaCompra.proveedor == proveedor):
             try:
                 txtformapago = self.formaspago[formapago][1]
             except TypeError:  # formapago es None. No se está filtrando
                 # por forma de pago.
                 filtrar_por_formapago = False
                 self.wids["ch_formapago"].set_active(False)
             if not filtrar_por_formapago or (txtformapago in utils.filtrar_tildes(pago.observaciones).lower()):
                 self.resultado.append(pago)
     for pagare in pagares:
         i += 1
         vpro.set_valor(i / tot, "Buscando pagos... (%d/%d)" % (i, tot))
         for pago in pagare.pagos:
             if not proveedor or (proveedor and pago.facturaCompra and pago.facturaCompra.proveedor == proveedor):
                 try:
                     txtformapago = self.formaspago[formapago][1]
                 except TypeError:  # formapago es None. No se está
                     # filtrando por forma de pago.
                     filtrar_por_formapago = False
                     self.wids["ch_formapago"].set_active(False)
                 if not filtrar_por_formapago or (txtformapago in utils.filtrar_tildes(pago.observaciones).lower()):
                     self.resultado.append(pago)
     vpro.ocultar()
     self.rellenar_tabla(self.resultado)
Example #4
0
 def rellenar_tabla(self, filtro = None, campo_orden = "id", padre = None,
                    sumatorios = [], limpiar_model = True,
                    objetos = None, *args, **kw):
     """
     A partir de todos los objetos de la clase rellena la tabla, mostrando 
     una ventana de progreso durante el proceso. Si filtro != None, debe 
     ser una función que sirva para DESCARTAR los objetos que no se 
     mostrarán. La función debe evaluarse a True con el objeto que se esté 
     tratando para que se añada al model ListView del TreeView.
     «padre» es la ventana padre para la de progreso.
     Las columnas (sus nombres en realidad) que vengan en «sumatorios» se 
     sumarán y se devolverán en el mismo orden.
     *args y **kw son parámetros adicionales que se pasarán al filtro.
     Hay otra opción para que en lugar de buscar los objetos a mostrar en
     el TreeView, los reciba en el parámetro «objetos». A esta lista
     se le pasaría también el filtro, pero no se le aplica el campo_orden.
     «objetos» debe ser un SelectResult o un SQLlist/SQLtuple.
     """
     # PLAN: Esto se podría optimizar según esta receta:
     # http://www.sqlobject.org/FAQ.html#efficient
     res = []
     for colsum in sumatorios:  # @UnusedVariable
         res.append(0.0)
     if objetos is None:
         objetos = self.clase.select(orderBy=campo_orden)
     model = self.tv.get_model()
     self.tv.freeze_child_notify()
     self.tv.set_model(None)
     if not filtro:
         filtro = self.filtro
     from ventana_progreso import VentanaProgreso
     vpro = VentanaProgreso(padre=padre)
     txtpro = "Mostrando %s (%%d/%%d)..." % self.clase.__name__
     vpro.mostrar()
     if limpiar_model:
         model.clear()
     total = objetos.count()
     if not total:
         total = 1.0
     i = 0.0
     vpro.set_valor(i / total, txtpro % (i, total))
     for objeto in objetos:
         i += 1
         if filtro(objeto, *args, **kw):
             fila = []
             for col in self.__columnas:
                 if col.name in self.cols_a_ignorar:
                     continue
                 if col.name in sumatorios:
                     res[sumatorios.index(col.name)] += getattr(objeto,
                                                                col.name)
                 valor = col2value(objeto, col)
                 fila.append(valor)
             fila.append(objeto.id)
             model.append(fila)
         vpro.set_valor(i / total, txtpro % (i, total))
     self.tv.set_model(model)
     self.tv.thaw_child_notify()
     vpro.ocultar()
     return res
Example #5
0
 def rellenar_tabla(self):
     vpro = VentanaProgreso(padre = self.wids['ventana'])
     vpro.mostrar()
     model = self.wids['tv_datos'].get_model()
     model.clear()
     padres = self.cargar_conceptos(vpro, model)
     mes_actual, mes_final, filas = self.cargar_subconceptos(vpro)
     filas = self.cargar_valores(mes_actual, mes_final, filas, vpro)
     self.volcar_a_tv(filas, vpro, padres, model)
     # Ahora toca pasar el mes que se ha ido al final del año actual
     #self.ciclar_mes(vpro)
     vpro.ocultar()
Example #6
0
 def buscar(self, boton):
     """
     Busca todos los productos e introduce en los TreeViews las existencias 
     de los mismos. En total y por almacén.
     El total no lo calcula, se obtiene del total global (que debería 
     coincidir con el sumatorio de...).
     """
     fechaini = self.wids['e_fechaini'].get_text().strip()
     if fechaini:
         try:
             fechaini = utils.parse_fecha(fechaini)
         except (ValueError, TypeError):
             utils.dialogo_info(titulo = "ERROR EN FECHA INICIAL", 
              texto = "El texto «%s» no es una fecha correcta." % fechaini,
              padre = self.wids['ventana'])
             fechaini = None
     fechafin = self.wids['e_fechafin'].get_text().strip()
     if fechafin:
         try:
             fechafin = utils.parse_fecha(fechafin)
         except (ValueError, TypeError):
             utils.dialogo_info(titulo = "ERROR EN FECHA FINAL", 
              texto = "El texto «%s» no es una fecha correcta." % fechafin,
              padre = self.wids['ventana'])
             fechafin = None
     if fechafin:
         FV = pclases.FacturaVenta
         if fechaini:
             facturas = FV.select(pclases.AND(
                                     FV.q.fecha >= fechaini, 
                                     FV.q.fecha <= fechafin))
         else:
             facturas = FV.select(FV.q.fecha <= fechafin)
         from ventana_progreso import VentanaProgreso
         vpro = VentanaProgreso(padre = self.wids['ventana'])
         vpro.mostrar()
         txtvpro = "Buscando facturas..."
         total = 0.0
         i = 0.0
         vpro.set_valor(i, txtvpro)
         model = self.wids['tv_datos'].get_model()
         model.clear()
         for f in facturas:
             i += 1
             vpro.set_valor(i/facturas.count(), 
                            txtvpro)
             model.append((f.numfactura, 
                         utils.str_fecha(f.fecha), 
                         f.cliente and f.cliente.cif or "¡Sin cliente!", 
                         f.cliente and f.cliente.nombre or "¡Sin cliente!", 
                         utils.float2str(f.calcular_base_imponible()), 
                         utils.float2str(f.calcular_total_iva()), 
                         utils.float2str(f.calcular_importe_total()), 
                         f.get_puid()))
             total += f.calcular_importe_total()
         vpro.ocultar()
         self.wids['e_total'].set_text(utils.float2str(total))
 def rellenar_tabla(self, items):
     """
     Rellena el model con los items de la consulta
     """
     vpro = VentanaProgreso(padre = self.wids['ventana'])
     vpro.mostrar()
     vpro.set_valor(0.0, "Contando existencias...")
     act = 0.0
     tot = len(items) * len(self.tvs)
     try:
         fecha = utils.parse_fecha(self.wids['e_fecha'].get_text())
     except (TypeError, ValueError, AttributeError):
         fecha = mx.DateTime.today()
         self.wids['e_fecha'].set_text(utils.str_fecha(fecha))
     # XXX: Optimización (cosas de cómo están hechas las funciones de get_*
     #      por dentro en pclases):
     if fecha >= mx.DateTime.today():
         fecha = None
     for tv, kg, bultos, a in self.tvs:
         model = tv.get_model()
         model.clear()
         totalkgs = 0.0
         totalbultos = 0
         for pv in items:
             vpro.set_valor(act/tot, 
                            "Contando existencias...\t[%s]" % pv.get_puid())
             stock = pv.get_stock(hasta = fecha, almacen = a)
             totalkgs += stock
             existencias = pv.get_existencias(hasta=fecha, almacen = a)
             totalbultos += existencias
             stock_A = pv.get_stock_A(hasta = fecha, almacen = a)
             existencias_A = pv.get_existencias_A(hasta=fecha, almacen = a)
             stock_B = pv.get_stock_B(hasta = fecha, almacen = a)
             existencias_B = pv.get_existencias_B(hasta=fecha, almacen = a)
             stock_C = pv.get_stock_C(hasta = fecha, almacen = a)
             existencias_C = pv.get_existencias_C(hasta=fecha, almacen = a)
             model.append((pv.codigo,
                           pv.descripcion,
                           utils.float2str(stock),
                           utils.float2str(existencias, autodec = True),
                           utils.float2str(stock_A!=None and stock_A or 0),
                           utils.float2str(existencias_A != None and 
                                           existencias_A or 0, 
                                           autodec = True),
                           utils.float2str(stock_B!=None and stock_B or 0),
                           utils.float2str(existencias_B != None and 
                                           existencias_B or 0, 
                                           autodec = True),
                           utils.float2str(stock_C!=None and stock_C or 0),
                           utils.float2str(existencias_C != None and 
                                           existencias_C or 0, 
                                           autodec = True),
                           pv.get_puid()))
             act += 1
         kg.set_text(utils.float2str(totalkgs))
         bultos.set_text(utils.float2str(totalbultos, autodec = True))
     vpro.ocultar()
    def rellenar_tabla(self, fib, gtx, cem, otros):
        """
        Rellena el model con los items de la consulta.
        Recibe cuatro diccionarios dependiendo del tipo de producto que habrá
        que introducir en los cuatro treeviews correspondientes.
        Los diccionarios se organizan:
        {'producto1': {'albarán1': {'m2': {'a': 0.0, 'b': 0.0, 'c': 0.0},
                                    'kg': {'a': 0.0, 'b': 0.0, 'c': 0.0},
                                    '#': {'a': 0, 'b': 0, 'c': 0}},
         'producto2': {'albarán1': {'cantidad': 0.0},
         'producto3': {'albarán2': {'kg': {'a': 0.0, 'b': 0.0, 'c': 0.0},
                                    '#': {'a': 0, 'b': 0, 'c': 0}},
        ...}
        """
        tot_fibra = {"kg": {"a": 0.0, "b": 0.0, "c": 0.0}, "#": {"a": 0, "b": 0, "c": 0}}
        tot_gtx = {
            "kg": {"a": 0.0, "b": 0.0, "c": 0.0},
            "#": {"a": 0, "b": 0, "c": 0},
            "m2": {"a": 0.0, "b": 0.0, "c": 0.0},
        }
        tot_cem = {"kg": {"a": 0.0, "b": 0.0, "c": 0.0}, "#": {"a": 0, "b": 0, "c": 0}}
        from ventana_progreso import VentanaProgreso

        vpro = VentanaProgreso(padre=self.wids["ventana"])
        vpro.mostrar()
        i = 0.0
        tot = len(fib) + len(gtx) + len(cem) + len(otros)
        try:
            vpro.set_valor(i / tot, "Mostrando %s..." % (""))
        except ZeroDivisionError:
            pass  # It's Easier to Ask Forgiveness than Permission (EAFP)
        for tv, dic, dic_tot in (
            (self.wids["tv_fibra"], fib, tot_fibra),
            (self.wids["tv_gtx"], gtx, tot_gtx),
            (self.wids["tv_cem"], cem, tot_cem),
            (self.wids["tv_otros"], otros, None),
        ):
            # "Otros" no lleva totales porque son unidades diferentes.
            model = tv.get_model()
            model.clear()
            for producto in dic:
                i += 1
                vpro.set_valor(i / tot, "Mostrando %s..." % (producto))
                fila_producto = build_fila(dic, producto)
                producto_padre = model.append(None, fila_producto)
                if dic_tot:
                    # PLAN: OPTIMIZAR: Estúpido, podrías aprovechar el bucle
                    # de los albaranes de abajo y no repetirlo en el
                    # update_total.
                    update_total(dic_tot, dic[producto])
                for albaran in dic[producto]:
                    fila_albaran = build_fila(dic[producto], albaran)
                    model.append(producto_padre, fila_albaran)
        vpro.ocultar()
        return tot_fibra, tot_gtx, tot_cem
Example #9
0
 def rellenar_tabla(self, filtro = None, campo_orden = "id", padre = None,
                    sumatorios = [], limpiar_model = True, *args, **kw):
     """
     A partir de todos los objetos de la clase rellena la tabla, mostrando 
     una ventana de progreso durante el proceso. Si filtro != None, debe 
     ser una función que sirva para DESCARTAR los objetos que no se 
     mostrarán. La función debe evaluarse a True con el objeto que se esté 
     tratando para que se añada al model ListView del TreeView.
     «padre» es la ventana padre para la de progreso.
     Las columnas (sus nombres en realidad) que vengan en «sumatorios» se 
     sumarán y se devolverán en el mismo orden.
     *args y **kw son parámetros adicionales que se pasarán al filtro.
     """
     res = []
     for colsum in sumatorios:
         res.append(0.0)
     objetos = self.clase.select(orderBy = campo_orden)
     model = self.tv.get_model()
     self.tv.freeze_child_notify()
     self.tv.set_model(None)
     if not filtro:
         filtro = self.filtro 
     from ventana_progreso import VentanaProgreso
     vpro = VentanaProgreso(padre = padre)
     txtpro = "Mostrando %s (%%d/%%d)..." % self.clase.__name__
     vpro.mostrar()
     if limpiar_model:
         model.clear()
     total = objetos.count()
     if not total:
         total = 1.0
     i = 0.0
     vpro.set_valor(i / total, txtpro % (i, total)) 
     for objeto in objetos:
         i += 1
         if filtro(objeto, *args, **kw):
             fila = []
             for col in objeto.sqlmeta.columnList:
                 if col.name in self.cols_a_ignorar:
                     continue
                 if col.name in sumatorios:
                     res[sumatorios.index(col.name)] += getattr(objeto, 
                                                                col.name)
                 valor = col2value(objeto, col)
                 fila.append(valor)
             fila.append(objeto.id)
             model.append(fila)
         vpro.set_valor(i / total, txtpro % (i, total)) 
     self.tv.set_model(model)
     self.tv.thaw_child_notify()
     vpro.ocultar()
     return res
 def buscar(self, boton):
     """
     Busca todos los productos e introduce en los TreeViews las existencias 
     de los mismos. En total y por almacén.
     El total no lo calcula, se obtiene del total global (que debería 
     coincidir con el sumatorio de...).
     """
     tipo = utils.combo_get_value(self.wids['cbe_tipo'])
     from ventana_progreso import VentanaProgreso
     vpro = VentanaProgreso(padre = self.wids['ventana'])
     vpro.mostrar()
     txtvpro = "Recuperando existencias por almacén..."
     i = 0.0
     vpro.set_valor(i, txtvpro)
     almacenes = pclases.Almacen.select(orderBy = "id")
     itotal = pclases.ProductoCompra.select().count() 
     model = self.wids['tv_por_producto'].get_model()
     model.clear()
     for a in almacenes:
         self.wids['tv_%d' % a.id].get_model().clear()
     if tipo in (0, -2) or tipo > 0:
         for pc in pclases.ProductoCompra.select():
             if ((tipo > 0 and pc.tipoDeMaterialID == tipo) 
                 or tipo in (0, -2)):
                 fila = [pc.codigo, pc.descripcion]
                 total = pc.existencias
                 for a in almacenes:
                     existencias_almacen = a.get_existencias(pc)
                     if existencias_almacen == None:
                         existencias_almacen = 0
                     fila.append(utils.float2str(existencias_almacen))
                     if existencias_almacen != 0:
                         self.wids['tv_%d' % a.id].get_model().append(
                             (pc.codigo, pc.descripcion, 
                              utils.float2str(existencias_almacen), 
                              pc.get_puid()))
                 fila.append(utils.float2str(total))
                 fila.append(pc.get_puid())
                 model.append(fila)
             txtvpro = "Recuperando existencias por almacén... (%s)" % (
                 pc.get_puid())
             i += 1
             vpro.set_valor(i/itotal, txtvpro)
     else:
         i += pclases.ProductoCompra.select().count()
     txtvpro = "Recuperando existencias por almacén..."
     vpro.ocultar()
Example #11
0
 def leer_datos_cargas_descargas(self, silo):
     """
     Devuelve las cargas y descargas (consumo) del silo 
     agrupadas por fecha en un diccionario de la forma:
     {fecha1: {'cargas': [cargaSilo1, cargaSilo2...], 
               'descargas': [consumo1, consumo2...]}, 
      fecha2: {'cargas': [], 
               'descargas': [consumo3, ...]}
     }
     """
     vpro = VentanaProgreso(padre = self.wids['ventana'])
     vpro.mostrar()
     i = 0.0
     tot = len(silo.cargasSilo) + len(silo.consumos)
     datos = {}
     for carga in silo.cargasSilo:
         vpro.set_valor(i/tot, 'Analizando cargas...')
         i += 1
         fechaCarga = utils.convertir_a_fechahora(carga.fechaCarga)
         if not fechaCarga:
             self.logger.error("silos::leer_datos_cargas_descargas -> "
                 "La carga %s tiene una fecha no válida: %s" % (
                     carga.puid, carga.fechaCarga))
             continue
         if fechaCarga not in datos:
             datos[fechaCarga] = {'cargas': [carga, ], 'descargas': []}
         else:
             datos[fechaCarga]['cargas'].append(carga)
     for descarga in silo.consumos:
         vpro.set_valor(i/tot, 'Analizando consumos...')
         i += 1
         if descarga.parteDeProduccionID != None:
             fecha = utils.convertir_a_fechahora(
                         descarga.parteDeProduccion.fecha)
         else:
             #fecha = None
             self.logger.error("silos::leer_datos_cargas_descargas -> "
                 "La descarga %s no tiene fecha porque no tiene parte"
                 "de producción." % (descarga.puid))
             continue
         if fecha not in datos:
             datos[fecha] = {'cargas': [], 'descargas': [descarga, ]}
         else:
             datos[fecha]['descargas'].append(descarga)
     vpro.ocultar()
     return datos
Example #12
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()
 def muestra_stock(self, boton = None):
     """
     Escribe el stock del producto en el widget.
     """
     producto = self.objeto
     from ventana_progreso import VentanaProgreso
     vpro = VentanaProgreso(padre = self.wids['ventana'])
     vpro.mostrar()
     vpro.set_valor(0.9, 'Contando existencias en almacén...')
     while gtk.events_pending(): gtk.main_iteration(False)
     self.wids['e_stock'].set_text("%s Kg" 
         % utils.float2str(round(producto.get_stock(),2)))
     vpro.ocultar()
Example #14
0
 def rellenar_widgets(self, boton = None):
     """
     Busca los productos coincidentes con la cadena del entry y los muestra en el TreeView.
     """
     from ventana_progreso import VentanaProgreso
     vpro = VentanaProgreso(padre = self.wids['ventana'])
     vpro.mostrar()
     a_buscar = self.wids['e_a_buscar'].get_text()
     pcs = pclases.ProductoCompra.select(
        pclases.OR(pclases.ProductoCompra.q.codigo.contains(a_buscar), 
                   pclases.ProductoCompra.q.descripcion.contains(a_buscar)), 
        orderBy = "descripcion")
     resultados = []
     i = 0.0
     tot = pcs.count() * len(self.__tarifas)
     for pc in pcs:
         vpro.set_valor(i/tot, 'Recuperando %s...' % pc.descripcion)
         fila = ["PC:%d" % pc.id, 
                 pc.codigo, 
                 pc.descripcion, 
                 utils.float2str(pc.existencias), 
                 utils.float2str(pc.precioDefecto)]
         for tarifa in self.__tarifas:
             if tarifa.esta_en_tarifa(pc):
                 porcentaje = tarifa.get_porcentaje(pc)
                 precio = tarifa.obtener_precio(pc)
                 fila.append("%s (%s %%)" % (utils.float2str(precio * 1.18), 
                                             utils.float2str(porcentaje, 1)))
             else:
                 fila.append("-")
             i += 1
         fila.append(pc.id)
         resultados.append(fila)
     resultados.sort(func_por_descripcion)
     model = self.wids['tv_datos'].get_model()
     self.wids['tv_datos'].freeze_child_notify()
     self.wids['tv_datos'].set_model(None)
     model.clear()
     for e in resultados:
         model.append(e)
     self.wids['tv_datos'].set_model(model)
     self.wids['tv_datos'].thaw_child_notify()
     vpro.ocultar()
Example #15
0
 def mostrar_silo(self, boton, silo):
     """
     Recibe el silo del que hay que mostrar el detalle de 
     cargas y descargas (consumos) y muestra una ventana con las 
     mismas ordenadas por fecha.
     """
     cd_fechas = self.leer_datos_cargas_descargas(silo)
     vpro = VentanaProgreso(padre = self.wids['ventana'])
     vpro.mostrar()
     i = 0.0
     tot = len(cd_fechas)
     datos = []
     fechas = cd_fechas.keys()
     fechas.sort()
     total_cargado = 0
     total_descargado = 0
     for fecha in fechas:
         vpro.set_valor(i/tot, 'Analizando movimientos...')
         i = i+1
         str_fecha = utils.str_fecha(fecha)
         for carga in cd_fechas[fecha]['cargas']:
             datos.append((str_fecha, carga.productoCompra.descripcion, 
                           utils.float2str(carga.cantidad), "", "", ""))
             total_cargado += carga.cantidad
         for descarga in cd_fechas[fecha]['descargas']: 
             producto_fabricado = "CLIC PARA VER [%d]" % (descarga.id)
             datos.append((str_fecha, "", "", 
                           descarga.productoCompra.descripcion, 
                           utils.float2str(descarga.cantidad), 
                           producto_fabricado))
             total_descargado += descarga.cantidad
     datos.append(("", "TOTAL CARGAS: ", utils.float2str(total_cargado), 
                   "TOTAL CONSUMOS: ", utils.float2str(total_descargado), 
                   ""))
     vpro.ocultar()
     utils.dialogo_resultado(datos, 
         titulo = "DETALLE DE CARGAS Y CONSUMOS DEL SILO", 
         padre = self.wids['ventana'], 
         cabeceras = ("Fecha", "Producto cargado", "Cantidad cargada", 
                      "Producto consumido", "Cantidad consumida", 
                      "Producto fabricado"), 
         func_change = self.mostrar_info_producto_fabricado)
 def buscar(self, boton):
     """
     Busca todos los productos e introduce en los TreeViews las existencias 
     de los mismos. En total y por almacén.
     El total no lo calcula, se obtiene del total global (que debería 
     coincidir con el sumatorio de...).
     """
     # DONE: Faltan los abonos por descontar.
     fechaini = self.wids['e_fechaini'].get_text().strip()
     if fechaini:
         try:
             fechaini = utils.parse_fecha(fechaini)
         except (ValueError, TypeError):
             utils.dialogo_info(titulo = "ERROR EN FECHA INICIAL", 
              texto = "El texto «%s» no es una fecha correcta." % fechaini,
              padre = self.wids['ventana'])
             fechaini = None
     fechafin = self.wids['e_fechafin'].get_text().strip()
     if fechafin:
         try:
             fechafin = utils.parse_fecha(fechafin)
         except (ValueError, TypeError):
             utils.dialogo_info(titulo = "ERROR EN FECHA FINAL", 
              texto = "El texto «%s» no es una fecha correcta." % fechafin,
              padre = self.wids['ventana'])
             fechafin = None
     if fechafin:
         FV = pclases.FacturaVenta
         VC = pclases.VencimientoCobro   # Para asegurarme de 
                                         # que tiene vencimientos.
         FDA = pclases.FacturaDeAbono
         C = pclases.Cobro
         if fechaini:
             facturas = FV.select(pclases.AND(
                                     FV.q.fecha >= fechaini, 
                                     FV.q.fecha <= fechafin, 
                                     VC.q.facturaVentaID == FV.q.id))
             # Busco los abonos (facturas de abono, en realidad, que no 
             # tienen por qué tener la misma fecha) que no hayan sido 
             # incluidos en facturas (porque si no el importe ya se habría 
             # contado en la factura anterior) ni en pagarés (porque 
             # entonces ya estarían en un documento de pago y por tanto 
             # no deberían aparecer en esta consulta)
             abonos = FDA.select(pclases.AND(
                 FDA.q.fecha >= fechaini, 
                 FDA.q.fecha <= fechafin))
         else:
             facturas = FV.select(pclases.AND(
                                     FV.q.fecha <= fechafin, 
                                     VC.q.facturaVentaID == FV.q.id))
             abonos = FDA.select(FDA.q.fecha <= fechafin)
         # No me queda otra que filtrar así aunque sea lento:
         abonos_pendientes = []
         for a in abonos:
             if not a.abono:
                 continue # ¿Error de borrado de un abono? Mmm... mal rollo.
             if a.abono.facturasVenta:
                 continue
             if a.cobros or a.pagosDeAbono:    
                             # Cada cobro de abono está relacionado 
                             # con un pagaré (o con lo que sea en un 
                             # posible futuro, el caso es que no 
                             # estaría pendiente).
                 continue
             abonos_pendientes.append(a)
         from ventana_progreso import VentanaProgreso
         vpro = VentanaProgreso(padre = self.wids['ventana'])
         vpro.mostrar()
         txtvpro = "Buscando facturas sin documento de pago..."
         nodos_clientes = {}
         total = 0.0
         i = 0.0
         vpro.set_valor(i, txtvpro)
         model = self.wids['tv_datos'].get_model()
         model.clear()
         facturas_tratadas = []  # Porque la consulta duplica facturas si 
             # tienen 2 vencimientos. Triplica si 3, etc.
         for f in facturas:
             i += 1
             vpro.set_valor(i/(facturas.count() + len(abonos_pendientes)), 
                            txtvpro)
             if f in facturas_tratadas:
                 continue
             facturas_tratadas.append(f)
             # Aquí voy a hacer un segundo filtro usando la cantidad 
             # pendiente de cobro de cada factura.
             #pendiente = f.calcular_pendiente_cobro()
             pendiente = f.calcular_pendiente_de_documento_de_pago()
             pendiente = round(pendiente, 2)
             if pendiente: 
                 #cliente = f.cliente
                 #if cliente not in nodos_clientes:
                 #    nodos_clientes[cliente] = model.append(None, 
                 #        (cliente.nombre, "", "", "", "0", 
                 #         -cliente.id))
                 total += pendiente
                 fechas_vto = f.vencimientosCobro[:]
                 fechas_vto.sort(lambda v1, v2: (v1.fecha < v2.fecha and -1)
                                             or (v1.fecha > v2.fecha and 1)
                                             or 0)
                 fechas_vto = [utils.str_fecha(v.fecha) 
                                   for v in f.vencimientosCobro]
                 vtos = "; ".join(fechas_vto)
                 # CWT: Resulta que quería un listado con los contactos de 
                 # las empresas para llamarlos y que paguen, pero ahora 
                 # prefiere que no aparezcan esos contactos porque la 
                 # mayoría están mal.
                 #info_contacto = "\n".join(
                 # (f.cliente.telefono, 
                 #  f.cliente.fax, 
                 #  "\n".join(f.cliente.email.replace(",", " ").replace(";", " ").split()), 
                 #  f.cliente.contacto))
                 # CWT: Prefiere listview, se acabó agrupar por cliente.
                 #nodo_padre = nodos_clientes[f.cliente]
                 nodo_padre = None
                 model.append(nodo_padre, 
                              #("", 
                              (f.cliente.nombre, 
                               f.numfactura, 
                               utils.str_fecha(f.fecha), 
                               vtos, 
                               utils.float2str(pendiente), 
                               # info_contacto, 
                               f.id))
                 #model[nodo_padre][4] = utils.float2str(
                 #    utils._float(model[nodo_padre][4]) + pendiente)
         for a in abonos_pendientes:
             pendiente = a.calcular_importe_total()  # O está descontada 
             # entera o no lo está. Con los abonos no hay pagos parciales.
             pendiente = round(pendiente, 2)
             if pendiente: 
                 total += pendiente
                 vtos = utils.str_fecha(a.fecha)  # Tampoco tiene 
                 # vencimientos. La obligación nace desde el mismo día 
                 # en que el abono se convierte en factura de abono.
                 nodo_padre = None
                 model.append(nodo_padre, 
                              (a.cliente.nombre, 
                               a.numfactura, 
                               utils.str_fecha(a.fecha), 
                               vtos, 
                               utils.float2str(pendiente), 
                               -a.id)) # Para distinguirlo de las facturas. 
             i += 1
             vpro.set_valor(i/(facturas.count() + len(abonos_pendientes)), 
                            txtvpro)
         vpro.ocultar()
         self.wids['e_total'].set_text(utils.float2str(total))
    def buscar(self, boton):
        """
        A partir de las fechas de inicio y fin de la ventana busca los
        artículos con trazabilidad y los clasifica por A, B y C en metros,
        kilos reales CON embalaje y bultos. También busca los productos de
        compra con las cantidades que salieron o entraron.
        """
        from ventana_progreso import VentanaProgreso

        vpro = VentanaProgreso(padre=self.wids["ventana"])
        vpro.mostrar()
        fini = utils.parse_fecha(self.wids["e_fechainicio"].get_text())
        ffin = utils.parse_fecha(self.wids["e_fechafin"].get_text())
        vpro.set_valor(0.0, "Buscando albaranes de salida...")
        self.albs = pclases.AlbaranSalida.select(
            pclases.AND(pclases.AlbaranSalida.q.fecha >= fini, pclases.AlbaranSalida.q.fecha < ffin), orderBy="fecha"
        )
        fib = {}
        gtx = {}
        cem = {}
        otros = {}
        i = 0.0
        tot = self.albs.count()
        for a in self.albs:
            i += 1
            vpro.set_valor(i / tot, "Analizando albarán %s..." % a.numalbaran)
            if a.es_de_movimiento():
                continue  # No cuento los interalmacenes porque me falsean
                # los totales ya que en realidad la mercancía no se ha movido
                # a ningún sitio todavía. Simplemente se han mandado a otro
                # almacén en espera de ser vendidos definitivamente al cliente.
                # Esa venta, aunque no se facture, es la que debe contar. Da
                # igual que sea venta a cliente o salida por consumo propio.
                # Los interalmacenes no implican salida real de mercancía,
                # solo movimiento.
            extract_data_from_albaran(a, fib, gtx, cem, otros)
        # Abonos
        vpro.set_valor(0.0, "Buscando abonos...")
        self.adedas = pclases.AlbaranDeEntradaDeAbono.select(
            pclases.AND(
                pclases.AlbaranDeEntradaDeAbono.q.fecha >= fini, pclases.AlbaranDeEntradaDeAbono.q.fecha < ffin
            ),
            orderBy="fecha",
        )
        i = 0.0
        tot = self.adedas.count()
        for a in self.adedas:
            i += 1
            vpro.set_valor(i / tot, "Analizando abono %s..." % a.numalbaran)
            extract_data_from_abono(a, fib, gtx, cem, otros)
        vpro.ocultar()
        tot_fib, tot_gtx, tot_cem = self.rellenar_tabla(fib, gtx, cem, otros)
        self.rellenar_totales(tot_fib, "fibra")
        self.rellenar_totales(tot_gtx, "gtx")
        self.rellenar_totales(tot_cem, "cem")
Example #18
0
 def preparar_datos_recuperacion(self, empleados, partes_result, fecha, aux):
     """
     A partir de los partes de producción recibidos genera una lista de diccionarios
     del tipo {'nombre': , 'horas': , 'extra': , 'noche': , 'extra_n': , 'total': , 'id': } donde se 
     guarda una entrada por empleado que contiene el nombre completo, las horas 
     "normales" trabajadas, las horas extras (día y noche), las que entran en franja nocturna 
     (de 22:00 a 6:00) y el total de horas entre todos los partes en los que trabajó.
     El id no se usará, pero es el del empleado.
     Todas las horas se devolverán en formato HH:MM
     """
     res = empleados
     # aux = {}
     try:
         turnonoche = pclases.Turno.select(pclases.Turno.q.noche == True)[0] 
     except IndexError:
         utils.dialogo_info(titulo = "TURNO DE NOCHE NO ENCONTRADO",
                            texto = "No se encontró un turno de noche definido.\nDebe configurar uno.",
                            padre = self.wids['ventana'])
         return
     ininoche = mx.DateTime.DateTimeDeltaFrom(hours = turnonoche.horainicio.hour, 
                                              minutes = turnonoche.horainicio.minute)
     finnoche = mx.DateTime.DateTimeDeltaFrom(hours = turnonoche.horafin.hour, 
                                              minutes = turnonoche.horafin.minute)
     # Hay que ordenar los partes por fecha y hora para que se contabilicen 
     # bien las horas extras.
     from ventana_progreso import VentanaProgreso
     vpro = VentanaProgreso(padre = self.wids['ventana'])
     vpro.mostrar()
     i = 0.0
     tot = partes_result.count()
     partes = []
     for p in partes_result:
         vpro.set_valor(i/tot, "Obteniendo partes de trabajo...")
         partes.append(p)
         i += 1
     vpro.set_valor(1, "Ordenando partes de trabajo...")
     partes.sort(self.func_sort_partes_t)
     i = 0.0
     for ht in partes:
         vpro.set_valor(i/tot, "Analizando partes de trabajo...")
         if ht.empleado.id not in aux:
             self.new_dic_empleado(aux, res, ht)
         pos = aux[ht.empleado.id]['pos']
         # Hora de inicio y fin de trabajo (hora inicio del primer parte y fin del último parte)
         # fin con la fecha de fin del último parte tratado.
         if res[pos]['horainicio'] == None or res[pos]['horainicio'] > utils.DateTime2DateTimeDelta(ht.horainicio):
             res[pos]['horainicio'] = utils.DateTime2DateTimeDelta(ht.horainicio)
         if res[pos]['horafin'] == None or res[pos]['horafin'] < utils.DateTime2DateTimeDelta(ht.horafin) or \
            utils.DateTime2DateTimeDelta(ht.horafin) < res[pos]['horainicio']:
             res[pos]['horafin'] = utils.DateTime2DateTimeDelta(ht.horafin)
         if ht not in res[pos]['partes']:
             res[pos]['partes'].append(ht)   # Aquí HT es un parte de trabajo, que equivale a los HT de los PDP.
         # Cálculo de las horas nocturnas:
         if self.get_solo_hora(ht.horainicio) >= ininoche and \
            self.get_solo_hora(ht.horafin) <= finnoche:
             noche = ht.horas
         else:
             noche = mx.DateTime.DateTimeDeltaFrom(hours = 0)
         if self.get_solo_hora(ht.horafin) < finnoche:
             dia = (ht.horainicio - mx.DateTime.oneDay).strftime('%Y-%m-%d')
         else:
             dia = ht.horainicio.strftime('%Y-%m-%d')
         if dia not in aux[ht.empleado.id]['fechas']:
             aux[ht.empleado.id]['fechas'][dia] = mx.DateTime.DateTimeDelta(0)
         if aux[ht.empleado.id]['fechas'][dia] + ht.horas > mx.DateTime.DateTimeDeltaFrom(hours = 8):
             extra = aux[ht.empleado.id]['fechas'][dia] + \
                     ht.horas - \
                     mx.DateTime.DateTimeDeltaFrom(hours = 8)
             aux[ht.empleado.id]['fechas'][dia] = mx.DateTime.DateTimeDeltaFrom(hours = 8) 
         else:
             extra = mx.DateTime.DateTimeDelta(0)
             aux[ht.empleado.id]['fechas'][dia] += ht.horas
         # Ya tengo las horas nocturas (variable noche) y las extras (extra). 
         # Guardo valores en el diccionario de resultados globales:
         if noche != 0:  # Un mx.DateTime... == 0 da True si es de 0 horas, 0 minutos...
             res[pos]['noche'] += noche - extra
             res[pos]['extra_n'] += extra
         else:
             res[pos]['horas'] += ht.horas - extra
             res[pos]['extra'] += extra
         # OJO: NOTA: HARCODED. Pero es que no encuentro otra forma de hacerlo.
         ct_gtx, ct_fib, ct_gmp, ct_almacen = self.get_centros()
         ct = ht.centroTrabajo
         if ct != None and ct == ct_gtx:
             res[pos]['mgtx'] += ht.horas
         elif ct != None and ct == ct_fib:
             res[pos]['mfib'] += ht.horas
         elif ct != None and ct == ct_gmp:
             res[pos]['mgmp'] += ht.horas
         elif ct != None and ct == ct_almacen:
             res[pos]['almacen'] += ht.horas
         else:
             res[pos]['varios'] += ht.horas
         res[pos]['total'] += ht.horas
         res[pos]['observaciones'] += "%s " % ht.trabajo
         # FIXME: No sé bien por qué no funciona el cálculo anterior de horas extras, así que:
         ocho_horas = mx.DateTime.DateTimeDeltaFrom(hours = 8)
         if res[pos]['total'] > ocho_horas:
             res[pos]['extra'] = res[pos]['total'] - ocho_horas
         i += 1
     vpro.ocultar()
     return res
Example #19
0
 def preparar_datos(self, partes_result, fecha):
     """
     A partir de los partes de producción recibidos genera una lista de 
     diccionarios del tipo {'nombre': , 'horas': , 'extra': , 'noche': , 
     'extra_n': , 'total': , 'id': } donde se guarda una entrada por 
     empleado que contiene el nombre completo, las horas "normales" 
     trabajadas, las horas extras (día y noche), las que entran en franja 
     nocturna (de 22:00 a 6:00) y el total de horas entre todos los partes 
     en los que trabajó.
     El id no se usará, pero es el del empleado.
     Todas las horas se devolverán en formato HH:MM
     """
     # WTF: Esto hay que refactorizarlo PERO YA.
     # NOTA: fechaini y fechafin no se llegan a usar. Las conservo 
     # porque aún está en pruebas el funcionamiento de la distribución 
     # de horas (se usaba para discriminar los partes pertenecientes
     # a otra jornada laboral distinta del día natural.
     res = []
     aux = {}
     try:
         turnonoche = pclases.Turno.select(pclases.Turno.q.noche == True)[0] 
         # No debería haber ni más ni menos que 1.
     except IndexError:
         utils.dialogo_info(titulo = "TURNO DE NOCHE NO ENCONTRADO",
                            texto = "No se encontró un turno de noche definido.\nDebe configurar uno.",
                            padre = self.wids['ventana'])
         return
     ininoche = mx.DateTime.DateTimeDeltaFrom(hours = turnonoche.horainicio.hour,  # @UnusedVariable
                                              minutes = turnonoche.horainicio.minute)
     finnoche = mx.DateTime.DateTimeDeltaFrom(hours = turnonoche.horafin.hour, 
                                              minutes = turnonoche.horafin.minute)
     # Hay que ordenar los partes por fecha y hora para que se contabilicen 
     # bien las horas extras.
     from ventana_progreso import VentanaProgreso
     vpro = VentanaProgreso(padre = self.wids['ventana'])
     vpro.mostrar()
     i = 0.0
     tot = partes_result.count()
     partes = []
     for p in partes_result:
         vpro.set_valor(i/tot, "Obteniendo partes de producción...")
         partes.append(p)
         i += 1
     vpro.set_valor(1, "Ordenando partes de producción...")
     partes.sort(self.func_sort_partes)
     i = 0.0
     for p in partes:
         vpro.set_valor(i/tot, "Analizando partes de producción...")
         for ht in p.horasTrabajadas:
             if ht.empleado.id not in aux:
                 self.new_dic_empleado(aux, res, ht)
             pos = aux[ht.empleado.id]['pos']
             # Hora de inicio y fin de trabajo (hora inicio del primer 
             # parte y fin del último parte)
             # fin con la fecha de fin del último parte tratado.
             # FIXME: Si por ejemplo 2 partes: de 22:00 a 5:00 y de 5:00 a 
             #   6:00, en lugar de poner horainicio y horafin a 22:00 y 6:00
             #   respectivamente, pone como horainicio 5:00 y como horafin 
             #   6:00. Sin embargo, el cómputo de horas sí es correcto.
             if res[pos]['horainicio'] == None or res[pos]['horainicio'] > ht.parteDeProduccion.fechahorainicio:
                 res[pos]['horainicio'] = ht.parteDeProduccion.fechahorainicio
             if res[pos]['horafin'] == None or res[pos]['horafin'] < ht.parteDeProduccion.fechahorafin or \
                 ht.parteDeProduccion.fechahorafin < res[pos]['fechahorainicio']:  # Es del día siguiente
                 res[pos]['horafin'] = ht.parteDeProduccion.fechahorafin
             if ht.parteDeProduccion not in res[pos]['partes']:
                 res[pos]['partes'].append(ht.parteDeProduccion)
             # Cálculo de las horas nocturnas:
             #if ht.parteDeProduccion.horainicio >= ininoche and \
             #    ht.parteDeProduccion.horafin <= finnoche:
             if ht.parteDeProduccion.es_nocturno():
                 # OJO: Nunca se dará un parte que cubra dos franjas 
                 # horarias de dos turnos diferentes, por tanto, si por 
                 # ejemplo un empleado hace 2 horas de un parte de 6
                 # o las 6 horas son completas de noche (y por lo tanto 
                 # las 2 del trabajador) o son de día. Resumiendo: No hay 
                 # partes que empiecen p. ej. a las 16:00 y acaben después 
                 # de las 22:00 y viceversa. De todas formas chequeo las 
                 # dos horas por si acaso. 
                 # IMPORTANTE: si se sale de la franja de noche, quedará 
                 # marcado como NO NOCTURNO.
                 noche = ht.horas
             else:
                 noche = mx.DateTime.DateTimeDeltaFrom(hours = 0)
             # Cálculo de las horas extras: El primer parte del día es el de 
             # las 6:00. 
             # Si la hora de inicio del parte es inferior a esa, se 
             # considerará del día anterior a efectos de horas extras.
             try:
                 empieza_en_turno_de_dia = (
                         ht.parteDeProduccion.horainicio < finnoche)
             except TypeError:
                 finnoche = datetime.time(finnoche.hour, finnoche.minute)
                 empieza_en_turno_de_dia = (
                         ht.parteDeProduccion.horainicio < finnoche)
             if empieza_en_turno_de_dia:
                 dia = (ht.parteDeProduccion.fecha - mx.DateTime.oneDay)
             else:
                 dia = ht.parteDeProduccion.fecha
             if dia not in aux[ht.empleado.id]['fechas']:
                 aux[ht.empleado.id]['fechas'][dia] = mx.DateTime.DateTimeDelta(0)
             if aux[ht.empleado.id]['fechas'][dia] + ht.horas > mx.DateTime.DateTimeDeltaFrom(hours = 8):
                 extra = aux[ht.empleado.id]['fechas'][dia] + \
                         ht.horas - \
                         mx.DateTime.DateTimeDeltaFrom(hours = 8)
                 aux[ht.empleado.id]['fechas'][dia] = mx.DateTime.DateTimeDeltaFrom(hours = 8) 
             else:
                 extra = mx.DateTime.DateTimeDelta(0)
                 aux[ht.empleado.id]['fechas'][dia] += ht.horas
             # Ya tengo las horas nocturas (variable noche) y las extras (extra). 
             # Guardo valores en el diccionario de resultados globales:
             if noche != 0:  # Un mx.DateTime... == 0 da True si es de 0 horas, 0 minutos...
                 res[pos]['noche'] += noche - extra
                 res[pos]['extra_n'] += extra
             else:
                 res[pos]['horas'] += ht.horas - extra
                 res[pos]['extra'] += extra
             if ht.parteDeProduccion.es_de_balas():
                 res[pos]['fib'] += ht.horas
             else:   
                 # PLAN: Hasta se que abra la línea de geocompuestos, 
                 # si no es de bala, es de geotextiles.
                 res[pos]['gtx'] += ht.horas
             res[pos]['total'] += ht.horas 
             # FIXME: No sé bien por qué no funciona el cálculo anterior 
             # de horas extras, así que:
             ocho_horas = mx.DateTime.DateTimeDeltaFrom(hours = 8)
             if res[pos]['total'] > ocho_horas:
                 res[pos]['extra'] = res[pos]['total'] - ocho_horas
         i += 1
     vpro.ocultar()
     return res, aux
 def rellenar_tabla(self, rollos_por_producto):
 	"""
     Rellena el model con el listado de rollos correspondiente.
     """
     from ventana_progreso import VentanaProgreso
     vpro = VentanaProgreso(padre = self.wids['ventana'])
 	model = self.wids['tv_rollos'].get_model()
 	model.clear()
     metros_almacen = 0
     rollos_almacen = 0
     metros_fabricados = 0
     i = 0.0
     totales_por_producto = {}   
         # Totales por producto. Fabricados y en almacén.
     tot = sum([len(rollos_por_producto[p]) 
                for p in rollos_por_producto.keys()])
     vpro.mostrar()
     # XXX Primer intento de acelerar los treeview
     self.wids['tv_rollos'].freeze_child_notify()
     self.wids['tv_rollos'].set_model(None)
     # XXX
     for p in rollos_por_producto:
         nodo_producto = model.append(None, (p.descripcion, 
                                             "", 
                                             "", 
                                             p.codigo, 
                                             "", 
                                             "", 
                                             p.id))
         if nodo_producto not in totales_por_producto:
             totales_por_producto[nodo_producto] = [0, 0, 0.0, 0.0]
             # Rollos fabricados, rollos en almacén.
             # Metros cuadrados fabricados, metros cuadrados en almacén.
         for rd in rollos_por_producto[p]:
             a = rd.articulo
             metros2 = a.superficie 
             vpro.set_valor(i/tot, 'Añadiendo rollo %s...' % a.codigo)
             if (a.albaranSalida != None 
                 and a.albaranSalida.fecha <= self.fin):
                 # FILTRO LOS ALBARANES FUERA DEL RANGO SUPERIOR DE 
                 # FECHAS PARA QUE APAREZCAN COMO QUE ESTABAN EN ALMACÉN 
                 # ANTES DE ESE DÍA.
                 info_albaran = "%s (%s)" % (a.albaranSalida.numalbaran, 
                                 utils.str_fecha(a.albaranSalida.fecha))
                 model.append(nodo_producto, 
                              (a.codigo,
                               utils.str_fecha(a.rolloDefectuoso.fechahora),
                               "CLIC PARA VER", 
                               a.partida.codigo,
                               info_albaran,
                               utils.float2str(a.get_largo(), autodec=True), 
                               a.id))
             else:   # En almacén en el rango de fechas especificado.
                 model.append(nodo_producto, 
                              (a.codigo,
                               utils.str_fecha(a.rolloDefectuoso.fechahora),
                               utils.str_fecha(a.rolloDefectuoso.fechahora),
                               a.partida.codigo,
                               '-',
                               utils.float2str(a.get_largo(), autodec=True), 
                               a.id))
                 totales_por_producto[nodo_producto][1] += 1
                 totales_por_producto[nodo_producto][3] += metros2
                 metros_almacen += metros2
                 rollos_almacen += 1
             metros_fabricados += metros2
             i += 1
             totales_por_producto[nodo_producto][0] += 1
             totales_por_producto[nodo_producto][2] += metros2
     # XXX Primer intento de acelerar los treeview
     self.wids['tv_rollos'].set_model(model)
     self.wids['tv_rollos'].thaw_child_notify()
     # XXX
     vpro.ocultar()
     # self.wids['e_total_almacen'].set_text(str(metros_almacen)+' m²')
     # self.wids['e_total_fabricado'].set_text(str(metros_fabricados)+' m²')
     self.wids['e_total_almacen'].set_text('%s m² (%d rollos)' % (utils.float2str(metros_almacen, 0), rollos_almacen))
     self.wids['e_total_fabricado'].set_text('%s m² (%d rollos)' % (utils.float2str(metros_fabricados, 0), tot))
     for iter in totales_por_producto:
         model[iter][5] = "%d (%s) / %d (%s)" % (
             totales_por_producto[iter][1], 
             utils.float2str(totales_por_producto[iter][3]),
             totales_por_producto[iter][0], 
             utils.float2str(totales_por_producto[iter][2]))
def buscar_pendiente_servir(cliente = None, padre = None, wids = None):
    """
    Devuelve una tupla de 4 listas:
    pedidos pendientes de servir de fibra, total de fibra pendiente de servir 
    por producto, pedidos pendientes de servir de geotextiles, total de 
    geotextiles pendientes de servir por producto.
    Si "cliente" es distinto de None, busca sólo entre los pedidos del cliente.
    El parámetro "padre" se recibe para poder centrar la barra de progreso.
    """
    from ventana_progreso import VentanaProgreso
    vpro = VentanaProgreso(padre = padre)
    vpro.mostrar()
    if wids != None:
        wids['cbe_cliente'].pop_down()      # Por si se queda abierto el 
                        # combobox y no deja ver la ventana de progreso.
    while gtk.events_pending(): gtk.main_iteration(False)
    fibra_por_pedido = fibra_por_producto = None
    gtx_por_pedido = gtx_por_producto = None
    if pclases.ProductoVenta.select().count() > 0:
        vpro.set_valor(1/9.0, 
            "Analizando pedidos pendientes de servir (fibra)...")
        fibra = build_diccionario_pendiente_servir(cliente, "fibra")
        vpro.set_valor(2/9.0, 
            "Analizando pedidos pendientes de servir (geotextiles)...")
        gtx = build_diccionario_pendiente_servir(cliente, "geotextiles")
    vpro.set_valor(3/9.0, "Analizando pedidos pendientes de servir (otros)...")
    otros = build_diccionario_pendiente_servir(cliente, "otros")

    if pclases.ProductoVenta.select().count() > 0:
        vpro.set_valor(4/9.0, 
            "Analizando pedidos pendientes de servir (fibra)...")
        fibra_por_pedido, raw_fibra_por_producto=build_datos_por_pedido(fibra)
        vpro.set_valor(5/9.0, 
            "Analizando pedidos pendientes de servir (geotextiles)...")
        gtx_por_pedido, raw_gtx_por_producto = build_datos_por_pedido(gtx)
    vpro.set_valor(6/9.0, "Analizando pedidos pendientes de servir (otros)...")
    otros_por_pedido, raw_otros_por_producto = build_datos_por_pedido(otros)

    if pclases.ProductoVenta.select().count() > 0:
        vpro.set_valor(7/9.0, 
            "Analizando pedidos pendientes de servir (fibra)...")
        fibra_por_producto = build_datos_por_producto(raw_fibra_por_producto)
        vpro.set_valor(8/9.0, 
            "Analizando pedidos pendientes de servir (geotextiles)...")
        gtx_por_producto = build_datos_por_producto(raw_gtx_por_producto)
    vpro.set_valor(9/9.0, "Analizando pedidos pendientes de servir (otros)...")
    otros_por_producto = build_datos_por_producto(raw_otros_por_producto)
    vpro.ocultar()
    return (fibra_por_pedido, fibra_por_producto, 
            gtx_por_pedido, gtx_por_producto, 
            otros_por_pedido, otros_por_producto)
Example #22
0
    def rellenar_tabla(self, partes, solobalas):
    	"""
        Rellena el model con los tipos de material existentes
        """        
        from ventana_progreso import VentanaProgreso
        vpro = VentanaProgreso(padre = self.wids['ventana'])
    	model = self.wids['tv_datos'].get_model()
    	model.clear()
        total = 0
        kilosproducidos = 0
        kilosgranza = 0
        personasturno = 0
        vector = []
        tot = len(partes)
        i = 0.0
        vpro.mostrar()
        e_personasturno = 0
        tiempototal = 0
        tiemporeal = 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]))
        # ... 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
        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.
    	for p in partes:
            if p.se_solapa():
                self.logger.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 "", p.id))
                p.bloqueado = False
                continue
            vpro.set_valor(i/tot, 'Añadiendo parte %s...' % (
                                    utils.str_fecha(p.fecha)))
            kilosgranza_del_parte = 0.0
            tiempototal, tiemporeal = self.calcular_tiempo_trabajado(p)
            tiempototaltotal += tiempototal
            try:
                # print tiemporeal, tiempototal
                productividad = (tiemporeal.seconds / tiempototal.seconds)*100
            except ZeroDivisionError:
                productividad = 100     # Bueno, el máximo es 1 (100%). Es lo 
                                    # más parecido a infinito positivo, ¿no?
            if productividad < 0:
                productividad = 0
                self.logger.warning("consulta_productividad::rellenar_tabla "
                    "-> Parte con productividad NEGATIVA: %s" % p)
            # Tratamiento especial para partes de balas
            if (self.wids['r_balas'].get_active() 
                or self.wids['r_ambos'].get_active()):   # Sólo balas o todos. 
                if p.es_de_fibra(): 
                    balas = [a.bala for a in p.articulos if a.balaID != None]
                    bigbags = [a.bigbag for a in p.articulos if a.bigbagID != None]
                    for b in balas:
                        kilosproducidos += b.pesobala
                    for b in bigbags:
                        kilosproducidos += b.pesobigbag
                    kilosgranza_del_parte = p.get_granza_consumida()
                    kilosgranza += kilosgranza_del_parte
                    if p.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) !!!" % (p.id, utils.str_fecha(p.fecha), utils.float2str(kilosgranza_del_parte), utils.float2str(p.get_produccion()[0])))     
                                                                    # XXX DEBUG
            if (self.wids['r_cemento'].get_active() 
                or self.wids['r_ambos'].get_active()):
                kilosproducidos += p.get_produccion()[0]
                kilosconsumidos += sum([bb.pesobigbag for bb in p.bigbags])
            if (self.wids['r_rollos'].get_active()
                or self.wids['r_ambos'].get_active()):  # Sólo rollos o todos.
                if p.es_de_geotextiles():
                    superficies_defectuosos = [a.superficie 
                        for a in p.articulos if a.es_rollo_defectuoso()]
                    metrosproducidos += sum(superficies_defectuosos)
                    rollos = [a.rollo for a in p.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.
                        metrosproducidos += len(rollos) * p.articulos[0].productoVenta.camposEspecificosRollo.ancho * p.articulos[0].productoVenta.camposEspecificosRollo.metrosLineales
                        if p.articulos[0].es_rollo():
                            partida = p.articulos[0].rollo.partida
                        elif p.articulos[0].es_rollo_defectuoso():
                            partida = p.articulos[0].rolloDefectuoso.partida
                        else:
                            partida = None
                        if partida != None:
                            contar_kilosconsumidos_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_kilosconsumidos_partidas_completas:
                                        kilosconsumidos_partidas_completas += bpesobala
                                    balas_consumidas.append(b)
            
            empleados = len(p.horasTrabajadas)
            e_personasturno += empleados
            tiempoparte = p.get_duracion().hours
            if tiempoparte > 0:
                personashora.append(empleados/tiempoparte)
            else:
                personashora.append(0.0)
            
            vector.append(productividad)
            produccion = p.get_produccion()

            # Resúmenes por día como nodos padre del TreeView.
            if dia_actual != utils.str_fecha(p.fecha):
                if dia_actual != "":  # Actualizo el padre
                    if not self.wids['r_ambos'].get_active():
                        model[padre][3] = "%s %s" % (utils.float2str(produccion_actual), produccion[1])
                    else:   # Evito mezclar kilos con metros
                        model[padre][3] = "-"
                    try:
                        productividad_actual /= nodos_hijos_por_dia
                    except ZeroDivisionError:
                        productividad_actual = 100.0    # A falta de infinito.
                    model[padre][4] = "%s %%" % (utils.float2str(productividad_actual))
                    model[padre][5] = productividad_actual
                dia_actual = utils.str_fecha(p.fecha)
                produccion_actual = 0.0
                productividad_actual = 0.0
                nodos_hijos_por_dia = 0
                padre = model.append(None, 
                            (utils.str_fecha(p.fecha), 
                             "", 
                             "", 
                             "", 
                             "%s %%" % (utils.float2str(productividad_actual)), 
                             productividad_actual,
                             0))
            model.append(padre, 
                (utils.str_fecha(p.fecha),
                 str(p.horainicio)[:5],
                 str(p.horafin)[:5],
                 "%s %s" % (utils.float2str(produccion[0]), produccion[1]),
                 "%s %%" % (utils.float2str(productividad)),
                 productividad,
                 p.id))
            produccion_actual += produccion[0]
            # BUG: Es media ponderada, no media aritmética:            productividad_actual += productividad
            # BUG: Es media ponderada, no media aritmética:            nodos_hijos_por_dia += 1
            productividad_actual += productividad * p.get_duracion().hours
            nodos_hijos_por_dia += p.get_duracion().hours
            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][3] = "%s %s" % (utils.float2str(produccion_actual), produccion[1])
            else:   # Evito mezclar kilos con metros
                model[padre][3] = "-"
            try:
                productividad_actual /= nodos_hijos_por_dia
            except ZeroDivisionError:
                productividad_actual = 100.0    # A falta de infinito...
            model[padre][4] = "%s %%" % (utils.float2str(productividad_actual))
            model[padre][5] = productividad_actual

        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 = total / len(partes)    
            total = sum([r[-2] for r in self.wids['tv_datos'].get_model() if r.parent == None]) / len([r for r in self.wids['tv_datos'].get_model() if r.parent == None])
            # 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. 
(En un caso se cuentan solo partidas de carga cuyas partidas de geotextiles se hayan completado estrictamente antes o en la cota superior. 
En el otro, por exceso, se contabilizan partidas completas aunque parte de su producción se salga del rango de fechas.
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)))
                self.wids['e_kilosgranza'].set_text("%s kg ~ %s kg" % (utils.float2str(kilosconsumidos_partidas_completas), 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(total / 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)))
Example #23
0
    def buscar(self, boton):
        """
        Dadas fecha de inicio y de fin, lista todos los albaranes
        pendientes de facturar.
        """
        from ventana_progreso import VentanaProgreso
        vpro = VentanaProgreso(padre = self.wids['ventana'])
        vpro.mostrar()
        i = 0.0
        clientes = pclases.Cliente.selectBy(inhabilitado = False)
        tot = clientes.count()
        por_edad = dict(zip(STR_RANGOS_EDAD, map(lambda x: 0, STR_RANGOS_EDAD)))
        por_profesion = {}
        por_sexo = {"Masculino": 0, "Femenino": 0}
        por_clases = {}
        por_padecimientos = {}
        for c in clientes:
            vpro.set_valor(i / tot, "Generando estadísticas...")
            c.sync()    # Por si ha habido cambios en algún cliente.
            # Edad:
            rango_edad = determinar_rango_edad(c, RANGOS_EDAD)
            clave_edad = STR_RANGOS_EDAD[RANGOS_EDAD.index(rango_edad)]
            por_edad[clave_edad] += 1
            # Profesión: 
            profesion = c.profesion.upper().strip()
            try:
                por_profesion[profesion] += 1
            except KeyError:
                por_profesion[profesion] = 1
            # Clases:
            for pc in c.productosContratados:
                p = pc.productoCompra.descripcion
                try:
                    por_clases[p] += 1
                except KeyError:
                    por_clases[p] = 1
            # Sexo: 
            if c.sexoMasculino:
                por_sexo["Masculino"] += 1
            else:
                por_sexo["Femenino"] += 1
            # Padecimientos: 
            for pad in c.padecimientos:
                p = pad.texto.upper().strip()
                try:
                    por_padecimientos[p] += 1
                except KeyError:
                    por_padecimientos[p] = 1
            i += 1

        for ntv, res, graf in (("tv_edad", por_edad, self.g_edad), 
                               ("tv_profesion", 
                                por_profesion, 
                                self.g_profesion), 
                               ("tv_sexo", por_sexo, self.g_sexo), 
                               ("tv_clases", por_clases, self.g_clases), 
                               ("tv_padecimientos", 
                                por_padecimientos, 
                                self.g_padecimientos)):
            self.rellenar_tabla(ntv, res)
            self.actualizar_grafica(graf, res)
        vpro.ocultar()
Example #24
0
    def rellenar_tabla(self, lista_balas = None, lista_bigbags = None,
                       lista_cajas = None):
        """
        Rellena el model con el listado de balas correspondiente
        """
        self.wids['tv_balas'].get_column(5).set_property("visible",
                                                         lista_cajas == None)
        if lista_cajas != None:   # Delego en otra función
            self.rellenar_pales(lista_cajas)
            return
        from ventana_progreso import VentanaProgreso
        vpro = VentanaProgreso(padre = self.wids['ventana'])
        model = self.wids['tv_balas'].get_model()
        model.clear()
        kilos_almacen = 0
        kilos_fabricados = 0
        bultos_almacen = 0
        bultos_fabricados = 0
        i = 0.0
        if lista_balas != None:
            lista = lista_balas
        elif lista_bigbags != None:
            lista = lista_bigbags
        else:
            return
        tot = lista.count()
        vpro.mostrar()
        # XXX Primer intento de acelerar los treeview
        self.wids['tv_balas'].freeze_child_notify()
        self.wids['tv_balas'].set_model(None)
        # XXX
        for t in lista:
            # kilos = t.bala.pesobala
            kilos = t.peso
            vpro.set_valor(i/tot, 'Añadiendo %s...' % t.codigo_interno)
            if t.albaranSalida != None and t.albaranSalida.fecha <= self.fin:
                # FILTRO LOS ALBARANES FUERA DEL RANGO SUPERIOR DE FECHAS PARA
                # QUE APAREZCAN COMO QUE ESTABAN EN ALMACÉN ANTES DE ESE DÍA.
                if t.balaID != None:
                    model.append(None,
                                 (t.bala.codigo,
                                  utils.str_fecha(t.bala.fechahora),
                                  utils.float2str(t.bala.pesobala, 1),
                                  t.bala.lote.numlote,
                                  "%s (%s)" % (t.albaranSalida.numalbaran,
                                    utils.str_fecha(t.albaranSalida.fecha)),
                                  t.bala.partidaCarga
                                    and t.bala.partidaCarga.codigo or "-",
                                  t.bala.analizada(),
                                  t.bala.claseb,
                                  t.almacen and t.almacen.nombre or "",
                                  t.puid))
                elif t.bigbagID != None:
                    if t.bigbag.parteDeProduccionID:
                        info_consumo = " (consumido el %s. %s)" % (
                            utils.str_fecha(t.bigbag.parteDeProduccion.fecha),
                            t.bigbag.parteDeProduccion.partidaCem.codigo)
                    else:
                        info_consumo = ""
                    model.append(None,
                                 (t.bigbag.codigo,
                                  utils.str_fecha(t.bigbag.fechahora),
                                  utils.float2str(t.bigbag.pesobigbag, 1),
                                  t.bigbag.loteCem.codigo,
                                  t.albaranSalida.numalbaran + info_consumo,
                                  '-',
                                  False,
                                  t.bigbag.claseb,
                                  t.almacen and t.almacen.nombre or "",
                                  t.puid))
                elif t.balaCableID != None:
                    model.append(None,
                                 (t.balaCable.codigo,
                                  utils.str_fecha(t.balaCable.fechahora),
                                  utils.float2str(t.balaCable.peso, 1),
                                  "N/A",
                                  t.albaranSalida.numalbaran,
                                  '-',
                                  False,
                                  True,
                                  t.almacen and t.almacen.nombre or "",
                                  t.puid))
                kilos_fabricados += kilos
                bultos_fabricados += 1
            elif (t.bala and t.bala.partidaID != None
                  and (t.bala.partida.fecha <= self.fin + mx.DateTime.oneDay
                       or t.bala.partida.fecha <= datetime.datetime(
                        *(self.fin + datetime.timedelta(days = 1)).tuple()[:3])
                      )
                 ):
                    # La fecha de la partida lleva hora, hay que compararla con las 00:00:00 del día siguiente.
                # FILTRO LAS BALAS CONSUMIDAS EN UNA PARTIDA PERO POSTERIORMENTE A LA FECHA DE FIN DE RANGO DE BÚSQUEDA.
                if t.albaranSalida:
                    numalbaran = t.albaranSalida.numalbaran
                else: # No tiene albarán de consumo, pero SÍ partida de carga.
                    numalbaran = "Consumida en partida carga %d" % (
                        t.bala.partidaCarga.numpartida)
                model.append(None,
                             (t.bala.codigo,
                              utils.str_fecha(t.bala.fechahora),
                              utils.float2str(t.bala.pesobala, 1),
                              t.bala.lote.numlote,
                              numalbaran,
                              t.bala.partida.codigo,
                              t.bala.analizada(),
                              t.bala.claseb,
                              t.almacen and t.almacen.nombre or "",
                              t.puid))
                kilos_fabricados += kilos
                bultos_fabricados += 1
            else:
                kilos_fabricados += kilos
                bultos_fabricados += 1
                kilos_almacen += kilos
                bultos_almacen += 1
                if t.balaID != None:
                    if t.bala.lote != None:
                        numlote = t.bala.lote.numlote
                    else:
                        numlote = "¡SIN LOTE!"
                    model.append(None,
                                 (t.bala.codigo,
                                  utils.str_fecha(t.bala.fechahora),
                                  utils.float2str(t.bala.pesobala, 1),
                                  numlote,
                                  '-',
                                  '-',
                                  t.bala.analizada(),
                                  t.bala.claseb,
                                  t.almacen and t.almacen.nombre or "",
                                  t.puid))
                elif t.bigbagID != None:
                    model.append(None,
                                 (t.bigbag.codigo,
                                  utils.str_fecha(t.bigbag.fechahora),
                                  utils.float2str(t.bigbag.pesobigbag, 1),
                                  t.bigbag.loteCem.codigo,
                                  '-',
                                  '-',
                                  False,
                                  t.bigbag.claseb,
                                  t.almacen and t.almacen.nombre or "",
                                  t.puid))
                elif t.balaCableID != None:
                    numlote = "N/A"
                    model.append(None,
                                 (t.balaCable.codigo,
                                  utils.str_fecha(t.balaCable.fechahora),
                                  utils.float2str(t.balaCable.peso, 1),
                                  numlote,
                                  '-',
                                  '-',
                                  False,
                                  True,
                                  t.almacen and t.almacen.nombre or "",
                                  t.puid))
            i += 1
        # XXX Primer intento de acelerar los treeview
        self.wids['tv_balas'].set_model(model)
        self.wids['tv_balas'].thaw_child_notify()
        # XXX
        vpro.ocultar()

        self.wids['e_total_almacen'].set_text("%s kg (%d bultos)" % (
            utils.float2str(kilos_almacen), bultos_almacen))
        self.wids['e_total_fabricado'].set_text("%s kg (%d bultos)" % (
            utils.float2str(kilos_fabricados), bultos_fabricados))
        self.colorear(self.wids['tv_balas'])
Example #25
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")
 def buscar(self, boton):
     """
     Dadas fecha de inicio y de fin, busca todas las ventas 
     (facturadas) entre esas dos fechas.
     """
     from ventana_progreso import VentanaProgreso
     vpro = VentanaProgreso(padre = self.wids['ventana'])
     vpro.mostrar()
     # print self.fin, self.inicio
     vpro.set_valor(0.0, "Analizando prefacturas...")
     idcliente = utils.combo_get_value(self.wids['cbe_cliente'])
     self.resultado = []
     fechafin = datetime.date(day = int(self.fin.split("/")[2]), 
                                         month = int(self.fin.split("/")[1]), 
                                         year = int(self.fin.split("/")[0]))
     if self.inicio == None:
         prefacturas = pclases.Prefactura.select(pclases.Prefactura.q.fecha <= fechafin, orderBy = 'fecha')
         vpro.set_valor(0.5, "Analizando prefacturas...")
     else:
         fechainicio = datetime.date(day = int(self.inicio.split("/")[2]), 
                                                month = int(self.inicio.split("/")[1]), 
                                                year = int(self.inicio.split("/")[0]))
         prefacturas = pclases.Prefactura.select(pclases.AND(pclases.Prefactura.q.fecha >= fechainicio,
                                                             pclases.Prefactura.q.fecha <= fechafin), orderBy='fecha')
         vpro.set_valor(0.5, "Analizando prefacturas...")
     self.resultado = list(prefacturas)
     vpro.set_valor(0.8, "Analizando prefacturas...")
     self.resultado.sort(self.por_fecha)
     vpro.set_valor(0.9, "Analizando prefacturas...")
     vpro.ocultar()
     self.rellenar_tabla(self.resultado)
    def buscar(self, boton):
        # DONE: Faltan los abonos por descontar.
        fechaini = self.wids["e_fechaini"].get_text().strip()
        if fechaini:
            try:
                fechaini = utils.parse_fecha(fechaini)
            except (ValueError, TypeError):
                utils.dialogo_info(
                    titulo="ERROR EN FECHA INICIAL",
                    texto="El texto «%s» no es una fecha correcta." % fechaini,
                    padre=self.wids["ventana"],
                )
                fechaini = None
        fechafin = self.wids["e_fechafin"].get_text().strip()
        if fechafin:
            try:
                fechafin = utils.parse_fecha(fechafin)
            except (ValueError, TypeError):
                utils.dialogo_info(
                    titulo="ERROR EN FECHA FINAL",
                    texto="El texto «%s» no es una fecha correcta." % fechafin,
                    padre=self.wids["ventana"],
                )
                fechafin = None
        if fechaini and fechafin and fechafin < fechaini:
            fechaini, fechafin = fechafin, fechaini
            self.wids["e_fechaini"].set_text(utils.str_fecha(fechaini))
            self.wids["e_fechafin"].set_text(utils.str_fecha(fechafin))
        if fechafin:
            FV = pclases.FacturaVenta
            VC = pclases.VencimientoCobro  # Para asegurarme de
            # que tiene vencimientos.
            FDA = pclases.FacturaDeAbono
            C = pclases.Cobro
            T = pclases.Tarea
            if fechaini:
                facturas = FV.select(
                    pclases.AND(FV.q.fecha >= fechaini, FV.q.fecha <= fechafin, VC.q.facturaVentaID == FV.q.id)
                )
                # Busco los abonos (facturas de abono, en realidad, que no
                # tienen por qué tener la misma fecha) que no hayan sido
                # incluidos en facturas (porque si no el importe ya se habría
                # contado en la factura anterior) ni en pagarés (porque
                # entonces ya estarían en un documento de pago y por tanto
                # no deberían aparecer en esta consulta)
                # ...
                # He decidido que no voy a sacar los abonos. No van a tener
                # ventana de seguimiento y no se le pueden relacionar tareas.
                # Además, esta ventana era para reclamar pagos, no para pagar.
                # abonos = FDA.select(pclases.AND(
                #    FDA.q.fecha >= fechaini,
                #    FDA.q.fecha <= fechafin))
                abonos = []
            else:
                facturas = FV.select(pclases.AND(FV.q.fecha <= fechafin, VC.q.facturaVentaID == FV.q.id))
                # abonos = FDA.select(FDA.q.fecha <= fechafin)
                abonos = []
            # No me queda otra que filtrar así aunque sea lento:
            abonos_pendientes = []
            for a in abonos:
                if not a.abono:
                    continue  # ¿Error de borrado de un abono? Mmm... mal rollo.
                if a.abono.facturasVenta:
                    continue
                if a.cobros:  # Cada cobro de abono está relacionado
                    # con un pagaré (o con lo que sea en un
                    # posible futuro, el caso es que no
                    # estaría pendiente).
                    continue
                abonos_pendientes.append(a)
            from ventana_progreso import VentanaProgreso

            vpro = VentanaProgreso(padre=self.wids["ventana"])
            vpro.mostrar()
            txtvpro = "Buscando facturas sin documento de pago..."
            nodos_clientes = {}
            total = 0.0
            i = 0.0
            vpro.set_valor(i, txtvpro)
            model = self.wids["tv_datos"].get_model()
            model.clear()
            facturas_added = []
            # Aprovecho para chequear alarmas automáticas.
            pclases.Alarma.crear_alarmas_automaticas(facturas)
            for f in facturas:
                # Aquí voy a hacer un segundo filtro usando la cantidad
                # pendiente de cobro de cada factura.
                # pendiente = f.calcular_pendiente_cobro()
                pendiente = f.calcular_pendiente_de_documento_de_pago()
                pendiente = round(pendiente, 2)
                if pendiente and f not in facturas_added:
                    total += pendiente
                    cliente = f.cliente
                    if cliente not in nodos_clientes:
                        tmp_nodo = model.append(None, (cliente.nombre, "", "", "", "0", "", cliente.id))
                        nodos_clientes[cliente] = {"nodo_cliente": tmp_nodo}
                    obra = f.obra
                    nodo_cliente_padre = nodos_clientes[cliente]["nodo_cliente"]
                    if obra not in nodos_clientes[cliente]:
                        nodos_clientes[cliente][obra] = model.append(
                            nodo_cliente_padre,
                            (obra and obra.nombre or "Sin obra", "", "", "", "0", "", obra and obra.id or 0),
                        )
                    fechas_vto = f.vencimientosCobro[:]
                    fechas_vto.sort(lambda v1, v2: (v1.fecha < v2.fecha and -1) or (v1.fecha > v2.fecha and 1) or 0)
                    fechas_vto = [utils.str_fecha(v.fecha) for v in f.vencimientosCobro]
                    vtos = "; ".join(fechas_vto)
                    nodo_padre = nodos_clientes[cliente][obra]
                    last_evento = f.get_last_evento()
                    if last_evento:
                        last_evento = "[%s] %s" % (utils.str_fechahora(last_evento.fechahora), last_evento.texto)
                    else:
                        last_evento = ""
                    model.append(
                        nodo_padre,
                        (
                            "",
                            # (f.cliente.nombre,
                            f.numfactura,
                            utils.str_fecha(f.fecha),
                            vtos,
                            utils.float2str(pendiente),
                            last_evento,
                            f.id,
                        ),
                    )
                    model[nodo_padre][4] = utils.float2str(utils._float(model[nodo_padre][4]) + pendiente)
                    model[nodo_cliente_padre][4] = utils.float2str(
                        utils._float(model[nodo_cliente_padre][4]) + pendiente
                    )
                    facturas_added.append(f)
                i += 1
                vpro.set_valor(i / (facturas.count() + len(abonos_pendientes)), txtvpro)
            for a in abonos_pendientes:
                pendiente = a.calcular_importe_total()  # O está descontada
                # entera o no lo está. Con los abonos no hay pagos parciales.
                pendiente = round(pendiente, 2)
                if pendiente:
                    total += pendiente
                    vtos = utils.str_fecha(a.fecha)  # Tampoco tiene
                    # vencimientos. La obligación nace desde el mismo día
                    # en que el abono se convierte en factura de abono.
                    try:
                        cliente = a.cliente
                    except AttributeError:
                        txt = (
                            "crm_seguimiento_impagos.py::buscar"
                            " -> FacturaDeAbono %d sin Abono o Cliente."
                            " Ignorando. " % a.id
                        )
                        self.logger.error(txt)
                        continue
                    if cliente not in nodos_clientes:
                        tmp_nodo = model.append(None, (cliente.nombre, "", "", "", "0", "", cliente.id))
                        nodos_clientes[cliente] = {"nodo_cliente": tmp_nodo}
                    obra = a.obra
                    nodo_cliente_padre = nodos_clientes[cliente]["nodo_cliente"]
                    if obra not in nodos_clientes[cliente]:
                        nodos_clientes[cliente][obra] = model.append(
                            nodo_cliente_padre,
                            (obra and obra.nombre or "Sin obra", "", "", "", "0", "", obra and obra.id or 0),
                        )
                    nodo_padre = nodos_clientes[cliente][obra]
                    model.append(
                        nodo_padre,
                        # (a.cliente.nombre,
                        (
                            "",
                            a.numfactura,
                            utils.str_fecha(a.fecha),
                            vtos,
                            utils.float2str(pendiente),
                            "",  # Facturas de abono no tienen anotaciones.
                            -a.id,
                        ),
                    )  # Para distinguirlo de las facturas.
                    model[nodo_padre][4] = utils.float2str(utils._float(model[nodo_padre][4]) + pendiente)
                    model[nodo_cliente_padre][4] = utils.float2str(
                        utils._float(model[nodo_cliente_padre][4]) + pendiente
                    )
                i += 1
                vpro.set_valor(i / (facturas.count() + len(abonos_pendientes)), txtvpro)
            vpro.ocultar()
            self.wids["e_total"].set_text(utils.float2str(total))
            self.buscar_todos()
            self.buscar_anotaciones()
            self.buscar_alertas()
Example #28
0
    def rellenar_tabla(self, lista, defectuosos, gtxcs, producto):
        """
        Rellena el model con el listado de rollos correspondiente.
        OJO: Los rollos defectuosos se listan, pero no se cuentan para los 
        totales. Los rollos de Gtx C van aparte siempre.
        """
        from ventana_progreso import VentanaProgreso
        vpro = VentanaProgreso(padre = self.wids['ventana'])
        model = self.wids['tv_rollos'].get_model()
        model.clear()
        metros_almacen = 0
        rollos_almacen = 0
        metros_fabricados = 0
        kilosc_fabricados = kilosc = 0.0
        rollosc_fabricados = rollosc = 0
        i = 0.0
        # tot = len(lista)
        tot = lista.count() + defectuosos.count() + gtxcs.count()
        vpro.mostrar()
        # XXX Primer intento de acelerar los treeview
        self.wids['tv_rollos'].freeze_child_notify()
        self.wids['tv_rollos'].set_model(None)
        # XXX
        for a in defectuosos:
            metros2 = a.superficie 
            metros_fabricados += metros2
            vpro.set_valor(i/tot, 'Añadiendo rollo %s...' % a.codigo)
            if a.albaranSalida != None and a.albaranSalida.fecha <= self.fin:
                # FILTRO LOS ALBARANES FUERA DEL RANGO SUPERIOR DE FECHAS PARA
                # QUE APAREZCAN COMO QUE ESTABAN EN ALMACÉN ANTES DE ESE DÍA.
                try:
                    info_albaran = self.cache_albaranes[a.albaranSalida]
                except KeyError:
                    info_albaran = "%s (%s - %s)" % (a.albaranSalida.numalbaran, utils.str_fecha(a.albaranSalida.fecha), a.albaranSalida.get_str_tipo())
                    self.cache_albaranes[a.albaranSalida] = info_albaran
                model.append((a.codigo,
                              utils.str_fecha(a.rolloDefectuoso.fechahora),
                              "CLIC PARA VER", 
                              a.partida.codigo,
                              info_albaran,
                              utils.float2str(a.get_largo(), autodec = True), 
                              a.almacen and a.almacen.nombre or "", 
                              a.id))
            else:
                model.append((a.codigo,
                              utils.str_fecha(a.rolloDefectuoso.fechahora),
                              utils.str_fecha(a.rolloDefectuoso.fechahora),
                              a.partida.codigo,
                              '-',
                              utils.float2str(a.get_largo(), autodec = True), 
                              a.almacen and a.almacen.nombre or "", 
                              a.id))
            i += 1
        for a in gtxcs:
            vpro.set_valor(i/tot, 'Añadiendo rollo %s...' % a.codigo)
            rollosc_fabricados += 1
            kilosc_fabricados += a.peso
            if a.albaranSalida != None and a.albaranSalida.fecha <= self.fin:
                # FILTRO LOS ALBARANES FUERA DEL RANGO SUPERIOR DE FECHAS PARA 
                # QUE APAREZCAN COMO QUE ESTABAN EN ALMACÉN ANTES DE ESE DÍA.
                try:
                    info_albaran = self.cache_albaranes[a.albaranSalida]
                except KeyError:
                    info_albaran = "%s (%s - %s)" % (a.albaranSalida.numalbaran, utils.str_fecha(a.albaranSalida.fecha), a.albaranSalida.get_str_tipo())
                    self.cache_albaranes[a.albaranSalida] = info_albaran
                model.append((a.codigo,
                              utils.str_fecha(a.rolloC.fechahora),
                              utils.str_hora(a.rolloC.fechahora),
                              "N/A",
                              info_albaran,
                              "%s kg" % utils.float2str(a.peso), 
                              a.almacen and a.almacen.nombre or "", 
                              a.id))
                # Si tienen albarán hay un caso en que cuentan para almacén:
                if a.albaranSalida and a.albaranSalida.es_de_movimiento():
                    kilosc += a.peso
                    rollosc += 1
            else:
                model.append((a.codigo,
                              utils.str_fecha(a.rolloC.fechahora),
                              utils.str_hora(a.rolloC.fechahora),
                              "N/A",
                              '-',
                              "%s kg" % utils.float2str(a.peso), 
                              a.almacen and a.almacen.nombre or "", 
                              a.id))
                kilosc += a.peso
                rollosc += 1
            i += 1
        for t in lista:
            metros2 = t.productoVenta.camposEspecificosRollo.metrosLineales * t.productoVenta.camposEspecificosRollo.ancho
            metros_fabricados += metros2
            vpro.set_valor(i/tot, 'Añadiendo rollo %s...' % t.rollo.codigo)
            if t.albaranSalida != None and t.albaranSalida.fecha <= self.fin:
                # FILTRO LOS ALBARANES FUERA DEL RANGO SUPERIOR DE FECHAS PARA 
                # QUE APAREZCAN COMO QUE ESTABAN EN ALMACÉN ANTES DE ESE DÍA.
                try:
                    info_albaran = self.cache_albaranes[t.albaranSalida]
                except KeyError:
                    info_albaran = "%s (%s - %s)" % (t.albaranSalida.numalbaran, utils.str_fecha(t.albaranSalida.fecha), t.albaranSalida.get_str_tipo())
                    self.cache_albaranes[t.albaranSalida] = info_albaran
                model.append((t.rollo.codigo,
                        utils.str_fecha(t.rollo.fechahora),
                        # -----------------------------------------------------
                        # t.rollo.articulos[0].parteDeProduccion and utils.str_fecha(t.rollo.articulos[0].parteDeProduccion.fecha) or '',
                        # utils.str_fecha(t.rollo.fechahora),
                        "CLIC PARA VER", 
                        # -----------------------------------------------------
                        t.rollo.partida.codigo,
                        info_albaran,
                        utils.float2str(t.get_largo(), autodec = True), 
                        t.almacen and t.almacen.nombre or "", 
                        t.id))
                # Si tienen albarán hay un caso en que cuentan para almacén:
                if t.albaranSalida and t.albaranSalida.es_de_movimiento():
                    metros_almacen += metros2
                    rollos_almacen += 1
            else:
                model.append((t.rollo.codigo,
                        utils.str_fecha(t.rollo.fechahora),
                        # -----------------------------------------------------
                        # t.rollo.articulos[0].parteDeProduccion and utils.str_fecha(t.rollo.articulos[0].parteDeProduccion.fecha) or '',
                        utils.str_fecha(t.rollo.fechahora),
                        # -----------------------------------------------------
                        t.rollo.partida.codigo,
                        '-',
                        utils.float2str(t.get_largo(), autodec = True), 
                        t.almacen and t.almacen.nombre or "", 
                        t.id))
                metros_almacen += metros2
                rollos_almacen += 1
            i += 1
        # XXX Primer intento de acelerar los treeview
        self.wids['tv_rollos'].set_model(model)
        self.wids['tv_rollos'].thaw_child_notify()
        # XXX
        vpro.ocultar()

        # self.wids['e_total_almacen'].set_text(str(metros_almacen)+' m²')
        # self.wids['e_total_fabricado'].set_text(str(metros_fabricados)+' m²')
        if producto.es_rolloC():
            self.wids['e_total_almacen'].set_text('%s kg (%d rollos)' 
                % (utils.float2str(kilosc, 2), rollosc))
            self.wids['e_total_fabricado'].set_text('%s kg (%d rollos)' 
                % (utils.float2str(kilosc_fabricados, 2), rollosc_fabricados))
        else:
            self.wids['e_total_almacen'].set_text('%s m² (%d rollos)' 
                % (utils.float2str(metros_almacen, 0), rollos_almacen))
            self.wids['e_total_fabricado'].set_text('%s m² (%d rollos)' 
                % (utils.float2str(metros_fabricados, 0), tot))
Example #29
0
 def rellenar_pales(self, rs_cajas):
     """
     Rellena el model pero con los palés de los artículos en lugar de
     con los artículos (bolsas) en sí.
     """
     # Vamos a ir montando un diccionario de iteradores de palés y de ellos
     # voy a colgar las cajas.
     from ventana_progreso import VentanaProgreso
     vpro = VentanaProgreso(padre = self.wids['ventana'])
     model = self.wids['tv_balas'].get_model()
     model.clear()
     kilos_almacen = 0  # @UnusedVariable
     kilos_fabricados = 0
     bultos_almacen = 0
     bultos_fabricados = 0
     i = 0.0
     tot = rs_cajas.count()
     pales = {}
     cajas_tratadas = []
     cajas_por_pale = {}
     self.wids['tv_balas'].freeze_child_notify()
     self.wids['tv_balas'].set_model(None)
     vpro.mostrar()
     for caja in rs_cajas:
         vpro.set_valor(i/tot, 'Añadiendo cajas por palé... (%s)' %
                                 caja.codigo)
         i += 1
         if pclases.DEBUG:
             print caja.codigo, len(cajas_tratadas)
         if caja in cajas_tratadas:
             if pclases.DEBUG:
                 print "Esta me la salto. Ya está metida de otra bolsa."
             continue
         cajas_tratadas.append(caja)
         paleid = caja.pale.id
         try:
             iterpale = pales[paleid]
         except KeyError:
             pale = pclases.Pale.get(paleid)
             iterpale = self.insert_pale(model, pale)
             pales[paleid] = iterpale
             # Como los totales van por kilos y palés, aprovecho ahora.
             # Lleva el el total de cajas en almacén de ese palé, el número
             # de cajas en almacén del palé y los kilos de esas cajas.
             cajas_por_pale[paleid] = {'Total cajas': pale.numcajas,
                                       'Cajas en almacén': 0,
                                       'Kilos en almacén': 0.0}
             bultos_fabricados += 1
             kilos_fabricados += pale.calcular_peso()
         kilos_caja = caja.peso
         albaran = caja.albaranSalida
         if not albaran or albaran.fecha > self.fin:    # Cajas en almacén.
             # FILTRO LOS ALBARANES FUERA DEL RANGO SUPERIOR DE FECHAS PARA
             # QUE APAREZCAN COMO QUE ESTABAN EN ALMACÉN ANTES DE ESE DÍA.
             cajas_por_pale[paleid]['Cajas en almacén'] += 1
             cajas_por_pale[paleid]['Kilos en almacén'] += kilos_caja
         else:   # Ya no está en almacén. Tiene albarán o lo tiene anterior
                 # a la fecha superior de filtro.
             if pclases.DEBUG:
                 print "Esta caja (%s) no está en almacén." % caja.codigo
         itercaja = self.insert_caja(model, caja, iterpale)  # @UnusedVariable
     # Ahora añado la información de las cajas en almacén de cada palé.
     tot = len(cajas_por_pale)
     i = 0
     for idpale in pales:
         vpro.set_valor(i/tot,
                        'Analizando palés incompletos... (%d)' % idpale)
         iterpale = pales[idpale]
         total = cajas_por_pale[idpale]['Total cajas']
         en_almacen = cajas_por_pale[idpale]['Cajas en almacén']
         model[iterpale][0] += " (%d/%d)" % (en_almacen, total)
         i += 1
     # Restauro el model y pongo totales.
     self.wids['tv_balas'].set_model(model)
     self.wids['tv_balas'].thaw_child_notify()
     vpro.ocultar()
     kilos_almacen = sum([cajas_por_pale[idpale]['Kilos en almacén']
                          for idpale in cajas_por_pale])
     bultos_cajas = sum([cajas_por_pale[idpale]['Cajas en almacén']
                         for idpale in cajas_por_pale])
     bultos_cajas_totales = sum([cajas_por_pale[idpale]['Total cajas']
                                 for idpale in cajas_por_pale])
     try:
         bultos_almacen = ((bultos_fabricados * bultos_cajas)
                             / bultos_cajas_totales)
         # bultos_fabricados son los palés en total fabricados.
         # bultos_cajas son los palés que hay en almacén.
         # Y bultos_cajas_totales son las cajas que hay en total en los
         # palés fabricados. Es una simple regla de tres.
     except ZeroDivisionError:
         bultos_almacen = 0
     self.wids['e_total_almacen'].set_text("%s kg (%s palés)" % (
         utils.float2str(kilos_almacen),
         utils.float2str(bultos_almacen, autodec = True)))
     self.wids['e_total_fabricado'].set_text("%s kg (%d palés)" % (
         utils.float2str(kilos_fabricados), bultos_fabricados))
     self.colorear(self.wids['tv_balas'])
 def buscar(self, boton):
     """
     Dadas fecha de inicio y de fin, busca todas las ofertas 
     (de estudio) entre esas dos fechas.
     """
     self.por_oferta = {} # defaultdict(lambda: [])
     self.por_producto = defaultdict(lambda: [])
     self.por_cliente = defaultdict(lambda: [])
     self.por_comercial = defaultdict(lambda: [])
     self.por_provincia = defaultdict(lambda: [])
     total_ofertas = 0.0
     total_ofertas_siva = 0.0
     ratio = None
     from ventana_progreso import VentanaProgreso
     vpro = VentanaProgreso(padre = self.wids['ventana'])
     vpro.mostrar()
     if pclases.DEBUG:
         print "self.inicio", self.inicio, "self.fin", self.fin
     vpro.set_valor(0.0, "Buscando ofertas de estudio...")
     criterios = [pclases.Presupuesto.q.estudio == True]
     idcliente = utils.combo_get_value(self.wids['cbe_cliente'])
     if idcliente != -1:
         criterios.append(pclases.Presupuesto.q.clienteID == idcliente)
     idcomercial = utils.combo_get_value(self.wids['cbe_comercial'])
     if idcomercial != -1:
         criterios.append(pclases.Presupuesto.q.comercialID == idcomercial)
     if self.inicio:
         criterios.append(pclases.Presupuesto.q.fecha >= self.inicio)
     if self.fin:
         criterios.append(pclases.Presupuesto.q.fecha <= self.fin)
     if not criterios:
         presupuestos = pclases.Presupuesto.select(orderBy = "id")
     elif len(criterios) == 1:
         presupuestos = pclases.Presupuesto.select(criterios[0], 
                                                   orderBy = "id")
     else:
         presupuestos = pclases.Presupuesto.select(pclases.AND(*criterios), 
                                                   orderBy = "id")
     tot = presupuestos.count()
     i = 0.0
     for p in presupuestos:
         vpro.set_valor(i/tot, "Clasificando ofertas de estudio...")
         if p in self.por_oferta and pclases.DEBUG:
             txt = "consulta_ofertas_estudio.py::buscar -> "\
                   "El presupuesto %s aparece dos veces en la consulta." % (
                           p.puid)
             try:
                 sys.stdout.write(txt + "\n")
             except:
                 self.logger.warning(txt)
         self.por_oferta[p] = p
         for ldp in p.lineasDePresupuesto:
             producto = ldp.producto or ldp.descripcion
             self.por_producto[producto].append(ldp)
         self.por_cliente[p.cliente].append(p)
         self.por_comercial[p.comercial].append(p)
         self.por_provincia[p.provincia.upper()].append(p)
         importe_total = p.calcular_importe_total()
         total_ofertas += importe_total
         importe_total_siva = p.calcular_importe_total(iva = False)
         total_ofertas_siva += importe_total_siva
         i += 1
     self.rellenar_tabla_por_oferta(vpro)
     self.rellenar_tabla_por_producto(vpro)
     self.rellenar_tabla_por_cliente(vpro)
     self.rellenar_tabla_por_comercial(vpro)
     self.rellenar_tabla_por_provincia(vpro)
     vpro.ocultar()
     self.wids['e_total_ofertas'].set_text("%s €" % (
         utils.float2str(total_ofertas)))
     self.wids['e_total_ofertas_siva'].set_text("%s €" % (
         utils.float2str(total_ofertas_siva)))
     self.wids['e_numero_ofertas'].set_text("%d" % (tot)) # assert i == tot