feat(payment_methods_v2): add payment methods list endpoint (#6938)

Co-authored-by: Sanchith Hegde <sanchith.hegde@juspay.in>
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
Narayan Bhat
2025-01-13 15:07:19 +05:30
committed by GitHub
parent 1d993055d2
commit 6a1f5a8875
47 changed files with 1228 additions and 864 deletions

View File

@ -1009,9 +1009,10 @@ pub struct MerchantConnectorResponse {
/// Type of the Connector for the financial use case. Could range from Payments to Accounting to Banking.
#[schema(value_type = ConnectorType, example = "payment_processor")]
pub connector_type: api_enums::ConnectorType,
/// Name of the Connector
#[schema(value_type = Connector, example = "stripe")]
pub connector_name: String,
pub connector_name: common_enums::connector_enums::Connector,
/// A unique label to identify the connector account created under a profile
#[schema(example = "stripe_US_travel")]
@ -1310,9 +1311,10 @@ pub struct MerchantConnectorListResponse {
/// Type of the Connector for the financial use case. Could range from Payments to Accounting to Banking.
#[schema(value_type = ConnectorType, example = "payment_processor")]
pub connector_type: api_enums::ConnectorType,
/// Name of the Connector
#[schema(value_type = Connector, example = "stripe")]
pub connector_name: String,
pub connector_name: common_enums::connector_enums::Connector,
/// A unique label to identify the connector account created under a profile
#[schema(example = "stripe_US_travel")]

View File

@ -1,320 +1 @@
pub use common_enums::enums::{PaymentMethod, PayoutType};
#[cfg(feature = "dummy_connector")]
use common_utils::errors;
use utoipa::ToSchema;
/// A connector is an integration to fulfill payments
#[derive(
Clone,
Copy,
Debug,
Eq,
PartialEq,
ToSchema,
serde::Deserialize,
serde::Serialize,
strum::VariantNames,
strum::EnumIter,
strum::Display,
strum::EnumString,
Hash,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum Connector {
Adyenplatform,
#[cfg(feature = "dummy_connector")]
#[serde(rename = "phonypay")]
#[strum(serialize = "phonypay")]
DummyConnector1,
#[cfg(feature = "dummy_connector")]
#[serde(rename = "fauxpay")]
#[strum(serialize = "fauxpay")]
DummyConnector2,
#[cfg(feature = "dummy_connector")]
#[serde(rename = "pretendpay")]
#[strum(serialize = "pretendpay")]
DummyConnector3,
#[cfg(feature = "dummy_connector")]
#[serde(rename = "stripe_test")]
#[strum(serialize = "stripe_test")]
DummyConnector4,
#[cfg(feature = "dummy_connector")]
#[serde(rename = "adyen_test")]
#[strum(serialize = "adyen_test")]
DummyConnector5,
#[cfg(feature = "dummy_connector")]
#[serde(rename = "checkout_test")]
#[strum(serialize = "checkout_test")]
DummyConnector6,
#[cfg(feature = "dummy_connector")]
#[serde(rename = "paypal_test")]
#[strum(serialize = "paypal_test")]
DummyConnector7,
Aci,
Adyen,
Airwallex,
// Amazonpay,
Authorizedotnet,
Bambora,
Bamboraapac,
Bankofamerica,
Billwerk,
Bitpay,
Bluesnap,
Boku,
Braintree,
Cashtocode,
Checkout,
Coinbase,
Cryptopay,
CtpMastercard,
Cybersource,
Datatrans,
Deutschebank,
Digitalvirgo,
Dlocal,
Ebanx,
Elavon,
Fiserv,
Fiservemea,
Fiuu,
Forte,
Globalpay,
Globepay,
Gocardless,
Gpayments,
Helcim,
// Inespay,
Iatapay,
Itaubank,
Jpmorgan,
Klarna,
Mifinity,
Mollie,
Multisafepay,
Netcetera,
Nexinets,
Nexixpay,
Nmi,
// Nomupay,
Noon,
Novalnet,
Nuvei,
// Opayo, added as template code for future usage
Opennode,
Paybox,
// Payeezy, As psync and rsync are not supported by this connector, it is added as template code for future usage
Payme,
Payone,
Paypal,
Payu,
Placetopay,
Powertranz,
Prophetpay,
Rapyd,
Razorpay,
// Redsys,
Shift4,
Square,
Stax,
Stripe,
Taxjar,
Threedsecureio,
//Thunes,
Trustpay,
Tsys,
// UnifiedAuthenticationService,
Volt,
Wellsfargo,
// Wellsfargopayout,
Wise,
Worldline,
Worldpay,
Signifyd,
Plaid,
Riskified,
// Xendit,
Zen,
Zsl,
}
impl Connector {
#[cfg(feature = "payouts")]
pub fn supports_instant_payout(self, payout_method: Option<PayoutType>) -> bool {
matches!(
(self, payout_method),
(Self::Paypal, Some(PayoutType::Wallet))
| (_, Some(PayoutType::Card))
| (Self::Adyenplatform, _)
)
}
#[cfg(feature = "payouts")]
pub fn supports_create_recipient(self, payout_method: Option<PayoutType>) -> bool {
matches!((self, payout_method), (_, Some(PayoutType::Bank)))
}
#[cfg(feature = "payouts")]
pub fn supports_payout_eligibility(self, payout_method: Option<PayoutType>) -> bool {
matches!((self, payout_method), (_, Some(PayoutType::Card)))
}
#[cfg(feature = "payouts")]
pub fn is_payout_quote_call_required(self) -> bool {
matches!(self, Self::Wise)
}
#[cfg(feature = "payouts")]
pub fn supports_access_token_for_payout(self, payout_method: Option<PayoutType>) -> bool {
matches!((self, payout_method), (Self::Paypal, _))
}
#[cfg(feature = "payouts")]
pub fn supports_vendor_disburse_account_create_for_payout(self) -> bool {
matches!(self, Self::Stripe)
}
pub fn supports_access_token(self, payment_method: PaymentMethod) -> bool {
matches!(
(self, payment_method),
(Self::Airwallex, _)
| (Self::Deutschebank, _)
| (Self::Globalpay, _)
| (Self::Jpmorgan, _)
| (Self::Paypal, _)
| (Self::Payu, _)
| (Self::Trustpay, PaymentMethod::BankRedirect)
| (Self::Iatapay, _)
| (Self::Volt, _)
| (Self::Itaubank, _)
)
}
pub fn supports_file_storage_module(self) -> bool {
matches!(self, Self::Stripe | Self::Checkout)
}
pub fn requires_defend_dispute(self) -> bool {
matches!(self, Self::Checkout)
}
pub fn is_separate_authentication_supported(self) -> bool {
match self {
#[cfg(feature = "dummy_connector")]
Self::DummyConnector1
| Self::DummyConnector2
| Self::DummyConnector3
| Self::DummyConnector4
| Self::DummyConnector5
| Self::DummyConnector6
| Self::DummyConnector7 => false,
Self::Aci
// Add Separate authentication support for connectors
| Self::Adyen
| Self::Adyenplatform
| Self::Airwallex
// | Self::Amazonpay
| Self::Authorizedotnet
| Self::Bambora
| Self::Bamboraapac
| Self::Bankofamerica
| Self::Billwerk
| Self::Bitpay
| Self::Bluesnap
| Self::Boku
| Self::Braintree
| Self::Cashtocode
| Self::Coinbase
| Self::Cryptopay
| Self::Deutschebank
| Self::Digitalvirgo
| Self::Dlocal
| Self::Ebanx
| Self::Elavon
| Self::Fiserv
| Self::Fiservemea
| Self::Fiuu
| Self::Forte
| Self::Globalpay
| Self::Globepay
| Self::Gocardless
| Self::Gpayments
| Self::Helcim
| Self::Iatapay
// | Self::Inespay
| Self::Itaubank
| Self::Jpmorgan
| Self::Klarna
| Self::Mifinity
| Self::Mollie
| Self::Multisafepay
| Self::Nexinets
| Self::Nexixpay
// | Self::Nomupay
| Self::Novalnet
| Self::Nuvei
| Self::Opennode
| Self::Paybox
| Self::Payme
| Self::Payone
| Self::Paypal
| Self::Payu
| Self::Placetopay
| Self::Powertranz
| Self::Prophetpay
| Self::Rapyd
// | Self::Redsys
| Self::Shift4
| Self::Square
| Self::Stax
| Self::Taxjar
// | Self::Thunes
| Self::Trustpay
| Self::Tsys
// | Self::UnifiedAuthenticationService
| Self::Volt
| Self::Wellsfargo
// | Self::Wellsfargopayout
| Self::Wise
| Self::Worldline
| Self::Worldpay
// | Self::Xendit
| Self::Zen
| Self::Zsl
| Self::Signifyd
| Self::Plaid
| Self::Razorpay
| Self::Riskified
| Self::Threedsecureio
| Self::Datatrans
| Self::Netcetera
| Self::CtpMastercard
| Self::Noon
| Self::Stripe => false,
Self::Checkout | Self::Nmi | Self::Cybersource => true,
}
}
pub fn is_pre_processing_required_before_authorize(self) -> bool {
matches!(self, Self::Airwallex)
}
pub fn should_acknowledge_webhook_for_resource_not_found_errors(self) -> bool {
matches!(self, Self::Adyenplatform)
}
#[cfg(feature = "dummy_connector")]
pub fn validate_dummy_connector_enabled(
self,
is_dummy_connector_enabled: bool,
) -> errors::CustomResult<(), errors::ValidationError> {
if !is_dummy_connector_enabled
&& matches!(
self,
Self::DummyConnector1
| Self::DummyConnector2
| Self::DummyConnector3
| Self::DummyConnector4
| Self::DummyConnector5
| Self::DummyConnector6
| Self::DummyConnector7
)
{
Err(errors::ValidationError::InvalidValue {
message: "Invalid connector name".to_string(),
}
.into())
} else {
Ok(())
}
}
}
pub use common_enums::connector_enums::Connector;

View File

@ -179,16 +179,6 @@ impl<T> ApiEventMetric for DisputesMetricsResponse<T> {
Some(ApiEventsType::Miscellaneous)
}
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
impl ApiEventMetric for PaymentMethodIntentConfirmInternal {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::PaymentMethod {
payment_method_id: self.id.clone(),
payment_method: Some(self.payment_method_type),
payment_method_type: Some(self.payment_method_subtype),
})
}
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
impl ApiEventMetric for PaymentMethodIntentCreate {

View File

@ -14,11 +14,11 @@ use crate::payment_methods::CustomerPaymentMethodsListResponse;
use crate::{events, payment_methods::CustomerPaymentMethodsListResponse};
use crate::{
payment_methods::{
CustomerDefaultPaymentMethodResponse, DefaultPaymentMethod, ListCountriesCurrenciesRequest,
ListCountriesCurrenciesResponse, PaymentMethodCollectLinkRenderRequest,
PaymentMethodCollectLinkRequest, PaymentMethodCollectLinkResponse,
PaymentMethodDeleteResponse, PaymentMethodListRequest, PaymentMethodListResponse,
PaymentMethodMigrateResponse, PaymentMethodResponse, PaymentMethodUpdate,
self, ListCountriesCurrenciesRequest, ListCountriesCurrenciesResponse,
PaymentMethodCollectLinkRenderRequest, PaymentMethodCollectLinkRequest,
PaymentMethodCollectLinkResponse, PaymentMethodDeleteResponse, PaymentMethodListRequest,
PaymentMethodListResponse, PaymentMethodMigrateResponse, PaymentMethodResponse,
PaymentMethodUpdate,
},
payments::{
self, ExtendedCardInfoResponse, PaymentIdType, PaymentListConstraints,
@ -211,9 +211,9 @@ impl ApiEventMetric for PaymentMethodResponse {
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::PaymentMethod {
payment_method_id: self.payment_method_id.clone(),
payment_method: self.payment_method_type,
payment_method_type: self.payment_method_subtype,
payment_method_id: self.id.clone(),
payment_method_type: self.payment_method_type,
payment_method_subtype: self.payment_method_subtype,
})
}
}
@ -234,16 +234,17 @@ impl ApiEventMetric for PaymentMethodMigrateResponse {
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::PaymentMethod {
payment_method_id: self.payment_method_response.payment_method_id.clone(),
payment_method: self.payment_method_response.payment_method_type,
payment_method_type: self.payment_method_response.payment_method_subtype,
payment_method_id: self.payment_method_response.id.clone(),
payment_method_type: self.payment_method_response.payment_method_type,
payment_method_subtype: self.payment_method_response.payment_method_subtype,
})
}
}
impl ApiEventMetric for PaymentMethodUpdate {}
impl ApiEventMetric for DefaultPaymentMethod {
#[cfg(feature = "v1")]
impl ApiEventMetric for payment_methods::DefaultPaymentMethod {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::PaymentMethod {
payment_method_id: self.payment_method_id.clone(),
@ -253,6 +254,18 @@ impl ApiEventMetric for DefaultPaymentMethod {
}
}
#[cfg(feature = "v2")]
impl ApiEventMetric for PaymentMethodDeleteResponse {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::PaymentMethod {
payment_method_id: self.id.clone(),
payment_method_type: None,
payment_method_subtype: None,
})
}
}
#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentMethodDeleteResponse {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::PaymentMethod {
@ -282,7 +295,8 @@ impl ApiEventMetric for ListCountriesCurrenciesRequest {}
impl ApiEventMetric for ListCountriesCurrenciesResponse {}
impl ApiEventMetric for PaymentMethodListResponse {}
impl ApiEventMetric for CustomerDefaultPaymentMethodResponse {
#[cfg(feature = "v1")]
impl ApiEventMetric for payment_methods::CustomerDefaultPaymentMethodResponse {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::PaymentMethod {
payment_method_id: self.default_payment_method_id.clone().unwrap_or_default(),

View File

@ -194,39 +194,6 @@ impl PaymentMethodIntentConfirm {
}
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct PaymentMethodIntentConfirmInternal {
#[schema(value_type = Option<String>, max_length = 64, min_length = 1, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
pub id: String,
/// The type of payment method use for the payment.
#[schema(value_type = PaymentMethod,example = "card")]
pub payment_method_type: api_enums::PaymentMethod,
/// This is a sub-category of payment method.
#[schema(value_type = PaymentMethodType,example = "credit")]
pub payment_method_subtype: api_enums::PaymentMethodType,
/// The unique identifier of the customer.
#[schema(value_type = Option<String>, max_length = 64, min_length = 1, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
pub customer_id: Option<id_type::CustomerId>,
/// Payment method data to be passed
pub payment_method_data: PaymentMethodCreateData,
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
impl From<PaymentMethodIntentConfirmInternal> for PaymentMethodIntentConfirm {
fn from(item: PaymentMethodIntentConfirmInternal) -> Self {
Self {
payment_method_type: item.payment_method_type,
payment_method_subtype: item.payment_method_subtype,
customer_id: item.customer_id,
payment_method_data: item.payment_method_data.clone(),
}
}
}
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
/// This struct is only used by and internal api to migrate payment method
pub struct PaymentMethodMigrate {
@ -776,6 +743,10 @@ pub struct PaymentMethodResponse {
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
#[derive(Debug, serde::Deserialize, serde::Serialize, ToSchema, Clone)]
pub struct PaymentMethodResponse {
/// The unique identifier of the Payment method
#[schema(value_type = String, example = "12345_pm_01926c58bc6e77c09e809964e72af8c8")]
pub id: id_type::GlobalPaymentMethodId,
/// Unique identifier for a merchant
#[schema(value_type = String, example = "merchant_1671528864")]
pub merchant_id: id_type::MerchantId,
@ -789,10 +760,6 @@ pub struct PaymentMethodResponse {
)]
pub customer_id: id_type::GlobalCustomerId,
/// The unique identifier of the Payment method
#[schema(example = "card_rGK4Vi5iSW70MY7J2mIg")]
pub payment_method_id: String,
/// The type of payment method use for the payment.
#[schema(value_type = PaymentMethod, example = "card")]
pub payment_method_type: Option<api_enums::PaymentMethod>,
@ -1043,6 +1010,13 @@ impl From<CardDetailFromLocker> for payments::AdditionalCardInfo {
}
}
#[cfg(feature = "v2")]
#[derive(Debug, serde::Serialize, ToSchema)]
pub struct PaymentMethodListResponse {
/// The list of payment methods that are enabled for the business profile
pub payment_methods_enabled: Vec<ResponsePaymentMethodTypes>,
}
#[cfg(all(
any(feature = "v1", feature = "v2"),
not(feature = "payment_methods_v2")
@ -1246,19 +1220,19 @@ pub struct ResponsePaymentMethodTypes {
#[derive(Debug, Clone, serde::Serialize, ToSchema, PartialEq)]
#[serde(untagged)] // Untagged used for serialization only
pub enum PaymentMethodSubtypeSpecificData {
#[schema(title = "card")]
Card {
card_networks: Vec<CardNetworkTypes>,
},
Bank {
bank_names: Vec<BankCodeResponse>,
},
#[schema(title = "bank")]
Bank { bank_names: Vec<BankCodeResponse> },
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
#[derive(Debug, Clone, serde::Serialize, ToSchema, PartialEq)]
pub struct ResponsePaymentMethodTypes {
/// The payment method type enabled
#[schema(example = "klarna", value_type = PaymentMethodType)]
#[schema(example = "pay_later", value_type = PaymentMethod)]
pub payment_method_type: common_enums::PaymentMethod,
/// The payment method subtype enabled
@ -1271,10 +1245,7 @@ pub struct ResponsePaymentMethodTypes {
/// Required fields for the payment_method_type.
/// This is the union of all the required fields for the payment method type enabled in all the connectors.
pub required_fields: Option<HashMap<String, RequiredFieldInfo>>,
/// surcharge details for this payment method type if exists
pub surcharge_details: Option<SurchargeDetailsResponse>,
pub required_fields: Vec<RequiredFieldInfo>,
}
#[derive(Clone, Debug, PartialEq, serde::Serialize, ToSchema)]
@ -1678,6 +1649,7 @@ fn set_or_reject_duplicate<T, E: de::Error>(
}
}
#[cfg(feature = "v1")]
#[derive(Debug, serde::Serialize, ToSchema)]
pub struct PaymentMethodListResponse {
/// Redirect URL of the merchant
@ -1758,9 +1730,11 @@ pub struct PaymentMethodDeleteResponse {
#[derive(Debug, serde::Serialize, ToSchema)]
pub struct PaymentMethodDeleteResponse {
/// The unique identifier of the Payment method
#[schema(example = "card_rGK4Vi5iSW70MY7J2mIg")]
pub payment_method_id: String,
#[schema(value_type = String, example = "12345_pm_01926c58bc6e77c09e809964e72af8c8")]
pub id: id_type::GlobalPaymentMethodId,
}
#[cfg(feature = "v1")]
#[derive(Debug, serde::Serialize, ToSchema)]
pub struct CustomerDefaultPaymentMethodResponse {
/// The unique identifier of the Payment method
@ -2046,12 +2020,14 @@ pub struct PaymentMethodId {
pub payment_method_id: String,
}
#[cfg(feature = "v1")]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, ToSchema)]
pub struct DefaultPaymentMethod {
#[schema(value_type = String, max_length = 64, min_length = 1, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
pub customer_id: id_type::CustomerId,
pub payment_method_id: String,
}
//------------------------------------------------TokenizeService------------------------------------------------
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct TokenizePayloadEncrypted {

View File

@ -6558,8 +6558,7 @@ pub struct PaymentMethodsListRequest {}
#[derive(Debug, serde::Serialize, ToSchema)]
pub struct PaymentMethodListResponseForPayments {
/// The list of payment methods that are enabled for the business profile
#[schema(value_type = Vec<ResponsePaymentMethodTypes>)]
pub payment_methods_enabled: Vec<payment_methods::ResponsePaymentMethodTypes>,
pub payment_methods_enabled: Vec<ResponsePaymentMethodTypesForPayments>,
/// The list of payment methods that are saved by the given customer
/// This field is only returned if the customer_id is provided in the request
@ -6567,6 +6566,32 @@ pub struct PaymentMethodListResponseForPayments {
pub customer_payment_methods: Option<Vec<payment_methods::CustomerPaymentMethod>>,
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
#[derive(Debug, Clone, serde::Serialize, ToSchema, PartialEq)]
pub struct ResponsePaymentMethodTypesForPayments {
/// The payment method type enabled
#[schema(example = "pay_later", value_type = PaymentMethod)]
pub payment_method_type: common_enums::PaymentMethod,
/// The payment method subtype enabled
#[schema(example = "klarna", value_type = PaymentMethodType)]
pub payment_method_subtype: common_enums::PaymentMethodType,
/// payment method subtype specific information
#[serde(flatten)]
#[schema(value_type = Option<PaymentMethodSubtypeSpecificData>)]
pub extra_information: Option<payment_methods::PaymentMethodSubtypeSpecificData>,
/// Required fields for the payment_method_type.
/// This is the union of all the required fields for the payment method type enabled in all the connectors.
#[schema(value_type = Option<RequiredFieldInfo>)]
pub required_fields: Option<Vec<payment_methods::RequiredFieldInfo>>,
/// surcharge details for this payment method type if exists
#[schema(value_type = Option<SurchargeDetailsResponse>)]
pub surcharge_details: Option<payment_methods::SurchargeDetailsResponse>,
}
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, ToSchema)]
pub struct PaymentsExternalAuthenticationResponse {
/// Indicates the transaction status