Skip to content
Merged
106 changes: 87 additions & 19 deletions crates/hyperswitch_connectors/src/connectors/xendit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ use transformers::{self as xendit, XenditEventType, XenditWebhookEvent};
use crate::{
constants::headers,
types::ResponseRouterData,
utils as connector_utils,
utils::{self, PaymentMethodDataType, RefundsRequestData},
};

Expand Down Expand Up @@ -301,14 +302,27 @@ impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData
.response
.parse_struct("XenditPaymentResponse")
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

let response_integrity_object = connector_utils::get_authorise_integrity_object(
self.amount_converter,
response.amount,
response.currency.to_string().clone(),
)?;

event_builder.map(|i| i.set_response_body(&response));
router_env::logger::info!(connector_response=?response);

RouterData::try_from(ResponseRouterData {
let new_router_data = RouterData::try_from(ResponseRouterData {
response,
data: data.clone(),
http_code: res.status_code,
})
.change_context(errors::ConnectorError::ResponseHandlingFailed);

new_router_data.map(|mut router_data| {
router_data.request.integrity_object = Some(response_integrity_object);
router_data
})
}

fn get_error_response(
Expand Down Expand Up @@ -478,20 +492,38 @@ impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Xen
event_builder: Option<&mut ConnectorEvent>,
res: Response,
) -> CustomResult<PaymentsSyncRouterData, errors::ConnectorError> {
let response: xendit::XenditResponse =
res.response
.parse_struct("xendit XenditResponse")
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
let response: xendit::XenditResponse = res
.response
.clone()
.parse_struct("xendit XenditResponse")
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

let response_integrity_object = match response.clone() {
xendit::XenditResponse::Payment(p) => connector_utils::get_sync_integrity_object(
self.amount_converter,
p.amount,
p.currency.to_string().clone(),
),
xendit::XenditResponse::Webhook(p) => connector_utils::get_sync_integrity_object(
self.amount_converter,
p.data.amount,
p.data.currency.to_string().clone(),
),
};

event_builder.map(|i| i.set_response_body(&response));
router_env::logger::info!(connector_response=?response);

RouterData::try_from(ResponseRouterData {
let new_router_data = RouterData::try_from(ResponseRouterData {
response,
data: data.clone(),
http_code: res.status_code,
});
new_router_data.and_then(|mut router_data| {
let integrity_object = response_integrity_object?;
router_data.request.integrity_object = Some(integrity_object);
Ok(router_data)
})
.change_context(errors::ConnectorError::ResponseHandlingFailed)
}
}

Expand Down Expand Up @@ -599,15 +631,26 @@ impl ConnectorIntegration<Capture, PaymentsCaptureData, PaymentsResponseData> fo
.parse_struct("Xendit PaymentsResponse")
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

let response_integrity_object = connector_utils::get_capture_integrity_object(
self.amount_converter,
Some(response.amount),
response.currency.to_string().clone(),
)?;

event_builder.map(|i| i.set_response_body(&response));
router_env::logger::info!(connector_response=?response);

RouterData::try_from(ResponseRouterData {
let new_router_data = RouterData::try_from(ResponseRouterData {
response,
data: data.clone(),
http_code: res.status_code,
})
.change_context(errors::ConnectorError::ResponseHandlingFailed)
.change_context(errors::ConnectorError::ResponseHandlingFailed);

new_router_data.map(|mut router_data| {
router_data.request.integrity_object = Some(response_integrity_object);
router_data
})
}

fn get_error_response(
Expand Down Expand Up @@ -695,15 +738,27 @@ impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Xendit
.parse_struct("xendit RefundResponse")
.change_context(errors::ConnectorError::RequestEncodingFailed)?;

let response_integrity_object = connector_utils::get_refund_integrity_object(
self.amount_converter,
response.amount,
response.currency.to_string().clone(),
)?;

event_builder.map(|i| i.set_response_body(&response));
router_env::logger::info!(connector_response=?response);

RouterData::try_from(ResponseRouterData {
let new_router_data = RouterData::try_from(ResponseRouterData {
response,
data: data.clone(),
http_code: res.status_code,
})
.change_context(errors::ConnectorError::ResponseHandlingFailed)
});

new_router_data
.map(|mut router_data| {
router_data.request.integrity_object = Some(response_integrity_object);
router_data
})
.change_context(errors::ConnectorError::ResponseHandlingFailed)
}

fn get_error_response(
Expand Down Expand Up @@ -772,19 +827,32 @@ impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Xendit {
event_builder: Option<&mut ConnectorEvent>,
res: Response,
) -> CustomResult<RefundSyncRouterData, errors::ConnectorError> {
let response: xendit::RefundResponse =
res.response
.parse_struct("xendit RefundResponse")
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
let response: xendit::RefundResponse = res
.response
.clone()
.parse_struct("xendit RefundResponse")
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

let response_integrity_object = connector_utils::get_refund_integrity_object(
self.amount_converter,
response.amount,
response.currency.to_string().clone(),
)?;

event_builder.map(|i| i.set_response_body(&response));
router_env::logger::info!(connector_response=?response);
RouterData::try_from(ResponseRouterData {
let new_router_data = RouterData::try_from(ResponseRouterData {
response,
data: data.clone(),
http_code: res.status_code,
})
.change_context(errors::ConnectorError::ResponseHandlingFailed)
});

new_router_data
.map(|mut router_data| {
router_data.request.integrity_object = Some(response_integrity_object);
router_data
})
.change_context(errors::ConnectorError::ResponseHandlingFailed)
}

fn get_error_response(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::collections::HashMap;

use cards::CardNumber;
use common_enums::enums;
use common_enums::{enums, Currency};
use common_utils::{pii, request::Method, types::FloatMajorUnit};
use hyperswitch_domain_models::{
payment_method_data::PaymentMethodData,
Expand Down Expand Up @@ -65,7 +65,7 @@ pub struct CardPaymentRequest {
#[derive(Serialize, Deserialize, Debug)]
pub struct MandatePaymentRequest {
pub amount: FloatMajorUnit,
pub currency: common_enums::Currency,
pub currency: Currency,
pub capture_method: String,
pub payment_method_id: Secret<String>,
pub channel_properties: ChannelProperties,
Expand All @@ -81,7 +81,7 @@ pub struct XenditPaymentsCaptureRequest {
#[derive(Serialize, Deserialize, Debug)]
pub struct XenditPaymentsRequest {
pub amount: FloatMajorUnit,
pub currency: common_enums::Currency,
pub currency: Currency,
pub capture_method: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub payment_method: Option<PaymentMethod>,
Expand All @@ -97,7 +97,7 @@ pub struct XenditSplitRoute {
pub flat_amount: Option<FloatMajorUnit>,
#[serde(skip_serializing_if = "Option::is_none")]
pub percent_amount: Option<i64>,
pub currency: enums::Currency,
pub currency: Currency,
pub destination_account_id: String,
pub reference_id: String,
}
Expand Down Expand Up @@ -164,7 +164,7 @@ pub enum PaymentStatus {
AwaitingCapture,
Verified,
}
#[derive(Debug, Deserialize, Serialize)]
#[derive(Debug, Deserialize, Serialize, Clone)]
#[serde(untagged)]
pub enum XenditResponse {
Payment(XenditPaymentResponse),
Expand All @@ -178,6 +178,8 @@ pub struct XenditPaymentResponse {
pub payment_method: PaymentMethodInfo,
pub failure_code: Option<String>,
pub reference_id: Secret<String>,
pub amount: FloatMajorUnit,
pub currency: Currency,
}

fn map_payment_response_to_attempt_status(
Expand Down Expand Up @@ -502,7 +504,7 @@ impl<F>
common_utils::types::AmountConvertor::convert_back(
&required_conversion_type,
amount,
item.data.request.currency.unwrap_or(enums::Currency::USD),
item.data.request.currency.unwrap_or(Currency::USD),
)
.map_err(|_| {
errors::ConnectorError::RequestEncodingFailedWithReason(
Expand Down Expand Up @@ -660,7 +662,7 @@ impl TryFrom<&PaymentsPreProcessingRouterData> for XenditSplitRequestData {
common_utils::types::AmountConvertor::convert(
&required_conversion_type,
amount,
item.request.currency.unwrap_or(enums::Currency::USD),
item.request.currency.unwrap_or(Currency::USD),
)
.map_err(|_| {
errors::ConnectorError::RequestEncodingFailedWithReason(
Expand Down Expand Up @@ -739,8 +741,10 @@ impl From<RefundStatus> for enums::RefundStatus {
//TODO: Fill the struct with respective fields
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RefundResponse {
id: String,
status: RefundStatus,
pub id: String,
pub status: RefundStatus,
pub amount: FloatMajorUnit,
pub currency: String,
}

impl TryFrom<RefundsResponseRouterData<Execute, RefundResponse>> for RefundsRouterData<Execute> {
Expand Down Expand Up @@ -777,20 +781,22 @@ impl TryFrom<RefundsResponseRouterData<RSync, RefundResponse>> for RefundsRouter
pub struct XenditMetadata {
pub for_user_id: String,
}
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct XenditWebhookEvent {
pub event: XenditEventType,
pub data: EventDetails,
}

#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct EventDetails {
pub id: String,
pub payment_request_id: Option<String>,
pub amount: FloatMajorUnit,
pub currency: String,
}
Comment on lines +795 to 797
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are we sure about this as required fields @deepanshu-iiitu can you please check and confirm

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

currency should be an enum of Currency, correcting it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you please test end to end!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have tested the flows, added them in the PR description as well

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay sure! but you are sure about the required fields from connector end right. We don't want a deserialization error

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum XenditEventType {
#[serde(rename = "payment.succeeded")]
PaymentSucceeded,
Expand Down
Loading
Loading