Open Closed

Problem using Payment module #4692


User avatar
0
alin.berce created

If you're creating a bug/problem report, please include followings:

  • ABP Framework version: v7.0.3
  • UI type: MVC
  • DB provider: EF Core
  • Tiered (MVC) or Identity Server Separated (Angular): no

Hello,

Either documentation is missing something or there's a bug or I'm not seeing something obvious. Here are the steps:

  • add a new project using the latest abp 7.0.3 with Public web site

  • either by using abp suite or by running abp add-module Volo.Payment add the payment module.

  • this will add various packages and dependencies based on project

  • I want to use this on Public site with Stripe (but it also doesn't work on Web) so because of this I add the packages in the project file

    <PackageReference Include="Volo.Payment.Admin.Web" Version="7.0.3" /> <PackageReference Include="Volo.Payment.Stripe.Web" Version="7.0.3" /> <PackageReference Include="Volo.Payment.Web" Version="7.0.3" />

and on WebPublicModule.cs

[DependsOn(typeof(AbpPaymentWebModule))]
[DependsOn(typeof(AbpPaymentStripeWebModule))]
[DependsOn(typeof(AbpPaymentAdminWebModule))]

also add url configs

  Configure<PaymentWebOptions>(options =>
        {
            options.RootUrl = configuration["App:SelfUrl"];
            options.CallbackUrl = configuration["App:SelfUrl"] + "/Paid";
        });
  • looking at docs, for predefined gateways, there is no need to configure PaymentOptions
  • in appsettings.json add
{
  "App": {...},
  "Redis": {...},
  "ConnectionStrings": {...},
  "AuthServer": {...},
  "Payment": {
    "Stripe": {
      "PublishableKey": "publishable_key",
      "SecretKey": "secret_key",
      "PaymentMethodTypes": [ "card" ]
    }
  }
}
  • start a payment from razor main index model
public async Task<IActionResult> OnGetAsync()
    {
        var paymentRequest = await paymentRequestAppService.CreateAsync(new PaymentRequestCreateDto()
        {
            Currency = "USD",
            Products = new List<PaymentRequestProductCreateDto>()
            {
                new PaymentRequestProductCreateDto
                {
                    Code = "Product_code",
                    Name = "Product name",
                    Count =1,
                    UnitPrice = 20,
                    TotalPrice = 20
                }
            }
        });

        return LocalRedirectPreserveMethod("/Payment/GatewaySelection?paymentRequestId=" + paymentRequest.Id);
    }
  • login with admin and run locally

Now the effects:

  • /Payment/GatewaySelection returns code 400. If I look at logs I can see that:
Request starting HTTP/2 GET https://localhost:44374/Payment/GatewaySelection?paymentRequestId=a246857e-af5f-012d-0eee-3a09ec82cd86 - -
[11:41:08 DBG] Added 0 entity changes to the current audit log
[11:41:08 DBG] Added 0 entity changes to the current audit log
[11:41:08 DBG] Added 0 entity changes to the current audit log
[11:41:08 INF] Executing endpoint '/Payment/GatewaySelection'
[11:41:08 INF] Route matched with {page = "/Payment/GatewaySelection", action = "", controller = "", area = ""}. Executing page /Payment/GatewaySelection
[11:41:08 INF] Skipping the execution of current filter as its not the most effective filter implementing the policy Microsoft.AspNetCore.Mvc.ViewFeatures.IAntiforgeryPolicy
[11:41:08 INF] Executing handler method Volo.Payment.Pages.Payment.GatewaySelectionModel.OnGet - ModelState is Valid
[11:41:08 INF] Executed handler method OnGet, returned result Microsoft.AspNetCore.Mvc.BadRequestResult.
[11:41:08 INF] Executing StatusCodeResult, setting HTTP status code 400
[11:41:08 INF] Executed page /Payment/GatewaySelection in 2.4219ms
[11:41:08 INF] Executed endpoint '/Payment/GatewaySelection'
[11:41:08 INF] Request finished HTTP/2 GET https://localhost:44374/Payment/GatewaySelection?paymentRequestId=a246857e-af5f-012d-0eee-3a09ec82cd86 - - - 400 0 - 47.9921ms
  • going to /Payment/Requests I can see the payment request created with Wait state

I've tried a bunch of configs and all that I could see in docs and around support answered questions. Basically the gateways pages are not available. Seems like it's missing some configuration? What could cause that BadRequestResult in GatewaySelectionModel.OnGet?

Please advise. Thank you.


8 Answer(s)
  • User Avatar
    0
    alin.berce created

    Any updates?

  • User Avatar
    0
    enisn created
    Support Team .NET Developer

    You should redirect a POST method to /Payment/GatewaySelection?paymentRequestId= instead GET. You can submit a form and redirect that request with LocalRedirectPreserveMethod().

    The example shows it but it seems it's not clearly described in the documentation, I'll update the documentation according to this issue.

  • User Avatar
    0
    alin.berce created

    @enisn thank you for your answer. If I do it in the Post indeed is does not throw the same error. However, now it says:

    ApplicationException: No payment gateway configured!
    
        Volo.Payment.Pages.Payment.GatewaySelectionModel.OnPostAsync()
    

    In the docs it says:

    PaymentOptions is used to store list of payment gateways. You don't have to configure this manually for existing payment gateways. You can, however, add a new gateway like below;

    also

    Instead of configuring options in your module class, you can configure it in your appsettings.json file like below;

    What's missing from my configuration? You can see above that in appsettings.json there's an entry for Payment containing only Stripe because that's the only thing I want to use. Also the PublicWebModule has [DependsOn(typeof(AbpPaymentStripeWebModule))] and [DependsOn(typeof(AbpPaymentWebModule))]

  • User Avatar
    0
    enisn created
    Support Team .NET Developer

    Did you configured properly according to the documentation: https://docs.abp.io/en/commercial/latest/modules/payment#paymentoptions

    You should add at least one of the payment provider as gateway. You can see each payment gateway has different parameters to configure.

    You can use your appsettings.json to configure them properly. You can use the following boilerplate from the documentation:

    "Payment": {
        "Payu": {
          "Merchant": "TEST",
          "Signature": "SECRET_KEY",
          "LanguageCode": "en",
          "CurrencyCode": "USD",
          "VatRate": "0",
          "PriceType": "GROSS",
          "Shipping": "0",
          "Installment": "1",
          "TestOrder": "1",
          "Debug": "1"
        },
        "TwoCheckout": {
          "Signature": "SECRET_KEY",
          "CheckoutUrl": "https://secure.2checkout.com/order/checkout.php",
          "LanguageCode": "en",
          "CurrencyCode": "USD",
          "TestOrder": "1"
        },
        "PayPal": {
          "ClientId": "CLIENT_ID",
          "Secret": "SECRET",
          "CurrencyCode": "USD",
          "Environment": "Sandbox",
          "Locale": "en_US"
        },
        "Stripe": {
          "PublishableKey": "PUBLISHABLE_KEY",
          "SecretKey": "SECRET_KEY",
          "PaymentMethodTypes": ["alipay"]
        },
        "Iyzico": {
          "ApiKey": "API_KEY",
          "SecretKey": "SECRET_KEY",
          "BaseUrl": "https://sandbox-api.iyzipay.com",
          "Locale": "en",
          "Currency": "USD"
        },
        "Alipay": {
          "AppId": "APP_ID",
          "GatewayHost": "openapi.alipaydev.com",
          "AlipayPublicKey": "ALIPAY_PUBLIC_KEY",
          "MerchantPrivateKey": "MERCHANT_PRIVATE_KEY"
        }
      }
    
    
  • User Avatar
    0
    alin.berce created

    I've had some commented out DependsOn in Domain project from my trials and errors and because of that, even with the appsettings.json configured it wasn't working. Now I can perform a stripe test payment and return back to callback URL.

    However, one last small bit that I am missing

    Looking at the docs, it says that

    Volo.Payment.PaymentRequestCompleted (PaymentRequestCompletedEto): Published when a payment is completed.

    My desire is to update something in the database when the event is handled. Here is some sample code

    public class MyTestEventHandler : IDistributedEventHandler<PaymentRequestCompletedEto>, ITransientDependency
    {
            private readonly IMyTestRepository myTestRepository;
           
            public PaymentRequestCompletedEventHandler(IMyTestRepository myTestRepository;)
            {
                this.myTestRepository = myTestRepository;
            }
    
            public async Task HandleEventAsync(PaymentRequestCompletedEto eventData)
            {
                Guid id = Guid.Parse(eventData.Products[0].Code); //the Code is entity Id
    
                var entity = await myTestRepository.GetAsync(id);
                
               //here at fetching data from the repository it throws error
            }
    }
    

    My repository is injected fine. the Id received exists in the database, however it throws error.

    The error I get is: Message: A task was cancelled Source: Microsoft.EntityFrameworkCore.Relational InnerException: null

    Digging a bit deeper into debug console I can see: An error occured using the connection to database 'MyProj' on server 'MyLocalServer'

    A task was cancelled. at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternalAsync(Boolean errorsExpected, CancellationToken cancellationToken)...

    Feels like there's no context for the event handler. How can I property handle the ETO while having access to the database?

  • User Avatar
    0
    alin.berce created

    @enisn any idea what to try?

  • User Avatar
    0
    alin.berce created

    @enisn any solution for my issue?

  • User Avatar
    0
    enisn created
    Support Team .NET Developer

    That way should work. https://docs.abp.io/en/abp/latest/Distributed-Event-Bus#subscribing-to-events

    Some cases might be changed according to your event bus service. Which one are you using? (RabbitMQ, Kafka, Azure etc.)

Made with ❤️ on ABP v9.1.0-preview. Updated on December 12, 2024, 07:15