mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +08:00
feat: Apple pay session flow integrate (#138)
This commit is contained in:
committed by
GitHub
parent
1f0d1deb2b
commit
8b8ff8188f
@ -37,8 +37,8 @@ locker_decryption_key1 = ""
|
|||||||
locker_decryption_key2 = ""
|
locker_decryption_key2 = ""
|
||||||
|
|
||||||
[connectors.supported]
|
[connectors.supported]
|
||||||
wallets = ["klarna","braintree"]
|
wallets = ["klarna","braintree","applepay"]
|
||||||
cards = ["stripe","adyen","authorizedotnet","checkout","braintree"]
|
cards = ["stripe","adyen","authorizedotnet","checkout","braintree","aci"]
|
||||||
|
|
||||||
[eph_key]
|
[eph_key]
|
||||||
validity = 1
|
validity = 1
|
||||||
@ -64,6 +64,9 @@ base_url = "https://api.sandbox.braintreegateway.com/"
|
|||||||
[connectors.klarna]
|
[connectors.klarna]
|
||||||
base_url = "https://api-na.playground.klarna.com/"
|
base_url = "https://api-na.playground.klarna.com/"
|
||||||
|
|
||||||
|
[connectors.applepay]
|
||||||
|
base_url = "https://apple-pay-gateway.apple.com/"
|
||||||
|
|
||||||
[scheduler]
|
[scheduler]
|
||||||
stream = "SCHEDULER_STREAM"
|
stream = "SCHEDULER_STREAM"
|
||||||
consumer_group = "SCHEDULER_GROUP"
|
consumer_group = "SCHEDULER_GROUP"
|
||||||
|
|||||||
@ -79,8 +79,8 @@ mock_locker = true # Emulate a locker locally using Postgres
|
|||||||
basilisk_host = "" #Basilisk host
|
basilisk_host = "" #Basilisk host
|
||||||
|
|
||||||
[jwekey] # 4 priv/pub key pair
|
[jwekey] # 4 priv/pub key pair
|
||||||
locker_key_identifier1 = "" # key identifier for key rotation , should be same as basilisk
|
locker_key_identifier1 = "" # key identifier for key rotation , should be same as basilisk
|
||||||
locker_key_identifier2 = "" # key identifier for key rotation , should be same as basilisk
|
locker_key_identifier2 = "" # key identifier for key rotation , should be same as basilisk
|
||||||
locker_encryption_key1 = "" # public key 1 in pem format, corresponding private key in basilisk
|
locker_encryption_key1 = "" # public key 1 in pem format, corresponding private key in basilisk
|
||||||
locker_encryption_key2 = "" # public key 2 in pem format, corresponding private key in basilisk
|
locker_encryption_key2 = "" # public key 2 in pem format, corresponding private key in basilisk
|
||||||
locker_decryption_key1 = "" # private key 1 in pem format, corresponding public key in basilisk
|
locker_decryption_key1 = "" # private key 1 in pem format, corresponding public key in basilisk
|
||||||
@ -116,9 +116,12 @@ base_url = "https://api.sandbox.braintreegateway.com/"
|
|||||||
[connectors.klarna]
|
[connectors.klarna]
|
||||||
base_url = "https://api-na.playground.klarna.com/"
|
base_url = "https://api-na.playground.klarna.com/"
|
||||||
|
|
||||||
|
[connectors.applepay]
|
||||||
|
base_url = "https://apple-pay-gateway.apple.com/"
|
||||||
|
|
||||||
# This data is used to call respective connectors for wallets and cards
|
# This data is used to call respective connectors for wallets and cards
|
||||||
[connectors.supported]
|
[connectors.supported]
|
||||||
wallets = ["klarna","braintree"]
|
wallets = ["klarna","braintree","applepay"]
|
||||||
cards = ["stripe","adyen","authorizedotnet","checkout","braintree"]
|
cards = ["stripe","adyen","authorizedotnet","checkout","braintree"]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -71,7 +71,9 @@ base_url = "https://api.sandbox.braintreegateway.com/"
|
|||||||
[connectors.klarna]
|
[connectors.klarna]
|
||||||
base_url = "https://api-na.playground.klarna.com/"
|
base_url = "https://api-na.playground.klarna.com/"
|
||||||
|
|
||||||
[connectors.supported]
|
[connectors.applepay]
|
||||||
wallets = ["klarna","braintree"]
|
base_url = "https://apple-pay-gateway.apple.com/"
|
||||||
cards = ["stripe","adyen","authorizedotnet","checkout","braintree"]
|
|
||||||
|
|
||||||
|
[connectors.supported]
|
||||||
|
wallets = ["klarna","braintree","applepay"]
|
||||||
|
cards = ["stripe","adyen","authorizedotnet","checkout","braintree"]
|
||||||
|
|||||||
@ -703,6 +703,19 @@ pub enum SessionToken {
|
|||||||
Paypal {
|
Paypal {
|
||||||
session_token: String,
|
session_token: String,
|
||||||
},
|
},
|
||||||
|
Applepay {
|
||||||
|
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,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, serde::Serialize, Clone)]
|
#[derive(Default, Debug, serde::Serialize, Clone)]
|
||||||
|
|||||||
@ -49,7 +49,7 @@ mime = "0.3.16"
|
|||||||
nanoid = "0.4.0"
|
nanoid = "0.4.0"
|
||||||
once_cell = "1.16.0"
|
once_cell = "1.16.0"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
reqwest = { version = "0.11.12", features = ["json"] }
|
reqwest = { version = "0.11.12", features = ["json", "native-tls"] }
|
||||||
ring = "0.16.20"
|
ring = "0.16.20"
|
||||||
serde = { version = "1.0.149", features = ["derive"] }
|
serde = { version = "1.0.149", features = ["derive"] }
|
||||||
serde_json = "1.0.89"
|
serde_json = "1.0.89"
|
||||||
|
|||||||
@ -114,6 +114,7 @@ pub struct Connectors {
|
|||||||
pub braintree: ConnectorParams,
|
pub braintree: ConnectorParams,
|
||||||
pub klarna: ConnectorParams,
|
pub klarna: ConnectorParams,
|
||||||
pub supported: SupportedConnectors,
|
pub supported: SupportedConnectors,
|
||||||
|
pub applepay: ConnectorParams,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone)]
|
#[derive(Debug, Deserialize, Clone)]
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
pub mod aci;
|
pub mod aci;
|
||||||
pub mod adyen;
|
pub mod adyen;
|
||||||
|
pub mod applepay;
|
||||||
pub mod authorizedotnet;
|
pub mod authorizedotnet;
|
||||||
pub mod braintree;
|
pub mod braintree;
|
||||||
pub mod checkout;
|
pub mod checkout;
|
||||||
@ -7,6 +8,6 @@ pub mod klarna;
|
|||||||
pub mod stripe;
|
pub mod stripe;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
aci::Aci, adyen::Adyen, authorizedotnet::Authorizedotnet, braintree::Braintree,
|
aci::Aci, adyen::Adyen, applepay::Applepay, authorizedotnet::Authorizedotnet,
|
||||||
checkout::Checkout, klarna::Klarna, stripe::Stripe,
|
braintree::Braintree, checkout::Checkout, klarna::Klarna, stripe::Stripe,
|
||||||
};
|
};
|
||||||
|
|||||||
246
crates/router/src/connector/applepay.rs
Normal file
246
crates/router/src/connector/applepay.rs
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
mod transformers;
|
||||||
|
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use bytes::Bytes;
|
||||||
|
use common_utils::ext_traits::ValueExt;
|
||||||
|
use error_stack::{IntoReport, ResultExt};
|
||||||
|
|
||||||
|
use self::transformers as applepay;
|
||||||
|
use crate::{
|
||||||
|
configs::settings,
|
||||||
|
core::errors::{self, CustomResult},
|
||||||
|
headers, services,
|
||||||
|
types::{
|
||||||
|
self,
|
||||||
|
api::{self, ConnectorCommon},
|
||||||
|
},
|
||||||
|
utils::{self, BytesExt, OptionExt},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Applepay;
|
||||||
|
|
||||||
|
impl api::ConnectorCommon for Applepay {
|
||||||
|
fn id(&self) -> &'static str {
|
||||||
|
"applepay"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn base_url(&self, connectors: settings::Connectors) -> String {
|
||||||
|
connectors.applepay.base_url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl api::Payment for Applepay {}
|
||||||
|
impl api::PaymentAuthorize for Applepay {}
|
||||||
|
impl api::PaymentSync for Applepay {}
|
||||||
|
impl api::PaymentVoid for Applepay {}
|
||||||
|
impl api::PaymentCapture for Applepay {}
|
||||||
|
impl api::PreVerify for Applepay {}
|
||||||
|
impl api::PaymentSession for Applepay {}
|
||||||
|
|
||||||
|
impl
|
||||||
|
services::ConnectorIntegration<
|
||||||
|
api::Verify,
|
||||||
|
types::VerifyRequestData,
|
||||||
|
types::PaymentsResponseData,
|
||||||
|
> for Applepay
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl
|
||||||
|
services::ConnectorIntegration<
|
||||||
|
api::Capture,
|
||||||
|
types::PaymentsCaptureData,
|
||||||
|
types::PaymentsResponseData,
|
||||||
|
> for Applepay
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl
|
||||||
|
services::ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsResponseData>
|
||||||
|
for Applepay
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl
|
||||||
|
services::ConnectorIntegration<
|
||||||
|
api::Authorize,
|
||||||
|
types::PaymentsAuthorizeData,
|
||||||
|
types::PaymentsResponseData,
|
||||||
|
> for Applepay
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl
|
||||||
|
services::ConnectorIntegration<
|
||||||
|
api::Void,
|
||||||
|
types::PaymentsCancelData,
|
||||||
|
types::PaymentsResponseData,
|
||||||
|
> for Applepay
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl
|
||||||
|
services::ConnectorIntegration<
|
||||||
|
api::Session,
|
||||||
|
types::PaymentsSessionData,
|
||||||
|
types::PaymentsResponseData,
|
||||||
|
> for Applepay
|
||||||
|
{
|
||||||
|
fn get_headers(
|
||||||
|
&self,
|
||||||
|
_req: &types::PaymentsSessionRouterData,
|
||||||
|
) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
|
||||||
|
let header = vec![(
|
||||||
|
headers::CONTENT_TYPE.to_string(),
|
||||||
|
types::PaymentsSessionType::get_content_type(self).to_string(),
|
||||||
|
)];
|
||||||
|
Ok(header)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_url(
|
||||||
|
&self,
|
||||||
|
_req: &types::PaymentsSessionRouterData,
|
||||||
|
connectors: settings::Connectors,
|
||||||
|
) -> CustomResult<String, errors::ConnectorError> {
|
||||||
|
Ok(format!(
|
||||||
|
"{}{}",
|
||||||
|
self.base_url(connectors),
|
||||||
|
"paymentservices/paymentSession"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_request_body(
|
||||||
|
&self,
|
||||||
|
req: &types::PaymentsSessionRouterData,
|
||||||
|
) -> CustomResult<Option<String>, errors::ConnectorError> {
|
||||||
|
let req = utils::Encode::<applepay::ApplepaySessionRequest>::convert_and_encode(req)
|
||||||
|
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
||||||
|
Ok(Some(req))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_request(
|
||||||
|
&self,
|
||||||
|
req: &types::PaymentsSessionRouterData,
|
||||||
|
connectors: settings::Connectors,
|
||||||
|
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
|
||||||
|
let request = services::RequestBuilder::new()
|
||||||
|
.method(services::Method::Post)
|
||||||
|
// TODO: [ORCA-346] Requestbuilder needs &str migrate get_url to send &str instead of owned string
|
||||||
|
.url(&types::PaymentsSessionType::get_url(self, req, connectors)?)
|
||||||
|
.headers(types::PaymentsSessionType::get_headers(self, req)?)
|
||||||
|
.body(types::PaymentsSessionType::get_request_body(self, req)?)
|
||||||
|
.add_certificate(types::PaymentsSessionType::get_certificate(self, req)?)
|
||||||
|
.add_certificate_key(types::PaymentsSessionType::get_certificate_key(self, req)?)
|
||||||
|
.build();
|
||||||
|
Ok(Some(request))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_response(
|
||||||
|
&self,
|
||||||
|
data: &types::PaymentsSessionRouterData,
|
||||||
|
res: types::Response,
|
||||||
|
) -> CustomResult<types::PaymentsSessionRouterData, errors::ConnectorError> {
|
||||||
|
let response: applepay::ApplepaySessionResponse = res
|
||||||
|
.response
|
||||||
|
.parse_struct("ApplepaySessionResponse")
|
||||||
|
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||||
|
|
||||||
|
types::RouterData::try_from(types::ResponseRouterData {
|
||||||
|
response,
|
||||||
|
data: data.clone(),
|
||||||
|
http_code: res.status_code,
|
||||||
|
})
|
||||||
|
.change_context(errors::ConnectorError::ResponseHandlingFailed)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_error_response(
|
||||||
|
&self,
|
||||||
|
res: Bytes,
|
||||||
|
) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
|
||||||
|
let response: applepay::ErrorResponse = res
|
||||||
|
.parse_struct("ErrorResponse")
|
||||||
|
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||||
|
Ok(types::ErrorResponse {
|
||||||
|
code: response.status_code,
|
||||||
|
message: response.status_message,
|
||||||
|
reason: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_certificate(
|
||||||
|
&self,
|
||||||
|
req: &types::PaymentsSessionRouterData,
|
||||||
|
) -> CustomResult<Option<String>, errors::ConnectorError> {
|
||||||
|
let metadata = req
|
||||||
|
.connector_meta_data
|
||||||
|
.to_owned()
|
||||||
|
.get_required_value("connector_meta_data")
|
||||||
|
.change_context(errors::ConnectorError::NoConnectorMetaData)?;
|
||||||
|
|
||||||
|
let session_object: transformers::SessionObject = metadata
|
||||||
|
.parse_value("SessionObject")
|
||||||
|
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
||||||
|
|
||||||
|
Ok(Some(session_object.certificate))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_certificate_key(
|
||||||
|
&self,
|
||||||
|
req: &types::PaymentsSessionRouterData,
|
||||||
|
) -> CustomResult<Option<String>, errors::ConnectorError> {
|
||||||
|
let metadata = req
|
||||||
|
.connector_meta_data
|
||||||
|
.to_owned()
|
||||||
|
.get_required_value("connector_meta_data")
|
||||||
|
.change_context(errors::ConnectorError::NoConnectorMetaData)?;
|
||||||
|
|
||||||
|
let session_object: transformers::SessionObject = metadata
|
||||||
|
.parse_value("SessionObject")
|
||||||
|
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
||||||
|
|
||||||
|
Ok(Some(session_object.certificate_keys))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl api::Refund for Applepay {}
|
||||||
|
impl api::RefundExecute for Applepay {}
|
||||||
|
impl api::RefundSync for Applepay {}
|
||||||
|
|
||||||
|
impl services::ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsResponseData>
|
||||||
|
for Applepay
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl services::ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponseData>
|
||||||
|
for Applepay
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl services::ConnectorRedirectResponse for Applepay {}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl api::IncomingWebhook for Applepay {
|
||||||
|
fn get_webhook_object_reference_id(
|
||||||
|
&self,
|
||||||
|
_body: &[u8],
|
||||||
|
) -> CustomResult<String, errors::ConnectorError> {
|
||||||
|
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_webhook_event_type(
|
||||||
|
&self,
|
||||||
|
_body: &[u8],
|
||||||
|
) -> CustomResult<api::IncomingWebhookEvent, errors::ConnectorError> {
|
||||||
|
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_webhook_resource_object(
|
||||||
|
&self,
|
||||||
|
_body: &[u8],
|
||||||
|
) -> CustomResult<serde_json::Value, errors::ConnectorError> {
|
||||||
|
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
|
||||||
|
}
|
||||||
|
}
|
||||||
103
crates/router/src/connector/applepay/transformers.rs
Normal file
103
crates/router/src/connector/applepay/transformers.rs
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
use common_utils::ext_traits::ValueExt;
|
||||||
|
use error_stack::ResultExt;
|
||||||
|
use masking::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::{core::errors, types, utils::OptionExt};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct ApplepaySessionRequest {
|
||||||
|
merchant_identifier: String,
|
||||||
|
display_name: String,
|
||||||
|
initiative: String,
|
||||||
|
initiative_context: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct ErrorResponse {
|
||||||
|
pub status_code: String,
|
||||||
|
pub status_message: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
|
pub struct SessionObject {
|
||||||
|
pub certificate: String,
|
||||||
|
pub certificate_keys: String,
|
||||||
|
pub merchant_identifier: String,
|
||||||
|
pub display_name: String,
|
||||||
|
pub initiative: String,
|
||||||
|
pub initiative_context: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&types::PaymentsSessionRouterData> for ApplepaySessionRequest {
|
||||||
|
type Error = error_stack::Report<errors::ConnectorError>;
|
||||||
|
fn try_from(item: &types::PaymentsSessionRouterData) -> Result<Self, Self::Error> {
|
||||||
|
let metadata = item
|
||||||
|
.connector_meta_data
|
||||||
|
.to_owned()
|
||||||
|
.get_required_value("connector_meta_data")
|
||||||
|
.change_context(errors::ConnectorError::NoConnectorMetaData)?;
|
||||||
|
|
||||||
|
let session_object: SessionObject = metadata
|
||||||
|
.parse_value("SessionObject")
|
||||||
|
.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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F, T>
|
||||||
|
TryFrom<types::ResponseRouterData<F, ApplepaySessionResponse, T, types::PaymentsResponseData>>
|
||||||
|
for types::RouterData<F, T, types::PaymentsResponseData>
|
||||||
|
{
|
||||||
|
type Error = error_stack::Report<errors::ParsingError>;
|
||||||
|
fn try_from(
|
||||||
|
item: types::ResponseRouterData<F, ApplepaySessionResponse, T, types::PaymentsResponseData>,
|
||||||
|
) -> Result<Self, Self::Error> {
|
||||||
|
Ok(types::RouterData {
|
||||||
|
//TODO : change in session response to fit apple pay session object
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
..item.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -321,6 +321,7 @@ pub async fn create_payment_connector(
|
|||||||
payment_methods_enabled,
|
payment_methods_enabled,
|
||||||
test_mode: req.test_mode,
|
test_mode: req.test_mode,
|
||||||
disabled: req.disabled,
|
disabled: req.disabled,
|
||||||
|
metadata: req.metadata,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mca = store
|
let mca = store
|
||||||
|
|||||||
@ -234,6 +234,8 @@ pub enum ApiClientError {
|
|||||||
InvalidProxyConfiguration,
|
InvalidProxyConfiguration,
|
||||||
#[error("Client construction failed")]
|
#[error("Client construction failed")]
|
||||||
ClientConstructionFailed,
|
ClientConstructionFailed,
|
||||||
|
#[error("Certificate decode failed")]
|
||||||
|
CertificateDecodeFailed,
|
||||||
|
|
||||||
#[error("URL encoding of request payload failed")]
|
#[error("URL encoding of request payload failed")]
|
||||||
UrlEncodingFailed,
|
UrlEncodingFailed,
|
||||||
@ -295,6 +297,12 @@ pub enum ConnectorError {
|
|||||||
MissingRequiredField { field_name: String },
|
MissingRequiredField { field_name: String },
|
||||||
#[error("Failed to obtain authentication type")]
|
#[error("Failed to obtain authentication type")]
|
||||||
FailedToObtainAuthType,
|
FailedToObtainAuthType,
|
||||||
|
#[error("Failed to obtain certificate")]
|
||||||
|
FailedToObtainCertificate,
|
||||||
|
#[error("Connector meta data not found")]
|
||||||
|
NoConnectorMetaData,
|
||||||
|
#[error("Failed to obtain certificate key")]
|
||||||
|
FailedToObtainCertificateKey,
|
||||||
#[error("This step has not been implemented for: {0}")]
|
#[error("This step has not been implemented for: {0}")]
|
||||||
NotImplemented(String),
|
NotImplemented(String),
|
||||||
#[error("Missing connector transaction ID")]
|
#[error("Missing connector transaction ID")]
|
||||||
|
|||||||
@ -183,7 +183,6 @@ where
|
|||||||
Op: Operation<F, Req> + Send + Sync + Clone,
|
Op: Operation<F, Req> + Send + Sync + Clone,
|
||||||
Req: Debug,
|
Req: Debug,
|
||||||
Res: transformers::ToResponse<Req, PaymentData<F>, Op> + From<Req>,
|
Res: transformers::ToResponse<Req, PaymentData<F>, Op> + From<Req>,
|
||||||
|
|
||||||
// To create connector flow specific interface data
|
// To create connector flow specific interface data
|
||||||
PaymentData<F>: ConstructFlowSpecificData<F, FData, types::PaymentsResponseData>,
|
PaymentData<F>: ConstructFlowSpecificData<F, FData, types::PaymentsResponseData>,
|
||||||
types::RouterData<F, FData, types::PaymentsResponseData>: Feature<F, FData>,
|
types::RouterData<F, FData, types::PaymentsResponseData>: Feature<F, FData>,
|
||||||
|
|||||||
@ -95,7 +95,7 @@ where
|
|||||||
.payment_attempt
|
.payment_attempt
|
||||||
.authentication_type
|
.authentication_type
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
|
connector_meta_data: merchant_connector_account.metadata,
|
||||||
request: T::try_from(payment_data.clone())?,
|
request: T::try_from(payment_data.clone())?,
|
||||||
response: response.map_or_else(|| Err(types::ErrorResponse::default()), Ok),
|
response: response.map_or_else(|| Err(types::ErrorResponse::default()), Ok),
|
||||||
};
|
};
|
||||||
|
|||||||
@ -71,6 +71,7 @@ pub async fn construct_refund_router_data<'a, F>(
|
|||||||
// Does refund need shipping/billing address ?
|
// Does refund need shipping/billing address ?
|
||||||
address: PaymentAddress::default(),
|
address: PaymentAddress::default(),
|
||||||
auth_type: payment_attempt.authentication_type.unwrap_or_default(),
|
auth_type: payment_attempt.authentication_type.unwrap_or_default(),
|
||||||
|
connector_meta_data: None,
|
||||||
|
|
||||||
request: types::RefundsData {
|
request: types::RefundsData {
|
||||||
refund_id: refund.refund_id.clone(),
|
refund_id: refund.refund_id.clone(),
|
||||||
|
|||||||
@ -168,6 +168,7 @@ impl MerchantConnectorAccountInterface for MockDb {
|
|||||||
disabled: t.disabled,
|
disabled: t.disabled,
|
||||||
merchant_connector_id: t.merchant_connector_id.unwrap_or_default(),
|
merchant_connector_id: t.merchant_connector_id.unwrap_or_default(),
|
||||||
payment_methods_enabled: t.payment_methods_enabled,
|
payment_methods_enabled: t.payment_methods_enabled,
|
||||||
|
metadata: t.metadata,
|
||||||
connector_type: t
|
connector_type: t
|
||||||
.connector_type
|
.connector_type
|
||||||
.unwrap_or(crate::types::storage::enums::ConnectorType::FinOperations),
|
.unwrap_or(crate::types::storage::enums::ConnectorType::FinOperations),
|
||||||
|
|||||||
@ -104,6 +104,20 @@ pub trait ConnectorIntegration<T, Req, Resp>: ConnectorIntegrationExt<T, Req, Re
|
|||||||
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
|
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
|
||||||
Ok(ErrorResponse::get_not_implemented())
|
Ok(ErrorResponse::get_not_implemented())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_certificate(
|
||||||
|
&self,
|
||||||
|
_req: &types::RouterData<T, Req, Resp>,
|
||||||
|
) -> CustomResult<Option<String>, errors::ConnectorError> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_certificate_key(
|
||||||
|
&self,
|
||||||
|
_req: &types::RouterData<T, Req, Resp>,
|
||||||
|
) -> CustomResult<Option<String>, errors::ConnectorError> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
@ -196,9 +210,10 @@ async fn send_request(
|
|||||||
&state.conf.proxy,
|
&state.conf.proxy,
|
||||||
should_bypass_proxy,
|
should_bypass_proxy,
|
||||||
crate::consts::REQUEST_TIME_OUT,
|
crate::consts::REQUEST_TIME_OUT,
|
||||||
|
request.certificate,
|
||||||
|
request.certificate_key,
|
||||||
)?;
|
)?;
|
||||||
let headers = request.headers.construct_header_map()?;
|
let headers = request.headers.construct_header_map()?;
|
||||||
|
|
||||||
match request.method {
|
match request.method {
|
||||||
Method::Get => client.get(url).add_headers(headers).send().await,
|
Method::Get => client.get(url).add_headers(headers).send().await,
|
||||||
Method::Post => {
|
Method::Post => {
|
||||||
|
|||||||
@ -36,6 +36,8 @@ pub(super) fn create_client(
|
|||||||
proxy: &Proxy,
|
proxy: &Proxy,
|
||||||
should_bypass_proxy: bool,
|
should_bypass_proxy: bool,
|
||||||
request_time_out: u64,
|
request_time_out: u64,
|
||||||
|
client_certificate: Option<String>,
|
||||||
|
client_certificate_key: Option<String>,
|
||||||
) -> CustomResult<reqwest::Client, errors::ApiClientError> {
|
) -> CustomResult<reqwest::Client, errors::ApiClientError> {
|
||||||
let mut client_builder = reqwest::Client::builder();
|
let mut client_builder = reqwest::Client::builder();
|
||||||
|
|
||||||
@ -58,6 +60,36 @@ pub(super) fn create_client(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client_builder = match (client_certificate, client_certificate_key) {
|
||||||
|
(Some(encoded_cert), Some(encoded_cert_key)) => {
|
||||||
|
let decoded_cert = base64::decode(encoded_cert)
|
||||||
|
.into_report()
|
||||||
|
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;
|
||||||
|
|
||||||
|
let decoded_cert_key = base64::decode(encoded_cert_key)
|
||||||
|
.into_report()
|
||||||
|
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;
|
||||||
|
|
||||||
|
let certificate = String::from_utf8(decoded_cert)
|
||||||
|
.into_report()
|
||||||
|
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;
|
||||||
|
|
||||||
|
let certificate_key = String::from_utf8(decoded_cert_key)
|
||||||
|
.into_report()
|
||||||
|
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;
|
||||||
|
|
||||||
|
let identity = reqwest::Identity::from_pkcs8_pem(
|
||||||
|
certificate.as_bytes(),
|
||||||
|
certificate_key.as_bytes(),
|
||||||
|
)
|
||||||
|
.into_report()
|
||||||
|
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;
|
||||||
|
|
||||||
|
client_builder.identity(identity)
|
||||||
|
}
|
||||||
|
_ => client_builder,
|
||||||
|
};
|
||||||
|
|
||||||
let duration = Duration::from_secs(request_time_out);
|
let duration = Duration::from_secs(request_time_out);
|
||||||
client_builder = client_builder.timeout(duration);
|
client_builder = client_builder.timeout(duration);
|
||||||
|
|
||||||
|
|||||||
@ -37,6 +37,8 @@ pub struct Request {
|
|||||||
pub payload: Option<Secret<String>>,
|
pub payload: Option<Secret<String>>,
|
||||||
pub method: Method,
|
pub method: Method,
|
||||||
pub content_type: Option<ContentType>,
|
pub content_type: Option<ContentType>,
|
||||||
|
pub certificate: Option<String>,
|
||||||
|
pub certificate_key: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Request {
|
impl Request {
|
||||||
@ -47,6 +49,8 @@ impl Request {
|
|||||||
headers: Vec::new(),
|
headers: Vec::new(),
|
||||||
payload: None,
|
payload: None,
|
||||||
content_type: None,
|
content_type: None,
|
||||||
|
certificate: None,
|
||||||
|
certificate_key: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,6 +66,14 @@ impl Request {
|
|||||||
pub fn add_content_type(&mut self, content_type: ContentType) {
|
pub fn add_content_type(&mut self, content_type: ContentType) {
|
||||||
self.content_type = Some(content_type);
|
self.content_type = Some(content_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_certificate(&mut self, certificate: Option<String>) {
|
||||||
|
self.certificate = certificate;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_certificate_key(&mut self, certificate_key: Option<String>) {
|
||||||
|
self.certificate = certificate_key;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RequestBuilder {
|
pub struct RequestBuilder {
|
||||||
@ -70,6 +82,8 @@ pub struct RequestBuilder {
|
|||||||
pub payload: Option<Secret<String>>,
|
pub payload: Option<Secret<String>>,
|
||||||
pub method: Method,
|
pub method: Method,
|
||||||
pub content_type: Option<ContentType>,
|
pub content_type: Option<ContentType>,
|
||||||
|
pub certificate: Option<String>,
|
||||||
|
pub certificate_key: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RequestBuilder {
|
impl RequestBuilder {
|
||||||
@ -80,6 +94,8 @@ impl RequestBuilder {
|
|||||||
headers: Vec::new(),
|
headers: Vec::new(),
|
||||||
payload: None,
|
payload: None,
|
||||||
content_type: None,
|
content_type: None,
|
||||||
|
certificate: None,
|
||||||
|
certificate_key: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,6 +131,16 @@ impl RequestBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_certificate(mut self, certificate: Option<String>) -> RequestBuilder {
|
||||||
|
self.certificate = certificate;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_certificate_key(mut self, certificate_key: Option<String>) -> RequestBuilder {
|
||||||
|
self.certificate_key = certificate_key;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn build(self) -> Request {
|
pub fn build(self) -> Request {
|
||||||
Request {
|
Request {
|
||||||
method: self.method,
|
method: self.method,
|
||||||
@ -122,6 +148,8 @@ impl RequestBuilder {
|
|||||||
headers: self.headers,
|
headers: self.headers,
|
||||||
payload: self.payload,
|
payload: self.payload,
|
||||||
content_type: self.content_type,
|
content_type: self.content_type,
|
||||||
|
certificate: self.certificate,
|
||||||
|
certificate_key: self.certificate_key,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,14 +48,14 @@ pub type PaymentsSyncType =
|
|||||||
dyn services::ConnectorIntegration<api::PSync, PaymentsSyncData, PaymentsResponseData>;
|
dyn services::ConnectorIntegration<api::PSync, PaymentsSyncData, PaymentsResponseData>;
|
||||||
pub type PaymentsCaptureType =
|
pub type PaymentsCaptureType =
|
||||||
dyn services::ConnectorIntegration<api::Capture, PaymentsCaptureData, PaymentsResponseData>;
|
dyn services::ConnectorIntegration<api::Capture, PaymentsCaptureData, PaymentsResponseData>;
|
||||||
|
pub type PaymentsSessionType =
|
||||||
|
dyn services::ConnectorIntegration<api::Session, PaymentsSessionData, PaymentsResponseData>;
|
||||||
pub type PaymentsVoidType =
|
pub type PaymentsVoidType =
|
||||||
dyn services::ConnectorIntegration<api::Void, PaymentsCancelData, PaymentsResponseData>;
|
dyn services::ConnectorIntegration<api::Void, PaymentsCancelData, PaymentsResponseData>;
|
||||||
pub type RefundExecuteType =
|
pub type RefundExecuteType =
|
||||||
dyn services::ConnectorIntegration<api::Execute, RefundsData, RefundsResponseData>;
|
dyn services::ConnectorIntegration<api::Execute, RefundsData, RefundsResponseData>;
|
||||||
pub type RefundSyncType =
|
pub type RefundSyncType =
|
||||||
dyn services::ConnectorIntegration<api::RSync, RefundsData, RefundsResponseData>;
|
dyn services::ConnectorIntegration<api::RSync, RefundsData, RefundsResponseData>;
|
||||||
pub type PaymentsSessionType =
|
|
||||||
dyn services::ConnectorIntegration<api::Session, PaymentsSessionData, PaymentsResponseData>;
|
|
||||||
|
|
||||||
pub type VerifyRouterData = RouterData<api::Verify, VerifyRequestData, PaymentsResponseData>;
|
pub type VerifyRouterData = RouterData<api::Verify, VerifyRequestData, PaymentsResponseData>;
|
||||||
|
|
||||||
@ -73,6 +73,7 @@ pub struct RouterData<Flow, Request, Response> {
|
|||||||
pub orca_return_url: Option<String>,
|
pub orca_return_url: Option<String>,
|
||||||
pub address: PaymentAddress,
|
pub address: PaymentAddress,
|
||||||
pub auth_type: storage_enums::AuthenticationType,
|
pub auth_type: storage_enums::AuthenticationType,
|
||||||
|
pub connector_meta_data: Option<serde_json::Value>,
|
||||||
|
|
||||||
/// Contains flow-specific data required to construct a request and send it to the connector.
|
/// Contains flow-specific data required to construct a request and send it to the connector.
|
||||||
pub request: Request,
|
pub request: Request,
|
||||||
@ -123,17 +124,11 @@ pub struct PaymentsCancelData {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct PaymentsSessionData {
|
pub struct PaymentsSessionData {
|
||||||
|
//TODO: Add the fields here as required
|
||||||
pub amount: i32,
|
pub amount: i32,
|
||||||
pub currency: storage_enums::Currency,
|
pub currency: storage_enums::Currency,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ConnectorSessionToken {
|
|
||||||
pub connector_name: String,
|
|
||||||
pub session_id: Option<String>,
|
|
||||||
pub session_token: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct VerifyRequestData {
|
pub struct VerifyRequestData {
|
||||||
pub payment_method_data: payments::PaymentMethod,
|
pub payment_method_data: payments::PaymentMethod,
|
||||||
@ -250,7 +245,7 @@ pub struct ResponseRouterData<Flow, R, Request, Response> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Different patterns of authentication.
|
// Different patterns of authentication.
|
||||||
#[derive(Debug, Clone, serde::Deserialize)]
|
#[derive(Default, Debug, Clone, serde::Deserialize)]
|
||||||
#[serde(tag = "auth_type")]
|
#[serde(tag = "auth_type")]
|
||||||
pub enum ConnectorAuthType {
|
pub enum ConnectorAuthType {
|
||||||
HeaderKey {
|
HeaderKey {
|
||||||
@ -265,15 +260,10 @@ pub enum ConnectorAuthType {
|
|||||||
key1: String,
|
key1: String,
|
||||||
api_secret: String,
|
api_secret: String,
|
||||||
},
|
},
|
||||||
|
#[default]
|
||||||
|
NoKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ConnectorAuthType {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::HeaderKey {
|
|
||||||
api_key: "".to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct ConnectorsList {
|
pub struct ConnectorsList {
|
||||||
pub connectors: Vec<String>,
|
pub connectors: Vec<String>,
|
||||||
|
|||||||
@ -103,6 +103,7 @@ impl ConnectorData {
|
|||||||
"authorizedotnet" => Ok(Box::new(&connector::Authorizedotnet)),
|
"authorizedotnet" => Ok(Box::new(&connector::Authorizedotnet)),
|
||||||
"braintree" => Ok(Box::new(&connector::Braintree)),
|
"braintree" => Ok(Box::new(&connector::Braintree)),
|
||||||
"klarna" => Ok(Box::new(&connector::Klarna)),
|
"klarna" => Ok(Box::new(&connector::Klarna)),
|
||||||
|
"applepay" => Ok(Box::new(&connector::Applepay)),
|
||||||
_ => Err(report!(errors::UnexpectedError)
|
_ => Err(report!(errors::UnexpectedError)
|
||||||
.attach_printable(format!("invalid connector name: {connector_name}")))
|
.attach_printable(format!("invalid connector name: {connector_name}")))
|
||||||
.change_context(errors::ConnectorError::InvalidConnectorName)
|
.change_context(errors::ConnectorError::InvalidConnectorName)
|
||||||
|
|||||||
@ -8,6 +8,7 @@ pub enum Connector {
|
|||||||
Authorizedotnet,
|
Authorizedotnet,
|
||||||
Braintree,
|
Braintree,
|
||||||
Klarna,
|
Klarna,
|
||||||
|
Applepay,
|
||||||
#[default]
|
#[default]
|
||||||
Dummy,
|
Dummy,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,6 +51,7 @@ fn construct_payment_router_data() -> types::PaymentsAuthorizeRouterData {
|
|||||||
response: Err(types::ErrorResponse::default()),
|
response: Err(types::ErrorResponse::default()),
|
||||||
payment_method_id: None,
|
payment_method_id: None,
|
||||||
address: PaymentAddress::default(),
|
address: PaymentAddress::default(),
|
||||||
|
connector_meta_data: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,6 +90,7 @@ fn construct_refund_router_data<F>() -> types::RefundsRouterData<F> {
|
|||||||
payment_method_id: None,
|
payment_method_id: None,
|
||||||
response: Err(types::ErrorResponse::default()),
|
response: Err(types::ErrorResponse::default()),
|
||||||
address: PaymentAddress::default(),
|
address: PaymentAddress::default(),
|
||||||
|
connector_meta_data: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -51,6 +51,7 @@ fn construct_payment_router_data() -> types::PaymentsAuthorizeRouterData {
|
|||||||
payment_method_id: None,
|
payment_method_id: None,
|
||||||
response: Err(types::ErrorResponse::default()),
|
response: Err(types::ErrorResponse::default()),
|
||||||
address: PaymentAddress::default(),
|
address: PaymentAddress::default(),
|
||||||
|
connector_meta_data: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,6 +62,7 @@ fn construct_refund_router_data<F>() -> types::RefundsRouterData<F> {
|
|||||||
|
|
||||||
types::RouterData {
|
types::RouterData {
|
||||||
flow: PhantomData,
|
flow: PhantomData,
|
||||||
|
connector_meta_data: None,
|
||||||
merchant_id: String::from("authorizedotnet"),
|
merchant_id: String::from("authorizedotnet"),
|
||||||
connector: "authorizedotnet".to_string(),
|
connector: "authorizedotnet".to_string(),
|
||||||
payment_id: uuid::Uuid::new_v4().to_string(),
|
payment_id: uuid::Uuid::new_v4().to_string(),
|
||||||
|
|||||||
@ -48,6 +48,7 @@ fn construct_payment_router_data() -> types::PaymentsAuthorizeRouterData {
|
|||||||
response: Err(types::ErrorResponse::default()),
|
response: Err(types::ErrorResponse::default()),
|
||||||
payment_method_id: None,
|
payment_method_id: None,
|
||||||
address: PaymentAddress::default(),
|
address: PaymentAddress::default(),
|
||||||
|
connector_meta_data: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,6 +59,7 @@ fn construct_refund_router_data<F>() -> types::RefundsRouterData<F> {
|
|||||||
|
|
||||||
types::RouterData {
|
types::RouterData {
|
||||||
flow: PhantomData,
|
flow: PhantomData,
|
||||||
|
connector_meta_data: None,
|
||||||
merchant_id: "checkout".to_string(),
|
merchant_id: "checkout".to_string(),
|
||||||
connector: "checkout".to_string(),
|
connector: "checkout".to_string(),
|
||||||
payment_id: uuid::Uuid::new_v4().to_string(),
|
payment_id: uuid::Uuid::new_v4().to_string(),
|
||||||
|
|||||||
@ -16,6 +16,7 @@ pub struct MerchantConnectorAccount {
|
|||||||
#[diesel(deserialize_as = super::OptionalDieselArray<serde_json::Value>)]
|
#[diesel(deserialize_as = super::OptionalDieselArray<serde_json::Value>)]
|
||||||
pub payment_methods_enabled: Option<Vec<serde_json::Value>>,
|
pub payment_methods_enabled: Option<Vec<serde_json::Value>>,
|
||||||
pub connector_type: storage_enums::ConnectorType,
|
pub connector_type: storage_enums::ConnectorType,
|
||||||
|
pub metadata: Option<serde_json::Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Insertable, router_derive::DebugAsDisplay)]
|
#[derive(Clone, Debug, Default, Insertable, router_derive::DebugAsDisplay)]
|
||||||
@ -29,6 +30,7 @@ pub struct MerchantConnectorAccountNew {
|
|||||||
pub disabled: Option<bool>,
|
pub disabled: Option<bool>,
|
||||||
pub merchant_connector_id: Option<i32>,
|
pub merchant_connector_id: Option<i32>,
|
||||||
pub payment_methods_enabled: Option<Vec<serde_json::Value>>,
|
pub payment_methods_enabled: Option<Vec<serde_json::Value>>,
|
||||||
|
pub metadata: Option<serde_json::Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|||||||
@ -175,6 +175,7 @@ diesel::table! {
|
|||||||
merchant_connector_id -> Int4,
|
merchant_connector_id -> Int4,
|
||||||
payment_methods_enabled -> Nullable<Array<Nullable<Json>>>,
|
payment_methods_enabled -> Nullable<Array<Nullable<Json>>>,
|
||||||
connector_type -> ConnectorType,
|
connector_type -> ConnectorType,
|
||||||
|
metadata -> Nullable<Jsonb>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -58,10 +58,12 @@ base_url = "http://stripe-mock:12111/"
|
|||||||
[connectors.braintree]
|
[connectors.braintree]
|
||||||
base_url = "https://api.sandbox.braintreegateway.com/"
|
base_url = "https://api.sandbox.braintreegateway.com/"
|
||||||
|
|
||||||
|
[connectors.applepay]
|
||||||
|
base_url = "https://apple-pay-gateway.apple.com/"
|
||||||
|
|
||||||
[connectors.klarna]
|
[connectors.klarna]
|
||||||
base_url = "https://api-na.playground.klarna.com/"
|
base_url = "https://api-na.playground.klarna.com/"
|
||||||
|
|
||||||
[connectors.supported]
|
[connectors.supported]
|
||||||
wallets = ["klarna","braintree"]
|
wallets = ["klarna","braintree","applepay"]
|
||||||
cards = ["stripe","adyen","authorizedotnet","checkout","braintree"]
|
cards = ["stripe","adyen","authorizedotnet","checkout","braintree"]
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE merchant_connector_account DROP COLUMN metadata;
|
||||||
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE merchant_connector_account ADD COLUMN metadata JSONB DEFAULT NULL;
|
||||||
Reference in New Issue
Block a user