From 06b6a73aa6f376a4cdc260fcdaf064bd23194b87 Mon Sep 17 00:00:00 2001 From: Rob Lineberger Date: Wed, 23 Dec 2015 17:21:44 -0500 Subject: [PATCH 1/2] fixed lack of project activities when activity group absent --- timepiece/entries/lookups.py | 3 ++- timepiece/entries/tests/test_dashboard.py | 13 ++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/timepiece/entries/lookups.py b/timepiece/entries/lookups.py index c4b267ae4..41b3472fa 100644 --- a/timepiece/entries/lookups.py +++ b/timepiece/entries/lookups.py @@ -13,7 +13,8 @@ def get_query(self, request, term): results = super(ActivityLookup, self).get_query(request, term) project = Project.objects.get(pk=request.GET.get('project', '')) if project: - results = project.activity_group.activities.all() + if project.activity_group: + return project.activity_group.activities.all() return results def get_item_label(self, item): diff --git a/timepiece/entries/tests/test_dashboard.py b/timepiece/entries/tests/test_dashboard.py index fa973de3a..20a11db0a 100644 --- a/timepiece/entries/tests/test_dashboard.py +++ b/timepiece/entries/tests/test_dashboard.py @@ -147,7 +147,7 @@ def test_no_other_active_entries(self): self.assertEqual(len(response.context['others_active_entries']), 0) def test_clock_in_form_activity_lookup(self): - """Create an ActivityGroup that includes the Activity, and accosiate it with the project. + """Create an ActivityGroup that includes the Activity, and associate it with the project. Add a second Activity that is not included. Ensure that the ActivityLookup disallows the second Activity. """ factory = RequestFactory() @@ -163,6 +163,17 @@ def test_clock_in_form_activity_lookup(self): self.assertEqual(1, len(data)) self.assertEqual(self.activity.pk, data[0]['id']) + def test_clock_in_form_activity_without_project_activity_group(self): + """Ensure that the ActivityLookup provides all Activities if Project does not have an + activity group. """ + factory = RequestFactory() + lookup = ActivityLookup() + factories.Activity() + request = factory.get("/entry/clock_in/", {'project': self.project.pk}) + response = lookup.results(request) + data = json.loads(response.content.decode("utf-8"))['data'] + self.assertEqual(2, len(data)) + class ProcessProgressTestCase(TestCase): """Tests for process_progress.""" From e2b3dc64bf1f8bcd4dedf32bafee551bef77bb4f Mon Sep 17 00:00:00 2001 From: Rob Lineberger Date: Mon, 28 Dec 2015 10:49:51 -0500 Subject: [PATCH 2/2] added tabbed interface to contract list to view pending and completed contracts --- timepiece/contracts/views.py | 4 + .../templates/timepiece/contract/list.html | 121 ++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/timepiece/contracts/views.py b/timepiece/contracts/views.py index 6dd4e3858..a944c098c 100644 --- a/timepiece/contracts/views.py +++ b/timepiece/contracts/views.py @@ -53,6 +53,10 @@ def get_context_data(self, *args, **kwargs): [0.0] + [c.fraction_hours for c in self.queryset.all()]) kwargs['max_schedule_fraction'] = max( [0.0] + [c.fraction_schedule for c in self.queryset.all()]) + kwargs['projects_pending'] = ProjectContract.objects.filter( + status=ProjectContract.STATUS_UPCOMING).order_by('name') + kwargs['projects_complete'] = ProjectContract.objects.filter( + status=ProjectContract.STATUS_COMPLETE).order_by('name') return super(ContractList, self).get_context_data(*args, **kwargs) diff --git a/timepiece/templates/timepiece/contract/list.html b/timepiece/templates/timepiece/contract/list.html index a6e53aee0..5a40f244c 100644 --- a/timepiece/templates/timepiece/contract/list.html +++ b/timepiece/templates/timepiece/contract/list.html @@ -17,6 +17,14 @@ {% block content %}
+ + +
+

Current Contracts

@@ -71,5 +79,118 @@

Current Contracts

+
+

Pending Contracts

+ + + + + + + + + + + + + + + + + + {% for contract in projects_pending %} + {% if contract.end_date < today %} + + {% elif contract.end_date < warning_date %} + + {% else %} + + {% endif %} + + + + + + + + + + {% endfor %} + +
NameStart DateEnd DateContract HoursHours WorkedProgress: days elapsed/hours workedContract Type
BillableNon-billable
{{ contract.name }}{{ contract.start_date|date:'M j, Y' }} + {{ contract.end_date|date:'M j, Y' }} + {% if contract.end_date >= today and contract.end_date < warning_date %} + + {% endif %} + + {{ contract.contracted_hours|floatformat:2 }} + {% if contract.pending_hours %} + (+{{ contract.pending_hours|floatformat:2 }}) + {% endif %} + {{ contract.hours_worked|floatformat:2 }} ({% widthratio contract.hours_worked contract.contracted_hours 100 %}%){{ contract.nonbillable_hours_worked|floatformat:2 }} +
+
+
{{ contract.get_type_display }}
+
+
+

Completed Contracts

+ + + + + + + + + + + + + + + + + + {% for contract in projects_complete %} + {% if contract.end_date < today %} + + {% elif contract.end_date < warning_date %} + + {% else %} + + {% endif %} + + + + + + + + + + {% endfor %} + +
NameStart DateEnd DateContract HoursHours WorkedProgress: days elapsed/hours workedContract Type
BillableNon-billable
{{ contract.name }}{{ contract.start_date|date:'M j, Y' }} + {{ contract.end_date|date:'M j, Y' }} + {% if contract.end_date >= today and contract.end_date < warning_date %} + + {% endif %} + + {{ contract.contracted_hours|floatformat:2 }} + {% if contract.pending_hours %} + (+{{ contract.pending_hours|floatformat:2 }}) + {% endif %} + {{ contract.hours_worked|floatformat:2 }} ({% widthratio contract.hours_worked contract.contracted_hours 100 %}%){{ contract.nonbillable_hours_worked|floatformat:2 }} +
+
+
{{ contract.get_type_display }}
+
+
+ +
{% endblock content %}