Browse Source

refactor(organization.plan): improvements after review

pull/90/head
berkansasmaz 5 years ago
parent
commit
37f0ce4837
No known key found for this signature in database GPG Key ID: 3AD81E2CA002230D
  1. 13
      src/EventHub.Application/Organizations/OrganizationAppService.cs
  2. 24
      src/EventHub.BackgroundServices/Organizations/OrganizationPaidEnrollmentEndDateWorker.cs
  3. 4
      src/EventHub.Domain/Events/EventManager.cs
  4. 2
      src/EventHub.Domain/Events/Registrations/EventRegistrationManager.cs
  5. 11
      src/EventHub.Domain/Organizations/Plans/FeatureOfPlanDefinition.cs
  6. 11
      src/EventHub.Domain/Organizations/Plans/IPlanInfoDefinitionStore.cs
  7. 34
      src/EventHub.Domain/Organizations/Plans/PlanFeatureManager.cs
  8. 6
      src/EventHub.Domain/Organizations/Plans/PlanInfoDefinition.cs
  9. 27
      src/EventHub.Domain/Organizations/Plans/PlanInfoDefinitionStore.cs
  10. 11
      src/EventHub.Domain/Organizations/Plans/PlanInfoOptions.cs
  11. 4
      test/EventHub.Domain.Tests/Events/Registrations/EventRegistrationManager_UnitTests.cs

13
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<OrganizationProfilePictureContainer> _organizationBlobContainer;
private readonly IUserRepository _userRepository;
private readonly IPlanInfoDefinitionStore _planInfoDefinitionStore;
private readonly IOptions<PlanInfoOptions> _planInfoOptions;
public OrganizationAppService(
IRepository<Organization, Guid> organizationRepository,
IOrganizationMembershipRepository organizationMembershipsRepository,
OrganizationManager organizationManager,
IBlobContainer<OrganizationProfilePictureContainer> organizationBlobContainer,
IUserRepository userRepository,
IPlanInfoDefinitionStore planInfoDefinitionStore)
IUserRepository userRepository,
IOptions<PlanInfoOptions> 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<List<PlanInfoDefinitionDto>> GetPlanInfosAsync()
{
var planInfoDefinitions = await _planInfoDefinitionStore.GetPlanInfosAsync();
return ObjectMapper.Map<List<PlanInfoDefinition>, List<PlanInfoDefinitionDto>>(planInfoDefinitions);
var planInfoDefinitions = _planInfoOptions.Value.GetPlanInfos();
return await Task.FromResult(ObjectMapper.Map<List<PlanInfoDefinition>, List<PlanInfoDefinitionDto>>(planInfoDefinitions));
}
private async Task SaveProfilePictureAsync(Guid id, IRemoteStreamContent streamContent)

24
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);

4
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);
}

2
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);
}

11
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<string> AdditionalFeatureInfos { get; set; }
public FeatureOfPlanDefinition()
{
AdditionalFeatureInfos = new List<string>();
}
}

11
src/EventHub.Domain/Organizations/Plans/IPlanInfoDefinitionStore.cs

@ -1,11 +0,0 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace EventHub.Organizations.Plans;
public interface IPlanInfoDefinitionStore
{
Task<List<PlanInfoDefinition>> GetPlanInfosAsync();
Task<PlanInfoDefinition> GetPlanInfoByTypeAsync(OrganizationPlanType type);
}

34
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> _planInfoOptions;
private readonly IRepository<Organization, Guid> _organizationRepository;
private readonly IRepository<Event, Guid> _eventRepository;
private readonly IEventRegistrationRepository _eventRegistrationRepository;
private readonly IClock _clock;
public PlanFeatureManager(
IPlanInfoDefinitionStore planInfoDefinitionStore,
IOptions<PlanInfoOptions> planInfoOptions,
IRepository<Organization, Guid> organizationRepository,
IRepository<Event, Guid> eventRepository,
IEventRegistrationRepository eventRegistrationRepository)
IEventRegistrationRepository eventRegistrationRepository,
IClock clock)
{
_planInfoDefinitionStore = planInfoDefinitionStore;
_planInfoOptions = planInfoOptions;
_organizationRepository = organizationRepository;
_eventRepository = eventRepository;
_eventRegistrationRepository = eventRegistrationRepository;
_clock = clock;
}
public virtual async Task<bool> CanCreateNewEvent(Guid organizationId)
public virtual async Task<bool> 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<bool> CanAddNewTrack(Event @event)
public virtual async Task<bool> 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<bool> CanRegisterToEvent(Event @event)
public virtual async Task<bool> 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<PlanInfoDefinition> GetCurrentPlanByOrganizationIdAsync(Guid organizationId)
{
var organization = await _organizationRepository.GetAsync(organizationId);
return await _planInfoDefinitionStore.GetPlanInfoByTypeAsync(organization.PlanType);
return _planInfoOptions.Value.GetPlanInfoByType(organization.PlanType);
}
}

6
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; }

27
src/EventHub.Domain/Organizations/Plans/PlanInfoDefinitionStore.cs

@ -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 = planInfoOptions.Value;
}
public async Task<List<PlanInfoDefinition>> GetPlanInfosAsync()
{
return await Task.FromResult(PlanInfoOptions.Infos);
}
public async Task<PlanInfoDefinition> GetPlanInfoByTypeAsync(OrganizationPlanType type)
{
return await Task.FromResult(PlanInfoOptions.Infos.SingleOrDefault(x => x.PlanType == type));
}
}

11
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<PlanInfoDefinition> GetPlanInfos()
{
return Infos.Where(x => x.IsActive).ToList();
}
public PlanInfoDefinition GetPlanInfoByType(OrganizationPlanType type)
{
return Infos.SingleOrDefault(x => x.IsActive && x.PlanType == type);
}
}

4
test/EventHub.Domain.Tests/Events/Registrations/EventRegistrationManager_UnitTests.cs

@ -58,8 +58,8 @@ namespace EventHub.Events.Registrations
var clock = Substitute.For<IClock>();
clock.Now.Returns(DateTime.Now);
var planFeatureManager = Substitute.For<PlanFeatureManager>(null, null, null, null);
planFeatureManager.CanRegisterToEvent(@event).Returns(Task.FromResult(true));
var planFeatureManager = Substitute.For<PlanFeatureManager>(null, null, null, null, null);
planFeatureManager.CanRegisterToEventAsync(@event).Returns(Task.FromResult(true));
var registrationManager = new EventRegistrationManager(
repository, guidGenerator, clock, planFeatureManager

Loading…
Cancel
Save