mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-01 19:42:27 +08:00
feat(storage): make amount as an enum (#98)
This commit is contained in:
@ -136,7 +136,7 @@ pub(crate) struct StripePaymentIntentRequest {
|
|||||||
impl From<StripePaymentIntentRequest> for PaymentsRequest {
|
impl From<StripePaymentIntentRequest> for PaymentsRequest {
|
||||||
fn from(item: StripePaymentIntentRequest) -> Self {
|
fn from(item: StripePaymentIntentRequest) -> Self {
|
||||||
PaymentsRequest {
|
PaymentsRequest {
|
||||||
amount: item.amount,
|
amount: item.amount.map(|amount| amount.into()),
|
||||||
currency: item.currency.as_ref().map(|c| c.to_uppercase()),
|
currency: item.currency.as_ref().map(|c| c.to_uppercase()),
|
||||||
capture_method: item.capture_method,
|
capture_method: item.capture_method,
|
||||||
amount_to_capture: item.amount_capturable,
|
amount_to_capture: item.amount_capturable,
|
||||||
|
|||||||
@ -431,7 +431,7 @@ where
|
|||||||
pub payment_intent: storage::PaymentIntent,
|
pub payment_intent: storage::PaymentIntent,
|
||||||
pub payment_attempt: storage::PaymentAttempt,
|
pub payment_attempt: storage::PaymentAttempt,
|
||||||
pub connector_response: storage::ConnectorResponse,
|
pub connector_response: storage::ConnectorResponse,
|
||||||
pub amount: i32,
|
pub amount: api::Amount,
|
||||||
pub currency: enums::Currency,
|
pub currency: enums::Currency,
|
||||||
pub mandate_id: Option<String>,
|
pub mandate_id: Option<String>,
|
||||||
pub setup_mandate: Option<api::MandateData>,
|
pub setup_mandate: Option<api::MandateData>,
|
||||||
|
|||||||
@ -210,27 +210,37 @@ pub fn validate_merchant_id(
|
|||||||
|
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
pub fn validate_request_amount_and_amount_to_capture(
|
pub fn validate_request_amount_and_amount_to_capture(
|
||||||
op_amount: Option<i32>,
|
op_amount: Option<api::Amount>,
|
||||||
op_amount_to_capture: Option<i32>,
|
op_amount_to_capture: Option<i32>,
|
||||||
) -> CustomResult<(), errors::ApiErrorResponse> {
|
) -> CustomResult<(), errors::ApiErrorResponse> {
|
||||||
// If both amount and amount to capture is present
|
match (op_amount, op_amount_to_capture) {
|
||||||
// then amount to be capture should be less than or equal to request amount
|
(None, _) => Ok(()),
|
||||||
|
(Some(_amount), None) => Ok(()),
|
||||||
let is_capture_amount_valid = op_amount
|
(Some(amount), Some(amount_to_capture)) => {
|
||||||
.and_then(|amount| {
|
match amount {
|
||||||
op_amount_to_capture.map(|amount_to_capture| amount_to_capture.le(&amount))
|
api::Amount::Value(amount_inner) => {
|
||||||
})
|
// If both amount and amount to capture is present
|
||||||
.unwrap_or(true);
|
// then amount to be capture should be less than or equal to request amount
|
||||||
|
utils::when(
|
||||||
utils::when(
|
!amount_to_capture.le(&amount_inner),
|
||||||
!is_capture_amount_valid,
|
Err(report!(errors::ApiErrorResponse::PreconditionFailed {
|
||||||
Err(report!(errors::ApiErrorResponse::PreconditionFailed {
|
message: format!(
|
||||||
message: format!(
|
"amount_to_capture is greater than amount capture_amount: {:?} request_amount: {:?}",
|
||||||
"amount_to_capture is greater than amount capture_amount: {:?} request_amount: {:?}",
|
amount_to_capture, amount
|
||||||
op_amount_to_capture, op_amount
|
)
|
||||||
)
|
})),
|
||||||
})),
|
)
|
||||||
)
|
}
|
||||||
|
api::Amount::Zero => {
|
||||||
|
// If the amount is Null but still amount_to_capture is passed this is invalid and
|
||||||
|
Err(report!(errors::ApiErrorResponse::PreconditionFailed {
|
||||||
|
message: "amount_to_capture should not exist for when amount = 0"
|
||||||
|
.to_string()
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate_mandate(
|
pub fn validate_mandate(
|
||||||
|
|||||||
@ -77,7 +77,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsCancelRequest>
|
|||||||
error.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)
|
error.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)
|
||||||
})?;
|
})?;
|
||||||
let currency = payment_attempt.currency.get_required_value("currency")?;
|
let currency = payment_attempt.currency.get_required_value("currency")?;
|
||||||
let amount = payment_attempt.amount;
|
let amount = payment_attempt.amount.into();
|
||||||
|
|
||||||
payment_attempt.cancellation_reason = request.cancellation_reason.clone();
|
payment_attempt.cancellation_reason = request.cancellation_reason.clone();
|
||||||
|
|
||||||
|
|||||||
@ -85,7 +85,7 @@ impl<F: Send + Clone> GetTracker<F, payments::PaymentData<F>, api::PaymentsCaptu
|
|||||||
|
|
||||||
currency = payment_attempt.currency.get_required_value("currency")?;
|
currency = payment_attempt.currency.get_required_value("currency")?;
|
||||||
|
|
||||||
amount = payment_attempt.amount;
|
amount = payment_attempt.amount.into();
|
||||||
|
|
||||||
let connector_response = db
|
let connector_response = db
|
||||||
.find_connector_response_by_payment_id_merchant_id_txn_id(
|
.find_connector_response_by_payment_id_merchant_id_txn_id(
|
||||||
|
|||||||
@ -93,7 +93,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
payment_attempt.payment_method = payment_method_type.or(payment_attempt.payment_method);
|
payment_attempt.payment_method = payment_method_type.or(payment_attempt.payment_method);
|
||||||
payment_attempt.browser_info = browser_info;
|
payment_attempt.browser_info = browser_info;
|
||||||
currency = payment_attempt.currency.get_required_value("currency")?;
|
currency = payment_attempt.currency.get_required_value("currency")?;
|
||||||
amount = payment_attempt.amount;
|
amount = payment_attempt.amount.into();
|
||||||
|
|
||||||
connector_response = db
|
connector_response = db
|
||||||
.find_connector_response_by_payment_id_merchant_id_txn_id(
|
.find_connector_response_by_payment_id_merchant_id_txn_id(
|
||||||
|
|||||||
@ -284,10 +284,8 @@ impl<F: Send + Clone> ValidateRequest<F, api::PaymentsRequest> for PaymentCreate
|
|||||||
helpers::validate_merchant_id(&merchant_account.merchant_id, request_merchant_id)
|
helpers::validate_merchant_id(&merchant_account.merchant_id, request_merchant_id)
|
||||||
.change_context(errors::ApiErrorResponse::MerchantAccountNotFound)?;
|
.change_context(errors::ApiErrorResponse::MerchantAccountNotFound)?;
|
||||||
|
|
||||||
let amount = request.amount.get_required_value("amount")?;
|
|
||||||
|
|
||||||
helpers::validate_request_amount_and_amount_to_capture(
|
helpers::validate_request_amount_and_amount_to_capture(
|
||||||
Some(amount),
|
request.amount,
|
||||||
request.amount_to_capture,
|
request.amount_to_capture,
|
||||||
)
|
)
|
||||||
.change_context(errors::ApiErrorResponse::InvalidDataFormat {
|
.change_context(errors::ApiErrorResponse::InvalidDataFormat {
|
||||||
@ -295,9 +293,10 @@ impl<F: Send + Clone> ValidateRequest<F, api::PaymentsRequest> for PaymentCreate
|
|||||||
expected_format: "amount_to_capture lesser than amount".to_string(),
|
expected_format: "amount_to_capture lesser than amount".to_string(),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let mandate_type = helpers::validate_mandate(request)?;
|
|
||||||
let payment_id = core_utils::get_or_generate_id("payment_id", &given_payment_id, "pay")?;
|
let payment_id = core_utils::get_or_generate_id("payment_id", &given_payment_id, "pay")?;
|
||||||
|
|
||||||
|
let mandate_type = helpers::validate_mandate(request)?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
Box::new(self),
|
Box::new(self),
|
||||||
operations::ValidateResult {
|
operations::ValidateResult {
|
||||||
@ -316,7 +315,7 @@ impl PaymentCreate {
|
|||||||
payment_id: &str,
|
payment_id: &str,
|
||||||
merchant_id: &str,
|
merchant_id: &str,
|
||||||
connector: types::Connector,
|
connector: types::Connector,
|
||||||
money: (i32, enums::Currency),
|
money: (api::Amount, enums::Currency),
|
||||||
payment_method: Option<enums::PaymentMethodType>,
|
payment_method: Option<enums::PaymentMethodType>,
|
||||||
request: &api::PaymentsRequest,
|
request: &api::PaymentsRequest,
|
||||||
browser_info: Option<serde_json::Value>,
|
browser_info: Option<serde_json::Value>,
|
||||||
@ -330,7 +329,7 @@ impl PaymentCreate {
|
|||||||
merchant_id: merchant_id.to_string(),
|
merchant_id: merchant_id.to_string(),
|
||||||
txn_id: Uuid::new_v4().to_string(),
|
txn_id: Uuid::new_v4().to_string(),
|
||||||
status,
|
status,
|
||||||
amount,
|
amount: amount.into(),
|
||||||
currency,
|
currency,
|
||||||
connector: connector.to_string(),
|
connector: connector.to_string(),
|
||||||
payment_method,
|
payment_method,
|
||||||
@ -351,7 +350,7 @@ impl PaymentCreate {
|
|||||||
payment_id: &str,
|
payment_id: &str,
|
||||||
merchant_id: &str,
|
merchant_id: &str,
|
||||||
connector_id: &str,
|
connector_id: &str,
|
||||||
money: (i32, enums::Currency),
|
money: (api::Amount, enums::Currency),
|
||||||
request: &api::PaymentsRequest,
|
request: &api::PaymentsRequest,
|
||||||
shipping_address_id: Option<String>,
|
shipping_address_id: Option<String>,
|
||||||
billing_address_id: Option<String>,
|
billing_address_id: Option<String>,
|
||||||
@ -366,7 +365,7 @@ impl PaymentCreate {
|
|||||||
payment_id: payment_id.to_string(),
|
payment_id: payment_id.to_string(),
|
||||||
merchant_id: merchant_id.to_string(),
|
merchant_id: merchant_id.to_string(),
|
||||||
status,
|
status,
|
||||||
amount,
|
amount: amount.into(),
|
||||||
currency,
|
currency,
|
||||||
connector_id: Some(connector_id.to_string()),
|
connector_id: Some(connector_id.to_string()),
|
||||||
description: request.description.clone(),
|
description: request.description.clone(),
|
||||||
@ -406,7 +405,7 @@ impl PaymentCreate {
|
|||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
pub fn payments_create_request_validation(
|
pub fn payments_create_request_validation(
|
||||||
req: &api::PaymentsRequest,
|
req: &api::PaymentsRequest,
|
||||||
) -> RouterResult<(i32, enums::Currency)> {
|
) -> RouterResult<(api::Amount, enums::Currency)> {
|
||||||
let currency: enums::Currency = req
|
let currency: enums::Currency = req
|
||||||
.currency
|
.currency
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
|||||||
@ -135,7 +135,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::VerifyRequest> for Paym
|
|||||||
payment_attempt,
|
payment_attempt,
|
||||||
/// currency and amount are irrelevant in this scenario
|
/// currency and amount are irrelevant in this scenario
|
||||||
currency: storage_enums::Currency::default(),
|
currency: storage_enums::Currency::default(),
|
||||||
amount: 0,
|
amount: api::Amount::Zero,
|
||||||
mandate_id: None,
|
mandate_id: None,
|
||||||
setup_mandate: request.mandate_data.clone(),
|
setup_mandate: request.mandate_data.clone(),
|
||||||
token: request.payment_token.clone(),
|
token: request.payment_token.clone(),
|
||||||
|
|||||||
@ -72,7 +72,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsSessionRequest>
|
|||||||
|
|
||||||
payment_attempt.payment_method = Some(enums::PaymentMethodType::Wallet);
|
payment_attempt.payment_method = Some(enums::PaymentMethodType::Wallet);
|
||||||
|
|
||||||
let amount = payment_intent.amount;
|
let amount = payment_intent.amount.into();
|
||||||
|
|
||||||
if let Some(ref payment_intent_client_secret) = payment_intent.client_secret {
|
if let Some(ref payment_intent_client_secret) = payment_intent.client_secret {
|
||||||
if request.client_secret.ne(payment_intent_client_secret) {
|
if request.client_secret.ne(payment_intent_client_secret) {
|
||||||
|
|||||||
@ -68,7 +68,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsStartRequest> f
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
currency = payment_attempt.currency.get_required_value("currency")?;
|
currency = payment_attempt.currency.get_required_value("currency")?;
|
||||||
amount = payment_attempt.amount;
|
amount = payment_attempt.amount.into();
|
||||||
|
|
||||||
let shipping_address = helpers::get_address_for_payment_request(
|
let shipping_address = helpers::get_address_for_payment_request(
|
||||||
db,
|
db,
|
||||||
|
|||||||
@ -167,7 +167,7 @@ async fn get_tracker_for_sync<
|
|||||||
|
|
||||||
connector_response.encoded_data = request.param.clone();
|
connector_response.encoded_data = request.param.clone();
|
||||||
currency = payment_attempt.currency.get_required_value("currency")?;
|
currency = payment_attempt.currency.get_required_value("currency")?;
|
||||||
amount = payment_attempt.amount;
|
amount = payment_attempt.amount.into();
|
||||||
|
|
||||||
let shipping_address =
|
let shipping_address =
|
||||||
helpers::get_address_by_id(db, payment_intent.shipping_address_id.clone()).await?;
|
helpers::get_address_by_id(db, payment_intent.shipping_address_id.clone()).await?;
|
||||||
|
|||||||
@ -42,12 +42,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
PaymentData<F>,
|
PaymentData<F>,
|
||||||
Option<CustomerDetails>,
|
Option<CustomerDetails>,
|
||||||
)> {
|
)> {
|
||||||
let (mut payment_intent, mut payment_attempt, currency, amount): (
|
let (mut payment_intent, mut payment_attempt, currency): (_, _, enums::Currency);
|
||||||
_,
|
|
||||||
_,
|
|
||||||
enums::Currency,
|
|
||||||
_,
|
|
||||||
);
|
|
||||||
|
|
||||||
let payment_id = payment_id
|
let payment_id = payment_id
|
||||||
.get_payment_intent_id()
|
.get_payment_intent_id()
|
||||||
@ -80,7 +75,9 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
|
|
||||||
payment_attempt.payment_method = payment_method_type.or(payment_attempt.payment_method);
|
payment_attempt.payment_method = payment_method_type.or(payment_attempt.payment_method);
|
||||||
|
|
||||||
amount = request.amount.unwrap_or(payment_attempt.amount);
|
let amount = request
|
||||||
|
.amount
|
||||||
|
.unwrap_or_else(|| payment_attempt.amount.into());
|
||||||
|
|
||||||
payment_intent = db
|
payment_intent = db
|
||||||
.find_payment_intent_by_payment_id_merchant_id(&payment_id, merchant_id, storage_scheme)
|
.find_payment_intent_by_payment_id_merchant_id(&payment_id, merchant_id, storage_scheme)
|
||||||
@ -202,7 +199,7 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
|
|||||||
.update_payment_attempt(
|
.update_payment_attempt(
|
||||||
payment_data.payment_attempt,
|
payment_data.payment_attempt,
|
||||||
storage::PaymentAttemptUpdate::Update {
|
storage::PaymentAttemptUpdate::Update {
|
||||||
amount: payment_data.amount,
|
amount: payment_data.amount.into(),
|
||||||
currency: payment_data.currency,
|
currency: payment_data.currency,
|
||||||
status: get_attempt_status(),
|
status: get_attempt_status(),
|
||||||
authentication_type: None,
|
authentication_type: None,
|
||||||
@ -237,7 +234,7 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
|
|||||||
.update_payment_intent(
|
.update_payment_intent(
|
||||||
payment_data.payment_intent.clone(),
|
payment_data.payment_intent.clone(),
|
||||||
storage::PaymentIntentUpdate::Update {
|
storage::PaymentIntentUpdate::Update {
|
||||||
amount: payment_data.amount,
|
amount: payment_data.amount.into(),
|
||||||
currency: payment_data.currency,
|
currency: payment_data.currency,
|
||||||
status: get_status(),
|
status: get_status(),
|
||||||
customer_id,
|
customer_id,
|
||||||
@ -285,6 +282,7 @@ impl<F: Send + Clone> ValidateRequest<F, api::PaymentsRequest> for PaymentUpdate
|
|||||||
field_name: "merchant_id".to_string(),
|
field_name: "merchant_id".to_string(),
|
||||||
expected_format: "merchant_id from merchant account".to_string(),
|
expected_format: "merchant_id from merchant account".to_string(),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
helpers::validate_request_amount_and_amount_to_capture(
|
helpers::validate_request_amount_and_amount_to_capture(
|
||||||
request.amount,
|
request.amount,
|
||||||
request.amount_to_capture,
|
request.amount_to_capture,
|
||||||
|
|||||||
@ -361,7 +361,7 @@ impl<F: Clone> TryFrom<PaymentData<F>> for types::PaymentsAuthorizeData {
|
|||||||
confirm: payment_data.payment_attempt.confirm,
|
confirm: payment_data.payment_attempt.confirm,
|
||||||
statement_descriptor_suffix: payment_data.payment_intent.statement_descriptor_suffix,
|
statement_descriptor_suffix: payment_data.payment_intent.statement_descriptor_suffix,
|
||||||
capture_method: payment_data.payment_attempt.capture_method,
|
capture_method: payment_data.payment_attempt.capture_method,
|
||||||
amount: payment_data.amount,
|
amount: payment_data.amount.into(),
|
||||||
currency: payment_data.currency,
|
currency: payment_data.currency,
|
||||||
browser_info,
|
browser_info,
|
||||||
})
|
})
|
||||||
|
|||||||
@ -16,13 +16,13 @@ use crate::{
|
|||||||
services::api,
|
services::api,
|
||||||
|
|
||||||
types::api::{
|
types::api::{
|
||||||
enums as api_enums,
|
self as api_types, enums as api_enums,
|
||||||
payments::{
|
payments::{
|
||||||
PaymentIdType, PaymentListConstraints, PaymentsCancelRequest, PaymentsCaptureRequest,
|
PaymentIdType, PaymentListConstraints, PaymentsCancelRequest, PaymentsCaptureRequest,
|
||||||
PaymentsRequest, PaymentsRetrieveRequest,
|
PaymentsRequest, PaymentsRetrieveRequest,
|
||||||
},
|
},
|
||||||
Authorize, Capture, PSync, PaymentRetrieveBody, PaymentsResponse, PaymentsStartRequest,
|
Authorize, Capture, PSync, PaymentRetrieveBody, PaymentsResponse, PaymentsStartRequest,
|
||||||
Verify, VerifyResponse, Void,
|
Verify, Void,
|
||||||
}, // FIXME imports
|
}, // FIXME imports
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -38,46 +38,43 @@ pub async fn payments_create(
|
|||||||
if let Some(api_enums::CaptureMethod::Scheduled) = payload.capture_method {
|
if let Some(api_enums::CaptureMethod::Scheduled) = payload.capture_method {
|
||||||
return http_not_implemented();
|
return http_not_implemented();
|
||||||
};
|
};
|
||||||
match payload.amount {
|
|
||||||
Some(0) | None => {
|
api::server_wrap(
|
||||||
api::server_wrap(
|
&state,
|
||||||
&state,
|
&req,
|
||||||
&req,
|
payload,
|
||||||
payload.into(),
|
|state, merchant_account, req| {
|
||||||
|state, merchant_account, req| {
|
// TODO: Change for making it possible for the flow to be inferred internally or through validation layer
|
||||||
payments::payments_core::<Verify, VerifyResponse, _, _, _>(
|
async {
|
||||||
state,
|
match req.amount.as_ref() {
|
||||||
merchant_account,
|
Some(api_types::Amount::Value(_)) | None => {
|
||||||
payments::PaymentMethodValidate,
|
payments::payments_core::<Authorize, PaymentsResponse, _, _, _>(
|
||||||
req,
|
state,
|
||||||
api::AuthFlow::Merchant,
|
merchant_account,
|
||||||
payments::CallConnectorAction::Trigger,
|
payments::PaymentCreate,
|
||||||
)
|
req,
|
||||||
},
|
api::AuthFlow::Merchant,
|
||||||
api::MerchantAuthentication::ApiKey,
|
payments::CallConnectorAction::Trigger,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
_ => {
|
Some(api_types::Amount::Zero) => {
|
||||||
api::server_wrap(
|
payments::payments_core::<Verify, PaymentsResponse, _, _, _>(
|
||||||
&state,
|
state,
|
||||||
&req,
|
merchant_account,
|
||||||
payload,
|
payments::PaymentCreate,
|
||||||
|state, merchant_account, req| {
|
req,
|
||||||
payments::payments_core::<Authorize, PaymentsResponse, _, _, _>(
|
api::AuthFlow::Merchant,
|
||||||
state,
|
payments::CallConnectorAction::Trigger,
|
||||||
merchant_account,
|
)
|
||||||
payments::PaymentCreate,
|
.await
|
||||||
req,
|
}
|
||||||
api::AuthFlow::Merchant,
|
}
|
||||||
payments::CallConnectorAction::Trigger,
|
}
|
||||||
)
|
},
|
||||||
},
|
api::MerchantAuthentication::ApiKey,
|
||||||
api::MerchantAuthentication::ApiKey,
|
)
|
||||||
)
|
.await
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(state), fields(flow = ?Flow::PaymentsStart))]
|
#[instrument(skip(state), fields(flow = ?Flow::PaymentsStart))]
|
||||||
|
|||||||
@ -27,7 +27,8 @@ pub struct PaymentsRequest {
|
|||||||
)]
|
)]
|
||||||
pub payment_id: Option<PaymentIdType>,
|
pub payment_id: Option<PaymentIdType>,
|
||||||
pub merchant_id: Option<String>,
|
pub merchant_id: Option<String>,
|
||||||
pub amount: Option<i32>,
|
#[serde(default, deserialize_with = "custom_serde::amount::deserialize_option")]
|
||||||
|
pub amount: Option<Amount>,
|
||||||
pub currency: Option<String>,
|
pub currency: Option<String>,
|
||||||
pub capture_method: Option<api_enums::CaptureMethod>,
|
pub capture_method: Option<api_enums::CaptureMethod>,
|
||||||
pub amount_to_capture: Option<i32>,
|
pub amount_to_capture: Option<i32>,
|
||||||
@ -68,6 +69,30 @@ impl PaymentsRequest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum Amount {
|
||||||
|
Value(i32),
|
||||||
|
#[default]
|
||||||
|
Zero,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Amount> for i32 {
|
||||||
|
fn from(amount: Amount) -> Self {
|
||||||
|
match amount {
|
||||||
|
Amount::Value(v) => v,
|
||||||
|
Amount::Zero => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<i32> for Amount {
|
||||||
|
fn from(val: i32) -> Self {
|
||||||
|
match val {
|
||||||
|
0 => Amount::Zero,
|
||||||
|
amount => Amount::Value(amount),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)]
|
#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct PaymentsRedirectRequest {
|
pub struct PaymentsRedirectRequest {
|
||||||
@ -788,7 +813,7 @@ mod payments_test {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn payments_request() -> PaymentsRequest {
|
fn payments_request() -> PaymentsRequest {
|
||||||
PaymentsRequest {
|
PaymentsRequest {
|
||||||
amount: Some(200),
|
amount: Some(Amount::Value(200)),
|
||||||
payment_method_data: Some(PaymentMethod::Card(card())),
|
payment_method_data: Some(PaymentMethod::Card(card())),
|
||||||
..PaymentsRequest::default()
|
..PaymentsRequest::default()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -72,3 +72,69 @@ pub(crate) mod payment_id_type {
|
|||||||
deserializer.deserialize_option(OptionalPaymentIdVisitor)
|
deserializer.deserialize_option(OptionalPaymentIdVisitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) mod amount {
|
||||||
|
use serde::de;
|
||||||
|
|
||||||
|
use crate::types::api;
|
||||||
|
struct AmountVisitor;
|
||||||
|
struct OptionalAmountVisitor;
|
||||||
|
|
||||||
|
// This is defined to provide guarded deserialization of amount
|
||||||
|
// which itself handles zero and non-zero values internally
|
||||||
|
impl<'de> de::Visitor<'de> for AmountVisitor {
|
||||||
|
type Value = api::Amount;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(formatter, "amount as i32")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
Ok(match v {
|
||||||
|
0 => api::Amount::Zero,
|
||||||
|
amount => api::Amount::Value(amount),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> de::Visitor<'de> for OptionalAmountVisitor {
|
||||||
|
type Value = Option<api::Amount>;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(formatter, "option of amount (as i32)")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
deserializer.deserialize_any(AmountVisitor).map(Some)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_none<E>(self) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<api::Amount, D::Error>
|
||||||
|
where
|
||||||
|
D: de::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
deserializer.deserialize_any(AmountVisitor)
|
||||||
|
}
|
||||||
|
pub(crate) fn deserialize_option<'de, D>(
|
||||||
|
deserializer: D,
|
||||||
|
) -> Result<Option<api::Amount>, D::Error>
|
||||||
|
where
|
||||||
|
D: de::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
deserializer.deserialize_option(OptionalAmountVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -288,7 +288,7 @@ async fn payments_create_core() {
|
|||||||
"pay_mbabizu24mvu3mela5njyhpit10".to_string(),
|
"pay_mbabizu24mvu3mela5njyhpit10".to_string(),
|
||||||
)),
|
)),
|
||||||
merchant_id: Some("jarnura".to_string()),
|
merchant_id: Some("jarnura".to_string()),
|
||||||
amount: Some(6540),
|
amount: Some(6540.into()),
|
||||||
currency: Some("USD".to_string()),
|
currency: Some("USD".to_string()),
|
||||||
capture_method: Some(api_enums::CaptureMethod::Automatic),
|
capture_method: Some(api_enums::CaptureMethod::Automatic),
|
||||||
amount_to_capture: Some(6540),
|
amount_to_capture: Some(6540),
|
||||||
@ -444,7 +444,7 @@ async fn payments_create_core_adyen_no_redirect() {
|
|||||||
let req = api::PaymentsRequest {
|
let req = api::PaymentsRequest {
|
||||||
payment_id: Some(api::PaymentIdType::PaymentIntentId(payment_id.clone())),
|
payment_id: Some(api::PaymentIdType::PaymentIntentId(payment_id.clone())),
|
||||||
merchant_id: Some(merchant_id.clone()),
|
merchant_id: Some(merchant_id.clone()),
|
||||||
amount: Some(6540),
|
amount: Some(6540.into()),
|
||||||
currency: Some("USD".to_string()),
|
currency: Some("USD".to_string()),
|
||||||
capture_method: Some(api_enums::CaptureMethod::Automatic),
|
capture_method: Some(api_enums::CaptureMethod::Automatic),
|
||||||
amount_to_capture: Some(6540),
|
amount_to_capture: Some(6540),
|
||||||
|
|||||||
@ -49,7 +49,7 @@ async fn payments_create_core() {
|
|||||||
"pay_mbabizu24mvu3mela5njyhpit10".to_string(),
|
"pay_mbabizu24mvu3mela5njyhpit10".to_string(),
|
||||||
)),
|
)),
|
||||||
merchant_id: Some("jarnura".to_string()),
|
merchant_id: Some("jarnura".to_string()),
|
||||||
amount: Some(6540),
|
amount: Some(6540.into()),
|
||||||
currency: Some("USD".to_string()),
|
currency: Some("USD".to_string()),
|
||||||
capture_method: Some(api_enums::CaptureMethod::Automatic),
|
capture_method: Some(api_enums::CaptureMethod::Automatic),
|
||||||
amount_to_capture: Some(6540),
|
amount_to_capture: Some(6540),
|
||||||
@ -200,7 +200,7 @@ async fn payments_create_core_adyen_no_redirect() {
|
|||||||
let req = api::PaymentsRequest {
|
let req = api::PaymentsRequest {
|
||||||
payment_id: Some(api::PaymentIdType::PaymentIntentId(payment_id.clone())),
|
payment_id: Some(api::PaymentIdType::PaymentIntentId(payment_id.clone())),
|
||||||
merchant_id: Some(merchant_id.clone()),
|
merchant_id: Some(merchant_id.clone()),
|
||||||
amount: Some(6540),
|
amount: Some(6540.into()),
|
||||||
currency: Some("USD".to_string()),
|
currency: Some("USD".to_string()),
|
||||||
capture_method: Some(api_enums::CaptureMethod::Automatic),
|
capture_method: Some(api_enums::CaptureMethod::Automatic),
|
||||||
amount_to_capture: Some(6540),
|
amount_to_capture: Some(6540),
|
||||||
|
|||||||
Reference in New Issue
Block a user