use std::str::FromStr; pub use common_enums::*; use utoipa::ToSchema; #[derive( Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, strum::Display, strum::EnumString, )] /// The routing algorithm to be used to process the incoming request from merchant to outgoing payment processor or payment method. The default is 'Custom' #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum RoutingAlgorithm { RoundRobin, MaxConversion, MinCost, Custom, } /// 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 { #[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, Authorizedotnet, Bambora, Bankofamerica, Billwerk, Bitpay, Bluesnap, Boku, Braintree, Cashtocode, Checkout, Coinbase, Cryptopay, Cybersource, Dlocal, Ebanx, Fiserv, Forte, Globalpay, Globepay, Gocardless, Gpayments, Helcim, Iatapay, Klarna, // Mifinity, Added as template code for future usage Mollie, Multisafepay, Netcetera, Nexinets, Nmi, Noon, Nuvei, // Opayo, added as template code for future usage Opennode, // 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, Shift4, Square, Stax, Stripe, Threedsecureio, Trustpay, // Tsys, Tsys, Volt, Wise, Worldline, Worldpay, Signifyd, Plaid, Riskified, Zen, Zsl, } impl Connector { #[cfg(feature = "payouts")] pub fn supports_instant_payout(&self, payout_method: PayoutType) -> bool { matches!( (self, payout_method), (Self::Paypal, PayoutType::Wallet) | (_, PayoutType::Card) ) } #[cfg(feature = "payouts")] pub fn supports_create_recipient(&self, payout_method: PayoutType) -> bool { matches!((self, payout_method), (_, PayoutType::Bank)) } #[cfg(feature = "payouts")] pub fn supports_payout_eligibility(&self, payout_method: PayoutType) -> bool { matches!((self, payout_method), (_, PayoutType::Card)) } #[cfg(feature = "payouts")] pub fn supports_access_token_for_payout(&self, payout_method: 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::Globalpay, _) | (Self::Paypal, _) | (Self::Payu, _) | (Self::Trustpay, PaymentMethod::BankRedirect) | (Self::Iatapay, _) | (Self::Volt, _) ) } 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 | Self::Adyen | Self::Airwallex | Self::Authorizedotnet | Self::Bambora | Self::Bankofamerica | Self::Billwerk | Self::Bitpay | Self::Bluesnap | Self::Boku | Self::Braintree | Self::Cashtocode | Self::Coinbase | Self::Cryptopay | Self::Dlocal | Self::Ebanx | Self::Fiserv | Self::Forte | Self::Globalpay | Self::Globepay | Self::Gocardless | Self::Gpayments | Self::Helcim | Self::Iatapay | Self::Klarna // | Self::Mifinity Added as template code for future usage | Self::Mollie | Self::Multisafepay | Self::Nexinets | Self::Nuvei | Self::Opennode | Self::Payme | Self::Payone | Self::Paypal | Self::Payu | Self::Placetopay | Self::Powertranz | Self::Prophetpay | Self::Rapyd | Self::Shift4 | Self::Square | Self::Stax | Self::Trustpay | Self::Tsys | Self::Volt | Self::Wise | Self::Worldline | Self::Worldpay | Self::Zen | Self::Zsl | Self::Signifyd | Self::Plaid | Self::Riskified | Self::Threedsecureio | Self::Netcetera | 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) } } #[derive( Clone, Copy, Debug, Eq, Hash, PartialEq, serde::Serialize, serde::Deserialize, strum::Display, strum::EnumString, ToSchema, )] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum AuthenticationConnectors { Threedsecureio, Netcetera, Gpayments, } impl AuthenticationConnectors { pub fn is_separate_version_call_required(&self) -> bool { match self { Self::Threedsecureio | Self::Netcetera => false, Self::Gpayments => true, } } } #[cfg(feature = "payouts")] #[derive( Clone, Copy, Debug, Eq, Hash, PartialEq, serde::Serialize, serde::Deserialize, strum::Display, strum::EnumString, ToSchema, )] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum PayoutConnectors { Adyen, Stripe, Payone, Paypal, Ebanx, Cybersource, Wise, } #[cfg(feature = "payouts")] impl From for RoutableConnectors { fn from(value: PayoutConnectors) -> Self { match value { PayoutConnectors::Adyen => Self::Adyen, PayoutConnectors::Stripe => Self::Stripe, PayoutConnectors::Payone => Self::Payone, PayoutConnectors::Paypal => Self::Paypal, PayoutConnectors::Ebanx => Self::Ebanx, PayoutConnectors::Cybersource => Self::Cybersource, PayoutConnectors::Wise => Self::Wise, } } } #[cfg(feature = "payouts")] impl From for Connector { fn from(value: PayoutConnectors) -> Self { match value { PayoutConnectors::Adyen => Self::Adyen, PayoutConnectors::Stripe => Self::Stripe, PayoutConnectors::Payone => Self::Payone, PayoutConnectors::Paypal => Self::Paypal, PayoutConnectors::Ebanx => Self::Ebanx, PayoutConnectors::Cybersource => Self::Cybersource, PayoutConnectors::Wise => Self::Wise, } } } #[cfg(feature = "payouts")] impl TryFrom for PayoutConnectors { type Error = String; fn try_from(value: Connector) -> Result { match value { Connector::Adyen => Ok(Self::Adyen), Connector::Stripe => Ok(Self::Stripe), Connector::Wise => Ok(Self::Wise), Connector::Paypal => Ok(Self::Paypal), Connector::Ebanx => Ok(Self::Ebanx), Connector::Cybersource => Ok(Self::Cybersource), Connector::Payone => Ok(Self::Payone), _ => Err(format!("Invalid payout connector {}", value)), } } } #[cfg(feature = "frm")] #[derive( Clone, Copy, Debug, Eq, Hash, PartialEq, serde::Serialize, serde::Deserialize, strum::Display, strum::EnumString, ToSchema, )] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum FrmConnectors { /// Signifyd Risk Manager. Official docs: https://docs.signifyd.com/ Signifyd, Riskified, } #[derive( Clone, Debug, serde::Deserialize, serde::Serialize, strum::Display, strum::EnumString, ToSchema, )] #[strum(serialize_all = "snake_case")] #[serde(rename_all = "snake_case")] pub enum FrmAction { CancelTxn, AutoRefund, ManualReview, } #[derive( Clone, Debug, serde::Deserialize, serde::Serialize, strum::Display, strum::EnumString, ToSchema, )] #[strum(serialize_all = "snake_case")] #[serde(rename_all = "snake_case")] pub enum FrmPreferredFlowTypes { Pre, Post, } #[derive(Debug, Eq, PartialEq, Clone, serde::Serialize, serde::Deserialize)] pub struct UnresolvedResponseReason { pub code: String, /// A message to merchant to give hint on next action he/she should do to resolve pub message: String, } /// Possible field type of required fields in payment_method_data #[derive( Clone, Debug, Eq, serde::Deserialize, serde::Serialize, strum::Display, strum::EnumString, ToSchema, )] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum FieldType { UserCardNumber, UserCardExpiryMonth, UserCardExpiryYear, UserCardCvc, UserFullName, UserEmailAddress, UserPhoneNumber, UserCountryCode, //phone number's country code UserCountry { options: Vec }, //for country inside payment method data ex- bank redirect UserCurrency { options: Vec }, UserBillingName, UserAddressLine1, UserAddressLine2, UserAddressCity, UserAddressPincode, UserAddressState, UserAddressCountry { options: Vec }, UserShippingName, UserShippingAddressLine1, UserShippingAddressLine2, UserShippingAddressCity, UserShippingAddressPincode, UserShippingAddressState, UserShippingAddressCountry { options: Vec }, UserBlikCode, UserBank, Text, DropDown { options: Vec }, } impl FieldType { pub fn get_billing_variants() -> Vec { vec![ Self::UserBillingName, Self::UserAddressLine1, Self::UserAddressLine2, Self::UserAddressCity, Self::UserAddressPincode, Self::UserAddressState, Self::UserAddressCountry { options: vec![] }, ] } pub fn get_shipping_variants() -> Vec { vec![ Self::UserShippingName, Self::UserShippingAddressLine1, Self::UserShippingAddressLine2, Self::UserShippingAddressCity, Self::UserShippingAddressPincode, Self::UserShippingAddressState, Self::UserShippingAddressCountry { options: vec![] }, ] } } /// This implementatiobn is to ignore the inner value of UserAddressCountry enum while comparing impl PartialEq for FieldType { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::UserCardNumber, Self::UserCardNumber) => true, (Self::UserCardExpiryMonth, Self::UserCardExpiryMonth) => true, (Self::UserCardExpiryYear, Self::UserCardExpiryYear) => true, (Self::UserCardCvc, Self::UserCardCvc) => true, (Self::UserFullName, Self::UserFullName) => true, (Self::UserEmailAddress, Self::UserEmailAddress) => true, (Self::UserPhoneNumber, Self::UserPhoneNumber) => true, (Self::UserCountryCode, Self::UserCountryCode) => true, ( Self::UserCountry { options: options_self, }, Self::UserCountry { options: options_other, }, ) => options_self.eq(options_other), ( Self::UserCurrency { options: options_self, }, Self::UserCurrency { options: options_other, }, ) => options_self.eq(options_other), (Self::UserBillingName, Self::UserBillingName) => true, (Self::UserAddressLine1, Self::UserAddressLine1) => true, (Self::UserAddressLine2, Self::UserAddressLine2) => true, (Self::UserAddressCity, Self::UserAddressCity) => true, (Self::UserAddressPincode, Self::UserAddressPincode) => true, (Self::UserAddressState, Self::UserAddressState) => true, (Self::UserAddressCountry { .. }, Self::UserAddressCountry { .. }) => true, (Self::UserShippingName, Self::UserShippingName) => true, (Self::UserShippingAddressLine1, Self::UserShippingAddressLine1) => true, (Self::UserShippingAddressLine2, Self::UserShippingAddressLine2) => true, (Self::UserShippingAddressCity, Self::UserShippingAddressCity) => true, (Self::UserShippingAddressPincode, Self::UserShippingAddressPincode) => true, (Self::UserShippingAddressState, Self::UserShippingAddressState) => true, (Self::UserShippingAddressCountry { .. }, Self::UserShippingAddressCountry { .. }) => { true } (Self::UserBlikCode, Self::UserBlikCode) => true, (Self::UserBank, Self::UserBank) => true, (Self::Text, Self::Text) => true, ( Self::DropDown { options: options_self, }, Self::DropDown { options: options_other, }, ) => options_self.eq(options_other), _unused => false, } } } #[cfg(test)] mod test { use super::*; #[test] fn test_partialeq_for_field_type() { let user_address_country_is_us = FieldType::UserAddressCountry { options: vec!["US".to_string()], }; let user_address_country_is_all = FieldType::UserAddressCountry { options: vec!["ALL".to_string()], }; assert!(user_address_country_is_us.eq(&user_address_country_is_all)) } } #[derive( Debug, serde::Deserialize, serde::Serialize, strum::Display, strum::EnumString, Clone, PartialEq, Eq, ToSchema, )] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum RetryAction { /// Payment can be retried from the client side until the payment is successful or payment expires or the attempts(configured by the merchant) for payment are exhausted ManualRetry, /// Denotes that the payment is requeued Requeue, } #[derive(Clone, Copy)] pub enum LockerChoice { HyperswitchCardVault, } #[derive( Clone, Copy, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, strum::Display, strum::EnumString, frunk::LabelledGeneric, ToSchema, )] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum PmAuthConnectors { Plaid, } pub fn convert_pm_auth_connector(connector_name: &str) -> Option { PmAuthConnectors::from_str(connector_name).ok() } pub fn convert_authentication_connector(connector_name: &str) -> Option { AuthenticationConnectors::from_str(connector_name).ok() } #[derive( Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, strum::Display, strum::EnumString, ToSchema, Hash, )] pub enum PaymentChargeType { #[serde(untagged)] Stripe(StripeChargeType), } impl Default for PaymentChargeType { fn default() -> Self { Self::Stripe(StripeChargeType::default()) } } #[derive( Clone, Debug, Default, Hash, Eq, PartialEq, ToSchema, serde::Serialize, serde::Deserialize, strum::Display, strum::EnumString, )] #[serde(rename_all = "lowercase")] #[strum(serialize_all = "lowercase")] pub enum StripeChargeType { #[default] Direct, Destination, } #[cfg(feature = "frm")] pub fn convert_frm_connector(connector_name: &str) -> Option { FrmConnectors::from_str(connector_name).ok() }