Browse Source

feat: add feature rules to event by organization plan type

pull/90/head
berkansasmaz 5 years ago
parent
commit
1327f4c678
No known key found for this signature in database GPG Key ID: 884D815C3F32BE00
  1. 2
      src/EventHub.Application.Contracts/Organizations/OrganizationInListDto.cs
  2. 6
      src/EventHub.Application.Contracts/Organizations/OrganizationProfileDto.cs
  3. 2
      src/EventHub.Application.Contracts/Organizations/PlanInfoDefinitionDto.cs
  4. 2
      src/EventHub.Application/EventHubApplicationAutoMapperProfile.cs
  5. 5
      src/EventHub.Application/Events/EventAppService.cs
  6. 5
      src/EventHub.Application/Organizations/OrganizationAppService.cs
  7. 2
      src/EventHub.BackgroundServices/EventHubBackgroundServicesModule.cs
  8. 32
      src/EventHub.BackgroundServices/Organizations/OrganizationPaidEnrollmentEndDateWorker.cs
  9. 20
      src/EventHub.BackgroundServices/Organizations/OrganizationPlanEndDateNotifier.cs
  10. 4
      src/EventHub.Domain.Shared/EventHubErrorCodes.cs
  11. 5
      src/EventHub.Domain.Shared/Localization/EventHub/en.json
  12. 2
      src/EventHub.Domain.Shared/Organizations/OrganizationPlanType.cs
  13. 6
      src/EventHub.Domain/Emailing/EmailTemplateDefinitionProvider.cs
  14. 4
      src/EventHub.Domain/Emailing/EmailTemplates.cs
  15. 0
      src/EventHub.Domain/Emailing/Templates/PaidEnrollmentEndDateReminder.tpl
  16. 2
      src/EventHub.Domain/Events/Event.cs
  17. 25
      src/EventHub.Domain/Events/EventManager.cs
  18. 11
      src/EventHub.Domain/Events/Registrations/EventRegistrationManager.cs
  19. 35
      src/EventHub.Domain/Organizations/Organization.cs
  20. 6
      src/EventHub.Domain/Organizations/PaymentRequests/PaymentRequestEventHandler.cs
  21. 2
      src/EventHub.Domain/Organizations/Plans/FeatureOfPlanDefinition.cs
  22. 4
      src/EventHub.Domain/Organizations/Plans/IPlanInfoDefinitionStore.cs
  23. 61
      src/EventHub.Domain/Organizations/Plans/PlanFeatureManager.cs
  24. 14
      src/EventHub.Domain/Organizations/Plans/PlanInfoDefinition.cs
  25. 12
      src/EventHub.Domain/Organizations/Plans/PlanInfoDefinitionStore.cs
  26. 2
      src/EventHub.Domain/Organizations/Plans/PlanInfoOptions.cs
  27. 2831
      src/EventHub.EntityFrameworkCore/Migrations/20220204083359_Updated_Organization.Designer.cs
  28. 57
      src/EventHub.EntityFrameworkCore/Migrations/20220204083359_Updated_Organization.cs
  29. 12
      src/EventHub.EntityFrameworkCore/Migrations/EventHubDbContextModelSnapshot.cs
  30. 5
      src/EventHub.HttpApi.Host/EventHubHttpApiHostModule.cs
  31. 2
      src/EventHub.HttpApi.Host/appsettings.json
  32. 7
      src/EventHub.Web/Pages/Organizations/Components/OrganizationsArea/_organizationListSection.cshtml
  33. 86
      src/EventHub.Web/Pages/Organizations/Components/_upgradeOrExtendOrganizationSection.cshtml
  34. 5
      src/EventHub.Web/Pages/Organizations/PlanInfoHelper.cs
  35. 5
      src/EventHub.Web/Pages/Organizations/Profile.cshtml
  36. 2
      src/EventHub.Web/Pages/Organizations/Profile.js
  37. 5
      src/EventHub.Web/Pages/Payment/PreCheckout.cshtml
  38. 25
      src/EventHub.Web/Pages/Pricing.cshtml
  39. 13
      src/EventHub.Web/Pages/Pricing.cshtml.cs
  40. 6
      src/EventHub.Web/Pages/Pricing.css
  41. 8
      test/EventHub.Domain.Tests/Events/Registrations/EventRegistrationManager_UnitTests.cs

2
src/EventHub.Application.Contracts/Organizations/OrganizationInListDto.cs

@ -11,6 +11,6 @@ namespace EventHub.Organizations
public string Description { get; set; }
public bool IsPremium { get; set; }
public OrganizationPlanType PlanType { get; set; }
}
}

6
src/EventHub.Application.Contracts/Organizations/OrganizationProfileDto.cs

@ -27,8 +27,8 @@ namespace EventHub.Organizations
public string MediumUsername { get; set; }
public bool IsPremium { get; set; }
public DateTime? PremiumEndDate { get; set; }
public OrganizationPlanType PlanType { get; set; }
public DateTime? PaidEnrollmentEndDate { get; set; }
}
}

2
src/EventHub.Application.Contracts/Organizations/PlanInfoDefinitionDto.cs

@ -14,7 +14,7 @@ public class PlanInfoDefinitionDto
public int? CanBeExtendedAfterHowManyMonths { get; set; }
public int? OnePremiumPeriodAsMonth { get; set; }
public int? OnePaidEnrollmentPeriodAsMonth { get; set; }
public FeatureOfPlanDefinitionDto Feature { get; set; }

2
src/EventHub.Application/EventHubApplicationAutoMapperProfile.cs

@ -5,7 +5,7 @@ using EventHub.Events.Registrations;
using EventHub.Members;
using EventHub.Organizations;
using EventHub.Organizations.Memberships;
using EventHub.Organizations.PaymentRequests;
using EventHub.Organizations.Plans;
using EventHub.Users;
using Volo.Abp.AutoMapper;
using Volo.Abp.Identity;

5
src/EventHub.Application/Events/EventAppService.cs

@ -299,10 +299,7 @@ namespace EventHub.Events
var @event = await _eventRepository.GetAsync(id, true);
await CheckIfValidOwnerAsync(@event);
@event.AddTrack(
GuidGenerator.Create(),
input.Name
);
await _eventManager.AddTrackAsync(@event, input.Name);
await _eventRepository.UpdateAsync(@event);
}

5
src/EventHub.Application/Organizations/OrganizationAppService.cs

@ -4,6 +4,7 @@ using System.Linq;
using System.Threading.Tasks;
using EventHub.Organizations.Memberships;
using EventHub.Organizations.PaymentRequests;
using EventHub.Organizations.Plans;
using EventHub.Users;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Application.Dtos;
@ -170,8 +171,8 @@ namespace EventHub.Organizations
[Authorize]
public async Task<List<PlanInfoDefinitionDto>> GetPlanInfosAsync()
{
var dd = await _planInfoDefinitionStore.GetPlanInfosAsync();
return ObjectMapper.Map<List<PlanInfoDefinition>, List<PlanInfoDefinitionDto>>(dd);
var planInfoDefinitions = await _planInfoDefinitionStore.GetPlanInfosAsync();
return ObjectMapper.Map<List<PlanInfoDefinition>, List<PlanInfoDefinitionDto>>(planInfoDefinitions);
}
private async Task SaveProfilePictureAsync(Guid id, IRemoteStreamContent streamContent)

2
src/EventHub.BackgroundServices/EventHubBackgroundServicesModule.cs

@ -47,7 +47,7 @@ namespace EventHub
context.AddBackgroundWorker<NewEventWorker>();
context.AddBackgroundWorker<EventTimingChangeWorker>();
context.AddBackgroundWorker<OrganizationPremiumEndDateWorker>();
context.AddBackgroundWorker<OrganizationPaidEnrollmentEndDateWorker>();
}
}
}

32
src/EventHub.BackgroundServices/Organizations/OrganizationPremiumEndDateWorker.cs → src/EventHub.BackgroundServices/Organizations/OrganizationPaidEnrollmentEndDateWorker.cs

@ -12,9 +12,9 @@ using Volo.Abp.Uow;
namespace EventHub.Organizations
{
public class OrganizationPremiumEndDateWorker : AsyncPeriodicBackgroundWorkerBase
public class OrganizationPaidEnrollmentEndDateWorker : AsyncPeriodicBackgroundWorkerBase
{
public OrganizationPremiumEndDateWorker(AbpAsyncTimer timer, IServiceScopeFactory serviceScopeFactory) : base(timer, serviceScopeFactory)
public OrganizationPaidEnrollmentEndDateWorker(AbpAsyncTimer timer, IServiceScopeFactory serviceScopeFactory) : base(timer, serviceScopeFactory)
{
Timer.Period = (int)TimeSpan.FromDays(1).TotalMilliseconds;
}
@ -22,26 +22,26 @@ namespace EventHub.Organizations
[UnitOfWork(isTransactional: false)]
protected override async Task DoWorkAsync(PeriodicBackgroundWorkerContext workerContext)
{
var organizationPremiumEndDateNotifier = workerContext.ServiceProvider.GetRequiredService<OrganizationPremiumEndDateNotifier>();
var organizationPaidEnrollmentEndDateNotifier = workerContext.ServiceProvider.GetRequiredService<OrganizationPlanEndDateNotifier>();
var organizationRepository = workerContext.ServiceProvider.GetRequiredService<IRepository<Organization, Guid>>();
var asyncExecuter = workerContext.ServiceProvider.GetRequiredService<IAsyncQueryableExecuter>();
var clock = workerContext.ServiceProvider.GetRequiredService<IClock>();
await SendPremiumReminderEmail(organizationRepository, organizationPremiumEndDateNotifier, asyncExecuter, clock);
await SendPremiumReminderEmail(organizationRepository, organizationPaidEnrollmentEndDateNotifier, asyncExecuter, clock);
await UpdatePremiumExpiredOrganization(organizationRepository, asyncExecuter, clock);
}
private async Task SendPremiumReminderEmail(
IRepository<Organization, Guid> organizationRepository,
OrganizationPremiumEndDateNotifier organizationPremiumEndDateNotifier,
OrganizationPlanEndDateNotifier organizationPlanEndDateNotifier,
IAsyncQueryableExecuter asyncExecuter,
IClock clock)
{
var oneMonthLater = clock.Now.AddMonths(1);
var queryable = await organizationRepository.GetQueryableAsync();
var query = queryable.Where(x =>
x.IsSendPremiumReminderEmail == false &&
x.PremiumEndDate <= oneMonthLater
x.IsSendPaidEnrollmentReminderEmail == false &&
x.PaidEnrollmentEndDate <= oneMonthLater
);
var organizations = await asyncExecuter.ToListAsync(query);
@ -50,14 +50,14 @@ namespace EventHub.Organizations
{
try
{
if (organization.IsPremium)
if (organization.PlanType != OrganizationPlanType.Free)
{
if (organization.PremiumEndDate >= clock.Now)
if (organization.PaidEnrollmentEndDate >= clock.Now)
{
await organizationPremiumEndDateNotifier.NotifyAsync(organization);
await organizationPlanEndDateNotifier.NotifyAsync(organization);
}
organization.IsSendPremiumReminderEmail = true;
organization.IsSendPaidEnrollmentReminderEmail = true;
await organizationRepository.UpdateAsync(organization);
}
}
@ -72,7 +72,7 @@ namespace EventHub.Organizations
{
var queryable = await organizationRepository.GetQueryableAsync();
var query = queryable.Where(x =>
x.PremiumEndDate >= clock.Now
x.PaidEnrollmentEndDate >= clock.Now
);
var organizations = await asyncExecuter.ToListAsync(query);
@ -81,13 +81,13 @@ namespace EventHub.Organizations
{
try
{
if (!organization.IsPremium)
if (organization.PlanType == OrganizationPlanType.Free)
{
continue;
}
organization.DowngradeToPremium();
organization.IsSendPremiumReminderEmail = false;
organization.SetFreeToPlanType();
organization.IsSendPaidEnrollmentReminderEmail = false;
await organizationRepository.UpdateAsync(organization);
}
catch (Exception ex)
@ -97,4 +97,4 @@ namespace EventHub.Organizations
}
}
}
}
}

20
src/EventHub.BackgroundServices/Organizations/OrganizationPremiumEndDateNotifier.cs → src/EventHub.BackgroundServices/Organizations/OrganizationPlanEndDateNotifier.cs

@ -10,18 +10,18 @@ using Volo.Abp.TextTemplating;
namespace EventHub.Organizations
{
public class OrganizationPremiumEndDateNotifier : ITransientDependency
public class OrganizationPlanEndDateNotifier : ITransientDependency
{
private readonly IEmailSender _emailSender;
private readonly ITemplateRenderer _templateRenderer;
private readonly IRepository<IdentityUser, Guid> _userRepository;
private readonly ILogger<OrganizationPremiumEndDateNotifier> _logger;
private readonly ILogger<OrganizationPlanEndDateNotifier> _logger;
public OrganizationPremiumEndDateNotifier(
public OrganizationPlanEndDateNotifier(
IEmailSender emailSender,
ITemplateRenderer templateRenderer,
IRepository<IdentityUser, Guid> userRepository,
ILogger<OrganizationPremiumEndDateNotifier> logger)
ILogger<OrganizationPlanEndDateNotifier> logger)
{
_emailSender = emailSender;
_templateRenderer = templateRenderer;
@ -31,7 +31,7 @@ namespace EventHub.Organizations
public async Task NotifyAsync(Organization organization)
{
if (organization is null || organization.IsSendPremiumReminderEmail || !organization.IsPremium)
if (organization is null || organization.IsSendPaidEnrollmentReminderEmail || organization.PlanType != OrganizationPlanType.Free)
{
return;
}
@ -39,21 +39,21 @@ namespace EventHub.Organizations
var user = await _userRepository.FindAsync(organization.OwnerUserId);
if (user is null)
{
_logger.LogError("(OrganizationPremiumEndDateNotifier) User not found!");
_logger.LogError("(OrganizationPaidEnrollmentEndDateNotifier) User not found!");
return;
}
var templateModel = new
{
OrganizationName = organization.Name,
EndDate = organization.PremiumEndDate!.Value.ToShortDateString()
EndDate = organization.PaidEnrollmentEndDate!.Value.ToShortDateString()
};
await _emailSender.SendAsync(
user.Email,
"EventHub: Your Premium Organization is expiring!",
await _templateRenderer.RenderAsync(EmailTemplates.PremiumEndDateReminder, templateModel)
"EventHub: Your" + organization.PlanType + "Organization is expiring!",
await _templateRenderer.RenderAsync(EmailTemplates.PaidEnrollmentEndDateReminder, templateModel)
);
}
}
}
}

4
src/EventHub.Domain.Shared/EventHubErrorCodes.cs

@ -20,6 +20,8 @@
public const string TrackNotFound = "EventHub:TrackNotFound";
public const string SessionNotFound = "EventHub:SessionNotFound";
public const string SessionTitleAlreadyExist = "EventHub:SessionTitleAlreadyExist";
public const string CannotCreateNewEvent = "EventHub:CannotCreateNewEvent";
public const string CannotAddNewTrack = "EventHub:CannotAddNewTrack";
public const string CannotRegisterToEvent = "EventHub:CannotRegisterToEvent";
}
}

5
src/EventHub.Domain.Shared/Localization/EventHub/en.json

@ -158,6 +158,9 @@
"EventHub:SessionNotFound": "The session not found!",
"EventHub:SessionTimeShouldBeInTheEventTime": "Session time should be in the event time!",
"EventHub:SessionTimeConflictsWithAnExistingSession": "Session time conflicts with an existing session!",
"EventHub:SessionTitleAlreadyExist": "The session {Title} already exists"
"EventHub:SessionTitleAlreadyExist": "The session {Title} already exists",
"EventHub:CannotCreateNewEvent": "Cannot create a new event, you need to upgrade your organization!",
"EventHub:CannotAddNewTrack": "Cannot add a new track, you need to upgrade your organization!",
"EventHub:CannotRegisterToEvent": "The maximum number of participants allowed by the organization has been reached!"
}
}

2
src/EventHub.Domain.Shared/Organizations/OrganizationPlanType.cs

@ -3,6 +3,6 @@ namespace EventHub.Organizations
public enum OrganizationPlanType : byte
{
Free = 0,
Premium
Premium,
}
}

6
src/EventHub.Domain/Emailing/EmailTemplateDefinitionProvider.cs

@ -76,12 +76,12 @@ namespace EventHub.Emailing
context.Add(
new TemplateDefinition(
EmailTemplates.PremiumEndDateReminder)
EmailTemplates.PaidEnrollmentEndDateReminder)
.WithVirtualFilePath(
"/Emailing/Templates/PremiumEndDateReminder.tpl",
"/Emailing/Templates/PaidEnrollmentEndDateReminder.tpl",
isInlineLocalized: true
)
);
}
}
}
}

4
src/EventHub.Domain/Emailing/EmailTemplates.cs

@ -16,6 +16,6 @@ namespace EventHub.Emailing
public const string PaymentRequestFailed = "EventHub.Organization.PaymentRequestFailed";
public const string PremiumEndDateReminder = "EventHub.Organization.PremiumEndDateReminder";
public const string PaidEnrollmentEndDateReminder = "EventHub.Organization.PaidEnrollmentEndDateReminder";
}
}
}

0
src/EventHub.Domain/Emailing/Templates/PremiumEndDateReminder.tpl → src/EventHub.Domain/Emailing/Templates/PaidEnrollmentEndDateReminder.tpl

2
src/EventHub.Domain/Events/Event.cs

@ -129,7 +129,7 @@ namespace EventHub.Events
return this;
}
public Event AddTrack(Guid trackId, string name)
internal Event AddTrack(Guid trackId, string name)
{
if (Tracks.Any(x => x.Name == name))
{

25
src/EventHub.Domain/Events/EventManager.cs

@ -3,6 +3,7 @@ using System.Threading.Tasks;
using EventHub.Countries;
using EventHub.Events.Registrations;
using EventHub.Organizations;
using EventHub.Organizations.Plans;
using Volo.Abp;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Domain.Services;
@ -14,15 +15,17 @@ namespace EventHub.Events
private readonly EventUrlCodeGenerator _eventUrlCodeGenerator;
private readonly IRepository<EventRegistration, Guid> _eventRegistrationRepository;
private readonly IRepository<Country, Guid> _countriesRepository;
private readonly PlanFeatureManager _planFeatureManager;
public EventManager(
EventUrlCodeGenerator eventUrlCodeGenerator,
IRepository<EventRegistration, Guid> eventRegistrationRepository,
IRepository<Country, Guid> countriesRepository)
IRepository<Country, Guid> countriesRepository,
PlanFeatureManager planFeatureManager)
{
_eventUrlCodeGenerator = eventUrlCodeGenerator;
_eventRegistrationRepository = eventRegistrationRepository;
_countriesRepository = countriesRepository;
_planFeatureManager = planFeatureManager;
}
public async Task<Event> CreateAsync(
@ -32,6 +35,11 @@ namespace EventHub.Events
DateTime endTime,
string description)
{
if (!await _planFeatureManager.CanCreateNewEvent(organization.Id))
{
throw new BusinessException(EventHubErrorCodes.CannotCreateNewEvent);
}
return new Event(
GuidGenerator.Create(),
organization.Id,
@ -42,6 +50,19 @@ namespace EventHub.Events
description
);
}
public async Task AddTrackAsync(Event @event, string name)
{
if (!await _planFeatureManager.CanAddNewTrack(@event))
{
throw new BusinessException(EventHubErrorCodes.CannotAddNewTrack);
}
@event.AddTrack(
GuidGenerator.Create(),
name
);
}
public async Task SetCapacityAsync(
Event @event,

11
src/EventHub.Domain/Events/Registrations/EventRegistrationManager.cs

@ -1,4 +1,5 @@
using System.Threading.Tasks;
using EventHub.Organizations.Plans;
using Volo.Abp;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Domain.Services;
@ -13,15 +14,18 @@ namespace EventHub.Events.Registrations
private readonly IEventRegistrationRepository _eventRegistrationRepository;
private readonly IGuidGenerator _guidGenerator;
private readonly IClock _clock;
private readonly PlanFeatureManager _planFeatureManager;
public EventRegistrationManager(
IEventRegistrationRepository eventRegistrationRepository,
IGuidGenerator guidGenerator,
IClock clock)
IClock clock,
PlanFeatureManager planFeatureManager)
{
_eventRegistrationRepository = eventRegistrationRepository;
_guidGenerator = guidGenerator;
_clock = clock;
_planFeatureManager = planFeatureManager;
}
public async Task RegisterAsync(
@ -47,6 +51,11 @@ namespace EventHub.Events.Registrations
.WithData("EventTitle", @event.Title);
}
}
if (!await _planFeatureManager.CanRegisterToEvent(@event))
{
throw new BusinessException(EventHubErrorCodes.CannotRegisterToEvent);
}
await _eventRegistrationRepository.InsertAsync(
new EventRegistration(

35
src/EventHub.Domain/Organizations/Organization.cs

@ -1,6 +1,8 @@
using System;
using JetBrains.Annotations;
using Volo.Abp;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.Validation;
namespace EventHub.Organizations
{
@ -28,11 +30,11 @@ namespace EventHub.Organizations
public int MemberCount { get; internal set; }
public bool IsPremium { get; private set; }
public OrganizationPlanType PlanType { get; private set; }
public DateTime? PremiumEndDate { get; private set; }
public DateTime? PaidEnrollmentEndDate { get; private set; }
public bool IsSendPremiumReminderEmail { get; set; }
public bool IsSendPaidEnrollmentReminderEmail { get; set; }
private Organization()
{
@ -50,6 +52,7 @@ namespace EventHub.Organizations
SetName(name);
SetDisplayName(displayName);
SetDescription(description);
SetFreeToPlanType();
}
internal Organization SetName(string name)
@ -70,38 +73,36 @@ namespace EventHub.Organizations
return this;
}
internal Organization UpgradeToPremium(DateTime endDate)
internal Organization UpgradeToPlanType(OrganizationPlanType planType, DateTime endDate)
{
SetPremiumStatus(true, endDate);
SetPlanType(planType, endDate);
return this;
}
public Organization DowngradeToPremium()
public Organization SetFreeToPlanType()
{
if (!IsPremium)
if (PlanType == OrganizationPlanType.Free)
{
return this;
}
SetPremiumStatus(false);
SetPlanType(OrganizationPlanType.Free, DateTime.Today);
return this;
}
private Organization SetPremiumStatus(bool isPremium, DateTime? endDate = null)
private Organization SetPlanType(OrganizationPlanType planType, DateTime endDate)
{
if (isPremium)
if (!Enum.IsDefined(typeof(OrganizationPlanType), planType))
{
Check.NotNull(endDate, nameof(endDate));
IsPremium = true;
PremiumEndDate = endDate;
return this;
throw new AbpValidationException();
}
IsPremium = false;
Check.NotNull(endDate, nameof(endDate));
PlanType = planType;
PaidEnrollmentEndDate = endDate;
return this;
}
}

6
src/EventHub.Domain/Organizations/PaymentRequests/PaymentRequestEventHandler.cs

@ -134,12 +134,12 @@ namespace EventHub.Organizations.PaymentRequests
if (organizationPaymentRequestExtraParameter.IsExtend)
{
organization.UpgradeToPremium(
organization.PremiumEndDate!.Value.AddMonths(organizationPaymentRequestExtraParameter.PremiumPeriodAsMonth!.Value));
organization.UpgradeToPlanType(organizationPaymentRequestExtraParameter.TargetPlanType,
organization.PaidEnrollmentEndDate!.Value.AddMonths(organizationPaymentRequestExtraParameter.PremiumPeriodAsMonth!.Value));
}
else
{
organization.UpgradeToPremium(DateTime.Now.AddMonths(organizationPaymentRequestExtraParameter.PremiumPeriodAsMonth!.Value));
organization.UpgradeToPlanType(organizationPaymentRequestExtraParameter.TargetPlanType, DateTime.Now.AddMonths(organizationPaymentRequestExtraParameter.PremiumPeriodAsMonth!.Value));
}
return await _organizationRepository.UpdateAsync(organization, true);

2
src/EventHub.Domain/Organizations/PaymentRequests/FeatureOfPlanDefinition.cs → src/EventHub.Domain/Organizations/Plans/FeatureOfPlanDefinition.cs

@ -2,7 +2,7 @@ using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using JetBrains.Annotations;
namespace EventHub.Organizations.PaymentRequests;
namespace EventHub.Organizations.Plans;
public class FeatureOfPlanDefinition
{

4
src/EventHub.Domain/Organizations/PaymentRequests/IPlanInfoDefinitionStore.cs → src/EventHub.Domain/Organizations/Plans/IPlanInfoDefinitionStore.cs

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

61
src/EventHub.Domain/Organizations/Plans/PlanFeatureManager.cs

@ -0,0 +1,61 @@
using System;
using System.Threading.Tasks;
using EventHub.Events;
using EventHub.Events.Registrations;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
namespace EventHub.Organizations.Plans;
public class PlanFeatureManager : ITransientDependency
{
private readonly IPlanInfoDefinitionStore _planInfoDefinitionStore;
private readonly IRepository<Organization, Guid> _organizationRepository;
private readonly IRepository<Event, Guid> _eventRepository;
private readonly IEventRegistrationRepository _eventRegistrationRepository;
public PlanFeatureManager(
IPlanInfoDefinitionStore planInfoDefinitionStore,
IRepository<Organization, Guid> organizationRepository,
IRepository<Event, Guid> eventRepository,
IEventRegistrationRepository eventRegistrationRepository)
{
_planInfoDefinitionStore = planInfoDefinitionStore;
_organizationRepository = organizationRepository;
_eventRepository = eventRepository;
_eventRegistrationRepository = eventRegistrationRepository;
}
public async Task<bool> CanCreateNewEvent(Guid organizationId)
{
var currentPlanOfOrganization = await GetCurrentPlanByOrganizationIdAsync(organizationId);
var totalEventCountByOrganization = await _eventRepository.CountAsync(x => x.OrganizationId == organizationId);
totalEventCountByOrganization++;
return currentPlanOfOrganization.Feature.MaxAllowedEventsCount >= totalEventCountByOrganization;
}
public async Task<bool> CanAddNewTrack(Event @event)
{
var currentPlanOfOrganization = await GetCurrentPlanByOrganizationIdAsync(@event.OrganizationId);
var tracksCount = @event.Tracks.Count;
tracksCount++;
return currentPlanOfOrganization.Feature.MaxAllowedTracksCountInOneEvent >= tracksCount;
}
public async Task<bool> CanRegisterToEvent(Event @event)
{
var currentPlanOfOrganization = await GetCurrentPlanByOrganizationIdAsync(@event.OrganizationId);
var attendeesCount = await _eventRegistrationRepository.CountAsync(x => x.EventId == @event.Id);
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);
}
}

14
src/EventHub.Domain/Organizations/PaymentRequests/PlanInfoDefinition.cs → src/EventHub.Domain/Organizations/Plans/PlanInfoDefinition.cs

@ -1,8 +1,9 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using JetBrains.Annotations;
namespace EventHub.Organizations.PaymentRequests;
namespace EventHub.Organizations.Plans;
public class PlanInfoDefinition
{
@ -25,13 +26,18 @@ public class PlanInfoDefinition
[CanBeNull]
[Range(1, 24, ErrorMessage = "Value for {0} must be between {1} and {2}.")]
public int? OnePremiumPeriodAsMonth { get; set; } = 12;
public int? OnePaidEnrollmentPeriodAsMonth { get; set; } = 12;
public FeatureOfPlanDefinition Feature { get; set; }
public PlanInfoDefinition()
{
Feature = new FeatureOfPlanDefinition();
Feature.AdditionalFeatureInfos = new List<string>();
Feature = new FeatureOfPlanDefinition
{
MaxAllowedEventsCount = uint.MaxValue,
MaxAllowedTracksCountInOneEvent = uint.MaxValue,
MaxAllowedAttendeesCountInOneEvent = uint.MaxValue,
AdditionalFeatureInfos = new List<string>()
};
}
}

12
src/EventHub.Domain/Organizations/PaymentRequests/PlanInfoDefinitionStore.cs → src/EventHub.Domain/Organizations/Plans/PlanInfoDefinitionStore.cs

@ -1,9 +1,10 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
namespace EventHub.Organizations.PaymentRequests;
namespace EventHub.Organizations.Plans;
public class PlanInfoDefinitionStore : IPlanInfoDefinitionStore, ITransientDependency
{
@ -14,8 +15,13 @@ public class PlanInfoDefinitionStore : IPlanInfoDefinitionStore, ITransientDepen
PlanInfoOptions = planInfoOptions.Value;
}
public Task<List<PlanInfoDefinition>> GetPlanInfosAsync()
public async Task<List<PlanInfoDefinition>> GetPlanInfosAsync()
{
return Task.FromResult(PlanInfoOptions.Infos);
return await Task.FromResult(PlanInfoOptions.Infos);
}
public async Task<PlanInfoDefinition> GetPlanInfoByTypeAsync(OrganizationPlanType type)
{
return await Task.FromResult(PlanInfoOptions.Infos.SingleOrDefault(x => x.PlanType == type));
}
}

2
src/EventHub.Domain/Organizations/PaymentRequests/PlanInfoOptions.cs → src/EventHub.Domain/Organizations/Plans/PlanInfoOptions.cs

@ -1,6 +1,6 @@
using System.Collections.Generic;
namespace EventHub.Organizations.PaymentRequests;
namespace EventHub.Organizations.Plans;
public class PlanInfoOptions
{

2831
src/EventHub.EntityFrameworkCore/Migrations/20220204083359_Updated_Organization.Designer.cs

File diff suppressed because it is too large

57
src/EventHub.EntityFrameworkCore/Migrations/20220204083359_Updated_Organization.cs

@ -0,0 +1,57 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace EventHub.Migrations
{
public partial class Updated_Organization : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "IsPremium",
table: "EhOrganizations");
migrationBuilder.RenameColumn(
name: "PremiumEndDate",
table: "EhOrganizations",
newName: "PaidEnrollmentEndDate");
migrationBuilder.RenameColumn(
name: "IsSendPremiumReminderEmail",
table: "EhOrganizations",
newName: "IsSendPaidEnrollmentReminderEmail");
migrationBuilder.AddColumn<byte>(
name: "PlanType",
table: "EhOrganizations",
type: "smallint",
nullable: false,
defaultValue: (byte)0);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "PlanType",
table: "EhOrganizations");
migrationBuilder.RenameColumn(
name: "PaidEnrollmentEndDate",
table: "EhOrganizations",
newName: "PremiumEndDate");
migrationBuilder.RenameColumn(
name: "IsSendPaidEnrollmentReminderEmail",
table: "EhOrganizations",
newName: "IsSendPremiumReminderEmail");
migrationBuilder.AddColumn<bool>(
name: "IsPremium",
table: "EhOrganizations",
type: "boolean",
nullable: false,
defaultValue: false);
}
}
}

12
src/EventHub.EntityFrameworkCore/Migrations/EventHubDbContextModelSnapshot.cs

@ -19,7 +19,7 @@ namespace EventHub.Migrations
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql)
.HasAnnotation("ProductVersion", "6.0.0")
.HasAnnotation("ProductVersion", "6.0.1")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
@ -376,10 +376,7 @@ namespace EventHub.Migrations
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<bool>("IsPremium")
.HasColumnType("boolean");
b.Property<bool>("IsSendPremiumReminderEmail")
b.Property<bool>("IsSendPaidEnrollmentReminderEmail")
.HasColumnType("boolean");
b.Property<DateTime?>("LastModificationTime")
@ -404,9 +401,12 @@ namespace EventHub.Migrations
b.Property<Guid>("OwnerUserId")
.HasColumnType("uuid");
b.Property<DateTime?>("PremiumEndDate")
b.Property<DateTime?>("PaidEnrollmentEndDate")
.HasColumnType("timestamp with time zone");
b.Property<byte>("PlanType")
.HasColumnType("smallint");
b.Property<string>("TwitterUsername")
.HasColumnType("text");

5
src/EventHub.HttpApi.Host/EventHubHttpApiHostModule.cs

@ -7,6 +7,7 @@ using EventHub.EntityFrameworkCore;
using EventHub.Events;
using EventHub.Organizations;
using EventHub.Organizations.PaymentRequests;
using EventHub.Organizations.Plans;
using EventHub.Utils;
using EventHub.Web;
using Microsoft.AspNetCore.Authentication.JwtBearer;
@ -219,9 +220,9 @@ namespace EventHub
if (config.IsActive && config.IsExtendable)
{
Check.NotNull(config.OnePremiumPeriodAsMonth, nameof(config.OnePremiumPeriodAsMonth));
Check.NotNull(config.OnePaidEnrollmentPeriodAsMonth, nameof(config.OnePaidEnrollmentPeriodAsMonth));
Check.NotNull(config.CanBeExtendedAfterHowManyMonths, nameof(config.CanBeExtendedAfterHowManyMonths));
return config.OnePremiumPeriodAsMonth > config.CanBeExtendedAfterHowManyMonths;
return config.OnePaidEnrollmentPeriodAsMonth > config.CanBeExtendedAfterHowManyMonths;
}
}

2
src/EventHub.HttpApi.Host/appsettings.json

@ -39,7 +39,7 @@
"Price": 29.90,
"IsExtendable": true,
"CanBeExtendedAfterHowManyMonths": 9,
"OnePremiumPeriodAsMonth": 12,
"OnePaidEnrollmentPeriodAsMonth": 12,
"Feature": {
"AdditionalFeatureInfos": [
"Be more prominent in the organization list.",

7
src/EventHub.Web/Pages/Organizations/Components/OrganizationsArea/_organizationListSection.cshtml

@ -1,3 +1,4 @@
@using EventHub.Organizations
@using EventHub.Web
@using Microsoft.Extensions.Options
@model List<EventHub.Organizations.OrganizationInListDto>
@ -14,9 +15,9 @@
<div class="event-info">
<h5>
@organization.DisplayName
@if (organization.IsPremium)
@if (organization.PlanType != OrganizationPlanType.Free)
{
<span class="align-top text-dark font-weight-bold" style="font-size: x-small" abp-badge-pill="Warning"> Premium </span>
<span class="align-top text-dark font-weight-bold" style="font-size: x-small" abp-badge-pill="Warning"> @organization.PlanType </span>
}
</h5>
@ -29,4 +30,4 @@
</div>
</div>
</div>
}
}

86
src/EventHub.Web/Pages/Organizations/Components/_upgradeOrExtendOrganizationSection.cshtml

@ -3,57 +3,65 @@
@inject IOrganizationAppService OrganizationAppService
@{
var premiumPlanInfo = (await OrganizationAppService.GetPlanInfosAsync()).MaxBy(x => x.Price)!;
PlanInfoDefinitionDto currentPlanInfo = null;
if (Model is not null)
{
var planInfos = await OrganizationAppService.GetPlanInfosAsync();
currentPlanInfo = planInfos.SingleOrDefault(x => x.PlanType == Model.PlanType);
}
}
<abp-container class="mt-4">
<abp-row>
@if (Model.IsPremium && premiumPlanInfo.IsActive && premiumPlanInfo.IsExtendable && Model.PremiumEndDate!.Value.IsBetween(DateTime.Now, DateTime.Now.AddMonths(premiumPlanInfo.OnePremiumPeriodAsMonth!.Value - premiumPlanInfo.CanBeExtendedAfterHowManyMonths!.Value)))
{
<span class="mb-2 ms-5 text-center strong">Premium end date: @Model.PremiumEndDate!.Value.ToShortDateString()</span>
}
<abp-column>
<a href="/organization/edit/@Model.Name" class="btn btn-success text-white">Edit</a>
</abp-column>
<abp-column size="_9">
@if (premiumPlanInfo.IsActive)
@if (Model is not null && currentPlanInfo is not null)
{
<abp-container class="mt-4">
<abp-row>
@if (Model.PlanType != OrganizationPlanType.Free && currentPlanInfo.IsActive && currentPlanInfo.IsExtendable && Model.PaidEnrollmentEndDate!.Value.IsBetween(DateTime.Now, DateTime.Now.AddMonths(currentPlanInfo.OnePaidEnrollmentPeriodAsMonth!.Value - currentPlanInfo.CanBeExtendedAfterHowManyMonths!.Value)))
{
@if (Model.IsPremium)
<span class="mb-2 ms-5 text-center strong">@Model.PlanType end date: @Model.PaidEnrollmentEndDate!.Value.ToShortDateString()</span>
}
<abp-column>
<a href="/organization/edit/@Model.Name" class="btn btn-success text-white">Edit</a>
</abp-column>
<abp-column size="_9">
@if (currentPlanInfo.IsActive)
{
@if (premiumPlanInfo.IsExtendable && Model.PremiumEndDate!.Value.IsBetween(DateTime.Now, DateTime.Now.AddMonths(premiumPlanInfo.OnePremiumPeriodAsMonth!.Value - premiumPlanInfo.CanBeExtendedAfterHowManyMonths!.Value)))
@if (Model.PlanType != OrganizationPlanType.Free)
{
<div class="d-grid gap-2">
<a href="@Url.Page("/Pricing", new { organizationName = Model.Name })" class="btn btn-info">
<i class="fas fa-crown me-2"></i> Extend Now
</a>
</div>
@if (currentPlanInfo.IsExtendable && Model.PaidEnrollmentEndDate!.Value.IsBetween(DateTime.Now, DateTime.Now.AddMonths(currentPlanInfo.OnePaidEnrollmentPeriodAsMonth!.Value - currentPlanInfo.CanBeExtendedAfterHowManyMonths!.Value)))
{
<div class="d-grid gap-2">
<a href="@Url.Page("/Pricing", new { organizationName = Model.Name })" class="btn btn-info">
<i class="fas fa-crown me-2"></i> Extend Now
</a>
</div>
}
else
{
<div class="d-grid gap-2">
<button class="btn btn-info">
<span class="mt-2">@Model.PlanType end date: @Model.PaidEnrollmentEndDate!.Value.ToShortDateString()</span>
</button>
</div>
}
}
else
{
<div class="d-grid gap-2">
<button class="btn btn-info">
<span class="mt-2">Premium end date: @Model.PremiumEndDate!.Value.ToShortDateString()</span>
</button>
<a href="@Url.Page("/Pricing", new { organizationName = Model.Name })" class="btn btn-info">
<i class="fas fa-crown me-2"></i> Upgrade your organization
</a>
</div>
}
}
else
{
<div class="d-grid gap-2">
<a href="@Url.Page("/Pricing", new { organizationName = Model.Name })" class="btn btn-info">
<i class="fas fa-crown me-2"></i> Upgrade To @premiumPlanInfo.PlanType
</a>
</div>
<abp-card class="text-center">
<abp-card-body>
<span>@Model.PlanType end date: @Model.PaidEnrollmentEndDate!.Value.ToShortDateString()</span>
</abp-card-body>
</abp-card>
}
}
else
{
<abp-card class="text-center">
<abp-card-body>
<span>Premium end date: @Model.PremiumEndDate!.Value.ToShortDateString()</span>
</abp-card-body>
</abp-card>
}
</abp-column>
</abp-row>
</abp-container>
</abp-column>
</abp-row>
</abp-container>
}

5
src/EventHub.Web/Pages/Payment/PlanInfoHelper.cs → src/EventHub.Web/Pages/Organizations/PlanInfoHelper.cs

@ -4,7 +4,7 @@ using System.Text;
using EventHub.Organizations;
using Volo.Abp;
namespace EventHub.Web.Pages.Payment;
namespace EventHub.Web.Pages.Organizations;
public static class PlanInfoHelper
{
@ -68,6 +68,7 @@ public static class PlanInfoHelper
public static string GetRestrictionInfoByCount(uint? count)
{
return count is null ? "Unlimited" : count.ToString();
count ??= uint.MaxValue;
return count == uint.MaxValue ? "Unlimited" : count.ToString();
}
}

5
src/EventHub.Web/Pages/Organizations/Profile.cshtml

@ -1,6 +1,7 @@
@page "/organizations/{name}"
@inject IHtmlLocalizer<EventHubResource> L
@using EventHub.Localization
@using EventHub.Organizations
@using EventHub.Web
@using EventHub.Web.Pages.Events.Components.EventsArea
@using EventHub.Web.Pages.Organizations.Components.JoinArea
@ -47,9 +48,9 @@
<div class="col-md-7">
<h5 class="detail-head mt-3 font-weight-bold">
@Model.Organization.DisplayName
@if (Model.Organization.IsPremium)
@if (Model.Organization.PlanType != OrganizationPlanType.Free)
{
<span class="align-top text-dark font-weight-bold" style="font-size: x-small" abp-badge-pill="Warning"> Premium </span>
<span class="align-top text-dark font-weight-bold" style="font-size: x-small" abp-badge-pill="Warning"> @Model.Organization.PlanType </span>
}
</h5>
<p>

2
src/EventHub.Web/Pages/Organizations/Profile.js

@ -20,7 +20,7 @@ $(function () {
if (r.extraProperties.Status === "COMPLETED") {
Swal.fire({
title: 'Thank you for your purchase!',
text: 'Your Organization has been upgraded to Premium.',
text: 'Your Organization has been upgraded.',
imageUrl: '/assets/success.svg',
imageHeight: "70",
imageWidth: "70",

5
src/EventHub.Web/Pages/Payment/PreCheckout.cshtml

@ -1,6 +1,7 @@
@page
@inherits Payment.Web.Pages.PaymentPageBase
@using EventHub.Organizations
@using EventHub.Web.Pages.Organizations
@using EventHub.Web.Pages.Payment
@using Microsoft.AspNetCore.Http
@using Newtonsoft.Json
@ -40,11 +41,11 @@
@if (!organizationPaymentRequestExtraParameterConfiguration.IsExtend && planInfo.IsExtendable)
{
<p>Start Date: <span class="text-dark">@DateTime.Now.ToShortDateString()</span></p>
<p>End Date: <span class="text-dark">@DateTime.Now.AddMonths(planInfo.OnePremiumPeriodAsMonth!.Value).ToShortDateString()</span></p>
<p>End Date: <span class="text-dark">@DateTime.Now.AddMonths(planInfo.OnePaidEnrollmentPeriodAsMonth!.Value).ToShortDateString()</span></p>
}
else
{
<p>Your license will be extended for <span class="text-dark">@planInfo.OnePremiumPeriodAsMonth!.Value</span> months.</p>
<p>Your license will be extended for <span class="text-dark">@planInfo.OnePaidEnrollmentPeriodAsMonth!.Value</span> months.</p>
}
</div>
</div>

25
src/EventHub.Web/Pages/Pricing.cshtml

@ -1,6 +1,6 @@
@page "/pricing/{organizationName}"
@using EventHub.Localization
@using EventHub.Web.Pages.Payment
@using EventHub.Web.Pages.Organizations
@using Microsoft.AspNetCore.Mvc.Localization
@model EventHub.Web.Pages.Pricing
@inject IHtmlLocalizer<EventHubResource> L
@ -16,7 +16,7 @@
@foreach (var plan in Model.PlanInfos)
{
<div class="col-md-6">
<div class="card">
<div class="card plan-card">
<div class="card-body px-4 py-4 text-center">
<h2 class="mt-4">@plan.PlanType Account</h2>
<p class="my-4">@L[plan.Description]</p>
@ -33,9 +33,9 @@
<li><i class="fa fa-check-circle"></i> @additionalFeatureInfo </li>
}
</ul>
@if (Model.Organization.IsPremium && plan.Price > 0)
@if (Model.Organization.PlanType == plan.PlanType && plan.Price > 0)
{
<form id="Extend" method="post" asp-page-handler="ExtendToPremium">
<form id="Extend" method="post" asp-page-handler="Extend">
<abp-input asp-for="TargetPlanToUpgrade" value="@plan.PlanType"></abp-input>
<abp-input asp-for="OrganizationName"></abp-input>
<a onclick="document.getElementById('Extend').submit()" class="btn btn-info my-4"><i class="fas fa-crown me-2"></i> Extend Now</a>
@ -43,10 +43,10 @@
}
else if (plan.IsExtendable)
{
<form id="Upgrade" method="post" asp-page-handler="UpgradeToPremium">
<form id="Upgrade-@plan.PlanType" method="post" asp-page-handler="Upgrade">
<abp-input asp-for="TargetPlanToUpgrade" value="@plan.PlanType"></abp-input>
<abp-input asp-for="OrganizationName"></abp-input>
<a onclick="document.getElementById('Upgrade').submit()" class="btn btn-info my-4"><i class="fas fa-crown me-2"></i> Upgrade to @plan.PlanType</a>
<a onclick="document.getElementById('Upgrade-@plan.PlanType').submit()" class="btn btn-info my-4"><i class="fas fa-crown me-2"></i> Upgrade to @plan.PlanType</a>
</form>
}
</div>
@ -65,8 +65,15 @@
{
@if (plan.IsExtendable)
{
var canExtendBeforeHowManyMonths = plan!.OnePremiumPeriodAsMonth - plan!.CanBeExtendedAfterHowManyMonths;
<p>For @plan.PlanType, @(canExtendBeforeHowManyMonths == plan!.OnePremiumPeriodAsMonth ? "You " : "in the last " + canExtendBeforeHowManyMonths + " months of your " + plan.PlanType.ToString().ToLower() + " period, you") can renew your plan by going to the Organization detail page.</p>
var canExtendBeforeHowManyMonths = plan.OnePaidEnrollmentPeriodAsMonth!.Value - plan.CanBeExtendedAfterHowManyMonths!.Value;
@if (canExtendBeforeHowManyMonths != 0)
{
<p>For @plan.PlanType, @(canExtendBeforeHowManyMonths == plan.OnePaidEnrollmentPeriodAsMonth!.Value ? "You " : "in the last " + canExtendBeforeHowManyMonths + " months of your " + plan.PlanType.ToString().ToLower() + " period, you") can renew your plan by going to the organization detail page.</p>
}
else
{
<p>For @plan.PlanType, when your @plan.PlanType period expires, you can repurchase your plan by going to the organization detail page.</p>
}
}
else
{
@ -83,7 +90,7 @@
</div>
<div id="accordion123" class="collapse" data-bs-parent="#accordion" style="">
<div class="faq-body">
<p>Don't worry about even if your organization has run out of premium, you can upgrade back to the Premium plan at any time.
<p>Don't worry about even if your organization has run out of premium, you can upgrade back to the plan at any time.
</p>
</div>
</div>

13
src/EventHub.Web/Pages/Pricing.cshtml.cs

@ -1,7 +1,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using EventHub.Organizations;
using EventHub.Web.Pages.Payment;
using EventHub.Web.Pages.Organizations;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Mvc;
using Payment.PaymentRequests;
@ -52,12 +52,11 @@ namespace EventHub.Web.Pages
PlanInfos = await _organizationAppService.GetPlanInfosAsync();
}
public async Task<IActionResult> OnPostUpgradeToPremiumAsync()
public async Task<IActionResult> OnPostUpgradeAsync()
{
var organization = await GetOrganizationProfileAsync();
PlanInfos = await _organizationAppService.GetPlanInfosAsync();
var plan = PlanInfoHelper.GetPlan(OrganizationPlanType.Premium, PlanInfos);
var plan = PlanInfoHelper.GetPlan(TargetPlanToUpgrade, PlanInfos);
if (plan is null || !plan.IsActive)
{
Alerts.Danger("Premium plan is currently inactive!");
@ -69,13 +68,13 @@ namespace EventHub.Web.Pages
return Redirect(_paymentUrlBuilder.BuildCheckoutUrl(paymentRequest.Id).AbsoluteUri);
}
public async Task<IActionResult> OnPostExtendToPremiumAsync()
public async Task<IActionResult> OnPostExtendAsync()
{
var organization = await GetOrganizationProfileAsync();
PlanInfos = await _organizationAppService.GetPlanInfosAsync();
var plan = PlanInfoHelper.GetPlan(OrganizationPlanType.Premium, PlanInfos);
var plan = PlanInfoHelper.GetPlan(TargetPlanToUpgrade, PlanInfos);
if (plan is null || !plan.IsActive)
{
Alerts.Danger("Premium plan is currently inactive!");
@ -116,7 +115,7 @@ namespace EventHub.Web.Pages
new OrganizationPaymentRequestExtraParameterConfiguration
{
OrganizationName = OrganizationName,
PremiumPeriodAsMonth = plan.OnePremiumPeriodAsMonth,
PremiumPeriodAsMonth = plan.OnePaidEnrollmentPeriodAsMonth,
IsExtend = isExtend,
TargetPlanType = TargetPlanToUpgrade
}

6
src/EventHub.Web/Pages/Pricing.css

@ -36,6 +36,10 @@
overflow: hidden;
}
.plan-card {
height: 570px;
}
html:not([dir=rtl]) .mb-4, html:not([dir=rtl]) .my-4 {
margin-bottom: 1.5rem !important;
}
}

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

@ -18,10 +18,10 @@ namespace EventHub.Events.Registrations
clock.Now.Returns(DateTime.Now);
var registrationManager = new EventRegistrationManager(
null, null, clock
null, null, clock, null
);
var evnt = new Event(
var @event = new Event(
Guid.NewGuid(),
Guid.NewGuid(),
"1a8j3v0d",
@ -31,7 +31,7 @@ namespace EventHub.Events.Registrations
"In this event, we will introduce the ABP Framework..."
);
registrationManager.IsPastEvent(evnt).ShouldBeTrue();
registrationManager.IsPastEvent(@event).ShouldBeTrue();
}
[Fact]
@ -58,7 +58,7 @@ namespace EventHub.Events.Registrations
clock.Now.Returns(DateTime.Now);
var registrationManager = new EventRegistrationManager(
repository, guidGenerator, clock
repository, guidGenerator, clock, null
);
await registrationManager.RegisterAsync(evnt, user);

Loading…
Cancel
Save