mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +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