def test_generate_dates(self): """ Test generation of full date ranges """ ### test WEEKLY # 2 weeks start = datetime.date(2011, 1, 17) end = datetime.date(2011, 1, 29) weeks = utils.generate_dates(start=start, end=end) self.assertEqual(2, weeks.count()) # 3 weeks start = datetime.date(2011, 1, 17) end = datetime.date(2011, 1, 31) weeks = utils.generate_dates(start=start, end=end) self.assertEqual(3, weeks.count()) # random weeks num = random.randint(5, 20) start = utils.get_week_start(datetime.date.today()) end = start + datetime.timedelta(weeks=num - 1) weeks = utils.generate_dates(start=start, end=end) self.assertEqual(num, weeks.count()) ### test MONTHLY start = datetime.date(2011, 1, 17) end = datetime.date(2011, 4, 29) months = utils.generate_dates(start=start, end=end, by='month') self.assertEqual(4, months.count()) for index, month in enumerate(months): self.assertEqual(month.date(), datetime.date(2011, index + 1, 1)) ### test DAILY start = datetime.date(2011, 2, 1) end = datetime.date(2011, 2, 15) days = utils.generate_dates(start=start, end=end, by='day') self.assertEqual(15, days.count()) for index, day in enumerate(days): self.assertEqual(day.date(), datetime.date(2011, 2, index + 1))
def testMonthlyTotal(self): start = timezone.make_aware( datetime.datetime(2011, 1, 1), timezone.get_current_timezone(), ) end = timezone.make_aware( datetime.datetime(2011, 3, 1), timezone.get_current_timezone(), ) trunc = 'month' last_day = randint(5, 10) worked1 = randint(1, 3) worked2 = randint(1, 3) for month in xrange(1, 7): for day in xrange(1, last_day + 1): day = timezone.make_aware( datetime.datetime(2011, month, day), timezone.get_current_timezone(), ) self.log_time(start=day, delta=(worked1, 0), user=self.user) self.log_time(start=day, delta=(worked2, 0), user=self.user2) date_headers = utils.generate_dates(start, end, trunc) pj_totals = self.get_project_totals(date_headers, trunc) for hour in pj_totals[0][0]: self.assertEqual(hour, last_day * worked1) for hour in pj_totals[0][1]: self.assertEqual(hour, last_day * worked2)
def bulk_entries(self, start=datetime.datetime(2011, 1, 2), end=datetime.datetime(2011, 1, 4)): start = utils.add_timezone(start) end = utils.add_timezone(end) dates = utils.generate_dates(start, end, "day") projects = [self.p1, self.p2, self.p2, self.p4, self.p5, self.sick] self.make_entries(projects=projects, dates=dates, user=self.user, hours=2) self.make_entries(projects=projects, dates=dates, user=self.user2, hours=1)
def testBillableNonBillable(self): start = timezone.make_aware( datetime.datetime(2011, 1, 1), timezone.get_current_timezone(), ) day2 = timezone.make_aware( datetime.datetime(2011, 1, 2), timezone.get_current_timezone(), ) end = timezone.make_aware( datetime.datetime(2011, 1, 3), timezone.get_current_timezone(), ) self.log_daily(start, day2, end) trunc = 'day' billableQ = Q(project__type__billable=True) non_billableQ = Q(project__type__billable=False) date_headers = utils.generate_dates(start, end, trunc) pj_billable = self.get_project_totals(date_headers, trunc, Q(), 'billable') pj_billable_q = self.get_project_totals(date_headers, trunc, billableQ, 'total') pj_non_billable = self.get_project_totals(date_headers, trunc, Q(), 'non_billable') pj_non_billable_q = self.get_project_totals(date_headers, trunc, non_billableQ, 'total') self.assertEqual(list(pj_billable), list(pj_billable_q)) self.assertEqual(list(pj_non_billable), list(pj_non_billable_q))
def testWeeklyTotal(self): start = utils.add_timezone(datetime.datetime(2011, 1, 3)) end = utils.add_timezone(datetime.datetime(2011, 1, 6)) self.bulk_entries(start, end) trunc = 'week' date_headers = utils.generate_dates(start, end, trunc) pj_totals = self.get_project_totals(date_headers, trunc) self.assertEqual(pj_totals[0][0], [48]) self.assertEqual(pj_totals[0][1], [24]) self.assertEqual(pj_totals[1], [72])
def testWeeklyTotal(self): start = datetime.datetime(2011, 1, 3) end = datetime.datetime(2011, 1, 6) self.bulk_entries(start, end) trunc = 'week' date_headers = utils.generate_dates(start, end, trunc) pj_totals = self.get_project_totals(date_headers, trunc) self.assertEqual(pj_totals[0][0], [48]) self.assertEqual(pj_totals[0][1], [24]) self.assertEqual(pj_totals[1], [72])
def hourly_report(request, date_form, from_date, to_date, status, activity): if not from_date: from_date = utils.get_month_start(datetime.datetime.today()).date() if not to_date: to_date = from_date + relativedelta(months=1) header_to = to_date - relativedelta(days=1) trunc = timepiece_forms.ProjectFiltersForm.DEFAULT_TRUNC query = Q(end_time__gt=utils.get_week_start(from_date), end_time__lt=to_date) if 'ok' in request.GET or 'export' in request.GET: form = timepiece_forms.ProjectFiltersForm(request.GET) if form.is_valid(): trunc = form.cleaned_data['trunc'] if not form.cleaned_data['paid_leave']: projects = getattr(settings, 'TIMEPIECE_PROJECTS', {}) query &= ~Q(project__in=projects.values()) if form.cleaned_data['pj_select']: query &= Q(project__in=form.cleaned_data['pj_select']) else: form = timepiece_forms.ProjectFiltersForm() hour_type = form.get_hour_type() entries = timepiece.Entry.objects.date_trunc(trunc).filter(query) date_headers = utils.generate_dates(from_date, header_to, by=trunc) project_totals = utils.project_totals(entries, date_headers, hour_type, total_column=True) if entries else '' if not request.GET.get('export', False): return { 'date_form': date_form, 'from_date': from_date, 'date_headers': date_headers, 'pj_filters': form, 'trunc': trunc, 'project_totals': project_totals, } else: from_date_str = from_date.strftime('%m-%d') to_date_str = to_date.strftime('%m-%d') response = HttpResponse(mimetype='text/csv') response['Content-Disposition'] = \ 'attachment; filename="%s_hours_%s_to_%s_by_%s.csv"' % ( hour_type, from_date_str, to_date_str, trunc) writer = csv.writer(response) headers = ['Name'] headers.extend([date.strftime('%m/%d/%Y') for date in date_headers]) headers.append('Total') writer.writerow(headers) for rows, totals in project_totals: for name, hours in rows: data = [name] data.extend(hours) writer.writerow(data) total = ['Totals'] total.extend(totals) writer.writerow(total) return response
def hourly_report(request, date_form, from_date, to_date, status, activity): if not from_date: from_date = utils.get_month_start(datetime.datetime.today()).date() if not to_date: to_date = from_date + relativedelta(months=1) header_to = to_date - relativedelta(days=1) trunc = timepiece_forms.ProjectFiltersForm.DEFAULT_TRUNC query = Q(end_time__gt=utils.get_week_start(from_date), end_time__lt=to_date) if 'ok' in request.GET or 'export' in request.GET: form = timepiece_forms.ProjectFiltersForm(request.GET) if form.is_valid(): trunc = form.cleaned_data['trunc'] if not form.cleaned_data['paid_leave']: projects = getattr(settings, 'TIMEPIECE_PROJECTS', {}) query &= ~Q(project__in=projects.values()) if form.cleaned_data['pj_select']: query &= Q(project__in=form.cleaned_data['pj_select']) else: form = timepiece_forms.ProjectFiltersForm() hour_type = form.get_hour_type() entries = timepiece.Entry.objects.date_trunc(trunc).filter(query) date_headers = utils.generate_dates(from_date, header_to, by=trunc) project_totals = utils.project_totals( entries, date_headers, hour_type, total_column=True) if entries else '' if not request.GET.get('export', False): return { 'date_form': date_form, 'from_date': from_date, 'date_headers': date_headers, 'pj_filters': form, 'trunc': trunc, 'project_totals': project_totals, } else: from_date_str = from_date.strftime('%m-%d') to_date_str = to_date.strftime('%m-%d') response = HttpResponse(mimetype='text/csv') response['Content-Disposition'] = \ 'attachment; filename="%s_hours_%s_to_%s_by_%s.csv"' % ( hour_type, from_date_str, to_date_str, trunc) writer = csv.writer(response) headers = ['Name'] headers.extend([date.strftime('%m/%d/%Y') for date in date_headers]) headers.append('Total') writer.writerow(headers) for rows, totals in project_totals: for name, hours in rows: data = [name] data.extend(hours) writer.writerow(data) total = ['Totals'] total.extend(totals) writer.writerow(total) return response
def user_weekly_assignments(): schedules = timepiece.PersonSchedule.objects.select_related() for schedule in schedules: for week in generate_dates(end=schedule.furthest_end_date, by='week'): next_week = week + relativedelta.relativedelta(weeks=1) assignments = timepiece.ContractAssignment.objects assignments = assignments.active_during_week(week, next_week) q = Q(user=schedule.user) q &= ~Q(contract__project__in=settings.TIMEPIECE_PROJECTS.values()) assignments = assignments.filter(q).select_related() yield schedule, week, assignments.order_by('end_date')
def testDailyTotal(self): start = utils.add_timezone(datetime.datetime(2011, 1, 1)) day2 = utils.add_timezone(datetime.datetime(2011, 1, 2)) end = utils.add_timezone(datetime.datetime(2011, 1, 3)) self.log_daily(start, day2, end) trunc = "day" date_headers = utils.generate_dates(start, end, trunc) pj_totals = self.get_project_totals(date_headers, trunc) self.assertEqual(pj_totals[0][0], [Decimal("1.00"), Decimal("1.50"), ""]) self.assertEqual(pj_totals[0][1], ["", Decimal("3.00"), Decimal("2.00")]) self.assertEqual(pj_totals[1], [Decimal("1.00"), Decimal("4.50"), Decimal("2.00")])
def bulk_entries(self, start=datetime.datetime(2011, 1, 2), end=datetime.datetime(2011, 1, 4)): if not timezone.is_aware(start): start = timezone.make_aware(start, timezone.get_current_timezone()) if not timezone.is_aware(end): end = timezone.make_aware(end, timezone.get_current_timezone()) dates = utils.generate_dates(start, end, 'day') projects = [self.p1, self.p2, self.p2, self.p4, self.p5, self.sick] self.make_entries(projects=projects, dates=dates, user=self.user, hours=2) self.make_entries(projects=projects, dates=dates, user=self.user2, hours=1)
def bulk_entries(self, start=datetime.datetime(2011, 1, 2), end=datetime.datetime(2011, 1, 4)): dates = utils.generate_dates(start, end, 'day') projects = [self.p1, self.p2, self.p2, self.p4, self.p5, self.sick] self.make_entries(projects=projects, dates=dates, user=self.user, hours=2) self.make_entries(projects=projects, dates=dates, user=self.user2, hours=1)
def testDailyTotal(self): start = utils.add_timezone(datetime.datetime(2011, 1, 1)) day2 = utils.add_timezone(datetime.datetime(2011, 1, 2)) end = utils.add_timezone(datetime.datetime(2011, 1, 3)) self.log_daily(start, day2, end) trunc = 'day' date_headers = utils.generate_dates(start, end, trunc) pj_totals = self.get_project_totals(date_headers, trunc) self.assertEqual(pj_totals[0][0], [Decimal('1.00'), Decimal('1.50'), '']) self.assertEqual(pj_totals[0][1], ['', Decimal('3.00'), Decimal('2.00')]) self.assertEqual(pj_totals[1], [Decimal('1.00'), Decimal('4.50'), Decimal('2.00')])
def testBillableNonBillable(self): start = utils.add_timezone(datetime.datetime(2011, 1, 1)) day2 = utils.add_timezone(datetime.datetime(2011, 1, 2)) end = utils.add_timezone(datetime.datetime(2011, 1, 3)) self.log_daily(start, day2, end) trunc = "day" billableQ = Q(project__type__billable=True) non_billableQ = Q(project__type__billable=False) date_headers = utils.generate_dates(start, end, trunc) pj_billable = self.get_project_totals(date_headers, trunc, Q(), "billable") pj_billable_q = self.get_project_totals(date_headers, trunc, billableQ, "total") pj_non_billable = self.get_project_totals(date_headers, trunc, Q(), "non_billable") pj_non_billable_q = self.get_project_totals(date_headers, trunc, non_billableQ, "total") self.assertEqual(list(pj_billable), list(pj_billable_q)) self.assertEqual(list(pj_non_billable), list(pj_non_billable_q))
def payroll_summary(request): year_month_form = timepiece_forms.YearMonthForm(request.GET or None) if request.GET and year_month_form.is_valid(): from_date, to_date, user = year_month_form.save() else: from_date = utils.get_month_start(datetime.datetime.today()).date() to_date = from_date + relativedelta(months=1) last_billable = utils.get_last_billable_day(from_date) projects = getattr(settings, 'TIMEPIECE_PROJECTS', {}) weekQ = Q(end_time__gt=utils.get_week_start(from_date), end_time__lt=last_billable + datetime.timedelta(days=1)) monthQ = Q(end_time__gt=from_date, end_time__lt=to_date) workQ = ~Q(project__in=projects.values()) statusQ = Q(status='invoiced') | Q(status='approved') # Weekly totals week_entries = timepiece.Entry.objects.date_trunc('week') week_entries = week_entries.filter(weekQ, statusQ, workQ) date_headers = utils.generate_dates(from_date, last_billable, by='week') weekly_totals = list( utils.project_totals(week_entries, date_headers, 'total', overtime=True)) # Monthly totals leave = timepiece.Entry.objects.filter(monthQ, ~workQ).values( 'user', 'hours', 'project__name') month_entries = timepiece.Entry.objects.date_trunc('month') month_entries_valid = month_entries.filter(monthQ, statusQ, workQ) monthly_totals = list( utils.payroll_totals(month_entries_valid, from_date, leave)) # Unapproved and unverified hours entries = timepiece.Entry.objects.filter(monthQ) user_values = ['user__pk', 'user__first_name', 'user__last_name'] unverified = entries.filter(monthQ, status='unverified', user__is_active=True) unapproved = entries.filter(monthQ, status='verified') return { 'from_date': from_date, 'year_month_form': year_month_form, 'date_headers': date_headers, 'weekly_totals': weekly_totals, 'monthly_totals': monthly_totals, 'unverified': unverified.values_list(*user_values).distinct(), 'unapproved': unapproved.values_list(*user_values).distinct(), }
def testDailyTotal(self): start = datetime.datetime(2011, 1, 1) day2 = datetime.datetime(2011, 1, 2) end = datetime.datetime(2011, 1, 3) self.log_daily(start, day2, end) trunc = 'day' date_headers = utils.generate_dates(start, end, trunc) pj_totals = self.get_project_totals(date_headers, trunc) self.assertEqual( pj_totals[0][0], [Decimal('1.00'), Decimal('1.50'), '']) self.assertEqual( pj_totals[0][1], ['', Decimal('3.00'), Decimal('2.00')]) self.assertEqual(pj_totals[1], [Decimal('1.00'), Decimal('4.50'), Decimal('2.00')])
def projection_summary(request, form, from_date, to_date, status, activity): if not (from_date and to_date): today = datetime.date.today() from_date = today.replace(day=1) to_date = from_date + relativedelta(months=1) contracts = timepiece.ProjectContract.objects.exclude(status='complete') contracts = contracts.exclude( project__in=settings.TIMEPIECE_PROJECTS.values()) contracts = contracts.order_by('end_date') users = User.objects.filter(assignments__contract__in=contracts).distinct() weeks = utils.generate_dates(start=from_date, end=to_date, by='week') return { 'form': form, 'weeks': weeks, 'contracts': contracts.select_related(), 'users': users, }
def testMonthlyTotal(self): start = datetime.datetime(2011, 1, 1) end = datetime.datetime(2011, 3, 1) trunc = 'month' last_day = randint(5, 10) worked1 = randint(1, 3) worked2 = randint(1, 3) for month in xrange(1, 7): for day in xrange(1, last_day + 1): day = datetime.datetime(2011, month, day) self.log_time(start=day, delta=(worked1, 0), user=self.user) self.log_time(start=day, delta=(worked2, 0), user=self.user2) date_headers = utils.generate_dates(start, end, trunc) pj_totals = self.get_project_totals(date_headers, trunc) for hour in pj_totals[0][0]: self.assertEqual(hour, last_day * worked1) for hour in pj_totals[0][1]: self.assertEqual(hour, last_day * worked2)
def testBillableNonBillable(self): start = datetime.datetime(2011, 1, 1) day2 = datetime.datetime(2011, 1, 2) end = datetime.datetime(2011, 1, 3) self.log_daily(start, day2, end) trunc = 'day' billableQ = Q(project__type__billable=True) non_billableQ = Q(project__type__billable=False) date_headers = utils.generate_dates(start, end, trunc) pj_billable = self.get_project_totals(date_headers, trunc, Q(), 'billable') pj_billable_q = self.get_project_totals(date_headers, trunc, billableQ, 'total') pj_non_billable = self.get_project_totals(date_headers, trunc, Q(), 'non_billable') pj_non_billable_q = self.get_project_totals(date_headers, trunc, non_billableQ, 'total') self.assertEqual(list(pj_billable), list(pj_billable_q)) self.assertEqual(list(pj_non_billable), list(pj_non_billable_q))
def payroll_summary(request): year_month_form = timepiece_forms.YearMonthForm(request.GET or None) if request.GET and year_month_form.is_valid(): from_date, to_date = year_month_form.save() else: from_date = utils.get_month_start(datetime.datetime.today()).date() to_date = from_date + relativedelta(months=1) last_billable = utils.get_last_billable_day(from_date) projects = getattr(settings, 'TIMEPIECE_PROJECTS', {}) weekQ = Q(end_time__gt=utils.get_week_start(from_date), end_time__lt=last_billable + datetime.timedelta(days=1)) monthQ = Q(end_time__gt=from_date, end_time__lt=to_date) workQ = ~Q(project__in=projects.values()) statusQ = Q(status='invoiced') | Q(status='approved') # Weekly totals week_entries = timepiece.Entry.objects.date_trunc('week') week_entries = week_entries.filter(weekQ, statusQ, workQ) date_headers = utils.generate_dates(from_date, last_billable, by='week') weekly_totals = list(utils.project_totals(week_entries, date_headers, 'total', overtime=True)) # Monthly totals leave = timepiece.Entry.objects.filter(monthQ, ~workQ ).values('user', 'hours', 'project__name') month_entries = timepiece.Entry.objects.date_trunc('month') month_entries_valid = month_entries.filter(monthQ, statusQ, workQ) monthly_totals = list(utils.payroll_totals(month_entries_valid, from_date, leave)) # Unapproved and unverified hours entries = timepiece.Entry.objects.filter(monthQ) user_values = ['user__pk', 'user__first_name', 'user__last_name'] unverified = entries.filter(monthQ, status='unverified', user__is_active=True) unapproved = entries.filter(monthQ, status='verified') return { 'from_date': from_date, 'year_month_form': year_month_form, 'date_headers': date_headers, 'weekly_totals': weekly_totals, 'monthly_totals': monthly_totals, 'unverified': unverified.values_list(*user_values).distinct(), 'unapproved': unapproved.values_list(*user_values).distinct(), }
def weeks_remaining(self): return utils.generate_dates(end=self.end_date, by='week')
def check_generate_dates(self, start, end, trunc, dates): for index, day in enumerate(utils.generate_dates(start, end, trunc)): if isinstance(day, datetime.datetime): day = day.date() self.assertEqual(day, dates[index].date())
def check_generate_dates(self, start, end, trunc, dates): for index, day in enumerate(utils.generate_dates(start, end, trunc)): self.assertEqual(day, dates[index])