Skip to content
This repository was archived by the owner on Oct 3, 2022. It is now read-only.

Commit 8a5a805

Browse files
authored
Merge pull request #43 from BinderDyn/dashboard-should-display-average-working-hours-per-day
Dashboard should display average working hours per day
2 parents 05b48b5 + 84e8c25 commit 8a5a805

File tree

12 files changed

+319
-29
lines changed

12 files changed

+319
-29
lines changed
0 Bytes
Binary file not shown.

.vs/TakeMyTime.NETCore/v16/.suo

9.5 KB
Binary file not shown.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netcoreapp3.1</TargetFramework>
5+
6+
<IsPackable>false</IsPackable>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
11+
<PackageReference Include="MSTest.TestAdapter" Version="2.0.0" />
12+
<PackageReference Include="MSTest.TestFramework" Version="2.0.0" />
13+
<PackageReference Include="coverlet.collector" Version="1.0.1" />
14+
</ItemGroup>
15+
16+
<ItemGroup>
17+
<ProjectReference Include="..\TakeMyTime.DAL\TakeMyTime.DAL.csproj" />
18+
<ProjectReference Include="..\TakeMyTime.Models\TakeMyTime.Models.csproj" />
19+
</ItemGroup>
20+
21+
</Project>
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2+
using System;
3+
using System.Linq;
4+
using TakeMyTime.Models.Models;
5+
6+
namespace TakeMyTime.DAL.Tests
7+
{
8+
[TestClass]
9+
public class WeekdayProductivityManagerTests
10+
{
11+
private WeekdayProductivityManager manager;
12+
13+
[TestInitialize]
14+
public void Initialize()
15+
{
16+
this.manager = new WeekdayProductivityManager();
17+
}
18+
19+
private Entry[] GenerateEntries()
20+
{
21+
return new Entry[]
22+
{
23+
new Entry
24+
{
25+
DurationAsTicks = TimeSpan.FromHours(1).Ticks,
26+
Started = new DateTime(2020, 3, 16)
27+
},
28+
new Entry
29+
{
30+
DurationAsTicks = TimeSpan.FromHours(1).Ticks,
31+
Started = new DateTime(2020, 3, 17)
32+
},
33+
new Entry
34+
{
35+
DurationAsTicks = TimeSpan.FromHours(1).Ticks,
36+
Started = new DateTime(2020, 3, 10)
37+
},
38+
new Entry
39+
{
40+
DurationAsTicks = TimeSpan.FromHours(1).Ticks,
41+
Started = new DateTime(2020, 3, 18)
42+
},
43+
new Entry
44+
{
45+
DurationAsTicks = TimeSpan.FromHours(1).Ticks,
46+
Started = new DateTime(2020, 3, 19)
47+
},
48+
new Entry
49+
{
50+
DurationAsTicks = TimeSpan.FromHours(1).Ticks,
51+
Started = new DateTime(2020, 3, 20)
52+
}
53+
};
54+
}
55+
56+
[TestMethod]
57+
public void TestDayWithoutEntries()
58+
{
59+
// ARRANGE
60+
var entries = this.GenerateEntries();
61+
62+
// ACT
63+
foreach (var entry in entries)
64+
{
65+
this.manager.ProcessEntry(entry);
66+
}
67+
var result = this.manager.GetResults();
68+
69+
// ASSERT
70+
double expectedTotalResultMonday = 0;
71+
double expectedAverageHoursMonday = 0;
72+
double expectedShareMonday = 0;
73+
74+
Assert.AreNotEqual(expectedTotalResultMonday, result.Single(r => r.Day == DayOfWeek.Monday).TotalHours);
75+
Assert.AreNotEqual(expectedAverageHoursMonday, result.Single(r => r.Day == DayOfWeek.Monday).AverageHours);
76+
Assert.AreNotEqual(expectedShareMonday, result.Single(r => r.Day == DayOfWeek.Monday).Value);
77+
}
78+
79+
[TestMethod]
80+
public void TestDayWithEntries()
81+
{
82+
// ARRANGE
83+
var entries = this.GenerateEntries();
84+
85+
// ACT
86+
foreach (var entry in entries)
87+
{
88+
this.manager.ProcessEntry(entry);
89+
}
90+
var result = this.manager.GetResults();
91+
92+
// ASSERT
93+
double expectedTotalResultTuesday = 2;
94+
double expectedAverageHoursTuesday = 1;
95+
double expectedShareTuesday = 33; // 100 / 6 = 16,7 => 16,7 x 2 ~ 33
96+
double expectedShareWednesday = 17;
97+
98+
Assert.AreEqual(expectedTotalResultTuesday, result.Single(r => r.Day == DayOfWeek.Tuesday).TotalHours);
99+
Assert.AreEqual(expectedAverageHoursTuesday, result.Single(r => r.Day == DayOfWeek.Tuesday).AverageHours);
100+
double roundedResultOfTuesdayShares = result.Where(r => r.Day == DayOfWeek.Tuesday).Sum(d => Math.Round(d.Value * 100));
101+
Assert.AreEqual(expectedShareTuesday, roundedResultOfTuesdayShares);
102+
double roundedResultOfWednesdayShares = Math.Round(result.Single(r => r.Day == DayOfWeek.Wednesday).Value * 100, 1);
103+
Assert.AreEqual(expectedShareWednesday, roundedResultOfWednesdayShares);
104+
}
105+
}
106+
}

TakeMyTime.DAL/Repositories/StatisticsRepository.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ public IEnumerable<ProductivityViewModel> GetProjectProductiveDays(int project_i
9292
var entries = this.context.Entries
9393
.Where(e => e.Project_Id == project_id);
9494

95-
foreach (var entry in entries)
95+
foreach (var entry in entries.Where(e => e.DurationAsTicks.HasValue))
9696
{
9797
results.Add(new ProductivityViewModel { X = entry.Date, Y = new TimeSpan(entry.DurationAsTicks.Value) });
9898
}
@@ -106,7 +106,7 @@ public IEnumerable<MostProductiveWeekDaysViewModel> GetMostProductiveDays()
106106
.Include(e => e.Project)
107107
.Where(e => e.Project.ProjectStatus == EnumDefinition.ProjectStatus.Active)
108108
.ToList();
109-
var weekdayManager = new WeekdayProductivityManager(entries.Count());
109+
var weekdayManager = new WeekdayProductivityManager();
110110

111111
foreach (var entry in entries)
112112
{

TakeMyTime.DAL/WeekdayProductivityManager.cs

Lines changed: 80 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,107 +8,161 @@ namespace TakeMyTime.DAL
88
{
99
public class WeekdayProductivityManager
1010
{
11-
public WeekdayProductivityManager(int totalEntryCount)
11+
public WeekdayProductivityManager()
1212
{
13-
this.TotalEntryCount = totalEntryCount;
1413
}
1514

1615
public void ProcessEntry(Entry entry)
1716
{
18-
if(CanProcessEntries)
17+
var durationAsHours = entry.DurationAsTicks.HasValue ? TimeSpan.FromTicks(entry.DurationAsTicks.Value).TotalHours : 0;
18+
if(durationAsHours > 0)
1919
{
20+
TotalWorkingHours += durationAsHours;
2021
var date = entry.Started.HasValue ? entry.Started.Value.DayOfWeek : entry.Date.DayOfWeek;
2122
switch (date)
2223
{
2324
case DayOfWeek.Monday:
25+
MondayTotalWorkingHours += durationAsHours;
2426
MondayEntryCount++;
25-
this.MondayValueShare = Math.Round((double)MondayEntryCount / (double)TotalEntryCount, 2);
27+
this.MondayAverageWorkingHours = Math.Round(MondayTotalWorkingHours / MondayEntryCount, 2);
28+
2629
break;
2730
case DayOfWeek.Tuesday:
31+
TuesdayTotalWorkingHours += durationAsHours;
2832
TuesdayEntryCount++;
29-
this.TuesdayValueShare = Math.Round((double)TuesdayEntryCount / (double)TotalEntryCount, 2);
33+
this.TuesdayAverageWorkingHours = Math.Round(TuesdayTotalWorkingHours / TuesdayEntryCount, 2);
34+
3035
break;
3136
case DayOfWeek.Wednesday:
37+
WednesdayTotalWorkingHours += durationAsHours;
3238
WednesdayEntryCount++;
33-
this.WednesdayValueShare = Math.Round((double)WednesdayEntryCount / (double)TotalEntryCount, 2);
39+
this.WednesdayAverageWorkingHours = Math.Round(WednesdayTotalWorkingHours / WednesdayEntryCount, 2);
40+
3441
break;
3542
case DayOfWeek.Thursday:
43+
ThursdayTotalWorkingHours += durationAsHours;
3644
ThursdayEntryCount++;
37-
this.ThursdayValueShare = Math.Round((double)ThursdayEntryCount / (double)TotalEntryCount, 2);
45+
this.ThursdayAverageWorkingHours = Math.Round(ThursdayTotalWorkingHours / ThursdayEntryCount, 2);
46+
3847
break;
3948
case DayOfWeek.Friday:
49+
FridayTotalWorkingHours += durationAsHours;
4050
FridayEntryCount++;
41-
this.FridayValueShare = Math.Round((double)FridayEntryCount / (double)TotalEntryCount, 2);
51+
this.FridayAverageWorkingHours = Math.Round(FridayTotalWorkingHours / FridayEntryCount, 2);
52+
4253
break;
4354
case DayOfWeek.Saturday:
55+
SaturdayTotalWorkingHours += durationAsHours;
4456
SaturdayEntryCount++;
45-
this.SaturdayValueShare = Math.Round((double)SaturdayEntryCount / (double)TotalEntryCount, 2);
57+
this.SaturdayAverageWorkingHours = Math.Round(SaturdayTotalWorkingHours / SaturdayEntryCount, 2);
58+
4659
break;
4760
case DayOfWeek.Sunday:
61+
SundayTotalWorkingHours += durationAsHours;
4862
SundayEntryCount++;
49-
this.SundayValueShare = Math.Round((double)SundayEntryCount / (double)TotalEntryCount, 2);
63+
this.SundayAverageWorkingHours = Math.Round(SundayTotalWorkingHours / SundayEntryCount, 2);
5064
break;
5165
};
66+
67+
CalculateShares();
5268
}
5369
}
5470

71+
private void CalculateShares()
72+
{
73+
this.MondayValueShare = Math.Round(MondayTotalWorkingHours / TotalWorkingHours, 2);
74+
this.TuesdayValueShare = Math.Round(TuesdayTotalWorkingHours / TotalWorkingHours, 2);
75+
this.WednesdayValueShare = Math.Round(WednesdayTotalWorkingHours / TotalWorkingHours, 2);
76+
this.ThursdayValueShare = Math.Round(ThursdayTotalWorkingHours / TotalWorkingHours, 2);
77+
this.FridayValueShare = Math.Round(FridayTotalWorkingHours / TotalWorkingHours, 2);
78+
this.SaturdayValueShare = Math.Round(SaturdayTotalWorkingHours / TotalWorkingHours, 2);
79+
this.SundayValueShare = Math.Round(SundayTotalWorkingHours / TotalWorkingHours, 2);
80+
}
81+
5582
public IEnumerable<MostProductiveWeekDaysViewModel> GetResults()
5683
{
5784
return new List<MostProductiveWeekDaysViewModel>
5885
{
5986
new MostProductiveWeekDaysViewModel
6087
{
6188
Day = DayOfWeek.Monday,
62-
Value = MondayValueShare
89+
Value = MondayValueShare,
90+
AverageHours = MondayAverageWorkingHours,
91+
TotalHours = MondayTotalWorkingHours
6392
},
6493
new MostProductiveWeekDaysViewModel
6594
{
6695
Day = DayOfWeek.Tuesday,
67-
Value = TuesdayValueShare
96+
Value = TuesdayValueShare,
97+
AverageHours = TuesdayAverageWorkingHours,
98+
TotalHours = TuesdayTotalWorkingHours
6899
},
69100
new MostProductiveWeekDaysViewModel
70101
{
71102
Day = DayOfWeek.Wednesday,
72-
Value = WednesdayValueShare
103+
Value = WednesdayValueShare,
104+
AverageHours = WednesdayAverageWorkingHours,
105+
TotalHours = WednesdayTotalWorkingHours
73106
},
74107
new MostProductiveWeekDaysViewModel
75108
{
76109
Day = DayOfWeek.Thursday,
77-
Value = ThursdayValueShare
110+
Value = ThursdayValueShare,
111+
AverageHours = ThursdayAverageWorkingHours,
112+
TotalHours = ThursdayTotalWorkingHours
78113
},
79114
new MostProductiveWeekDaysViewModel
80115
{
81116
Day = DayOfWeek.Friday,
82-
Value = FridayValueShare
117+
Value = FridayValueShare,
118+
AverageHours = FridayAverageWorkingHours,
119+
TotalHours = FridayTotalWorkingHours
83120
},
84121
new MostProductiveWeekDaysViewModel
85122
{
86123
Day = DayOfWeek.Saturday,
87-
Value = SaturdayValueShare
124+
Value = SaturdayValueShare,
125+
AverageHours = SaturdayAverageWorkingHours,
126+
TotalHours = SaturdayTotalWorkingHours
88127
},
89128
new MostProductiveWeekDaysViewModel
90129
{
91130
Day = DayOfWeek.Sunday,
92-
Value = SundayValueShare
131+
Value = SundayValueShare,
132+
AverageHours = SundayAverageWorkingHours,
133+
TotalHours = SundayTotalWorkingHours
93134
},
94135
};
95136
}
96137

97-
public int TotalEntryCount { get; private set; }
98-
public int MondayEntryCount { get; private set; }
138+
public double TotalWorkingHours { get; private set; }
139+
public double MondayTotalWorkingHours { get; private set; }
99140
public double MondayValueShare { get; private set; }
100-
public int TuesdayEntryCount { get; private set; }
141+
public double MondayAverageWorkingHours { get; private set; }
142+
public double MondayEntryCount { get; set; }
143+
public double TuesdayTotalWorkingHours { get; private set; }
101144
public double TuesdayValueShare { get; private set; }
102-
public int WednesdayEntryCount { get; private set; }
145+
public double TuesdayAverageWorkingHours { get; private set; }
146+
public double TuesdayEntryCount { get; set; }
147+
public double WednesdayTotalWorkingHours { get; private set; }
103148
public double WednesdayValueShare { get; private set; }
104-
public int ThursdayEntryCount { get; private set; }
149+
public double WednesdayAverageWorkingHours { get; private set; }
150+
public double WednesdayEntryCount { get; set; }
151+
public double ThursdayTotalWorkingHours { get; private set; }
105152
public double ThursdayValueShare { get; private set; }
106-
public int FridayEntryCount { get; private set; }
153+
public double ThursdayAverageWorkingHours { get; private set; }
154+
public double ThursdayEntryCount { get; set; }
155+
public double FridayTotalWorkingHours { get; private set; }
107156
public double FridayValueShare { get; private set; }
108-
public int SaturdayEntryCount { get; private set; }
157+
public double FridayAverageWorkingHours { get; private set; }
158+
public double FridayEntryCount { get; set; }
159+
public double SaturdayTotalWorkingHours { get; private set; }
109160
public double SaturdayValueShare { get; private set; }
110-
public int SundayEntryCount { get; private set; }
161+
public double SaturdayAverageWorkingHours { get; private set; }
162+
public double SaturdayEntryCount { get; set; }
163+
public double SundayTotalWorkingHours { get; private set; }
111164
public double SundayValueShare { get; private set; }
112-
public bool CanProcessEntries { get => this.TotalEntryCount > 0; }
165+
public double SundayAverageWorkingHours { get; private set; }
166+
public double SundayEntryCount { get; set; }
113167
}
114168
}

TakeMyTime.Models/Models/MostProductiveWeekDaysViewModel.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,7 @@ public class MostProductiveWeekDaysViewModel
88
{
99
public DayOfWeek Day { get; set; }
1010
public double Value { get; set; }
11+
public double AverageHours { get; set; }
12+
public double TotalHours { get; set; }
1113
}
1214
}

TakeMyTime.NETCore.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TakeMyTime.BLL.Tests", "Tak
1919
EndProject
2020
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TakeMyTime.Tests.Common", "TakeMyTime.Tests.Common\TakeMyTime.Tests.Common.csproj", "{D7D6ABCF-39A8-4C17-BF63-F29F11F496BC}"
2121
EndProject
22+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakeMyTime.DAL.Tests", "TakeMyTime.DAL.Tests\TakeMyTime.DAL.Tests.csproj", "{E778405A-42E7-4F78-BE0F-EB025BDDD2CB}"
23+
EndProject
2224
Global
2325
GlobalSection(SolutionConfigurationPlatforms) = preSolution
2426
Debug|Any CPU = Debug|Any CPU
@@ -57,6 +59,10 @@ Global
5759
{D7D6ABCF-39A8-4C17-BF63-F29F11F496BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
5860
{D7D6ABCF-39A8-4C17-BF63-F29F11F496BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
5961
{D7D6ABCF-39A8-4C17-BF63-F29F11F496BC}.Release|Any CPU.Build.0 = Release|Any CPU
62+
{E778405A-42E7-4F78-BE0F-EB025BDDD2CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
63+
{E778405A-42E7-4F78-BE0F-EB025BDDD2CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
64+
{E778405A-42E7-4F78-BE0F-EB025BDDD2CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
65+
{E778405A-42E7-4F78-BE0F-EB025BDDD2CB}.Release|Any CPU.Build.0 = Release|Any CPU
6066
EndGlobalSection
6167
GlobalSection(SolutionProperties) = preSolution
6268
HideSolutionNode = FALSE

TakeMyTime.WPF/Statistics/Dashboard.xaml.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,9 @@ private string[] ResolveWeekdayNames(IEnumerable<MostProductiveWeekDaysViewModel
140140
var labels = new List<string>();
141141
foreach (var vm in viewModels)
142142
{
143-
labels.Add(ResourceStringManager.GetResourceByKey(vm.Day.ToString()));
143+
string formattedAvgHours = string.Format("{0}(Ø {1:0.00}h){2}(Total: {3:0.00}h)", System.Environment.NewLine,
144+
vm.AverageHours, System.Environment.NewLine, vm.TotalHours);
145+
labels.Add(ResourceStringManager.GetResourceByKey(vm.Day.ToString()) + formattedAvgHours);
144146
}
145147

146148
return labels.ToArray();

0 commit comments

Comments
 (0)