From 37f0ce4837efb8d724483ca8ba44634fb448e532 Mon Sep 17 00:00:00 2001 From: berkansasmaz Date: Thu, 3 Mar 2022 19:05:15 +0300 Subject: [PATCH] refactor(organization.plan): improvements after review --- .../Organizations/OrganizationAppService.cs | 13 +++---- ...OrganizationPaidEnrollmentEndDateWorker.cs | 24 +++++-------- src/EventHub.Domain/Events/EventManager.cs | 4 +-- .../Registrations/EventRegistrationManager.cs | 2 +- .../Plans/FeatureOfPlanDefinition.cs | 11 ++++-- .../Plans/IPlanInfoDefinitionStore.cs | 11 ------ .../Organizations/Plans/PlanFeatureManager.cs | 34 +++++++++---------- .../Organizations/Plans/PlanInfoDefinition.cs | 6 ++-- .../Plans/PlanInfoDefinitionStore.cs | 27 --------------- .../Organizations/Plans/PlanInfoOptions.cs | 11 ++++++ .../EventRegistrationManager_UnitTests.cs | 4 +-- 11 files changed, 60 insertions(+), 87 deletions(-) delete mode 100644 src/EventHub.Domain/Organizations/Plans/IPlanInfoDefinitionStore.cs delete mode 100644 src/EventHub.Domain/Organizations/Plans/PlanInfoDefinitionStore.cs diff --git a/src/EventHub.Application/Organizations/OrganizationAppService.cs b/src/EventHub.Application/Organizations/OrganizationAppService.cs index 4f9f3dd..f61c5da 100644 --- a/src/EventHub.Application/Organizations/OrganizationAppService.cs +++ b/src/EventHub.Application/Organizations/OrganizationAppService.cs @@ -7,6 +7,7 @@ using EventHub.Organizations.PaymentRequests; using EventHub.Organizations.Plans; using EventHub.Users; using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Options; using Volo.Abp.Application.Dtos; using Volo.Abp.Authorization; using Volo.Abp.BlobStoring; @@ -23,22 +24,22 @@ namespace EventHub.Organizations private readonly OrganizationManager _organizationManager; private readonly IBlobContainer _organizationBlobContainer; private readonly IUserRepository _userRepository; - private readonly IPlanInfoDefinitionStore _planInfoDefinitionStore; + private readonly IOptions _planInfoOptions; public OrganizationAppService( IRepository organizationRepository, IOrganizationMembershipRepository organizationMembershipsRepository, OrganizationManager organizationManager, IBlobContainer organizationBlobContainer, - IUserRepository userRepository, - IPlanInfoDefinitionStore planInfoDefinitionStore) + IUserRepository userRepository, + IOptions planInfoOptions) { _organizationRepository = organizationRepository; _organizationMembershipsRepository = organizationMembershipsRepository; _organizationManager = organizationManager; _organizationBlobContainer = organizationBlobContainer; _userRepository = userRepository; - _planInfoDefinitionStore = planInfoDefinitionStore; + _planInfoOptions = planInfoOptions; } [Authorize] @@ -171,8 +172,8 @@ namespace EventHub.Organizations [Authorize] public async Task> GetPlanInfosAsync() { - var planInfoDefinitions = await _planInfoDefinitionStore.GetPlanInfosAsync(); - return ObjectMapper.Map, List>(planInfoDefinitions); + var planInfoDefinitions = _planInfoOptions.Value.GetPlanInfos(); + return await Task.FromResult(ObjectMapper.Map, List>(planInfoDefinitions)); } private async Task SaveProfilePictureAsync(Guid id, IRemoteStreamContent streamContent) diff --git a/src/EventHub.BackgroundServices/Organizations/OrganizationPaidEnrollmentEndDateWorker.cs b/src/EventHub.BackgroundServices/Organizations/OrganizationPaidEnrollmentEndDateWorker.cs index c4316b5..910c602 100644 --- a/src/EventHub.BackgroundServices/Organizations/OrganizationPaidEnrollmentEndDateWorker.cs +++ b/src/EventHub.BackgroundServices/Organizations/OrganizationPaidEnrollmentEndDateWorker.cs @@ -41,7 +41,8 @@ namespace EventHub.Organizations var queryable = await organizationRepository.GetQueryableAsync(); var query = queryable.Where(x => x.IsSendPaidEnrollmentReminderEmail == false && - x.PaidEnrollmentEndDate <= oneMonthLater + x.PaidEnrollmentEndDate <= oneMonthLater && + x.PlanType != OrganizationPlanType.Free ); var organizations = await asyncExecuter.ToListAsync(query); @@ -50,16 +51,13 @@ namespace EventHub.Organizations { try { - if (organization.PlanType != OrganizationPlanType.Free) + if (organization.PaidEnrollmentEndDate >= clock.Now) { - if (organization.PaidEnrollmentEndDate >= clock.Now) - { - await organizationPlanEndDateNotifier.NotifyAsync(organization); - } - - organization.IsSendPaidEnrollmentReminderEmail = true; - await organizationRepository.UpdateAsync(organization); + await organizationPlanEndDateNotifier.NotifyAsync(organization); } + + organization.IsSendPaidEnrollmentReminderEmail = true; + await organizationRepository.UpdateAsync(organization); } catch (Exception ex) { @@ -72,7 +70,8 @@ namespace EventHub.Organizations { var queryable = await organizationRepository.GetQueryableAsync(); var query = queryable.Where(x => - x.PaidEnrollmentEndDate >= clock.Now + x.PaidEnrollmentEndDate > clock.Now.Date && + x.PlanType != OrganizationPlanType.Free ); var organizations = await asyncExecuter.ToListAsync(query); @@ -81,11 +80,6 @@ namespace EventHub.Organizations { try { - if (organization.PlanType == OrganizationPlanType.Free) - { - continue; - } - organization.SetFreeToPlanType(); organization.IsSendPaidEnrollmentReminderEmail = false; await organizationRepository.UpdateAsync(organization); diff --git a/src/EventHub.Domain/Events/EventManager.cs b/src/EventHub.Domain/Events/EventManager.cs index 24b18a8..ed58c98 100644 --- a/src/EventHub.Domain/Events/EventManager.cs +++ b/src/EventHub.Domain/Events/EventManager.cs @@ -35,7 +35,7 @@ namespace EventHub.Events DateTime endTime, string description) { - if (!await _planFeatureManager.CanCreateNewEvent(organization.Id)) + if (!await _planFeatureManager.CanCreateNewEventAsync(organization.Id)) { throw new BusinessException(EventHubErrorCodes.CannotCreateNewEvent); } @@ -53,7 +53,7 @@ namespace EventHub.Events public async Task AddTrackAsync(Event @event, string name) { - if (!await _planFeatureManager.CanAddNewTrack(@event)) + if (!await _planFeatureManager.CanAddNewTrackAsync(@event)) { throw new BusinessException(EventHubErrorCodes.CannotAddNewTrack); } diff --git a/src/EventHub.Domain/Events/Registrations/EventRegistrationManager.cs b/src/EventHub.Domain/Events/Registrations/EventRegistrationManager.cs index 4aac5d3..bc41542 100644 --- a/src/EventHub.Domain/Events/Registrations/EventRegistrationManager.cs +++ b/src/EventHub.Domain/Events/Registrations/EventRegistrationManager.cs @@ -52,7 +52,7 @@ namespace EventHub.Events.Registrations } } - if (!await _planFeatureManager.CanRegisterToEvent(@event)) + if (!await _planFeatureManager.CanRegisterToEventAsync(@event)) { throw new BusinessException(EventHubErrorCodes.CannotRegisterToEvent); } diff --git a/src/EventHub.Domain/Organizations/Plans/FeatureOfPlanDefinition.cs b/src/EventHub.Domain/Organizations/Plans/FeatureOfPlanDefinition.cs index c693856..bf25258 100644 --- a/src/EventHub.Domain/Organizations/Plans/FeatureOfPlanDefinition.cs +++ b/src/EventHub.Domain/Organizations/Plans/FeatureOfPlanDefinition.cs @@ -7,17 +7,22 @@ namespace EventHub.Organizations.Plans; public class FeatureOfPlanDefinition { [CanBeNull] - [Range(0, uint.MaxValue, ErrorMessage = "Value for {0} must be between {1} and {2}.")] + [Range(0, uint.MaxValue)] public uint? MaxAllowedEventsCountInOneYear { get; set; } [CanBeNull] - [Range(0, uint.MaxValue, ErrorMessage = "Value for {0} must be between {1} and {2}.")] + [Range(0, uint.MaxValue)] public uint? MaxAllowedTracksCountInOneEvent { get; set; } [CanBeNull] - [Range(0, uint.MaxValue, ErrorMessage = "Value for {0} must be between {1} and {2}.")] + [Range(0, uint.MaxValue)] public uint? MaxAllowedAttendeesCountInOneEvent { get; set; } [NotNull] public List AdditionalFeatureInfos { get; set; } + + public FeatureOfPlanDefinition() + { + AdditionalFeatureInfos = new List(); + } } diff --git a/src/EventHub.Domain/Organizations/Plans/IPlanInfoDefinitionStore.cs b/src/EventHub.Domain/Organizations/Plans/IPlanInfoDefinitionStore.cs deleted file mode 100644 index 4572650..0000000 --- a/src/EventHub.Domain/Organizations/Plans/IPlanInfoDefinitionStore.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace EventHub.Organizations.Plans; - -public interface IPlanInfoDefinitionStore -{ - Task> GetPlanInfosAsync(); - - Task GetPlanInfoByTypeAsync(OrganizationPlanType type); -} diff --git a/src/EventHub.Domain/Organizations/Plans/PlanFeatureManager.cs b/src/EventHub.Domain/Organizations/Plans/PlanFeatureManager.cs index 6074015..be95b4c 100644 --- a/src/EventHub.Domain/Organizations/Plans/PlanFeatureManager.cs +++ b/src/EventHub.Domain/Organizations/Plans/PlanFeatureManager.cs @@ -2,60 +2,60 @@ using System; using System.Threading.Tasks; using EventHub.Events; using EventHub.Events.Registrations; +using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Repositories; +using Volo.Abp.Timing; namespace EventHub.Organizations.Plans; public class PlanFeatureManager : ITransientDependency { - private readonly IPlanInfoDefinitionStore _planInfoDefinitionStore; + private readonly IOptions _planInfoOptions; private readonly IRepository _organizationRepository; private readonly IRepository _eventRepository; private readonly IEventRegistrationRepository _eventRegistrationRepository; - + private readonly IClock _clock; public PlanFeatureManager( - IPlanInfoDefinitionStore planInfoDefinitionStore, + IOptions planInfoOptions, IRepository organizationRepository, IRepository eventRepository, - IEventRegistrationRepository eventRegistrationRepository) + IEventRegistrationRepository eventRegistrationRepository, + IClock clock) { - _planInfoDefinitionStore = planInfoDefinitionStore; + _planInfoOptions = planInfoOptions; _organizationRepository = organizationRepository; _eventRepository = eventRepository; _eventRegistrationRepository = eventRegistrationRepository; + _clock = clock; } - public virtual async Task CanCreateNewEvent(Guid organizationId) + public virtual async Task CanCreateNewEventAsync(Guid organizationId) { var currentPlanOfOrganization = await GetCurrentPlanByOrganizationIdAsync(organizationId); - - var totalEventCountByOrganization = await _eventRepository.CountAsync(x => x.OrganizationId == organizationId && x.CreationTime.Year < DateTime.Now.Year + 1 && x.CreationTime.Year > DateTime.Now.Year - 1); - totalEventCountByOrganization++; - return currentPlanOfOrganization.Feature.MaxAllowedEventsCountInOneYear >= totalEventCountByOrganization; + var totalEventCountByOrganizationInThisYear = await _eventRepository.CountAsync(x => x.OrganizationId == organizationId && x.CreationTime.Year == _clock.Now.Year); + return currentPlanOfOrganization.Feature.MaxAllowedEventsCountInOneYear > totalEventCountByOrganizationInThisYear; } - public virtual async Task CanAddNewTrack(Event @event) + public virtual async Task CanAddNewTrackAsync(Event @event) { var currentPlanOfOrganization = await GetCurrentPlanByOrganizationIdAsync(@event.OrganizationId); var tracksCount = @event.Tracks.Count; - tracksCount++; - return currentPlanOfOrganization.Feature.MaxAllowedTracksCountInOneEvent >= tracksCount; + return currentPlanOfOrganization.Feature.MaxAllowedTracksCountInOneEvent > tracksCount; } - public virtual async Task CanRegisterToEvent(Event @event) + public virtual async Task CanRegisterToEventAsync(Event @event) { var currentPlanOfOrganization = await GetCurrentPlanByOrganizationIdAsync(@event.OrganizationId); var attendeesCount = await _eventRegistrationRepository.CountAsync(x => x.EventId == @event.Id); - attendeesCount++; - return currentPlanOfOrganization.Feature.MaxAllowedAttendeesCountInOneEvent >= attendeesCount; + return currentPlanOfOrganization.Feature.MaxAllowedAttendeesCountInOneEvent > attendeesCount; } private async Task GetCurrentPlanByOrganizationIdAsync(Guid organizationId) { var organization = await _organizationRepository.GetAsync(organizationId); - return await _planInfoDefinitionStore.GetPlanInfoByTypeAsync(organization.PlanType); + return _planInfoOptions.Value.GetPlanInfoByType(organization.PlanType); } } diff --git a/src/EventHub.Domain/Organizations/Plans/PlanInfoDefinition.cs b/src/EventHub.Domain/Organizations/Plans/PlanInfoDefinition.cs index 22043f1..4735ca4 100644 --- a/src/EventHub.Domain/Organizations/Plans/PlanInfoDefinition.cs +++ b/src/EventHub.Domain/Organizations/Plans/PlanInfoDefinition.cs @@ -17,17 +17,17 @@ public class PlanInfoDefinition public bool IsActive { get; set; } - [Range(1.0, 100.0, ErrorMessage = "Value for {0} must be between {1} and {2}.")] + [Range(1.0, 100.0)] public decimal Price { get; set; } = 1.0M; public bool IsExtendable { get; set; } [CanBeNull] - [Range(0, 12, ErrorMessage = "Value for {0} must be between {1} and {2}.")] + [Range(0, 12)] public int? CanBeExtendedAfterHowManyMonths { get; set; } [CanBeNull] - [Range(1, 24, ErrorMessage = "Value for {0} must be between {1} and {2}.")] + [Range(1, 24)] public int? OnePaidEnrollmentPeriodAsMonth { get; set; } = 12; public FeatureOfPlanDefinition Feature { get; set; } diff --git a/src/EventHub.Domain/Organizations/Plans/PlanInfoDefinitionStore.cs b/src/EventHub.Domain/Organizations/Plans/PlanInfoDefinitionStore.cs deleted file mode 100644 index 1f1b603..0000000 --- a/src/EventHub.Domain/Organizations/Plans/PlanInfoDefinitionStore.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.Extensions.Options; -using Volo.Abp.DependencyInjection; - -namespace EventHub.Organizations.Plans; - -public class PlanInfoDefinitionStore : IPlanInfoDefinitionStore, ITransientDependency -{ - protected PlanInfoOptions PlanInfoOptions { get; } - - public PlanInfoDefinitionStore(IOptions planInfoOptions) - { - PlanInfoOptions = planInfoOptions.Value; - } - - public async Task> GetPlanInfosAsync() - { - return await Task.FromResult(PlanInfoOptions.Infos); - } - - public async Task GetPlanInfoByTypeAsync(OrganizationPlanType type) - { - return await Task.FromResult(PlanInfoOptions.Infos.SingleOrDefault(x => x.PlanType == type)); - } -} diff --git a/src/EventHub.Domain/Organizations/Plans/PlanInfoOptions.cs b/src/EventHub.Domain/Organizations/Plans/PlanInfoOptions.cs index 771c825..46671a7 100644 --- a/src/EventHub.Domain/Organizations/Plans/PlanInfoOptions.cs +++ b/src/EventHub.Domain/Organizations/Plans/PlanInfoOptions.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; namespace EventHub.Organizations.Plans; @@ -27,4 +28,14 @@ public class PlanInfoOptions return this; } + + public List GetPlanInfos() + { + return Infos.Where(x => x.IsActive).ToList(); + } + + public PlanInfoDefinition GetPlanInfoByType(OrganizationPlanType type) + { + return Infos.SingleOrDefault(x => x.IsActive && x.PlanType == type); + } } diff --git a/test/EventHub.Domain.Tests/Events/Registrations/EventRegistrationManager_UnitTests.cs b/test/EventHub.Domain.Tests/Events/Registrations/EventRegistrationManager_UnitTests.cs index ce8c7a4..4b59f93 100644 --- a/test/EventHub.Domain.Tests/Events/Registrations/EventRegistrationManager_UnitTests.cs +++ b/test/EventHub.Domain.Tests/Events/Registrations/EventRegistrationManager_UnitTests.cs @@ -58,8 +58,8 @@ namespace EventHub.Events.Registrations var clock = Substitute.For(); clock.Now.Returns(DateTime.Now); - var planFeatureManager = Substitute.For(null, null, null, null); - planFeatureManager.CanRegisterToEvent(@event).Returns(Task.FromResult(true)); + var planFeatureManager = Substitute.For(null, null, null, null, null); + planFeatureManager.CanRegisterToEventAsync(@event).Returns(Task.FromResult(true)); var registrationManager = new EventRegistrationManager( repository, guidGenerator, clock, planFeatureManager