WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit 0582129

Browse files
authored
feat(connector): Introduce Connector Customer Flow and Optional Billing Address Support (#10499)
1 parent a4b55b4 commit 0582129

File tree

10 files changed

+228
-30
lines changed

10 files changed

+228
-30
lines changed

crates/connector_configs/toml/development.toml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6998,6 +6998,8 @@ key1="Product Line Id"
69986998
payment_method_type = "Mastercard"
69996999
[[payload.debit]]
70007000
payment_method_type = "Visa"
7001+
[[payload.bank_debit]]
7002+
payment_method_type = "ach"
70017003

70027004
[payload.connector_auth.CurrencyAuthKey.auth_key_map.USD]
70037005
processing_account_id = "processing_account_id"
@@ -7721,6 +7723,24 @@ options=["CRYPTOGRAM_3DS"]
77217723
api_key="Username"
77227724
api_secret="Password"
77237725
key1="Account ID"
7726+
[zift.metadata.acquirer_bin]
7727+
name="acquirer_bin"
7728+
label="Acquirer Bin"
7729+
placeholder="Enter Acquirer Bin"
7730+
required=false
7731+
type="Text"
7732+
[zift.metadata.acquirer_merchant_id]
7733+
name="acquirer_merchant_id"
7734+
label="Acquirer Merchant ID"
7735+
placeholder="Enter Acquirer Merchant ID"
7736+
required=false
7737+
type="Text"
7738+
[zift.metadata.acquirer_country_code]
7739+
name="acquirer_country_code"
7740+
label="Acquirer Country Code"
7741+
placeholder="Enter Acquirer Country Code"
7742+
required=false
7743+
type="Text"
77247744

77257745
[payjustnow]
77267746
[payjustnow.connector_auth.BodyKey]

crates/connector_configs/toml/production.toml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5695,6 +5695,8 @@ payment_method_type = "Discover"
56955695
payment_method_type = "Mastercard"
56965696
[[payload.debit]]
56975697
payment_method_type = "Visa"
5698+
[[payload.bank_debit]]
5699+
payment_method_type = "ach"
56985700

56995701
[payload.connector_auth.CurrencyAuthKey.auth_key_map.USD]
57005702
processing_account_id = "processing_account_id"
@@ -6456,6 +6458,24 @@ options=["CRYPTOGRAM_3DS"]
64566458
api_key="Username"
64576459
api_secret="Password"
64586460
key1="Account ID"
6461+
[zift.metadata.acquirer_bin]
6462+
name="acquirer_bin"
6463+
label="Acquirer Bin"
6464+
placeholder="Enter Acquirer Bin"
6465+
required=false
6466+
type="Text"
6467+
[zift.metadata.acquirer_merchant_id]
6468+
name="acquirer_merchant_id"
6469+
label="Acquirer Merchant ID"
6470+
placeholder="Enter Acquirer Merchant ID"
6471+
required=false
6472+
type="Text"
6473+
[zift.metadata.acquirer_country_code]
6474+
name="acquirer_country_code"
6475+
label="Acquirer Country Code"
6476+
placeholder="Enter Acquirer Country Code"
6477+
required=false
6478+
type="Text"
64596479

64606480
[payjustnow]
64616481
[payjustnow.connector_auth.BodyKey]

crates/connector_configs/toml/sandbox.toml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6976,6 +6976,8 @@ payment_method_type = "Discover"
69766976
payment_method_type = "Mastercard"
69776977
[[payload.debit]]
69786978
payment_method_type = "Visa"
6979+
[[payload.bank_debit]]
6980+
payment_method_type = "ach"
69796981

69806982
[payload.connector_auth.CurrencyAuthKey.auth_key_map.USD]
69816983
processing_account_id = "processing_account_id"
@@ -7694,6 +7696,24 @@ options=["CRYPTOGRAM_3DS"]
76947696
api_key="Username"
76957697
api_secret="Password"
76967698
key1="Account ID"
7699+
[zift.metadata.acquirer_bin]
7700+
name="acquirer_bin"
7701+
label="Acquirer Bin"
7702+
placeholder="Enter Acquirer Bin"
7703+
required=false
7704+
type="Text"
7705+
[zift.metadata.acquirer_merchant_id]
7706+
name="acquirer_merchant_id"
7707+
label="Acquirer Merchant ID"
7708+
placeholder="Enter Acquirer Merchant ID"
7709+
required=false
7710+
type="Text"
7711+
[zift.metadata.acquirer_country_code]
7712+
name="acquirer_country_code"
7713+
label="Acquirer Country Code"
7714+
placeholder="Enter Acquirer Country Code"
7715+
required=false
7716+
type="Text"
76977717

76987718
[payjustnow]
76997719
[payjustnow.connector_auth.BodyKey]

crates/hyperswitch_connectors/src/connectors/payload.rs

Lines changed: 103 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,25 @@ use hyperswitch_domain_models::{
2020
router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData},
2121
router_flow_types::{
2222
access_token_auth::AccessTokenAuth,
23-
payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void},
23+
payments::{
24+
Authorize, Capture, CreateConnectorCustomer, PSync, PaymentMethodToken, Session,
25+
SetupMandate, Void,
26+
},
2427
refunds::{Execute, RSync},
2528
},
2629
router_request_types::{
27-
AccessTokenRequestData, PaymentMethodTokenizationData, PaymentsAuthorizeData,
28-
PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, PaymentsSyncData,
29-
RefundsData, SetupMandateRequestData,
30+
AccessTokenRequestData, ConnectorCustomerData, PaymentMethodTokenizationData,
31+
PaymentsAuthorizeData, PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData,
32+
PaymentsSyncData, RefundsData, SetupMandateRequestData,
3033
},
3134
router_response_types::{
3235
ConnectorInfo, PaymentMethodDetails, PaymentsResponseData, RefundsResponseData,
3336
SupportedPaymentMethods, SupportedPaymentMethodsExt,
3437
},
3538
types::{
36-
PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData,
37-
PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData, SetupMandateRouterData,
39+
ConnectorCustomerRouterData, PaymentsAuthorizeRouterData, PaymentsCancelRouterData,
40+
PaymentsCaptureRouterData, PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData,
41+
SetupMandateRouterData,
3842
},
3943
};
4044
use hyperswitch_interfaces::{
@@ -45,7 +49,7 @@ use hyperswitch_interfaces::{
4549
configs::Connectors,
4650
errors,
4751
events::connector_api_logs::ConnectorEvent,
48-
types::{self, PaymentsVoidType, Response, SetupMandateType},
52+
types::{self, ConnectorCustomerType, PaymentsVoidType, Response, SetupMandateType},
4953
webhooks,
5054
};
5155
use masking::{ExposeInterface, Mask};
@@ -78,6 +82,88 @@ impl api::Refund for Payload {}
7882
impl api::RefundExecute for Payload {}
7983
impl api::RefundSync for Payload {}
8084
impl api::PaymentToken for Payload {}
85+
impl api::ConnectorCustomer for Payload {}
86+
87+
impl ConnectorIntegration<CreateConnectorCustomer, ConnectorCustomerData, PaymentsResponseData>
88+
for Payload
89+
{
90+
fn get_headers(
91+
&self,
92+
req: &ConnectorCustomerRouterData,
93+
_connectors: &Connectors,
94+
) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
95+
let mut header = vec![(
96+
headers::CONTENT_TYPE.to_string(),
97+
"application/json".to_string().into(),
98+
)];
99+
let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
100+
header.append(&mut api_key);
101+
Ok(header)
102+
}
103+
fn get_url(
104+
&self,
105+
_req: &ConnectorCustomerRouterData,
106+
connectors: &Connectors,
107+
) -> CustomResult<String, errors::ConnectorError> {
108+
Ok(format!("{}/customers", self.base_url(connectors),))
109+
}
110+
111+
fn get_request_body(
112+
&self,
113+
req: &ConnectorCustomerRouterData,
114+
_connectors: &Connectors,
115+
) -> CustomResult<RequestContent, errors::ConnectorError> {
116+
let connector_req = requests::CustomerRequest::try_from(req)?;
117+
Ok(RequestContent::Json(Box::new(connector_req)))
118+
}
119+
120+
fn build_request(
121+
&self,
122+
req: &ConnectorCustomerRouterData,
123+
connectors: &Connectors,
124+
) -> CustomResult<Option<Request>, errors::ConnectorError> {
125+
Ok(Some(
126+
RequestBuilder::new()
127+
.method(Method::Post)
128+
.url(&ConnectorCustomerType::get_url(self, req, connectors)?)
129+
.attach_default_headers()
130+
.headers(ConnectorCustomerType::get_headers(self, req, connectors)?)
131+
.set_body(ConnectorCustomerType::get_request_body(
132+
self, req, connectors,
133+
)?)
134+
.build(),
135+
))
136+
}
137+
138+
fn handle_response(
139+
&self,
140+
data: &ConnectorCustomerRouterData,
141+
event_builder: Option<&mut ConnectorEvent>,
142+
res: Response,
143+
) -> CustomResult<ConnectorCustomerRouterData, errors::ConnectorError> {
144+
let response: responses::CustomerResponse =
145+
res.response
146+
.parse_struct("CustomerResponse")
147+
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
148+
149+
event_builder.map(|i| i.set_response_body(&response));
150+
router_env::logger::info!(connector_response=?response);
151+
152+
RouterData::try_from(ResponseRouterData {
153+
response,
154+
data: data.clone(),
155+
http_code: res.status_code,
156+
})
157+
}
158+
159+
fn get_error_response(
160+
&self,
161+
res: Response,
162+
event_builder: Option<&mut ConnectorEvent>,
163+
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
164+
self.build_error_response(res, event_builder)
165+
}
166+
}
81167

82168
impl ConnectorIntegration<PaymentMethodToken, PaymentMethodTokenizationData, PaymentsResponseData>
83169
for Payload
@@ -962,4 +1048,14 @@ impl ConnectorSpecifications for Payload {
9621048
fn get_supported_webhook_flows(&self) -> Option<&'static [enums::EventClass]> {
9631049
Some(&PAYLOAD_SUPPORTED_WEBHOOK_FLOWS)
9641050
}
1051+
fn should_call_connector_customer(
1052+
&self,
1053+
payment_attempt: &hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt,
1054+
) -> bool {
1055+
#[cfg(feature = "v1")]
1056+
return payment_attempt.customer_acceptance.is_some()
1057+
&& payment_attempt.setup_future_usage_applied == Some(enums::FutureUsage::OffSession);
1058+
#[cfg(feature = "v2")]
1059+
return false;
1060+
}
9651061
}

crates/hyperswitch_connectors/src/connectors/payload/requests.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use common_utils::types::StringMajorUnit;
1+
use common_utils::{pii::Email, types::StringMajorUnit};
22
use masking::Secret;
33
use serde::{Deserialize, Serialize};
44

@@ -26,15 +26,15 @@ pub enum TransactionTypes {
2626
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
2727
pub struct BillingAddress {
2828
#[serde(rename = "payment_method[billing_address][city]")]
29-
pub city: String,
29+
pub city: Option<String>,
3030
#[serde(rename = "payment_method[billing_address][country_code]")]
31-
pub country: common_enums::CountryAlpha2,
31+
pub country: Option<common_enums::CountryAlpha2>,
3232
#[serde(rename = "payment_method[billing_address][postal_code]")]
3333
pub postal_code: Secret<String>,
3434
#[serde(rename = "payment_method[billing_address][state_province]")]
35-
pub state_province: Secret<String>,
35+
pub state_province: Option<Secret<String>>,
3636
#[serde(rename = "payment_method[billing_address][street_address]")]
37-
pub street_address: Secret<String>,
37+
pub street_address: Option<Secret<String>>,
3838
}
3939

4040
#[derive(Debug, Clone, Serialize)]
@@ -55,6 +55,15 @@ pub struct PayloadPaymentRequestData {
5555
/// This is true by default
5656
#[serde(rename = "payment_method[keep_active]")]
5757
pub keep_active: bool,
58+
#[serde(skip_serializing_if = "Option::is_none")]
59+
pub customer_id: Option<String>,
60+
}
61+
62+
#[derive(Debug, Clone, Serialize)]
63+
pub struct CustomerRequest {
64+
pub keep_active: bool,
65+
pub email: Email,
66+
pub name: Secret<String>,
5867
}
5968

6069
#[derive(Debug, Clone, Serialize, PartialEq)]

crates/hyperswitch_connectors/src/connectors/payload/responses.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ pub struct PayloadCardsResponseData {
4848
#[serde(rename = "type")]
4949
pub response_type: Option<String>,
5050
}
51-
51+
#[derive(Debug, Clone, Serialize, Deserialize)]
52+
pub struct CustomerResponse {
53+
pub id: String,
54+
}
5255
// Type definition for Refund Response
5356
// Added based on assumptions since this is not provided in the documentation
5457
#[derive(Debug, Copy, Serialize, Default, Deserialize, Clone)]

0 commit comments

Comments
 (0)