def timesheet_report_data(mission, start=None, end=None, padding=False): """Prepare data for timesheet report from start to end. Padding align total in the same column""" timesheets = Timesheet.objects.select_related().filter(mission=mission) months = timesheets.dates("working_date", "month") data = [] for month in months: if start and month < start: continue if end and month > end: break days = daysOfMonth(month) next_month = nextMonth(month) padding_length = 31 - len( days ) # Padding for month with less than 31 days to align total column # Header data.append([""]) data.append([formats.date_format(month, format="YEAR_MONTH_FORMAT")]) # Days data.append([ "", ] + [d.day for d in days]) dayHeader = [_("Consultants")] + [_(d.strftime("%a")) for d in days] if padding: dayHeader.extend([""] * padding_length) dayHeader.append(_("total")) data.append(dayHeader) for consultant in mission.consultants(): total = 0 row = [ consultant, ] consultant_timesheets = {} for timesheet in timesheets.filter(consultant_id=consultant.id, working_date__gte=month, working_date__lt=next_month): consultant_timesheets[ timesheet.working_date] = timesheet.charge for day in days: try: charge = consultant_timesheets.get(day) if charge: row.append( formats.number_format(to_int_or_round(charge, 2))) total += charge else: row.append("") except Timesheet.DoesNotExist: row.append("") if padding: row.extend([""] * padding_length) row.append(formats.number_format(to_int_or_round(total, 2))) if total > 0: data.append(row) return data
def gatherTimesheetData(consultant, missions, month): """Gather existing timesheet timesheetData @returns: (timesheetData, timesheetTotal, warning) timesheetData represent timesheet form post timesheetData as a dict timesheetTotal is a dict of total charge (key is mission id) warning is a list of 0 (ok) or 1 (surbooking) or 2 (no data). One entry per day""" timesheetData = {} timesheetTotal = {} warning = [] totalPerDay = [0] * month_days(month) next_month = nextMonth(month) for mission in missions: timesheets = Timesheet.objects.select_related().filter( consultant=consultant).filter(mission=mission) timesheets = timesheets.filter(working_date__gte=month).filter( working_date__lt=next_month) for timesheet in timesheets: timesheetData["charge_%s_%s" % (timesheet.mission.id, timesheet.working_date.day)] = timesheet.charge if mission.id in timesheetTotal: timesheetTotal[mission.id] += timesheet.charge else: timesheetTotal[mission.id] = timesheet.charge totalPerDay[timesheet.working_date.day - 1] += timesheet.charge # Gather lunck ticket data totalTicket = 0 lunchTickets = LunchTicket.objects.filter(consultant=consultant) lunchTickets = lunchTickets.filter(lunch_date__gte=month).filter( lunch_date__lt=next_month) for lunchTicket in lunchTickets: timesheetData["lunch_ticket_%s" % lunchTicket.lunch_date.day] = lunchTicket.no_ticket totalTicket += 1 timesheetTotal["ticket"] = totalTicket # Compute warnings (overbooking and no data) for i in totalPerDay: i = round( i, 4 ) # We must round because using keyboard time input may lead to real numbers that are truncated if i > 1: # Surbooking warning.append(1) elif i == 1: # Ok warning.append(0) else: # warning (no data, or half day) warning.append(2) # Don't emit warning for no data during week ends and holidays holiday_days = holidayDays(month) for day in daysOfMonth(month): if day.isoweekday() in (6, 7) or day in holiday_days: warning[day.day - 1] = None return (timesheetData, timesheetTotal, warning)
def timesheet_report_data(mission, start=None, end=None, padding=False): """Prepare data for timesheet report from start to end. Padding align total in the same column""" timesheets = Timesheet.objects.select_related().filter(mission=mission) months = timesheets.dates("working_date", "month") data = [] for month in months: if start and month < start: continue if end and month > end: break days = daysOfMonth(month) next_month = nextMonth(month) padding_length = 31 - len(days) # Padding for month with less than 31 days to align total column # Header data.append([""]) data.append([formats.date_format(month, format="YEAR_MONTH_FORMAT")]) # Days data.append(["", ] + [d.day for d in days]) dayHeader = [_("Consultants")] + [_(d.strftime("%a")) for d in days] if padding: dayHeader.extend([""] * padding_length) dayHeader.append(_("total")) data.append(dayHeader) for consultant in mission.consultants(): total = 0 row = [consultant, ] consultant_timesheets = {} for timesheet in timesheets.filter(consultant_id=consultant.id, working_date__gte=month, working_date__lt=next_month): consultant_timesheets[timesheet.working_date] = timesheet.charge for day in days: try: charge = consultant_timesheets.get(day) if charge: row.append(formats.number_format(to_int_or_round(charge, 2))) total += charge else: row.append("") except Timesheet.DoesNotExist: row.append("") if padding: row.extend([""] * padding_length) row.append(formats.number_format(to_int_or_round(total, 2))) if total > 0: data.append(row) return data
def gatherTimesheetData(consultant, missions, month): """Gather existing timesheet timesheetData @returns: (timesheetData, timesheetTotal, warning) timesheetData represent timesheet form post timesheetData as a dict timesheetTotal is a dict of total charge (key is mission id) warning is a list of 0 (ok) or 1 (surbooking) or 2 (no data). One entry per day""" timesheetData = {} timesheetTotal = {} warning = [] totalPerDay = [0] * month_days(month) next_month = nextMonth(month) for mission in missions: timesheets = Timesheet.objects.select_related().filter(consultant=consultant).filter(mission=mission) timesheets = timesheets.filter(working_date__gte=month).filter(working_date__lt=next_month) for timesheet in timesheets: timesheetData["charge_%s_%s" % (timesheet.mission.id, timesheet.working_date.day)] = timesheet.charge if mission.id in timesheetTotal: timesheetTotal[mission.id] += timesheet.charge else: timesheetTotal[mission.id] = timesheet.charge totalPerDay[timesheet.working_date.day - 1] += timesheet.charge # Gather lunck ticket data totalTicket = 0 lunchTickets = LunchTicket.objects.filter(consultant=consultant) lunchTickets = lunchTickets.filter(lunch_date__gte=month).filter(lunch_date__lt=next_month) for lunchTicket in lunchTickets: timesheetData["lunch_ticket_%s" % lunchTicket.lunch_date.day] = lunchTicket.no_ticket totalTicket += 1 timesheetTotal["ticket"] = totalTicket # Compute warnings (overbooking and no data) for i in totalPerDay: i = round(i, 4) # We must round because using keyboard time input may lead to real numbers that are truncated if i > 1: # Surbooking warning.append(1) elif i == 1: # Ok warning.append(0) else: # warning (no data, or half day) warning.append(2) # Don't emit warning for no data during week ends and holidays holiday_days = holidayDays(month) for day in daysOfMonth(month): if day.isoweekday() in (6, 7) or day in holiday_days: warning[day.day - 1] = None return (timesheetData, timesheetTotal, warning)