mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-03 05:17:02 +08:00
feat(router): store network_reference_id against the payment_method_id in the payment_method_table (#4041)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -126,6 +126,10 @@ pub enum PaymentMethodUpdate {
|
|||||||
LastUsedUpdate {
|
LastUsedUpdate {
|
||||||
last_used_at: PrimitiveDateTime,
|
last_used_at: PrimitiveDateTime,
|
||||||
},
|
},
|
||||||
|
NetworkTransactionIdAndStatusUpdate {
|
||||||
|
network_transaction_id: Option<String>,
|
||||||
|
status: Option<storage_enums::PaymentMethodStatus>,
|
||||||
|
},
|
||||||
StatusUpdate {
|
StatusUpdate {
|
||||||
status: Option<storage_enums::PaymentMethodStatus>,
|
status: Option<storage_enums::PaymentMethodStatus>,
|
||||||
},
|
},
|
||||||
@ -140,6 +144,7 @@ pub struct PaymentMethodUpdateInternal {
|
|||||||
metadata: Option<serde_json::Value>,
|
metadata: Option<serde_json::Value>,
|
||||||
payment_method_data: Option<Encryption>,
|
payment_method_data: Option<Encryption>,
|
||||||
last_used_at: Option<PrimitiveDateTime>,
|
last_used_at: Option<PrimitiveDateTime>,
|
||||||
|
network_transaction_id: Option<String>,
|
||||||
status: Option<storage_enums::PaymentMethodStatus>,
|
status: Option<storage_enums::PaymentMethodStatus>,
|
||||||
connector_mandate_details: Option<serde_json::Value>,
|
connector_mandate_details: Option<serde_json::Value>,
|
||||||
}
|
}
|
||||||
@ -159,6 +164,7 @@ impl From<PaymentMethodUpdate> for PaymentMethodUpdateInternal {
|
|||||||
metadata,
|
metadata,
|
||||||
payment_method_data: None,
|
payment_method_data: None,
|
||||||
last_used_at: None,
|
last_used_at: None,
|
||||||
|
network_transaction_id: None,
|
||||||
status: None,
|
status: None,
|
||||||
connector_mandate_details: None,
|
connector_mandate_details: None,
|
||||||
},
|
},
|
||||||
@ -168,6 +174,7 @@ impl From<PaymentMethodUpdate> for PaymentMethodUpdateInternal {
|
|||||||
metadata: None,
|
metadata: None,
|
||||||
payment_method_data,
|
payment_method_data,
|
||||||
last_used_at: None,
|
last_used_at: None,
|
||||||
|
network_transaction_id: None,
|
||||||
status: None,
|
status: None,
|
||||||
connector_mandate_details: None,
|
connector_mandate_details: None,
|
||||||
},
|
},
|
||||||
@ -175,13 +182,26 @@ impl From<PaymentMethodUpdate> for PaymentMethodUpdateInternal {
|
|||||||
metadata: None,
|
metadata: None,
|
||||||
payment_method_data: None,
|
payment_method_data: None,
|
||||||
last_used_at: Some(last_used_at),
|
last_used_at: Some(last_used_at),
|
||||||
|
network_transaction_id: None,
|
||||||
status: None,
|
status: None,
|
||||||
connector_mandate_details: None,
|
connector_mandate_details: None,
|
||||||
},
|
},
|
||||||
|
PaymentMethodUpdate::NetworkTransactionIdAndStatusUpdate {
|
||||||
|
network_transaction_id,
|
||||||
|
status,
|
||||||
|
} => Self {
|
||||||
|
metadata: None,
|
||||||
|
payment_method_data: None,
|
||||||
|
last_used_at: None,
|
||||||
|
network_transaction_id,
|
||||||
|
status,
|
||||||
|
connector_mandate_details: None,
|
||||||
|
},
|
||||||
PaymentMethodUpdate::StatusUpdate { status } => Self {
|
PaymentMethodUpdate::StatusUpdate { status } => Self {
|
||||||
metadata: None,
|
metadata: None,
|
||||||
payment_method_data: None,
|
payment_method_data: None,
|
||||||
last_used_at: None,
|
last_used_at: None,
|
||||||
|
network_transaction_id: None,
|
||||||
status,
|
status,
|
||||||
connector_mandate_details: None,
|
connector_mandate_details: None,
|
||||||
},
|
},
|
||||||
@ -193,6 +213,7 @@ impl From<PaymentMethodUpdate> for PaymentMethodUpdateInternal {
|
|||||||
last_used_at: None,
|
last_used_at: None,
|
||||||
status: None,
|
status: None,
|
||||||
connector_mandate_details,
|
connector_mandate_details,
|
||||||
|
network_transaction_id: None,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2231,6 +2231,7 @@ impl Deref for PaymentIntentSyncResponse {
|
|||||||
pub struct StripeAdditionalCardDetails {
|
pub struct StripeAdditionalCardDetails {
|
||||||
checks: Option<Value>,
|
checks: Option<Value>,
|
||||||
three_d_secure: Option<Value>,
|
three_d_secure: Option<Value>,
|
||||||
|
network_transaction_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug, PartialEq, Eq, Serialize)]
|
#[derive(Deserialize, Clone, Debug, PartialEq, Eq, Serialize)]
|
||||||
@ -2685,12 +2686,24 @@ impl<F, T>
|
|||||||
item.response.id.clone(),
|
item.response.id.clone(),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
|
let network_transaction_id = match item.response.latest_attempt {
|
||||||
|
Some(LatestAttempt::PaymentIntentAttempt(attempt)) => attempt
|
||||||
|
.payment_method_details
|
||||||
|
.and_then(|payment_method_details| match payment_method_details {
|
||||||
|
StripePaymentMethodDetailsResponse::Card { card } => {
|
||||||
|
card.network_transaction_id
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
Ok(types::PaymentsResponseData::TransactionResponse {
|
Ok(types::PaymentsResponseData::TransactionResponse {
|
||||||
resource_id: types::ResponseId::ConnectorTransactionId(item.response.id.clone()),
|
resource_id: types::ResponseId::ConnectorTransactionId(item.response.id.clone()),
|
||||||
redirection_data,
|
redirection_data,
|
||||||
mandate_reference,
|
mandate_reference,
|
||||||
connector_metadata: None,
|
connector_metadata: None,
|
||||||
network_txn_id: Option::foreign_from(item.response.latest_attempt),
|
network_txn_id: network_transaction_id,
|
||||||
connector_response_reference_id: Some(item.response.id),
|
connector_response_reference_id: Some(item.response.id),
|
||||||
incremental_authorization_allowed: None,
|
incremental_authorization_allowed: None,
|
||||||
})
|
})
|
||||||
@ -3140,6 +3153,7 @@ pub struct LatestPaymentAttempt {
|
|||||||
pub payment_method_options: Option<StripePaymentMethodOptions>,
|
pub payment_method_options: Option<StripePaymentMethodOptions>,
|
||||||
pub payment_method_details: Option<StripePaymentMethodDetailsResponse>,
|
pub payment_method_details: Option<StripePaymentMethodDetailsResponse>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
|
// #[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
|
||||||
// pub struct Card
|
// pub struct Card
|
||||||
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, Default, Eq, PartialEq)]
|
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, Default, Eq, PartialEq)]
|
||||||
|
|||||||
@ -87,6 +87,7 @@ pub async fn create_payment_method(
|
|||||||
payment_method_data: Option<Encryption>,
|
payment_method_data: Option<Encryption>,
|
||||||
key_store: &domain::MerchantKeyStore,
|
key_store: &domain::MerchantKeyStore,
|
||||||
connector_mandate_details: Option<serde_json::Value>,
|
connector_mandate_details: Option<serde_json::Value>,
|
||||||
|
network_transaction_id: Option<String>,
|
||||||
) -> errors::CustomResult<storage::PaymentMethod, errors::ApiErrorResponse> {
|
) -> errors::CustomResult<storage::PaymentMethod, errors::ApiErrorResponse> {
|
||||||
let customer = db
|
let customer = db
|
||||||
.find_customer_by_customer_id_merchant_id(customer_id, merchant_id, key_store)
|
.find_customer_by_customer_id_merchant_id(customer_id, merchant_id, key_store)
|
||||||
@ -107,6 +108,7 @@ pub async fn create_payment_method(
|
|||||||
payment_method_data,
|
payment_method_data,
|
||||||
connector_mandate_details,
|
connector_mandate_details,
|
||||||
customer_acceptance: customer_acceptance.map(masking::Secret::new),
|
customer_acceptance: customer_acceptance.map(masking::Secret::new),
|
||||||
|
network_transaction_id: network_transaction_id.to_owned(),
|
||||||
..storage::PaymentMethodNew::default()
|
..storage::PaymentMethodNew::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
@ -205,6 +207,7 @@ pub async fn get_or_insert_payment_method(
|
|||||||
None,
|
None,
|
||||||
locker_id,
|
locker_id,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
} else {
|
} else {
|
||||||
@ -392,6 +395,7 @@ pub async fn add_payment_method(
|
|||||||
None,
|
None,
|
||||||
locker_id,
|
locker_id,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
@ -412,6 +416,7 @@ pub async fn insert_payment_method(
|
|||||||
customer_acceptance: Option<serde_json::Value>,
|
customer_acceptance: Option<serde_json::Value>,
|
||||||
locker_id: Option<String>,
|
locker_id: Option<String>,
|
||||||
connector_mandate_details: Option<serde_json::Value>,
|
connector_mandate_details: Option<serde_json::Value>,
|
||||||
|
network_transaction_id: Option<String>,
|
||||||
) -> errors::RouterResult<diesel_models::PaymentMethod> {
|
) -> errors::RouterResult<diesel_models::PaymentMethod> {
|
||||||
let pm_card_details = resp
|
let pm_card_details = resp
|
||||||
.card
|
.card
|
||||||
@ -430,6 +435,7 @@ pub async fn insert_payment_method(
|
|||||||
pm_data_encrypted,
|
pm_data_encrypted,
|
||||||
key_store,
|
key_store,
|
||||||
connector_mandate_details,
|
connector_mandate_details,
|
||||||
|
network_transaction_id,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ use data_models::payments::payment_attempt::PaymentAttempt;
|
|||||||
use error_stack::{report, ResultExt};
|
use error_stack::{report, ResultExt};
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use router_derive;
|
use router_derive;
|
||||||
use router_env::{instrument, tracing};
|
use router_env::{instrument, logger, tracing};
|
||||||
use storage_impl::DataModelExt;
|
use storage_impl::DataModelExt;
|
||||||
use tracing_futures::Instrument;
|
use tracing_futures::Instrument;
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ use crate::{
|
|||||||
self, api,
|
self, api,
|
||||||
storage::{self, enums},
|
storage::{self, enums},
|
||||||
transformers::{ForeignFrom, ForeignTryFrom},
|
transformers::{ForeignFrom, ForeignTryFrom},
|
||||||
CaptureSyncResponse,
|
CaptureSyncResponse, ErrorResponse,
|
||||||
},
|
},
|
||||||
utils,
|
utils,
|
||||||
};
|
};
|
||||||
@ -833,7 +833,7 @@ async fn payment_response_update_tracker<F: Clone, T: types::Capturable>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let amount_captured = get_total_amount_captured(
|
let amount_captured = get_total_amount_captured(
|
||||||
router_data.request,
|
&router_data.request,
|
||||||
router_data.amount_captured,
|
router_data.amount_captured,
|
||||||
router_data.status,
|
router_data.status,
|
||||||
&payment_data,
|
&payment_data,
|
||||||
@ -862,7 +862,13 @@ async fn payment_response_update_tracker<F: Clone, T: types::Capturable>(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
update_payment_method_status(state, &mut payment_data, router_data.status).await?;
|
update_payment_method_status_and_ntid(
|
||||||
|
state,
|
||||||
|
&mut payment_data,
|
||||||
|
router_data.status,
|
||||||
|
router_data.response.clone(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
let m_db = state.clone().store;
|
let m_db = state.clone().store;
|
||||||
let m_payment_data_payment_intent = payment_data.payment_intent.clone();
|
let m_payment_data_payment_intent = payment_data.payment_intent.clone();
|
||||||
let m_payment_intent_update = payment_intent_update.clone();
|
let m_payment_intent_update = payment_intent_update.clone();
|
||||||
@ -954,10 +960,11 @@ async fn payment_response_update_tracker<F: Clone, T: types::Capturable>(
|
|||||||
Ok(payment_data)
|
Ok(payment_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn update_payment_method_status<F: Clone>(
|
async fn update_payment_method_status_and_ntid<F: Clone>(
|
||||||
state: &AppState,
|
state: &AppState,
|
||||||
payment_data: &mut PaymentData<F>,
|
payment_data: &mut PaymentData<F>,
|
||||||
attempt_status: common_enums::AttemptStatus,
|
attempt_status: common_enums::AttemptStatus,
|
||||||
|
payment_response: Result<types::PaymentsResponseData, ErrorResponse>,
|
||||||
) -> RouterResult<()> {
|
) -> RouterResult<()> {
|
||||||
if let Some(id) = &payment_data.payment_attempt.payment_method_id {
|
if let Some(id) = &payment_data.payment_attempt.payment_method_id {
|
||||||
let pm = state
|
let pm = state
|
||||||
@ -965,8 +972,20 @@ async fn update_payment_method_status<F: Clone>(
|
|||||||
.find_payment_method(id)
|
.find_payment_method(id)
|
||||||
.await
|
.await
|
||||||
.to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?;
|
.to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?;
|
||||||
|
let network_transaction_id = payment_response
|
||||||
|
.map(|resp| match resp {
|
||||||
|
crate::types::PaymentsResponseData::TransactionResponse { network_txn_id, .. } => {
|
||||||
|
network_txn_id.to_owned()
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map_err(|err| {
|
||||||
|
logger::error!(error=?err, "Failed to obtain the network_transaction_id from payment response");
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
.flatten();
|
||||||
|
|
||||||
if pm.status != common_enums::PaymentMethodStatus::Active
|
let pm_update = if pm.status != common_enums::PaymentMethodStatus::Active
|
||||||
&& pm.status != attempt_status.into()
|
&& pm.status != attempt_status.into()
|
||||||
{
|
{
|
||||||
let updated_pm_status = common_enums::PaymentMethodStatus::from(attempt_status);
|
let updated_pm_status = common_enums::PaymentMethodStatus::from(attempt_status);
|
||||||
@ -975,16 +994,23 @@ async fn update_payment_method_status<F: Clone>(
|
|||||||
.payment_method_info
|
.payment_method_info
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.map(|info| info.status = updated_pm_status);
|
.map(|info| info.status = updated_pm_status);
|
||||||
let pm_update = storage::PaymentMethodUpdate::StatusUpdate {
|
storage::PaymentMethodUpdate::NetworkTransactionIdAndStatusUpdate {
|
||||||
|
network_transaction_id,
|
||||||
status: Some(updated_pm_status),
|
status: Some(updated_pm_status),
|
||||||
};
|
}
|
||||||
state
|
} else {
|
||||||
.store
|
storage::PaymentMethodUpdate::NetworkTransactionIdAndStatusUpdate {
|
||||||
.update_payment_method(pm, pm_update)
|
network_transaction_id,
|
||||||
.await
|
status: None,
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
}
|
||||||
.attach_printable("Failed to update payment method in db")?;
|
};
|
||||||
}
|
|
||||||
|
state
|
||||||
|
.store
|
||||||
|
.update_payment_method(pm, pm_update)
|
||||||
|
.await
|
||||||
|
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Failed to update payment method in db")?;
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -1043,7 +1069,7 @@ fn get_capture_update_for_unmapped_capture_responses(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_total_amount_captured<F: Clone, T: types::Capturable>(
|
fn get_total_amount_captured<F: Clone, T: types::Capturable>(
|
||||||
request: T,
|
request: &T,
|
||||||
amount_captured: Option<i64>,
|
amount_captured: Option<i64>,
|
||||||
router_data_status: enums::AttemptStatus,
|
router_data_status: enums::AttemptStatus,
|
||||||
payment_data: &PaymentData<F>,
|
payment_data: &PaymentData<F>,
|
||||||
|
|||||||
@ -399,6 +399,18 @@ async fn get_tracker_for_sync<
|
|||||||
.to_not_found_response(errors::ApiErrorResponse::BusinessProfileNotFound {
|
.to_not_found_response(errors::ApiErrorResponse::BusinessProfileNotFound {
|
||||||
id: profile_id.to_string(),
|
id: profile_id.to_string(),
|
||||||
})?;
|
})?;
|
||||||
|
let payment_method_info =
|
||||||
|
if let Some(ref payment_method_id) = payment_attempt.payment_method_id.clone() {
|
||||||
|
Some(
|
||||||
|
db.find_payment_method(payment_method_id)
|
||||||
|
.await
|
||||||
|
.to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)
|
||||||
|
.attach_printable("error retrieving payment method from DB")?,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let merchant_id = payment_intent.merchant_id.clone();
|
let merchant_id = payment_intent.merchant_id.clone();
|
||||||
let authentication = payment_attempt.authentication_id.clone().async_map(|authentication_id| async move {
|
let authentication = payment_attempt.authentication_id.clone().async_map(|authentication_id| async move {
|
||||||
db.find_authentication_by_merchant_id_authentication_id(
|
db.find_authentication_by_merchant_id_authentication_id(
|
||||||
@ -436,7 +448,7 @@ async fn get_tracker_for_sync<
|
|||||||
token_data: None,
|
token_data: None,
|
||||||
confirm: Some(request.force_sync),
|
confirm: Some(request.force_sync),
|
||||||
payment_method_data: None,
|
payment_method_data: None,
|
||||||
payment_method_info: None,
|
payment_method_info,
|
||||||
force_sync: Some(
|
force_sync: Some(
|
||||||
request.force_sync
|
request.force_sync
|
||||||
&& (helpers::check_force_psync_precondition(&payment_attempt.status)
|
&& (helpers::check_force_psync_precondition(&payment_attempt.status)
|
||||||
|
|||||||
@ -57,6 +57,13 @@ where
|
|||||||
.map(|token_filter| token_filter.long_lived_token)
|
.map(|token_filter| token_filter.long_lived_token)
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
let network_transaction_id = match responses.clone() {
|
||||||
|
types::PaymentsResponseData::TransactionResponse { network_txn_id, .. } => {
|
||||||
|
network_txn_id
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
let connector_token = if token_store {
|
let connector_token = if token_store {
|
||||||
let tokens = resp
|
let tokens = resp
|
||||||
.payment_method_token
|
.payment_method_token
|
||||||
@ -255,6 +262,7 @@ where
|
|||||||
pm_data_encrypted,
|
pm_data_encrypted,
|
||||||
key_store,
|
key_store,
|
||||||
connector_mandate_details,
|
connector_mandate_details,
|
||||||
|
network_transaction_id,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
} else {
|
} else {
|
||||||
@ -337,6 +345,7 @@ where
|
|||||||
customer_acceptance,
|
customer_acceptance,
|
||||||
locker_id,
|
locker_id,
|
||||||
connector_mandate_details,
|
connector_mandate_details,
|
||||||
|
network_transaction_id,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
} else {
|
} else {
|
||||||
@ -459,6 +468,7 @@ where
|
|||||||
pm_data_encrypted,
|
pm_data_encrypted,
|
||||||
key_store,
|
key_store,
|
||||||
connector_mandate_details,
|
connector_mandate_details,
|
||||||
|
network_transaction_id,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,8 +13,8 @@ use crate::{
|
|||||||
core::{
|
core::{
|
||||||
errors::{self, RouterResult},
|
errors::{self, RouterResult},
|
||||||
payment_methods::{
|
payment_methods::{
|
||||||
cards, transformers,
|
cards,
|
||||||
transformers::{StoreCardReq, StoreGenericReq, StoreLockerReq},
|
transformers::{self, StoreCardReq, StoreGenericReq, StoreLockerReq},
|
||||||
vault,
|
vault,
|
||||||
},
|
},
|
||||||
payments::{
|
payments::{
|
||||||
@ -389,6 +389,7 @@ pub async fn save_payout_data_to_locker(
|
|||||||
card_details_encrypted,
|
card_details_encrypted,
|
||||||
key_store,
|
key_store,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user