Esempio n. 1
0
def test_creacion_dias_no_laborales():
    # Creación de un conjunto de días laborables sin días
    cd = DiasNoLaborables(usuario='@JJ', insertar=True)

    assert cd.usuario == '@JJ'
    assert cd.dias_antelacion == None
    assert cd.conjunto == []

    # Comprobar que los datos se han insertado en la base de datos
    data = cd.storage.get_usuario('@JJ')
    assert data['diasantelacion'] == None
    assert data['conjunto'] == []

    # No se puede insertar ese día no laborable ya que ahí existe un acontecimiento
    with patch.object(DiasNoLaborables, '_obtener_dias_con_acontecimiento', return_value=[datetime(2020, 2, 3)]):
        cd = DiasNoLaborables(usuario='@albertosml', dias_antelacion=2, conjunto=[datetime(2020, 1, 2), 
                                            datetime(2020, 2, 3)], insertar=True)
        assert cd.conjunto == [datetime(2020, 1, 2)]

    # Al especificar un día en el sexto día de la semana (sábado) el día de la semana no se guarda
    cd = DiasNoLaborables(usuario='@a', dias_antelacion=2, conjunto=[6, datetime(2019, 11, 9)], insertar=True)
    
    assert cd.conjunto == [6]

    # Creación de un conjunto de días laborables con días
    cd = DiasNoLaborables(usuario='@pepe', dias_antelacion=2, conjunto=[6, datetime(2020, 1, 2)], insertar=True)
    
    assert cd.conjunto == [6, datetime(2020, 1, 2)]
Esempio n. 2
0
def test_cancelar_recordatorio():
    cd = DiasNoLaborables(usuario='@albertosml', dias_antelacion=2, insertar=True)

    assert cd.dias_antelacion == 2

    cd.cancelar_recordatorio()

    assert cd.dias_antelacion == None
Esempio n. 3
0
def test_cancelar_recordatorio(app_client):
    DiasNoLaborables(usuario='albertosml',
                     conjunto=[6, datetime(2020, 1, 2)],
                     dias_antelacion=5,
                     insertar=True)

    # Cancelo el recordatorio
    response = app_client.post('/diasnolaborables/cancelar_recordatorio',
                               data=json.dumps({'usuario': 'albertosml'}),
                               content_type='application/json')
    assert response.status_code == 200
    assert json.loads(response.get_data()) == {'msg': 'Recordatorio cancelado'}

    # Chequear recordatorio
    cd = DiasNoLaborables(usuario='albertosml')
    assert cd.dias_antelacion == None
Esempio n. 4
0
def cancelar_recordatorio():
    data = request.get_json()
    usuario = data['usuario']

    try:
        # Obtener el conjunto para ese usuario
        cd = DiasNoLaborables(usuario=usuario)
    except DiasNoLaborablesException:
        return jsonify({
            'msg':
            'No existe un conjunto de días no laborables para ese usuario'
        }), 200

    # Cancelar recordatorio de un día no laboral de un usuario
    cd.cancelar_recordatorio()

    return jsonify({'msg': 'Recordatorio cancelado'}), 200
Esempio n. 5
0
def modificar_recordatorio():
    data = request.get_json()
    usuario = data['usuario']
    dias_antelacion = data['diasantelacion']

    try:
        # Obtener el conjunto para ese usuario
        cd = DiasNoLaborables(usuario=usuario)
    except DiasNoLaborablesException:
        return jsonify({
            'msg':
            'No existe un conjunto de días no laborables para ese usuario'
        }), 200

    # Modificar días de antelación de recuerdo
    cd.modificar_dias_antelacion_recordatorio(dias_antelacion)

    return jsonify({'msg': 'Recordatorio modificado'}), 200
Esempio n. 6
0
    def __init__(self):
        super(Table, self).__init__()
        self.setupUi(self)

        self.table_logs.setColumnCount(10)
        self.table_rango.setColumnCount(10)
        self.__row = 0
        self.diasnolaborables = DiasNoLaborables()
        self.tablesContent = {'logs': [], 'rango': []}
Esempio n. 7
0
def eliminar_dia_no_laboral():
    data = request.get_json()
    usuario = data['usuario']
    dia_a_eliminar = data['diaaeliminar']

    try:
        # Obtener el conjunto para ese usuario
        cd = DiasNoLaborables(usuario=usuario)
    except DiasNoLaborablesException:
        return jsonify({
            'msg':
            'No existe un conjunto de días no laborables para ese usuario'
        }), 200

    # Transformar fecha (si se ha introducido)
    if isinstance(dia_a_eliminar, str):
        dia_a_eliminar = datetime.strptime(dia_a_eliminar, '%d/%m/%Y')

    # Se elimina el día no laboral del conjunto
    cd.eliminar_dia_no_laboral(dia_a_eliminar)

    return jsonify({'msg': 'Se ha eliminado el día del conjunto'}), 200
Esempio n. 8
0
def obtener_dias():
    data = request.get_json()
    usuario = data['usuario']
    fecha_inicio = data['fechainicio']
    fecha_fin = data['fechafin']

    try:
        # Obtener el conjunto para ese usuario
        cd = DiasNoLaborables(usuario=usuario)
    except DiasNoLaborablesException:
        return jsonify({
            'msg':
            'No existe un conjunto de días no laborables para ese usuario'
        }), 200

    # Transformar fechas
    fecha_inicio = datetime.strptime(fecha_inicio, '%d/%m/%Y')
    fecha_fin = datetime.strptime(fecha_fin, '%d/%m/%Y')

    # Devolver conjunto días no laborables
    dias_no_laborables = cd.devolver_dias_no_laborables_anio(
        fecha_inicio, fecha_fin)

    return jsonify({'diasnolaborables': dias_no_laborables}), 200
Esempio n. 9
0
def aniadir_dias_no_laborables():
    data = request.get_json()
    usuario = data['usuario']
    dias_a_aniadir = data['diasaaniadir']

    try:
        # Obtener el conjunto para ese usuario
        cd = DiasNoLaborables(usuario=usuario)
    except DiasNoLaborablesException:
        return jsonify({
            'msg':
            'No existe un conjunto de días no laborables para ese usuario'
        }), 200

    # Procesar conjunto de días no laborables
    dias_a_aniadir = transformar_conjunto(dias_a_aniadir)

    # Añadir los días no laborables al conjunto
    cd.aniadir_dias_no_laborables(dias_a_aniadir)

    return jsonify({
        'msg':
        'Se han añadido los días no laborables correspondientes al conjunto'
    }), 200
Esempio n. 10
0
    def __init__(self):
        database = SQL()
        database.loadChekInOutTable()

        self.matriz = database.data_matrix
        self.personal = sorted(jornada_personal.keys())
        dates = database.dates
        self.dates = [d for d in dates if d > datetime.date(2014, 1, 1)]
        self.start_date = self.dates[0]
        self.stop_date = self.dates[-1]
        self.exceptions = None
        self.workers_not_found = None
        self.days_of_work = {}  # contendrá los días de trabajo del archivo empaquetados en la clase Workday
        self.validateCheck()
        self.content = ()
        self.thisday = DiasNoLaborables()
        self.organizar_por_fecha()
Esempio n. 11
0
def test_eliminar_dia(app_client):
    crear_conjunto_dias_no_laborables()

    # Elimino el jueves del conjunto
    response = app_client.post('/diasnolaborables/eliminar_dia',
                               data=json.dumps({
                                   'usuario': 'albertosml',
                                   'diaaeliminar': 6
                               }),
                               content_type='application/json')
    assert response.status_code == 200
    assert json.loads(response.get_data()) == {
        'msg': 'Se ha eliminado el día del conjunto'
    }

    # Comprobar conjunto
    cd = DiasNoLaborables(usuario='albertosml')
    assert cd.conjunto == [datetime(2020, 1, 2)]
Esempio n. 12
0
def test_modificar_recordatorio(app_client):
    crear_conjunto_dias_no_laborables()

    # Modifico los días de antelación de recordatorio
    response = app_client.post('/diasnolaborables/modificar_recordatorio',
                               data=json.dumps({
                                   'usuario': 'albertosml',
                                   'diasantelacion': 5
                               }),
                               content_type='application/json')
    assert response.status_code == 200
    assert json.loads(response.get_data()) == {
        'msg': 'Recordatorio modificado'
    }

    # Chequear recordatorio
    cd = DiasNoLaborables(usuario='albertosml')
    assert cd.dias_antelacion == 5
Esempio n. 13
0
def test_aniadir_dias(app_client):
    crear_conjunto_dias_no_laborables()

    # Añado el jueves al conjunto
    response = app_client.post('/diasnolaborables/aniadir_dias',
                               data=json.dumps({
                                   'usuario': 'albertosml',
                                   'diasaaniadir': [4]
                               }),
                               content_type='application/json')
    assert response.status_code == 200
    assert json.loads(response.get_data()) == {
        'msg':
        'Se han añadido los días no laborables correspondientes al conjunto'
    }

    # Comprobar conjunto
    cd = DiasNoLaborables(usuario='albertosml')
    assert cd.conjunto == [4, 6]
Esempio n. 14
0
def nuevo_conjunto_dias_no_laborables():
    data = request.get_json()
    usuario = data['usuario']
    dias_antelacion = data.get('diasantelacion', None)
    conjunto = data.get('conjunto', [])

    # Procesar conjunto de días no laborables
    conjunto = transformar_conjunto(conjunto)

    try:
        # Crear el conjunto de días no laborables para ese usuario
        DiasNoLaborables(usuario=usuario,
                         dias_antelacion=dias_antelacion,
                         conjunto=conjunto,
                         insertar=True)
    except DiasNoLaborablesException:
        return jsonify({'msg': 'Problemas al crear el conjunto'}), 200

    return jsonify({
        'msg':
        'El conjunto de días laborables para ese usuario se ha creado'
    }), 200
Esempio n. 15
0
class Reorganizar:
    def __init__(self):
        database = SQL()
        database.loadChekInOutTable()

        self.matriz = database.data_matrix
        self.personal = sorted(jornada_personal.keys())
        dates = database.dates
        self.dates = [d for d in dates if d > datetime.date(2014, 1, 1)]
        self.start_date = self.dates[0]
        self.stop_date = self.dates[-1]
        self.exceptions = None
        self.workers_not_found = None
        self.days_of_work = {}  # contendrá los días de trabajo del archivo empaquetados en la clase Workday
        self.validateCheck()
        self.content = ()
        self.thisday = DiasNoLaborables()
        self.organizar_por_fecha()


    def validateCheck(self):
        matrix = []
        exceptions = []
        workers_not_found = []
        for row in self.matriz:
            # determiar si el check in es valido
            worker = row[0]
            check = row[1]
            in_or_out = row[2]

            # Los checks mal hechos o fuera de los parametros aceptados
            # pasan a una lista para ser verificados
            try:
                jornada = jornada_personal[worker]
            except KeyError:
                if worker not in workers_not_found:
                    workers_not_found.append(worker)
                continue
            if jornada == "diurno":
                if not HorarioDiurno.validateCheck(check, in_or_out):
                    exceptions.append(row)
                    continue
            if jornada == "nocturno":
                if not HorarioNocturno.validateCheck(check, in_or_out):
                    exceptions.append(row)
                    continue
            matrix.append(row)

        self.exceptions = exceptions
        self.workers_not_found = workers_not_found
        self.matriz = matrix

    def __str__(self):
        texto = ''
        for line in self.matriz:
            line = line[:8]
            line = '\t'.join(line)
            texto += line + '\n'
        return texto

    def organizar_por_fecha(self):
        """
        return: dict
        """
        # ordena las self.fechas por lista para luego generar el documento por fecha

        self.__matriz = self.matriz.copy()
        self.content = ()
        # Rango de fechas
        start_date = min(self.dates)
        stop_date = max(self.dates)
        ciclos.DaybyDay(start_date, stop_date, daysCycle=self.loadContent)

    def loadContent(self, date):
        """
        Función sobre la cual se iterará para llenar los work_days.
                Por cada día en el intervalo se generará un Workday que será almacenado en work_days
        :param date: recibe la fecha de iteración
        :return: work_days (lista)
        """
        # organiza la matriz que generara el documento de salida por fecha
        workday = Workday(date, self.personal)
        temp = []  # matriz temporal
        for line in self.__matriz:
            if date == line[1].date():
                # line [worker, checktime, in/out]
                temp.append(line)  # agrega la matriz correspondiente a la fecha

        for worker in self.personal:
            # transformar a [worker, time_segment, entry_time, exit_time]
            worker_schedule = jornada_personal[worker]

            if worker_schedule == "diurno":
                w = {"worker": worker, "matutino": {"entrada": None, "salida": None},
                     "vespertino": {"entrada": None, "salida": None}}
                for line in temp:
                    if worker in line:
                        # checktime, in/out -> time_segment, entry_time, exit_time
                        checktime = line[1]
                        in_out = line[2]
                        if HorarioDiurno.is_matutino(checktime, in_out):
                            if in_out == "I":
                                w["matutino"]["entrada"] = checktime
                            elif in_out == "O":
                                w["matutino"]["salida"] = checktime
                        elif HorarioDiurno.is_vespertino(checktime, in_out):
                            if in_out == "I":
                                w["vespertino"]["entrada"] = checktime
                            elif in_out == "O":
                                w["vespertino"]["salida"] = checktime

                workday.load_horary(
                        w["worker"], "matutino", w["matutino"]["entrada"], w["matutino"]["salida"])
                workday.load_horary(
                        w["worker"], "vespertino", w["vespertino"]["entrada"], w["vespertino"]["salida"])

            elif worker_schedule == "nocturno":
                w = {"worker": worker, "nocturno": {"entrada": None, "salida": None}}
                for line in temp:
                    if worker in line:
                        # checktime, in/out -> time_segment, entry_time, exit_time
                        checktime = line[1]
                        in_out = line[2]
                        if in_out == "I":
                            w["nocturno"]["entrada"] = checktime
                        elif in_out == "O":
                            w["nocturno"]["salida"] = checktime
                workday.load_horary(
                        w["worker"], "nocturno", w["nocturno"]["entrada"], w["nocturno"]["salida"])

            else:
                print("Este tipo de horario no existe aun")
                raise TypeError
            # end for worker in self.personal
        # end for date in self.dates
        # TODO mecanismo para detectar las fechas especiales y modificar las horas laborables
        if not self.thisday.isWorkable(date):
            workday.isworkable = False
            workday.changeWorkableHours(diurno=0, nocturno=0)

        self.content += (workday,)

    def calculateWorkedTime(self):
        """
        Agrega los workday del contenido los calculos del tiempo trabajado, tiempo ausente y tiempo extra
        """

        content = list(self.content)
        content_length = len(self.content)
        assert content_length > 0, "No hay contenido que analizar."
        for i in range(content_length):
            workday = self.content[i]
            date = workday.date

            try:
                next_workday = self.content[i + 1]
            except IndexError:
                next_workday = None

            # cargar el resumen del mes
            for w in self.personal:
                w_info = workday.workers[w]
                h = w_info['horario'].content

                zero_time = datetime.timedelta(hours=0)
                worked_time = zero_time

                for k, v in h.items():
                    if k == 'matutino' or k == 'vespertino':
                        v_in = v['entrada']
                        v_out = v['salida']
                    elif k == 'nocturno':
                        # worked_time += datetime.timedelta(hours=24) + (v_out - v_in)
                        v_in = v['entrada']
                        if next_workday is None:
                            v_out = None
                        else:
                            v_out = next_workday.workers[w]['horario'].content['nocturno']['salida']

                    if v_out != None and v_in != None:
                        worked_time += v_out - v_in

                #Dependiendo de la jornada del trabajador, las horas laborables del dia pueden variar
                work_time_reference = workday.workableHours[jornada_personal[w]]

                # si no hay tiempo extra, el resultado será zero. Es decir, no habrán resultados negativos
                if worked_time > work_time_reference:
                    extra_time = worked_time - work_time_reference
                else:
                    extra_time = datetime.timedelta(hours=0)
                # si no hay tiempo ausente, el resultado será zero. Igual que para el tiempo extra
                if worked_time < work_time_reference:
                    absent_time = work_time_reference - worked_time
                else:
                    absent_time = datetime.timedelta(hours=0)

                workday.addPerformance(w, worked_time, extra_time, absent_time)
            content[i] = workday

    def row(self, n):
        row = self.matriz[n]
        # print(row)
        return row

    def column(self, n):
        column = []
        for line in self.matriz:
            try:
                column.append(line[n])
            except IndexError:
                raise Exception(IndexError, str(line[n]))
        return column

    def filter(self, from_date, to_date, personal=None):
        # TODO filtrar personal
        if personal is None: personal = self.personal
        self.start_date = from_date
        self.stop_date = to_date
        filtered_content = ()
        for wd in self.content:
            d = wd.date
            if from_date > d: continue
            if to_date < d: continue
            filtered_content += (wd.filterWorkers(personal),)
        self.content = filtered_content
Esempio n. 16
0
def crear_conjunto_dias_no_laborables():
    cd = DiasNoLaborables(usuario='@albertosml', conjunto=[6, datetime(2020, 1, 2)], insertar=True)
    return cd
Esempio n. 17
0
class Table(QWidget, Ui_Form):
    def __init__(self):
        super(Table, self).__init__()
        self.setupUi(self)

        self.table_logs.setColumnCount(10)
        self.table_rango.setColumnCount(10)
        self.__row = 0
        self.diasnolaborables = DiasNoLaborables()
        self.tablesContent = {'logs': [], 'rango': []}

    def append(self, item, column=0, color=None):

        if type(item) == list:
            for i in item:
                newItem = QTableWidgetItem(i)
                if color is not None: newItem.setBackground(QColor(color))
                self.activeTable.setItem(self.__row, column, newItem)
                column += 1
            index_increment = 1
        else:
            newItem = QTableWidgetItem(item)
            if color is not None:
                newItem.setBackground(color)
            index_increment = 1
            self.activeTable.setItem(self.__row, column, newItem)
            item = [item]
            column += 1
        self.__row += index_increment

        if self.activeTable is self.table_logs: tableName = 'logs'
        elif self.activeTable is self.table_rango: tableName = 'rango'
        else: tableName = 'otra'
        save = item + ['' for i in range(10 - column)]
        self.tablesContent[tableName] += [save, ]

    def paintHorary(self, row, horary):
        column = 1
        for h in (horary['matutino']['entrada'], horary['matutino']['salida'],
                         horary['vespertino']['entrada'], horary['vespertino']['salida'],
                         horary['nocturno']['entrada'], horary['nocturno']['salida'],):
            if not h == '--':
                self.activeTable.item(row, column).setBackground(QColor(150, 255, 150))
            else:
                self.activeTable.item(row, column).setBackground(QColor(255, 100, 100))
            column += 1

    def paintNotWorkable(self):
        pass

    def loadTables(self, reporte):
        self.reporte = reporte
        self.totals = AnvizReader.TotalizeByRange(reporte)
        self.reset()

        #Cargar tabla de dias
        self.activeTable = self.table_logs
        self.__workdays = list(self.reporte.content)
        day_table_length = len(self.__workdays) * (2 + len(header) + len(self.reporte.personal))
        self.table_logs.setRowCount(day_table_length)
        while self.__workdays: self.workDays()
        self.table_logs.setRowCount(self.__row + 1)

        #Cargar tabla de rango
        self.activeTable = self.table_rango
        self.__row = 0
        self.__workrange = list(self.totals.byRange)
        month_table_length = len(self.__workrange) * (5 + len(self.reporte.personal))
        self.table_rango.setRowCount(month_table_length)
        while self.__workrange: self.workRange()
        self.table_rango.setRowCount(self.__row + 1)

    def workDays(self):

        date = self.__workdays[0].date
        year, month, day = date.year, date.month, date.day
        fecha_invertida = "Fecha: {dia} {d} de {m} del {year}".format(dia=MyDates.dayName(year, month, day),
                                                                      d=day,
                                                                      m=MyDates.monthName(month),
                                                                      year=year)
        #TODO mostrar los dias no laborables como una fecha coloreada en azul claro
        if not self.diasnolaborables.isWorkable(date):
            self.activeTable.setSpan(self.__row, 0, 1, 10)
            self.append(fecha_invertida, color=QColor(200,200,255))

            if self.diasnolaborables.significado(date) is not None:
                self.activeTable.setSpan(self.__row, 0, 1, 10)
                self.append(self.diasnolaborables.significado(date), color=QColor(200,200,255))
            self.append('')
            del self.__workdays[0]
            return
        #implementando una lista FIFO
        try:
            workday = self.__workdays[0]
        except IndexError:
            print('--- END ---')
            return
        else:
            # self..append(header)
            # Cargar en excel el desempeño de los trabajadores en el día
            workday_info = workday.get_workers_info()
            self.activeTable.setSpan(self.__row, 0, 1, 10)
            self.append(fecha_invertida)
            for horario in horarios:
                for i in heads[horario]:
                    self.append(i)
                for worker in self.reporte.personal:
                    if personalShift[worker] != horario: continue
                    schedule = workday_info[worker]
                    # print(worker, schedule)
                    h = schedule['horario']
                    if horario == 'diurno':
                        line_to_QTable = [schedule['nombre'],
                                          h['matutino']['entrada'], h['matutino']['salida'],
                                          h['vespertino']['entrada'], h['vespertino']['salida'],
                                          schedule['tiempo trabajado'],
                                          schedule['tiempo extra'],
                                          schedule['tiempo ausente']]
                    else:
                        line_to_QTable = [schedule['nombre'],
                                          h['nocturno']['entrada'], h['nocturno']['salida'],
                                          schedule['tiempo trabajado'],
                                          schedule['tiempo extra'],
                                          schedule['tiempo ausente']]

                    self.append(line_to_QTable)
                    #self.paintHorary(self.__row - 1, h)
                self.append('')
                # salto de linea
            self.append('')
            del self.__workdays[0]

    def workRange(self):
        if not self.__workrange: return

        self.activeTable = self.table_rango
        _wm = self.__workrange
        year, month, day = _wm.from_date.year, _wm.from_date.month, _wm.from_date.day
        fecha_invertida1 = "Desde el {dia} {d} de {m} del {year}".format(dia=MyDates.dayName(year, month, day),
                                                                         d=day,
                                                                         m=MyDates.monthName(month),
                                                                         year=year)
        year, month, day = _wm.to_date.year, _wm.to_date.month, _wm.to_date.day
        fecha_invertida2 = "Hasta el {dia} {d} de {m} del {year}".format(dia=MyDates.dayName(year, month, day),
                                                                         d=day,
                                                                         m=MyDates.monthName(month),
                                                                         year=year)

        self.activeTable.setSpan(self.__row, 0, 1, 4)
        self.append(fecha_invertida1)
        self.activeTable.setSpan(self.__row, 0, 1, 4)
        self.append(fecha_invertida2)
        self.activeTable.setSpan(self.__row, 0, 1, 4)
        self.append("Horas diurnas laborables: {}".format(_wm.workableHours['diurno']))
        self.activeTable.setSpan(self.__row, 0, 1, 4)
        self.append("Horas nocturnas laborables: {}".format(_wm.workableHours['nocturno']))
        self.append(header2)
        for worker in self.reporte.personal:
            schedule = _wm.getWorkerInfo(worker)
            # print(worker, schedule)
            line_to_QTable = [worker,
                              str(schedule['tiempo trabajado']),
                              str(schedule['tiempo extra']),
                              str(schedule['tiempo ausente'])]
            self.append(line_to_QTable)
        # salto de linea
        self.append('')

    def loadRange(self, reporte):
        self.reporte = reporte
        self.totals = AnvizReader.TotalizeByRange(reporte)
        self.reset()

        # Cargar tabla de dias
        self.activeTable = self.table_logs
        self.__workdays = list(self.reporte.content)
        day_table_length = len(self.__workdays) * (2 + len(header) + len(self.reporte.personal))
        self.table_logs.setRowCount(day_table_length)
        while self.__workdays: self.workDays()

        # Cargar tabla de meses
        self.__row = 0
        self.__workrange = self.totals.byRange
        month_table_length = 5 + len(self.reporte.personal)
        self.table_rango.setRowCount(month_table_length)
        self.workRange()

    def reset(self):
        self.__row = 0
        self.table_rango.clearContents()
        self.table_logs.clearContents()