Open Closed

Question: recurring payment for customers instead of tenants #8025


User avatar
1
jaylin created

ABP Framework version: v8.2.2

UI Type: Angular

Database System: EF Core (SQL Server)

Tiered (for MVC) or Auth Server Separated (for Angular): yes

Exception message and full stack trace:

Steps to reproduce the issue:

My last question (https://abp.io/support/questions/7847/Stripe-Payment--Subscription-Questions) was regarding recurring payment against tenant, I managed to add EditionId and TenantId into the ExtraPropertyDictionary to link to the built-in Stripe Webhook to trigger Tenant-Edition recurring subscription.

public virtual async Task OnPost(Guid planId, Guid editionId)
{
// PaymentRequestProductDto can't edit ExtraProperties
var paymentRequest = await PaymentRequestAppService.CreateAsync(
new CustomPaymentRequestCreateDto(new ExtraPropertyDictionary() {
{ "EditionId", editionId },
{ "TenantId", CurrentTenant.Id }
})
{
Products =
{
new PaymentRequestProductCreateDto
{
PaymentType = PaymentType.Subscription,
Name = "Standard",
Code = $"{CurrentTenant.Id}\_{planId}",
Count = 1,
PlanId = planId
}
}
});

 return LocalRedirectPreserveMethod("/Payment/GatewaySelection?paymentRequestId=" + paymentRequest.Id);

}

Question: I am building a B2C platform that all users belongs to the same pre-defined tenant, how to handle the recurring subscriptions for each individual users? Do I need to include the UserId to the extra property and extend the built-in Stripe webhook? Then store the subscription expiry date for each individual user?

Any suggestions or working examples will be appreciated!


4 Answer(s)
  • User Avatar
    0
    jaylin created

    It's nearly a week now, nobody wants to reply my question?

  • User Avatar
    0
    enisn created
    Support Team .NET Developer

    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.

  • User Avatar
    0
    jaylin created

    Thanks, so I have to create a new table to manage the User - Plan relation, once recurring payment comes, I need to extend the subscription expiry to next month (if recurring monthly)?

    I didn't find any invoice ready "Distributed Events", how can I implement such event?

  • User Avatar
    0
    enisn created
    Support Team .NET Developer

    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;
        }
    }
    
Made with ❤️ on ABP v9.1.0-preview. Updated on December 13, 2024, 06:09