mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 17:19:15 +08:00
fix(router): Update request body for migrate-batch api (#6429)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -6,6 +6,8 @@ use cards::CardNumber;
|
|||||||
use common_utils::{
|
use common_utils::{
|
||||||
consts::SURCHARGE_PERCENTAGE_PRECISION_LENGTH,
|
consts::SURCHARGE_PERCENTAGE_PRECISION_LENGTH,
|
||||||
crypto::OptionalEncryptableName,
|
crypto::OptionalEncryptableName,
|
||||||
|
errors,
|
||||||
|
ext_traits::OptionExt,
|
||||||
id_type, link_utils, pii,
|
id_type, link_utils, pii,
|
||||||
types::{MinorUnit, Percentage, Surcharge},
|
types::{MinorUnit, Percentage, Surcharge},
|
||||||
};
|
};
|
||||||
@ -2065,16 +2067,16 @@ pub struct PaymentMethodRecord {
|
|||||||
pub email: Option<pii::Email>,
|
pub email: Option<pii::Email>,
|
||||||
pub phone: Option<masking::Secret<String>>,
|
pub phone: Option<masking::Secret<String>>,
|
||||||
pub phone_country_code: Option<String>,
|
pub phone_country_code: Option<String>,
|
||||||
pub merchant_id: id_type::MerchantId,
|
pub merchant_id: Option<id_type::MerchantId>,
|
||||||
pub payment_method: Option<api_enums::PaymentMethod>,
|
pub payment_method: Option<api_enums::PaymentMethod>,
|
||||||
pub payment_method_type: Option<api_enums::PaymentMethodType>,
|
pub payment_method_type: Option<api_enums::PaymentMethodType>,
|
||||||
pub nick_name: masking::Secret<String>,
|
pub nick_name: masking::Secret<String>,
|
||||||
pub payment_instrument_id: masking::Secret<String>,
|
pub payment_instrument_id: Option<masking::Secret<String>>,
|
||||||
pub card_number_masked: masking::Secret<String>,
|
pub card_number_masked: masking::Secret<String>,
|
||||||
pub card_expiry_month: masking::Secret<String>,
|
pub card_expiry_month: masking::Secret<String>,
|
||||||
pub card_expiry_year: masking::Secret<String>,
|
pub card_expiry_year: masking::Secret<String>,
|
||||||
pub card_scheme: Option<String>,
|
pub card_scheme: Option<String>,
|
||||||
pub original_transaction_id: String,
|
pub original_transaction_id: Option<String>,
|
||||||
pub billing_address_zip: masking::Secret<String>,
|
pub billing_address_zip: masking::Secret<String>,
|
||||||
pub billing_address_state: masking::Secret<String>,
|
pub billing_address_state: masking::Secret<String>,
|
||||||
pub billing_address_first_name: masking::Secret<String>,
|
pub billing_address_first_name: masking::Secret<String>,
|
||||||
@ -2085,7 +2087,7 @@ pub struct PaymentMethodRecord {
|
|||||||
pub billing_address_line2: Option<masking::Secret<String>>,
|
pub billing_address_line2: Option<masking::Secret<String>>,
|
||||||
pub billing_address_line3: Option<masking::Secret<String>>,
|
pub billing_address_line3: Option<masking::Secret<String>>,
|
||||||
pub raw_card_number: Option<masking::Secret<String>>,
|
pub raw_card_number: Option<masking::Secret<String>>,
|
||||||
pub merchant_connector_id: id_type::MerchantConnectorAccountId,
|
pub merchant_connector_id: Option<id_type::MerchantConnectorAccountId>,
|
||||||
pub original_transaction_amount: Option<i64>,
|
pub original_transaction_amount: Option<i64>,
|
||||||
pub original_transaction_currency: Option<common_enums::Currency>,
|
pub original_transaction_currency: Option<common_enums::Currency>,
|
||||||
pub line_number: Option<i64>,
|
pub line_number: Option<i64>,
|
||||||
@ -2171,31 +2173,54 @@ impl From<PaymentMethodMigrationResponseType> for PaymentMethodMigrationResponse
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<PaymentMethodRecord> for PaymentMethodMigrate {
|
impl
|
||||||
fn from(record: PaymentMethodRecord) -> Self {
|
TryFrom<(
|
||||||
let mut mandate_reference = HashMap::new();
|
PaymentMethodRecord,
|
||||||
mandate_reference.insert(
|
id_type::MerchantId,
|
||||||
record.merchant_connector_id,
|
Option<id_type::MerchantConnectorAccountId>,
|
||||||
|
)> for PaymentMethodMigrate
|
||||||
|
{
|
||||||
|
type Error = error_stack::Report<errors::ValidationError>;
|
||||||
|
fn try_from(
|
||||||
|
item: (
|
||||||
|
PaymentMethodRecord,
|
||||||
|
id_type::MerchantId,
|
||||||
|
Option<id_type::MerchantConnectorAccountId>,
|
||||||
|
),
|
||||||
|
) -> Result<Self, Self::Error> {
|
||||||
|
let (record, merchant_id, mca_id) = item;
|
||||||
|
|
||||||
|
// if payment instrument id is present then only construct this
|
||||||
|
let connector_mandate_details = if record.payment_instrument_id.is_some() {
|
||||||
|
Some(PaymentsMandateReference(HashMap::from([(
|
||||||
|
mca_id.get_required_value("merchant_connector_id")?,
|
||||||
PaymentsMandateReferenceRecord {
|
PaymentsMandateReferenceRecord {
|
||||||
connector_mandate_id: record.payment_instrument_id.peek().to_string(),
|
connector_mandate_id: record
|
||||||
|
.payment_instrument_id
|
||||||
|
.get_required_value("payment_instrument_id")?
|
||||||
|
.peek()
|
||||||
|
.to_string(),
|
||||||
payment_method_type: record.payment_method_type,
|
payment_method_type: record.payment_method_type,
|
||||||
original_payment_authorized_amount: record.original_transaction_amount,
|
original_payment_authorized_amount: record.original_transaction_amount,
|
||||||
original_payment_authorized_currency: record.original_transaction_currency,
|
original_payment_authorized_currency: record.original_transaction_currency,
|
||||||
},
|
},
|
||||||
);
|
)])))
|
||||||
Self {
|
} else {
|
||||||
merchant_id: record.merchant_id,
|
None
|
||||||
|
};
|
||||||
|
Ok(Self {
|
||||||
|
merchant_id,
|
||||||
customer_id: Some(record.customer_id),
|
customer_id: Some(record.customer_id),
|
||||||
card: Some(MigrateCardDetail {
|
card: Some(MigrateCardDetail {
|
||||||
card_number: record.raw_card_number.unwrap_or(record.card_number_masked),
|
card_number: record.raw_card_number.unwrap_or(record.card_number_masked),
|
||||||
card_exp_month: record.card_expiry_month,
|
card_exp_month: record.card_expiry_month,
|
||||||
card_exp_year: record.card_expiry_year,
|
card_exp_year: record.card_expiry_year,
|
||||||
card_holder_name: record.name,
|
card_holder_name: record.name.clone(),
|
||||||
card_network: None,
|
card_network: None,
|
||||||
card_type: None,
|
card_type: None,
|
||||||
card_issuer: None,
|
card_issuer: None,
|
||||||
card_issuing_country: None,
|
card_issuing_country: None,
|
||||||
nick_name: Some(record.nick_name),
|
nick_name: Some(record.nick_name.clone()),
|
||||||
}),
|
}),
|
||||||
payment_method: record.payment_method,
|
payment_method: record.payment_method,
|
||||||
payment_method_type: record.payment_method_type,
|
payment_method_type: record.payment_method_type,
|
||||||
@ -2218,7 +2243,7 @@ impl From<PaymentMethodRecord> for PaymentMethodMigrate {
|
|||||||
}),
|
}),
|
||||||
email: record.email,
|
email: record.email,
|
||||||
}),
|
}),
|
||||||
connector_mandate_details: Some(PaymentsMandateReference(mandate_reference)),
|
connector_mandate_details,
|
||||||
metadata: None,
|
metadata: None,
|
||||||
payment_method_issuer_code: None,
|
payment_method_issuer_code: None,
|
||||||
card_network: None,
|
card_network: None,
|
||||||
@ -2227,17 +2252,18 @@ impl From<PaymentMethodRecord> for PaymentMethodMigrate {
|
|||||||
#[cfg(feature = "payouts")]
|
#[cfg(feature = "payouts")]
|
||||||
wallet: None,
|
wallet: None,
|
||||||
payment_method_data: None,
|
payment_method_data: None,
|
||||||
network_transaction_id: record.original_transaction_id.into(),
|
network_transaction_id: record.original_transaction_id,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))]
|
#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))]
|
||||||
impl From<PaymentMethodRecord> for customers::CustomerRequest {
|
impl From<(PaymentMethodRecord, id_type::MerchantId)> for customers::CustomerRequest {
|
||||||
fn from(record: PaymentMethodRecord) -> Self {
|
fn from(value: (PaymentMethodRecord, id_type::MerchantId)) -> Self {
|
||||||
|
let (record, merchant_id) = value;
|
||||||
Self {
|
Self {
|
||||||
customer_id: Some(record.customer_id),
|
customer_id: Some(record.customer_id),
|
||||||
merchant_id: record.merchant_id,
|
merchant_id,
|
||||||
name: record.name,
|
name: record.name,
|
||||||
email: record.email,
|
email: record.email,
|
||||||
phone: record.phone,
|
phone: record.phone,
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use actix_multipart::form::{bytes::Bytes, MultipartForm};
|
use actix_multipart::form::{bytes::Bytes, text::Text, MultipartForm};
|
||||||
use api_models::payment_methods::{PaymentMethodMigrationResponse, PaymentMethodRecord};
|
use api_models::payment_methods::{PaymentMethodMigrationResponse, PaymentMethodRecord};
|
||||||
use csv::Reader;
|
use csv::Reader;
|
||||||
|
use error_stack::ResultExt;
|
||||||
use rdkafka::message::ToBytes;
|
use rdkafka::message::ToBytes;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -15,12 +16,32 @@ pub async fn migrate_payment_methods(
|
|||||||
merchant_id: &common_utils::id_type::MerchantId,
|
merchant_id: &common_utils::id_type::MerchantId,
|
||||||
merchant_account: &domain::MerchantAccount,
|
merchant_account: &domain::MerchantAccount,
|
||||||
key_store: &domain::MerchantKeyStore,
|
key_store: &domain::MerchantKeyStore,
|
||||||
|
mca_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
|
||||||
) -> errors::RouterResponse<Vec<PaymentMethodMigrationResponse>> {
|
) -> errors::RouterResponse<Vec<PaymentMethodMigrationResponse>> {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
for record in payment_methods {
|
for record in payment_methods {
|
||||||
|
let req = api::PaymentMethodMigrate::try_from((
|
||||||
|
record.clone(),
|
||||||
|
merchant_id.clone(),
|
||||||
|
mca_id.clone(),
|
||||||
|
))
|
||||||
|
.map_err(|err| errors::ApiErrorResponse::InvalidRequestData {
|
||||||
|
message: format!("error: {:?}", err),
|
||||||
|
})
|
||||||
|
.attach_printable("record deserialization failed");
|
||||||
|
match req {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(e) => {
|
||||||
|
result.push(PaymentMethodMigrationResponse::from((
|
||||||
|
Err(e.to_string()),
|
||||||
|
record,
|
||||||
|
)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
let res = migrate_payment_method(
|
let res = migrate_payment_method(
|
||||||
state.clone(),
|
state.clone(),
|
||||||
api::PaymentMethodMigrate::from(record.clone()),
|
req?,
|
||||||
merchant_id,
|
merchant_id,
|
||||||
merchant_account,
|
merchant_account,
|
||||||
key_store,
|
key_store,
|
||||||
@ -42,6 +63,10 @@ pub async fn migrate_payment_methods(
|
|||||||
pub struct PaymentMethodsMigrateForm {
|
pub struct PaymentMethodsMigrateForm {
|
||||||
#[multipart(limit = "1MB")]
|
#[multipart(limit = "1MB")]
|
||||||
pub file: Bytes,
|
pub file: Bytes,
|
||||||
|
|
||||||
|
pub merchant_id: Text<common_utils::id_type::MerchantId>,
|
||||||
|
|
||||||
|
pub merchant_connector_id: Text<Option<common_utils::id_type::MerchantConnectorAccountId>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_csv(data: &[u8]) -> csv::Result<Vec<PaymentMethodRecord>> {
|
fn parse_csv(data: &[u8]) -> csv::Result<Vec<PaymentMethodRecord>> {
|
||||||
@ -58,26 +83,19 @@ fn parse_csv(data: &[u8]) -> csv::Result<Vec<PaymentMethodRecord>> {
|
|||||||
}
|
}
|
||||||
pub fn get_payment_method_records(
|
pub fn get_payment_method_records(
|
||||||
form: PaymentMethodsMigrateForm,
|
form: PaymentMethodsMigrateForm,
|
||||||
) -> Result<(common_utils::id_type::MerchantId, Vec<PaymentMethodRecord>), errors::ApiErrorResponse>
|
) -> Result<
|
||||||
{
|
(
|
||||||
|
common_utils::id_type::MerchantId,
|
||||||
|
Vec<PaymentMethodRecord>,
|
||||||
|
Option<common_utils::id_type::MerchantConnectorAccountId>,
|
||||||
|
),
|
||||||
|
errors::ApiErrorResponse,
|
||||||
|
> {
|
||||||
match parse_csv(form.file.data.to_bytes()) {
|
match parse_csv(form.file.data.to_bytes()) {
|
||||||
Ok(records) => {
|
Ok(records) => {
|
||||||
if let Some(first_record) = records.first() {
|
let merchant_id = form.merchant_id.clone();
|
||||||
if records
|
let mca_id = form.merchant_connector_id.clone();
|
||||||
.iter()
|
Ok((merchant_id.clone(), records, mca_id))
|
||||||
.all(|merchant_id| merchant_id.merchant_id == first_record.merchant_id)
|
|
||||||
{
|
|
||||||
Ok((first_record.merchant_id.clone(), records))
|
|
||||||
} else {
|
|
||||||
Err(errors::ApiErrorResponse::PreconditionFailed {
|
|
||||||
message: "Only one merchant id can be updated at a time".to_string(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err(errors::ApiErrorResponse::PreconditionFailed {
|
|
||||||
message: "No records found".to_string(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(e) => Err(errors::ApiErrorResponse::PreconditionFailed {
|
Err(e) => Err(errors::ApiErrorResponse::PreconditionFailed {
|
||||||
message: e.to_string(),
|
message: e.to_string(),
|
||||||
|
|||||||
@ -331,8 +331,11 @@ pub async fn migrate_payment_methods(
|
|||||||
MultipartForm(form): MultipartForm<migration::PaymentMethodsMigrateForm>,
|
MultipartForm(form): MultipartForm<migration::PaymentMethodsMigrateForm>,
|
||||||
) -> HttpResponse {
|
) -> HttpResponse {
|
||||||
let flow = Flow::PaymentMethodsMigrate;
|
let flow = Flow::PaymentMethodsMigrate;
|
||||||
let (merchant_id, records) = match migration::get_payment_method_records(form) {
|
let (merchant_id, records, merchant_connector_id) =
|
||||||
Ok((merchant_id, records)) => (merchant_id, records),
|
match migration::get_payment_method_records(form) {
|
||||||
|
Ok((merchant_id, records, merchant_connector_id)) => {
|
||||||
|
(merchant_id, records, merchant_connector_id)
|
||||||
|
}
|
||||||
Err(e) => return api::log_and_return_error_response(e.into()),
|
Err(e) => return api::log_and_return_error_response(e.into()),
|
||||||
};
|
};
|
||||||
Box::pin(api::server_wrap(
|
Box::pin(api::server_wrap(
|
||||||
@ -342,6 +345,7 @@ pub async fn migrate_payment_methods(
|
|||||||
records,
|
records,
|
||||||
|state, _, req, _| {
|
|state, _, req, _| {
|
||||||
let merchant_id = merchant_id.clone();
|
let merchant_id = merchant_id.clone();
|
||||||
|
let merchant_connector_id = merchant_connector_id.clone();
|
||||||
async move {
|
async move {
|
||||||
let (key_store, merchant_account) =
|
let (key_store, merchant_account) =
|
||||||
get_merchant_account(&state, &merchant_id).await?;
|
get_merchant_account(&state, &merchant_id).await?;
|
||||||
@ -349,7 +353,7 @@ pub async fn migrate_payment_methods(
|
|||||||
customers::migrate_customers(
|
customers::migrate_customers(
|
||||||
state.clone(),
|
state.clone(),
|
||||||
req.iter()
|
req.iter()
|
||||||
.map(|e| CustomerRequest::from(e.clone()))
|
.map(|e| CustomerRequest::from((e.clone(), merchant_id.clone())))
|
||||||
.collect(),
|
.collect(),
|
||||||
merchant_account.clone(),
|
merchant_account.clone(),
|
||||||
key_store.clone(),
|
key_store.clone(),
|
||||||
@ -362,6 +366,7 @@ pub async fn migrate_payment_methods(
|
|||||||
&merchant_id,
|
&merchant_id,
|
||||||
&merchant_account,
|
&merchant_account,
|
||||||
&key_store,
|
&key_store,
|
||||||
|
merchant_connector_id,
|
||||||
))
|
))
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user