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
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()