feat(router): use payment confirm for confirmed payments in payments create and update (#165)

Co-authored-by: Arun Raj M <jarnura47@gmail.com>
This commit is contained in:
ItsMeShashank
2022-12-21 14:36:37 +05:30
committed by GitHub
parent 60d1ad52b1
commit 47741b47fa
5 changed files with 62 additions and 18 deletions

View File

@ -482,6 +482,7 @@ pub struct CustomerDetails {
pub fn if_not_create_change_operation<'a, Op, F>( pub fn if_not_create_change_operation<'a, Op, F>(
is_update: bool, is_update: bool,
status: storage_enums::IntentStatus, status: storage_enums::IntentStatus,
confirm: Option<bool>,
current: &'a Op, current: &'a Op,
) -> BoxedOperation<F, api::PaymentsRequest> ) -> BoxedOperation<F, api::PaymentsRequest>
where where
@ -489,6 +490,9 @@ where
Op: Operation<F, api::PaymentsRequest> + Send + Sync, Op: Operation<F, api::PaymentsRequest> + Send + Sync,
&'a Op: Operation<F, api::PaymentsRequest>, &'a Op: Operation<F, api::PaymentsRequest>,
{ {
if confirm.unwrap_or(false) {
Box::new(PaymentConfirm)
} else {
match status { match status {
storage_enums::IntentStatus::RequiresConfirmation storage_enums::IntentStatus::RequiresConfirmation
| storage_enums::IntentStatus::RequiresCustomerAction | storage_enums::IntentStatus::RequiresCustomerAction
@ -501,6 +505,7 @@ where
} }
_ => Box::new(&PaymentStatus), _ => Box::new(&PaymentStatus),
} }
}
} }
pub fn is_confirm<'a, F: Clone + Send, R, Op>( pub fn is_confirm<'a, F: Clone + Send, R, Op>(

View File

@ -257,7 +257,7 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
db: &dyn StorageInterface, db: &dyn StorageInterface,
_payment_id: &api::PaymentIdType, _payment_id: &api::PaymentIdType,
mut payment_data: PaymentData<F>, mut payment_data: PaymentData<F>,
_customer: Option<storage::Customer>, customer: Option<storage::Customer>,
storage_scheme: enums::MerchantStorageScheme, storage_scheme: enums::MerchantStorageScheme,
) -> RouterResult<(BoxedOperation<'b, F, api::PaymentsRequest>, PaymentData<F>)> ) -> RouterResult<(BoxedOperation<'b, F, api::PaymentsRequest>, PaymentData<F>)>
where where
@ -285,8 +285,11 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
.update_payment_attempt( .update_payment_attempt(
payment_data.payment_attempt, payment_data.payment_attempt,
storage::PaymentAttemptUpdate::ConfirmUpdate { storage::PaymentAttemptUpdate::ConfirmUpdate {
amount: payment_data.amount.into(),
currency: payment_data.currency,
status: attempt_status, status: attempt_status,
payment_method, payment_method,
authentication_type: None,
browser_info, browser_info,
connector, connector,
payment_token, payment_token,
@ -303,11 +306,16 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
payment_data.payment_intent.billing_address_id.clone(), payment_data.payment_intent.billing_address_id.clone(),
); );
let customer_id = customer.map(|c| c.customer_id);
payment_data.payment_intent = db payment_data.payment_intent = db
.update_payment_intent( .update_payment_intent(
payment_data.payment_intent, payment_data.payment_intent,
storage::PaymentIntentUpdate::MerchantStatusUpdate { storage::PaymentIntentUpdate::Update {
amount: payment_data.amount.into(),
currency: payment_data.currency,
status: intent_status, status: intent_status,
customer_id,
shipping_address_id: shipping_address, shipping_address_id: shipping_address,
billing_address_id: billing_address, billing_address_id: billing_address,
}, },

View File

@ -185,6 +185,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
let operation = payments::if_not_create_change_operation::<_, F>( let operation = payments::if_not_create_change_operation::<_, F>(
is_update, is_update,
payment_intent.status, payment_intent.status,
request.confirm,
self, self,
); );
@ -280,10 +281,10 @@ impl<F: Clone + Send> Domain<F, api::PaymentsRequest> for PaymentCreate {
#[instrument(skip_all)] #[instrument(skip_all)]
async fn add_task_to_process_tracker<'a>( async fn add_task_to_process_tracker<'a>(
&'a self, &'a self,
state: &'a AppState, _state: &'a AppState,
payment_attempt: &storage::PaymentAttempt, _payment_attempt: &storage::PaymentAttempt,
) -> CustomResult<(), errors::ApiErrorResponse> { ) -> CustomResult<(), errors::ApiErrorResponse> {
helpers::add_domain_task_to_pt(self, state, payment_attempt).await Ok(())
} }
async fn get_connector<'a>( async fn get_connector<'a>(
@ -388,6 +389,13 @@ impl<F: Send + Clone> ValidateRequest<F, api::PaymentsRequest> for PaymentCreate
None => None, None => None,
}; };
if let Some(true) = request.confirm {
helpers::validate_pm_or_token_given(
&request.payment_token,
&request.payment_method_data,
)?;
}
let request_merchant_id = request.merchant_id.as_deref(); let request_merchant_id = request.merchant_id.as_deref();
helpers::validate_merchant_id(&merchant_account.merchant_id, request_merchant_id) helpers::validate_merchant_id(&merchant_account.merchant_id, request_merchant_id)
.change_context(errors::ApiErrorResponse::MerchantAccountNotFound)?; .change_context(errors::ApiErrorResponse::MerchantAccountNotFound)?;

View File

@ -126,6 +126,13 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
.attach_printable("Database error when finding connector response") .attach_printable("Database error when finding connector response")
})?; })?;
let next_operation: BoxedOperation<'a, F, api::PaymentsRequest> =
if request.confirm.unwrap_or(false) {
Box::new(operations::PaymentConfirm)
} else {
Box::new(self)
};
match payment_intent.status { match payment_intent.status {
enums::IntentStatus::Succeeded | enums::IntentStatus::Failed => { enums::IntentStatus::Succeeded | enums::IntentStatus::Failed => {
Err(report!(errors::ApiErrorResponse::PreconditionFailed { Err(report!(errors::ApiErrorResponse::PreconditionFailed {
@ -135,7 +142,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
})) }))
} }
_ => Ok(( _ => Ok((
Box::new(self), next_operation,
PaymentData { PaymentData {
flow: PhantomData, flow: PhantomData,
payment_intent, payment_intent,
@ -227,10 +234,10 @@ impl<F: Clone + Send> Domain<F, api::PaymentsRequest> for PaymentUpdate {
#[instrument(skip_all)] #[instrument(skip_all)]
async fn add_task_to_process_tracker<'a>( async fn add_task_to_process_tracker<'a>(
&'a self, &'a self,
state: &'a AppState, _state: &'a AppState,
payment_attempt: &storage::PaymentAttempt, _payment_attempt: &storage::PaymentAttempt,
) -> CustomResult<(), errors::ApiErrorResponse> { ) -> CustomResult<(), errors::ApiErrorResponse> {
helpers::add_domain_task_to_pt(self, state, payment_attempt).await Ok(())
} }
async fn get_connector<'a>( async fn get_connector<'a>(
@ -352,6 +359,13 @@ impl<F: Send + Clone> ValidateRequest<F, api::PaymentsRequest> for PaymentUpdate
None => None, None => None,
}; };
if let Some(true) = request.confirm {
helpers::validate_pm_or_token_given(
&request.payment_token,
&request.payment_method_data,
)?;
}
let request_merchant_id = request.merchant_id.as_deref(); let request_merchant_id = request.merchant_id.as_deref();
helpers::validate_merchant_id(&merchant_account.merchant_id, request_merchant_id) helpers::validate_merchant_id(&merchant_account.merchant_id, request_merchant_id)
.change_context(errors::ApiErrorResponse::InvalidDataFormat { .change_context(errors::ApiErrorResponse::InvalidDataFormat {

View File

@ -95,7 +95,10 @@ pub enum PaymentAttemptUpdate {
authentication_type: storage_enums::AuthenticationType, authentication_type: storage_enums::AuthenticationType,
}, },
ConfirmUpdate { ConfirmUpdate {
amount: i64,
currency: storage_enums::Currency,
status: storage_enums::AttemptStatus, status: storage_enums::AttemptStatus,
authentication_type: Option<storage_enums::AuthenticationType>,
payment_method: Option<storage_enums::PaymentMethodType>, payment_method: Option<storage_enums::PaymentMethodType>,
browser_info: Option<serde_json::Value>, browser_info: Option<serde_json::Value>,
connector: Option<String>, connector: Option<String>,
@ -199,12 +202,18 @@ impl From<PaymentAttemptUpdate> for PaymentAttemptUpdateInternal {
..Default::default() ..Default::default()
}, },
PaymentAttemptUpdate::ConfirmUpdate { PaymentAttemptUpdate::ConfirmUpdate {
amount,
currency,
authentication_type,
status, status,
payment_method, payment_method,
browser_info, browser_info,
connector, connector,
payment_token, payment_token,
} => Self { } => Self {
amount: Some(amount),
currency: Some(currency),
authentication_type,
status: Some(status), status: Some(status),
payment_method, payment_method,
modified_at: Some(common_utils::date_time::now()), modified_at: Some(common_utils::date_time::now()),