mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-02 12:06:56 +08:00
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
239 lines
7.6 KiB
Rust
239 lines
7.6 KiB
Rust
#[cfg(all(
|
|
any(feature = "v1", feature = "v2"),
|
|
not(feature = "payment_methods_v2")
|
|
))]
|
|
use api_models::enums as api_enums;
|
|
use api_models::locker_migration::MigrateCardResponse;
|
|
use common_utils::{errors::CustomResult, id_type};
|
|
#[cfg(all(
|
|
any(feature = "v1", feature = "v2"),
|
|
not(feature = "payment_methods_v2")
|
|
))]
|
|
use diesel_models::enums as storage_enums;
|
|
#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))]
|
|
use error_stack::FutureExt;
|
|
use error_stack::ResultExt;
|
|
#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))]
|
|
use futures::TryFutureExt;
|
|
|
|
#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))]
|
|
use super::errors::StorageErrorExt;
|
|
#[cfg(all(
|
|
any(feature = "v1", feature = "v2"),
|
|
not(feature = "payment_methods_v2")
|
|
))]
|
|
use super::payment_methods::cards;
|
|
#[cfg(all(
|
|
any(feature = "v1", feature = "v2"),
|
|
not(feature = "payment_methods_v2")
|
|
))]
|
|
use crate::services::logger;
|
|
#[cfg(all(
|
|
any(feature = "v1", feature = "v2"),
|
|
not(feature = "payment_methods_v2")
|
|
))]
|
|
use crate::types::api;
|
|
use crate::{errors, routes::SessionState, services, types::domain};
|
|
|
|
#[cfg(all(
|
|
feature = "v2",
|
|
feature = "customer_v2",
|
|
feature = "payment_methods_v2"
|
|
))]
|
|
pub async fn rust_locker_migration(
|
|
_state: SessionState,
|
|
_merchant_id: &id_type::MerchantId,
|
|
) -> CustomResult<services::ApplicationResponse<MigrateCardResponse>, errors::ApiErrorResponse> {
|
|
todo!()
|
|
}
|
|
|
|
#[cfg(all(
|
|
any(feature = "v1", feature = "v2"),
|
|
not(feature = "customer_v2"),
|
|
not(feature = "payment_methods_v2")
|
|
))]
|
|
pub async fn rust_locker_migration(
|
|
state: SessionState,
|
|
merchant_id: &id_type::MerchantId,
|
|
) -> CustomResult<services::ApplicationResponse<MigrateCardResponse>, errors::ApiErrorResponse> {
|
|
use crate::db::customers::CustomerListConstraints;
|
|
|
|
let db = state.store.as_ref();
|
|
let key_manager_state = &(&state).into();
|
|
let key_store = state
|
|
.store
|
|
.get_merchant_key_store_by_merchant_id(
|
|
key_manager_state,
|
|
merchant_id,
|
|
&state.store.get_master_key().to_vec().into(),
|
|
)
|
|
.await
|
|
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
|
|
|
let merchant_account = db
|
|
.find_merchant_account_by_merchant_id(key_manager_state, merchant_id, &key_store)
|
|
.await
|
|
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)
|
|
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
|
|
|
// Handle cases where the number of customers is greater than the limit
|
|
let constraints = CustomerListConstraints {
|
|
limit: u16::MAX,
|
|
offset: None,
|
|
};
|
|
|
|
let domain_customers = db
|
|
.list_customers_by_merchant_id(key_manager_state, merchant_id, &key_store, constraints)
|
|
.await
|
|
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
|
|
|
let mut customers_moved = 0;
|
|
let mut cards_moved = 0;
|
|
|
|
for customer in domain_customers {
|
|
let result = db
|
|
.find_payment_method_by_customer_id_merchant_id_list(
|
|
key_manager_state,
|
|
&key_store,
|
|
&customer.customer_id,
|
|
merchant_id,
|
|
None,
|
|
)
|
|
.change_context(errors::ApiErrorResponse::InternalServerError)
|
|
.and_then(|pm| {
|
|
call_to_locker(
|
|
&state,
|
|
pm,
|
|
&customer.customer_id,
|
|
merchant_id,
|
|
&merchant_account,
|
|
)
|
|
})
|
|
.await?;
|
|
|
|
customers_moved += 1;
|
|
cards_moved += result;
|
|
}
|
|
|
|
Ok(services::api::ApplicationResponse::Json(
|
|
MigrateCardResponse {
|
|
status_code: "200".to_string(),
|
|
status_message: "Card migration completed".to_string(),
|
|
customers_moved,
|
|
cards_moved,
|
|
},
|
|
))
|
|
}
|
|
|
|
#[cfg(all(
|
|
any(feature = "v1", feature = "v2"),
|
|
not(feature = "payment_methods_v2")
|
|
))]
|
|
pub async fn call_to_locker(
|
|
state: &SessionState,
|
|
payment_methods: Vec<domain::PaymentMethod>,
|
|
customer_id: &id_type::CustomerId,
|
|
merchant_id: &id_type::MerchantId,
|
|
merchant_account: &domain::MerchantAccount,
|
|
) -> CustomResult<usize, errors::ApiErrorResponse> {
|
|
let mut cards_moved = 0;
|
|
|
|
for pm in payment_methods
|
|
.into_iter()
|
|
.filter(|pm| matches!(pm.payment_method, Some(storage_enums::PaymentMethod::Card)))
|
|
{
|
|
let card = cards::get_card_from_locker(
|
|
state,
|
|
customer_id,
|
|
merchant_id,
|
|
pm.locker_id.as_ref().unwrap_or(&pm.payment_method_id),
|
|
)
|
|
.await;
|
|
|
|
let card = match card {
|
|
Ok(card) => card,
|
|
Err(err) => {
|
|
logger::error!("Failed to fetch card from Basilisk HS locker : {:?}", err);
|
|
continue;
|
|
}
|
|
};
|
|
|
|
let card_details = api::CardDetail {
|
|
card_number: card.card_number,
|
|
card_exp_month: card.card_exp_month,
|
|
card_exp_year: card.card_exp_year,
|
|
card_holder_name: card.name_on_card,
|
|
nick_name: card.nick_name.map(masking::Secret::new),
|
|
card_issuing_country: None,
|
|
card_network: None,
|
|
card_issuer: None,
|
|
card_type: None,
|
|
};
|
|
|
|
let pm_create = api::PaymentMethodCreate {
|
|
payment_method: pm.payment_method,
|
|
payment_method_type: pm.payment_method_type,
|
|
payment_method_issuer: pm.payment_method_issuer,
|
|
payment_method_issuer_code: pm.payment_method_issuer_code,
|
|
card: Some(card_details.clone()),
|
|
#[cfg(feature = "payouts")]
|
|
wallet: None,
|
|
#[cfg(feature = "payouts")]
|
|
bank_transfer: None,
|
|
metadata: pm.metadata,
|
|
customer_id: Some(pm.customer_id),
|
|
card_network: card.card_brand,
|
|
client_secret: None,
|
|
payment_method_data: None,
|
|
billing: None,
|
|
connector_mandate_details: None,
|
|
network_transaction_id: None,
|
|
};
|
|
|
|
let add_card_result = cards::add_card_hs(
|
|
state,
|
|
pm_create,
|
|
&card_details,
|
|
customer_id,
|
|
merchant_account,
|
|
api_enums::LockerChoice::HyperswitchCardVault,
|
|
Some(pm.locker_id.as_ref().unwrap_or(&pm.payment_method_id)),
|
|
|
|
)
|
|
.await
|
|
.change_context(errors::ApiErrorResponse::InternalServerError)
|
|
.attach_printable(format!(
|
|
"Card migration failed for merchant_id: {merchant_id:?}, customer_id: {customer_id:?}, payment_method_id: {} ",
|
|
pm.payment_method_id
|
|
));
|
|
|
|
let (_add_card_rs_resp, _is_duplicate) = match add_card_result {
|
|
Ok(output) => output,
|
|
Err(err) => {
|
|
logger::error!("Failed to add card to Rust locker : {:?}", err);
|
|
continue;
|
|
}
|
|
};
|
|
|
|
cards_moved += 1;
|
|
|
|
logger::info!(
|
|
"Card migrated for merchant_id: {merchant_id:?}, customer_id: {customer_id:?}, payment_method_id: {} ",
|
|
pm.payment_method_id
|
|
);
|
|
}
|
|
|
|
Ok(cards_moved)
|
|
}
|
|
|
|
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
|
|
pub async fn call_to_locker(
|
|
_state: &SessionState,
|
|
_payment_methods: Vec<domain::PaymentMethod>,
|
|
_customer_id: &id_type::CustomerId,
|
|
_merchant_id: &id_type::MerchantId,
|
|
_merchant_account: &domain::MerchantAccount,
|
|
) -> CustomResult<usize, errors::ApiErrorResponse> {
|
|
todo!()
|
|
}
|