refactor: Mandate unification (#191)

This commit is contained in:
Nishant Joshi
2022-12-21 23:27:57 +05:30
committed by GitHub
parent 57366f3304
commit 939827da8f
3 changed files with 153 additions and 144 deletions

View File

@ -1,12 +1,15 @@
use error_stack::{report, ResultExt};
use router_env::{tracing, tracing::instrument};
use storage_models::enums as storage_enums;
use super::payments::helpers;
use crate::{
core::errors::{self, RouterResponse, StorageErrorExt},
db::StorageInterface,
routes::AppState,
services,
types::{
self,
api::{
customers,
mandates::{self, MandateResponseExt},
@ -79,3 +82,103 @@ pub async fn get_customer_mandates(
Ok(services::BachResponse::Json(response_vec))
}
}
pub async fn mandate_procedure<F, FData>(
state: &AppState,
mut resp: types::RouterData<F, FData, types::PaymentsResponseData>,
maybe_customer: &Option<storage::Customer>,
) -> errors::RouterResult<types::RouterData<F, FData, types::PaymentsResponseData>>
where
FData: MandateBehaviour,
{
match resp.request.get_mandate_id() {
Some(mandate_id) => {
let mandate = state
.store
.find_mandate_by_merchant_id_mandate_id(resp.merchant_id.as_ref(), mandate_id)
.await
.change_context(errors::ApiErrorResponse::MandateNotFound)?;
let mandate = match mandate.mandate_type {
storage_enums::MandateType::SingleUse => state
.store
.update_mandate_by_merchant_id_mandate_id(
&resp.merchant_id,
mandate_id,
storage::MandateUpdate::StatusUpdate {
mandate_status: storage_enums::MandateStatus::Revoked,
},
)
.await
.change_context(errors::ApiErrorResponse::MandateNotFound),
storage_enums::MandateType::MultiUse => state
.store
.update_mandate_by_merchant_id_mandate_id(
&resp.merchant_id,
mandate_id,
storage::MandateUpdate::CaptureAmountUpdate {
amount_captured: Some(
mandate.amount_captured.unwrap_or(0) + resp.request.get_amount(),
),
},
)
.await
.change_context(errors::ApiErrorResponse::MandateNotFound),
}?;
resp.payment_method_id = Some(mandate.payment_method_id);
}
None => {
if resp.request.get_setup_future_usage().is_some() {
let payment_method_id = helpers::call_payment_method(
state,
&resp.merchant_id,
Some(&resp.request.get_payment_method_data()),
Some(resp.payment_method),
maybe_customer,
)
.await?
.payment_method_id;
resp.payment_method_id = Some(payment_method_id.clone());
let mandate_reference = match resp.response.as_ref().ok() {
Some(types::PaymentsResponseData::TransactionResponse {
mandate_reference,
..
}) => mandate_reference.clone(),
_ => None,
};
if let Some(new_mandate_data) = helpers::generate_mandate(
resp.merchant_id.clone(),
resp.connector.clone(),
None,
maybe_customer,
payment_method_id,
mandate_reference,
) {
resp.request
.set_mandate_id(new_mandate_data.mandate_id.clone());
state
.store
.insert_mandate(new_mandate_data)
.await
.map_err(|err| {
err.to_duplicate_response(
errors::ApiErrorResponse::DuplicateRefundRequest,
)
})?;
};
}
}
}
Ok(resp)
}
pub trait MandateBehaviour {
fn get_amount(&self) -> i64;
fn get_setup_future_usage(&self) -> Option<storage_models::enums::FutureUsage>;
fn get_mandate_id(&self) -> Option<&String>;
fn set_mandate_id(&mut self, new_mandate_id: String);
fn get_payment_method_data(&self) -> api_models::payments::PaymentMethod;
}

View File

@ -1,11 +1,11 @@
use async_trait::async_trait;
use error_stack::ResultExt;
use super::{ConstructFlowSpecificData, Feature};
use crate::{
core::{
errors::{self, ConnectorErrorExt, RouterResult, StorageErrorExt},
payments::{self, helpers, transformers, PaymentData},
errors::{ConnectorErrorExt, RouterResult},
mandate,
payments::{self, transformers, PaymentData},
},
routes::AppState,
scheduler::metrics,
@ -91,7 +91,7 @@ impl PaymentsAuthorizeRouterData {
PaymentsAuthorizeData,
PaymentsResponseData,
> = connector.connector.get_connector_integration();
let mut resp = services::execute_connector_processing_step(
let resp = services::execute_connector_processing_step(
state,
connector_integration,
self,
@ -99,93 +99,28 @@ impl PaymentsAuthorizeRouterData {
)
.await
.map_err(|error| error.to_payment_failed_response())?;
match &self.request.mandate_id {
Some(mandate_id) => {
let mandate = state
.store
.find_mandate_by_merchant_id_mandate_id(
resp.merchant_id.as_ref(),
mandate_id,
)
.await
.change_context(errors::ApiErrorResponse::MandateNotFound)?;
let mandate = match mandate.mandate_type {
storage_enums::MandateType::SingleUse => state
.store
.update_mandate_by_merchant_id_mandate_id(
&resp.merchant_id,
mandate_id,
storage::MandateUpdate::StatusUpdate {
mandate_status: storage_enums::MandateStatus::Revoked,
},
)
.await
.change_context(errors::ApiErrorResponse::MandateNotFound),
storage_enums::MandateType::MultiUse => state
.store
.update_mandate_by_merchant_id_mandate_id(
&resp.merchant_id,
mandate_id,
storage::MandateUpdate::CaptureAmountUpdate {
amount_captured: Some(
mandate.amount_captured.unwrap_or(0)
+ self.request.amount,
),
},
)
.await
.change_context(errors::ApiErrorResponse::MandateNotFound),
}?;
resp.payment_method_id = Some(mandate.payment_method_id);
}
None => {
if self.request.setup_future_usage.is_some() {
let payment_method_id = helpers::call_payment_method(
state,
&self.merchant_id,
Some(&self.request.payment_method_data),
Some(self.payment_method),
maybe_customer,
)
.await?
.payment_method_id;
resp.payment_method_id = Some(payment_method_id.clone());
resp.payment_method_id = Some(payment_method_id.clone());
let mandate_reference = match resp.response.as_ref().ok() {
Some(types::PaymentsResponseData::TransactionResponse {
mandate_reference,
..
}) => mandate_reference.clone(),
_ => None,
};
if let Some(new_mandate_data) = helpers::generate_mandate(
self.merchant_id.clone(),
self.connector.clone(),
None,
maybe_customer,
payment_method_id,
mandate_reference,
) {
resp.request.mandate_id = Some(new_mandate_data.mandate_id.clone());
state.store.insert_mandate(new_mandate_data).await.map_err(
|err| {
err.to_duplicate_response(
errors::ApiErrorResponse::DuplicateRefundRequest,
)
},
)?;
};
}
}
}
Ok(resp)
Ok(mandate::mandate_procedure(state, resp, maybe_customer).await?)
}
_ => Ok(self.clone()),
}
}
}
impl mandate::MandateBehaviour for types::PaymentsAuthorizeData {
fn get_amount(&self) -> i64 {
self.amount
}
fn get_mandate_id(&self) -> Option<&String> {
self.mandate_id.as_ref()
}
fn get_payment_method_data(&self) -> api_models::payments::PaymentMethod {
self.payment_method_data.clone()
}
fn get_setup_future_usage(&self) -> Option<storage_models::enums::FutureUsage> {
self.setup_future_usage
}
fn set_mandate_id(&mut self, new_mandate_id: String) {
self.mandate_id = Some(new_mandate_id);
}
}

View File

@ -1,11 +1,11 @@
use async_trait::async_trait;
use error_stack::ResultExt;
use super::{ConstructFlowSpecificData, Feature};
use crate::{
core::{
errors::{self, ConnectorErrorExt, RouterResult, StorageErrorExt},
payments::{self, helpers, transformers, PaymentData},
errors::{ConnectorErrorExt, RouterResult},
mandate,
payments::{self, transformers, PaymentData},
},
routes::AppState,
services,
@ -74,7 +74,7 @@ impl types::VerifyRouterData {
types::VerifyRequestData,
types::PaymentsResponseData,
> = connector.connector.get_connector_integration();
let mut resp = services::execute_connector_processing_step(
let resp = services::execute_connector_processing_step(
state,
connector_integration,
self,
@ -82,60 +82,31 @@ impl types::VerifyRouterData {
)
.await
.map_err(|err| err.to_verify_failed_response())?;
match &self.request.mandate_id {
Some(mandate_id) => {
let mandate = state
.store
.find_mandate_by_merchant_id_mandate_id(&resp.merchant_id, mandate_id)
.await
.change_context(errors::ApiErrorResponse::MandateNotFound)?;
resp.payment_method_id = Some(mandate.payment_method_id);
}
None => {
if self.request.setup_future_usage.is_some() {
let payment_method_id = helpers::call_payment_method(
state,
&self.merchant_id,
Some(&self.request.payment_method_data),
Some(self.payment_method),
maybe_customer,
)
.await?
.payment_method_id;
resp.payment_method_id = Some(payment_method_id.clone());
let mandate_reference = match resp.response.as_ref().ok() {
Some(types::PaymentsResponseData::TransactionResponse {
mandate_reference,
..
}) => mandate_reference.clone(),
_ => None,
};
if let Some(new_mandate_data) = helpers::generate_mandate(
self.merchant_id.clone(),
self.connector.clone(),
self.request.setup_mandate_details.clone(),
maybe_customer,
payment_method_id,
mandate_reference,
) {
resp.request.mandate_id = Some(new_mandate_data.mandate_id.clone());
state.store.insert_mandate(new_mandate_data).await.map_err(
|err| {
err.to_duplicate_response(
errors::ApiErrorResponse::DuplicateMandate,
)
},
)?;
}
}
}
}
Ok(resp)
Ok(mandate::mandate_procedure(state, resp, maybe_customer).await?)
}
_ => Ok(self.clone()),
}
}
}
impl mandate::MandateBehaviour for types::VerifyRequestData {
fn get_amount(&self) -> i64 {
0
}
fn get_setup_future_usage(&self) -> Option<storage_models::enums::FutureUsage> {
self.setup_future_usage
}
fn get_mandate_id(&self) -> Option<&String> {
self.mandate_id.as_ref()
}
fn set_mandate_id(&mut self, new_mandate_id: String) {
self.mandate_id = Some(new_mandate_id);
}
fn get_payment_method_data(&self) -> api_models::payments::PaymentMethod {
self.payment_method_data.clone()
}
}