def get_context_data(self, **kwargs): context = super(HourlyReport, self).get_context_data(**kwargs) # Sum the hours totals for each user & interval. entries = context['entries'] date_headers = context['date_headers'] summaries = [] if context['entries']: summaries.append( ('By User', get_project_totals(entries.order_by('user__last_name', 'user__id', 'date'), date_headers, 'total', total_column=True, by='user'))) entries = entries.order_by('project__type__label', 'project__name', 'project__id', 'date') func = lambda x: x['project__type__label'] for label, group in groupby(entries, func): title = label + ' Projects' summaries.append(( title, get_project_totals( list(group), date_headers, 'total', total_column=True, by='project', ), )) # Adjust date headers & create range headers. from_date = context['from_date'] from_date = utils.add_timezone(from_date) if from_date else None to_date = context['to_date'] to_date = utils.add_timezone(to_date) if to_date else None trunc = context['trunc'] date_headers, range_headers = self.get_headers(date_headers, from_date, to_date, trunc) context.update({ 'date_headers': date_headers, 'summaries': OrderedDict(summaries), 'range_headers': range_headers, }) return context
def get_context_data(self, **kwargs): context = super(HourlyReport, self).get_context_data(**kwargs) # Sum the hours totals for each user & interval. entries = context['entries'] date_headers = context['date_headers'] summaries = [] if context['entries']: summaries.append(('By User', get_project_totals( entries.order_by('user__last_name', 'user__id', 'date'), date_headers, 'total', total_column=True, by='user'))) entries = entries.order_by('project__type__label', 'project__name', 'project__id', 'date') func = lambda x: x['project__type__label'] for label, group in groupby(entries, func): title = label + ' Projects' summaries.append(( title, get_project_totals( list(group), date_headers, 'total', total_column=True, by='project', ), )) # Adjust date headers & create range headers. from_date = context['from_date'] from_date = utils.add_timezone(from_date) if from_date else None to_date = context['to_date'] to_date = utils.add_timezone(to_date) if to_date else None trunc = context['trunc'] date_headers, range_headers = self.get_headers( date_headers, from_date, to_date, trunc) context.update({ 'date_headers': date_headers, 'summaries': OrderedDict(summaries), 'range_headers': range_headers, }) return context
def report_payroll_summary(request): date = timezone.now() - relativedelta(months=1) from_date = utils.get_month_start(date).date() to_date = from_date + relativedelta(months=1) year_month_form = PayrollSummaryReportForm(request.GET or None, initial={ 'month': from_date.month, 'year': from_date.year }) if year_month_form.is_valid(): from_date, to_date = year_month_form.save() last_billable = utils.get_last_billable_day(from_date) projects = utils.get_setting('TIMEPIECE_PAID_LEAVE_PROJECTS') weekQ = Q(end_time__gt=utils.get_week_start(from_date), end_time__lt=last_billable + relativedelta(days=1)) monthQ = Q(end_time__gt=from_date, end_time__lt=to_date) workQ = ~Q(project__in=projects.values()) statusQ = Q(status=Entry.INVOICED) | Q(status=Entry.APPROVED) # Weekly totals week_entries = Entry.objects.date_trunc('week').filter( weekQ, statusQ, workQ) date_headers = generate_dates(from_date, last_billable, by='week') weekly_totals = list( get_project_totals(week_entries, date_headers, 'total', overtime=True)) # Monthly totals leave = Entry.objects.filter(monthQ, ~workQ).values('user', 'hours', 'project__name') extra_values = ('project__type__label', ) month_entries = Entry.objects.date_trunc('month', extra_values) month_entries_valid = month_entries.filter(monthQ, statusQ, workQ) labels, monthly_totals = get_payroll_totals(month_entries_valid, leave) # Unapproved and unverified hours entries = Entry.objects.filter(monthQ).order_by() # No ordering user_values = ['user__pk', 'user__first_name', 'user__last_name'] unverified = entries.filter(status=Entry.UNVERIFIED, user__is_active=True) \ .values_list(*user_values).distinct() unapproved = entries.filter(status=Entry.VERIFIED) \ .values_list(*user_values).distinct() return render( request, 'timepiece/reports/payroll_summary.html', { 'from_date': from_date, 'year_month_form': year_month_form, 'date_headers': date_headers, 'weekly_totals': weekly_totals, 'monthly_totals': monthly_totals, 'unverified': unverified, 'unapproved': unapproved, 'labels': labels, })
def get_project_totals(self, date_headers, trunc, query=Q(), hour_type='total'): """Helper function for testing project_totals utility directly""" entries = Entry.objects.date_trunc(trunc).filter(query) if entries: pj_totals = get_project_totals(entries, date_headers, hour_type) pj_totals = list(pj_totals) rows = pj_totals[0][0] hours = [hours for name, user_id, hours in rows] totals = pj_totals[0][1] return hours, totals else: return ''
def report_payroll_summary(request): date = timezone.now() - relativedelta(months=1) from_date = utils.get_month_start(date).date() to_date = from_date + relativedelta(months=1) year_month_form = PayrollSummaryReportForm(request.GET or None, initial={ 'month': from_date.month, 'year': from_date.year, }) if year_month_form.is_valid(): from_date, to_date = year_month_form.save() last_billable = utils.get_last_billable_day(from_date) projects = utils.get_setting('TIMEPIECE_PAID_LEAVE_PROJECTS') weekQ = Q(end_time__gt=utils.get_week_start(from_date), end_time__lt=last_billable + relativedelta(days=1)) monthQ = Q(end_time__gt=from_date, end_time__lt=to_date) workQ = ~Q(project__in=projects.values()) statusQ = Q(status=Entry.INVOICED) | Q(status=Entry.APPROVED) # Weekly totals week_entries = Entry.objects.date_trunc('week').filter( weekQ, statusQ, workQ ) date_headers = generate_dates(from_date, last_billable, by='week') weekly_totals = list(get_project_totals(week_entries, date_headers, 'total', overtime=True)) # Monthly totals leave = Entry.objects.filter(monthQ, ~workQ) leave = leave.values('user', 'hours', 'project__name') extra_values = ('project__type__label',) month_entries = Entry.objects.date_trunc('month', extra_values) month_entries_valid = month_entries.filter(monthQ, statusQ, workQ) labels, monthly_totals = get_payroll_totals(month_entries_valid, leave) # Unapproved and unverified hours entries = Entry.objects.filter(monthQ).order_by() # No ordering user_values = ['user__pk', 'user__first_name', 'user__last_name'] unverified = entries.filter(status=Entry.UNVERIFIED, user__is_active=True) \ .values_list(*user_values).distinct() unapproved = entries.filter(status=Entry.VERIFIED) \ .values_list(*user_values).distinct() return render(request, 'timepiece/reports/payroll_summary.html', { 'from_date': from_date, 'year_month_form': year_month_form, 'date_headers': date_headers, 'weekly_totals': weekly_totals, 'monthly_totals': monthly_totals, 'unverified': unverified, 'unapproved': unapproved, 'labels': labels, })
def get_hours_data(self, entries, date_headers): """Sum billable and non-billable hours across all users.""" project_totals = get_project_totals( entries, date_headers, total_column=False) if entries else [] data_map = {} for rows, totals in project_totals: for user, user_id, periods in rows: for period in periods: day = period['day'] if day not in data_map: data_map[day] = {'billable': 0, 'nonbillable': 0} data_map[day]['billable'] += period['billable'] data_map[day]['nonbillable'] += period['nonbillable'] return data_map