Sana Assistant (online)
Table of Contents

Configuring Settings Per Payment Method

Payment service providers (PSPs) often support multiple payment methods, each requiring specific configuration parameters to function correctly. Sana provides extension developers with a robust framework to implement payment method-specific settings through the PaymentMethodSettings class. This guide demonstrates how to implement and manage payment method settings for your payment extensions. This guide builds upon the Stripe payment extension created in the Implementing New Payment Service Provider tutorial. We'll extend it to support configurable payment methods.

Prerequisites

Before implementing payment method settings, ensure you have:

Required References

Create Payment Method Settings Class

Create a new class that inherits from PaymentMethodSettings. This class defines the configuration properties that administrators can set for each payment method instance.

using System.ComponentModel.DataAnnotations;
using Sana.Extensions.Payment;

namespace Sana.Extensions.CustomStripe
{
    /// <summary>
    /// Defines configurable settings for Stripe payment methods.
    /// These settings appear in the Sana Admin payment method configuration page.
    /// </summary>
    public class CustomStripePaymentMethodSettings : PaymentMethodSettings
    {
        /// <summary>
        /// Gets or sets the enabled payment methods for this configuration.
        /// </summary>
        [Display(Name = "Payment Methods", 
                Description = "Select the payment method type to enable for this configuration")]
        [Required(ErrorMessage = "Please select a payment method")]
        public PaymentMethods paymentMethods { get; set; }

        /// <summary>
        /// Enumeration of supported Stripe payment methods.
        /// </summary>
        public enum PaymentMethods
        {
            Card,
            BanContact,
            EPS,
            P24,
            other
        }
    }
}
Note

A class that inherits from PaymentMethodSettings acts as the view-model Sana renders on the payment-method configuration page in Sana Admin, so you can decorate its properties with DataAnnotations attributes and even supply custom editor templates.

Update Payment Extension Class

Modify your payment extension to use the generic type parameter with your settings class:

using Sana.Extensions.Cache;
using Sana.Extensions.Models.Orders;
using Sana.Extensions.Payment;
using Sana.Extensions.Payment.Contexts;
using System;
using System.Collections.Generic;
using System.Linq;
using Stripe;
using Stripe.Checkout;

namespace Sana.Extensions.CustomStripe
{
    /// <summary>
    /// Custom Stripe Payment Extension with configurable payment method settings.
    /// </summary>
    [PaymentModuleId("CustomStripePayment")]
    public class CustomStripePaymentExtension: PaymentExtension<CustomStripePaymentMethodSettings>, IConfigurable<CustomStripeConfiguration>
    {
        public CustomStripeConfiguration Configuration { get; set; }
        
        // Extension implementation continues...
    }
}

After these steps we can see the following block with the "PaymentMethods" input on the payment method configuration page. Note the generic type parameter <CustomStripePaymentMethodSettings> added to PaymentExtension.

Access Payment Method Settings

Within your payment extension methods, access the configured settings through the context parameter:

public override NextAction StartPayment(PaymentStartContext context)
{
    try
    {
        // Validate the input context
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context), "Payment context cannot be null");
        }

        // Access payment method settings with type safety
        var paymentMethodSettings = (CustomStripePaymentMethodSettings)context.MethodSettings;
        
        // Retrieve the configured payment method
        var selectedPaymentMethod = paymentMethodSettings.paymentMethods;
        
        // Convert enum to Stripe-compatible string format
        var stripePaymentMethod = ConvertToStripePaymentMethod(selectedPaymentMethod);
        
        // Configure Stripe API
        StripeConfiguration.ApiKey = Configuration.ApiKey;
        
        // Create Stripe checkout session with the selected payment method
        var options = new SessionCreateOptions
        {
            PaymentMethodTypes = new List<string> { stripePaymentMethod },
            Mode = StripeConstants.CHECKOUT_MODE_PAYMENT,
            SuccessUrl = context.SuccessUrl,
            CancelUrl = context.CancelUrl,
            LineItems = CreateLineItemsFromOrderLines(context)
        };
        
        var sessionService = new SessionService();
        Session session = sessionService.Create(options);
        
        // Continue with payment flow...
        return NextAction.Redirect(session.Url);
    }
    catch (Exception ex)
    {
        // Log exception details for debugging
        Api.LogError(ex, "Failed to start Stripe payment");
        throw;
    }
}

Implement Helper Method (ConvertToStripePaymentMethod)

Add helper methods to handle payment method conversions and validations:

/// <summary>
/// Converts the payment method enum to Stripe's expected format.
/// </summary>
/// <param name="paymentMethod">The configured payment method</param>
/// <returns>Stripe-compatible payment method string</returns>
private string ConvertToStripePaymentMethod(CustomStripePaymentMethodSettings.PaymentMethods paymentMethod)
{
    switch (paymentMethod)
    {
        case CustomStripePaymentMethodSettings.PaymentMethods.Card:
            return "card";
        
        case CustomStripePaymentMethodSettings.PaymentMethods.BanContact:
            return "bancontact";
        
        case CustomStripePaymentMethodSettings.PaymentMethods.EPS:
            return "eps";
        
        case CustomStripePaymentMethodSettings.PaymentMethods.P24:
            return "p24";
        
        case CustomStripePaymentMethodSettings.PaymentMethods.other:
            // For 'other', you might want to implement additional logic
            // or configuration to specify the exact payment method
            return "card"; // Default fallback
        
        default:
            throw new NotSupportedException($"Payment method {paymentMethod} is not supported");
    }
}

See also