mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-10-31 10:06:32 +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
	 Prasunna Soppa
					Prasunna Soppa