def evolucion_registros_x_estado(start_date, ends_date): estados = Estado.objects.values_list('codigo', flat=True) qs = RegistroAsistencia.objects.filter( asistencia__fecha__gte=start_date, asistencia__fecha__lte=ends_date).values_list( 'asistencia__fecha', 'estado__codigo').annotate(cant=Count('estado_id')) processed = defaultdict(dict) esto = [] for it in qs: processed[it[0]][it[1]]=it[2] if it[1] not in esto: esto.append(it[1]) report = [] for est in esto: series = {} series["key"] = est series["values"] = list() for day in daterange(start_date, ends_date): val = processed.get(day, {}).get(est, 0) series["values"].append({'x': day.isoformat(), 'y': val}) report.append(series) return report
def get_datos_porcentuales(start, end): estados = Estado.objects.values_list('codigo', flat=True) qs = RegistroAsistencia.objects.filter( asistencia__fecha__gte=start, asistencia__fecha__lte=end ).values_list('asistencia__fecha', 'estado__codigo').annotate(cant=Count('pk')).order_by('asistencia__fecha') totales = dict(RegistroAsistencia.objects.filter( asistencia__fecha__gte=start, asistencia__fecha__lte=end ).values_list('asistencia__fecha').annotate(cant=Count('pk')).order_by('asistencia__fecha')) totales_rango = dict(RegistroAsistencia.objects.filter( asistencia__fecha__gte=start, asistencia__fecha__lte=end ).values_list('estado__codigo').annotate(cant=Count('pk'))) total_rango = sum([v for k,v in totales_rango.items()]) processed = defaultdict(dict) for it in qs: processed[it[0]][it[1]]=it[2] report = list() header = ["Fecha", ] header.extend(estados) report.append(header) totales_row = ["Totales", False,] for day in daterange(start, end): aux = list() aux.append(day) aux.append(day.isoweekday() in [6,7]) data = processed.get(day, {}) total = totales.get(day, 0) for est in estados: if total == 0: aux.append(0) else: aux.append(processed.get(day, {}).get(est, 0) * 100 / total) report.append(aux) for est in estados: if total_rango == 0: totales_row.append(0) else: totales_row.append(totales_rango.get(est, 0) / total_rango) report.append(totales_row) for k,v in totales_rango.items(): totales_rango[k] = v / total_rango * 100 if total_rango != 0 else 0 return report, totales_rango
def evolucion_registros_asistencia(start_date, ends_date): """ Devuelve los datos para el gráfico de codigo de barras con los presentes y ausentes """ qs = RegistroAsistencia.objects.select_related('estado', 'persona').filter( asistencia__fecha__gte=start_date, asistencia__fecha__lte=ends_date).values_list( 'asistencia__fecha', 'estado__no_ocioso').annotate(cant=Count('estado_id')) processed = defaultdict(dict) for it in qs: processed[it[0]][it[1]]=it[2] report = list() data_table = list() for day in daterange(start_date, ends_date): aux = list() aux.append(day) aux.append(processed.get(day, {}).get(True, 0)) aux.append(processed.get(day, {}).get(False, 0)) data_table.append(aux) for est in ["Presentes", "Ausentes"]: series = dict() series["key"] = est series["values"] = list() for day in daterange(start_date, ends_date): if est == "Presentes": val = processed.get(day, {}).get(True, 0) else: val = processed.get(day, {}).get(False, 0) # desconozco porque debe sumar un día para que sea correcto el gráfico series["values"].append({'x': (day+ timedelta(days=1)).isoformat(), 'y': val}) report.append(series) return report, data_table
def fill_resumen_dias_trabajados(self, context): """ Muestra un reporte de con el detalle de asistencia cada dia (dentro del rango de fechas) por persona para un proyecto seleccionado. """ worksheet_s_name = "Resumen RRHH" worksheet_s = self.workbook.add_worksheet(worksheet_s_name) fechas = context["filter"].form.cleaned_data["fecha"] start_date = fechas.start end_date = fechas.stop rango_de_dias = [x for x in daterange(start_date, end_date)] # cabecera con logo y título "Resumen de días trabajados" - RRHH - # subcabecera: fecha de emisión y proyecto seleccionado # referencia de estados y códigos # encabezado de tabla """ Resumen personal | Días | * cada estado con su acumulado personas | Cada dia | Acumulado por persona por estado ... * Total cada estado | Acumulado diario | Totales """ # formats header = self.workbook.add_format({ 'color': 'black', 'align': 'center', 'valign': 'vcenter', 'border': 1, 'bold': True, 'font_size': 12, }) header_date = self.workbook.add_format({ 'color': 'black', 'align': 'center', 'valign': 'vcenter', 'border': 1, 'bold': True, 'font_size': 12, 'num_format': 'dd/mm/yy' }) normal = self.workbook.add_format({ 'color': 'black', 'align': 'center', 'valign': 'vcenter', 'border': 1, 'font_size': 9, }) normal_left = self.workbook.add_format({ 'color': 'black', 'align': 'left', 'valign': 'vcenter', 'border': 1, 'font_size': 9, }) normal_color = self.workbook.add_format({ 'bg_color': '#b6eda8', 'color': 'black', 'align': 'center', 'valign': 'vcenter', 'border': 1, 'font_size': 9, }) xs_total_color = self.workbook.add_format({ 'bg_color': '#c6a5a5', 'color': 'black', 'align': 'center', 'valign': 'vcenter', 'border': 1, 'font_size': 9, }) xs_total_color_left = self.workbook.add_format({ 'bg_color': '#c6a5a5', 'color': 'black', 'align': 'left', 'valign': 'vcenter', 'border': 1, 'font_size': 9, }) cant_dias = len(rango_de_dias) # título worksheet_s.merge_range(0, 0, 0, 3, "") worksheet_s.insert_image(0, 0, os.path.join(settings.STATIC_ROOT, "frontend/img/footer-zille.png"), {'x_offset': 15, 'y_offset': 5}) worksheet_s.merge_range(0, 4, 0, cant_dias + 3, "RESUMEN DE DÍAS TRABAJADOS\n-RRHH-", self.style_dict["title"]) # subtítulo worksheet_s.merge_range(1, 0, 1, 1, "Fecha de Emisión:", header) worksheet_s.merge_range(1, 2, 1, 3, datetime.now(), header_date) worksheet_s.merge_range(1, 4, 1, 14, "Operación (Proyecto / Servicio):", header) proyecto_name = str(context["filter"].form.cleaned_data["proyecto"]) if context["filter"].form.cleaned_data["proyecto"] else "Todos" worksheet_s.merge_range(1, 15, 1, 3 + cant_dias, proyecto_name, header) referencias = dict(Estado.objects.values_list("codigo", "situacion")) # mejorar presentación de referencias.. # worksheet_s.write(2, 0, " ".join(["REFERENCIAS: ", ] + referencias)) # encabezados tabla worksheet_s.merge_range(3 , 0, 3, 3, "RESUMEN PERSONAL DE ZILLE SRL", normal_color) worksheet_s.merge_range(3, 4, 3, cant_dias + 3, "MES", normal_color) # encabezados worksheet_s.write_row(4, 0, ["ITEM", "APELLIDO Y NOMBRE", "CUIL", "CATEGORÍA"], normal_color) worksheet_s.write_row(4, 4, [x.strftime("%d/%m") for x in rango_de_dias], normal_color) # encabecados estados i = 4 for k, v in referencias.items(): worksheet_s.merge_range(3, cant_dias + i, 4, cant_dias + i, "{}\n{}".format(k, v), xs_total_color) i += 1 # buscamos las personas, las ordenamos por apellido personas = context["filter"].qs.values_list( 'persona_id', 'persona__apellido', 'persona__nombre', 'persona__cuil', 'persona__cct__nombre').order_by( "persona__apellido", "persona__nombre").distinct() row_init_data = item = 5 # primer fila con datos totales_diarios = {} # dict con una lista de asistencias por día. Key: dia, value, list de estados totales_por_estados = {} for persona in personas: # datos de empleado worksheet_s.write(item, 0, item-4, normal) # item worksheet_s.write(item, 1, "{}, {}".format(persona[1], persona[2]), normal_left) # nombre worksheet_s.write(item, 2, persona[3], normal) # cuit worksheet_s.write(item, 3, persona[4], normal) # categoria col = 4 # columna de datos de asistencia avance = 0 # avance de la columna asistencia = dict(context["filter"].qs.filter( persona_id=persona[0]).values_list( "asistencia__fecha", 'estado__codigo').order_by("asistencia__fecha")) totales = Counter(asistencia.values()) # guardos los totales de esta persona, para calcular los totales por estado for k, total in totales.items(): try: totales_por_estados[k].append(total) except KeyError: totales_por_estados[k] = [total, ] # recorremos los días for dia in rango_de_dias: # armo dict para contabilizar asistencias por día if dia not in totales_diarios: totales_diarios[dia] = [] totales_diarios[dia].append(asistencia.get(dia, "")) worksheet_s.write(item, col + avance, asistencia.get(dia, ""), normal) avance += 1 # poner campos para estados y sus sumatorias for estado in referencias.keys(): worksheet_s.write_formula(item, col + avance, '=COUNTIF({0}{1}:{2}{1},"{3}")'.format( self.get_c(col + 1), item + 1, self.get_c(col + avance), estado), cell_format=xs_total_color, value=totales.get(estado, 0)) avance += 1 item += 1 row_fin_data = item - 1 # lista de estados y totales diarios for estado in referencias.keys(): col = 4 # columna de datos de asistencia avance = 0 # avance de la columna worksheet_s.merge_range(item, 0, item, 3, "TOTAL {}".format(referencias.get(estado)), xs_total_color_left) # recorremos los días for dia in rango_de_dias: totales_dia = Counter(totales_diarios.get(dia, [])) worksheet_s.write_formula(item, col + avance, '=COUNTIF({0}{1}:{0}{2},"{3}")'.format( self.get_c(col + avance + 1), row_init_data + 1, row_fin_data + 1, estado), cell_format=xs_total_color, value=totales_dia.get(estado, 0)) avance += 1 if item == row_fin_data + 1: # si es el primero de los totales, agrego los totales por estado for estado2 in referencias.keys(): total = sum(totales_por_estados.get(estado2, [])) # primero hago el merge de la celda worksheet_s.merge_range(item, col + avance, item + 3, col + avance, "") # luego aplico la formula worksheet_s.write_formula( item, col + avance, '=SUM({0}{1}:{0}{2})'.format(self.get_c(col + avance + 1), row_init_data + 1, row_fin_data + 1), cell_format=normal_color, value=total) avance += 1 item += 1 # setear altos y anchos worksheet_s.set_row(0, 45) worksheet_s.set_row(1, 30) worksheet_s.set_column(0, 0, 5) worksheet_s.set_column(1, 1, 35) worksheet_s.set_column(2, 2, 15) worksheet_s.set_column(3, 3, 20) worksheet_s.set_column(4, 4 + cant_dias, 5) worksheet_s.freeze_panes(5, 2) return self.prepare_response()