def add_actividad(self, boton): texto = utils.dialogo_entrada(titulo = "NUEVA ACTIVIDAD", texto = "Introduzca la descripción de la nueva actividad deportiva:", padre = self.wids['ventana']) if texto != None: opciones = [(e.id, e.nombre) for e in pclases.Evento.select(orderBy = "nombre")] opciones.insert(0, (0, "Sin evento relacionado")) idevento = utils.dialogo_combo(titulo = "SELECCIONE EVENTO:", texto = "Seleccione un evento de la lista:", ops = opciones, padre = self.wids['ventana'], valor_por_defecto = 0) if idevento != None: if idevento == 0: evento = None else: evento = pclases.Evento.get(idevento) actividad = pclases.Actividad(descripcion = texto, evento = evento, fechahoraInicio = datetime.datetime.today(), fechahoraFin = datetime.datetime.today(), grupoAlumnos = self.objeto) model = self.wids['tv_actividades'].get_model() model.append((actividad.descripcion, actividad.evento and actividad.evento.nombre or "", utils.str_fechahora(actividad.fechahoraInicio), utils.str_fechahora(actividad.fechahoraFin), actividad.get_puid()))
def rellenar_tabla_actividades(self): model = self.wids['tv_actividades'].get_model() model.clear() for c in self.objeto.clientes: if not self.objeto.en_lista_de_espera(c): for p in c.actividades: model.append((p.descripcion, p.evento and p.evento.nombre or "", utils.str_fechahora(p.fechahoraInicio), utils.str_fechahora(p.fechahoraFin), p.get_puid()))
def buscar_alertas(self): idfras = [] if self.wids["tg_filtrar"].get_active(): # Filtrar por seleccionada. sel = self.wids["tv_datos"].get_selection() model, iters = sel.get_selected_rows() for iter in iters: id = model[iter][-1] if not model[iter].parent: # Es cliente for iterhijo in model[iter].iterchildren(): for iternieto in model[iterhijo.iter].iterchildren(): idfras.append(model[iternieto.iter][-1]) elif not model[iter].parent.parent: # Es obra for iterhijo in model[iter].iterchildren(): idfras.append(model[iterhijo.iter][-1]) else: # Es factura idfras.append(id) else: model = self.wids["tv_datos"].get_model() idfras = [] for fila in model: for hijo in model[fila.iter].iterchildren(): for nieto in model[hijo.iter].iterchildren(): idfras.append(model[nieto.iter][-1]) model = self.wids["tv_alarmas"].get_model() model.clear() hoy = mx.DateTime.today() for id in idfras: if id > 0: fra = pclases.FacturaVenta.get(id) for a in fra.alarmas: if a.fechahoraAlarma >= hoy + mx.DateTime.oneDay or not a.estado.pendiente: continue try: nombre_cliente = a.facturaVenta.cliente.nombre except AttributeError: nombre_cliente = "¡Sin cliente!" model.append( ( nombre_cliente, a.facturaVenta.numfactura, a.estado.descripcion, utils.str_fechahora(a.fechahora), a.texto, utils.str_fechahora(a.fechahoraAlarma), a.observaciones, a.id, ) )
def abrir_factura_from_alarma(self, tv, path, view_column): """ Abre la factura a la que pertenece la alarma en la ventana de detalles. """ model = tv.get_model() id = model[path][-1] a = pclases.Alarma.get(id) fra = a.facturaVenta import crm_detalles_factura v = crm_detalles_factura.CRM_DetallesFactura(fra, usuario=self.usuario) # Actualizo último evento porque probablemente lo haya cambiado # en la ventana recién abierta. El resto de datos de la # factura debería permanecer tal cual (¿A excepción de los # vencimientos? No creo. No se renegocian... o no debería.). model = self.wids["tv_datos"].get_model() last_evento = fra.get_last_evento() if last_evento: last_evento = "[%s] %s" % (utils.str_fechahora(last_evento.fechahora), last_evento.texto) else: last_evento = "" model[path][5] = last_evento self.buscar_todos() self.buscar_alertas() self.buscar_anotaciones()
def rellenar_tabla(self, balas): """ Introduce las balas recibidas en el TreeView «tv» y lo desplaza a la última fila (la más baja) """ tv = self.wids['tv_balas'] model = tv.get_model() tv.freeze_child_notify() tv.set_model(None) model.clear() totpantalla = 0.0 for bala, producto in balas: if producto != None: desc = producto.descripcion else: desc = "?" fila = (utils.str_fechahora(bala.fechahora), bala.codigo, utils.float2str(bala.peso, 1), desc, bala.observaciones, bala.id) model.append(fila) totpantalla += bala.peso_sin tv.set_model(model) tv.thaw_child_notify() self.rellenar_totales(totpantalla) self.mover_al_final(self.wids['tv_balas'])
def buscar_fecha(self, boton): """ Muestra el diálogo calendario y establece la fecha de la partida. """ partida = self.get_partida() if partida != None: fecha = utils.mostrar_calendario(fecha_defecto = partida.fecha, padre = self.wids['ventana']) fecha = utils.parse_fecha(utils.str_fecha(fecha)) partida.fecha = mx.DateTime.DateTimeFrom(day = fecha.day, month = fecha.month, year = fecha.year, hour = partida.fecha.hour, minute = partida.fecha.minute, second = partida.fecha.second) self.wids['e_fecha'].set_text(utils.str_fechahora(partida.fecha))
def rellenar_widgets(self): partida = self.get_partida() if partida != None: self.wids['e_partida'].set_text("%d (%s)" % (partida.numpartida, partida.codigo)) self.wids['e_fecha'].set_text(utils.str_fechahora(partida.fecha)) else: self.wids['e_partida'].set_text("") self.wids['e_fecha'].set_text("") self.rellenar_balas() self.rellenar_partidas_gtx() self.comprobar_permisos()
def fecha_from_pdp(self, boton): """ Busca la fecha más temprana de producción y se la asigna a la partida de carga. Si no hay producción aún, deja la actual. """ partida = self.get_partida() if partida != None: fecha = partida.get_fecha_inicio() if fecha: partida.fecha = fecha self.wids['e_fecha'].set_text(utils.str_fechahora(partida.fecha))
def rellenar_tabla(self, rollos): """ Rellena la tabla con la información de los rollos recibidos. """ model = self.wids['tv_datos'].get_model() model.clear() for r in rollos: model.append((r.codigo, r.partida and r.partida.codigo or "", r.albaranSalida and r.albaranSalida.numalbaran or "", utils.str_fechahora(r.fechahora), r.id))
def cambiar_fin_actividad(self, cell, path, text): model = self.wids['tv_actividades'].get_model() puid = model[path][-1] p = pclases.getObjetoPUID(puid) try: p.fechahoraFin = utils.parse_fechahora(text) p.syncUpdate() except (TypeError, ValueError): utils.dialogo_info(titulo = "ERROR DE FORMATO", texto = "La fecha %s no es correcta." % text, padre = self.wids['ventana']) else: model[path][3] = utils.str_fechahora(p.fechahoraFin)
def add_nueva_bala_tv(self, bala): """ Introduce la bala al final del TreeView y lo desplaza. """ model = self.wids['tv_balas'].get_model() fila = (utils.str_fechahora(bala.fechahora), bala.codigo, utils.float2str(bala.peso, 1), bala.productoVenta.descripcion, bala.observaciones, bala.id) model.append(fila) self.mover_al_final(self.wids['tv_balas'])
def fecha_from_albaran(self, boton): """ Busca la fecha del albarán interno. Si hay más de uno, selecciona el más temprano de ellos. Si no hay albarán interno, deja la actual. """ partida = self.get_partida() if partida != None: fecha = partida.get_fecha_inicio() if fecha: albaranes_internos = list(partida.get_albaranes_internos()) if albaranes_internos: albaranes_internos.sort(lambda a1, a2: (a1.fecha < a2.fecha and -1) or (a1.fecha > a2.fecha and 1) or 0) fecha = albaranes_internos[0].fecha partida.fecha = mx.DateTime.DateTimeFrom(day = fecha.day, month = fecha.month, year = fecha.year, hour = partida.fecha.hour, minute = partida.fecha.minute, second = partida.fecha.second) self.wids['e_fecha'].set_text(utils.str_fechahora(partida.fecha))
def buscar_anotaciones(self): idfras = [] if self.wids["tg_filtrar"].get_active(): # Filtrar por seleccionada. sel = self.wids["tv_datos"].get_selection() model, iters = sel.get_selected_rows() for iter in iters: id = model[iter][-1] if not model[iter].parent: # Es cliente for iterhijo in model[iter].iterchildren(): for iternieto in model[iterhijo.iter].iterchildren(): idfras.append(model[iternieto.iter][-1]) elif not model[iter].parent.parent: # Es obra for iterhijo in model[iter].iterchildren(): idfras.append(model[iterhijo.iter][-1]) else: # Es factura idfras.append(id) else: model = self.wids["tv_datos"].get_model() idfras = [] for fila in model: for hijo in model[fila.iter].iterchildren(): for nieto in model[hijo.iter].iterchildren(): idfras.append(model[nieto.iter][-1]) model = self.wids["tv_notas"].get_model() model.clear() for id in idfras: if id > 0: fra = pclases.FacturaVenta.get(id) for n in fra.notas: try: nombre_cliente = n.facturaVenta.cliente.nombre except AttributeError: nombre_cliente = "¡Sin cliente!" model.append( ( nombre_cliente, n.facturaVenta.numfactura, utils.str_fechahora(n.fechahora), n.texto, n.observaciones, n.id, ) )
def cambiar_todo_pendiente(self, cell, path): """ Cambia la tarea de pendiente a terminada. """ model = self.wids["tv_todos"].get_model() id = model[path][-1] tarea = pclases.Tarea.get(id) tarea.pendiente = model[path][0] if tarea.pendiente: tarea.fechadone = None else: tarea.fechadone = mx.DateTime.localtime() tarea.sync() model[path][0] = not tarea.pendiente if not tarea.pendiente: nota = pclases.Nota( facturaVenta=tarea.facturaVenta, fechahora=mx.DateTime.localtime(), texto="Se completó la tarea «%s»" % tarea.texto, observaciones="Creado automáticamente desde " "crm_seguimiento_impagos al cerrar la tarea %d" % (tarea.id), ) else: nota = pclases.Nota( facturaVenta=tarea.facturaVenta, fechahora=mx.DateTime.localtime(), texto="Se anuló el cierre de la tarea «%s»" % tarea.texto, observaciones="Creado automáticamente desde " "crm_seguimiento_impagos al abrir la tarea %d" % (tarea.id), ) last_evento = nota model = self.wids["tv_datos"].get_model() for fila in model: # print fila for hijo in model[fila.iter].iterchildren(): # print model[hijo.iter[-1]] if model[hijo.iter][-1] == tarea.facturaVentaID: last_evento = "[%s] %s" % (utils.str_fechahora(last_evento.fechahora), last_evento.texto) # print last_evento model[hijo.iter][5] = last_evento return # No quiero seguir recorriendo.
def edit_fechahora(cell, path, newtext, tv, numcol, clase, atributo): """ Cambia el texto del model[path][numcol] y del objeto relacionado que saca a partir del ID de la última columna del model. """ model = tv.get_model() id = model[path][-1] objeto = clase.get(id) try: fecha = utils.parse_fechahora(newtext) except (ValueError, TypeError): parent = tv.parent while parent != None: parent = parent.parent utils.dialogo_info(titulo = "ERROR EN FECHA Y HORA", texto = "El texto «%s» no es una fecha y hora válida." % (newtext), padre = parent) else: setattr(objeto, atributo, fecha) objeto.syncUpdate() model[path][numcol] = utils.str_fechahora(getattr(objeto, atributo))
def col2value(objeto, col): """ Convierte el valor del objeto a un formato legible en función de su tipo de datos. """ valor = getattr(objeto, col.name) if isinstance(col, pclases.SODateCol): # Es DATE. return utils.str_fecha(valor) elif isinstance(col, pclases.SOStringCol): # TEXT return valor elif isinstance(col, pclases.SOFloatCol): # FLOAT return utils.float2str(valor, autodec = True) elif isinstance(col, pclases.SOIntCol): # INT return valor elif isinstance(col, pclases.SOBoolCol): # BOOLEAN return valor elif isinstance(col, pclases.SOForeignKey): # Clave ajena. return valor # and valor.id or "" elif isinstance(col, pclases.SOCol): # Es TIMESTAMP o TIME if "timestamp" in str(col) or ("fecha" in col.name and "hora" in col.name): return utils.str_fechahora(valor) else: return utils.str_hora(valor)
def abrir_factura(self, tv, path, view_column): """ Abre la factura a la que pertenece el vencimiento sobre el que se ha hecho doble clic. """ model = tv.get_model() id = model[path][-1] if model[path].parent: # Es nodo hijo: abono o factura. if id > 0: # Si es negativo es un ID de cliente. No me interesa. fra = pclases.FacturaVenta.get(id) # import facturas_venta # v = facturas_venta.FacturasVenta(fra, usuario = self.usuario) import crm_detalles_factura v = crm_detalles_factura.CRM_DetallesFactura(fra, usuario=self.usuario) # Actualizo último evento porque probablemente lo haya cambiado # en la ventana recién abierta. El resto de datos de la # factura debería permanecer tal cual (¿A excepción de los # vencimientos? No creo. No se renegocian... o no debería.). last_evento = fra.get_last_evento() if last_evento: last_evento = "[%s] %s" % (utils.str_fechahora(last_evento.fechahora), last_evento.texto) else: last_evento = "" model[path][5] = last_evento elif id < 0: # Ahora los id negativos son de abonos, no clientes. fda = pclases.FacturaDeAbono.get(-id) a = fda.abono import abonos_venta v = abonos_venta.AbonosVenta(a, usuario=self.usuario) else: cliente = pclases.Cliente.get(id) import clientes v = clientes.Clientes(cliente, usuario=self.usuario)
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()