From cebdf2edc86ac92175494479deac31a5e4b26f74 Mon Sep 17 00:00:00 2001 From: Ashwin Thyagarajan Date: Mon, 21 Aug 2023 20:07:13 +0530 Subject: [PATCH 1/3] Moves calculations related to the monthly page to a new service --- subtrack.MAUI/MauiProgram.cs | 3 +- subtrack.MAUI/Pages/Monthly.razor | 51 +++++++---------- .../Abstractions/IMonthlyPageCalculator.cs | 10 ++++ .../Abstractions/ISubscriptionsCalculator.cs | 11 +--- .../Services/MonthlyPageCalculator.cs | 45 +++++++++++++++ .../Services/SubscriptionsCalculator.cs | 27 --------- .../GetSubscriptionListByMonthTests.cs | 55 +++++++++++-------- 7 files changed, 110 insertions(+), 92 deletions(-) create mode 100644 subtrack.MAUI/Services/Abstractions/IMonthlyPageCalculator.cs create mode 100644 subtrack.MAUI/Services/MonthlyPageCalculator.cs diff --git a/subtrack.MAUI/MauiProgram.cs b/subtrack.MAUI/MauiProgram.cs index b6b0e88..adfdc69 100644 --- a/subtrack.MAUI/MauiProgram.cs +++ b/subtrack.MAUI/MauiProgram.cs @@ -48,7 +48,8 @@ public static IServiceCollection AddSubtrackServices(this IServiceCollection ser .AddScoped() .AddScoped() .AddScoped() - .AddScoped(); + .AddScoped() + .AddScoped(); } private static void SeedDb(SubtrackDbContext dbContext) diff --git a/subtrack.MAUI/Pages/Monthly.razor b/subtrack.MAUI/Pages/Monthly.razor index 4169c21..ffed1f6 100644 --- a/subtrack.MAUI/Pages/Monthly.razor +++ b/subtrack.MAUI/Pages/Monthly.razor @@ -1,45 +1,32 @@ @page "/monthly" -@inject subtrack.MAUI.Services.Abstractions.ISubscriptionService SubscriptionService -@inject subtrack.MAUI.Services.Abstractions.ISubscriptionsCalculator SubscriptionCalculator +@inject subtrack.MAUI.Services.Abstractions.IDateProvider DateProvider +@inject subtrack.MAUI.Services.Abstractions.IMonthlyPageCalculator MonthlyPageCalculator -@foreach (var subMonth in _currentYearSubscriptionMonths) +@foreach (var subs in monthlySubscriptions) { - -} - -
@(_currentMonthDate.AddYears(1).Year)
- -@foreach (var subMonth in _nextYearSubscriptionMonths) -{ - -} - -
@(_currentMonthDate.AddYears(2).Year)
- -@foreach (var subMonth in _nextYearSubscriptionMonths) -{ - + var displayYear = subs.Key != currentYear; + @if (displayYear) + { +
@(subs.Key)
+ } + @foreach(var subMonth in subs) + { + + } } @code { - IEnumerable _subscriptions = new List(); - DateTime _currentMonthDate = DateTime.Now; - - IEnumerable _currentYearSubscriptionMonths = null!; - IEnumerable _nextYearSubscriptionMonths = null!; - IEnumerable _twoYearsForwardSubscriptionMonths = null!; - + int currentYear; + IEnumerable> monthlySubscriptions = default!; protected override async Task OnInitializedAsync() { - _subscriptions = await SubscriptionService.GetAllAsync(); - - var twoYearsForwardDate = _currentMonthDate.AddYears(2); - var paymentsTwoYearsForward = SubscriptionCalculator.GetMonthlySubscriptionLists(_subscriptions, _currentMonthDate.FirstDayOfMonthDate(), twoYearsForwardDate.LastDayOfMonthDate()); + var fromDate = DateProvider.Today; + currentYear = fromDate.Year; + var futureYearsToDisplay = 2; - _currentYearSubscriptionMonths = paymentsTwoYearsForward.Where(m => m.MonthDate.Year == _currentMonthDate.Year).ToList(); - _nextYearSubscriptionMonths = paymentsTwoYearsForward.Where(m => m.MonthDate.Year == _currentMonthDate.AddYears(1).Year).ToList(); - _twoYearsForwardSubscriptionMonths = paymentsTwoYearsForward.Where(m => m.MonthDate.Year == _currentMonthDate.AddYears(2).Year).ToList(); + var toDate = fromDate.AddYears(futureYearsToDisplay); + monthlySubscriptions = await MonthlyPageCalculator.GetMonthlySubscriptionLists(fromDate.FirstDayOfMonthDate(), toDate.LastDayOfMonthDate()); } } \ No newline at end of file diff --git a/subtrack.MAUI/Services/Abstractions/IMonthlyPageCalculator.cs b/subtrack.MAUI/Services/Abstractions/IMonthlyPageCalculator.cs new file mode 100644 index 0000000..17c8ce8 --- /dev/null +++ b/subtrack.MAUI/Services/Abstractions/IMonthlyPageCalculator.cs @@ -0,0 +1,10 @@ +using subtrack.DAL.Entities; +using subtrack.MAUI.Responses; + +namespace subtrack.MAUI.Services.Abstractions +{ + public interface IMonthlyPageCalculator + { + Task>> GetMonthlySubscriptionLists(DateTime fromIncludedDate, DateTime toIncludedDate); + } +} diff --git a/subtrack.MAUI/Services/Abstractions/ISubscriptionsCalculator.cs b/subtrack.MAUI/Services/Abstractions/ISubscriptionsCalculator.cs index 8d6ee9d..a93985c 100644 --- a/subtrack.MAUI/Services/Abstractions/ISubscriptionsCalculator.cs +++ b/subtrack.MAUI/Services/Abstractions/ISubscriptionsCalculator.cs @@ -1,22 +1,17 @@ using subtrack.DAL.Entities; -using subtrack.MAUI.Responses; namespace subtrack.MAUI.Services.Abstractions { public interface ISubscriptionsCalculator { int GetDueDays(Subscription subscription); + decimal GetTotalCost(IEnumerable subscriptions); + decimal GetYearlyCost(Subscription subscription); - /// - /// Gets lists of due subs for each month up until-including a specific month date - /// - /// - /// - /// Subscriptions due for a specific Month Date - IEnumerable GetMonthlySubscriptionLists(IEnumerable subscriptions, DateTime fromIncludedDate, DateTime toIncludedDate); DateTime GetNextPaymentDate(Subscription subscription); + (bool IsDue, DateTime NextPaymentDate) IsDue(Subscription subscription); decimal GetAverageMonthlyCost(IEnumerable subscriptions); diff --git a/subtrack.MAUI/Services/MonthlyPageCalculator.cs b/subtrack.MAUI/Services/MonthlyPageCalculator.cs new file mode 100644 index 0000000..a55d2b9 --- /dev/null +++ b/subtrack.MAUI/Services/MonthlyPageCalculator.cs @@ -0,0 +1,45 @@ +using subtrack.DAL.Entities; +using subtrack.MAUI.Responses; +using subtrack.MAUI.Services.Abstractions; + +namespace subtrack.MAUI.Services +{ + internal class MonthlyPageCalculator : IMonthlyPageCalculator + { + private readonly ISubscriptionsCalculator subscriptionsCalculator; + private readonly ISubscriptionService subscriptionService; + + public MonthlyPageCalculator(ISubscriptionsCalculator subscriptionsCalculator, ISubscriptionService subscriptionService) + { + this.subscriptionsCalculator = subscriptionsCalculator; + this.subscriptionService = subscriptionService; + } + + private IEnumerable GetPaymentsUntilMonth(Subscription subscription, DateTime fromIncludedDate, DateTime toIncludedDate) + { + subscription.LastPayment = subscriptionsCalculator.GetNextPaymentDate(subscription); + + while (subscription.LastPayment.Date >= fromIncludedDate.Date + && subscription.LastPayment.Date <= toIncludedDate.Date) + { + yield return (Subscription)subscription.Clone(); + subscription.LastPayment = subscriptionsCalculator.GetNextPaymentDate(subscription); + } + } + + public async Task>> GetMonthlySubscriptionLists(DateTime fromIncludedMonthDate, DateTime finalIncludedMonthDate) + { + var subscriptions = await subscriptionService.GetAllAsync(); + return subscriptions + .SelectMany(s => GetPaymentsUntilMonth(s, fromIncludedMonthDate, finalIncludedMonthDate)) + .GroupBy(s => (s.LastPayment.Year, s.LastPayment.Month)) + .Select(g => + new SubscriptionsMonthResponse + { + MonthDate = new DateTime(g.Key.Year, g.Key.Month, 1), + Subscriptions = g.OrderBy(s => s.LastPayment).ToList(), + Cost = subscriptionsCalculator.GetTotalCost(g) + }).GroupBy(r => r.MonthDate.Year); + } + } +} diff --git a/subtrack.MAUI/Services/SubscriptionsCalculator.cs b/subtrack.MAUI/Services/SubscriptionsCalculator.cs index 97034c1..3bc8961 100644 --- a/subtrack.MAUI/Services/SubscriptionsCalculator.cs +++ b/subtrack.MAUI/Services/SubscriptionsCalculator.cs @@ -1,5 +1,4 @@ using subtrack.DAL.Entities; -using subtrack.MAUI.Responses; using subtrack.MAUI.Services.Abstractions; using subtrack.MAUI.Utilities; using System.Globalization; @@ -50,32 +49,6 @@ public decimal GetYearlyCost(Subscription subscription) return subscription.Cost * yearlyPaymentsCount; } - private IEnumerable GetPaymentsUntilMonth(Subscription subscription, DateTime fromIncludedDate, DateTime toIncludedDate) - { - subscription.LastPayment = GetNextPaymentDate(subscription); - - while (subscription.LastPayment.Date >= fromIncludedDate.Date - && subscription.LastPayment.Date <= toIncludedDate.Date) - { - yield return (Subscription)subscription.Clone(); - subscription.LastPayment = GetNextPaymentDate(subscription); - } - } - - public IEnumerable GetMonthlySubscriptionLists(IEnumerable subscriptions, DateTime fromIncludedMonthDate, DateTime finalIncludedMonthDate) - { - return subscriptions - .SelectMany(s => GetPaymentsUntilMonth(s, fromIncludedMonthDate, finalIncludedMonthDate)) - .GroupBy(s => (s.LastPayment.Year, s.LastPayment.Month)) - .Select(g => - new SubscriptionsMonthResponse - { - MonthDate = new DateTime(g.Key.Year, g.Key.Month, 1), - Subscriptions = g.OrderBy(s => s.LastPayment).ToList(), - Cost = GetTotalCost(g) - }).ToList(); - } - public DateTime GetNextPaymentDate(Subscription subscription) { int startDay = subscription.FirstPaymentDay; diff --git a/subtrack.Tests/SubscriptionCalculatorTests/GetSubscriptionListByMonthTests.cs b/subtrack.Tests/SubscriptionCalculatorTests/GetSubscriptionListByMonthTests.cs index 22a78f6..933a38d 100644 --- a/subtrack.Tests/SubscriptionCalculatorTests/GetSubscriptionListByMonthTests.cs +++ b/subtrack.Tests/SubscriptionCalculatorTests/GetSubscriptionListByMonthTests.cs @@ -5,8 +5,8 @@ namespace subtrack.Tests.SubscriptionCalculatorTests { public class GetSubscriptionListByMonthTests { - private readonly ISubscriptionsCalculator _sut; - private readonly IDateProvider _dateTimeProvider = Substitute.For(); + private readonly IMonthlyPageCalculator _sut; + private readonly ISubscriptionService _subscriptionService = Substitute.For(); private readonly int _numberOfMonths = 3; private readonly DateTime _fromIncludedDate = new(2023, 4, 1), _toIncludedDate; @@ -14,98 +14,105 @@ public class GetSubscriptionListByMonthTests public GetSubscriptionListByMonthTests() { _toIncludedDate = _fromIncludedDate.AddMonths(_numberOfMonths - 1); - _sut = new SubscriptionsCalculator(_dateTimeProvider); - _dateTimeProvider.Today.Returns(_fromIncludedDate); + var dateProvider = Substitute.For(); + var subscriptionsCalculator = new SubscriptionsCalculator(dateProvider); + _sut = new MonthlyPageCalculator(subscriptionsCalculator, _subscriptionService); } [Theory] [InlineData(0)] [InlineData(1)] - public void GetSubscriptionListByMonth_MonthProvided_Returns_UnpaidSubscriptions(int subscriptionIndex) + public async Task GetSubscriptionListByMonth_MonthProvided_Returns_UnpaidSubscriptions(int subscriptionIndex) { // Arrange var subscriptions = CreateSubscriptions(); var subscription = subscriptions.ElementAt(subscriptionIndex); + _subscriptionService.GetAllAsync().Returns(subscriptions); // Act - var result = _sut.GetMonthlySubscriptionLists(subscriptions, _fromIncludedDate, _toIncludedDate); + var result = await _sut.GetMonthlySubscriptionLists(_fromIncludedDate, _toIncludedDate); var collectedSubscriptions = CollectSubscriptions(result); // Assert - Assert.Equal(_numberOfMonths, result.Count()); + Assert.Equal(_numberOfMonths, result.First().Count()); Assert.Equal(_numberOfMonths, collectedSubscriptions.Count(sub => sub.Id.Equals(subscription.Id))); } [Fact] - public void GetSubscriptionListByMonth_DoesNotReturn_SubscriptionsWithNonStartedPayments() + public async Task GetSubscriptionListByMonth_DoesNotReturn_SubscriptionsWithNonStartedPayments() { // Arrange var subscriptions = new[] { new Subscription() { Name = "Subscription", LastPayment = _fromIncludedDate.AddMonths(1), BillingInterval = 1, BillingOccurrence = BillingOccurrence.Month, FirstPaymentDay = 1 } }; + _subscriptionService.GetAllAsync().Returns(subscriptions); // Act - var result = _sut.GetMonthlySubscriptionLists(subscriptions, _fromIncludedDate, _fromIncludedDate.LastDayOfMonthDate()); + var result = await _sut.GetMonthlySubscriptionLists(_fromIncludedDate, _fromIncludedDate.LastDayOfMonthDate()); // Assert Assert.Empty(result); } [Fact] - public void GetSubscriptionListByMonth_MonthProvided_ShouldNotReturn_PaidSubscriptions() + public async Task GetSubscriptionListByMonth_MonthProvided_ShouldNotReturn_PaidSubscriptions() { // Arrange var subscriptions = CreateSubscriptions(); + _subscriptionService.GetAllAsync().Returns(subscriptions); // Act - var result = _sut.GetMonthlySubscriptionLists(subscriptions, _fromIncludedDate, _toIncludedDate); + var result = await _sut.GetMonthlySubscriptionLists(_fromIncludedDate, _toIncludedDate); // Assert - Assert.Equal(_numberOfMonths, result.Count()); + Assert.Equal(_numberOfMonths, result.First().Count()); } [Theory] [InlineData(5, 4)] [InlineData(4, 2)] - public void GetSubscriptionListByMonth_MonthProvided_ShouldReturnWeeklySubscriptionsMultipleTimes(int subscriptionsIndex, int expectedNumberOfIterationsInMonth) + public async Task GetSubscriptionListByMonth_MonthProvided_ShouldReturnWeeklySubscriptionsMultipleTimes(int subscriptionsIndex, int expectedNumberOfIterationsInMonth) { // Arrange var subscriptions = CreateSubscriptions(); var subscription = subscriptions.ElementAt(subscriptionsIndex); + _subscriptionService.GetAllAsync().Returns(subscriptions); // Act - var result = _sut.GetMonthlySubscriptionLists(subscriptions, _fromIncludedDate, _toIncludedDate); + var result = await _sut.GetMonthlySubscriptionLists(_fromIncludedDate, _toIncludedDate); var collectedSubscriptions = CollectSubscriptions(result); // Assert - Assert.Equal(_numberOfMonths, result.Count()); + Assert.Equal(_numberOfMonths, result.First().Count()); Assert.Equal(expectedNumberOfIterationsInMonth, collectedSubscriptions.Count(sub => sub.Id.Equals(subscription.Id))); } [Fact] - public void GetSubscriptionListByMonth_WeeklySub_ShouldNotContainLastPayment() + public async Task GetSubscriptionListByMonth_WeeklySub_ShouldNotContainLastPayment() { // Arrange var sub = new Subscription { Name = "Subscriptions", FirstPaymentDay = 1, BillingInterval = 1, BillingOccurrence = BillingOccurrence.Week, LastPayment = new DateTime(2023, 4, 19) }; + _subscriptionService.GetAllAsync().Returns(new[] { sub }); // Act - var result = _sut.GetMonthlySubscriptionLists(new[] { sub }, _fromIncludedDate, _toIncludedDate); + var result = await _sut.GetMonthlySubscriptionLists(_fromIncludedDate, _toIncludedDate); // Assert - Assert.Equal(2, result.Count()); + Assert.Equal(2, result.First().Count()); } [Fact] - public void GetSubscriptionListByMonth_MonthProvided_SubscriptionsHavingLongerThanMonthlyCycle_ShouldReturnAsExpected() + public async Task GetSubscriptionListByMonth_MonthProvided_SubscriptionsHavingLongerThanMonthlyCycle_ShouldReturnAsExpected() { // Arrange var subscriptions = CreateSubscriptions(); var subscription = subscriptions.ElementAt(6); + _subscriptionService.GetAllAsync().Returns(subscriptions); // Act - var result = _sut.GetMonthlySubscriptionLists(subscriptions, _fromIncludedDate, _toIncludedDate); + var result = await _sut.GetMonthlySubscriptionLists(_fromIncludedDate, _toIncludedDate); // Assert - Assert.Equal(_numberOfMonths, result.Count()); - Assert.Contains(result.Last().Subscriptions, (sub) => sub.Id.Equals(subscription.Id)); + Assert.Equal(_numberOfMonths, result.First().Count()); + Assert.Contains(result.Last().Last().Subscriptions, (sub) => sub.Id.Equals(subscription.Id)); } private IEnumerable CreateSubscriptions() @@ -202,9 +209,9 @@ private IEnumerable CreateSubscriptions() }; } - private static IEnumerable CollectSubscriptions(IEnumerable subscriptionsMonthResponses) + private static IEnumerable CollectSubscriptions(IEnumerable> subscriptionsMonthResponses) { - return subscriptionsMonthResponses.SelectMany(response => response.Subscriptions); + return subscriptionsMonthResponses.SelectMany(response => response.SelectMany(r => r.Subscriptions)); } } } From 7025aa2dbca124fb07f26d3005a2f921abbb3efa Mon Sep 17 00:00:00 2001 From: Ashwin Thyagarajan Date: Mon, 21 Aug 2023 22:55:01 +0530 Subject: [PATCH 2/3] Refactorings: private field naming convention Dictionary instead of IGrouing returned from the service --- subtrack.MAUI/Pages/Monthly.razor | 14 ++++++------- .../Abstractions/IMonthlyPageCalculator.cs | 11 +++++++--- .../Services/MonthlyPageCalculator.cs | 20 +++++++++---------- .../GetSubscriptionListByMonthTests.cs | 16 +++++++-------- 4 files changed, 33 insertions(+), 28 deletions(-) diff --git a/subtrack.MAUI/Pages/Monthly.razor b/subtrack.MAUI/Pages/Monthly.razor index ffed1f6..e88ca76 100644 --- a/subtrack.MAUI/Pages/Monthly.razor +++ b/subtrack.MAUI/Pages/Monthly.razor @@ -4,29 +4,29 @@ -@foreach (var subs in monthlySubscriptions) +@foreach (var subs in _monthlySubscriptions) { - var displayYear = subs.Key != currentYear; + var displayYear = subs.Key != _currentYear; @if (displayYear) {
@(subs.Key)
} - @foreach(var subMonth in subs) + @foreach(var subMonth in subs.Value) { } } @code { - int currentYear; - IEnumerable> monthlySubscriptions = default!; + int _currentYear; + IDictionary> _monthlySubscriptions = default!; protected override async Task OnInitializedAsync() { var fromDate = DateProvider.Today; - currentYear = fromDate.Year; + _currentYear = fromDate.Year; var futureYearsToDisplay = 2; var toDate = fromDate.AddYears(futureYearsToDisplay); - monthlySubscriptions = await MonthlyPageCalculator.GetMonthlySubscriptionLists(fromDate.FirstDayOfMonthDate(), toDate.LastDayOfMonthDate()); + _monthlySubscriptions = await MonthlyPageCalculator.GetMonthlySubscriptionLists(fromDate.FirstDayOfMonthDate(), toDate.LastDayOfMonthDate()); } } \ No newline at end of file diff --git a/subtrack.MAUI/Services/Abstractions/IMonthlyPageCalculator.cs b/subtrack.MAUI/Services/Abstractions/IMonthlyPageCalculator.cs index 17c8ce8..5d07fb7 100644 --- a/subtrack.MAUI/Services/Abstractions/IMonthlyPageCalculator.cs +++ b/subtrack.MAUI/Services/Abstractions/IMonthlyPageCalculator.cs @@ -1,10 +1,15 @@ -using subtrack.DAL.Entities; -using subtrack.MAUI.Responses; +using subtrack.MAUI.Responses; namespace subtrack.MAUI.Services.Abstractions { public interface IMonthlyPageCalculator { - Task>> GetMonthlySubscriptionLists(DateTime fromIncludedDate, DateTime toIncludedDate); + /// + /// Fetches all subscriptions that are active between the given dates grouped by month and year + /// + /// Starting date for fetching the subscriptions + /// Ending date for fetching the subscriptions + /// A object where key is the year and value is the list of subscriptions grouped by month for that year + Task>> GetMonthlySubscriptionLists(DateTime fromIncludedDate, DateTime toIncludedDate); } } diff --git a/subtrack.MAUI/Services/MonthlyPageCalculator.cs b/subtrack.MAUI/Services/MonthlyPageCalculator.cs index a55d2b9..19c4b56 100644 --- a/subtrack.MAUI/Services/MonthlyPageCalculator.cs +++ b/subtrack.MAUI/Services/MonthlyPageCalculator.cs @@ -6,30 +6,30 @@ namespace subtrack.MAUI.Services { internal class MonthlyPageCalculator : IMonthlyPageCalculator { - private readonly ISubscriptionsCalculator subscriptionsCalculator; - private readonly ISubscriptionService subscriptionService; + private readonly ISubscriptionsCalculator _subscriptionsCalculator; + private readonly ISubscriptionService _subscriptionService; public MonthlyPageCalculator(ISubscriptionsCalculator subscriptionsCalculator, ISubscriptionService subscriptionService) { - this.subscriptionsCalculator = subscriptionsCalculator; - this.subscriptionService = subscriptionService; + _subscriptionsCalculator = subscriptionsCalculator; + _subscriptionService = subscriptionService; } private IEnumerable GetPaymentsUntilMonth(Subscription subscription, DateTime fromIncludedDate, DateTime toIncludedDate) { - subscription.LastPayment = subscriptionsCalculator.GetNextPaymentDate(subscription); + subscription.LastPayment = _subscriptionsCalculator.GetNextPaymentDate(subscription); while (subscription.LastPayment.Date >= fromIncludedDate.Date && subscription.LastPayment.Date <= toIncludedDate.Date) { yield return (Subscription)subscription.Clone(); - subscription.LastPayment = subscriptionsCalculator.GetNextPaymentDate(subscription); + subscription.LastPayment = _subscriptionsCalculator.GetNextPaymentDate(subscription); } } - public async Task>> GetMonthlySubscriptionLists(DateTime fromIncludedMonthDate, DateTime finalIncludedMonthDate) + public async Task>> GetMonthlySubscriptionLists(DateTime fromIncludedMonthDate, DateTime finalIncludedMonthDate) { - var subscriptions = await subscriptionService.GetAllAsync(); + var subscriptions = await _subscriptionService.GetAllAsync(); return subscriptions .SelectMany(s => GetPaymentsUntilMonth(s, fromIncludedMonthDate, finalIncludedMonthDate)) .GroupBy(s => (s.LastPayment.Year, s.LastPayment.Month)) @@ -38,8 +38,8 @@ public async Task>> GetMo { MonthDate = new DateTime(g.Key.Year, g.Key.Month, 1), Subscriptions = g.OrderBy(s => s.LastPayment).ToList(), - Cost = subscriptionsCalculator.GetTotalCost(g) - }).GroupBy(r => r.MonthDate.Year); + Cost = _subscriptionsCalculator.GetTotalCost(g) + }).GroupBy(r => r.MonthDate.Year).ToDictionary(k => k.Key, v => v.ToList()); } } } diff --git a/subtrack.Tests/SubscriptionCalculatorTests/GetSubscriptionListByMonthTests.cs b/subtrack.Tests/SubscriptionCalculatorTests/GetSubscriptionListByMonthTests.cs index 933a38d..5c6756a 100644 --- a/subtrack.Tests/SubscriptionCalculatorTests/GetSubscriptionListByMonthTests.cs +++ b/subtrack.Tests/SubscriptionCalculatorTests/GetSubscriptionListByMonthTests.cs @@ -34,7 +34,7 @@ public async Task GetSubscriptionListByMonth_MonthProvided_Returns_UnpaidSubscri var collectedSubscriptions = CollectSubscriptions(result); // Assert - Assert.Equal(_numberOfMonths, result.First().Count()); + Assert.Equal(_numberOfMonths, result.First().Value.Count); Assert.Equal(_numberOfMonths, collectedSubscriptions.Count(sub => sub.Id.Equals(subscription.Id))); } @@ -63,7 +63,7 @@ public async Task GetSubscriptionListByMonth_MonthProvided_ShouldNotReturn_PaidS var result = await _sut.GetMonthlySubscriptionLists(_fromIncludedDate, _toIncludedDate); // Assert - Assert.Equal(_numberOfMonths, result.First().Count()); + Assert.Equal(_numberOfMonths, result.First().Value.Count); } [Theory] @@ -81,7 +81,7 @@ public async Task GetSubscriptionListByMonth_MonthProvided_ShouldReturnWeeklySub var collectedSubscriptions = CollectSubscriptions(result); // Assert - Assert.Equal(_numberOfMonths, result.First().Count()); + Assert.Equal(_numberOfMonths, result.First().Value.Count); Assert.Equal(expectedNumberOfIterationsInMonth, collectedSubscriptions.Count(sub => sub.Id.Equals(subscription.Id))); } @@ -96,7 +96,7 @@ public async Task GetSubscriptionListByMonth_WeeklySub_ShouldNotContainLastPayme var result = await _sut.GetMonthlySubscriptionLists(_fromIncludedDate, _toIncludedDate); // Assert - Assert.Equal(2, result.First().Count()); + Assert.Equal(2, result.First().Value.Count); } [Fact] @@ -111,8 +111,8 @@ public async Task GetSubscriptionListByMonth_MonthProvided_SubscriptionsHavingLo var result = await _sut.GetMonthlySubscriptionLists(_fromIncludedDate, _toIncludedDate); // Assert - Assert.Equal(_numberOfMonths, result.First().Count()); - Assert.Contains(result.Last().Last().Subscriptions, (sub) => sub.Id.Equals(subscription.Id)); + Assert.Equal(_numberOfMonths, result.First().Value.Count); + Assert.Contains(result.Last().Value.Last().Subscriptions, (sub) => sub.Id.Equals(subscription.Id)); } private IEnumerable CreateSubscriptions() @@ -209,9 +209,9 @@ private IEnumerable CreateSubscriptions() }; } - private static IEnumerable CollectSubscriptions(IEnumerable> subscriptionsMonthResponses) + private static IEnumerable CollectSubscriptions(IDictionary> subscriptionsMonthResponses) { - return subscriptionsMonthResponses.SelectMany(response => response.SelectMany(r => r.Subscriptions)); + return subscriptionsMonthResponses.SelectMany(response => response.Value.SelectMany(r => r.Subscriptions)); } } } From 55a834746242f472802fbca12370d42cff62057c Mon Sep 17 00:00:00 2001 From: ChrisK00 Date: Thu, 24 Aug 2023 18:28:48 +0200 Subject: [PATCH 3/3] undo commit --- subtrack.MAUI/Pages/Monthly.razor | 11 ++++-- .../Abstractions/IMonthlyPageCalculator.cs | 8 +++-- .../Abstractions/ISubscriptionsCalculator.cs | 6 ++-- .../Services/MonthlyPageCalculator.cs | 7 ++-- .../GetSubscriptionListByMonthTests.cs | 35 ++++++++----------- 5 files changed, 32 insertions(+), 35 deletions(-) diff --git a/subtrack.MAUI/Pages/Monthly.razor b/subtrack.MAUI/Pages/Monthly.razor index e88ca76..4c81e20 100644 --- a/subtrack.MAUI/Pages/Monthly.razor +++ b/subtrack.MAUI/Pages/Monthly.razor @@ -1,4 +1,6 @@ @page "/monthly" + +@inject subtrack.MAUI.Services.Abstractions.ISubscriptionService SubscriptionService @inject subtrack.MAUI.Services.Abstractions.IDateProvider DateProvider @inject subtrack.MAUI.Services.Abstractions.IMonthlyPageCalculator MonthlyPageCalculator @@ -11,9 +13,10 @@ {
@(subs.Key)
} - @foreach(var subMonth in subs.Value) + @foreach (var subMonth in subs.Value) { - + + } } @@ -22,11 +25,13 @@ IDictionary> _monthlySubscriptions = default!; protected override async Task OnInitializedAsync() { + var subscriptions = await SubscriptionService.GetAllAsync(); + var fromDate = DateProvider.Today; _currentYear = fromDate.Year; var futureYearsToDisplay = 2; var toDate = fromDate.AddYears(futureYearsToDisplay); - _monthlySubscriptions = await MonthlyPageCalculator.GetMonthlySubscriptionLists(fromDate.FirstDayOfMonthDate(), toDate.LastDayOfMonthDate()); + _monthlySubscriptions = MonthlyPageCalculator.GetMonthlySubscriptionLists(subscriptions, fromDate.FirstDayOfMonthDate(), toDate.LastDayOfMonthDate()); } } \ No newline at end of file diff --git a/subtrack.MAUI/Services/Abstractions/IMonthlyPageCalculator.cs b/subtrack.MAUI/Services/Abstractions/IMonthlyPageCalculator.cs index 5d07fb7..64bcaba 100644 --- a/subtrack.MAUI/Services/Abstractions/IMonthlyPageCalculator.cs +++ b/subtrack.MAUI/Services/Abstractions/IMonthlyPageCalculator.cs @@ -1,4 +1,5 @@ -using subtrack.MAUI.Responses; +using subtrack.DAL.Entities; +using subtrack.MAUI.Responses; namespace subtrack.MAUI.Services.Abstractions { @@ -7,9 +8,10 @@ public interface IMonthlyPageCalculator /// /// Fetches all subscriptions that are active between the given dates grouped by month and year /// + /// /// Starting date for fetching the subscriptions /// Ending date for fetching the subscriptions - /// A object where key is the year and value is the list of subscriptions grouped by month for that year - Task>> GetMonthlySubscriptionLists(DateTime fromIncludedDate, DateTime toIncludedDate); + /// A dictionary where key is the year and value is the list of subscriptions grouped by month for that year + IDictionary> GetMonthlySubscriptionLists(IEnumerable subscriptions, DateTime fromIncludedDate, DateTime toIncludedDate); } } diff --git a/subtrack.MAUI/Services/Abstractions/ISubscriptionsCalculator.cs b/subtrack.MAUI/Services/Abstractions/ISubscriptionsCalculator.cs index a93985c..d80d02e 100644 --- a/subtrack.MAUI/Services/Abstractions/ISubscriptionsCalculator.cs +++ b/subtrack.MAUI/Services/Abstractions/ISubscriptionsCalculator.cs @@ -5,13 +5,13 @@ namespace subtrack.MAUI.Services.Abstractions public interface ISubscriptionsCalculator { int GetDueDays(Subscription subscription); - + decimal GetTotalCost(IEnumerable subscriptions); - + decimal GetYearlyCost(Subscription subscription); DateTime GetNextPaymentDate(Subscription subscription); - + (bool IsDue, DateTime NextPaymentDate) IsDue(Subscription subscription); decimal GetAverageMonthlyCost(IEnumerable subscriptions); diff --git a/subtrack.MAUI/Services/MonthlyPageCalculator.cs b/subtrack.MAUI/Services/MonthlyPageCalculator.cs index 19c4b56..d16c1d8 100644 --- a/subtrack.MAUI/Services/MonthlyPageCalculator.cs +++ b/subtrack.MAUI/Services/MonthlyPageCalculator.cs @@ -7,12 +7,10 @@ namespace subtrack.MAUI.Services internal class MonthlyPageCalculator : IMonthlyPageCalculator { private readonly ISubscriptionsCalculator _subscriptionsCalculator; - private readonly ISubscriptionService _subscriptionService; - public MonthlyPageCalculator(ISubscriptionsCalculator subscriptionsCalculator, ISubscriptionService subscriptionService) + public MonthlyPageCalculator(ISubscriptionsCalculator subscriptionsCalculator) { _subscriptionsCalculator = subscriptionsCalculator; - _subscriptionService = subscriptionService; } private IEnumerable GetPaymentsUntilMonth(Subscription subscription, DateTime fromIncludedDate, DateTime toIncludedDate) @@ -27,9 +25,8 @@ private IEnumerable GetPaymentsUntilMonth(Subscription subscriptio } } - public async Task>> GetMonthlySubscriptionLists(DateTime fromIncludedMonthDate, DateTime finalIncludedMonthDate) + public IDictionary> GetMonthlySubscriptionLists(IEnumerable subscriptions, DateTime fromIncludedMonthDate, DateTime finalIncludedMonthDate) { - var subscriptions = await _subscriptionService.GetAllAsync(); return subscriptions .SelectMany(s => GetPaymentsUntilMonth(s, fromIncludedMonthDate, finalIncludedMonthDate)) .GroupBy(s => (s.LastPayment.Year, s.LastPayment.Month)) diff --git a/subtrack.Tests/SubscriptionCalculatorTests/GetSubscriptionListByMonthTests.cs b/subtrack.Tests/SubscriptionCalculatorTests/GetSubscriptionListByMonthTests.cs index 5c6756a..2b37f4c 100644 --- a/subtrack.Tests/SubscriptionCalculatorTests/GetSubscriptionListByMonthTests.cs +++ b/subtrack.Tests/SubscriptionCalculatorTests/GetSubscriptionListByMonthTests.cs @@ -6,31 +6,29 @@ namespace subtrack.Tests.SubscriptionCalculatorTests public class GetSubscriptionListByMonthTests { private readonly IMonthlyPageCalculator _sut; - private readonly ISubscriptionService _subscriptionService = Substitute.For(); private readonly int _numberOfMonths = 3; private readonly DateTime _fromIncludedDate = new(2023, 4, 1), _toIncludedDate; - + public GetSubscriptionListByMonthTests() { _toIncludedDate = _fromIncludedDate.AddMonths(_numberOfMonths - 1); var dateProvider = Substitute.For(); var subscriptionsCalculator = new SubscriptionsCalculator(dateProvider); - _sut = new MonthlyPageCalculator(subscriptionsCalculator, _subscriptionService); + _sut = new MonthlyPageCalculator(subscriptionsCalculator); } [Theory] [InlineData(0)] [InlineData(1)] - public async Task GetSubscriptionListByMonth_MonthProvided_Returns_UnpaidSubscriptions(int subscriptionIndex) + public void GetSubscriptionListByMonth_MonthProvided_Returns_UnpaidSubscriptions(int subscriptionIndex) { // Arrange var subscriptions = CreateSubscriptions(); var subscription = subscriptions.ElementAt(subscriptionIndex); - _subscriptionService.GetAllAsync().Returns(subscriptions); // Act - var result = await _sut.GetMonthlySubscriptionLists(_fromIncludedDate, _toIncludedDate); + var result = _sut.GetMonthlySubscriptionLists(subscriptions, _fromIncludedDate, _toIncludedDate); var collectedSubscriptions = CollectSubscriptions(result); // Assert @@ -39,28 +37,26 @@ public async Task GetSubscriptionListByMonth_MonthProvided_Returns_UnpaidSubscri } [Fact] - public async Task GetSubscriptionListByMonth_DoesNotReturn_SubscriptionsWithNonStartedPayments() + public void GetSubscriptionListByMonth_DoesNotReturn_SubscriptionsWithNonStartedPayments() { // Arrange var subscriptions = new[] { new Subscription() { Name = "Subscription", LastPayment = _fromIncludedDate.AddMonths(1), BillingInterval = 1, BillingOccurrence = BillingOccurrence.Month, FirstPaymentDay = 1 } }; - _subscriptionService.GetAllAsync().Returns(subscriptions); // Act - var result = await _sut.GetMonthlySubscriptionLists(_fromIncludedDate, _fromIncludedDate.LastDayOfMonthDate()); + var result = _sut.GetMonthlySubscriptionLists(subscriptions, _fromIncludedDate, _fromIncludedDate.LastDayOfMonthDate()); // Assert Assert.Empty(result); } [Fact] - public async Task GetSubscriptionListByMonth_MonthProvided_ShouldNotReturn_PaidSubscriptions() + public void GetSubscriptionListByMonth_MonthProvided_ShouldNotReturn_PaidSubscriptions() { // Arrange var subscriptions = CreateSubscriptions(); - _subscriptionService.GetAllAsync().Returns(subscriptions); // Act - var result = await _sut.GetMonthlySubscriptionLists(_fromIncludedDate, _toIncludedDate); + var result = _sut.GetMonthlySubscriptionLists(subscriptions, _fromIncludedDate, _toIncludedDate); // Assert Assert.Equal(_numberOfMonths, result.First().Value.Count); @@ -69,15 +65,14 @@ public async Task GetSubscriptionListByMonth_MonthProvided_ShouldNotReturn_PaidS [Theory] [InlineData(5, 4)] [InlineData(4, 2)] - public async Task GetSubscriptionListByMonth_MonthProvided_ShouldReturnWeeklySubscriptionsMultipleTimes(int subscriptionsIndex, int expectedNumberOfIterationsInMonth) + public void GetSubscriptionListByMonth_MonthProvided_ShouldReturnWeeklySubscriptionsMultipleTimes(int subscriptionsIndex, int expectedNumberOfIterationsInMonth) { // Arrange var subscriptions = CreateSubscriptions(); var subscription = subscriptions.ElementAt(subscriptionsIndex); - _subscriptionService.GetAllAsync().Returns(subscriptions); // Act - var result = await _sut.GetMonthlySubscriptionLists(_fromIncludedDate, _toIncludedDate); + var result = _sut.GetMonthlySubscriptionLists(subscriptions, _fromIncludedDate, _toIncludedDate); var collectedSubscriptions = CollectSubscriptions(result); // Assert @@ -86,29 +81,27 @@ public async Task GetSubscriptionListByMonth_MonthProvided_ShouldReturnWeeklySub } [Fact] - public async Task GetSubscriptionListByMonth_WeeklySub_ShouldNotContainLastPayment() + public void GetSubscriptionListByMonth_WeeklySub_ShouldNotContainLastPayment() { // Arrange var sub = new Subscription { Name = "Subscriptions", FirstPaymentDay = 1, BillingInterval = 1, BillingOccurrence = BillingOccurrence.Week, LastPayment = new DateTime(2023, 4, 19) }; - _subscriptionService.GetAllAsync().Returns(new[] { sub }); // Act - var result = await _sut.GetMonthlySubscriptionLists(_fromIncludedDate, _toIncludedDate); + var result = _sut.GetMonthlySubscriptionLists(new[] { sub }, _fromIncludedDate, _toIncludedDate); // Assert Assert.Equal(2, result.First().Value.Count); } [Fact] - public async Task GetSubscriptionListByMonth_MonthProvided_SubscriptionsHavingLongerThanMonthlyCycle_ShouldReturnAsExpected() + public void GetSubscriptionListByMonth_MonthProvided_SubscriptionsHavingLongerThanMonthlyCycle_ShouldReturnAsExpected() { // Arrange var subscriptions = CreateSubscriptions(); var subscription = subscriptions.ElementAt(6); - _subscriptionService.GetAllAsync().Returns(subscriptions); // Act - var result = await _sut.GetMonthlySubscriptionLists(_fromIncludedDate, _toIncludedDate); + var result = _sut.GetMonthlySubscriptionLists(subscriptions, _fromIncludedDate, _toIncludedDate); // Assert Assert.Equal(_numberOfMonths, result.First().Value.Count);