Skip to content

Commit 7eabd24

Browse files
authored
fix: consume profile_id throughout payouts flow (#2501)
Co-authored-by: Kashif <[email protected]>
1 parent 1ee1184 commit 7eabd24

File tree

6 files changed

+38
-29
lines changed

6 files changed

+38
-29
lines changed

crates/api_models/src/payouts.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@ pub struct PayoutCreateRequest {
146146
/// Provide a reference to a stored payment method
147147
#[schema(example = "187282ab-40ef-47a9-9206-5099ba31e432")]
148148
pub payout_token: Option<String>,
149+
150+
/// The business profile to use for this payment, if not passed the default business profile
151+
/// associated with the merchant account will be used.
152+
pub profile_id: Option<String>,
149153
}
150154

151155
#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)]
@@ -376,6 +380,9 @@ pub struct PayoutCreateResponse {
376380
/// If there was an error while calling the connectors the code is received here
377381
#[schema(value_type = String, example = "E0001")]
378382
pub error_code: Option<String>,
383+
384+
/// The business profile that is associated with this payment
385+
pub profile_id: Option<String>,
379386
}
380387

381388
#[derive(Default, Debug, Clone, Deserialize, ToSchema)]

crates/router/src/core/payouts.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,7 @@ pub async fn create_recipient(
618618
let merchant_id = merchant_account.merchant_id.to_owned();
619619
let updated_customer = storage::CustomerUpdate::ConnectorCustomer {
620620
connector_customer: Some(
621-
serde_json::json!({"id": recipient_create_data.connector_payout_id}),
621+
serde_json::json!({connector_label: recipient_create_data.connector_payout_id}),
622622
),
623623
};
624624
payout_data.customer_details = Some(
@@ -1116,6 +1116,7 @@ pub async fn response_handler(
11161116
status: payout_attempt.status.to_owned(),
11171117
error_message: payout_attempt.error_message.to_owned(),
11181118
error_code: payout_attempt.error_code,
1119+
profile_id: payout_attempt.profile_id,
11191120
};
11201121
Ok(services::ApplicationResponse::Json(response))
11211122
}
@@ -1244,6 +1245,7 @@ pub async fn payout_create_db_entries(
12441245
.set_payout_token(req.payout_token.to_owned())
12451246
.set_created_at(Some(common_utils::date_time::now()))
12461247
.set_last_modified_at(Some(common_utils::date_time::now()))
1248+
.set_profile_id(req.profile_id.to_owned())
12471249
.to_owned();
12481250
let payout_attempt = db
12491251
.insert_payout_attempt(payout_attempt_req)

crates/router/src/core/utils.rs

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -40,31 +40,32 @@ pub async fn get_mca_for_payout<'a>(
4040
merchant_account: &domain::MerchantAccount,
4141
key_store: &domain::MerchantKeyStore,
4242
payout_data: &PayoutData,
43-
) -> RouterResult<helpers::MerchantConnectorAccountType> {
43+
) -> RouterResult<(helpers::MerchantConnectorAccountType, String)> {
4444
let payout_attempt = &payout_data.payout_attempt;
45+
let profile_id = get_profile_id_from_business_details(
46+
payout_attempt.business_country,
47+
payout_attempt.business_label.as_ref(),
48+
merchant_account,
49+
payout_attempt.profile_id.as_ref(),
50+
&*state.store,
51+
false,
52+
)
53+
.await
54+
.change_context(errors::ApiErrorResponse::InternalServerError)
55+
.attach_printable("profile_id is not set in payout_attempt")?;
4556
match payout_data.merchant_connector_account.to_owned() {
46-
Some(mca) => Ok(mca),
57+
Some(mca) => Ok((mca, profile_id)),
4758
None => {
48-
let profile_id = payout_attempt
49-
.profile_id
50-
.as_ref()
51-
.ok_or(errors::ApiErrorResponse::MissingRequiredField {
52-
field_name: "business_profile",
53-
})
54-
.into_report()
55-
.change_context(errors::ApiErrorResponse::InternalServerError)
56-
.attach_printable("profile_id is not set in payment_intent")?;
57-
5859
let merchant_connector_account = helpers::get_merchant_connector_account(
5960
state,
6061
merchant_account.merchant_id.as_str(),
6162
None,
6263
key_store,
63-
profile_id,
64+
&profile_id,
6465
connector_id,
6566
)
6667
.await?;
67-
Ok(merchant_connector_account)
68+
Ok((merchant_connector_account, profile_id))
6869
}
6970
}
7071
}
@@ -79,12 +80,7 @@ pub async fn construct_payout_router_data<'a, F>(
7980
_request: &api_models::payouts::PayoutRequest,
8081
payout_data: &mut PayoutData,
8182
) -> RouterResult<types::PayoutsRouterData<F>> {
82-
let (business_country, _) = helpers::get_business_details(
83-
payout_data.payout_attempt.business_country,
84-
payout_data.payout_attempt.business_label.as_ref(),
85-
merchant_account,
86-
)?;
87-
let merchant_connector_account = get_mca_for_payout(
83+
let (merchant_connector_account, profile_id) = get_mca_for_payout(
8884
state,
8985
connector_id,
9086
merchant_account,
@@ -130,10 +126,11 @@ pub async fn construct_payout_router_data<'a, F>(
130126
let payouts = &payout_data.payouts;
131127
let payout_attempt = &payout_data.payout_attempt;
132128
let customer_details = &payout_data.customer_details;
129+
let connector_label = format!("{profile_id}_{}", payout_attempt.connector);
133130
let connector_customer_id = customer_details
134131
.as_ref()
135132
.and_then(|c| c.connector_customer.as_ref())
136-
.and_then(|cc| cc.get("id"))
133+
.and_then(|cc| cc.get(connector_label))
137134
.and_then(|id| serde_json::from_value::<String>(id.to_owned()).ok());
138135
let router_data = types::RouterData {
139136
flow: PhantomData,
@@ -161,7 +158,6 @@ pub async fn construct_payout_router_data<'a, F>(
161158
source_currency: payouts.source_currency,
162159
entity_type: payouts.entity_type.to_owned(),
163160
payout_type: payouts.payout_type,
164-
country_code: business_country,
165161
customer_details: customer_details
166162
.to_owned()
167163
.map(|c| payments::CustomerDetails {

crates/router/src/types.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,6 @@ pub struct PayoutsData {
335335
pub source_currency: storage_enums::Currency,
336336
pub payout_type: storage_enums::PayoutType,
337337
pub entity_type: storage_enums::PayoutEntityType,
338-
pub country_code: storage_enums::CountryAlpha2,
339338
pub customer_details: Option<CustomerDetails>,
340339
}
341340

crates/router/tests/connectors/utils.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -442,11 +442,6 @@ pub trait ConnectorActions: Connector {
442442
}),
443443
entity_type: enums::PayoutEntityType::Individual,
444444
payout_type,
445-
country_code: payment_info
446-
.to_owned()
447-
.map_or(enums::CountryAlpha2::NL, |pi| {
448-
pi.country.map_or(enums::CountryAlpha2::NL, |c| c)
449-
}),
450445
customer_details: Some(payments::CustomerDetails {
451446
customer_id: core_utils::get_or_generate_id("customer_id", &None, "cust_").ok(),
452447
name: Some(Secret::new("John Doe".to_string())),

openapi/openapi_spec.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9847,6 +9847,11 @@
98479847
"description": "Provide a reference to a stored payment method",
98489848
"example": "187282ab-40ef-47a9-9206-5099ba31e432",
98499849
"nullable": true
9850+
},
9851+
"profile_id": {
9852+
"type": "string",
9853+
"description": "The business profile to use for this payment, if not passed the default business profile\nassociated with the merchant account will be used.",
9854+
"nullable": true
98509855
}
98519856
}
98529857
},
@@ -9996,6 +10001,11 @@
999610001
"type": "string",
999710002
"description": "If there was an error while calling the connectors the code is received here",
999810003
"example": "E0001"
10004+
},
10005+
"profile_id": {
10006+
"type": "string",
10007+
"description": "The business profile that is associated with this payment",
10008+
"nullable": true
999910009
}
1000010010
}
1000110011
},

0 commit comments

Comments
 (0)