refactor(connector): [BraintreeGraphQl] Enhance currency Mapping with ConnectorCurrencyCommon Trait (#2143)

This commit is contained in:
chikke srujan
2023-09-14 13:05:46 +05:30
committed by GitHub
parent 5c5058de87
commit 05696d326f
6 changed files with 246 additions and 66 deletions

View File

@ -70,6 +70,13 @@ impl ConnectorCommon for {{project-name | downcase | pascal_case}} {
"{{project-name | downcase}}" "{{project-name | downcase}}"
} }
fn get_currency_unit(&self) -> api::CurrencyUnit {
todo!()
// TODO! Check connector documentation, on which unit they are processing the currency.
// If the connector accepts amount in lower unit ( i.e cents for USD) then return api::CurrencyUnit::Minor,
// if connector accepts amount in base unit (i.e dollars for USD) then return api::CurrencyUnit::Base
}
fn common_get_content_type(&self) -> &'static str { fn common_get_content_type(&self) -> &'static str {
"application/json" "application/json"
} }
@ -150,7 +157,14 @@ impl
} }
fn get_request_body(&self, req: &types::PaymentsAuthorizeRouterData) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> { fn get_request_body(&self, req: &types::PaymentsAuthorizeRouterData) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> {
let req_obj = {{project-name | downcase}}::{{project-name | downcase | pascal_case}}PaymentsRequest::try_from(req)?; let connector_router_data =
{{project-name | downcase}}::{{project-name | downcase | pascal_case}}RouterData::try_from((
&self.get_currency_unit(),
req.request.currency,
req.request.amount,
req,
))?;
let req_obj = {{project-name | downcase}}::{{project-name | downcase | pascal_case}}PaymentsRequest::try_from(&connector_router_data)?;
let {{project-name | downcase}}_req = types::RequestBody::log_and_get_request_body(&req_obj, utils::Encode::<{{project-name | downcase}}::{{project-name | downcase | pascal_case}}PaymentsRequest>::encode_to_string_of_json) let {{project-name | downcase}}_req = types::RequestBody::log_and_get_request_body(&req_obj, utils::Encode::<{{project-name | downcase}}::{{project-name | downcase | pascal_case}}PaymentsRequest>::encode_to_string_of_json)
.change_context(errors::ConnectorError::RequestEncodingFailed)?; .change_context(errors::ConnectorError::RequestEncodingFailed)?;
Ok(Some({{project-name | downcase}}_req)) Ok(Some({{project-name | downcase}}_req))
@ -361,7 +375,14 @@ impl
} }
fn get_request_body(&self, req: &types::RefundsRouterData<api::Execute>) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> { fn get_request_body(&self, req: &types::RefundsRouterData<api::Execute>) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> {
let req_obj = {{project-name | downcase}}::{{project-name | downcase | pascal_case}}RefundRequest::try_from(req)?; let connector_router_data =
{{project-name | downcase}}::{{project-name | downcase | pascal_case}}RouterData::try_from((
&self.get_currency_unit(),
req.request.currency,
req.request.refund_amount,
req,
))?;
let req_obj = {{project-name | downcase}}::{{project-name | downcase | pascal_case}}RefundRequest::try_from(&connector_router_data)?;
let {{project-name | downcase}}_req = types::RequestBody::log_and_get_request_body(&req_obj, utils::Encode::<{{project-name | downcase}}::{{project-name | downcase | pascal_case}}RefundRequest>::encode_to_string_of_json) let {{project-name | downcase}}_req = types::RequestBody::log_and_get_request_body(&req_obj, utils::Encode::<{{project-name | downcase}}::{{project-name | downcase | pascal_case}}RefundRequest>::encode_to_string_of_json)
.change_context(errors::ConnectorError::RequestEncodingFailed)?; .change_context(errors::ConnectorError::RequestEncodingFailed)?;
Ok(Some({{project-name | downcase}}_req)) Ok(Some({{project-name | downcase}}_req))

View File

@ -1,6 +1,37 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use masking::Secret; use masking::Secret;
use crate::{connector::utils::PaymentsAuthorizeRequestData,core::errors,types::{self,api, storage::enums}}; use crate::{connector::utils::{PaymentsAuthorizeRequestData},core::errors,types::{self,api, storage::enums}};
//TODO: Fill the struct with respective fields
pub struct {{project-name | downcase | pascal_case}}RouterData<T> {
pub amount: i64, // The type of amount that a connector accepts, for example, String, i64, f64, etc.
pub router_data: T,
}
impl<T>
TryFrom<(
&types::api::CurrencyUnit,
types::storage::enums::Currency,
i64,
T,
)> for {{project-name | downcase | pascal_case}}RouterData<T>
{
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(
(_currency_unit, _currency, amount, item): (
&types::api::CurrencyUnit,
types::storage::enums::Currency,
i64,
T,
),
) -> Result<Self, Self::Error> {
//Todo : use utils to convert the amount to the type of amount that a connector accepts
Ok(Self {
amount,
router_data: item,
})
}
}
//TODO: Fill the struct with respective fields //TODO: Fill the struct with respective fields
#[derive(Default, Debug, Serialize, Eq, PartialEq)] #[derive(Default, Debug, Serialize, Eq, PartialEq)]
@ -19,10 +50,10 @@ pub struct {{project-name | downcase | pascal_case}}Card {
complete: bool, complete: bool,
} }
impl TryFrom<&types::PaymentsAuthorizeRouterData> for {{project-name | downcase | pascal_case}}PaymentsRequest { impl TryFrom<&{{project-name | downcase | pascal_case}}RouterData<&types::PaymentsAuthorizeRouterData>> for {{project-name | downcase | pascal_case}}PaymentsRequest {
type Error = error_stack::Report<errors::ConnectorError>; type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result<Self,Self::Error> { fn try_from(item: &{{project-name | downcase | pascal_case}}RouterData<&types::PaymentsAuthorizeRouterData>) -> Result<Self,Self::Error> {
match item.request.payment_method_data.clone() { match item.router_data.request.payment_method_data.clone() {
api::PaymentMethodData::Card(req_card) => { api::PaymentMethodData::Card(req_card) => {
let card = {{project-name | downcase | pascal_case}}Card { let card = {{project-name | downcase | pascal_case}}Card {
name: req_card.card_holder_name, name: req_card.card_holder_name,
@ -30,10 +61,10 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for {{project-name | downcase
expiry_month: req_card.card_exp_month, expiry_month: req_card.card_exp_month,
expiry_year: req_card.card_exp_year, expiry_year: req_card.card_exp_year,
cvc: req_card.card_cvc, cvc: req_card.card_cvc,
complete: item.request.is_auto_capture()?, complete: item.router_data.request.is_auto_capture()?,
}; };
Ok(Self { Ok(Self {
amount: item.request.amount, amount: item.amount.to_owned(),
card, card,
}) })
} }
@ -113,11 +144,11 @@ pub struct {{project-name | downcase | pascal_case}}RefundRequest {
pub amount: i64 pub amount: i64
} }
impl<F> TryFrom<&types::RefundsRouterData<F>> for {{project-name | downcase | pascal_case}}RefundRequest { impl<F> TryFrom<&{{project-name | downcase | pascal_case}}RouterData<&types::RefundsRouterData<F>>> for {{project-name | downcase | pascal_case}}RefundRequest {
type Error = error_stack::Report<errors::ConnectorError>; type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(item: &types::RefundsRouterData<F>) -> Result<Self,Self::Error> { fn try_from(item: &{{project-name | downcase | pascal_case}}RouterData<&types::RefundsRouterData<F>>) -> Result<Self,Self::Error> {
Ok(Self { Ok(Self {
amount: item.request.refund_amount, amount: item.amount.to_owned(),
}) })
} }
} }

View File

@ -74,6 +74,10 @@ impl ConnectorCommon for Braintree {
"braintree" "braintree"
} }
fn get_currency_unit(&self) -> api::CurrencyUnit {
api::CurrencyUnit::Base
}
fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str {
connectors.braintree.base_url.as_ref() connectors.braintree.base_url.as_ref()
} }
@ -425,10 +429,19 @@ impl ConnectorIntegration<api::Capture, types::PaymentsCaptureData, types::Payme
req: &types::PaymentsCaptureRouterData, req: &types::PaymentsCaptureRouterData,
) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> { ) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> {
let connector_api_version = &req.connector_api_version.clone(); let connector_api_version = &req.connector_api_version.clone();
let connector_router_data =
braintree_graphql_transformers::BraintreeRouterData::try_from((
&self.get_currency_unit(),
req.request.currency,
req.request.amount_to_capture,
req,
))?;
match self.is_braintree_graphql_version(connector_api_version) { match self.is_braintree_graphql_version(connector_api_version) {
true => { true => {
let connector_request = let connector_request =
braintree_graphql_transformers::BraintreeCaptureRequest::try_from(req)?; braintree_graphql_transformers::BraintreeCaptureRequest::try_from(
&connector_router_data,
)?;
let braintree_req = types::RequestBody::log_and_get_request_body( let braintree_req = types::RequestBody::log_and_get_request_body(
&connector_request, &connector_request,
@ -736,10 +749,19 @@ impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::P
req: &types::PaymentsAuthorizeRouterData, req: &types::PaymentsAuthorizeRouterData,
) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> { ) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> {
let connector_api_version = &req.connector_api_version; let connector_api_version = &req.connector_api_version;
let connector_router_data =
braintree_graphql_transformers::BraintreeRouterData::try_from((
&self.get_currency_unit(),
req.request.currency,
req.request.amount,
req,
))?;
match self.is_braintree_graphql_version(connector_api_version) { match self.is_braintree_graphql_version(connector_api_version) {
true => { true => {
let connector_request = let connector_request =
braintree_graphql_transformers::BraintreePaymentsRequest::try_from(req)?; braintree_graphql_transformers::BraintreePaymentsRequest::try_from(
&connector_router_data,
)?;
let braintree_payment_request = types::RequestBody::log_and_get_request_body( let braintree_payment_request = types::RequestBody::log_and_get_request_body(
&connector_request, &connector_request,
utils::Encode::<braintree_graphql_transformers::BraintreePaymentsRequest>::encode_to_string_of_json, utils::Encode::<braintree_graphql_transformers::BraintreePaymentsRequest>::encode_to_string_of_json,
@ -1026,10 +1048,19 @@ impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsRespon
req: &types::RefundsRouterData<api::Execute>, req: &types::RefundsRouterData<api::Execute>,
) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> { ) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> {
let connector_api_version = &req.connector_api_version; let connector_api_version = &req.connector_api_version;
let connector_router_data =
braintree_graphql_transformers::BraintreeRouterData::try_from((
&self.get_currency_unit(),
req.request.currency,
req.request.refund_amount,
req,
))?;
match self.is_braintree_graphql_version(connector_api_version) { match self.is_braintree_graphql_version(connector_api_version) {
true => { true => {
let connector_request = let connector_request =
braintree_graphql_transformers::BraintreeRefundRequest::try_from(req)?; braintree_graphql_transformers::BraintreeRefundRequest::try_from(
connector_router_data,
)?;
let braintree_refund_request = types::RequestBody::log_and_get_request_body( let braintree_refund_request = types::RequestBody::log_and_get_request_body(
&connector_request, &connector_request,
utils::Encode::<braintree_graphql_transformers::BraintreeRefundRequest>::encode_to_string_of_json, utils::Encode::<braintree_graphql_transformers::BraintreeRefundRequest>::encode_to_string_of_json,
@ -1310,11 +1341,20 @@ impl
&self, &self,
req: &types::PaymentsCompleteAuthorizeRouterData, req: &types::PaymentsCompleteAuthorizeRouterData,
) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> { ) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> {
let connector_router_data =
braintree_graphql_transformers::BraintreeRouterData::try_from((
&self.get_currency_unit(),
req.request.currency,
req.request.amount,
req,
))?;
let connector_api_version = &req.connector_api_version; let connector_api_version = &req.connector_api_version;
match self.is_braintree_graphql_version(connector_api_version) { match self.is_braintree_graphql_version(connector_api_version) {
true => { true => {
let connector_request = let connector_request =
braintree_graphql_transformers::BraintreePaymentsRequest::try_from(req)?; braintree_graphql_transformers::BraintreePaymentsRequest::try_from(
&connector_router_data,
)?;
let braintree_payment_request = types::RequestBody::log_and_get_request_body( let braintree_payment_request = types::RequestBody::log_and_get_request_body(
&connector_request, &connector_request,
utils::Encode::<braintree_graphql_transformers::BraintreePaymentsRequest>::encode_to_string_of_json, utils::Encode::<braintree_graphql_transformers::BraintreePaymentsRequest>::encode_to_string_of_json,

View File

@ -18,6 +18,37 @@ pub const CAPTURE_TRANSACTION_MUTATION: &str = "mutation captureTransaction($inp
pub const VOID_TRANSACTION_MUTATION: &str = "mutation voidTransaction($input: ReverseTransactionInput!) { reverseTransaction(input: $input) { clientMutationId reversal { ... on Transaction { id legacyId amount { value currencyCode } status } } } }"; pub const VOID_TRANSACTION_MUTATION: &str = "mutation voidTransaction($input: ReverseTransactionInput!) { reverseTransaction(input: $input) { clientMutationId reversal { ... on Transaction { id legacyId amount { value currencyCode } status } } } }";
pub const REFUND_TRANSACTION_MUTATION: &str = "mutation refundTransaction($input: RefundTransactionInput!) { refundTransaction(input: $input) {clientMutationId refund { id legacyId amount { value currencyCode } status } } }"; pub const REFUND_TRANSACTION_MUTATION: &str = "mutation refundTransaction($input: RefundTransactionInput!) { refundTransaction(input: $input) {clientMutationId refund { id legacyId amount { value currencyCode } status } } }";
#[derive(Debug, Serialize)]
pub struct BraintreeRouterData<T> {
pub amount: String,
pub router_data: T,
}
impl<T>
TryFrom<(
&types::api::CurrencyUnit,
types::storage::enums::Currency,
i64,
T,
)> for BraintreeRouterData<T>
{
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(
(currency_unit, currency, amount, item): (
&types::api::CurrencyUnit,
types::storage::enums::Currency,
i64,
T,
),
) -> Result<Self, Self::Error> {
let amount = utils::get_amount_as_string(currency_unit, amount, currency)?;
Ok(Self {
amount,
router_data: item,
})
}
}
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct PaymentInput { pub struct PaymentInput {
@ -56,16 +87,23 @@ pub struct TransactionBody {
merchant_account_id: Secret<String>, merchant_account_id: Secret<String>,
} }
impl TryFrom<&types::PaymentsAuthorizeRouterData> for BraintreePaymentsRequest { impl TryFrom<&BraintreeRouterData<&types::PaymentsAuthorizeRouterData>>
for BraintreePaymentsRequest
{
type Error = error_stack::Report<errors::ConnectorError>; type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result<Self, Self::Error> { fn try_from(
item: &BraintreeRouterData<&types::PaymentsAuthorizeRouterData>,
) -> Result<Self, Self::Error> {
let metadata: BraintreeMeta = let metadata: BraintreeMeta =
utils::to_connector_meta_from_secret(item.connector_meta_data.clone())?; utils::to_connector_meta_from_secret(item.router_data.connector_meta_data.clone())?;
utils::validate_currency(item.request.currency, metadata.merchant_config_currency)?; utils::validate_currency(
item.router_data.request.currency,
metadata.merchant_config_currency,
)?;
match item.request.payment_method_data.clone() { match item.router_data.request.payment_method_data.clone() {
api::PaymentMethodData::Card(_) => { api::PaymentMethodData::Card(_) => {
if item.is_three_ds() { if item.router_data.is_three_ds() {
Ok(Self::CardThreeDs(BraintreeClientTokenRequest::try_from( Ok(Self::CardThreeDs(BraintreeClientTokenRequest::try_from(
metadata, metadata,
)?)) )?))
@ -94,10 +132,14 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for BraintreePaymentsRequest {
} }
} }
impl TryFrom<&types::PaymentsCompleteAuthorizeRouterData> for BraintreePaymentsRequest { impl TryFrom<&BraintreeRouterData<&types::PaymentsCompleteAuthorizeRouterData>>
for BraintreePaymentsRequest
{
type Error = error_stack::Report<errors::ConnectorError>; type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(item: &types::PaymentsCompleteAuthorizeRouterData) -> Result<Self, Self::Error> { fn try_from(
match item.request.payment_method_data.clone() { item: &BraintreeRouterData<&types::PaymentsCompleteAuthorizeRouterData>,
) -> Result<Self, Self::Error> {
match item.router_data.request.payment_method_data.clone() {
Some(api::PaymentMethodData::Card(_)) => { Some(api::PaymentMethodData::Card(_)) => {
Ok(Self::Card(CardPaymentRequest::try_from(item)?)) Ok(Self::Card(CardPaymentRequest::try_from(item)?))
} }
@ -537,22 +579,24 @@ pub struct BraintreeRefundRequest {
variables: BraintreeRefundVariables, variables: BraintreeRefundVariables,
} }
impl<F> TryFrom<&types::RefundsRouterData<F>> for BraintreeRefundRequest { impl<F> TryFrom<BraintreeRouterData<&types::RefundsRouterData<F>>> for BraintreeRefundRequest {
type Error = error_stack::Report<errors::ConnectorError>; type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(item: &types::RefundsRouterData<F>) -> Result<Self, Self::Error> { fn try_from(
item: BraintreeRouterData<&types::RefundsRouterData<F>>,
) -> Result<Self, Self::Error> {
let metadata: BraintreeMeta = let metadata: BraintreeMeta =
utils::to_connector_meta_from_secret(item.connector_meta_data.clone())?; utils::to_connector_meta_from_secret(item.router_data.connector_meta_data.clone())?;
utils::validate_currency(item.request.currency, metadata.merchant_config_currency)?; utils::validate_currency(
item.router_data.request.currency,
metadata.merchant_config_currency,
)?;
let query = REFUND_TRANSACTION_MUTATION.to_string(); let query = REFUND_TRANSACTION_MUTATION.to_string();
let variables = BraintreeRefundVariables { let variables = BraintreeRefundVariables {
input: BraintreeRefundInput { input: BraintreeRefundInput {
transaction_id: item.request.connector_transaction_id.clone(), transaction_id: item.router_data.request.connector_transaction_id.clone(),
refund: RefundInputData { refund: RefundInputData {
amount: utils::to_currency_base_unit( amount: item.amount,
item.request.refund_amount,
item.request.currency,
)?,
merchant_account_id: metadata.merchant_account_id.ok_or( merchant_account_id: metadata.merchant_account_id.ok_or(
errors::ConnectorError::MissingRequiredField { errors::ConnectorError::MissingRequiredField {
field_name: "merchant_account_id", field_name: "merchant_account_id",
@ -928,18 +972,17 @@ pub struct BraintreeCaptureRequest {
variables: VariableCaptureInput, variables: VariableCaptureInput,
} }
impl TryFrom<&types::PaymentsCaptureRouterData> for BraintreeCaptureRequest { impl TryFrom<&BraintreeRouterData<&types::PaymentsCaptureRouterData>> for BraintreeCaptureRequest {
type Error = error_stack::Report<errors::ConnectorError>; type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(item: &types::PaymentsCaptureRouterData) -> Result<Self, Self::Error> { fn try_from(
item: &BraintreeRouterData<&types::PaymentsCaptureRouterData>,
) -> Result<Self, Self::Error> {
let query = CAPTURE_TRANSACTION_MUTATION.to_string(); let query = CAPTURE_TRANSACTION_MUTATION.to_string();
let variables = VariableCaptureInput { let variables = VariableCaptureInput {
input: CaptureInputData { input: CaptureInputData {
transaction_id: item.request.connector_transaction_id.clone(), transaction_id: item.router_data.request.connector_transaction_id.clone(),
transaction: CaptureTransactionBody { transaction: CaptureTransactionBody {
amount: utils::to_currency_base_unit( amount: item.amount.to_owned(),
item.request.amount_to_capture,
item.request.currency,
)?,
}, },
}, },
}; };
@ -1231,14 +1274,20 @@ impl TryFrom<BraintreeMeta> for BraintreeClientTokenRequest {
} }
} }
impl TryFrom<(&types::PaymentsAuthorizeRouterData, BraintreeMeta)> for CardPaymentRequest { impl
TryFrom<(
&BraintreeRouterData<&types::PaymentsAuthorizeRouterData>,
BraintreeMeta,
)> for CardPaymentRequest
{
type Error = error_stack::Report<errors::ConnectorError>; type Error = error_stack::Report<errors::ConnectorError>;
fn try_from( fn try_from(
payment_info: (&types::PaymentsAuthorizeRouterData, BraintreeMeta), (item, metadata): (
&BraintreeRouterData<&types::PaymentsAuthorizeRouterData>,
BraintreeMeta,
),
) -> Result<Self, Self::Error> { ) -> Result<Self, Self::Error> {
let item = payment_info.0; let query = match item.router_data.request.is_auto_capture()? {
let metadata = payment_info.1;
let query = match item.request.is_auto_capture()? {
true => CHARGE_CREDIT_CARD_MUTATION.to_string(), true => CHARGE_CREDIT_CARD_MUTATION.to_string(),
false => AUTHORIZE_CREDIT_CARD_MUTATION.to_string(), false => AUTHORIZE_CREDIT_CARD_MUTATION.to_string(),
}; };
@ -1246,17 +1295,14 @@ impl TryFrom<(&types::PaymentsAuthorizeRouterData, BraintreeMeta)> for CardPayme
query, query,
variables: VariablePaymentInput { variables: VariablePaymentInput {
input: PaymentInput { input: PaymentInput {
payment_method_id: match item.get_payment_method_token()? { payment_method_id: match item.router_data.get_payment_method_token()? {
types::PaymentMethodToken::Token(token) => token, types::PaymentMethodToken::Token(token) => token,
types::PaymentMethodToken::ApplePayDecrypt(_) => { types::PaymentMethodToken::ApplePayDecrypt(_) => {
Err(errors::ConnectorError::InvalidWalletToken)? Err(errors::ConnectorError::InvalidWalletToken)?
} }
}, },
transaction: TransactionBody { transaction: TransactionBody {
amount: utils::to_currency_base_unit( amount: item.amount.to_owned(),
item.request.amount,
item.request.currency,
)?,
merchant_account_id: metadata.merchant_account_id.ok_or( merchant_account_id: metadata.merchant_account_id.ok_or(
errors::ConnectorError::MissingRequiredField { errors::ConnectorError::MissingRequiredField {
field_name: "merchant_account_id", field_name: "merchant_account_id",
@ -1269,15 +1315,22 @@ impl TryFrom<(&types::PaymentsAuthorizeRouterData, BraintreeMeta)> for CardPayme
} }
} }
impl TryFrom<&types::PaymentsCompleteAuthorizeRouterData> for CardPaymentRequest { impl TryFrom<&BraintreeRouterData<&types::PaymentsCompleteAuthorizeRouterData>>
for CardPaymentRequest
{
type Error = error_stack::Report<errors::ConnectorError>; type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(item: &types::PaymentsCompleteAuthorizeRouterData) -> Result<Self, Self::Error> { fn try_from(
item: &BraintreeRouterData<&types::PaymentsCompleteAuthorizeRouterData>,
) -> Result<Self, Self::Error> {
let metadata: BraintreeMeta = let metadata: BraintreeMeta =
utils::to_connector_meta_from_secret(item.connector_meta_data.clone())?; utils::to_connector_meta_from_secret(item.router_data.connector_meta_data.clone())?;
utils::validate_currency(item.request.currency, metadata.merchant_config_currency)?; utils::validate_currency(
item.router_data.request.currency,
metadata.merchant_config_currency,
)?;
let payload_data = let payload_data =
utils::PaymentsCompleteAuthorizeRequestData::get_redirect_response_payload( utils::PaymentsCompleteAuthorizeRequestData::get_redirect_response_payload(
&item.request, &item.router_data.request,
)? )?
.expose(); .expose();
let redirection_response: BraintreeRedirectionResponse = let redirection_response: BraintreeRedirectionResponse =
@ -1293,21 +1346,19 @@ impl TryFrom<&types::PaymentsCompleteAuthorizeRouterData> for CardPaymentRequest
.change_context(errors::ConnectorError::MissingConnectorRedirectionPayload { .change_context(errors::ConnectorError::MissingConnectorRedirectionPayload {
field_name: "three_ds_data", field_name: "three_ds_data",
})?; })?;
let query = let query = match utils::PaymentsCompleteAuthorizeRequestData::is_auto_capture(
match utils::PaymentsCompleteAuthorizeRequestData::is_auto_capture(&item.request)? { &item.router_data.request,
true => CHARGE_CREDIT_CARD_MUTATION.to_string(), )? {
false => AUTHORIZE_CREDIT_CARD_MUTATION.to_string(), true => CHARGE_CREDIT_CARD_MUTATION.to_string(),
}; false => AUTHORIZE_CREDIT_CARD_MUTATION.to_string(),
};
Ok(Self { Ok(Self {
query, query,
variables: VariablePaymentInput { variables: VariablePaymentInput {
input: PaymentInput { input: PaymentInput {
payment_method_id: three_ds_data.nonce, payment_method_id: three_ds_data.nonce,
transaction: TransactionBody { transaction: TransactionBody {
amount: utils::to_currency_base_unit( amount: item.amount.to_owned(),
item.request.amount,
item.request.currency,
)?,
merchant_account_id: metadata.merchant_account_id.ok_or( merchant_account_id: metadata.merchant_account_id.ok_or(
errors::ConnectorError::MissingRequiredField { errors::ConnectorError::MissingRequiredField {
field_name: "merchant_account_id", field_name: "merchant_account_id",

View File

@ -994,6 +994,33 @@ pub fn to_currency_base_unit_from_optional_amount(
} }
} }
pub fn get_amount_as_string(
currency_unit: &types::api::CurrencyUnit,
amount: i64,
currency: diesel_models::enums::Currency,
) -> Result<String, error_stack::Report<errors::ConnectorError>> {
let amount = match currency_unit {
types::api::CurrencyUnit::Minor => amount.to_string(),
types::api::CurrencyUnit::Base => to_currency_base_unit(amount, currency)?,
};
Ok(amount)
}
pub fn get_amount_as_f64(
currency_unit: &types::api::CurrencyUnit,
amount: i64,
currency: diesel_models::enums::Currency,
) -> Result<f64, error_stack::Report<errors::ConnectorError>> {
let amount = match currency_unit {
types::api::CurrencyUnit::Base => to_currency_base_unit_asf64(amount, currency)?,
types::api::CurrencyUnit::Minor => u32::try_from(amount)
.into_report()
.change_context(errors::ConnectorError::ParsingFailed)?
.into(),
};
Ok(amount)
}
pub fn to_currency_base_unit( pub fn to_currency_base_unit(
amount: i64, amount: i64,
currency: diesel_models::enums::Currency, currency: diesel_models::enums::Currency,
@ -1001,7 +1028,7 @@ pub fn to_currency_base_unit(
currency currency
.to_currency_base_unit(amount) .to_currency_base_unit(amount)
.into_report() .into_report()
.change_context(errors::ConnectorError::RequestEncodingFailed) .change_context(errors::ConnectorError::ParsingFailed)
} }
pub fn to_currency_lower_unit( pub fn to_currency_lower_unit(
@ -1050,7 +1077,7 @@ pub fn to_currency_base_unit_asf64(
currency currency
.to_currency_base_unit_asf64(amount) .to_currency_base_unit_asf64(amount)
.into_report() .into_report()
.change_context(errors::ConnectorError::RequestEncodingFailed) .change_context(errors::ConnectorError::ParsingFailed)
} }
pub fn str_to_f32<S>(value: &str, serializer: S) -> Result<S::Ok, S::Error> pub fn str_to_f32<S>(value: &str, serializer: S) -> Result<S::Ok, S::Error>

View File

@ -47,10 +47,20 @@ pub trait ConnectorTransactionId: ConnectorCommon + Sync {
} }
} }
pub enum CurrencyUnit {
Base,
Minor,
}
pub trait ConnectorCommon { pub trait ConnectorCommon {
/// Name of the connector (in lowercase). /// Name of the connector (in lowercase).
fn id(&self) -> &'static str; fn id(&self) -> &'static str;
/// Connector accepted currency unit as either "Base" or "Minor"
fn get_currency_unit(&self) -> CurrencyUnit {
CurrencyUnit::Minor // Default implementation should be remove once it is implemented in all connectors
}
/// HTTP header used for authorization. /// HTTP header used for authorization.
fn get_auth_header( fn get_auth_header(
&self, &self,