Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(connector): [Paypal] Add support for passing shipping_cost in Payment request #6423

Merged
merged 8 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion crates/hyperswitch_domain_models/src/router_request_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,17 +71,22 @@ pub struct PaymentsAuthorizeData {
/// In case the connector supports only one reference id, Hyperswitch's Payment ID will be sent as reference.
pub merchant_order_reference_id: Option<String>,
pub integrity_object: Option<AuthoriseIntegrityObject>,
pub shipping_cost: Option<MinorUnit>,
}

#[derive(Debug, Clone)]
pub struct PaymentsPostSessionTokensData {
// amount here would include amount, surcharge_amount and shipping_cost
pub amount: MinorUnit,
/// original amount sent by the merchant
pub order_amount: MinorUnit,
pub currency: storage_enums::Currency,
pub capture_method: Option<storage_enums::CaptureMethod>,
/// Merchant's identifier for the payment/invoice. This will be sent to the connector
/// if the connector provides support to accept multiple reference ids.
/// In case the connector supports only one reference id, Hyperswitch's Payment ID will be sent as reference.
pub merchant_order_reference_id: Option<String>,
pub shipping_cost: Option<MinorUnit>,
}

#[derive(Debug, Clone, PartialEq)]
Expand Down Expand Up @@ -833,10 +838,13 @@ pub struct PaymentsTaxCalculationData {
#[derive(Debug, Clone, Default)]
pub struct SdkPaymentsSessionUpdateData {
pub order_tax_amount: MinorUnit,
pub net_amount: MinorUnit,
// amount here would include amount, surcharge_amount, order_tax_amount and shipping_cost
pub amount: MinorUnit,
/// original amount sent by the merchant
pub order_amount: MinorUnit,
pub currency: storage_enums::Currency,
pub session_id: Option<String>,
pub shipping_cost: Option<MinorUnit>,
}

#[derive(Debug, Clone)]
Expand All @@ -862,4 +870,5 @@ pub struct SetupMandateRequestData {

// MinorUnit for amount framework
pub minor_amount: Option<MinorUnit>,
pub shipping_cost: Option<MinorUnit>,
}
46 changes: 38 additions & 8 deletions crates/router/src/connector/paypal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use base64::Engine;
use common_utils::{
ext_traits::ByteSliceExt,
request::RequestContent,
types::{AmountConvertor, StringMajorUnit, StringMajorUnitForConnector},
types::{AmountConvertor, MinorUnit, StringMajorUnit, StringMajorUnitForConnector},
};
use diesel_models::enums;
use error_stack::ResultExt;
Expand Down Expand Up @@ -484,7 +484,8 @@ impl ConnectorIntegration<api::PoFulfill, types::PayoutsData, types::PayoutsResp
req.request.minor_amount,
req.request.destination_currency,
)?;
let connector_router_data = paypal::PaypalRouterData::try_from((amount, None, None, req))?;
let connector_router_data =
paypal::PaypalRouterData::try_from((amount, None, None, None, req))?;
let connector_req = paypal::PaypalFulfillRequest::try_from(&connector_router_data)?;
Ok(RequestContent::Json(Box::new(connector_req)))
}
Expand Down Expand Up @@ -710,7 +711,23 @@ impl
req.request.amount,
req.request.currency,
)?;
let connector_router_data = paypal::PaypalRouterData::try_from((amount, None, None, req))?;
let shipping_cost = connector_utils::convert_amount(
self.amount_converter,
req.request.shipping_cost.unwrap_or(MinorUnit::zero()),
req.request.currency,
)?;
let order_amount = connector_utils::convert_amount(
self.amount_converter,
req.request.order_amount,
req.request.currency,
)?;
let connector_router_data = paypal::PaypalRouterData::try_from((
amount,
Some(shipping_cost),
None,
Some(order_amount),
req,
))?;
let connector_req = paypal::PaypalPaymentsRequest::try_from(&connector_router_data)?;
Ok(RequestContent::Json(Box::new(connector_req)))
}
Expand Down Expand Up @@ -810,21 +827,27 @@ impl
) -> CustomResult<RequestContent, errors::ConnectorError> {
let order_amount = connector_utils::convert_amount(
self.amount_converter,
req.request.amount,
req.request.order_amount,
req.request.currency,
)?;
let amount = connector_utils::convert_amount(
self.amount_converter,
req.request.net_amount,
req.request.amount,
req.request.currency,
)?;
let order_tax_amount = connector_utils::convert_amount(
self.amount_converter,
req.request.order_tax_amount,
req.request.currency,
)?;
let shipping_cost = connector_utils::convert_amount(
self.amount_converter,
req.request.shipping_cost.unwrap_or(MinorUnit::zero()),
req.request.currency,
)?;
let connector_router_data = paypal::PaypalRouterData::try_from((
amount,
Some(shipping_cost),
Some(order_tax_amount),
Some(order_amount),
req,
Expand Down Expand Up @@ -915,7 +938,13 @@ impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::P
req.request.minor_amount,
req.request.currency,
)?;
let connector_router_data = paypal::PaypalRouterData::try_from((amount, None, None, req))?;
let shipping_cost = connector_utils::convert_amount(
self.amount_converter,
req.request.shipping_cost.unwrap_or(MinorUnit::zero()),
req.request.currency,
)?;
let connector_router_data =
paypal::PaypalRouterData::try_from((amount, Some(shipping_cost), None, None, req))?;
let connector_req = paypal::PaypalPaymentsRequest::try_from(&connector_router_data)?;
Ok(RequestContent::Json(Box::new(connector_req)))
}
Expand Down Expand Up @@ -1432,7 +1461,7 @@ impl ConnectorIntegration<api::Capture, types::PaymentsCaptureData, types::Payme
req.request.currency,
)?;
let connector_router_data =
paypal::PaypalRouterData::try_from((amount_to_capture, None, None, req))?;
paypal::PaypalRouterData::try_from((amount_to_capture, None, None, None, req))?;
let connector_req = paypal::PaypalPaymentsCaptureRequest::try_from(&connector_router_data)?;
Ok(RequestContent::Json(Box::new(connector_req)))
}
Expand Down Expand Up @@ -1599,7 +1628,8 @@ impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsRespon
req.request.minor_refund_amount,
req.request.currency,
)?;
let connector_router_data = paypal::PaypalRouterData::try_from((amount, None, None, req))?;
let connector_router_data =
paypal::PaypalRouterData::try_from((amount, None, None, None, req))?;
let connector_req = paypal::PaypalRefundRequest::try_from(&connector_router_data)?;
Ok(RequestContent::Json(Box::new(connector_req)))
}
Expand Down
68 changes: 55 additions & 13 deletions crates/router/src/connector/paypal/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use crate::{
#[derive(Debug, Serialize)]
pub struct PaypalRouterData<T> {
pub amount: StringMajorUnit,
pub shipping_cost: Option<StringMajorUnit>,
pub order_tax_amount: Option<StringMajorUnit>,
pub order_amount: Option<StringMajorUnit>,
pub router_data: T,
Expand All @@ -38,20 +39,23 @@ impl<T>
StringMajorUnit,
Option<StringMajorUnit>,
Option<StringMajorUnit>,
Option<StringMajorUnit>,
T,
)> for PaypalRouterData<T>
{
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(
(amount, order_tax_amount, order_amount, item): (
(amount, shipping_cost, order_tax_amount, order_amount, item): (
StringMajorUnit,
Option<StringMajorUnit>,
Option<StringMajorUnit>,
Option<StringMajorUnit>,
T,
),
) -> Result<Self, Self::Error> {
Ok(Self {
amount,
shipping_cost,
order_tax_amount,
order_amount,
router_data: item,
Expand Down Expand Up @@ -107,24 +111,47 @@ impl From<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for OrderReque
value: item.amount.clone(),
},
tax_total: None,
shipping: Some(OrderAmount {
currency_code: item.router_data.request.currency,
value: item
.shipping_cost
.clone()
.unwrap_or(StringMajorUnit::zero()),
}),
},
}
}
}

impl From<&PaypalRouterData<&types::PaymentsPostSessionTokensRouterData>> for OrderRequestAmount {
fn from(item: &PaypalRouterData<&types::PaymentsPostSessionTokensRouterData>) -> Self {
Self {
impl TryFrom<&PaypalRouterData<&types::PaymentsPostSessionTokensRouterData>>
for OrderRequestAmount
{
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(
item: &PaypalRouterData<&types::PaymentsPostSessionTokensRouterData>,
) -> Result<Self, Self::Error> {
Ok(Self {
currency_code: item.router_data.request.currency,
value: item.amount.clone(),
breakdown: AmountBreakdown {
item_total: OrderAmount {
currency_code: item.router_data.request.currency,
value: item.amount.clone(),
value: item.order_amount.clone().ok_or(
errors::ConnectorError::MissingRequiredField {
field_name: "order_amount",
},
)?,
},
tax_total: None,
shipping: Some(OrderAmount {
currency_code: item.router_data.request.currency,
value: item
.shipping_cost
.clone()
.unwrap_or(StringMajorUnit::zero()),
}),
},
}
})
}
}

Expand Down Expand Up @@ -153,6 +180,13 @@ impl TryFrom<&PaypalRouterData<&types::SdkSessionUpdateRouterData>> for OrderReq
},
)?,
}),
shipping: Some(OrderAmount {
currency_code: item.router_data.request.currency,
value: item
.shipping_cost
.clone()
.unwrap_or(StringMajorUnit::zero()),
}),
},
})
}
Expand All @@ -162,6 +196,7 @@ impl TryFrom<&PaypalRouterData<&types::SdkSessionUpdateRouterData>> for OrderReq
pub struct AmountBreakdown {
item_total: OrderAmount,
tax_total: Option<OrderAmount>,
shipping: Option<OrderAmount>,
}

#[derive(Default, Debug, Serialize, Eq, PartialEq)]
Expand Down Expand Up @@ -206,20 +241,27 @@ impl From<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for ItemDetail
}
}

impl From<&PaypalRouterData<&types::PaymentsPostSessionTokensRouterData>> for ItemDetails {
fn from(item: &PaypalRouterData<&types::PaymentsPostSessionTokensRouterData>) -> Self {
Self {
impl TryFrom<&PaypalRouterData<&types::PaymentsPostSessionTokensRouterData>> for ItemDetails {
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(
item: &PaypalRouterData<&types::PaymentsPostSessionTokensRouterData>,
) -> Result<Self, Self::Error> {
Ok(Self {
name: format!(
"Payment for invoice {}",
item.router_data.connector_request_reference_id
),
quantity: ORDER_QUANTITY,
unit_amount: OrderAmount {
currency_code: item.router_data.request.currency,
value: item.amount.clone(),
value: item.order_amount.clone().ok_or(
errors::ConnectorError::MissingRequiredField {
field_name: "order_amount",
},
)?,
},
tax: None,
}
})
}
}

Expand Down Expand Up @@ -549,12 +591,12 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsPostSessionTokensRouterData>>
PaypalAuthType::try_from(&item.router_data.connector_auth_type)?;
let payee = get_payee(&paypal_auth);

let amount = OrderRequestAmount::from(item);
let amount = OrderRequestAmount::try_from(item)?;
let connector_request_reference_id =
item.router_data.connector_request_reference_id.clone();

let shipping_address = ShippingAddress::from(item);
let item_details = vec![ItemDetails::from(item)];
let item_details = vec![ItemDetails::try_from(item)?];

let purchase_units = vec![PurchaseUnitRequest {
reference_id: Some(connector_request_reference_id.clone()),
Expand Down
11 changes: 9 additions & 2 deletions crates/router/src/core/payments/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ pub async fn construct_payment_router_data_for_authorize<'a>(
charges: None,
merchant_order_reference_id: None,
integrity_object: None,
shipping_cost: payment_data.payment_intent.amount_details.shipping_cost,
};

// TODO: evaluate the fields in router data, if they are required or not
Expand Down Expand Up @@ -2150,6 +2151,7 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsAuthoriz
.payment_intent
.merchant_order_reference_id
.clone();
let shipping_cost = payment_data.payment_intent.shipping_cost;

Ok(Self {
payment_method_data: (payment_method_data.get_required_value("payment_method_data")?),
Expand Down Expand Up @@ -2196,6 +2198,7 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsAuthoriz
charges,
merchant_order_reference_id,
integrity_object: None,
shipping_cost,
})
}
}
Expand Down Expand Up @@ -2534,11 +2537,12 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::SdkPaymentsSessi
+ shipping_cost
+ surcharge_amount;
Ok(Self {
net_amount,
amount: net_amount,
order_tax_amount,
currency: payment_data.currency,
amount: payment_data.payment_intent.amount,
order_amount: payment_data.payment_intent.amount,
session_id: payment_data.session_id,
shipping_cost: payment_data.payment_intent.shipping_cost,
})
}
}
Expand Down Expand Up @@ -2575,9 +2579,11 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsPostSess
.clone();
Ok(Self {
amount, //need to change after we move to connector module
order_amount: payment_data.payment_intent.amount,
currency: payment_data.currency,
merchant_order_reference_id,
capture_method: payment_data.payment_attempt.capture_method,
shipping_cost: payment_data.payment_intent.shipping_cost,
})
}
}
Expand Down Expand Up @@ -2770,6 +2776,7 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::SetupMandateRequ
| Some(RequestIncrementalAuthorization::Default)
),
metadata: payment_data.payment_intent.metadata.clone().map(Into::into),
shipping_cost: payment_data.payment_intent.shipping_cost,
})
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/router/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,7 @@ impl ForeignFrom<&SetupMandateRouterData> for PaymentsAuthorizeData {
charges: None, // TODO: allow charges on mandates?
merchant_order_reference_id: None,
integrity_object: None,
shipping_cost: data.request.shipping_cost,
}
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/router/src/types/api/verify_connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ impl VerifyConnectorData {
charges: None,
merchant_order_reference_id: None,
integrity_object: None,
shipping_cost: None,
}
}

Expand Down
1 change: 1 addition & 0 deletions crates/router/tests/connectors/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,7 @@ impl Default for PaymentAuthorizeType {
charges: None,
integrity_object: None,
merchant_order_reference_id: None,
shipping_cost: None,
};
Self(data)
}
Expand Down
Loading