623 lines
19 KiB
Python
623 lines
19 KiB
Python
# coding: utf-8
|
|
#from datetime import datetime
|
|
from sqlalchemy.sql import func
|
|
from sqlalchemy.dialects.postgresql import UUID
|
|
from sqlalchemy.dialects import sqlite
|
|
|
|
from webinterface import db
|
|
from flask_login import current_user
|
|
from flask import current_app, g
|
|
import datetime
|
|
import unidecode
|
|
from webinterface.models.system import Persona
|
|
from webinterface.models.documentos import Documento
|
|
|
|
|
|
class Comision(db.Model):
|
|
__tablename__ = 'comisiones'
|
|
__table_args__ = { 'schema': 'gestion' }
|
|
__bind_key__ = 'system'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
nombre = db.Column(db.String(100), nullable=False)
|
|
descripcion = db.Column(db.String(100))
|
|
creado = db.Column(db.Integer, db.ForeignKey('gestion.comisiones.id'), nullable=False)
|
|
logo = db.Column(UUID(as_uuid=True), nullable=True, autoincrement=False)
|
|
titulo = db.Column(UUID(as_uuid=True), nullable=True, autoincrement=False)
|
|
|
|
__table_args__ = (db.UniqueConstraint('nombre', 'creado', name='nodupesComisiones'), { 'schema': 'gestion' })
|
|
|
|
@property
|
|
def supervisor(self):
|
|
return Comision.query.filter(Comision.id==self.creado).one_or_none()
|
|
|
|
@property
|
|
def quorum(self):
|
|
miembro = Miembro.query.filter(Miembro.comisionid==self.id).count()
|
|
if miembro == 0:
|
|
return False
|
|
else:
|
|
return miembro
|
|
|
|
@property
|
|
def miembros(self):
|
|
for miembro in Miembro.query.filter(Miembro.comisionid==self.id).all():
|
|
yield miembro.persona
|
|
|
|
def mvector(self):
|
|
vector = []
|
|
for persona in self.miembros:
|
|
vector.append(persona.id)
|
|
|
|
return vector
|
|
|
|
|
|
class Miembro(db.Model):
|
|
__tablename__ = 'miembros'
|
|
__table_args__ = { 'schema': 'gestion' }
|
|
__bind_key__ = 'system'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
personaid = db.Column(db.BigInteger, db.ForeignKey('usuarios.personas.id'))
|
|
comisionid = db.Column(db.Integer, db.ForeignKey('gestion.comisiones.id'))
|
|
|
|
persona = db.relationship('Persona')
|
|
comision = db.relationship('Comision')
|
|
|
|
class Objetivo(db.Model):
|
|
__tablename__ = 'objetivos'
|
|
__table_args__ = { 'schema': 'gestion' }
|
|
__bind_key__ = 'system'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
tipo = db.Column(db.String(100), nullable=False, default=u'Estratégico')
|
|
nombre = db.Column(db.String(200), nullable=False)
|
|
descripcion = db.Column(db.Text)
|
|
|
|
parentid = db.Column(db.Integer, db.ForeignKey('gestion.objetivos.id'), nullable=False)
|
|
responsableid = db.Column(db.Integer, db.ForeignKey('gestion.comisiones.id'), nullable=False)
|
|
invitadosid = db.Column(db.Integer, db.ForeignKey('gestion.comisiones.id'), nullable=True)
|
|
|
|
# indicadores = db.relationship('Avance', back_populates="objetivo", order_by='Accion.id.desc()')
|
|
actas = db.relationship('Acta', back_populates="objetivo", order_by='Acta.secuencia.desc()')
|
|
actividades = db.relationship('Accion', back_populates="objetivo", order_by='Accion.fecha.desc()')
|
|
responsable = db.relationship('Comision', foreign_keys=[responsableid])
|
|
invitados = db.relationship('Comision', foreign_keys=[invitadosid])
|
|
|
|
estado = db.Column(db.SmallInteger, default=100)
|
|
|
|
## registros de auditoria
|
|
creado = db.Column(db.DateTime, default=func.now())
|
|
creadopor = db.Column(db.Integer, db.ForeignKey('usuarios.personas.id'), nullable=True)
|
|
modificado = db.Column(db.DateTime, default=func.now(), onupdate=func.now())
|
|
modificadopor = db.Column(db.Integer, db.ForeignKey('usuarios.personas.id'), nullable=True)
|
|
|
|
@property
|
|
def actasr(self):
|
|
for item in Acta.query.filter(Acta.objetivoid==self.id).order_by(Acta.secuencia.asc()).all():
|
|
yield item
|
|
|
|
@property
|
|
def sub_HDS(self):
|
|
return round(self.sub_horas/26,2)
|
|
|
|
@property
|
|
def modulo(self):
|
|
return ModuloGestion.query.filter(ModuloGestion.basenodeid==self.get_root().parentid).one_or_none()
|
|
|
|
@property
|
|
def modulo_raw(self):
|
|
return ModuloGestion.query.filter(ModuloGestion.basenodeid==self.id).one_or_none()
|
|
|
|
@property
|
|
def indicadores(self):
|
|
for item in Avance.query.filter(Avance.objetivoid==self.id).order_by(Avance.id.asc()).all():
|
|
yield item
|
|
|
|
@property
|
|
def iactividades(self):
|
|
for item in Accion.query.filter(Accion.objetivoid==self.id).order_by(Accion.fecha.asc()).all():
|
|
yield item
|
|
|
|
@property
|
|
def hijos(self):
|
|
for item in Objetivo.query.filter(Objetivo.parentid==self.id, Objetivo.estado<100).order_by(Objetivo.id.asc()).all():
|
|
yield item
|
|
for item in Objetivo.query.filter(Objetivo.parentid==self.id, Objetivo.estado>=100).order_by(Objetivo.id.asc()).all():
|
|
yield item
|
|
|
|
@property
|
|
def padre(self):
|
|
return Objetivo.query.get(self.parentid)
|
|
|
|
@property
|
|
def icon_class(self):
|
|
return self.get_root().tipo
|
|
|
|
@property
|
|
def sub_actividades(self):
|
|
i = 0
|
|
for item in self.hijos:
|
|
i += item.sub_actividades
|
|
for item in self.actividades:
|
|
i += 1
|
|
return i
|
|
|
|
@property
|
|
def sub_horas(self):
|
|
h = 0
|
|
for item in self.hijos:
|
|
h += item.sub_horas
|
|
for item in self.actividades:
|
|
h += item.dedicacion
|
|
for item in self.actas:
|
|
h += item.dedicacion
|
|
|
|
return h
|
|
@property
|
|
def sub_HDS(self):
|
|
return round(self.sub_horas/26,2)
|
|
|
|
@property
|
|
def sub_avanceNormalizado(self):
|
|
base = 0
|
|
numBase = 0
|
|
|
|
for item in self.hijos:
|
|
base += item.sub_avanceNormalizado
|
|
numBase += 1
|
|
|
|
for item in self.indicadores:
|
|
base += item.avanceNormalizado
|
|
numBase += 1
|
|
|
|
return base/numBase if numBase else 0
|
|
|
|
@property
|
|
def sub_avance(self):
|
|
return round(100*self.sub_avanceNormalizado)
|
|
|
|
def is_root(self):
|
|
if self.padre.parentid == 1:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def get_root(self):
|
|
|
|
node = self
|
|
while node.padre.parentid > 1:
|
|
node = node.padre
|
|
|
|
return node
|
|
|
|
@property
|
|
def comisiones_validas(self):
|
|
node = self.get_root()
|
|
|
|
yield node.responsable
|
|
|
|
for comision in Comision.query.filter(Comision.creado == node.responsableid).all():
|
|
yield comision
|
|
|
|
@property
|
|
def miembros_responsables(self):
|
|
for miembro in self.responsable.miembros:
|
|
yield miembro
|
|
|
|
@property
|
|
def miembros_habilitados(self):
|
|
vistos = []
|
|
for miembro in self.responsable.miembros:
|
|
if miembro not in vistos:
|
|
vistos.append(miembro)
|
|
yield miembro
|
|
if self.invitados is not None:
|
|
for miembro in self.invitados.miembros:
|
|
if miembro not in vistos:
|
|
vistos.append(miembro)
|
|
yield miembro
|
|
|
|
@property
|
|
def archivado(self):
|
|
if self.estado < 100:
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
def lineage(self):
|
|
ancestrys=[]
|
|
|
|
node = self.padre
|
|
while node.parentid > 1:
|
|
ancestrys.append(node)
|
|
node = node.padre
|
|
|
|
for node in reversed(ancestrys):
|
|
yield node
|
|
|
|
def get_comisiones(self, lvl=1, archived=False):
|
|
|
|
if self.invitadosid is None:
|
|
comisiones = [self.responsableid]
|
|
else:
|
|
comisiones = [self.responsableid, self.invitadosid]
|
|
if lvl > 0:
|
|
lvl = lvl - 1
|
|
for objetivo in self.hijos:
|
|
if objetivo.estado is None or objetivo.estado<100 or archived:
|
|
comisiones = comisiones + objetivo.get_comisiones(lvl=lvl, archived=archived)
|
|
|
|
return comisiones
|
|
|
|
def visible(self, lvl=5, archived=False):
|
|
comisiones = self.get_comisiones(lvl=lvl, archived=archived)
|
|
if len(comisiones)>0:
|
|
comisiones = list(set(comisiones))
|
|
try:
|
|
comisiones.remove(1)
|
|
except:
|
|
pass
|
|
existe = Miembro.query.filter(Miembro.comisionid.in_(comisiones), Miembro.personaid==current_user.id).first()
|
|
if existe is None:
|
|
# current_app.logger.debug('[No-Visble] Nodo {}: {} ({})'.format(self.nombre, current_user.login, comisiones))
|
|
return False
|
|
else:
|
|
# current_app.logger.debug('[Visible] Nodo {}: {} ({})'.format(self.nombre, current_user.login, comisiones))
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
@property
|
|
def is_manager(self):
|
|
|
|
|
|
comisiones = list(set( [ self.responsableid, self.padre.responsableid ] ))
|
|
|
|
existe = Miembro.query.filter(Miembro.comisionid.in_(comisiones), Miembro.personaid==current_user.id).first()
|
|
if existe is None:
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
|
|
class Avance(db.Model):
|
|
__tablename__ = 'indicadores'
|
|
__table_args__ = { 'schema': 'gestion' }
|
|
__bind_key__ = 'system'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
objetivoid = db.Column(db.Integer, db.ForeignKey('gestion.objetivos.id'))
|
|
|
|
nombre = db.Column(db.String(200), nullable=False)
|
|
|
|
inicial = db.Column(db.Integer, default=0)
|
|
valor = db.Column(db.Integer)
|
|
meta = db.Column(db.Integer, default=100)
|
|
ponderacion = db.Column(db.Integer, default=1)
|
|
|
|
objetivo = db.relationship('Objetivo')
|
|
|
|
@property
|
|
def progreso(self):
|
|
if self.valor>self.inicial:
|
|
return self.valor-self.inicial
|
|
else:
|
|
return 0
|
|
@property
|
|
def previo(self):
|
|
return int(100.0*self.inicial/self.meta)
|
|
|
|
@property
|
|
def avanceNormalizado(self):
|
|
return min(self.progreso/(self.meta-self.inicial), 1)
|
|
|
|
@property
|
|
def avance(self):
|
|
return int(100.0*self.progreso/self.meta)
|
|
|
|
class Acta(db.Model):
|
|
__tablename__ = 'actas'
|
|
__table_args__ = { 'schema': 'gestion' }
|
|
__bind_key__ = 'system'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
objetivoid = db.Column(db.Integer, db.ForeignKey('gestion.objetivos.id'))
|
|
secuencia = db.Column(db.Integer)
|
|
|
|
horaini = db.Column(db.DateTime)
|
|
horafin = db.Column(db.DateTime)
|
|
|
|
lugar = db.Column(db.String, nullable=False)
|
|
|
|
temas = db.Column(db.Text)
|
|
desarrollo = db.Column(db.Text)
|
|
acuerdos = db.Column(db.Text)
|
|
|
|
objetivo = db.relationship('Objetivo', back_populates='actas')
|
|
miembros = db.relationship('MiembrosAsistentes', back_populates='acta')
|
|
invitados = db.relationship('InvitadosAsistentes', back_populates='acta')
|
|
anexos = db.relationship('AnexosActa', back_populates='acta')
|
|
|
|
## registros de auditoria
|
|
creado = db.Column(db.DateTime, default=func.now())
|
|
creadopor = db.Column(db.Integer, db.ForeignKey('usuarios.personas.id'), nullable=True)
|
|
modificado = db.Column(db.DateTime, default=func.now(), onupdate=func.now())
|
|
modificadopor = db.Column(db.Integer, db.ForeignKey('usuarios.personas.id'), nullable=True)
|
|
|
|
@property
|
|
def documentos(self):
|
|
for evidencia in self.anexos:
|
|
yield evidencia.documento
|
|
|
|
@property
|
|
def dedicacion(self):
|
|
import datetime
|
|
now = datetime.datetime.now()
|
|
if self.horaini < now and self.horafin < now:
|
|
timedelta = self.horafin - self.horaini
|
|
secondsdelta = timedelta.total_seconds()
|
|
horasdelta = secondsdelta / 3600.0
|
|
else:
|
|
horasdelta = 0
|
|
|
|
return horasdelta
|
|
|
|
@property
|
|
def correosasistentes(self):
|
|
asistentes = []
|
|
for persona in self.miembros:
|
|
asistentes.append( (persona.persona.nombrecompleto, persona.persona.correodefecto.correo) )
|
|
for persona in self.invitados:
|
|
asistentes.append( (persona.nombre, persona.correo) )
|
|
return asistentes
|
|
|
|
@property
|
|
def asistentes(self):
|
|
asistentes = []
|
|
for persona in self.miembros:
|
|
asistentes.append( persona.persona.nombrecompleto )
|
|
for persona in self.invitados:
|
|
asistentes.append( persona.nombre )
|
|
return asistentes
|
|
|
|
@property
|
|
def txtasistentes(self):
|
|
asistentes = []
|
|
for persona in self.miembros:
|
|
asistentes.append( persona.persona.nombrecompleto )
|
|
for persona in self.invitados:
|
|
asistentes.append( u"{} ({})".format(persona.nombre, persona.correo) )
|
|
|
|
return ", ".join(asistentes)
|
|
|
|
@property
|
|
def miembrosid(self):
|
|
listado = []
|
|
for persona in self.miembros:
|
|
listado.append( persona.personaid )
|
|
return listado
|
|
|
|
@property
|
|
def invitadostextarea(self):
|
|
listado = []
|
|
for persona in self.invitados:
|
|
listado.append( u"{} {}".format(persona.correo, persona.nombre))
|
|
return "\n".join(listado)
|
|
|
|
@property
|
|
def documentos(self):
|
|
for anexo in self.anexos:
|
|
yield anexo.documento
|
|
|
|
|
|
class AnexosActa(db.Model):
|
|
__tablename__ = 'acta_anexos'
|
|
__table_args__ = { 'schema': 'gestion' }
|
|
__bind_key__ = 'system'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
actaid = db.Column(db.Integer, db.ForeignKey('gestion.actas.id'))
|
|
documentohash = db.Column(UUID(as_uuid=True), db.ForeignKey('doc.archivos.hash'))
|
|
|
|
__table_args__ = (db.UniqueConstraint('actaid', 'documentohash', name='nodupesAnexosActa'), { 'schema': 'gestion' })
|
|
|
|
acta = db.relationship('Acta', back_populates='anexos')
|
|
documento = db.relationship('Documento')
|
|
|
|
|
|
class MiembrosAsistentes(db.Model):
|
|
__tablename__ = 'acta_asistentes'
|
|
__table_args__ = { 'schema': 'gestion' }
|
|
__bind_key__ = 'system'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
personaid = db.Column(db.BigInteger, db.ForeignKey('usuarios.personas.id'))
|
|
actaid = db.Column(db.Integer, db.ForeignKey('gestion.actas.id'))
|
|
|
|
acta = db.relationship('Acta', back_populates='miembros')
|
|
persona = db.relationship('Persona')
|
|
__table_args__ = (db.UniqueConstraint('personaid', 'actaid', name='nodupesMiembrosActas'), { 'schema': 'gestion' })
|
|
|
|
|
|
class InvitadosAsistentes(db.Model):
|
|
__tablename__ = 'acta_invitados'
|
|
__table_args__ = { 'schema': 'gestion' }
|
|
__bind_key__ = 'system'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
correo = db.Column(db.String, nullable=False)
|
|
nombre = db.Column(db.String, nullable=False)
|
|
actaid = db.Column(db.Integer, db.ForeignKey('gestion.actas.id'))
|
|
|
|
acta = db.relationship('Acta', back_populates='invitados')
|
|
__table_args__ = (db.UniqueConstraint('correo', 'actaid', name='nodupesInvitadosActas'), { 'schema': 'gestion' })
|
|
|
|
|
|
class Accion(db.Model):
|
|
__tablename__ = 'actividades'
|
|
__table_args__ = { 'schema': 'gestion' }
|
|
__bind_key__ = 'system'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
objetivoid = db.Column(db.Integer, db.ForeignKey('gestion.objetivos.id'))
|
|
|
|
nombre = db.Column(db.String(200), nullable=False)
|
|
descripcion = db.Column(db.Text)
|
|
|
|
fecha = db.Column(db.Date)
|
|
estado = db.Column(db.SmallInteger, default=100)
|
|
dedicacion = db.Column(db.Integer, default=0)
|
|
|
|
objetivo = db.relationship('Objetivo', back_populates='actividades')
|
|
evidencias = db.relationship('Evidencia', back_populates='actividad')
|
|
|
|
## registros de auditoria
|
|
creado = db.Column(db.DateTime, default=func.now())
|
|
creadopor = db.Column(db.Integer, db.ForeignKey('usuarios.personas.id'), nullable=True)
|
|
modificado = db.Column(db.DateTime, default=func.now(), onupdate=func.now())
|
|
modificadopor = db.Column(db.Integer, db.ForeignKey('usuarios.personas.id'), nullable=True)
|
|
|
|
|
|
@property
|
|
def documentos(self):
|
|
for evidencia in self.evidencias:
|
|
yield evidencia.documento
|
|
|
|
class Evidencia(db.Model):
|
|
__tablename__ = 'evidencias'
|
|
__table_args__ = { 'schema': 'gestion' }
|
|
__bind_key__ = 'system'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
actividadid = db.Column(db.Integer, db.ForeignKey('gestion.actividades.id'))
|
|
documentohash = db.Column(UUID(as_uuid=True), db.ForeignKey('doc.archivos.hash'))
|
|
|
|
__table_args__ = (db.UniqueConstraint('actividadid', 'documentohash', name='nodupesEvidencia'), { 'schema': 'gestion' })
|
|
|
|
actividad = db.relationship('Accion', back_populates='evidencias')
|
|
documento = db.relationship('Documento')
|
|
|
|
class ModuloGestion(db.Model):
|
|
__tablename__ = 'modulo'
|
|
__table_args__ = { 'schema': 'gestion' }
|
|
__bind_key__ = 'system'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
basenodeid = db.Column(db.Integer, db.ForeignKey('gestion.objetivos.id'))
|
|
nombre = db.Column(db.String(100), nullable=False)
|
|
uri = db.Column(db.String(100), nullable=False, unique=True)
|
|
etiqueta = db.Column(db.String(100), nullable=False)
|
|
|
|
nodobase = db.relationship('Objetivo')
|
|
|
|
@property
|
|
def icon(self):
|
|
return self.nodobase.tipo
|
|
|
|
@property
|
|
def quorum(self):
|
|
return AccesosModuloGestion.query.filter(AccesosModuloGestion.moduloid==self.id).count()
|
|
|
|
def mvector(self):
|
|
vector = []
|
|
for acceso in AccesosModuloGestion.query.filter(AccesosModuloGestion.moduloid==self.id).all():
|
|
vector.append(acceso.comisionid)
|
|
|
|
return vector
|
|
|
|
class AccesosModuloGestion(db.Model):
|
|
__tablename__ = 'acceso'
|
|
__table_args__ = { 'schema': 'gestion' }
|
|
__bind_key__ = 'system'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
moduloid = db.Column(db.Integer, db.ForeignKey('gestion.modulo.id'))
|
|
comisionid = db.Column(db.Integer, db.ForeignKey('gestion.comisiones.id'))
|
|
|
|
__table_args__ = (db.UniqueConstraint('moduloid', 'comisionid', name='no_dupes_acceso_gestion'), { 'schema': 'gestion' })
|
|
|
|
modulo = db.relationship('ModuloGestion')
|
|
comision = db.relationship('Comision')
|
|
|
|
|
|
class AccesoGestion():
|
|
def __init__(self):
|
|
if 'accesogestion' not in g:
|
|
self.sysadmin = False
|
|
self.admin = []
|
|
self.usuario = []
|
|
for modulo in self.get_modulos():
|
|
if modulo.nodobase.visible():
|
|
self.usuario.append(modulo)
|
|
|
|
for comision in Comision.query.join(Miembro).filter(Miembro.personaid==current_user.id, Comision.creado==1).all():
|
|
if comision.id > 999:
|
|
self.admin.append(comision.id)
|
|
elif comision.id == 1:
|
|
self.sysadmin = True
|
|
self.admin.append(comision.id)
|
|
|
|
g.accesogestion = {
|
|
'sysadmin': self.sysadmin,
|
|
'admin': self.admin,
|
|
'usuario': self.usuario
|
|
}
|
|
else:
|
|
self.sysadmin = g.accesogestion['sysadmin']
|
|
self.admin = g.accesogestion['admin']
|
|
self.usuario = g.accesogestion['usuario']
|
|
|
|
def get_nodes(self):
|
|
for modulo in self.usuario:
|
|
yield modulo
|
|
|
|
def get_modulos(self):
|
|
for modulo in ModuloGestion.query.order_by(ModuloGestion.id.asc()).all():
|
|
yield modulo
|
|
|
|
def in_gestion(self):
|
|
if len(self.usuario) > 0:
|
|
return True
|
|
else:
|
|
return self.sysadmin
|
|
|
|
def is_sysadmin(self):
|
|
return self.sysadmin
|
|
|
|
def is_admin(self):
|
|
if len(self.admin)>0:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def administrador(self):
|
|
for item in self.admin:
|
|
yield Comision.query.get(item)
|
|
|
|
def comisiones(self, admin):
|
|
if admin > 1:
|
|
yield Comision.query.get(admin)
|
|
for item in Comision.query.filter(Comision.creado.in_(self.admin), Comision.creado==admin).all():
|
|
yield item
|
|
elif self.sysadmin:
|
|
for item in Comision.query.filter(Comision.creado==1).order_by(Comision.id.asc()).all():
|
|
yield item
|
|
|
|
def valid_users(self, admin):
|
|
if admin > 1:
|
|
for item in Miembro.query.join(Comision).filter(Comision.creado==1).distinct(Miembro.personaid).all():
|
|
yield Persona.query.get(item.personaid)
|
|
elif self.sysadmin:
|
|
for item in Persona.query.order_by(Persona.nombres.asc(), Persona.apellidop.asc()).all():
|
|
yield item
|