コード例 #1
0
 def test_get(self):
     """Get without param gets entries for this week."""
     response = self.client.get(reverse('dashboard'))
     self.assertEqual(response.status_code, 200)
     self.assertEqual(response.context['week_start'],
             utils.get_week_start().date())
     self.assertEqual(response.context['week_end'],
             utils.get_week_start().date() + relativedelta(days=6))
コード例 #2
0
 def test_week_start(self):
     """ Test that all days Sun. through Sat. return the previous Monday"""
     monday = datetime.date(2011, 1, 10)
     self.assertEqual(monday, utils.get_week_start(monday).date())
     sunday = datetime.date(2011, 1, 16)
     self.assertEqual(monday, utils.get_week_start(sunday).date())
     following_monday = datetime.date(2011, 1, 17)
     saturday = datetime.date(2011, 1, 22)
     self.assertEqual(following_monday, utils.get_week_start(saturday).date())
コード例 #3
0
 def test_assignment_active_within_week(self):
     """ Test manager returns assignments that contain entire week """
     start = utils.get_week_start() - datetime.timedelta(weeks=1)
     end = start + datetime.timedelta(weeks=3)
     ca = self._assign(start, end)
     week = utils.get_week_start()
     next_week = week + datetime.timedelta(weeks=1)
     assignments = timepiece.ContractAssignment.objects
     assignments = assignments.active_during_week(week, next_week)
     self.assertTrue(assignments.filter(pk=ca.pk).exists())
コード例 #4
0
 def test_assignment_active_starts_mid_week(self):
     """ Test manager returns assignments that start before window """
     start = utils.get_week_start() + datetime.timedelta(days=2)
     end = start + datetime.timedelta(weeks=2)
     ca = self._assign(start, end)
     week = utils.get_week_start()
     next_week = week + datetime.timedelta(weeks=1)
     assignments = timepiece.ContractAssignment.objects
     assignments = assignments.active_during_week(week, next_week)
     self.assertTrue(assignments.filter(pk=ca.pk).exists())
コード例 #5
0
 def setUp(self):
     super(ProjectHoursListViewTestCase, self).setUp()
     self.past_week = utils.get_week_start(datetime.date(2012, 4, 1)).date()
     self.current_week = utils.get_week_start().date()
     for i in range(5):
         self.create_project_hours_entry(self.past_week, published=True)
         self.create_project_hours_entry(self.current_week, published=True)
     self.url = reverse('view_schedule')
     self.client.login(username='******', password='******')
     self.date_format = '%Y-%m-%d'
コード例 #6
0
 def setUp(self):
     super(ProjectHoursListViewTestCase, self).setUp()
     self.past_week = utils.get_week_start(datetime.date(2012, 4, 1)).date()
     self.current_week = utils.get_week_start().date()
     for i in range(5):
         factories.ProjectHours(week_start=self.past_week, published=True)
         factories.ProjectHours(week_start=self.current_week, published=True)
     self.url = reverse("view_schedule")
     self.login_user(self.user)
     self.date_format = "%Y-%m-%d"
コード例 #7
0
    def dispatch(self, request, *args, **kwargs):
        # Since we use get param in multiple places, attach it to the class
        default_week = utils.get_week_start(datetime.date.today()).date()

        if request.method == 'GET':
            week_start_str = request.GET.get('week_start', '')
        else:
            week_start_str = request.POST.get('week_start', '')

        # Account for an empty string
        self.week_start = default_week if week_start_str == '' \
            else utils.get_week_start(datetime.datetime.strptime(
                week_start_str, '%Y-%m-%d').date())

        return super(ScheduleMixin, self).dispatch(request, *args,
                **kwargs)
コード例 #8
0
ファイル: utils.py プロジェクト: Cashiuus/django-timepiece
def grouped_totals(entries):
    select = {
        "day": {"date": """DATE_TRUNC('day', end_time)"""},
        "week": {"date": """DATE_TRUNC('week', end_time)"""},
    }
    weekly = entries.extra(select=select["week"]).values('date', 'billable')
    weekly = weekly.annotate(hours=Sum('hours')).order_by('date')
    daily = entries.extra(select=select["day"]).values('date', 'project__name',
                                                       'billable')
    daily = daily.annotate(hours=Sum('hours')).order_by('date',
                                                        'project__name')
    weeks = {}
    for week, week_entries in groupby(weekly, lambda x: x['date']):
        if week is not None:
            week = add_timezone(week)
        weeks[week] = get_hours_summary(week_entries)
    days = []
    last_week = None
    for day, day_entries in groupby(daily, lambda x: x['date']):
        week = get_week_start(day)
        if last_week and week > last_week:
            yield last_week, weeks.get(last_week, {}), days
            days = []
        days.append((day, daily_summary(day_entries)))
        last_week = week
    yield week, weeks.get(week, {}), days
コード例 #9
0
 def test_week_filter_midweek(self):
     """Filter corrects mid-week date to Monday of specified week."""
     wednesday = datetime.date(2012, 7, 4)
     monday = utils.get_week_start(wednesday).date()
     data = {"week_start": wednesday.strftime(self.date_format), "submit": ""}
     response = self.client.get(self.url, data)
     self.assertEquals(response.context["week"].date(), monday)
コード例 #10
0
ファイル: models.py プロジェクト: pobk/django-timepiece
 def weekly_commitment(self, day=None):
     self._log("Commitment for {0}".format(day))
     # earlier assignments may have already allocated time for this week
     unallocated = self.unallocated_hours_for_week(day)
     self._log('Unallocated hours {0}'.format(unallocated))
     reserved = self.remaining_min_hours()
     self._log('Reserved hours {0}'.format(reserved))
     # start with unallocated hours
     commitment = unallocated
     # reserve required hours on later assignments (min_hours_per_week)
     commitment -= self.remaining_min_hours()
     self._log('Commitment after reservation {0}'.format(commitment))
     # if we're under the needed minimum hours and we have available
     # time, then raise our commitment to the desired level
     if commitment < self.min_hours_per_week \
     and unallocated >= self.min_hours_per_week:
         commitment = self.min_hours_per_week
     self._log('Commitment after minimum weekly hours {0}'\
         .format(commitment))
     # calculate hours left on contract (subtract worked hours this week)
     week_start = utils.get_week_start(day)
     remaining = self.num_hours - self._filtered_hours_worked(week_start)
     total_allocated = self.blocks.aggregate(s=Sum('hours'))['s'] or 0
     remaining -= total_allocated
     if remaining < 0:
         remaining = 0
     self._log('Remaining {0}'.format(remaining))
     # reduce commitment to remaining hours
     if commitment > remaining:
         commitment = remaining
     self._log('Final commitment {0}'.format(commitment))
     return commitment
コード例 #11
0
 def test_weekly_commitment_over_remaining(self):
     # 1 week assignment, 20 hours
     start = utils.get_week_start()
     end = start + datetime.timedelta(weeks=1) - datetime.timedelta(days=1)
     ca = self._assign(start, end, hours=20)
     # only 20 hours left on assignment
     self.assertEqual(ca.weekly_commitment(start), 20)
コード例 #12
0
 def testFindStart(self):
     """
     With various kwargs, find_start should return the correct date
     """
     # Establish some datetimes
     now = timezone.now()
     today = now - relativedelta(
         hour=0, minute=0, second=0, microsecond=0)
     last_billing = today - relativedelta(months=1, day=1)
     yesterday = today - relativedelta(days=1)
     ten_days_ago = today - relativedelta(days=10)
     thisweek = utils.get_week_start(today)
     thismonth = today - relativedelta(day=1)
     thisyear = today - relativedelta(month=1, day=1)
     # Use command flags to obtain datetimes
     start_default = check_entries.Command().find_start()
     start_yesterday = check_entries.Command().find_start(days=1)
     start_ten_days_ago = check_entries.Command().find_start(days=10)
     start_of_week = check_entries.Command().find_start(week=True)
     start_of_month = check_entries.Command().find_start(month=True)
     start_of_year = check_entries.Command().find_start(year=True)
     # assure the returned datetimes are correct
     self.assertEqual(start_default, last_billing)
     self.assertEqual(start_yesterday, yesterday)
     self.assertEqual(start_ten_days_ago, ten_days_ago)
     self.assertEqual(start_of_week, thisweek)
     self.assertEqual(start_of_month, thismonth)
     self.assertEqual(start_of_year, thisyear)
コード例 #13
0
 def test_single_assignment_projection(self):
     # 2 weeks, 60 hours
     start = utils.get_week_start()
     end = start + datetime.timedelta(weeks=2) - datetime.timedelta(days=1)
     ca = self._assign(start, end, hours=60)
     run_projection()
     self.assertEqual(60, ca.blocks.aggregate(s=Sum('hours'))['s'])
コード例 #14
0
 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))
コード例 #15
0
 def create_project_hours_entry(self, week_start=None, project=None,
             user=None, hours=None, **kwargs):
     week_start = week_start or utils.get_week_start(add_tzinfo=False)
     project = project or self.create_project()
     user = user or self.create_user()
     hours = Decimal(str(random.random() * 20)) if hours is None else hours
     return ProjectHours.objects.create(week_start=week_start,
             project=project, user=user, hours=hours, **kwargs)
コード例 #16
0
 def test_no_entries(self):
     date = utils.get_week_start(datetime.date(2012, 3, 15))
     data = {
         'week_start': date.strftime('%Y-%m-%d'),
         'submit': '',
     }
     response = self.client.get(self.url, data)
     self.assertEquals(len(response.context['projects']), 0)
     self.assertEquals(len(response.context['users']), 0)
コード例 #17
0
ファイル: reports.py プロジェクト: eschipul/django-timepiece
 def get_entries_data(self):
     projects = utils.get_setting('TIMEPIECE_PAID_LEAVE_PROJECTS')
     # Account for the day added by the form
     query = Q(end_time__gt=utils.get_week_start(self.from_date),
         end_time__lt=self.to_date + relativedelta(days=1))
     query &= ~Q(project__in=projects.values())
     entries = timepiece.Entry.objects.date_trunc('week',
         extra_values=('activity', 'project__status')).filter(query)
     return entries
コード例 #18
0
 def test_weekly_commmitment_with_hours_worked(self):
     """ Test weekly commitment with previously logged hours """
     start = utils.get_week_start()
     end = start + datetime.timedelta(weeks=2) - datetime.timedelta(days=1)
     ca = self._assign(start, end, hours=30)
     self.log_time(ca, start=start, delta=(10, 0))
     self.assertEqual(ca.hours_worked, 10)
     self.assertEqual(ca.hours_remaining, 20)
     self.assertEqual(ca.weekly_commitment(start), 30)
コード例 #19
0
ファイル: hours.py プロジェクト: gtp/django-timepiece
 def setUp(self):
     super(ProjectHoursEditTestCase, self).setUp()
     self.permission = Permission.objects.filter(codename='add_projecthours')
     self.manager = self.create_user('manager', '*****@*****.**', 'abc')
     self.manager.user_permissions = self.permission
     self.view_url = reverse('edit_project_hours')
     self.ajax_url = reverse('project_hours_ajax_view')
     self.week_start = utils.get_week_start(datetime.date.today())
     self.next_week = self.week_start + relativedelta(days=7)
     self.future = self.week_start + relativedelta(days=14)
コード例 #20
0
 def test_unallocated_hours(self):
     """ Test unallocated hours calculation """
     start = utils.get_week_start()
     end = start + datetime.timedelta(weeks=2) - datetime.timedelta(days=1)
     ca = self._assign(start, end, hours=40)
     unallocated_hours = ca.unallocated_hours_for_week(start)
     self.assertEqual(unallocated_hours, 40)
     ca.blocks.create(date=start, hours=5)
     unallocated_hours = ca.unallocated_hours_for_week(start)
     self.assertEqual(unallocated_hours, 35)
コード例 #21
0
 def setUp(self):
     super(ProjectHoursEditTestCase, self).setUp()
     self.permission = Permission.objects.filter(codename="add_projecthours")
     self.manager = factories.User()
     self.manager.user_permissions = self.permission
     self.view_url = reverse("edit_schedule")
     self.ajax_url = reverse("ajax_schedule")
     self.week_start = utils.get_week_start(datetime.date.today())
     self.next_week = self.week_start + relativedelta(days=7)
     self.future = self.week_start + relativedelta(days=14)
コード例 #22
0
ファイル: base.py プロジェクト: DarioGT/schedulall
 def create_project_hours_entry(self, week_start=None, project=None,
             user=None, hours=None, published=None):
     week_start = (utils.get_week_start(add_tzinfo=False)
         if not week_start else week_start)
     project = self.create_project() if not project else project
     user = self.create_user() if not user else user
     hours = Decimal(str(random.random() * 20)) if not hours else hours
     return timepiece.ProjectHours.objects.create(week_start=week_start,
             project=project, user=user, hours=hours,
             published=published or False)
コード例 #23
0
ファイル: views.py プロジェクト: CalebMuhia/JobsBoard
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
コード例 #24
0
 def test_this_weeks_priority_type(self):
     """ Test categories for this week. """
     start = utils.get_week_start(datetime.date.today())
     end = start + datetime.timedelta(weeks=1)
     ca_starting = self._assign(start, end, hours=40)
     self.assertEqual('starting', ca_starting.this_weeks_priority_type)
     end = utils.get_week_start()
     start = end - datetime.timedelta(days=2)
     ca_ending = self._assign(start, end, hours=40)
     self.assertEqual('ending', ca_ending.this_weeks_priority_type)
     start = utils.get_week_start()
     end = start + datetime.timedelta(days=6)
     ca_starting_ending = self._assign(start, end, hours=40)
     self.assertEqual('ending', ca_starting_ending.this_weeks_priority_type)
     start = utils.get_week_start() - datetime.timedelta(days=1)
     end = start + datetime.timedelta(days=9)
     ca_ongoing = self._assign(start, end, hours=40)
     self.assertEqual('ongoing', ca_ongoing.this_weeks_priority_type)
     ## Need to test order goes ending, starting, ongoing.
     assignments = timepiece.ContractAssignment.objects.sort_by_priority()
コード例 #25
0
 def setUp(self):
     super(ProjectHoursEditTestCase, self).setUp()
     self.permission = Permission.objects.filter(
         codename='add_projecthours')
     self.manager = factories.User()
     self.manager.user_permissions = self.permission
     self.view_url = reverse('edit_schedule')
     self.ajax_url = reverse('ajax_schedule')
     self.week_start = utils.get_week_start(datetime.date.today())
     self.next_week = self.week_start + relativedelta(days=7)
     self.future = self.week_start + relativedelta(days=14)
コード例 #26
0
ファイル: hours.py プロジェクト: eschipul/django-timepiece
 def setUp(self):
     super(ProjectHoursEditTestCase, self).setUp()
     self.permission = Permission.objects.filter(
         codename='add_projecthours')
     self.manager = self.create_user('manager', '*****@*****.**', 'abc')
     self.manager.user_permissions = self.permission
     self.view_url = reverse('edit_project_hours')
     self.ajax_url = reverse('project_hours_ajax_view')
     self.week_start = utils.get_week_start(datetime.date.today())
     self.next_week = self.week_start + relativedelta(days=7)
     self.future = self.week_start + relativedelta(days=14)
コード例 #27
0
    def setUp(self):
        self.today = datetime.date(2012, 11, 7)
        self.this_week = utils.get_week_start(self.today)
        self.next_week = self.this_week + relativedelta(days=7)

        self.user = factories.User()

        self.project = factories.Project()
        self.activity = factories.Activity()
        self.location = factories.Location()
        self.status = Entry.UNVERIFIED
コード例 #28
0
 def test_no_remaining_hours(self):
     """ Gurantee no overcommittment """
     # 1 week, 40 hours
     start = utils.get_week_start()
     end = start + datetime.timedelta(weeks=1) - datetime.timedelta(days=1)
     ca1 = self._assign(start, end, hours=40)
     ca1.blocks.create(date=start, hours=40)
     self.assertEqual(ca1.weekly_commitment(start), 0)
     # 2 weeks, 40 hours
     end = start + datetime.timedelta(weeks=2) - datetime.timedelta(days=1)
     ca2 = self._assign(start, end, hours=40)
     self.assertEqual(ca2.weekly_commitment(start), 0)
コード例 #29
0
 def get_dates(self):
     today = datetime.date.today()
     day = today
     if 'week_start' in self.request.GET:
         param = self.request.GET.get('week_start')
         try:
             day = datetime.datetime.strptime(param, '%Y-%m-%d').date()
         except:
             pass
     week_start = utils.get_week_start(day)
     week_end = week_start + relativedelta(days=6)
     return today, week_start, week_end
コード例 #30
0
 def get_dates(self):
     today = datetime.date.today()
     day = today
     if 'week_start' in self.request.GET:
         param = self.request.GET.get('week_start')
         try:
             day = datetime.datetime.strptime(param, '%Y-%m-%d').date()
         except:
             pass
     week_start = utils.get_week_start(day)
     week_end = week_start + relativedelta(days=6)
     return today, week_start, week_end
コード例 #31
0
 def test_weekly_commmitment_with_earlier_allocation(self):
     """ Test calculation of contract assignment's weekly commitment """
     # 1 week assignment, 20 hours
     start = utils.get_week_start()
     end = start + datetime.timedelta(weeks=1) - datetime.timedelta(days=1)
     ca1 = self._assign(start, end, hours=20)
     # allocate 20 hours to this assignment
     ca1.blocks.create(date=start, hours=20)
     # 1 week assignment, 20 hours
     ca2 = self._assign(start, end, hours=20)
     # only 20 hours left this week
     self.assertEqual(ca2.weekly_commitment(start), 20)
コード例 #32
0
ファイル: views.py プロジェクト: commoncode/django-timepiece
def view_entries(request):
    week_start = utils.get_week_start()
    entries = timepiece.Entry.objects.select_related(
        'project__business', ).filter(
            user=request.user,
            end_time__gte=week_start,
        ).select_related('project', 'activity', 'location')
    today = datetime.date.today()
    assignments = timepiece.ContractAssignment.objects.filter(
        user=request.user,
        user__project_relationships__project=F('contract__project'),
        end_date__gte=today,
        contract__status='current',
    ).order_by('contract__project__type', 'end_date')
    assignments = assignments.select_related('user', 'contract__project__type')
    activity_entries = entries.values(
        'billable', ).annotate(sum=Sum('hours')).order_by('-sum')
    current_total = entries.aggregate(sum=Sum('hours'))['sum']
    others_active_entries = timepiece.Entry.objects.filter(
        end_time__isnull=True, ).exclude(user=request.user, ).select_related(
            'user', 'project', 'activity')
    my_active_entries = timepiece.Entry.objects.select_related(
        'project__business', ).only('user', 'project', 'activity',
                                    'start_time').filter(
                                        user=request.user,
                                        end_time__isnull=True,
                                    )
    #     temporarily disabled until the allocations represent accurate goals
    #     -TM 6/27
    allocations = []
    allocated_projects = timepiece.Project.objects.none()
    #    allocations = timepiece.AssignmentAllocation.objects.during_this_week(
    #        request.user
    #        ).order_by('assignment__contract__project__name')
    #    allocated_projects = allocations.values_list(
    #    'assignment__contract__project',)

    project_entries = entries.exclude(project__in=allocated_projects, ).values(
        'project__name',
        'project__pk').annotate(sum=Sum('hours')).order_by('project__name')
    schedule = timepiece.PersonSchedule.objects.filter(user=request.user)
    context = {
        'this_weeks_entries': entries.order_by('-start_time'),
        'assignments': assignments,
        'allocations': allocations,
        'schedule': schedule,
        'project_entries': project_entries,
        'activity_entries': activity_entries,
        'current_total': current_total,
        'others_active_entries': others_active_entries,
        'my_active_entries': my_active_entries,
    }
    return context
コード例 #33
0
 def test_no_remaining_hours(self):
     """ Gurantee no overcommittment """
     # 1 week, 40 hours
     start = utils.get_week_start()
     end = start + datetime.timedelta(weeks=1) - datetime.timedelta(days=1)
     ca1 = self._assign(start, end, hours=40)
     ca1.blocks.create(date=start, hours=40)
     self.assertEqual(ca1.weekly_commitment(start), 0)
     # 2 weeks, 40 hours
     end = start + datetime.timedelta(weeks=2) - datetime.timedelta(days=1)
     ca2 = self._assign(start, end, hours=40)
     self.assertEqual(ca2.weekly_commitment(start), 0)
コード例 #34
0
 def test_this_weeks_hours(self):
     start = utils.get_week_start()
     end = start + datetime.timedelta(weeks=2) - datetime.timedelta(days=1)
     ca = self._assign(start, end, hours=60)
     run_projection()
     self.log_time(ca, start=start, delta=(10, 0))
     assignments = timepiece.AssignmentAllocation.objects.during_this_week(
         self.ps.user)
     self.assertEquals(assignments.count(), 1)
     assignment = assignments[0]
     self.assertEquals(assignment.hours_worked, 10)
     self.assertEquals(assignment.hours_left, assignment.hours - 10)
コード例 #35
0
 def test_weekly_commmitment_with_earlier_allocation(self):
     """ Test calculation of contract assignment's weekly commitment """
     # 1 week assignment, 20 hours
     start = utils.get_week_start()
     end = start + datetime.timedelta(weeks=1) - datetime.timedelta(days=1)
     ca1 = self._assign(start, end, hours=20)
     # allocate 20 hours to this assignment
     ca1.blocks.create(date=start, hours=20)
     # 1 week assignment, 20 hours
     ca2 = self._assign(start, end, hours=20)
     # only 20 hours left this week
     self.assertEqual(ca2.weekly_commitment(start), 20)
コード例 #36
0
 def test_this_weeks_hours(self):
     start = utils.get_week_start()
     end = start + datetime.timedelta(weeks=2) - datetime.timedelta(days=1)
     ca = self._assign(start, end, hours=60)
     run_projection()
     self.log_time(ca, start=start, delta=(10, 0))
     assignments = timepiece.AssignmentAllocation.objects.during_this_week(
         self.ps.user)
     self.assertEquals(assignments.count(), 1)
     assignment = assignments[0]
     self.assertEquals(assignment.hours_worked, 10)
     self.assertEquals(assignment.hours_left, assignment.hours - 10)
コード例 #37
0
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,
        })
コード例 #38
0
 def test_weekly_commmitment_with_look_ahead(self):
     """ Test later assignment's min hours factor into weekly commitment """
     # 1 week assignment, 40 hours
     start = utils.get_week_start()
     end = start + datetime.timedelta(weeks=1) - datetime.timedelta(days=1)
     ca1 = self._assign(start, end, hours=40)
     # 2 week assignment, 40 hours
     end = start + datetime.timedelta(weeks=1) - datetime.timedelta(days=1)
     ca2 = self._assign(start, end, hours=40)
     ca2.min_hours_per_week = 5
     ca2.save()
     self.assertEqual(ca1.weekly_commitment(start), 35)
     ca1.blocks.create(date=start, hours=35)
     self.assertEqual(ca2.weekly_commitment(start), 5)
コード例 #39
0
    def setUp(self):
        self.today = datetime.date(2012, 11, 7)
        self.this_week = utils.get_week_start(self.today)
        self.next_week = self.this_week + relativedelta(days=7)

        self.uname = 'test'
        self.pword = 'password'
        self.user = self.create_user(username=self.uname, password=self.pword)
        self.client.login(username=self.uname, password=self.pword)

        self.project = self.create_project()
        self.activity = self.create_activity()
        self.location = self.create_location()
        self.status = 'unverified'
コード例 #40
0
ファイル: views.py プロジェクト: Cashiuus/django-timepiece
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,
    })
コード例 #41
0
ファイル: utils.py プロジェクト: sgentilini/django-timepiece
def generate_dates(start=None, end=None, by='week'):
    if start:
        start = add_timezone(start)
    if end:
        end = add_timezone(end)
    if by == 'year':
        start = get_year_start(start)
        return rrule.rrule(rrule.YEARLY, dtstart=start, until=end)
    if by == 'month':
        start = get_month_start(start)
        return rrule.rrule(rrule.MONTHLY, dtstart=start, until=end)
    if by == 'week':
        start = get_week_start(start)
        return rrule.rrule(rrule.WEEKLY, dtstart=start, until=end, byweekday=0)
    if by == 'day':
        return rrule.rrule(rrule.DAILY, dtstart=start, until=end)
コード例 #42
0
    def setUp(self):
        self.today = datetime.date(2012, 11, 7)
        self.this_week = utils.get_week_start(self.today)
        self.next_week = self.this_week + relativedelta(days=7)

        get_params = {'week_start': self.this_week.strftime('%Y-%m-%d')}
        self.url = reverse('dashboard') + '?' + urlencode(get_params)

        self.user = factories.User()
        self.permission = Permission.objects.get(codename='can_clock_in')
        self.user.user_permissions.add(self.permission)
        self.login_user(self.user)

        self.project = factories.Project()
        self.activity = factories.Activity()
        self.location = factories.Location()
        self.status = Entry.UNVERIFIED
コード例 #43
0
ファイル: views.py プロジェクト: commoncode/django-timepiece
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(),
    }
コード例 #44
0
 def test_min_hours_per_week_weighted(self):
     """
     Test minimum hours/week with weighting based on assignment end date
     """
     start = utils.get_week_start()
     end = start + datetime.timedelta(weeks=1)
     ca1 = self._assign(start, end, hours=40)
     ca2 = self._assign(start, end + datetime.timedelta(days=1), hours=40)
     ca1.min_hours_per_week = 30
     ca1.save()
     ca2.min_hours_per_week = 30
     ca2.save()
     run_projection()
     projection = ca1.blocks.filter(date=start).aggregate(s=Sum('hours'))
     self.assertEqual(30, projection['s'])
     projection = ca2.blocks.filter(date=start).aggregate(s=Sum('hours'))
     self.assertEqual(10, projection['s'])
コード例 #45
0
    def setUp(self):
        self.today = datetime.date(2012, 11, 7)
        self.this_week = utils.get_week_start(self.today)
        self.next_week = self.this_week + relativedelta(days=7)

        get_params = {'week_start': self.this_week.strftime('%Y-%m-%d')}
        self.url = reverse('dashboard') + '?' + urlencode(get_params)

        self.uname = 'test'
        self.pword = 'password'
        self.user = self.create_user(username=self.uname, password=self.pword)
        self.permission = Permission.objects.get(codename='can_clock_in')
        self.user.user_permissions.add(self.permission)
        self.client.login(username=self.uname, password=self.pword)

        self.project = self.create_project()
        self.activity = self.create_activity()
        self.location = self.create_location()
        self.status = 'unverified'
コード例 #46
0
 def test_this_weeks_allocations(self):
     # 2 weeks, 60 hours
     start = utils.get_week_start()
     end = start + datetime.timedelta(weeks=2) - datetime.timedelta(days=1)
     ca = self._assign(start, end, hours=20)
     person = User.objects.create_user('test2', '*****@*****.**', 'abc')
     ps = self.create_person_schedule(data={'user': person})
     run_projection()
     assignments = timepiece.AssignmentAllocation.objects.during_this_week(
         self.ps.user)
     self.assertEquals(assignments.count(), 1)
     assignments = timepiece.AssignmentAllocation.objects.during_this_week(
         person)
     self.assertEquals(assignments.count(), 0)
     ca_2 = self._assign(start, end, hours=30)
     run_projection()
     assignments = timepiece.AssignmentAllocation.objects.during_this_week(
         self.ps.user)
     self.assertEquals(assignments.count(), 2)
コード例 #47
0
 def find_start(self, **kwargs):
     """
     Determine the starting point of the query using CLI keyword arguments
     """
     week = kwargs.get('week', False)
     month = kwargs.get('month', False)
     year = kwargs.get('year', False)
     days = kwargs.get('days', 0)
     #If no flags are True, set to the beginning of last billing window
     #to assure we catch all recent violations
     start = timezone.now() - relativedelta(months=1, day=1)
     #Set the start date based on arguments provided through options
     if week:
         start = utils.get_week_start()
     if month:
         start = timezone.now() - relativedelta(day=1)
     if year:
         start = timezone.now() - relativedelta(day=1, month=1)
     if days:
         start = timezone.now() - datetime.timedelta(days=days)
     start -= relativedelta(hour=0, minute=0, second=0, microsecond=0)
     return start
コード例 #48
0
def week_start(date):
    return utils.get_week_start(date).strftime('%m/%d/%Y')
コード例 #49
0
ファイル: views.py プロジェクト: commoncode/django-timepiece
def view_person_time_sheet(request, user_id):
    user = get_object_or_404(User, pk=user_id)
    if not (request.user.has_perm('timepiece.view_entry_summary') or \
        user.pk == request.user.pk):
        return HttpResponseForbidden('Forbidden')
    from_date = utils.get_month_start(datetime.datetime.today()).date()
    to_date = from_date + relativedelta(months=1)
    initial = {
        'request_user': request.user,
        'user': request.GET.get('user', user_id)
    }
    year_month_form = timepiece_forms.YearMonthForm(request.GET or None,
                                                    initial=initial)
    if year_month_form.is_valid():
        from_date, to_date, form_user = year_month_form.save()
        if form_user:
            url = reverse('view_person_time_sheet', args=(form_user.pk, ))
            # Do not use request.GET in urlencode in case it has the
            # user parameter (redirect loop otherwise)
            request_data = {
                'month': request.GET.get('month', from_date.month),
                'year': request.GET.get('year', from_date.year)
            }
            url += '?{0}'.format(urllib.urlencode(request_data))
            return HttpResponseRedirect(url)
    entries_qs = timepiece.Entry.objects.filter(user=user)
    month_qs = entries_qs.timespan(from_date, span='month')
    month_entries = month_qs.date_trunc('month', True)
    # For grouped entries, back date up to the start of the week.
    first_week = utils.get_week_start(from_date)
    month_week = first_week + datetime.timedelta(weeks=1)
    grouped_qs = entries_qs.timespan(first_week, to_date=to_date)
    intersection = grouped_qs.filter(start_time__lt=month_week,
                                     start_time__gte=from_date)
    # If the month of the first week starts in the previous
    # month and we dont have entries in that previous ISO
    # week, then update the first week to start at the first
    # of the actual month
    if not intersection and first_week.month < from_date.month:
        grouped_qs = entries_qs.timespan(from_date, to_date=to_date)
    grouped_totals = utils.grouped_totals(grouped_qs) if month_entries else ''
    project_entries = month_qs.order_by().values('project__name').annotate(
        sum=Sum('hours')).order_by('-sum')
    summary = timepiece.Entry.summary(user, from_date, to_date)
    show_approve = show_verify = False
    if request.user.has_perm('timepiece.change_entry') or \
        user == request.user:
        statuses = list(entries_qs.values_list('status', flat=True))
        total_statuses = len(statuses)
        unverified_count = statuses.count('unverified')
        verified_count = statuses.count('verified')
        approved_count = statuses.count('approved')
        show_verify = unverified_count != 0
    if request.user.has_perm('timepiece.change_entry'):
        show_approve = verified_count + approved_count == total_statuses \
        and verified_count > 0 and total_statuses != 0
    context = {
        'year_month_form': year_month_form,
        'from_date': from_date,
        'to_date': to_date - datetime.timedelta(days=1),
        'show_verify': show_verify,
        'show_approve': show_approve,
        'timesheet_user': user,
        'entries': month_entries,
        'grouped_totals': grouped_totals,
        'project_entries': project_entries,
        'summary': summary,
    }
    return render_to_response('timepiece/time-sheet/people/view.html',
                              context,
                              context_instance=RequestContext(request))
コード例 #50
0
def view_user_timesheet(request, user_id, active_tab):
    # User can only view their own time sheet unless they have a permission.
    user = get_object_or_404(User, pk=user_id)
    has_perm = request.user.has_perm('entries.view_entry_summary')
    if not (has_perm or user.pk == request.user.pk):
        return HttpResponseForbidden('Forbidden')

    FormClass = UserYearMonthForm if has_perm else YearMonthForm
    form = FormClass(request.GET or None)
    if form.is_valid():
        if has_perm:
            from_date, to_date, form_user = form.save()
            if form_user and request.GET.get('yearmonth', None):
                # Redirect to form_user's time sheet.
                # Do not use request.GET in urlencode to prevent redirect
                # loop caused by yearmonth parameter.
                url = reverse('view_user_timesheet', args=(form_user.pk, ))
                request_data = {
                    'month': from_date.month,
                    'year': from_date.year,
                    'user': form_user.pk,  # Keep so that user appears in form.
                }
                url += '?{0}'.format(urllib.urlencode(request_data))
                return HttpResponseRedirect(url)
        else:  # User must be viewing their own time sheet; no redirect needed.
            from_date, to_date = form.save()
        from_date = utils.add_timezone(from_date)
        to_date = utils.add_timezone(to_date)
    else:
        # Default to showing this month.
        from_date = utils.get_month_start()
        to_date = from_date + relativedelta(months=1)

    entries_qs = Entry.objects.filter(user=user)
    month_qs = entries_qs.timespan(from_date, span='month')
    extra_values = ('start_time', 'end_time', 'comments', 'seconds_paused',
                    'id', 'location__name', 'project__name', 'activity__name',
                    'status')
    month_entries = month_qs.date_trunc('month', extra_values)
    # For grouped entries, back date up to the start of the week.
    first_week = utils.get_week_start(from_date)
    month_week = first_week + relativedelta(weeks=1)
    grouped_qs = entries_qs.timespan(first_week, to_date=to_date)
    intersection = grouped_qs.filter(start_time__lt=month_week,
                                     start_time__gte=from_date)
    # If the month of the first week starts in the previous
    # month and we dont have entries in that previous ISO
    # week, then update the first week to start at the first
    # of the actual month
    if not intersection and first_week.month < from_date.month:
        grouped_qs = entries_qs.timespan(from_date, to_date=to_date)
    totals = grouped_totals(grouped_qs) if month_entries else ''
    project_entries = month_qs.order_by().values('project__name').annotate(
        sum=Sum('hours')).order_by('-sum')
    summary = Entry.summary(user, from_date, to_date)

    show_approve = show_verify = False
    can_change = request.user.has_perm('entries.change_entry')
    can_approve = request.user.has_perm('entries.approve_timesheet')
    if can_change or can_approve or user == request.user:
        statuses = list(month_qs.values_list('status', flat=True))
        total_statuses = len(statuses)
        unverified_count = statuses.count(Entry.UNVERIFIED)
        verified_count = statuses.count(Entry.VERIFIED)
        approved_count = statuses.count(Entry.APPROVED)
    if can_change or user == request.user:
        show_verify = unverified_count != 0
    if can_approve:
        show_approve = verified_count + approved_count == total_statuses \
                and verified_count > 0 and total_statuses != 0

    return render(
        request, 'timepiece/user/timesheet/view.html', {
            'active_tab': active_tab or 'overview',
            'year_month_form': form,
            'from_date': from_date,
            'to_date': to_date - relativedelta(days=1),
            'show_verify': show_verify,
            'show_approve': show_approve,
            'timesheet_user': user,
            'entries': month_entries,
            'grouped_totals': totals,
            'project_entries': project_entries,
            'summary': summary,
        })
コード例 #51
0
def report_productivity(request):
    report = []
    organize_by = None

    form = ProductivityReportForm(request.GET or None)
    if form.is_valid():
        project = form.cleaned_data['project']
        organize_by = form.cleaned_data['organize_by']
        export = request.GET.get('export', False)

        actualsQ = Q(project=project, end_time__isnull=False)
        actuals = Entry.objects.filter(actualsQ)
        projections = ProjectHours.objects.filter(project=project)
        entry_count = actuals.count() + projections.count()

        if organize_by == 'week' and entry_count > 0:
            # Determine the project's time range.
            amin, amax, pmin, pmax = (None, None, None, None)
            if actuals.count() > 0:
                amin = actuals.aggregate(Min('start_time')).values()[0]
                amin = utils.get_week_start(amin).date()
                amax = actuals.aggregate(Max('start_time')).values()[0]
                amax = utils.get_week_start(amax).date()
            if projections.count() > 0:
                pmin = projections.aggregate(Min('week_start')).values()[0]
                pmax = projections.aggregate(Max('week_start')).values()[0]
            current = min(amin, pmin) if (amin and pmin) else (amin or pmin)
            latest = max(amax, pmax) if (amax and pmax) else (amax or pmax)

            # Report for each week during the project's time range.
            while current <= latest:
                next_week = current + relativedelta(days=7)
                actual_hours = actuals.filter(
                    start_time__gte=current,
                    start_time__lt=next_week).aggregate(
                        Sum('hours')).values()[0]
                projected_hours = projections.filter(
                    week_start__gte=current,
                    week_start__lt=next_week).aggregate(
                        Sum('hours')).values()[0]
                report.append([
                    date_format_filter(current, 'M j, Y'), actual_hours or 0,
                    projected_hours or 0
                ])
                current = next_week

        elif organize_by == 'user' and entry_count > 0:
            # Determine all users who worked on or were assigned to the
            # project.
            vals = ('user', 'user__first_name', 'user__last_name')
            ausers = list(actuals.values_list(*vals).distinct())
            pusers = list(projections.values_list(*vals).distinct())
            key = lambda x: (x[1] + x[2]).lower()  # Sort by name
            users = sorted(list(set(ausers + pusers)), key=key)

            # Report for each user.
            for user in users:
                name = '{0} {1}'.format(user[1], user[2])
                actual_hours = actuals.filter(user=user[0]) \
                        .aggregate(Sum('hours')).values()[0]
                projected_hours = projections.filter(user=user[0]) \
                        .aggregate(Sum('hours')).values()[0]
                report.append([name, actual_hours or 0, projected_hours or 0])

        col_headers = [organize_by.title(), 'Worked Hours', 'Assigned Hours']
        report.insert(0, col_headers)

        if export:
            response = HttpResponse(content_type='text/csv')
            filename = '{0}_productivity'.format(project.name)
            content_disp = 'attachment; filename={0}.csv'.format(filename)
            response['Content-Disposition'] = content_disp
            writer = csv.writer(response)
            for row in report:
                writer.writerow(row)
            return response

    return render(
        request, 'timepiece/reports/productivity.html', {
            'form': form,
            'report': json.dumps(report, cls=DecimalEncoder),
            'type': organize_by or '',
            'total_worked': sum([r[1] for r in report[1:]]),
            'total_assigned': sum([r[2] for r in report[1:]]),
        })
コード例 #52
0
ファイル: forms.py プロジェクト: sgentilini/django-timepiece
 def clean_week_start(self):
     week_start = self.cleaned_data.get('week_start', None)
     return utils.get_week_start(week_start, False) if week_start else None
コード例 #53
0
 def save(self, *args, **kwargs):
     # Ensure that week_start is the Monday of a given week.
     self.week_start = utils.get_week_start(self.week_start)
     return super(ProjectHours, self).save(*args, **kwargs)
コード例 #54
0
ファイル: utils.py プロジェクト: sgentilini/django-timepiece
def get_week_window(day=None):
    """Returns (Monday, Sunday) of the requested week."""
    start = get_week_start(day)
    return (start, start + relativedelta(days=6))
コード例 #55
0
 def test_weekly_commmitment(self):
     """ Test calculation of contract assignment's weekly commitment """
     start = utils.get_week_start()
     end = start + datetime.timedelta(weeks=2) - datetime.timedelta(days=1)
     ca = self._assign(start, end, hours=40)
     self.assertEqual(ca.weekly_commitment(start), 40)
コード例 #56
0
def view_user_timesheet(request, user_id, active_tab):
    user = get_object_or_404(User, pk=user_id)
    has_perm = request.user.has_perm('entries.view_entry_summary')
    if not (has_perm or user.pk == request.user.pk):
        return HttpResponseForbidden('Forbidden')

    FormClass = UserYearMonthForm if has_perm else YearMonthForm
    form = FormClass(request.GET or None)
    if form.is_valid():
        if has_perm:
            from_date, to_date, form_user = form.save()
            if form_user and request.GET.get('yearmonth', None):
                url = reverse('view_user_timesheet', args=(form_user.pk, ))
                request_data = {
                    'month': from_date.month,
                    'year': from_date.year,
                    'user': form_user.pk,
                }
                url += '?{0}'.format(urlencode(request_data))
                return HttpResponseRedirect(url)
        else:
            from_date, to_date = form.save()
        from_date = add_timezone(from_date)
        to_date = add_timezone(to_date)
    else:
        # from_date = get_month_start()
        # to_date = from_date + relativedelta(months=1)
        from_date = Entry.objects.last().start_time
        to_date = datetime.datetime.today()

    entries_qs = Entry.objects.filter(user=user)
    if form.is_valid():
        month_qs = entries_qs.timespan(from_date, span='month')
    else:
        month_qs = entries_qs.timespan(from_date)
    extra_values = ('start_time', 'end_time', 'comments', 'seconds_paused',
                    'id', 'location__name', 'project__name', 'activity__name',
                    'status')
    month_entries = month_qs.date_trunc('month',
                                        extra_values).order_by('start_time')
    entry_ids = month_entries.values_list('id', flat=True)
    tasks = TaskList.objects.filter(entry_id__in=entry_ids).values(
        'entry_id', 'tasks').order_by('entry_id')
    task_values = [
        tasks.get(entry_id=entry_id)['tasks']
        if entry_id in tasks.values_list('entry_id', flat=True) else ''
        for entry_id in entry_ids
    ]
    first_week = get_week_start(from_date)
    month_week = first_week + relativedelta(weeks=1)
    grouped_qs = entries_qs.timespan(first_week, to_date=to_date)
    intersection = grouped_qs.filter(start_time__lt=month_week,
                                     start_time__gte=from_date)
    if not intersection and first_week.month < from_date.month:
        grouped_qs = entries_qs.timespan(from_date, to_date=to_date)
    totals = grouped_totals(grouped_qs) if month_entries else ''
    project_entries = month_qs.order_by().values('project__name').annotate(
        sum=Sum('hours')).order_by('-sum')
    summary = Entry.summary(user, from_date, to_date)

    show_approve = show_verify = False
    can_change = request.user.has_perm('entries.can_change_entry')
    can_approve = request.user.has_perm('entries.approve_timesheet')
    if can_change or can_approve or user == request.user:
        statuses = list(month_qs.values_list('status', flat=True))
        total_statuses = len(statuses)
        unverified_count = statuses.count(Entry.UNVERIFIED)
        verified_count = statuses.count(Entry.VERIFIED)
        approved_count = statuses.count(Entry.APPROVED)
    if can_change or user == request.user:
        show_verify = unverified_count != 0
    if can_approve:
        show_approve = all([
            verified_count + approved_count == total_statuses,
            verified_count > 0,
            total_statuses != 0,
        ])

        return render(
            request, 'user/timesheet_view.html', {
                'active_tab': active_tab or 'overview',
                'year_month_form': form,
                'from_date': from_date,
                'to_date': to_date - relativedelta(days=1),
                'show_verify': show_verify,
                'show_approve': show_approve,
                'timesheet_user': user,
                'entries': zip(month_entries, task_values),
                'grouped_totals': totals,
                'project_entries': project_entries,
                'summary': summary
            })
コード例 #57
0
def week_start(date):
    """Return the starting day of the week with the given date."""
    return utils.get_week_start(date)