mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-31 01:57:45 +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,6 +216,7 @@ 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;
|
||||||
@ -228,7 +229,6 @@ function boot() {
|
|||||||
link.type = "image/x-icon";
|
link.type = "image/x-icon";
|
||||||
document.head.appendChild(link);
|
document.head.appendChild(link);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Render UI
|
// Render UI
|
||||||
|
|
||||||
if (paymentDetails.display_sdk_only){
|
if (paymentDetails.display_sdk_only){
|
||||||
|
|||||||
@ -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