feat: ACH transfers (#905)

This commit is contained in:
Sangamesh Kulkarni
2023-05-19 15:14:29 +05:30
committed by GitHub
parent 39405bb478
commit 23bca66b81
39 changed files with 1247 additions and 66 deletions

View File

@ -6,7 +6,7 @@ pub mod operations;
pub mod tokenization;
pub mod transformers;
use std::{fmt::Debug, marker::PhantomData, time::Instant};
use std::{fmt::Debug, marker::PhantomData, ops::Deref, time::Instant};
use api_models::payments::Metadata;
use common_utils::pii::Email;
@ -143,10 +143,12 @@ where
.await?;
if let Some(connector_details) = connector {
operation
.to_domain()?
.add_task_to_process_tracker(state, &payment_data.payment_attempt)
.await?;
if should_add_task_to_process_tracker(&payment_data)? {
operation
.to_domain()?
.add_task_to_process_tracker(state, &payment_data.payment_attempt)
.await?;
}
payment_data = match connector_details {
api::ConnectorCallType::Single(connector) => {
@ -188,8 +190,7 @@ where
.await?
}
};
if payment_data.payment_intent.status != storage_enums::IntentStatus::RequiresCustomerAction
{
if should_delete_pm_from_locker(payment_data.payment_intent.status) {
vault::Vault::delete_locker_payment_method_by_lookup_key(state, &payment_data.token)
.await
}
@ -499,7 +500,7 @@ where
.add_access_token(state, &connector, merchant_account)
.await?;
let should_continue_payment = access_token::update_router_data_with_access_token_result(
let mut should_continue_payment = access_token::update_router_data_with_access_token_result(
&add_access_token_result,
&mut router_data,
&call_connector_action,
@ -513,6 +514,15 @@ where
router_data.payment_method_token = Some(payment_method_token);
};
(router_data, should_continue_payment) = complete_preprocessing_steps_if_required(
state,
&connector,
payment_data,
router_data,
should_continue_payment,
)
.await?;
let router_data_res = if should_continue_payment {
router_data
.decide_flows(
@ -665,6 +675,39 @@ where
}
}
async fn complete_preprocessing_steps_if_required<F, Req, Res>(
state: &AppState,
connector: &api::ConnectorData,
payment_data: &PaymentData<F>,
router_data: types::RouterData<F, Req, Res>,
should_continue_payment: bool,
) -> RouterResult<(types::RouterData<F, Req, Res>, bool)>
where
F: Send + Clone + Sync,
Req: Send + Sync,
types::RouterData<F, Req, Res>: Feature<F, Req> + Send,
dyn api::Connector: services::api::ConnectorIntegration<F, Req, types::PaymentsResponseData>,
{
//TODO: For ACH transfers, if preprocessing_step is not required for connectors encountered in future, add the check
let router_data_and_should_continue_payment = match payment_data.payment_method_data.clone() {
Some(api_models::payments::PaymentMethodData::BankTransfer(data)) => match data.deref() {
api_models::payments::BankTransferData::AchBankTransfer(_) => {
if payment_data.payment_attempt.preprocessing_step_id.is_none() {
(
router_data.preprocessing_steps(state, connector).await?,
false,
)
} else {
(router_data, should_continue_payment)
}
}
},
_ => (router_data, should_continue_payment),
};
Ok(router_data_and_should_continue_payment)
}
fn is_payment_method_tokenization_enabled_for_connector(
state: &AppState,
connector_name: &str,
@ -979,6 +1022,13 @@ pub fn should_call_connector<Op: Debug, F: Clone>(
}
}
pub fn should_delete_pm_from_locker(status: storage_enums::IntentStatus) -> bool {
!matches!(
status,
storage_models::enums::IntentStatus::RequiresCustomerAction
)
}
pub fn is_operation_confirm<Op: Debug>(operation: &Op) -> bool {
matches!(format!("{operation:?}").as_str(), "PaymentConfirm")
}
@ -1259,3 +1309,23 @@ pub fn decide_connector(
Ok(api::ConnectorCallType::Single(connector_data))
}
pub fn should_add_task_to_process_tracker<F: Clone>(
payment_data: &PaymentData<F>,
) -> RouterResult<bool> {
let pm = payment_data
.payment_attempt
.payment_method
.get_required_value("payment_method")?;
let connector = payment_data
.payment_attempt
.connector
.clone()
.get_required_value("connector")?;
let add_task_check = if matches!(pm, storage_enums::PaymentMethod::BankTransfer) {
!connector.eq("stripe")
} else {
true
};
Ok(add_task_check)
}