feat(router): Added amount conversion function in core for connector module (#4710)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
Co-authored-by: Hrithikesh <61539176+hrithikesh026@users.noreply.github.com>
Co-authored-by: Narayan Bhat <narayan.bhat@juspay.in>
This commit is contained in:
Sahkal Poddar
2024-05-30 19:21:33 +05:30
committed by GitHub
parent f7e99e1eda
commit 08eefdba4a
30 changed files with 577 additions and 150 deletions

View File

@ -219,6 +219,8 @@ pub enum ConnectorError {
},
#[error("Invalid Configuration")]
InvalidConnectorConfig { config: &'static str },
#[error("Failed to convert amount to required type")]
AmountConversionFailed,
}
#[derive(Debug, thiserror::Error)]

View File

@ -215,7 +215,8 @@ impl<T> ConnectorErrorExt<T> for error_stack::Result<T, errors::ConnectorError>
| errors::ConnectorError::InSufficientBalanceInPaymentMethod
| errors::ConnectorError::RequestTimeoutReceived
| errors::ConnectorError::CurrencyNotSupported { .. }
| errors::ConnectorError::InvalidConnectorConfig { .. } => {
| errors::ConnectorError::InvalidConnectorConfig { .. }
| errors::ConnectorError::AmountConversionFailed { .. } => {
err.change_context(errors::ApiErrorResponse::RefundFailed { data: None })
}
})
@ -309,7 +310,8 @@ impl<T> ConnectorErrorExt<T> for error_stack::Result<T, errors::ConnectorError>
errors::ConnectorError::MissingPaymentMethodType |
errors::ConnectorError::InSufficientBalanceInPaymentMethod |
errors::ConnectorError::RequestTimeoutReceived |
errors::ConnectorError::ProcessingStepFailed(None) => errors::ApiErrorResponse::InternalServerError
errors::ConnectorError::ProcessingStepFailed(None)|
errors::ConnectorError::AmountConversionFailed => errors::ApiErrorResponse::InternalServerError
};
err.change_context(error)
})
@ -399,7 +401,8 @@ impl<T> ConnectorErrorExt<T> for error_stack::Result<T, errors::ConnectorError>
| errors::ConnectorError::InSufficientBalanceInPaymentMethod
| errors::ConnectorError::RequestTimeoutReceived
| errors::ConnectorError::CurrencyNotSupported { .. }
| errors::ConnectorError::ProcessingStepFailed(None) => {
| errors::ConnectorError::ProcessingStepFailed(None)
| errors::ConnectorError::AmountConversionFailed { .. } => {
logger::error!(%error,"Setup Mandate flow failed");
errors::ApiErrorResponse::PaymentAuthorizationFailed { data: None }
}

View File

@ -1260,6 +1260,7 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsAuthoriz
statement_descriptor: payment_data.payment_intent.statement_descriptor_name,
capture_method: payment_data.payment_attempt.capture_method,
amount: amount.get_amount_as_i64(),
minor_amount: amount,
currency: payment_data.currency,
browser_info,
email: payment_data.email,
@ -1420,12 +1421,14 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsCaptureD
let amount = MinorUnit::from(payment_data.amount);
Ok(Self {
amount_to_capture: amount_to_capture.get_amount_as_i64(), // This should be removed once we start moving to connector module
minor_amount_to_capture: amount_to_capture,
currency: payment_data.currency,
connector_transaction_id: connector
.connector
.connector_transaction_id(payment_data.payment_attempt.clone())?
.ok_or(errors::ApiErrorResponse::ResourceIdNotFound)?,
payment_amount: amount.get_amount_as_i64(), // This should be removed once we start moving to connector module
minor_payment_amount: amount,
connector_meta: payment_data.payment_attempt.connector_metadata,
multiple_capture_data: match payment_data.multiple_capture_data {
Some(multiple_capture_data) => Some(MultipleCaptureRequestData {
@ -1702,6 +1705,7 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::CompleteAuthoriz
statement_descriptor_suffix: payment_data.payment_intent.statement_descriptor_suffix,
capture_method: payment_data.payment_attempt.capture_method,
amount: amount.get_amount_as_i64(), // need to change once we move to connector module
minor_amount: amount,
currency: payment_data.currency,
browser_info,
email: payment_data.email,

View File

@ -5,7 +5,10 @@ use std::collections::HashMap;
#[cfg(feature = "olap")]
use api_models::admin::MerchantConnectorInfo;
use common_utils::ext_traits::{AsyncExt, ValueExt};
use common_utils::{
ext_traits::{AsyncExt, ValueExt},
types::MinorUnit,
};
use error_stack::{report, ResultExt};
use masking::PeekInterface;
use router_env::{instrument, tracing};
@ -75,14 +78,12 @@ pub async fn refund_create_core(
// Amount is not passed in request refer from payment intent.
amount = req
.amount
.or(payment_intent
.amount_captured
.map(|capture_amount| capture_amount.get_amount_as_i64()))
.or(payment_intent.amount_captured)
.ok_or(errors::ApiErrorResponse::InternalServerError)
.attach_printable("amount captured is none in a successful payment")?;
//[#299]: Can we change the flow based on some workflow idea
utils::when(amount <= 0, || {
utils::when(amount <= MinorUnit::new(0), || {
Err(report!(errors::ApiErrorResponse::InvalidDataFormat {
field_name: "amount".to_string(),
expected_format: "positive integer".to_string()
@ -178,7 +179,7 @@ pub async fn trigger_refund_to_gateway(
&routed_through,
merchant_account,
key_store,
(payment_attempt.amount.get_amount_as_i64(), currency),
(payment_attempt.amount, currency),
payment_intent,
payment_attempt,
refund,
@ -458,7 +459,7 @@ pub async fn sync_refund_with_gateway(
&connector_id,
merchant_account,
key_store,
(payment_attempt.amount.get_amount_as_i64(), currency),
(payment_attempt.amount, currency),
payment_intent,
payment_attempt,
refund,
@ -588,7 +589,7 @@ pub async fn validate_and_create_refund(
key_store: &domain::MerchantKeyStore,
payment_attempt: &storage::PaymentAttempt,
payment_intent: &storage::PaymentIntent,
refund_amount: i64,
refund_amount: MinorUnit,
req: refunds::RefundRequest,
creds_identifier: Option<String>,
) -> RouterResult<refunds::RefundResponse> {
@ -680,7 +681,7 @@ pub async fn validate_and_create_refund(
validator::validate_refund_amount(
total_amount_captured.get_amount_as_i64(),
&all_refunds,
refund_amount,
refund_amount.get_amount_as_i64(),
)
.change_context(errors::ApiErrorResponse::RefundAmountExceedsPaymentAmount)?;
@ -705,7 +706,7 @@ pub async fn validate_and_create_refund(
.set_connector_transaction_id(connecter_transaction_id.to_string())
.set_connector(connector)
.set_refund_type(req.refund_type.unwrap_or_default().foreign_into())
.set_total_amount(payment_attempt.amount.get_amount_as_i64())
.set_total_amount(payment_attempt.amount)
.set_refund_amount(refund_amount)
.set_currency(currency)
.set_created_at(Some(common_utils::date_time::now()))

View File

@ -54,7 +54,7 @@ pub fn validate_refund_amount(
if refund.refund_status != enums::RefundStatus::Failure
&& refund.refund_status != enums::RefundStatus::TransactionFailure
{
Some(refund.refund_amount)
Some(refund.refund_amount.get_amount_as_i64())
} else {
None
}

View File

@ -6,7 +6,7 @@ use api_models::payouts::PayoutVendorAccountDetails;
use common_enums::{IntentStatus, RequestIncrementalAuthorization};
#[cfg(feature = "payouts")]
use common_utils::{crypto::Encryptable, pii::Email};
use common_utils::{errors::CustomResult, ext_traits::AsyncExt};
use common_utils::{errors::CustomResult, ext_traits::AsyncExt, types::MinorUnit};
use error_stack::{report, ResultExt};
use hyperswitch_domain_models::{payment_address::PaymentAddress, router_data::ErrorResponse};
#[cfg(feature = "payouts")]
@ -218,7 +218,7 @@ pub async fn construct_refund_router_data<'a, F>(
connector_id: &str,
merchant_account: &domain::MerchantAccount,
key_store: &domain::MerchantKeyStore,
money: (i64, enums::Currency),
money: (MinorUnit, enums::Currency),
payment_intent: &'a storage::PaymentIntent,
payment_attempt: &storage::PaymentAttempt,
refund: &'a storage::Refund,
@ -323,9 +323,11 @@ pub async fn construct_refund_router_data<'a, F>(
request: types::RefundsData {
refund_id: refund.refund_id.clone(),
connector_transaction_id: refund.connector_transaction_id.clone(),
refund_amount: refund.refund_amount,
refund_amount: refund.refund_amount.get_amount_as_i64(),
minor_refund_amount: refund.refund_amount,
currency,
payment_amount,
payment_amount: payment_amount.get_amount_as_i64(),
minor_payment_amount: payment_amount,
webhook_url,
connector_metadata: payment_attempt.connector_metadata.clone(),
reason: refund.refund_reason.clone(),