I lost a lof of time to this as well. But it seems in 5.0.0-rc1, the problem for the most part has been resolved.
After you mentioned that the Admin page was include, I had a look at my main Blazor project and none of the payment modules were added to that project aby ABP Suite (4.4.3). So I manually added them. After that I received an Automapper exception complaining about Extraproperties being null. So I went into ExtensionsConfigurator and added an additional property and that seemed to do the trick and it's working now.
However, for the Public UI side of things, I guess we should just build that porition out?
There is currently no documentation / code examples for using the payments module to process a payment from end to end using blazor server. Could you provide an example? PaymentWebOptions for example, is not included in the default nugets for blazor server.
This is a Blazor Server-Side Application. I assumed that Volo.Payment.Web was for an MVC application.
I used ABP Suite to create my project. Although the Volo.Payment.HttpApi nuget was added to the [ProjectName].HttpApi project. Volo.Payment.Web has to be manually added to the solution.
Even then, doing a simple test in the browser by going to the url /Payment/GatewaySelection?paymentRequestId=12345 returns an autofac exception. If you can upload a sample ABP Suite Blazor Server-Side project to Github with the payment Gateway url working that would be great.
ComponentNotRegisteredException: The requested service 'Volo.Payment.Pages.Payment.GatewaySelectionModel' has not been registered.
Volo.Payment.HttpApi includes webhook endpoints. If you add that dependency properly, the endpoint will exist in your application. Also sending a test webhook will always return an error because the application can't find any entry with a randomly generated id sent by test request.
When testing the webhook through stripe It's returning a 404, not a 400.
Can you please share what exception you got?
System.Collections.Generic.KeyNotFoundException: The given key 'SessionId' was not present in the dictionary.
It's looking for me to do:
await _paymentRequestAppService.CompleteAsync(new CompletePaymentRequestDto() { Id = paymentRequest.Id, GateWay = "stripe", ExtraProperties = { { "SessionId", ????? } } });
But since I am not able to suppy an SessionId it's throwing that exception.
Actually, I do not really care about the other Gateways. I intend on only using Stripe. Can you provide an example of how this will be done to integrate it with ABP?
Otherwise, I will have to write out my own Stripe integration.
At a high level, It would seem that I would use IPaymentRequestAppService to create a PaymentRequest. Map the PaymentRequest to a Stripe LineItems Object. Create a session using the Session Service. Then pass that SessionId to IPaymentRequestAppService's CompleteAsync method.
One of the main reasons why I signed up for the Commercial version of ABP, is actually because of the payments module. I am a sole developer, it's not really worth it to upgrade to one of your higher plans that include the complete source code. The payment's module without proper Blazor support seems incomplete.
In my opinion, stating that the payment process is really simple when you haven't tried it, and your documentation is geared towards MVC, is not really helpful.
I am not able to get the Payment to succeed so I am not sure how CallbackUrl in PaymentWebOptions would be helpful. The PaymentWebOptions is also geared towards an MVC application.
It would be very helpful if you could provide some sample code or update your documentation to include Blazor Server.
I basically followed the method that I mentioned above, and everything works, however, when I try to complete the transaction by calling CompleteAsync on the PaymentRequestAppService it throws an exception
"System.Collections.Generic.KeyNotFoundException: The given key 'PaymentRequestId' was not present in the dictionary."
I am able to verify that the transaction has been completed in the stripe dashboard, however, I would like it to be updated on the admin page as well.
This is how I am using it:
await _paymentRequestAppService.CompleteAsync(new CompletePaymentRequestDto()
{
Id = completedPayment.PaymentRequestId, GateWay = "stripe",
ExtraProperties = { { "SessionId", completedPayment.Id } }
});
the PaymentRequestId is what is returned from
var paymentRequest = await _paymentRequestAppService.CreateAsync(new PaymentRequestCreateDto()
{
Products = paymentRequestDto.Products
});
Also, I updated to the latest stripe nuget as it supports server-side redirects. When you create a stripe session it returns a URL in the response that you can redirect to. I thought this would be the simpler/better approach rather than integrating with stripe.js and having to do Javascript Interop.
This is the full stack trace:
ystem.Collections.Generic.KeyNotFoundException: The given key 'PaymentRequestId' was not present in the dictionary.
at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
at Volo.Payment.Stripe.StripePaymentGateway.IsValid(PaymentRequest paymentRequest, Dictionary`2 properties)
at Volo.Payment.Requests.PaymentRequestAppService.CompleteAsync(CompletePaymentRequestDto input)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
at Volo.Abp.GlobalFeatures.GlobalFeatureInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
at Volo.Abp.Auditing.AuditingInterceptor.ProceedByLoggingAsync(IAbpMethodInvocation invocation, IAuditingHelper auditingHelper, IAuditLogScope auditLogScope)
at Volo.Abp.Auditing.AuditingInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
at Volo.Abp.Validation.ValidationInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at ReferMe.Payments.StripePaymentService.CompletePayment(SessionDto completedPayment) in D:\_dev\ReferMe\src\ReferMe.Application\Payments\StripePaymentService.cs:line 62
Thanks that helped. It works now. I am now able to confirm a completed payment in the admin page.
When I create the SessionCreateOptions object, I add the PaymentRequestId to the Metadata dictionary.
Quick question, are the webhooks going to work? Or do I need to implement that separately? I believe that they should be included in the Volo.Payment.Stripe.HttpApi nuget. However, when I test it from Stripe, I am getting a 404.