mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-11-01 02:57:02 +08:00 
			
		
		
		
	feat(core): [CYBERSOURCE] Add original authorized amount in router data (#3417)
Co-authored-by: Samraat Bansal <samraat.bansal@juspay.in> Co-authored-by: SamraatBansal <55536657+SamraatBansal@users.noreply.github.com>
This commit is contained in:
		| @ -442,7 +442,7 @@ pub struct ClientRiskInformationRules { | ||||
| #[serde(rename_all = "camelCase")] | ||||
| pub struct Avs { | ||||
|     code: String, | ||||
|     code_raw: String, | ||||
|     code_raw: Option<String>, | ||||
| } | ||||
|  | ||||
| impl | ||||
|  | ||||
| @ -10,7 +10,7 @@ use crate::{ | ||||
|     connector::utils::{ | ||||
|         self, AddressDetailsData, ApplePayDecrypt, CardData, PaymentsAuthorizeRequestData, | ||||
|         PaymentsCompleteAuthorizeRequestData, PaymentsPreProcessingData, | ||||
|         PaymentsSetupMandateRequestData, PaymentsSyncRequestData, RouterData, | ||||
|         PaymentsSetupMandateRequestData, PaymentsSyncRequestData, RecurringMandateData, RouterData, | ||||
|     }, | ||||
|     consts, | ||||
|     core::errors, | ||||
| @ -47,6 +47,7 @@ impl<T> | ||||
|             T, | ||||
|         ), | ||||
|     ) -> Result<Self, Self::Error> { | ||||
|         // This conversion function is used at different places in the file, if updating this, keep a check for those | ||||
|         let amount = utils::get_amount_as_string(currency_unit, amount, currency)?; | ||||
|         Ok(Self { | ||||
|             amount, | ||||
| @ -81,11 +82,11 @@ impl TryFrom<&types::SetupMandateRouterData> for CybersourceZeroMandateRequest { | ||||
|             Some(vec![CybersourceActionsList::TokenCreate]), | ||||
|             Some(vec![CybersourceActionsTokenType::PaymentInstrument]), | ||||
|             Some(CybersourceAuthorizationOptions { | ||||
|                 initiator: CybersourcePaymentInitiator { | ||||
|                 initiator: Some(CybersourcePaymentInitiator { | ||||
|                     initiator_type: Some(CybersourcePaymentInitiatorTypes::Customer), | ||||
|                     credential_stored_on_file: Some(true), | ||||
|                     stored_credential_used: None, | ||||
|                 }, | ||||
|                 }), | ||||
|                 merchant_intitiated_transaction: None, | ||||
|             }), | ||||
|         ); | ||||
| @ -272,14 +273,16 @@ pub enum CybersourceActionsTokenType { | ||||
| #[derive(Debug, Serialize)] | ||||
| #[serde(rename_all = "camelCase")] | ||||
| pub struct CybersourceAuthorizationOptions { | ||||
|     initiator: CybersourcePaymentInitiator, | ||||
|     initiator: Option<CybersourcePaymentInitiator>, | ||||
|     merchant_intitiated_transaction: Option<MerchantInitiatedTransaction>, | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Serialize)] | ||||
| #[serde(rename_all = "camelCase")] | ||||
| pub struct MerchantInitiatedTransaction { | ||||
|     reason: String, | ||||
|     reason: Option<String>, | ||||
|     //Required for recurring mandates payment | ||||
|     original_authorized_amount: Option<String>, | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Serialize)] | ||||
| @ -470,35 +473,60 @@ impl From<&CybersourceRouterData<&types::PaymentsCompleteAuthorizeRouterData>> | ||||
| } | ||||
|  | ||||
| impl | ||||
|     From<( | ||||
|     TryFrom<( | ||||
|         &CybersourceRouterData<&types::PaymentsAuthorizeRouterData>, | ||||
|         Option<PaymentSolution>, | ||||
|     )> for ProcessingInformation | ||||
| { | ||||
|     fn from( | ||||
|     type Error = error_stack::Report<errors::ConnectorError>; | ||||
|     fn try_from( | ||||
|         (item, solution): ( | ||||
|             &CybersourceRouterData<&types::PaymentsAuthorizeRouterData>, | ||||
|             Option<PaymentSolution>, | ||||
|         ), | ||||
|     ) -> Self { | ||||
|     ) -> Result<Self, Self::Error> { | ||||
|         let (action_list, action_token_types, authorization_options) = | ||||
|             if item.router_data.request.setup_mandate_details.is_some() { | ||||
|                 ( | ||||
|                     Some(vec![CybersourceActionsList::TokenCreate]), | ||||
|                     Some(vec![CybersourceActionsTokenType::PaymentInstrument]), | ||||
|                     Some(CybersourceAuthorizationOptions { | ||||
|                         initiator: CybersourcePaymentInitiator { | ||||
|                         initiator: Some(CybersourcePaymentInitiator { | ||||
|                             initiator_type: Some(CybersourcePaymentInitiatorTypes::Customer), | ||||
|                             credential_stored_on_file: Some(true), | ||||
|                             stored_credential_used: None, | ||||
|                         }, | ||||
|                         }), | ||||
|                         merchant_intitiated_transaction: None, | ||||
|                     }), | ||||
|                 ) | ||||
|             } else if item.router_data.request.connector_mandate_id().is_some() { | ||||
|                 let original_amount = item | ||||
|                     .router_data | ||||
|                     .get_recurring_mandate_payment_data()? | ||||
|                     .get_original_payment_amount()?; | ||||
|                 let original_currency = item | ||||
|                     .router_data | ||||
|                     .get_recurring_mandate_payment_data()? | ||||
|                     .get_original_payment_currency()?; | ||||
|                 ( | ||||
|                     None, | ||||
|                     None, | ||||
|                     Some(CybersourceAuthorizationOptions { | ||||
|                         initiator: None, | ||||
|                         merchant_intitiated_transaction: Some(MerchantInitiatedTransaction { | ||||
|                             reason: None, | ||||
|                             original_authorized_amount: Some(utils::get_amount_as_string( | ||||
|                                 &types::api::CurrencyUnit::Base, | ||||
|                                 original_amount, | ||||
|                                 original_currency, | ||||
|                             )?), | ||||
|                         }), | ||||
|                     }), | ||||
|                 ) | ||||
|             } else { | ||||
|                 (None, None, None) | ||||
|             }; | ||||
|         Self { | ||||
|         Ok(Self { | ||||
|             capture: Some(matches!( | ||||
|                 item.router_data.request.capture_method, | ||||
|                 Some(enums::CaptureMethod::Automatic) | None | ||||
| @ -509,7 +537,7 @@ impl | ||||
|             authorization_options, | ||||
|             capture_options: None, | ||||
|             commerce_indicator: String::from("internet"), | ||||
|         } | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -533,11 +561,11 @@ impl | ||||
|                     Some(vec![CybersourceActionsList::TokenCreate]), | ||||
|                     Some(vec![CybersourceActionsTokenType::PaymentInstrument]), | ||||
|                     Some(CybersourceAuthorizationOptions { | ||||
|                         initiator: CybersourcePaymentInitiator { | ||||
|                         initiator: Some(CybersourcePaymentInitiator { | ||||
|                             initiator_type: Some(CybersourcePaymentInitiatorTypes::Customer), | ||||
|                             credential_stored_on_file: Some(true), | ||||
|                             stored_credential_used: None, | ||||
|                         }, | ||||
|                         }), | ||||
|                         merchant_intitiated_transaction: None, | ||||
|                     }), | ||||
|                 ) | ||||
| @ -680,7 +708,7 @@ impl | ||||
|             }, | ||||
|         }); | ||||
|  | ||||
|         let processing_information = ProcessingInformation::from((item, None)); | ||||
|         let processing_information = ProcessingInformation::try_from((item, None))?; | ||||
|         let client_reference_information = ClientReferenceInformation::from(item); | ||||
|         let merchant_defined_information = | ||||
|             item.router_data.request.metadata.clone().map(|metadata| { | ||||
| @ -792,7 +820,7 @@ impl | ||||
|         let bill_to = build_bill_to(item.router_data.get_billing()?, email)?; | ||||
|         let order_information = OrderInformationWithBill::from((item, bill_to)); | ||||
|         let processing_information = | ||||
|             ProcessingInformation::from((item, Some(PaymentSolution::ApplePay))); | ||||
|             ProcessingInformation::try_from((item, Some(PaymentSolution::ApplePay)))?; | ||||
|         let client_reference_information = ClientReferenceInformation::from(item); | ||||
|         let expiration_month = apple_pay_data.get_expiry_month()?; | ||||
|         let expiration_year = apple_pay_data.get_four_digit_expiry_year()?; | ||||
| @ -846,7 +874,7 @@ impl | ||||
|             }, | ||||
|         }); | ||||
|         let processing_information = | ||||
|             ProcessingInformation::from((item, Some(PaymentSolution::GooglePay))); | ||||
|             ProcessingInformation::try_from((item, Some(PaymentSolution::GooglePay)))?; | ||||
|         let client_reference_information = ClientReferenceInformation::from(item); | ||||
|         let merchant_defined_information = | ||||
|             item.router_data.request.metadata.clone().map(|metadata| { | ||||
| @ -893,10 +921,9 @@ impl TryFrom<&CybersourceRouterData<&types::PaymentsAuthorizeRouterData>> | ||||
|                                         build_bill_to(item.router_data.get_billing()?, email)?; | ||||
|                                     let order_information = | ||||
|                                         OrderInformationWithBill::from((item, bill_to)); | ||||
|                                     let processing_information = ProcessingInformation::from(( | ||||
|                                         item, | ||||
|                                         Some(PaymentSolution::ApplePay), | ||||
|                                     )); | ||||
|                                     let processing_information = ProcessingInformation::try_from( | ||||
|                                         (item, Some(PaymentSolution::ApplePay)), | ||||
|                                     )?; | ||||
|                                     let client_reference_information = | ||||
|                                         ClientReferenceInformation::from(item); | ||||
|                                     let payment_information = PaymentInformation::ApplePayToken( | ||||
| @ -1008,7 +1035,7 @@ impl | ||||
|             String, | ||||
|         ), | ||||
|     ) -> Result<Self, Self::Error> { | ||||
|         let processing_information = ProcessingInformation::from((item, None)); | ||||
|         let processing_information = ProcessingInformation::try_from((item, None))?; | ||||
|         let payment_instrument = CybersoucrePaymentInstrument { | ||||
|             id: connector_mandate_id, | ||||
|         }; | ||||
| @ -1159,13 +1186,14 @@ impl TryFrom<&CybersourceRouterData<&types::PaymentsIncrementalAuthorizationRout | ||||
|                 action_list: None, | ||||
|                 action_token_types: None, | ||||
|                 authorization_options: Some(CybersourceAuthorizationOptions { | ||||
|                     initiator: CybersourcePaymentInitiator { | ||||
|                     initiator: Some(CybersourcePaymentInitiator { | ||||
|                         initiator_type: None, | ||||
|                         credential_stored_on_file: None, | ||||
|                         stored_credential_used: Some(true), | ||||
|                     }, | ||||
|                     }), | ||||
|                     merchant_intitiated_transaction: Some(MerchantInitiatedTransaction { | ||||
|                         reason: "5".to_owned(), | ||||
|                         reason: Some("5".to_owned()), | ||||
|                         original_authorized_amount: None, | ||||
|                     }), | ||||
|                 }), | ||||
|                 commerce_indicator: String::from("internet"), | ||||
| @ -1339,18 +1367,6 @@ impl From<CybersourceIncrementalAuthorizationStatus> for common_enums::Authoriza | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<CybersourcePaymentStatus> for enums::RefundStatus { | ||||
|     fn from(item: CybersourcePaymentStatus) -> Self { | ||||
|         match item { | ||||
|             CybersourcePaymentStatus::Succeeded | CybersourcePaymentStatus::Transmitted => { | ||||
|                 Self::Success | ||||
|             } | ||||
|             CybersourcePaymentStatus::Failed => Self::Failure, | ||||
|             _ => Self::Pending, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Deserialize)] | ||||
| #[serde(untagged)] | ||||
| pub enum CybersourcePaymentsResponse { | ||||
| @ -1430,7 +1446,7 @@ pub struct ClientProcessorInformation { | ||||
| #[serde(rename_all = "camelCase")] | ||||
| pub struct Avs { | ||||
|     code: String, | ||||
|     code_raw: String, | ||||
|     code_raw: Option<String>, | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Clone, Deserialize)] | ||||
|  | ||||
| @ -25,7 +25,7 @@ use crate::{ | ||||
|     consts, | ||||
|     core::{ | ||||
|         errors::{self, ApiErrorResponse, CustomResult}, | ||||
|         payments::PaymentData, | ||||
|         payments::{PaymentData, RecurringMandatePaymentData}, | ||||
|     }, | ||||
|     pii::PeekInterface, | ||||
|     types::{ | ||||
| @ -81,6 +81,7 @@ pub trait RouterData { | ||||
|     fn get_customer_id(&self) -> Result<String, Error>; | ||||
|     fn get_connector_customer_id(&self) -> Result<String, Error>; | ||||
|     fn get_preprocessing_id(&self) -> Result<String, Error>; | ||||
|     fn get_recurring_mandate_payment_data(&self) -> Result<RecurringMandatePaymentData, Error>; | ||||
|     #[cfg(feature = "payouts")] | ||||
|     fn get_payout_method_data(&self) -> Result<api::PayoutMethodData, Error>; | ||||
|     #[cfg(feature = "payouts")] | ||||
| @ -250,6 +251,12 @@ impl<Flow, Request, Response> RouterData for types::RouterData<Flow, Request, Re | ||||
|             .to_owned() | ||||
|             .ok_or_else(missing_field_err("preprocessing_id")) | ||||
|     } | ||||
|     fn get_recurring_mandate_payment_data(&self) -> Result<RecurringMandatePaymentData, Error> { | ||||
|         self.recurring_mandate_payment_data | ||||
|             .to_owned() | ||||
|             .ok_or_else(missing_field_err("recurring_mandate_payment_data")) | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "payouts")] | ||||
|     fn get_payout_method_data(&self) -> Result<api::PayoutMethodData, Error> { | ||||
|         self.payout_method_data | ||||
| @ -1133,6 +1140,22 @@ impl MandateData for payments::MandateAmountData { | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub trait RecurringMandateData { | ||||
|     fn get_original_payment_amount(&self) -> Result<i64, Error>; | ||||
|     fn get_original_payment_currency(&self) -> Result<diesel_models::enums::Currency, Error>; | ||||
| } | ||||
|  | ||||
| impl RecurringMandateData for RecurringMandatePaymentData { | ||||
|     fn get_original_payment_amount(&self) -> Result<i64, Error> { | ||||
|         self.original_payment_authorized_amount | ||||
|             .ok_or_else(missing_field_err("original_payment_authorized_amount")) | ||||
|     } | ||||
|     fn get_original_payment_currency(&self) -> Result<diesel_models::enums::Currency, Error> { | ||||
|         self.original_payment_authorized_currency | ||||
|             .ok_or_else(missing_field_err("original_payment_authorized_currency")) | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub trait MandateReferenceData { | ||||
|     fn get_connector_mandate_id(&self) -> Result<String, Error>; | ||||
| } | ||||
|  | ||||
| @ -2039,6 +2039,8 @@ pub struct IncrementalAuthorizationDetails { | ||||
| #[derive(Debug, Default, Clone)] | ||||
| pub struct RecurringMandatePaymentData { | ||||
|     pub payment_method_type: Option<storage_enums::PaymentMethodType>, //required for making recurring payment using saved payment method through stripe | ||||
|     pub original_payment_authorized_amount: Option<i64>, | ||||
|     pub original_payment_authorized_currency: Option<storage_enums::Currency>, | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Default, Clone)] | ||||
|  | ||||
| @ -479,6 +479,27 @@ pub async fn get_token_for_recurring_mandate( | ||||
|         .await | ||||
|         .to_not_found_response(errors::ApiErrorResponse::MandateNotFound)?; | ||||
|  | ||||
|     let original_payment_intent = mandate | ||||
|         .original_payment_id | ||||
|         .as_ref() | ||||
|         .async_map(|payment_id| async { | ||||
|             db.find_payment_intent_by_payment_id_merchant_id( | ||||
|                 payment_id, | ||||
|                 &mandate.merchant_id, | ||||
|                 merchant_account.storage_scheme, | ||||
|             ) | ||||
|             .await | ||||
|             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound) | ||||
|             .map_err(|err| logger::error!(mandate_original_payment_not_found=?err)) | ||||
|             .ok() | ||||
|         }) | ||||
|         .await | ||||
|         .flatten(); | ||||
|  | ||||
|     let original_payment_authorized_amount = original_payment_intent.clone().map(|pi| pi.amount); | ||||
|     let original_payment_authorized_currency = | ||||
|         original_payment_intent.clone().and_then(|pi| pi.currency); | ||||
|  | ||||
|     let customer = req.customer_id.clone().get_required_value("customer_id")?; | ||||
|  | ||||
|     let payment_method_id = { | ||||
| @ -540,6 +561,8 @@ pub async fn get_token_for_recurring_mandate( | ||||
|             Some(payment_method.payment_method), | ||||
|             Some(payments::RecurringMandatePaymentData { | ||||
|                 payment_method_type, | ||||
|                 original_payment_authorized_amount, | ||||
|                 original_payment_authorized_currency, | ||||
|             }), | ||||
|             payment_method.payment_method_type, | ||||
|             Some(mandate_connector_details), | ||||
| @ -550,6 +573,8 @@ pub async fn get_token_for_recurring_mandate( | ||||
|             Some(payment_method.payment_method), | ||||
|             Some(payments::RecurringMandatePaymentData { | ||||
|                 payment_method_type, | ||||
|                 original_payment_authorized_amount, | ||||
|                 original_payment_authorized_currency, | ||||
|             }), | ||||
|             payment_method.payment_method_type, | ||||
|             Some(mandate_connector_details), | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 DEEPANSHU BANSAL
					DEEPANSHU BANSAL