Hi,
After completing the first subscription with the following example:
public virtual async Task<IActionResult> OnPost()
{
var paymentRequest = await PaymentRequestAppService.CreateAsync(
new PaymentRequestCreateDto
{
Products =
{
new PaymentRequestProductCreateDto
{
PaymentType = PaymentType.Subscription,
Name = DemoAppData.Plan_2_Name,
Code = "EP",
Count = 1,
PlanId = DemoAppData.Plan_2_Id,
}
}
});
return LocalRedirectPreserveMethod("/Payment/GatewaySelection?paymentRequestId=" + paymentRequest.Id);
}
You need to add handler for the following events:
public class MySubscriptionCreatedHandler : IDistributedEventHandler<SubscriptionCreatedEto>, ITransientDependency
{
public Task HandleEventAsync(SubscriptionCreatedEto eventData)
{
Console.WriteLine("Subscription Created with Payment Request Id:" + eventData.PaymentRequestId);
// Map that PaymentRequest to your Subscription Entity. You'll use this PaymentRequestId in the future events.
return Task.CompletedTask;
}
}
public class MySubscriptionCanceledHandler : IDistributedEventHandler<SubscriptionCanceledEto>, ITransientDependency
{
public Task HandleEventAsync(SubscriptionCanceledEto eventData)
{
Console.WriteLine("Subscription Cancelled with Payment Request Id:" + eventData.PaymentRequestId);
// Find and Cancel the Subscription in your system.
return Task.CompletedTask;
}
}
public class MySubscriptionUpdatedHandler : IDistributedEventHandler<SubscriptionUpdatedEto>, ITransientDependency
{
public Task HandleEventAsync(SubscriptionUpdatedEto eventData)
{
Console.WriteLine("Subscription Updated with Payment Request Id:" + eventData.PaymentRequestId);
// Find and Update the Subscription in your system.
if (eventData.State == PaymentRequestState.Completed)
{
// Another payment completed for the Subscription. You can keep subscription going on.
}
if (eventData.State == PaymentRequestState.Failed || eventData.State == PaymentRequestState.Refunded)
{
// Subscription is failed or refunded. You can cancel the subscription.
}
return Task.CompletedTask;
}
}
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService: Information: Authorization failed. These requirements were not met: PermissionRequirement: SettingManagement.Emailing Microsoft.AspNetCore.Authorization.DefaultAuthorizationService: Information: Authorization failed. These requirements were not met: PermissionRequirement: SettingManagement.TimeZone Microsoft.AspNetCore.Authorization.DefaultAuthorizationService: Information: Authorization failed. These requirements were not met: PermissionRequirement: AbpAccount.SettingManagement Microsoft.AspNetCore.Authorization.DefaultAuthorizationService: Information: Authorization failed. These requirements were not met: PermissionRequirement: AbpIdentity.SettingManagement Microsoft.AspNetCore.Authorization.DefaultAuthorizationService: Information: Authorization failed. These requirements were not met:
It's hard to understand this authentication problem, can I see your authserver configuration?
This is related to UI theme, it's solved and will be published in LeptonX nuget packages
Hi,
Only Tenant - Edition relation is tracked and managed by ABP, otherwise you need to create a subscription by using PaymentRequestAppService with paymentType as subscription and track changed by listening events from payment module: https://abp.io/docs/latest/modules/payment#distributed-events
Those events are properly triggered by host application that uses payment module application package. If you configure webhooks, you can ensure all the events will be delivered while your payment application is up. If not, still payment gateway retries webhooks until application respond with 200. So configuring webhooks is enough to get events eventually.
Q. Are saying we can somehow utilise this package in the Microsoft Maui Blazor Hybrid project to implement a Login flow? It seems pretty tightly coupled to the ABP architecture.
Yes it's built for the best compatibility with ABP and ABP services. If you need the same implementation for plain Blazor Hybrid project, you'll need to implement it yourself, this package can't be used without ABP.
Also can you please comment on why the ABP Maui Blazor Hybrid will not startup without connectivity to the Server as we haven't received an answer to our overall question.
ABP Client architecture is designed for Web Applications mostly MVC & Blazor, so they need to get configuration from server. By default ABP applications can't work without a backend, since they get application-configuration, permissions and even localization from backend. But you can still handle Application Initialization in MauiProgram.cs with a simple try-catch code block and show a different error page when there is no connection. Or you can override client packages to cache application-configuration and other datas from server.
the following code in MauiProgram.cs
sends request to backend, gets configuration and initializes all the ABP infrastructure:
csharp app.Services.GetRequiredService<IAbpApplicationWithExternalServiceProvider>().Initialize(app.Services);
Q. with regard to authentication, can we just call the Swagger Login endpoint on the server to authenticate, or do we need to do anything else?
You can use the same way with MauiBlazor template. It has pre-configured login-flow by using Volo.Abp.Account.Pro.Public.MauiBlazor
package. You can check usage of by creating a MauiBlazor template and implement to your case.
Alternatively, you can implement OAUTH login from scratch by using WebAuthenticator
Hi,
You told you are working on Android. Did you forward your local machine port to the emulator by following Port mapping step from the documentation?
https://abp.io/docs/latest/framework/ui/maui?Tiered=No#android
As an example:
adb reverse tcp:44305 tcp:44305
44305 should be your HttpApi.Host port
Payment redirection is confusing, where does LocalRedirectPreserveMethod
It redirects a page that is included in Volo.Payment.Web
. It should redirect to the application which has this reference.
You can add Volo.Payment.Web
to your HttpApi.Host project and redirect to the API project. This page contains gateway selection UI if configured multiple gateway, otherwise directly redirects to the single payment provider's page
Sorry for the three new questions to the payment / subscriptions:
Where do I configure whether a subscription is automatically renewed or whether the user has to renew it manually? You at ABP have implemented the “Automatic Renewal” option in “Organization Management”. How does it work if this is changed? Is there a request to the payment provider and then this is stored there with the subscription?
How can you implement that a customer can cancel their subscription again?
Hi,
The Payment Module implements only abstraction between payment gateways and makes payments only. Subscription logic is not implemented in the module. For the subscription feature, it uses Stripe API endpoints and it doesn't track or keep any data about subscription. It checks by using stripe APIs if the subscription ended or was canceled. So, If you need to implement a Subscription logic, you can build your own tracking & keeping data logic in a new module or use an existing subscription logic as a service. Payment module uses only payment APIs over gateways
How can you hide language, container width and appearance menus, both in Main Header Toolbar (General Settings) and in MobileNavBar (MobileGeneralSettings)? Looking into the files for LeptonX, there seem to be switches like" @if (HasMultipleStyles)" and "@if (HasContainerWidth)" but we have not been able where to control/change those. Unlike previous Lepton theme, even if you disable all languages but one, the language menu still seem to render in LeptonX but with only one choice available (the enabled language).
You can create the following component in your application:
using Microsoft.AspNetCore.Components.Rendering;
using Volo.Abp.AspNetCore.Components.Web.LeptonXTheme.Components.ApplicationLayout.Common;
using Volo.Abp.DependencyInjection;
namespace LeptonXDemoApp.Blazor.Components;
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(GeneralSettings), typeof(EmptyGeneralSettings))]
public class EmptyGeneralSettings : GeneralSettings
{
protected override void BuildRenderTree(RenderTreeBuilder __builder)
{
__builder.OpenElement(0, "div");
__builder.AddAttribute(1, "class", "empty-general-settings");
__builder.CloseElement();
}
}
How can you specify theme, container width and appearance either in code or settings (appsettings or similar) for Leptonx so you can control it but not allowing users to modify it?
You can create the following script in wwwroot/globa.js
$(function () {
const currentInitLeptonX = window.initLeptonX;
window.initLeptonX = function (layout, defaultStyle = "dim") {
currentInitLeptonX(layout, defaultStyle);
leptonx.globalConfig.defaultSettings =
{
appearance: "dark",
containerWidth: 'full',
};
leptonx.init.run();
}
});
And add it to the bundle configuration: (Configure both for Blazor Server)
// For Blazor Server
options.ScriptBundles.Configure(
LeptonXThemeBundles.Scripts.Global,
bundle =>
{
bundle.AddFiles("/global.js");
}
);
// For Blazor WASM / MauiBlazor / Blazor Server
options.ScriptBundles.Configure(
BlazorLeptonXThemeBundles.Scripts.Global,
bundle =>
{
bundle.AddFiles("/global.js");
});
3.For the MobileNavBar, is there a way to hide the "Settings" or at least move it in under the user menu so that "slot" in the tab bar can instead be used for something more useful, like navigating to a page just like Home/Dashboard? With only fem slots available, 4 including the hamburger menu, it seems like a waste to dedicate one of them to Settings that you might change once or twice (or never)
It's a design decision, there is no configuration for it right now, you can customize it by overriding the MobileNavBar component in your project.
4.How come the MobileNavBar can't be controlled like the normal main menu? Seems like the only way is to hardcode items using options.MobileMenuSelector = items => items.Where(...) which isn't ideal for various reasons.
5.How can you control/change the number of items for MobileMenuSelector ? 2 seems to be default but have found not documentation on how to change that.
It uses regular menu contributor to list menu items. Bottom bar is designed for mobile requirements and it has limited space. So only 2 items can be placed there, you can pick which ones will be there. But still all the menu items will be included in hamburger menu.