Skip to content

Commit

Permalink
refactor: add mapping for ConnectorError in payouts flow (#2608)
Browse files Browse the repository at this point in the history
Co-authored-by: Kashif <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Kashif <[email protected]>
  • Loading branch information
4 people authored Nov 21, 2023
1 parent cfabfa6 commit 5c4e7c9
Show file tree
Hide file tree
Showing 96 changed files with 2,310 additions and 62 deletions.
2 changes: 1 addition & 1 deletion crates/api_models/src/payouts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ pub struct PayoutCreateResponse {
pub error_code: Option<String>,

/// The business profile that is associated with this payment
pub profile_id: Option<String>,
pub profile_id: String,
}

#[derive(Default, Debug, Clone, Deserialize, ToSchema)]
Expand Down
4 changes: 2 additions & 2 deletions crates/diesel_models/src/payout_attempt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub struct PayoutAttempt {
pub created_at: PrimitiveDateTime,
#[serde(with = "common_utils::custom_serde::iso8601")]
pub last_modified_at: PrimitiveDateTime,
pub profile_id: Option<String>,
pub profile_id: String,
pub merchant_connector_id: Option<String>,
}

Expand All @@ -51,7 +51,7 @@ impl Default for PayoutAttempt {
business_label: None,
created_at: now,
last_modified_at: now,
profile_id: None,
profile_id: String::default(),
merchant_connector_id: None,
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/diesel_models/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -755,7 +755,7 @@ diesel::table! {
created_at -> Timestamp,
last_modified_at -> Timestamp,
#[max_length = 64]
profile_id -> Nullable<Varchar>,
profile_id -> Varchar,
#[max_length = 32]
merchant_connector_id -> Nullable<Varchar>,
}
Expand Down
8 changes: 6 additions & 2 deletions crates/router/src/connector/adyen/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4010,8 +4010,12 @@ impl<F> TryFrom<&AdyenRouterData<&types::PayoutsRouterData<F>>> for AdyenPayoutC
iban: Some(b.iban),
tax_id: None,
},
_ => Err(errors::ConnectorError::NotSupported {
message: "Bank transfers via ACH or Bacs are not supported".to_string(),
payouts::BankPayout::Ach(..) => Err(errors::ConnectorError::NotSupported {
message: "Bank transfer via ACH is not supported".to_string(),
connector: "Adyen",
})?,
payouts::BankPayout::Bacs(..) => Err(errors::ConnectorError::NotSupported {
message: "Bank transfer via Bacs is not supported".to_string(),
connector: "Adyen",
})?,
};
Expand Down
5 changes: 5 additions & 0 deletions crates/router/src/core/errors/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,11 @@ impl<T> ConnectorErrorExt<T> for error_stack::Result<T, errors::ConnectorError>
field_names: field_names.to_vec(),
}
}
errors::ConnectorError::NotSupported { message, connector } => {
errors::ApiErrorResponse::NotSupported {
message: format!("{} by {}", message, connector),
}
}
_ => errors::ApiErrorResponse::InternalServerError,
};
err.change_context(error)
Expand Down
31 changes: 13 additions & 18 deletions crates/router/src/core/payouts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub struct PayoutData {
pub payout_attempt: storage::PayoutAttempt,
pub payout_method_data: Option<payouts::PayoutMethodData>,
pub merchant_connector_account: Option<payment_helpers::MerchantConnectorAccountType>,
pub profile_id: String,
}

// ********************************************** CORE FLOWS **********************************************
Expand Down Expand Up @@ -96,9 +97,7 @@ pub async fn payouts_create_core(
merchant_account: domain::MerchantAccount,
key_store: domain::MerchantKeyStore,
req: payouts::PayoutCreateRequest,
) -> RouterResponse<payouts::PayoutCreateResponse>
where
{
) -> RouterResponse<payouts::PayoutCreateResponse> {
// Form connector data
let connector_data = get_connector_data(
&state,
Expand All @@ -111,7 +110,7 @@ where
.await?;

// Validate create request
let (payout_id, payout_method_data) =
let (payout_id, payout_method_data, profile_id) =
validator::validate_create_request(&state, &merchant_account, &req, &key_store).await?;

// Create DB entries
Expand All @@ -121,6 +120,7 @@ where
&key_store,
&req,
&payout_id,
&profile_id,
&connector_data.connector_name,
payout_method_data.as_ref(),
)
Expand Down Expand Up @@ -561,18 +561,8 @@ pub async fn create_recipient(
let customer_details = payout_data.customer_details.to_owned();
let connector_name = connector_data.connector_name.to_string();

let profile_id = core_utils::get_profile_id_from_business_details(
payout_data.payout_attempt.business_country,
payout_data.payout_attempt.business_label.as_ref(),
merchant_account,
payout_data.payout_attempt.profile_id.as_ref(),
&*state.store,
false,
)
.await?;

// Create the connector label using {profile_id}_{connector_name}
let connector_label = format!("{profile_id}_{}", connector_name);
let connector_label = format!("{}_{}", payout_data.profile_id, connector_name);

let (should_call_connector, _connector_customer_id) =
helpers::should_call_payout_connector_create_customer(
Expand Down Expand Up @@ -1124,13 +1114,15 @@ pub async fn response_handler(
}

// DB entries
#[allow(clippy::too_many_arguments)]
#[cfg(feature = "payouts")]
pub async fn payout_create_db_entries(
state: &AppState,
merchant_account: &domain::MerchantAccount,
key_store: &domain::MerchantKeyStore,
req: &payouts::PayoutCreateRequest,
payout_id: &String,
profile_id: &String,
connector_name: &api_enums::PayoutConnectors,
stored_payout_method_data: Option<&payouts::PayoutMethodData>,
) -> RouterResult<PayoutData> {
Expand Down Expand Up @@ -1231,8 +1223,7 @@ pub async fn payout_create_db_entries(
} else {
storage_enums::PayoutStatus::RequiresPayoutMethodData
};
let _id = core_utils::get_or_generate_uuid("payout_attempt_id", None)?;
let payout_attempt_id = format!("{}_{}", merchant_id.to_owned(), payout_id.to_owned());
let payout_attempt_id = utils::get_payment_attempt_id(payout_id, 1);

let payout_attempt_req = storage::PayoutAttemptNew::default()
.set_payout_attempt_id(payout_attempt_id.to_string())
Expand All @@ -1247,7 +1238,7 @@ pub async fn payout_create_db_entries(
.set_payout_token(req.payout_token.to_owned())
.set_created_at(Some(common_utils::date_time::now()))
.set_last_modified_at(Some(common_utils::date_time::now()))
.set_profile_id(req.profile_id.to_owned())
.set_profile_id(Some(profile_id.to_string()))
.to_owned();
let payout_attempt = db
.insert_payout_attempt(payout_attempt_req)
Expand All @@ -1269,6 +1260,7 @@ pub async fn payout_create_db_entries(
.cloned()
.or(stored_payout_method_data.cloned()),
merchant_connector_account: None,
profile_id: profile_id.to_owned(),
})
}

Expand Down Expand Up @@ -1318,12 +1310,15 @@ pub async fn make_payout_data(
.await
.map_or(None, |c| c);

let profile_id = payout_attempt.profile_id.clone();

Ok(PayoutData {
billing_address,
customer_details,
payouts,
payout_attempt,
payout_method_data: None,
merchant_connector_account: None,
profile_id,
})
}
18 changes: 13 additions & 5 deletions crates/router/src/core/payouts/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use crate::{
utils as core_utils,
},
db::StorageInterface,
logger,
routes::AppState,
types::{api::payouts, domain, storage},
utils,
Expand All @@ -24,8 +23,6 @@ pub async fn validate_uniqueness_of_payout_id_against_merchant_id(
let payout = db
.find_payout_by_merchant_id_payout_id(merchant_id, payout_id)
.await;

logger::debug!(?payout);
match payout {
Err(err) => {
if err.current_context().is_db_not_found() {
Expand Down Expand Up @@ -58,7 +55,7 @@ pub async fn validate_create_request(
merchant_account: &domain::MerchantAccount,
req: &payouts::PayoutCreateRequest,
merchant_key_store: &domain::MerchantKeyStore,
) -> RouterResult<(String, Option<payouts::PayoutMethodData>)> {
) -> RouterResult<(String, Option<payouts::PayoutMethodData>, String)> {
let merchant_id = &merchant_account.merchant_id;

// Merchant ID
Expand Down Expand Up @@ -111,5 +108,16 @@ pub async fn validate_create_request(
None => None,
};

Ok((payout_id, payout_method_data))
// Profile ID
let profile_id = core_utils::get_profile_id_from_business_details(
req.business_country,
req.business_label.as_ref(),
merchant_account,
req.profile_id.as_ref(),
&*state.store,
false,
)
.await?;

Ok((payout_id, payout_method_data, profile_id))
}
26 changes: 7 additions & 19 deletions crates/router/src/core/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,33 +48,21 @@ pub async fn get_mca_for_payout<'a>(
merchant_account: &domain::MerchantAccount,
key_store: &domain::MerchantKeyStore,
payout_data: &PayoutData,
) -> RouterResult<(helpers::MerchantConnectorAccountType, String)> {
let payout_attempt = &payout_data.payout_attempt;
let profile_id = get_profile_id_from_business_details(
payout_attempt.business_country,
payout_attempt.business_label.as_ref(),
merchant_account,
payout_attempt.profile_id.as_ref(),
&*state.store,
false,
)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("profile_id is not set in payout_attempt")?;
) -> RouterResult<helpers::MerchantConnectorAccountType> {
match payout_data.merchant_connector_account.to_owned() {
Some(mca) => Ok((mca, profile_id)),
Some(mca) => Ok(mca),
None => {
let merchant_connector_account = helpers::get_merchant_connector_account(
state,
merchant_account.merchant_id.as_str(),
None,
key_store,
&profile_id,
&payout_data.profile_id,
connector_id,
payout_attempt.merchant_connector_id.as_ref(),
payout_data.payout_attempt.merchant_connector_id.as_ref(),
)
.await?;
Ok((merchant_connector_account, profile_id))
Ok(merchant_connector_account)
}
}
}
Expand All @@ -89,7 +77,7 @@ pub async fn construct_payout_router_data<'a, F>(
_request: &api_models::payouts::PayoutRequest,
payout_data: &mut PayoutData,
) -> RouterResult<types::PayoutsRouterData<F>> {
let (merchant_connector_account, profile_id) = get_mca_for_payout(
let merchant_connector_account = get_mca_for_payout(
state,
connector_id,
merchant_account,
Expand Down Expand Up @@ -135,7 +123,7 @@ pub async fn construct_payout_router_data<'a, F>(
let payouts = &payout_data.payouts;
let payout_attempt = &payout_data.payout_attempt;
let customer_details = &payout_data.customer_details;
let connector_label = format!("{profile_id}_{}", payout_attempt.connector);
let connector_label = format!("{}_{}", payout_data.profile_id, payout_attempt.connector);
let connector_customer_id = customer_details
.as_ref()
.and_then(|c| c.connector_customer.as_ref())
Expand Down
4 changes: 4 additions & 0 deletions migrations/2023-10-27-064512_alter_payout_profile_id/down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ALTER TABLE
payout_attempt
ALTER COLUMN
profile_id DROP NOT NULL;
6 changes: 6 additions & 0 deletions migrations/2023-10-27-064512_alter_payout_profile_id/up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
ALTER TABLE
payout_attempt
ALTER COLUMN
profile_id
SET
NOT NULL;
6 changes: 3 additions & 3 deletions openapi/openapi_spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -10570,7 +10570,8 @@
"entity_type",
"status",
"error_message",
"error_code"
"error_code",
"profile_id"
],
"properties": {
"payout_id": {
Expand Down Expand Up @@ -10702,8 +10703,7 @@
},
"profile_id": {
"type": "string",
"description": "The business profile that is associated with this payment",
"nullable": true
"description": "The business profile that is associated with this payment"
}
}
},
Expand Down
15 changes: 15 additions & 0 deletions postman/collection-dir/adyen_uk/.variable.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@
"key": "refund_id",
"value": ""
},
{
"key": "payout_id",
"value": "",
"type": "string"
},
{
"key": "merchant_connector_id",
"value": ""
Expand Down Expand Up @@ -90,6 +95,16 @@
"key": "connector_api_secret",
"value": "",
"type": "string"
},
{
"key": "payment_profile_id",
"value": "",
"type": "string"
},
{
"key": "payout_profile_id",
"value": "",
"type": "string"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@
"Scenario6-Create 3DS payment",
"Scenario7-Create 3DS payment with confrm false",
"Scenario9-Refund full payment",
"Scenario10-Partial refund",
"Scenario11-Create a mandate and recurring payment",
"Scenario11-Refund recurring payment",
"Scenario16-Bank Redirect-sofort",
"Scenario17-Bank Redirect-eps",
"Scenario18-Bank Redirect-giropay",
"Scenario19-Bank Redirect-Trustly",
"Scenario19-Bank debit-ach",
"Scenario19-Bank debit-Bacs"
"Scenario10-Create a mandate and recurring payment",
"Scenario11-Partial refund",
"Scenario12-Bank Redirect-sofort",
"Scenario13-Bank Redirect-eps",
"Scenario14-Refund recurring payment",
"Scenario15-Bank Redirect-giropay",
"Scenario16-Bank debit-ach",
"Scenario17-Bank debit-Bacs",
"Scenario18-Bank Redirect-Trustly",
"Scenario19-Add card flow",
"Scenario20-Pass Invalid CVV for save card flow and verify failed payment",
"Scenario21-Don't Pass CVV for save card flow and verify failed payment Copy"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
"Merchant Account - Create",
"API Key - Create",
"Payment Connector - Create",
"Payout Connector - Create",
"Payments - Create",
"Payments - Retrieve",
"Refunds - Create",
"Refunds - Retrieve"
"Refunds - Retrieve",
"Payouts - Create",
"Payouts - Retrieve"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
{
"country": "US",
"business": "default"
},
{
"country": "GB",
"business": "payouts"
}
],
"merchant_details": {
Expand Down
Loading

0 comments on commit 5c4e7c9

Please sign in to comment.