mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-28 12:15:40 +08:00
feat: applepay payment request object (#519)
This commit is contained in:
committed by
GitHub
parent
63f9b6124d
commit
8ee097ea21
@ -1096,51 +1096,100 @@ pub struct GpaySessionTokenData {
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum SessionToken {
|
||||
/// The session response structure for Google Pay
|
||||
Gpay {
|
||||
/// The merchant info
|
||||
merchant_info: GpayMerchantInfo,
|
||||
/// List of the allowed payment meythods
|
||||
allowed_payment_methods: Vec<GpayAllowedPaymentMethods>,
|
||||
/// The transaction info Google Pay requires
|
||||
transaction_info: GpayTransactionInfo,
|
||||
},
|
||||
Gpay(Box<GpayData>),
|
||||
/// The session response structure for Klarna
|
||||
Klarna {
|
||||
/// The session token for Klarna
|
||||
session_token: String,
|
||||
/// The identifier for the session
|
||||
session_id: String,
|
||||
},
|
||||
Klarna(Box<KlarnaData>),
|
||||
/// The session response structure for PayPal
|
||||
Paypal {
|
||||
/// The session token for PayPal
|
||||
session_token: String,
|
||||
},
|
||||
Paypal(Box<PaypalData>),
|
||||
/// The session response structure for Apple Pay
|
||||
Applepay {
|
||||
/// Timestamp at which session is requested
|
||||
epoch_timestamp: u64,
|
||||
/// Timestamp at which session expires
|
||||
expires_at: u64,
|
||||
/// The identifier for the merchant session
|
||||
merchant_session_identifier: String,
|
||||
/// Applepay generates unique ID (UUID) value
|
||||
nonce: String,
|
||||
/// The identifier for the merchant
|
||||
merchant_identifier: String,
|
||||
/// The domain name of the merchant which is registered in Apple Pay
|
||||
domain_name: String,
|
||||
/// The name to be displayed on Apple Pay button
|
||||
display_name: String,
|
||||
/// A string which represents the properties of a payment
|
||||
signature: String,
|
||||
/// The identifier for the operational analytics
|
||||
operational_analytics_identifier: String,
|
||||
/// The number of retries to get the session response
|
||||
retries: u8,
|
||||
/// The identifier for the connector transaction
|
||||
psp_id: String,
|
||||
},
|
||||
Applepay(Box<ApplepayData>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, ToSchema)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub struct GpayData {
|
||||
/// The merchant info
|
||||
pub merchant_info: GpayMerchantInfo,
|
||||
/// List of the allowed payment meythods
|
||||
pub allowed_payment_methods: Vec<GpayAllowedPaymentMethods>,
|
||||
/// The transaction info Google Pay requires
|
||||
pub transaction_info: GpayTransactionInfo,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, ToSchema)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub struct KlarnaData {
|
||||
/// The session token for Klarna
|
||||
pub session_token: String,
|
||||
/// The identifier for the session
|
||||
pub session_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, ToSchema)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub struct PaypalData {
|
||||
/// The session token for PayPal
|
||||
pub session_token: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, ToSchema)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub struct ApplepayData {
|
||||
/// Session object for Apple Pay
|
||||
pub session_object: ApplePaySessionObject,
|
||||
/// Payment request object for Apple Pay
|
||||
pub payment_request_object: ApplePayRequest,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, ToSchema, serde::Deserialize)]
|
||||
pub struct ApplePaySessionObject {
|
||||
/// Timestamp at which session is requested
|
||||
pub epoch_timestamp: u64,
|
||||
/// Timestamp at which session expires
|
||||
pub expires_at: u64,
|
||||
/// The identifier for the merchant session
|
||||
pub merchant_session_identifier: String,
|
||||
/// Applepay generates unique ID (UUID) value
|
||||
pub nonce: String,
|
||||
/// The identifier for the merchant
|
||||
pub merchant_identifier: String,
|
||||
/// The domain name of the merchant which is registered in Apple Pay
|
||||
pub domain_name: String,
|
||||
/// The name to be displayed on Apple Pay button
|
||||
pub display_name: String,
|
||||
/// A string which represents the properties of a payment
|
||||
pub signature: String,
|
||||
/// The identifier for the operational analytics
|
||||
pub operational_analytics_identifier: String,
|
||||
/// The number of retries to get the session response
|
||||
pub retries: u8,
|
||||
/// The identifier for the connector transaction
|
||||
pub psp_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, ToSchema, serde::Deserialize)]
|
||||
pub struct ApplePayRequest {
|
||||
/// The code for country
|
||||
pub country_code: String,
|
||||
/// The code for currency
|
||||
pub currency_code: String,
|
||||
/// Represents the total for the payment.
|
||||
pub total: AmountInfo,
|
||||
/// The list of merchant capabilities(ex: whether capable of 3ds or no-3ds)
|
||||
pub merchant_capabilities: Vec<String>,
|
||||
/// The list of supported networks
|
||||
pub supported_networks: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, ToSchema, serde::Deserialize)]
|
||||
pub struct AmountInfo {
|
||||
/// the label must be non-empty to pass validation.
|
||||
pub label: String,
|
||||
/// The type of label
|
||||
#[serde(rename = "type")]
|
||||
pub label_type: String,
|
||||
/// The total amount for the payment
|
||||
pub amount: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, serde::Serialize, Clone, ToSchema)]
|
||||
|
||||
@ -197,11 +197,11 @@ impl
|
||||
.get_required_value("connector_meta_data")
|
||||
.change_context(errors::ConnectorError::NoConnectorMetaData)?;
|
||||
|
||||
let session_object: transformers::SessionObject = metadata
|
||||
.parse_value("SessionObject")
|
||||
let metadata: transformers::ApplePayMetaData = metadata
|
||||
.parse_value("ApplePayMetaData")
|
||||
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
||||
|
||||
Ok(Some(session_object.certificate))
|
||||
Ok(Some(metadata.session_object.certificate))
|
||||
}
|
||||
|
||||
fn get_certificate_key(
|
||||
@ -214,11 +214,11 @@ impl
|
||||
.get_required_value("connector_meta_data")
|
||||
.change_context(errors::ConnectorError::NoConnectorMetaData)?;
|
||||
|
||||
let session_object: transformers::SessionObject = metadata
|
||||
.parse_value("SessionObject")
|
||||
let metadata: transformers::ApplePayMetaData = metadata
|
||||
.parse_value("ApplePayMetaData")
|
||||
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
||||
|
||||
Ok(Some(session_object.certificate_keys))
|
||||
Ok(Some(metadata.session_object.certificate_keys))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use api_models::payments;
|
||||
use common_utils::ext_traits::ValueExt;
|
||||
use error_stack::ResultExt;
|
||||
use masking::{Deserialize, Serialize};
|
||||
@ -16,17 +17,17 @@ pub struct ApplepaySessionRequest {
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ApplepaySessionResponse {
|
||||
epoch_timestamp: u64,
|
||||
expires_at: u64,
|
||||
merchant_session_identifier: String,
|
||||
nonce: String,
|
||||
merchant_identifier: String,
|
||||
domain_name: String,
|
||||
display_name: String,
|
||||
signature: String,
|
||||
operational_analytics_identifier: String,
|
||||
retries: u8,
|
||||
psp_id: String,
|
||||
pub epoch_timestamp: u64,
|
||||
pub expires_at: u64,
|
||||
pub merchant_session_identifier: String,
|
||||
pub nonce: String,
|
||||
pub merchant_identifier: String,
|
||||
pub domain_name: String,
|
||||
pub display_name: String,
|
||||
pub signature: String,
|
||||
pub operational_analytics_identifier: String,
|
||||
pub retries: u8,
|
||||
pub psp_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
@ -36,6 +37,19 @@ pub struct ErrorResponse {
|
||||
pub status_message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
pub struct ApplePayMetaData {
|
||||
pub payment_object: PaymentObjectMetaData,
|
||||
pub session_object: SessionObject,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
pub struct PaymentObjectMetaData {
|
||||
pub supported_networks: Vec<String>,
|
||||
pub merchant_capabilities: Vec<String>,
|
||||
pub label: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
pub struct SessionObject {
|
||||
pub certificate: String,
|
||||
@ -46,6 +60,25 @@ pub struct SessionObject {
|
||||
pub initiative_context: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct PaymentRequest {
|
||||
pub apple_pay_merchant_id: String,
|
||||
pub country_code: String,
|
||||
pub currency_code: String,
|
||||
pub total: AmountInfo,
|
||||
pub merchant_capabilities: Vec<String>,
|
||||
pub supported_networks: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
pub struct AmountInfo {
|
||||
pub label: String,
|
||||
#[serde(rename = "type")]
|
||||
pub label_type: String,
|
||||
pub amount: String,
|
||||
}
|
||||
|
||||
impl TryFrom<&types::PaymentsSessionRouterData> for ApplepaySessionRequest {
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
fn try_from(item: &types::PaymentsSessionRouterData) -> Result<Self, Self::Error> {
|
||||
@ -55,48 +88,136 @@ impl TryFrom<&types::PaymentsSessionRouterData> for ApplepaySessionRequest {
|
||||
.get_required_value("connector_meta_data")
|
||||
.change_context(errors::ConnectorError::NoConnectorMetaData)?;
|
||||
|
||||
let session_object: SessionObject = metadata
|
||||
.parse_value("SessionObject")
|
||||
let metadata: ApplePayMetaData = metadata
|
||||
.parse_value("ApplePayMetaData")
|
||||
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
||||
|
||||
Ok(Self {
|
||||
merchant_identifier: session_object.merchant_identifier,
|
||||
display_name: session_object.display_name,
|
||||
initiative: session_object.initiative,
|
||||
initiative_context: session_object.initiative_context,
|
||||
merchant_identifier: metadata.session_object.merchant_identifier,
|
||||
display_name: metadata.session_object.display_name,
|
||||
initiative: metadata.session_object.initiative,
|
||||
initiative_context: metadata.session_object.initiative_context,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, T>
|
||||
TryFrom<types::ResponseRouterData<F, ApplepaySessionResponse, T, types::PaymentsResponseData>>
|
||||
for types::RouterData<F, T, types::PaymentsResponseData>
|
||||
impl<F>
|
||||
TryFrom<
|
||||
types::ResponseRouterData<
|
||||
F,
|
||||
ApplepaySessionResponse,
|
||||
types::PaymentsSessionData,
|
||||
types::PaymentsResponseData,
|
||||
>,
|
||||
> for types::RouterData<F, types::PaymentsSessionData, types::PaymentsResponseData>
|
||||
{
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
fn try_from(
|
||||
item: types::ResponseRouterData<F, ApplepaySessionResponse, T, types::PaymentsResponseData>,
|
||||
item: types::ResponseRouterData<
|
||||
F,
|
||||
ApplepaySessionResponse,
|
||||
types::PaymentsSessionData,
|
||||
types::PaymentsResponseData,
|
||||
>,
|
||||
) -> Result<Self, Self::Error> {
|
||||
let metadata = item
|
||||
.data
|
||||
.connector_meta_data
|
||||
.to_owned()
|
||||
.get_required_value("connector_meta_data")
|
||||
.change_context(errors::ConnectorError::NoConnectorMetaData)?;
|
||||
|
||||
let metadata: ApplePayMetaData = metadata
|
||||
.parse_value("ApplePayMetaData")
|
||||
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
||||
|
||||
let amount_info = AmountInfo {
|
||||
label: metadata.payment_object.label,
|
||||
label_type: "final".to_string(),
|
||||
amount: (item.data.request.amount / 100).to_string(),
|
||||
};
|
||||
|
||||
let payment_request = PaymentRequest {
|
||||
country_code: item
|
||||
.data
|
||||
.request
|
||||
.country
|
||||
.to_owned()
|
||||
.get_required_value("country_code")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "country_code",
|
||||
})?,
|
||||
currency_code: item.data.request.currency.to_string(),
|
||||
total: amount_info,
|
||||
merchant_capabilities: metadata.payment_object.merchant_capabilities,
|
||||
supported_networks: metadata.payment_object.supported_networks,
|
||||
apple_pay_merchant_id: metadata.session_object.merchant_identifier,
|
||||
};
|
||||
|
||||
let applepay_session_object = ApplepaySessionResponse {
|
||||
epoch_timestamp: item.response.epoch_timestamp,
|
||||
expires_at: item.response.expires_at,
|
||||
merchant_session_identifier: item.response.merchant_session_identifier,
|
||||
nonce: item.response.nonce,
|
||||
merchant_identifier: item.response.merchant_identifier,
|
||||
domain_name: item.response.domain_name,
|
||||
display_name: item.response.display_name,
|
||||
signature: item.response.signature,
|
||||
operational_analytics_identifier: item.response.operational_analytics_identifier,
|
||||
retries: item.response.retries,
|
||||
psp_id: item.response.psp_id,
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
response: Ok(types::PaymentsResponseData::SessionResponse {
|
||||
session_token: {
|
||||
api_models::payments::SessionToken::Applepay {
|
||||
epoch_timestamp: item.response.epoch_timestamp,
|
||||
expires_at: item.response.expires_at,
|
||||
merchant_session_identifier: item.response.merchant_session_identifier,
|
||||
nonce: item.response.nonce,
|
||||
merchant_identifier: item.response.merchant_identifier,
|
||||
domain_name: item.response.domain_name,
|
||||
display_name: item.response.display_name,
|
||||
signature: item.response.signature,
|
||||
operational_analytics_identifier: item
|
||||
.response
|
||||
.operational_analytics_identifier,
|
||||
retries: item.response.retries,
|
||||
psp_id: item.response.psp_id,
|
||||
}
|
||||
api_models::payments::SessionToken::Applepay(Box::new(payments::ApplepayData {
|
||||
session_object: applepay_session_object.into(),
|
||||
payment_request_object: payment_request.into(),
|
||||
}))
|
||||
},
|
||||
}),
|
||||
..item.data
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PaymentRequest> for payments::ApplePayRequest {
|
||||
fn from(value: PaymentRequest) -> Self {
|
||||
Self {
|
||||
country_code: value.country_code,
|
||||
currency_code: value.currency_code,
|
||||
total: value.total.into(),
|
||||
merchant_capabilities: value.merchant_capabilities,
|
||||
supported_networks: value.supported_networks,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AmountInfo> for payments::AmountInfo {
|
||||
fn from(value: AmountInfo) -> Self {
|
||||
Self {
|
||||
label: value.label,
|
||||
label_type: value.label_type,
|
||||
amount: value.amount,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ApplepaySessionResponse> for payments::ApplePaySessionObject {
|
||||
fn from(value: ApplepaySessionResponse) -> Self {
|
||||
Self {
|
||||
epoch_timestamp: value.epoch_timestamp,
|
||||
expires_at: value.expires_at,
|
||||
merchant_session_identifier: value.merchant_session_identifier,
|
||||
nonce: value.nonce,
|
||||
merchant_identifier: value.merchant_identifier,
|
||||
domain_name: value.domain_name,
|
||||
display_name: value.display_name,
|
||||
signature: value.signature,
|
||||
operational_analytics_identifier: value.operational_analytics_identifier,
|
||||
retries: value.retries,
|
||||
psp_id: value.psp_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use api_models::payments;
|
||||
use base64::Engine;
|
||||
use error_stack::ResultExt;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -243,9 +244,9 @@ impl<F, T>
|
||||
) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
response: Ok(types::PaymentsResponseData::SessionResponse {
|
||||
session_token: types::api::SessionToken::Paypal {
|
||||
session_token: types::api::SessionToken::Paypal(Box::new(payments::PaypalData {
|
||||
session_token: item.response.client_token.value,
|
||||
},
|
||||
})),
|
||||
}),
|
||||
..item.data
|
||||
})
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use api_models::payments;
|
||||
use error_stack::report;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@ -71,10 +72,10 @@ impl TryFrom<types::PaymentsSessionResponseRouterData<KlarnaSessionResponse>>
|
||||
let response = &item.response;
|
||||
Ok(Self {
|
||||
response: Ok(types::PaymentsResponseData::SessionResponse {
|
||||
session_token: types::api::SessionToken::Klarna {
|
||||
session_token: types::api::SessionToken::Klarna(Box::new(payments::KlarnaData {
|
||||
session_token: response.client_token.clone(),
|
||||
session_id: response.session_id.clone(),
|
||||
},
|
||||
})),
|
||||
}),
|
||||
..item.data
|
||||
})
|
||||
|
||||
@ -91,11 +91,11 @@ fn create_gpay_session_token(
|
||||
|
||||
let response_router_data = types::PaymentsSessionRouterData {
|
||||
response: Ok(types::PaymentsResponseData::SessionResponse {
|
||||
session_token: payment_types::SessionToken::Gpay {
|
||||
transaction_info,
|
||||
session_token: payment_types::SessionToken::Gpay(Box::new(payment_types::GpayData {
|
||||
merchant_info: gpay_data.data.merchant_info,
|
||||
allowed_payment_methods: gpay_data.data.allowed_payment_methods,
|
||||
},
|
||||
transaction_info,
|
||||
})),
|
||||
}),
|
||||
..router_data.clone()
|
||||
};
|
||||
|
||||
@ -173,12 +173,19 @@ Never share your secret api keys. Keep them guarded and secure.
|
||||
api_models::payments::PaymentsSessionRequest,
|
||||
api_models::payments::PaymentsSessionResponse,
|
||||
api_models::payments::SessionToken,
|
||||
api_models::payments::ApplePaySessionObject,
|
||||
api_models::payments::ApplePayRequest,
|
||||
api_models::payments::AmountInfo,
|
||||
api_models::payments::GpayMerchantInfo,
|
||||
api_models::payments::GpayAllowedPaymentMethods,
|
||||
api_models::payments::GpayAllowedMethodsParameters,
|
||||
api_models::payments::GpayTokenizationSpecification,
|
||||
api_models::payments::GpayTokenParameters,
|
||||
api_models::payments::GpayTransactionInfo,
|
||||
api_models::payments::GpayData,
|
||||
api_models::payments::KlarnaData,
|
||||
api_models::payments::PaypalData,
|
||||
api_models::payments::ApplepayData,
|
||||
api_models::payments::PaymentsCancelRequest,
|
||||
api_models::payments::PaymentListConstraints,
|
||||
api_models::payments::PaymentListResponse,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user