Skip to content

Commit 93930ac

Browse files
authored
feat: additional sum for statistic tab (#1116)
1 parent 7397312 commit 93930ac

File tree

9 files changed

+82
-21
lines changed

9 files changed

+82
-21
lines changed

backend/timed/projects/factories.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class ProjectFactory(DjangoModelFactory):
4444

4545
name = Faker("catch_phrase")
4646
estimated_time = Faker("time_delta")
47+
total_remaining_effort = Faker("time_delta")
4748
archived = False
4849
billed = False
4950
customer_visible = False
@@ -66,6 +67,7 @@ class TaskFactory(DjangoModelFactory):
6667

6768
name = Faker("company_suffix")
6869
estimated_time = Faker("time_delta")
70+
most_recent_remaining_effort = Faker("time_delta")
6971
archived = False
7072
project = SubFactory("timed.projects.factories.ProjectFactory")
7173
cost_center = SubFactory("timed.projects.factories.CostCenterFactory")

backend/timed/reports/tests/__snapshots__/test_work_report.ambr

Lines changed: 3 additions & 3 deletions
Large diffs are not rendered by default.

backend/timed/reports/tests/test_project_statistic.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,18 @@ def test_project_statistic_list(
3737
is_employed=is_employed,
3838
is_external=False,
3939
)
40-
report = ReportFactory.create(duration=timedelta(hours=1))
40+
report = ReportFactory.create(
41+
duration=timedelta(hours=1),
42+
task__project__total_remaining_effort=timedelta(hours=3),
43+
task__project__estimated_time=timedelta(hours=7),
44+
)
4145
project = report.task.project
4246
ReportFactory.create(duration=timedelta(hours=2), task=report.task)
43-
report2 = ReportFactory.create(duration=timedelta(hours=4))
47+
report2 = ReportFactory.create(
48+
duration=timedelta(hours=4),
49+
task__project__total_remaining_effort=timedelta(hours=5),
50+
task__project__estimated_time=timedelta(hours=2),
51+
)
4452
project_2 = report2.task.project
4553
task = TaskFactory(project=report.task.project)
4654
ReportFactory.create(duration=timedelta(hours=2), task=task)
@@ -65,8 +73,8 @@ def test_project_statistic_list(
6573
"amount-offered-currency": project_2.amount_offered_currency,
6674
"amount-invoiced": str(project_2.amount_invoiced.amount),
6775
"amount-invoiced-currency": project_2.amount_invoiced_currency,
68-
"estimated-time": "00:00:00",
69-
"total-remaining-effort": "00:00:00",
76+
"estimated-time": "02:00:00",
77+
"total-remaining-effort": "05:00:00",
7078
},
7179
"relationships": {
7280
"customer": {
@@ -87,8 +95,8 @@ def test_project_statistic_list(
8795
"amount-offered-currency": project.amount_offered_currency,
8896
"amount-invoiced": str(project.amount_invoiced.amount),
8997
"amount-invoiced-currency": project.amount_invoiced_currency,
90-
"estimated-time": "00:00:00",
91-
"total-remaining-effort": "00:00:00",
98+
"estimated-time": "07:00:00",
99+
"total-remaining-effort": "03:00:00",
92100
},
93101
"relationships": {
94102
"customer": {
@@ -102,6 +110,8 @@ def test_project_statistic_list(
102110
]
103111
assert json["data"] == expected_json
104112
assert json["meta"]["total-time"] == "09:00:00"
113+
assert json["meta"]["total-estimated-time"] == "09:00:00"
114+
assert json["meta"]["total-remaining-effort"] == "08:00:00"
105115

106116

107117
@pytest.mark.parametrize(

backend/timed/reports/tests/test_task_statistic.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,16 @@ def test_task_statistic_list(
3737
is_employed=is_employed,
3838
is_external=False,
3939
)
40-
task_z = TaskFactory.create(name="Z")
41-
task_test = TaskFactory.create(name="Test")
40+
task_z = TaskFactory.create(
41+
name="Z",
42+
most_recent_remaining_effort=timedelta(hours=3),
43+
estimated_time=timedelta(hours=5),
44+
)
45+
task_test = TaskFactory.create(
46+
name="Test",
47+
most_recent_remaining_effort=timedelta(hours=7),
48+
estimated_time=timedelta(hours=2),
49+
)
4250
ReportFactory.create(duration=timedelta(hours=1), task=task_test)
4351
ReportFactory.create(duration=timedelta(hours=2), task=task_test)
4452
ReportFactory.create(duration=timedelta(hours=2), task=task_z)
@@ -63,8 +71,8 @@ def test_task_statistic_list(
6371
"attributes": {
6472
"duration": "03:00:00",
6573
"name": str(task_test.name),
66-
"most-recent-remaining-effort": None,
67-
"estimated-time": "00:00:00",
74+
"most-recent-remaining-effort": "07:00:00",
75+
"estimated-time": "02:00:00",
6876
},
6977
"relationships": {
7078
"project": {
@@ -78,8 +86,8 @@ def test_task_statistic_list(
7886
"attributes": {
7987
"duration": "02:00:00",
8088
"name": str(task_z.name),
81-
"most-recent-remaining-effort": None,
82-
"estimated-time": "00:00:00",
89+
"most-recent-remaining-effort": "03:00:00",
90+
"estimated-time": "05:00:00",
8391
},
8492
"relationships": {
8593
"project": {
@@ -90,6 +98,8 @@ def test_task_statistic_list(
9098
]
9199
assert json["data"] == expected_json
92100
assert json["meta"]["total-time"] == "05:00:00"
101+
assert json["meta"]["total-remaining-effort"] == "10:00:00"
102+
assert json["meta"]["total-estimated-time"] == "07:00:00"
93103

94104

95105
@pytest.mark.parametrize(

backend/timed/serializers.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,28 @@ class TotalTimeRootMetaMixin:
99

1010
def get_root_meta(self, _resource, many):
1111
"""Add total hours over whole result (not just page) to meta."""
12+
aggregate_list = {"total_time": Sum(self.duration_field)}
13+
if "estimated_time" in self.fields:
14+
aggregate_list["total_estimated_time"] = Sum("estimated_time")
15+
if "total_remaining_effort" in self.fields:
16+
aggregate_list["total_remaining_effort"] = Sum("total_remaining_effort")
17+
if "most_recent_remaining_effort" in self.fields:
18+
aggregate_list["total_remaining_effort"] = Sum(
19+
"most_recent_remaining_effort"
20+
)
1221
if many:
1322
view = self.context["view"]
1423
queryset = view.filter_queryset(view.get_queryset())
15-
data = queryset.aggregate(total_time=Sum(self.duration_field))
24+
data = queryset.aggregate(**aggregate_list)
1625
data["total_time"] = duration_string(data["total_time"] or timedelta(0))
26+
if "total_estimated_time" in aggregate_list:
27+
data["total_estimated_time"] = duration_string(
28+
data["total_estimated_time"] or timedelta(0)
29+
)
30+
if "total_remaining_effort" in aggregate_list:
31+
data["total_remaining_effort"] = duration_string(
32+
data["total_remaining_effort"] or timedelta(0)
33+
)
1734
return data
1835
return {}
1936

backend/timed/tracking/tests/__snapshots__/test_report.ambr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868

6969

7070
* Task
71-
[old] Brown LLC > Synchronized impactful attitude > LLC
71+
[old] Brown LLC > Synchronized impactful attitude > Group
7272
[new] Brown LLC > Synchronized impactful attitude > LLC
7373

7474
* Comment

backend/timed/tracking/tests/test_report.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1985,7 +1985,7 @@ def test_report_create_remaining_effort(
19851985
assert task.most_recent_remaining_effort == timedelta(hours=1)
19861986
assert task.project.total_remaining_effort == timedelta(hours=1)
19871987
else:
1988-
assert task.most_recent_remaining_effort is None
1988+
assert task.most_recent_remaining_effort == timedelta(0)
19891989
assert task.project.total_remaining_effort == timedelta(0)
19901990

19911991

frontend/app/components/statistic-list.hbs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,17 @@
9797
Total:
9898
{{else if (eq column.title "Duration")}}
9999
<span class="total">{{humanize-duration
100-
this.total
100+
this.totalDuration
101+
false
102+
}}</span>
103+
{{else if (eq column.title "Estimated")}}
104+
<span class="total">{{humanize-duration
105+
this.totalEstimatedTime
106+
false
107+
}}</span>
108+
{{else if (eq column.title "Remaining Effort")}}
109+
<span class="total">{{humanize-duration
110+
this.totalRemainingEfforts
101111
false
102112
}}</span>
103113
{{/if}}

frontend/app/components/statistic-list.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const COLUMN_MAP = {
4949
{ title: "Estimated", path: "estimatedTime", layout: DURATION_LAYOUT },
5050
{ title: "Duration", path: "duration", layout: DURATION_LAYOUT },
5151
{
52-
title: "Remaining effort",
52+
title: "Remaining Effort",
5353
path: "mostRecentRemainingEffort",
5454
layout: DURATION_LAYOUT,
5555
},
@@ -91,10 +91,22 @@ export default class StatisticList extends Component {
9191
return Math.max(maxEstimated, maxDurationWithRemainingEffort);
9292
}
9393

94-
get total() {
94+
get totalDuration() {
9595
return parseDjangoDuration(this.value.meta?.["total-time"] ?? null);
9696
}
9797

98+
get totalEstimatedTime() {
99+
return parseDjangoDuration(
100+
this.value.meta?.["total-estimated-time"] ?? null,
101+
);
102+
}
103+
104+
get totalRemainingEfforts() {
105+
return parseDjangoDuration(
106+
this.value.meta?.["total-remaining-effort"] ?? null,
107+
);
108+
}
109+
98110
get columns() {
99111
return get(COLUMN_MAP, this.args.type).map((col) => ({
100112
...col,

0 commit comments

Comments
 (0)