Hi @hmahmood
ABP doesn't provide any UI for pricing, plans or something like that. You have to implement your own UI for that.
When a user chooses a plan in a page designed by you, you should call Create method of IPaymentRequestAppService
.
var paymentRequest = await PaymentRequestAppService.CreateAsync(
new PaymentRequestCreateDto()
{
Products =
{
new PaymentRequestProductCreateDto
{
PaymentType = PaymentType.Subscription,
Name = "Enterprise Plan",
Code = "EP",
Count = 1,
// Place below your created PlanId.
PlanId = DemoAppData.Plan_2_Id,
}
}
});
return LocalRedirectPreserveMethod("/Payment/GatewaySelection?paymentRequestId=" + paymentRequest.Id);
Subscription feature provides only C# interface. It doesn't provide built-in plans/pricing table.
Hi @adam-dot-cohen
Lepton doesn't have an HTML template. It's implemented in ABP.
We're working on LeptonX Theme. It'll include also an html+css template.
We separated Client & Server logic in the next version (v5.2)
In the current version, the Payment module doesn't support blazor UI officially, but the next version will provide an AppService and you can implement whichever UI you want.
I've just tried, it's working in a basic demo.
endeditiondate will not be affected if a user ends the payment. The last period is still can be used until the end date. But end date will not be extended if the user hasn't paid the last bill.
I'm not sure is there an option in stripe for ending subscription immediately instead of canceling at end of the period, but if it can be done on stripe, it'll affect to abp application too. We handle PeriodEndDate from stripe.
I did the ignore payment tables and everything seemed fine until I went to go to the Tenant section and Edition section and then I get the below error. Any ideas how I can get around this besides putting those tables back?
[ { "code": null, "message": "Invalid object name 'PayPlans'.", "details": "SqlException: Invalid object name 'PayPlans'.\r\nSTACK TRACE: at Microsoft.Data.SqlClient.SqlCommand.<>c.<ExecuteDbDataReaderAsync>b__207_0(Task
1 result)\r\n at System.Threading.Tasks.ContinuationResultTaskFromResultTask
2.InnerInvoke()\r\n at System.Threading.Tasks.Task.<>c.<.cctor>b__272_0(Object obj)\r\n at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)\r\n--- End of stack trace from previous location ---\r\n at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)\r\n at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)\r\n--- End of stack trace from previous location ---\r\n at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)\r\n at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)\r\n at Microsoft.EntityFrameworkCore.Query.Internal.SplitQueryingEnumerable1.AsyncEnumerator.InitializeReaderAsync(AsyncEnumerator enumerator, CancellationToken cancellationToken)\r\n at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func
4 operation, Func4 verifySucceeded, CancellationToken cancellationToken)\r\n at Microsoft.EntityFrameworkCore.Query.Internal.SplitQueryingEnumerable
1.AsyncEnumerator.MoveNextAsync()\r\n at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable1 source, CancellationToken cancellationToken)\r\n at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable
1 source, CancellationToken cancellationToken)\r\n at Volo.Payment.Plans.EfCorePlanRepository.GetManyAsync(Guid[] ids)\r\n at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)\r\n at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue1.ProceedAsync()\r\n at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)\r\n at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter
1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func3 proceed)\r\n at Volo.Saas.Host.EditionAppService.GetListAsync(GetEditionsInput input)\r\n at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)\r\n at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue
1.ProceedAsync()\r\n at Volo.Abp.Authorization.AuthorizationInterceptor.InterceptAsync(IAbpMethodInvocation invocation)\r\n at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func
3 proceed)\r\n at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)\r\n at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue1.ProceedAsync()\r\n at Volo.Abp.GlobalFeatures.GlobalFeatureInterceptor.InterceptAsync(IAbpMethodInvocation invocation)\r\n at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter
1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func3 proceed)\r\n at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)\r\n at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue
1.ProceedAsync()\r\n at Volo.Abp.Auditing.AuditingInterceptor.ProceedByLoggingAsync(IAbpMethodInvocation invocation, IAuditingHelper auditingHelper, IAuditLogScope auditLogScope)\r\n at Volo.Abp.Auditing.AuditingInterceptor.ProcessWithNewAuditingScopeAsync(IAbpMethodInvocation invocation, AbpAuditingOptions options, ICurrentUser currentUser, IAuditingManager auditingManager, IAuditingHelper auditingHelper)\r\n", "data": null, "validationErrors": null } ]
Please don't ignore PayPlans table, It's used for checking & managing Tenant-Edition Subscribers
Hi @zhongfang
Have you completed all installation steps of CmsKit?
I think enabling Global Features will solve the problem:
GlobalFeatureManager.Instance.Modules.CmsKit(cmsKit =>
{
cmsKit.EnableAll();
});
GlobalFeatureManager.Instance.Modules.CmsKitPro(cmsKitPro =>
{
cmsKitPro.EnableAll();
});
Can you try creating migration after enabling global features?
No, you don't need to define a custom UI. Just override only IdentityUserAppService
, and the existing UI will use the same endpoint. You'll just add some custom logic for existing AppService logic.
I think you need something like that: https://stackoverflow.com/a/16517768/7200126
In your scenario, you can use add a where clause to specify the type, so you can access the Id property. The following extension method should work:
public static class QueryExtensions
{
public static IQueryable<T> IncludeFilterIds<T>(this IQueryable<T> queryable, List<Guid> ids)
where T : Entity<Guid>
{
return queryable.WhereIf(!ids.IsNullOrEmpty(), t => ids.Contains(t.Id));
}
}
Then you can call normally:
query = query.IncludeFilterIds(filterIds);
No need to create a new entity.
Using extraproperties without ModuleEntityExtension is possible. You can still add and read new keys via using ExtraProperties. But they'll not create new columns in your databases, they'll be stored as just JSON in a single column:
You can do it something like that:
var blogPost = await BlogPostManager.CreateAsync(
author,
blog,
input.Title,
input.Slug,
input.ShortDescription,
input.Content,
input.CoverImageMediaId);
blogPost.ExtraProperties.Add("MyCustomKey", "My Custom Value");