Skip to content

Commit

Permalink
refactor(connector): [Paypal] Add support for passing shipping_cost i…
Browse files Browse the repository at this point in the history
…n Payment request (#6423)
  • Loading branch information
swangi-kumari authored Oct 25, 2024
1 parent 4647a2f commit b0d5c96
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 24 deletions.
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

0 comments on commit b0d5c96

Please sign in to comment.