Skip to content

Commit b8b1960

Browse files
swangi-kumarihyperswitch-bot[bot]Aishwariyaa Anand
authored
feat(core): accept merchant_connector_details in Payments and Psync flow (#8199)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Co-authored-by: Aishwariyaa Anand <[email protected]>
1 parent 4d36be8 commit b8b1960

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+938
-360
lines changed

api-reference/v2/openapi_spec_v2.json

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13442,16 +13442,17 @@
1344213442
},
1344313443
"MerchantConnectorDetails": {
1344413444
"type": "object",
13445+
"required": [
13446+
"connector_name",
13447+
"merchant_connector_creds"
13448+
],
1344513449
"properties": {
13446-
"connector_account_details": {
13447-
"type": "object",
13448-
"description": "Account details of the Connector. You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Useful for storing additional, structured information on an object.",
13449-
"nullable": true
13450+
"connector_name": {
13451+
"$ref": "#/components/schemas/Connector"
1345013452
},
13451-
"metadata": {
13453+
"merchant_connector_creds": {
1345213454
"type": "object",
13453-
"description": "Metadata is useful for storing additional, unstructured information on an object.",
13454-
"nullable": true
13455+
"description": "The merchant connector credentials used for the payment"
1345513456
}
1345613457
}
1345713458
},
@@ -18091,6 +18092,14 @@
1809118092
"type": "string",
1809218093
"example": "187282ab-40ef-47a9-9206-5099ba31e432",
1809318094
"nullable": true
18095+
},
18096+
"merchant_connector_details": {
18097+
"allOf": [
18098+
{
18099+
"$ref": "#/components/schemas/MerchantConnectorDetails"
18100+
}
18101+
],
18102+
"nullable": true
1809418103
}
1809518104
},
1809618105
"additionalProperties": false
@@ -18288,6 +18297,14 @@
1828818297
"type": "boolean",
1828918298
"description": "Indicates if 3ds challenge is forced",
1829018299
"nullable": true
18300+
},
18301+
"merchant_connector_details": {
18302+
"allOf": [
18303+
{
18304+
"$ref": "#/components/schemas/MerchantConnectorDetails"
18305+
}
18306+
],
18307+
"nullable": true
1829118308
}
1829218309
},
1829318310
"additionalProperties": false
@@ -19074,6 +19091,14 @@
1907419091
"type": "boolean",
1907519092
"description": "Indicates if the redirection has to open in the iframe",
1907619093
"nullable": true
19094+
},
19095+
"merchant_connector_details": {
19096+
"allOf": [
19097+
{
19098+
"$ref": "#/components/schemas/MerchantConnectorDetails"
19099+
}
19100+
],
19101+
"nullable": true
1907719102
}
1907819103
},
1907919104
"additionalProperties": false
@@ -19250,12 +19275,20 @@
1925019275
"type": "boolean",
1925119276
"description": "Indicates if the redirection has to open in the iframe",
1925219277
"nullable": true
19278+
},
19279+
"merchant_reference_id": {
19280+
"type": "string",
19281+
"description": "Unique identifier for the payment. This ensures idempotency for multiple payments\nthat have been done by a single merchant.",
19282+
"example": "pay_mbabizu24mvu3mela5njyhpit4",
19283+
"nullable": true,
19284+
"maxLength": 30,
19285+
"minLength": 30
1925319286
}
1925419287
}
1925519288
},
1925619289
"PaymentsRetrieveRequest": {
1925719290
"type": "object",
19258-
"description": "Request for Payment Status",
19291+
"description": "Request body for Payment Status",
1925919292
"properties": {
1926019293
"force_sync": {
1926119294
"type": "boolean",
@@ -19274,6 +19307,14 @@
1927419307
"type": "boolean",
1927519308
"description": "If enabled, provides whole connector response",
1927619309
"nullable": true
19310+
},
19311+
"merchant_connector_details": {
19312+
"allOf": [
19313+
{
19314+
"$ref": "#/components/schemas/MerchantConnectorDetails"
19315+
}
19316+
],
19317+
"nullable": true
1927719318
}
1927819319
}
1927919320
},
@@ -19308,6 +19349,30 @@
1930819349
}
1930919350
}
1931019351
},
19352+
"PaymentsStatusRequest": {
19353+
"type": "object",
19354+
"description": "Request for Payment Status",
19355+
"properties": {
19356+
"force_sync": {
19357+
"type": "boolean",
19358+
"description": "A boolean used to indicate if the payment status should be fetched from the connector\nIf this is set to true, the status will be fetched from the connector"
19359+
},
19360+
"expand_attempts": {
19361+
"type": "boolean",
19362+
"description": "A boolean used to indicate if all the attempts needs to be fetched for the intent.\nIf this is set to true, attempts list will be available in the response."
19363+
},
19364+
"param": {
19365+
"type": "string",
19366+
"description": "These are the query params that are sent in case of redirect response.\nThese can be ingested by the connector to take necessary actions.",
19367+
"nullable": true
19368+
},
19369+
"all_keys_required": {
19370+
"type": "boolean",
19371+
"description": "If enabled, provides whole connector response",
19372+
"nullable": true
19373+
}
19374+
}
19375+
},
1931119376
"PaymentsUpdateIntentRequest": {
1931219377
"type": "object",
1931319378
"properties": {

crates/api_models/src/payments.rs

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,26 @@ pub struct PaymentsCreateIntentRequest {
269269

270270
/// Indicates if 3ds challenge is forced
271271
pub force_3ds_challenge: Option<bool>,
272+
273+
/// Merchant connector details used to make payments.
274+
pub merchant_connector_details: Option<MerchantConnectorDetails>,
275+
}
276+
277+
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
278+
#[cfg(feature = "v2")]
279+
pub struct MerchantConnectorDetails {
280+
/// The connector used for the payment
281+
#[schema(value_type = Connector)]
282+
pub connector_name: api_enums::Connector,
283+
284+
/// The merchant connector credentials used for the payment
285+
#[schema(value_type = Object, example = r#"{
286+
"merchant_connector_creds": {
287+
"auth_type": "HeaderKey",
288+
"api_key":"sk_test_xxxxxexamplexxxxxx12345"
289+
},
290+
}"#)]
291+
pub merchant_connector_creds: pii::SecretSerdeValue,
272292
}
273293

274294
#[cfg(feature = "v2")]
@@ -5348,6 +5368,9 @@ pub struct PaymentsConfirmIntentRequest {
53485368

53495369
#[schema(example = "187282ab-40ef-47a9-9206-5099ba31e432")]
53505370
pub payment_token: Option<String>,
5371+
5372+
/// Merchant connector details used to make payments.
5373+
pub merchant_connector_details: Option<MerchantConnectorDetails>,
53515374
}
53525375

53535376
#[cfg(feature = "v2")]
@@ -5520,6 +5543,9 @@ pub struct PaymentsRequest {
55205543

55215544
/// Indicates if the redirection has to open in the iframe
55225545
pub is_iframe_redirection_enabled: Option<bool>,
5546+
5547+
/// Merchant connector details used to make payments.
5548+
pub merchant_connector_details: Option<MerchantConnectorDetails>,
55235549
}
55245550

55255551
#[cfg(feature = "v2")]
@@ -5554,6 +5580,7 @@ impl From<&PaymentsRequest> for PaymentsCreateIntentRequest {
55545580
.request_external_three_ds_authentication
55555581
.clone(),
55565582
force_3ds_challenge: request.force_3ds_challenge,
5583+
merchant_connector_details: request.merchant_connector_details.clone(),
55575584
}
55585585
}
55595586
}
@@ -5571,14 +5598,15 @@ impl From<&PaymentsRequest> for PaymentsConfirmIntentRequest {
55715598
browser_info: request.browser_info.clone(),
55725599
payment_method_id: request.payment_method_id.clone(),
55735600
payment_token: None,
5601+
merchant_connector_details: request.merchant_connector_details.clone(),
55745602
}
55755603
}
55765604
}
55775605

55785606
// Serialize is implemented because, this will be serialized in the api events.
55795607
// Usually request types should not have serialize implemented.
55805608
//
5581-
/// Request for Payment Status
5609+
/// Request body for Payment Status
55825610
#[cfg(feature = "v2")]
55835611
#[derive(Debug, serde::Deserialize, serde::Serialize, ToSchema)]
55845612
pub struct PaymentsRetrieveRequest {
@@ -5595,6 +5623,27 @@ pub struct PaymentsRetrieveRequest {
55955623
pub param: Option<String>,
55965624
/// If enabled, provides whole connector response
55975625
pub all_keys_required: Option<bool>,
5626+
/// Merchant connector details used to make payments.
5627+
pub merchant_connector_details: Option<MerchantConnectorDetails>,
5628+
}
5629+
5630+
#[cfg(feature = "v2")]
5631+
#[derive(Debug, serde::Deserialize, serde::Serialize, ToSchema)]
5632+
/// Request for Payment Status
5633+
pub struct PaymentsStatusRequest {
5634+
/// A boolean used to indicate if the payment status should be fetched from the connector
5635+
/// If this is set to true, the status will be fetched from the connector
5636+
#[serde(default)]
5637+
pub force_sync: bool,
5638+
/// A boolean used to indicate if all the attempts needs to be fetched for the intent.
5639+
/// If this is set to true, attempts list will be available in the response.
5640+
#[serde(default)]
5641+
pub expand_attempts: bool,
5642+
/// These are the query params that are sent in case of redirect response.
5643+
/// These can be ingested by the connector to take necessary actions.
5644+
pub param: Option<String>,
5645+
/// If enabled, provides whole connector response
5646+
pub all_keys_required: Option<bool>,
55985647
}
55995648

56005649
/// Error details for the payment
@@ -5740,6 +5789,16 @@ pub struct PaymentsResponse {
57405789

57415790
/// Indicates if the redirection has to open in the iframe
57425791
pub is_iframe_redirection_enabled: Option<bool>,
5792+
5793+
/// Unique identifier for the payment. This ensures idempotency for multiple payments
5794+
/// that have been done by a single merchant.
5795+
#[schema(
5796+
value_type = Option<String>,
5797+
min_length = 30,
5798+
max_length = 30,
5799+
example = "pay_mbabizu24mvu3mela5njyhpit4"
5800+
)]
5801+
pub merchant_reference_id: Option<id_type::PaymentReferenceId>,
57435802
}
57445803

57455804
#[cfg(feature = "v2")]

crates/hyperswitch_domain_models/src/customer.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ use masking::{PeekInterface, Secret, SwitchStrategy};
2020
use rustc_hash::FxHashMap;
2121
use time::PrimitiveDateTime;
2222

23+
#[cfg(feature = "v2")]
24+
use crate::merchant_connector_account::MerchantConnectorAccountTypeDetails;
2325
use crate::{behaviour, merchant_key_store::MerchantKeyStore, type_encryption as types};
2426

2527
#[cfg(feature = "v1")]
@@ -101,12 +103,18 @@ impl Customer {
101103
#[cfg(feature = "v2")]
102104
pub fn get_connector_customer_id(
103105
&self,
104-
merchant_connector_id: &id_type::MerchantConnectorAccountId,
106+
merchant_connector_account: &MerchantConnectorAccountTypeDetails,
105107
) -> Option<&str> {
106-
self.connector_customer
107-
.as_ref()
108-
.and_then(|connector_customer_map| connector_customer_map.get(merchant_connector_id))
109-
.map(|connector_customer_id| connector_customer_id.as_str())
108+
match merchant_connector_account {
109+
MerchantConnectorAccountTypeDetails::MerchantConnectorAccount(account) => {
110+
let connector_account_id = account.get_id();
111+
self.connector_customer
112+
.as_ref()?
113+
.get(&connector_account_id)
114+
.map(|connector_customer_id| connector_customer_id.as_str())
115+
}
116+
MerchantConnectorAccountTypeDetails::MerchantConnectorDetails(_) => None,
117+
}
110118
}
111119
}
112120

crates/hyperswitch_domain_models/src/merchant_connector_account.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,92 @@ impl MerchantConnectorAccount {
9393
}
9494
}
9595

96+
#[cfg(feature = "v2")]
97+
#[derive(Clone, Debug)]
98+
pub enum MerchantConnectorAccountTypeDetails {
99+
MerchantConnectorAccount(Box<MerchantConnectorAccount>),
100+
MerchantConnectorDetails(api_models::payments::MerchantConnectorDetails),
101+
}
102+
103+
#[cfg(feature = "v2")]
104+
impl MerchantConnectorAccountTypeDetails {
105+
pub fn get_connector_account_details(
106+
&self,
107+
) -> error_stack::Result<router_data::ConnectorAuthType, common_utils::errors::ParsingError>
108+
{
109+
match self {
110+
Self::MerchantConnectorAccount(merchant_connector_account) => {
111+
merchant_connector_account
112+
.connector_account_details
113+
.peek()
114+
.clone()
115+
.parse_value("ConnectorAuthType")
116+
}
117+
Self::MerchantConnectorDetails(merchant_connector_details) => {
118+
merchant_connector_details
119+
.merchant_connector_creds
120+
.peek()
121+
.clone()
122+
.parse_value("ConnectorAuthType")
123+
}
124+
}
125+
}
126+
127+
pub fn is_disabled(&self) -> bool {
128+
match self {
129+
Self::MerchantConnectorAccount(merchant_connector_account) => {
130+
merchant_connector_account.disabled.unwrap_or(false)
131+
}
132+
Self::MerchantConnectorDetails(_) => false,
133+
}
134+
}
135+
136+
pub fn get_metadata(&self) -> Option<Secret<Value>> {
137+
match self {
138+
Self::MerchantConnectorAccount(merchant_connector_account) => {
139+
merchant_connector_account.metadata.to_owned()
140+
}
141+
Self::MerchantConnectorDetails(_) => None,
142+
}
143+
}
144+
145+
pub fn get_id(&self) -> Option<id_type::MerchantConnectorAccountId> {
146+
match self {
147+
Self::MerchantConnectorAccount(merchant_connector_account) => {
148+
Some(merchant_connector_account.id.clone())
149+
}
150+
Self::MerchantConnectorDetails(_) => None,
151+
}
152+
}
153+
154+
pub fn get_mca_id(&self) -> Option<id_type::MerchantConnectorAccountId> {
155+
match self {
156+
Self::MerchantConnectorAccount(merchant_connector_account) => {
157+
Some(merchant_connector_account.get_id())
158+
}
159+
Self::MerchantConnectorDetails(_) => None,
160+
}
161+
}
162+
163+
pub fn get_connector_name(&self) -> Option<common_enums::connector_enums::Connector> {
164+
match self {
165+
Self::MerchantConnectorAccount(merchant_connector_account) => {
166+
Some(merchant_connector_account.connector_name)
167+
}
168+
Self::MerchantConnectorDetails(_) => None,
169+
}
170+
}
171+
172+
pub fn get_inner_db_merchant_connector_account(&self) -> Option<&MerchantConnectorAccount> {
173+
match self {
174+
Self::MerchantConnectorAccount(merchant_connector_account) => {
175+
Some(merchant_connector_account)
176+
}
177+
Self::MerchantConnectorDetails(_) => None,
178+
}
179+
}
180+
}
181+
96182
#[cfg(feature = "v2")]
97183
#[derive(Clone, Debug, router_derive::ToEncryption)]
98184
pub struct MerchantConnectorAccount {

0 commit comments

Comments
 (0)