mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-10-31 10:06:32 +08:00 
			
		
		
		
	feat(payment_link): add multiple custom css support in business level (#5137)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
		| @ -6821,6 +6821,15 @@ | |||||||
|             "properties": { |             "properties": { | ||||||
|               "domain_name": { |               "domain_name": { | ||||||
|                 "type": "string", |                 "type": "string", | ||||||
|  |                 "description": "Custom domain name to be used for hosting the link in your own domain", | ||||||
|  |                 "nullable": true | ||||||
|  |               }, | ||||||
|  |               "business_specific_configs": { | ||||||
|  |                 "type": "object", | ||||||
|  |                 "description": "list of configs for multi theme setup", | ||||||
|  |                 "additionalProperties": { | ||||||
|  |                   "$ref": "#/components/schemas/PaymentLinkConfigRequest" | ||||||
|  |                 }, | ||||||
|                 "nullable": true |                 "nullable": true | ||||||
|               } |               } | ||||||
|             } |             } | ||||||
| @ -14978,6 +14987,11 @@ | |||||||
|             ], |             ], | ||||||
|             "nullable": true |             "nullable": true | ||||||
|           }, |           }, | ||||||
|  |           "payment_link_config_id": { | ||||||
|  |             "type": "string", | ||||||
|  |             "description": "custom payment link config id set at business profile send only if business_specific_configs is configured", | ||||||
|  |             "nullable": true | ||||||
|  |           }, | ||||||
|           "payment_type": { |           "payment_type": { | ||||||
|             "allOf": [ |             "allOf": [ | ||||||
|               { |               { | ||||||
| @ -15311,6 +15325,11 @@ | |||||||
|             ], |             ], | ||||||
|             "nullable": true |             "nullable": true | ||||||
|           }, |           }, | ||||||
|  |           "payment_link_config_id": { | ||||||
|  |             "type": "string", | ||||||
|  |             "description": "custom payment link config id set at business profile send only if business_specific_configs is configured", | ||||||
|  |             "nullable": true | ||||||
|  |           }, | ||||||
|           "profile_id": { |           "profile_id": { | ||||||
|             "type": "string", |             "type": "string", | ||||||
|             "description": "The business profile to use for this payment, if not passed the default business profile\nassociated with the merchant account will be used.", |             "description": "The business profile to use for this payment, if not passed the default business profile\nassociated with the merchant account will be used.", | ||||||
| @ -16351,6 +16370,11 @@ | |||||||
|             ], |             ], | ||||||
|             "nullable": true |             "nullable": true | ||||||
|           }, |           }, | ||||||
|  |           "payment_link_config_id": { | ||||||
|  |             "type": "string", | ||||||
|  |             "description": "custom payment link config id set at business profile send only if business_specific_configs is configured", | ||||||
|  |             "nullable": true | ||||||
|  |           }, | ||||||
|           "profile_id": { |           "profile_id": { | ||||||
|             "type": "string", |             "type": "string", | ||||||
|             "description": "The business profile to use for this payment, if not passed the default business profile\nassociated with the merchant account will be used.", |             "description": "The business profile to use for this payment, if not passed the default business profile\nassociated with the merchant account will be used.", | ||||||
| @ -17359,6 +17383,11 @@ | |||||||
|             ], |             ], | ||||||
|             "nullable": true |             "nullable": true | ||||||
|           }, |           }, | ||||||
|  |           "payment_link_config_id": { | ||||||
|  |             "type": "string", | ||||||
|  |             "description": "custom payment link config id set at business profile send only if business_specific_configs is configured", | ||||||
|  |             "nullable": true | ||||||
|  |           }, | ||||||
|           "surcharge_details": { |           "surcharge_details": { | ||||||
|             "allOf": [ |             "allOf": [ | ||||||
|               { |               { | ||||||
|  | |||||||
| @ -1159,9 +1159,14 @@ pub struct BusinessGenericLinkConfig { | |||||||
|  |  | ||||||
| #[derive(Clone, Debug, serde::Deserialize, serde::Serialize, PartialEq, ToSchema)] | #[derive(Clone, Debug, serde::Deserialize, serde::Serialize, PartialEq, ToSchema)] | ||||||
| pub struct BusinessPaymentLinkConfig { | pub struct BusinessPaymentLinkConfig { | ||||||
|  |     /// Custom domain name to be used for hosting the link in your own domain | ||||||
|     pub domain_name: Option<String>, |     pub domain_name: Option<String>, | ||||||
|  |     /// Default payment link config for all future payment link | ||||||
|     #[serde(flatten)] |     #[serde(flatten)] | ||||||
|     pub config: PaymentLinkConfigRequest, |     #[schema(value_type = PaymentLinkConfigRequest)] | ||||||
|  |     pub default_config: Option<PaymentLinkConfigRequest>, | ||||||
|  |     /// list of configs for multi theme setup | ||||||
|  |     pub business_specific_configs: Option<HashMap<String, PaymentLinkConfigRequest>>, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Clone, Debug, serde::Deserialize, serde::Serialize, PartialEq, ToSchema)] | #[derive(Clone, Debug, serde::Deserialize, serde::Serialize, PartialEq, ToSchema)] | ||||||
|  | |||||||
| @ -469,6 +469,9 @@ pub struct PaymentsRequest { | |||||||
|     #[schema(value_type = Option<PaymentCreatePaymentLinkConfig>)] |     #[schema(value_type = Option<PaymentCreatePaymentLinkConfig>)] | ||||||
|     pub payment_link_config: Option<PaymentCreatePaymentLinkConfig>, |     pub payment_link_config: Option<PaymentCreatePaymentLinkConfig>, | ||||||
|  |  | ||||||
|  |     /// custom payment link config id set at business profile send only if business_specific_configs is configured | ||||||
|  |     pub payment_link_config_id: Option<String>, | ||||||
|  |  | ||||||
|     /// The business profile to use for this payment, if not passed the default business profile |     /// The business profile to use for this payment, if not passed the default business profile | ||||||
|     /// associated with the merchant account will be used. |     /// associated with the merchant account will be used. | ||||||
|     #[remove_in(PaymentsUpdateRequest, PaymentsConfirmRequest)] |     #[remove_in(PaymentsUpdateRequest, PaymentsConfirmRequest)] | ||||||
| @ -5034,7 +5037,7 @@ pub enum PaymentLinkData<'a> { | |||||||
|  |  | ||||||
| #[derive(Debug, serde::Serialize, Clone)] | #[derive(Debug, serde::Serialize, Clone)] | ||||||
| pub struct PaymentLinkDetails { | pub struct PaymentLinkDetails { | ||||||
|     pub amount: String, |     pub amount: StringMajorUnit, | ||||||
|     pub currency: api_enums::Currency, |     pub currency: api_enums::Currency, | ||||||
|     pub pub_key: String, |     pub pub_key: String, | ||||||
|     pub client_secret: String, |     pub client_secret: String, | ||||||
| @ -5055,7 +5058,7 @@ pub struct PaymentLinkDetails { | |||||||
|  |  | ||||||
| #[derive(Debug, serde::Serialize)] | #[derive(Debug, serde::Serialize)] | ||||||
| pub struct PaymentLinkStatusDetails { | pub struct PaymentLinkStatusDetails { | ||||||
|     pub amount: String, |     pub amount: StringMajorUnit, | ||||||
|     pub currency: api_enums::Currency, |     pub currency: api_enums::Currency, | ||||||
|     pub payment_id: String, |     pub payment_id: String, | ||||||
|     pub merchant_logo: String, |     pub merchant_logo: String, | ||||||
| @ -5129,7 +5132,8 @@ pub struct PaymentLinkListResponse { | |||||||
| pub struct PaymentCreatePaymentLinkConfig { | pub struct PaymentCreatePaymentLinkConfig { | ||||||
|     #[serde(flatten)] |     #[serde(flatten)] | ||||||
|     #[schema(value_type = Option<PaymentLinkConfigRequest>)] |     #[schema(value_type = Option<PaymentLinkConfigRequest>)] | ||||||
|     pub config: admin::PaymentLinkConfigRequest, |     /// Theme config for the particular payment | ||||||
|  |     pub theme_config: admin::PaymentLinkConfigRequest, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Debug, Default, Eq, PartialEq, serde::Deserialize, serde::Serialize, Clone, ToSchema)] | #[derive(Debug, Default, Eq, PartialEq, serde::Deserialize, serde::Serialize, Clone, ToSchema)] | ||||||
| @ -5141,7 +5145,7 @@ pub struct OrderDetailsWithStringAmount { | |||||||
|     #[schema(example = 1)] |     #[schema(example = 1)] | ||||||
|     pub quantity: u16, |     pub quantity: u16, | ||||||
|     /// the amount per quantity of product |     /// the amount per quantity of product | ||||||
|     pub amount: String, |     pub amount: StringMajorUnit, | ||||||
|     /// Product Image link |     /// Product Image link | ||||||
|     pub product_img_link: Option<String>, |     pub product_img_link: Option<String>, | ||||||
| } | } | ||||||
|  | |||||||
| @ -251,6 +251,28 @@ impl AmountConvertor for StringMinorUnitForConnector { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Core required conversion type | ||||||
|  | #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq)] | ||||||
|  | pub struct StringMajorUnitForCore; | ||||||
|  | impl AmountConvertor for StringMajorUnitForCore { | ||||||
|  |     type Output = StringMajorUnit; | ||||||
|  |     fn convert( | ||||||
|  |         &self, | ||||||
|  |         amount: MinorUnit, | ||||||
|  |         currency: enums::Currency, | ||||||
|  |     ) -> Result<Self::Output, error_stack::Report<ParsingError>> { | ||||||
|  |         amount.to_major_unit_as_string(currency) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn convert_back( | ||||||
|  |         &self, | ||||||
|  |         amount: StringMajorUnit, | ||||||
|  |         currency: enums::Currency, | ||||||
|  |     ) -> Result<MinorUnit, error_stack::Report<ParsingError>> { | ||||||
|  |         amount.to_minor_unit_as_i64(currency) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| /// Connector required amount type | /// Connector required amount type | ||||||
| #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq)] | #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq)] | ||||||
| pub struct StringMajorUnitForConnector; | pub struct StringMajorUnitForConnector; | ||||||
|  | |||||||
| @ -275,6 +275,8 @@ pub enum ApiErrorResponse { | |||||||
|     MissingTenantId, |     MissingTenantId, | ||||||
|     #[error(error_type = ErrorType::ProcessingError, code = "HE_06", message = "Invalid tenant id: {tenant_id}")] |     #[error(error_type = ErrorType::ProcessingError, code = "HE_06", message = "Invalid tenant id: {tenant_id}")] | ||||||
|     InvalidTenant { tenant_id: String }, |     InvalidTenant { tenant_id: String }, | ||||||
|  |     #[error(error_type = ErrorType::ValidationError, code = "HE_01", message = "Failed to convert amount to {amount_type} type")] | ||||||
|  |     AmountConversionFailed { amount_type: &'static str }, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Clone)] | #[derive(Clone)] | ||||||
| @ -613,6 +615,9 @@ impl ErrorSwitch<api_models::errors::types::ApiErrorResponse> for ApiErrorRespon | |||||||
|             Self::InvalidTenant { tenant_id }  => { |             Self::InvalidTenant { tenant_id }  => { | ||||||
|                 AER::InternalServerError(ApiError::new("HE", 6, format!("Invalid Tenant {tenant_id}"), None)) |                 AER::InternalServerError(ApiError::new("HE", 6, format!("Invalid Tenant {tenant_id}"), None)) | ||||||
|             } |             } | ||||||
|  |             Self::AmountConversionFailed { amount_type }  => { | ||||||
|  |                 AER::InternalServerError(ApiError::new("HE", 6, format!("Failed to convert amount to {amount_type} type"), None)) | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -266,6 +266,8 @@ pub enum StripeErrorCode { | |||||||
|     ExtendedCardInfoNotFound, |     ExtendedCardInfoNotFound, | ||||||
|     #[error(error_type = StripeErrorType::InvalidRequestError, code = "IR_28", message = "Invalid tenant")] |     #[error(error_type = StripeErrorType::InvalidRequestError, code = "IR_28", message = "Invalid tenant")] | ||||||
|     InvalidTenant, |     InvalidTenant, | ||||||
|  |     #[error(error_type = StripeErrorType::HyperswitchError, code = "HE_01", message = "Failed to convert amount to {amount_type} type")] | ||||||
|  |     AmountConversionFailed { amount_type: &'static str }, | ||||||
|     // [#216]: https://github.com/juspay/hyperswitch/issues/216 |     // [#216]: https://github.com/juspay/hyperswitch/issues/216 | ||||||
|     // Implement the remaining stripe error codes |     // Implement the remaining stripe error codes | ||||||
|  |  | ||||||
| @ -650,6 +652,9 @@ impl From<errors::ApiErrorResponse> for StripeErrorCode { | |||||||
|             errors::ApiErrorResponse::ExtendedCardInfoNotFound => Self::ExtendedCardInfoNotFound, |             errors::ApiErrorResponse::ExtendedCardInfoNotFound => Self::ExtendedCardInfoNotFound, | ||||||
|             errors::ApiErrorResponse::InvalidTenant { tenant_id: _ } |             errors::ApiErrorResponse::InvalidTenant { tenant_id: _ } | ||||||
|             | errors::ApiErrorResponse::MissingTenantId => Self::InvalidTenant, |             | errors::ApiErrorResponse::MissingTenantId => Self::InvalidTenant, | ||||||
|  |             errors::ApiErrorResponse::AmountConversionFailed { amount_type } => { | ||||||
|  |                 Self::AmountConversionFailed { amount_type } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -730,7 +735,8 @@ impl actix_web::ResponseError for StripeErrorCode { | |||||||
|             | Self::MandateActive |             | Self::MandateActive | ||||||
|             | Self::CustomerRedacted |             | Self::CustomerRedacted | ||||||
|             | Self::WebhookProcessingError |             | Self::WebhookProcessingError | ||||||
|             | Self::InvalidTenant => StatusCode::INTERNAL_SERVER_ERROR, |             | Self::InvalidTenant | ||||||
|  |             | Self::AmountConversionFailed { .. } => StatusCode::INTERNAL_SERVER_ERROR, | ||||||
|             Self::ReturnUrlUnavailable => StatusCode::SERVICE_UNAVAILABLE, |             Self::ReturnUrlUnavailable => StatusCode::SERVICE_UNAVAILABLE, | ||||||
|             Self::ExternalConnectorError { status_code, .. } => { |             Self::ExternalConnectorError { status_code, .. } => { | ||||||
|                 StatusCode::from_u16(*status_code).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR) |                 StatusCode::from_u16(*status_code).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR) | ||||||
|  | |||||||
| @ -5,6 +5,7 @@ use common_utils::{ | |||||||
|         DEFAULT_MERCHANT_LOGO, DEFAULT_PRODUCT_IMG, DEFAULT_SDK_LAYOUT, DEFAULT_SESSION_EXPIRY, |         DEFAULT_MERCHANT_LOGO, DEFAULT_PRODUCT_IMG, DEFAULT_SDK_LAYOUT, DEFAULT_SESSION_EXPIRY, | ||||||
|     }, |     }, | ||||||
|     ext_traits::{OptionExt, ValueExt}, |     ext_traits::{OptionExt, ValueExt}, | ||||||
|  |     types::{AmountConvertor, MinorUnit, StringMajorUnitForCore}, | ||||||
| }; | }; | ||||||
| use error_stack::ResultExt; | use error_stack::ResultExt; | ||||||
| use futures::future; | use futures::future; | ||||||
| @ -14,6 +15,7 @@ use time::PrimitiveDateTime; | |||||||
| use super::errors::{self, RouterResult, StorageErrorExt}; | use super::errors::{self, RouterResult, StorageErrorExt}; | ||||||
| use crate::{ | use crate::{ | ||||||
|     errors::RouterResponse, |     errors::RouterResponse, | ||||||
|  |     get_payment_link_config_value, get_payment_link_config_value_based_on_priority, | ||||||
|     routes::SessionState, |     routes::SessionState, | ||||||
|     services, |     services, | ||||||
|     types::{ |     types::{ | ||||||
| @ -121,9 +123,15 @@ pub async fn initiate_payment_link_flow( | |||||||
|         payment_intent.currency, |         payment_intent.currency, | ||||||
|         payment_intent.client_secret.clone(), |         payment_intent.client_secret.clone(), | ||||||
|     )?; |     )?; | ||||||
|     let amount = currency |  | ||||||
|         .to_currency_base_unit(payment_intent.amount.get_amount_as_i64()) |     let required_conversion_type = StringMajorUnitForCore; | ||||||
|         .change_context(errors::ApiErrorResponse::CurrencyConversionFailed)?; |  | ||||||
|  |     let amount = required_conversion_type | ||||||
|  |         .convert(payment_intent.amount, currency) | ||||||
|  |         .change_context(errors::ApiErrorResponse::AmountConversionFailed { | ||||||
|  |             amount_type: "StringMajorUnit", | ||||||
|  |         })?; | ||||||
|  |  | ||||||
|     let order_details = validate_order_details(payment_intent.order_details.clone(), currency)?; |     let order_details = validate_order_details(payment_intent.order_details.clone(), currency)?; | ||||||
|  |  | ||||||
|     let session_expiry = payment_link.fulfilment_time.unwrap_or_else(|| { |     let session_expiry = payment_link.fulfilment_time.unwrap_or_else(|| { | ||||||
| @ -325,6 +333,7 @@ fn validate_order_details( | |||||||
|     Option<Vec<api_models::payments::OrderDetailsWithStringAmount>>, |     Option<Vec<api_models::payments::OrderDetailsWithStringAmount>>, | ||||||
|     error_stack::Report<errors::ApiErrorResponse>, |     error_stack::Report<errors::ApiErrorResponse>, | ||||||
| > { | > { | ||||||
|  |     let required_conversion_type = StringMajorUnitForCore; | ||||||
|     let order_details = order_details |     let order_details = order_details | ||||||
|         .map(|order_details| { |         .map(|order_details| { | ||||||
|             order_details |             order_details | ||||||
| @ -356,10 +365,11 @@ fn validate_order_details( | |||||||
|                         .product_img_link |                         .product_img_link | ||||||
|                         .clone_from(&order.product_img_link) |                         .clone_from(&order.product_img_link) | ||||||
|                 }; |                 }; | ||||||
|                 order_details_amount_string.amount = |                 order_details_amount_string.amount = required_conversion_type | ||||||
|                     currency |                     .convert(MinorUnit::new(order.amount), currency) | ||||||
|                         .to_currency_base_unit(order.amount) |                     .change_context(errors::ApiErrorResponse::AmountConversionFailed { | ||||||
|                         .change_context(errors::ApiErrorResponse::CurrencyConversionFailed)?; |                         amount_type: "StringMajorUnit", | ||||||
|  |                     })?; | ||||||
|                 order_details_amount_string.product_name = |                 order_details_amount_string.product_name = | ||||||
|                     capitalize_first_char(&order.product_name.clone()); |                     capitalize_first_char(&order.product_name.clone()); | ||||||
|                 order_details_amount_string.quantity = order.quantity; |                 order_details_amount_string.quantity = order.quantity; | ||||||
| @ -386,9 +396,11 @@ pub fn get_payment_link_config_based_on_priority( | |||||||
|     business_link_config: Option<serde_json::Value>, |     business_link_config: Option<serde_json::Value>, | ||||||
|     merchant_name: String, |     merchant_name: String, | ||||||
|     default_domain_name: String, |     default_domain_name: String, | ||||||
|  |     payment_link_config_id: Option<String>, | ||||||
| ) -> Result<(admin_types::PaymentLinkConfig, String), error_stack::Report<errors::ApiErrorResponse>> | ) -> Result<(admin_types::PaymentLinkConfig, String), error_stack::Report<errors::ApiErrorResponse>> | ||||||
| { | { | ||||||
|     let (domain_name, business_config) = if let Some(business_config) = business_link_config { |     let (domain_name, business_theme_configs) = if let Some(business_config) = business_link_config | ||||||
|  |     { | ||||||
|         let extracted_value: api_models::admin::BusinessPaymentLinkConfig = business_config |         let extracted_value: api_models::admin::BusinessPaymentLinkConfig = business_config | ||||||
|             .parse_value("BusinessPaymentLinkConfig") |             .parse_value("BusinessPaymentLinkConfig") | ||||||
|             .change_context(errors::ApiErrorResponse::InvalidDataValue { |             .change_context(errors::ApiErrorResponse::InvalidDataValue { | ||||||
| @ -402,73 +414,32 @@ pub fn get_payment_link_config_based_on_priority( | |||||||
|                 .clone() |                 .clone() | ||||||
|                 .map(|d_name| format!("https://{}", d_name)) |                 .map(|d_name| format!("https://{}", d_name)) | ||||||
|                 .unwrap_or_else(|| default_domain_name.clone()), |                 .unwrap_or_else(|| default_domain_name.clone()), | ||||||
|             Some(extracted_value.config), |             payment_link_config_id | ||||||
|  |                 .and_then(|id| { | ||||||
|  |                     extracted_value | ||||||
|  |                         .business_specific_configs | ||||||
|  |                         .as_ref() | ||||||
|  |                         .and_then(|specific_configs| specific_configs.get(&id).cloned()) | ||||||
|  |                 }) | ||||||
|  |                 .or(extracted_value.default_config), | ||||||
|         ) |         ) | ||||||
|     } else { |     } else { | ||||||
|         (default_domain_name, None) |         (default_domain_name, None) | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     let theme = payment_create_link_config |     let (theme, logo, seller_name, sdk_layout, display_sdk_only, enabled_saved_payment_method) = get_payment_link_config_value!( | ||||||
|         .as_ref() |         payment_create_link_config, | ||||||
|         .and_then(|pc_config| pc_config.config.theme.clone()) |         business_theme_configs, | ||||||
|         .or_else(|| { |         (theme, DEFAULT_BACKGROUND_COLOR.to_string()), | ||||||
|             business_config |         (logo, DEFAULT_MERCHANT_LOGO.to_string()), | ||||||
|                 .as_ref() |         (seller_name, merchant_name.clone()), | ||||||
|                 .and_then(|business_config| business_config.theme.clone()) |         (sdk_layout, DEFAULT_SDK_LAYOUT.to_owned()), | ||||||
|         }) |         (display_sdk_only, DEFAULT_DISPLAY_SDK_ONLY), | ||||||
|         .unwrap_or(DEFAULT_BACKGROUND_COLOR.to_string()); |         ( | ||||||
|  |             enabled_saved_payment_method, | ||||||
|     let logo = payment_create_link_config |             DEFAULT_ENABLE_SAVED_PAYMENT_METHOD | ||||||
|         .as_ref() |         ) | ||||||
|         .and_then(|pc_config| pc_config.config.logo.clone()) |     ); | ||||||
|         .or_else(|| { |  | ||||||
|             business_config |  | ||||||
|                 .as_ref() |  | ||||||
|                 .and_then(|business_config| business_config.logo.clone()) |  | ||||||
|         }) |  | ||||||
|         .unwrap_or(DEFAULT_MERCHANT_LOGO.to_string()); |  | ||||||
|  |  | ||||||
|     let seller_name = payment_create_link_config |  | ||||||
|         .as_ref() |  | ||||||
|         .and_then(|pc_config| pc_config.config.seller_name.clone()) |  | ||||||
|         .or_else(|| { |  | ||||||
|             business_config |  | ||||||
|                 .as_ref() |  | ||||||
|                 .and_then(|business_config| business_config.seller_name.clone()) |  | ||||||
|         }) |  | ||||||
|         .unwrap_or(merchant_name.clone()); |  | ||||||
|  |  | ||||||
|     let sdk_layout = payment_create_link_config |  | ||||||
|         .as_ref() |  | ||||||
|         .and_then(|pc_config| pc_config.config.sdk_layout.clone()) |  | ||||||
|         .or_else(|| { |  | ||||||
|             business_config |  | ||||||
|                 .as_ref() |  | ||||||
|                 .and_then(|business_config| business_config.sdk_layout.clone()) |  | ||||||
|         }) |  | ||||||
|         .unwrap_or(DEFAULT_SDK_LAYOUT.to_owned()); |  | ||||||
|  |  | ||||||
|     let display_sdk_only = payment_create_link_config |  | ||||||
|         .as_ref() |  | ||||||
|         .and_then(|pc_config| { |  | ||||||
|             pc_config.config.display_sdk_only.or_else(|| { |  | ||||||
|                 business_config |  | ||||||
|                     .as_ref() |  | ||||||
|                     .and_then(|business_config| business_config.display_sdk_only) |  | ||||||
|             }) |  | ||||||
|         }) |  | ||||||
|         .unwrap_or(DEFAULT_DISPLAY_SDK_ONLY); |  | ||||||
|  |  | ||||||
|     let enabled_saved_payment_method = payment_create_link_config |  | ||||||
|         .as_ref() |  | ||||||
|         .and_then(|pc_config| { |  | ||||||
|             pc_config.config.enabled_saved_payment_method.or_else(|| { |  | ||||||
|                 business_config |  | ||||||
|                     .as_ref() |  | ||||||
|                     .and_then(|business_config| business_config.enabled_saved_payment_method) |  | ||||||
|             }) |  | ||||||
|         }) |  | ||||||
|         .unwrap_or(DEFAULT_ENABLE_SAVED_PAYMENT_METHOD); |  | ||||||
|  |  | ||||||
|     let payment_link_config = admin_types::PaymentLinkConfig { |     let payment_link_config = admin_types::PaymentLinkConfig { | ||||||
|         theme, |         theme, | ||||||
| @ -567,9 +538,13 @@ pub async fn get_payment_link_status( | |||||||
|                 field_name: "currency", |                 field_name: "currency", | ||||||
|             })?; |             })?; | ||||||
|  |  | ||||||
|     let amount = currency |     let required_conversion_type = StringMajorUnitForCore; | ||||||
|         .to_currency_base_unit(payment_attempt.net_amount.get_amount_as_i64()) |  | ||||||
|         .change_context(errors::ApiErrorResponse::CurrencyConversionFailed)?; |     let amount = required_conversion_type | ||||||
|  |         .convert(payment_attempt.net_amount, currency) | ||||||
|  |         .change_context(errors::ApiErrorResponse::AmountConversionFailed { | ||||||
|  |             amount_type: "StringMajorUnit", | ||||||
|  |         })?; | ||||||
|  |  | ||||||
|     // converting first letter of merchant name to upperCase |     // converting first letter of merchant name to upperCase | ||||||
|     let merchant_name = capitalize_first_char(&payment_link_config.seller_name); |     let merchant_name = capitalize_first_char(&payment_link_config.seller_name); | ||||||
|  | |||||||
| @ -216,18 +216,18 @@ function boot() { | |||||||
|         "quantity": null |         "quantity": null | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|     if (paymentDetails.merchant_name) { |   if (paymentDetails.merchant_name) { | ||||||
|       document.title = "Payment requested by " + paymentDetails.merchant_name; |     document.title = "Payment requested by " + paymentDetails.merchant_name; | ||||||
|     } |   } | ||||||
|  |  | ||||||
|     if (paymentDetails.merchant_logo) { |   if (paymentDetails.merchant_logo) { | ||||||
|       var link = document.createElement("link"); |     var link = document.createElement("link"); | ||||||
|       link.rel = "icon"; |     link.rel = "icon"; | ||||||
|       link.href = paymentDetails.merchant_logo; |     link.href = paymentDetails.merchant_logo; | ||||||
|       link.type = "image/x-icon"; |     link.type = "image/x-icon"; | ||||||
|       document.head.appendChild(link); |     document.head.appendChild(link); | ||||||
|     } |  | ||||||
|   } |   } | ||||||
|   // Render UI |   // Render UI | ||||||
|  |  | ||||||
|  | |||||||
| @ -209,12 +209,12 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa | |||||||
|                 ), |                 ), | ||||||
|             )); |             )); | ||||||
|  |  | ||||||
|         let payment_link_data = if let Some(payment_link_create) = request.payment_link { |         let payment_link_data = match request.payment_link { | ||||||
|             if payment_link_create { |             Some(true) => { | ||||||
|                 let merchant_name = merchant_account |                 let merchant_name = merchant_account | ||||||
|                     .merchant_name |                     .merchant_name | ||||||
|                     .clone() |                     .clone() | ||||||
|                     .map(|merchant_name| merchant_name.into_inner().peek().to_owned()) |                     .map(|name| name.into_inner().peek().to_owned()) | ||||||
|                     .unwrap_or_default(); |                     .unwrap_or_default(); | ||||||
|  |  | ||||||
|                 let default_domain_name = state.base_url.clone(); |                 let default_domain_name = state.base_url.clone(); | ||||||
| @ -225,7 +225,9 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa | |||||||
|                         business_profile.payment_link_config.clone(), |                         business_profile.payment_link_config.clone(), | ||||||
|                         merchant_name, |                         merchant_name, | ||||||
|                         default_domain_name, |                         default_domain_name, | ||||||
|  |                         request.payment_link_config_id.clone(), | ||||||
|                     )?; |                     )?; | ||||||
|  |  | ||||||
|                 create_payment_link( |                 create_payment_link( | ||||||
|                     request, |                     request, | ||||||
|                     payment_link_config, |                     payment_link_config, | ||||||
| @ -239,11 +241,8 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa | |||||||
|                     session_expiry, |                     session_expiry, | ||||||
|                 ) |                 ) | ||||||
|                 .await? |                 .await? | ||||||
|             } else { |  | ||||||
|                 None |  | ||||||
|             } |             } | ||||||
|         } else { |             _ => None, | ||||||
|             None |  | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         let payment_intent_new = Self::make_payment_intent( |         let payment_intent_new = Self::make_payment_intent( | ||||||
|  | |||||||
| @ -9,3 +9,27 @@ macro_rules! get_formatted_date_time { | |||||||
|             .change_context($crate::core::errors::ConnectorError::InvalidDateFormat) |             .change_context($crate::core::errors::ConnectorError::InvalidDateFormat) | ||||||
|     }}; |     }}; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[macro_export] | ||||||
|  | macro_rules! get_payment_link_config_value_based_on_priority { | ||||||
|  |     ($config:expr, $business_config:expr, $field:ident, $default:expr) => { | ||||||
|  |         $config | ||||||
|  |             .as_ref() | ||||||
|  |             .and_then(|pc_config| pc_config.theme_config.$field.clone()) | ||||||
|  |             .or_else(|| { | ||||||
|  |                 $business_config | ||||||
|  |                     .as_ref() | ||||||
|  |                     .and_then(|business_config| business_config.$field.clone()) | ||||||
|  |             }) | ||||||
|  |             .unwrap_or($default) | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[macro_export] | ||||||
|  | macro_rules! get_payment_link_config_value { | ||||||
|  |     ($config:expr, $business_config:expr, $(($field:ident, $default:expr)),*) => { | ||||||
|  |         ( | ||||||
|  |             $(get_payment_link_config_value_based_on_priority!($config, $business_config, $field, $default)),* | ||||||
|  |         ) | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Sahkal Poddar
					Sahkal Poddar