Skip to content

Commit caa0723

Browse files
bsayak03Sayak Bhattacharyahyperswitch-bot[bot]
authored
feat(connector): [XENDIT] Added Integrity Check for Authorize, Capture, Refund & RSync flows (#8049)
Co-authored-by: Sayak Bhattacharya <[email protected]> Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
1 parent 9f9fef4 commit caa0723

File tree

4 files changed

+173
-100
lines changed

4 files changed

+173
-100
lines changed

crates/hyperswitch_connectors/src/connectors/xendit.rs

Lines changed: 87 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ use transformers::{self as xendit, XenditEventType, XenditWebhookEvent};
5757
use crate::{
5858
constants::headers,
5959
types::ResponseRouterData,
60+
utils as connector_utils,
6061
utils::{self, PaymentMethodDataType, RefundsRequestData},
6162
};
6263

@@ -301,14 +302,27 @@ impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData
301302
.response
302303
.parse_struct("XenditPaymentResponse")
303304
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
305+
306+
let response_integrity_object = connector_utils::get_authorise_integrity_object(
307+
self.amount_converter,
308+
response.amount,
309+
response.currency.to_string().clone(),
310+
)?;
311+
304312
event_builder.map(|i| i.set_response_body(&response));
305313
router_env::logger::info!(connector_response=?response);
306314

307-
RouterData::try_from(ResponseRouterData {
315+
let new_router_data = RouterData::try_from(ResponseRouterData {
308316
response,
309317
data: data.clone(),
310318
http_code: res.status_code,
311319
})
320+
.change_context(errors::ConnectorError::ResponseHandlingFailed);
321+
322+
new_router_data.map(|mut router_data| {
323+
router_data.request.integrity_object = Some(response_integrity_object);
324+
router_data
325+
})
312326
}
313327

314328
fn get_error_response(
@@ -478,20 +492,38 @@ impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Xen
478492
event_builder: Option<&mut ConnectorEvent>,
479493
res: Response,
480494
) -> CustomResult<PaymentsSyncRouterData, errors::ConnectorError> {
481-
let response: xendit::XenditResponse =
482-
res.response
483-
.parse_struct("xendit XenditResponse")
484-
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
495+
let response: xendit::XenditResponse = res
496+
.response
497+
.clone()
498+
.parse_struct("xendit XenditResponse")
499+
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
500+
501+
let response_integrity_object = match response.clone() {
502+
xendit::XenditResponse::Payment(p) => connector_utils::get_sync_integrity_object(
503+
self.amount_converter,
504+
p.amount,
505+
p.currency.to_string().clone(),
506+
),
507+
xendit::XenditResponse::Webhook(p) => connector_utils::get_sync_integrity_object(
508+
self.amount_converter,
509+
p.data.amount,
510+
p.data.currency.to_string().clone(),
511+
),
512+
};
485513

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

489-
RouterData::try_from(ResponseRouterData {
517+
let new_router_data = RouterData::try_from(ResponseRouterData {
490518
response,
491519
data: data.clone(),
492520
http_code: res.status_code,
521+
});
522+
new_router_data.and_then(|mut router_data| {
523+
let integrity_object = response_integrity_object?;
524+
router_data.request.integrity_object = Some(integrity_object);
525+
Ok(router_data)
493526
})
494-
.change_context(errors::ConnectorError::ResponseHandlingFailed)
495527
}
496528
}
497529

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

634+
let response_integrity_object = connector_utils::get_capture_integrity_object(
635+
self.amount_converter,
636+
Some(response.amount),
637+
response.currency.to_string().clone(),
638+
)?;
639+
602640
event_builder.map(|i| i.set_response_body(&response));
603641
router_env::logger::info!(connector_response=?response);
604642

605-
RouterData::try_from(ResponseRouterData {
643+
let new_router_data = RouterData::try_from(ResponseRouterData {
606644
response,
607645
data: data.clone(),
608646
http_code: res.status_code,
609647
})
610-
.change_context(errors::ConnectorError::ResponseHandlingFailed)
648+
.change_context(errors::ConnectorError::ResponseHandlingFailed);
649+
650+
new_router_data.map(|mut router_data| {
651+
router_data.request.integrity_object = Some(response_integrity_object);
652+
router_data
653+
})
611654
}
612655

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

741+
let response_integrity_object = connector_utils::get_refund_integrity_object(
742+
self.amount_converter,
743+
response.amount,
744+
response.currency.to_string().clone(),
745+
)?;
746+
698747
event_builder.map(|i| i.set_response_body(&response));
699748
router_env::logger::info!(connector_response=?response);
700749

701-
RouterData::try_from(ResponseRouterData {
750+
let new_router_data = RouterData::try_from(ResponseRouterData {
702751
response,
703752
data: data.clone(),
704753
http_code: res.status_code,
705-
})
706-
.change_context(errors::ConnectorError::ResponseHandlingFailed)
754+
});
755+
756+
new_router_data
757+
.map(|mut router_data| {
758+
router_data.request.integrity_object = Some(response_integrity_object);
759+
router_data
760+
})
761+
.change_context(errors::ConnectorError::ResponseHandlingFailed)
707762
}
708763

709764
fn get_error_response(
@@ -772,19 +827,32 @@ impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Xendit {
772827
event_builder: Option<&mut ConnectorEvent>,
773828
res: Response,
774829
) -> CustomResult<RefundSyncRouterData, errors::ConnectorError> {
775-
let response: xendit::RefundResponse =
776-
res.response
777-
.parse_struct("xendit RefundResponse")
778-
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
830+
let response: xendit::RefundResponse = res
831+
.response
832+
.clone()
833+
.parse_struct("xendit RefundResponse")
834+
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
835+
836+
let response_integrity_object = connector_utils::get_refund_integrity_object(
837+
self.amount_converter,
838+
response.amount,
839+
response.currency.to_string().clone(),
840+
)?;
779841

780842
event_builder.map(|i| i.set_response_body(&response));
781843
router_env::logger::info!(connector_response=?response);
782-
RouterData::try_from(ResponseRouterData {
844+
let new_router_data = RouterData::try_from(ResponseRouterData {
783845
response,
784846
data: data.clone(),
785847
http_code: res.status_code,
786-
})
787-
.change_context(errors::ConnectorError::ResponseHandlingFailed)
848+
});
849+
850+
new_router_data
851+
.map(|mut router_data| {
852+
router_data.request.integrity_object = Some(response_integrity_object);
853+
router_data
854+
})
855+
.change_context(errors::ConnectorError::ResponseHandlingFailed)
788856
}
789857

790858
fn get_error_response(

crates/hyperswitch_connectors/src/connectors/xendit/transformers.rs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::collections::HashMap;
22

33
use cards::CardNumber;
4-
use common_enums::enums;
4+
use common_enums::{enums, Currency};
55
use common_utils::{pii, request::Method, types::FloatMajorUnit};
66
use hyperswitch_domain_models::{
77
payment_method_data::PaymentMethodData,
@@ -65,7 +65,7 @@ pub struct CardPaymentRequest {
6565
#[derive(Serialize, Deserialize, Debug)]
6666
pub struct MandatePaymentRequest {
6767
pub amount: FloatMajorUnit,
68-
pub currency: common_enums::Currency,
68+
pub currency: Currency,
6969
pub capture_method: String,
7070
pub payment_method_id: Secret<String>,
7171
pub channel_properties: ChannelProperties,
@@ -81,7 +81,7 @@ pub struct XenditPaymentsCaptureRequest {
8181
#[derive(Serialize, Deserialize, Debug)]
8282
pub struct XenditPaymentsRequest {
8383
pub amount: FloatMajorUnit,
84-
pub currency: common_enums::Currency,
84+
pub currency: Currency,
8585
pub capture_method: String,
8686
#[serde(skip_serializing_if = "Option::is_none")]
8787
pub payment_method: Option<PaymentMethod>,
@@ -97,7 +97,7 @@ pub struct XenditSplitRoute {
9797
pub flat_amount: Option<FloatMajorUnit>,
9898
#[serde(skip_serializing_if = "Option::is_none")]
9999
pub percent_amount: Option<i64>,
100-
pub currency: enums::Currency,
100+
pub currency: Currency,
101101
pub destination_account_id: String,
102102
pub reference_id: String,
103103
}
@@ -164,7 +164,7 @@ pub enum PaymentStatus {
164164
AwaitingCapture,
165165
Verified,
166166
}
167-
#[derive(Debug, Deserialize, Serialize)]
167+
#[derive(Debug, Deserialize, Serialize, Clone)]
168168
#[serde(untagged)]
169169
pub enum XenditResponse {
170170
Payment(XenditPaymentResponse),
@@ -178,6 +178,8 @@ pub struct XenditPaymentResponse {
178178
pub payment_method: PaymentMethodInfo,
179179
pub failure_code: Option<String>,
180180
pub reference_id: Secret<String>,
181+
pub amount: FloatMajorUnit,
182+
pub currency: Currency,
181183
}
182184

183185
fn map_payment_response_to_attempt_status(
@@ -502,7 +504,7 @@ impl<F>
502504
common_utils::types::AmountConvertor::convert_back(
503505
&required_conversion_type,
504506
amount,
505-
item.data.request.currency.unwrap_or(enums::Currency::USD),
507+
item.data.request.currency.unwrap_or(Currency::USD),
506508
)
507509
.map_err(|_| {
508510
errors::ConnectorError::RequestEncodingFailedWithReason(
@@ -660,7 +662,7 @@ impl TryFrom<&PaymentsPreProcessingRouterData> for XenditSplitRequestData {
660662
common_utils::types::AmountConvertor::convert(
661663
&required_conversion_type,
662664
amount,
663-
item.request.currency.unwrap_or(enums::Currency::USD),
665+
item.request.currency.unwrap_or(Currency::USD),
664666
)
665667
.map_err(|_| {
666668
errors::ConnectorError::RequestEncodingFailedWithReason(
@@ -739,8 +741,10 @@ impl From<RefundStatus> for enums::RefundStatus {
739741
//TODO: Fill the struct with respective fields
740742
#[derive(Debug, Clone, Serialize, Deserialize)]
741743
pub struct RefundResponse {
742-
id: String,
743-
status: RefundStatus,
744+
pub id: String,
745+
pub status: RefundStatus,
746+
pub amount: FloatMajorUnit,
747+
pub currency: String,
744748
}
745749

746750
impl TryFrom<RefundsResponseRouterData<Execute, RefundResponse>> for RefundsRouterData<Execute> {
@@ -777,20 +781,22 @@ impl TryFrom<RefundsResponseRouterData<RSync, RefundResponse>> for RefundsRouter
777781
pub struct XenditMetadata {
778782
pub for_user_id: String,
779783
}
780-
#[derive(Debug, Serialize, Deserialize)]
784+
#[derive(Debug, Serialize, Deserialize, Clone)]
781785
#[serde(rename_all = "camelCase")]
782786
pub struct XenditWebhookEvent {
783787
pub event: XenditEventType,
784788
pub data: EventDetails,
785789
}
786790

787-
#[derive(Debug, Serialize, Deserialize)]
791+
#[derive(Debug, Serialize, Deserialize, Clone)]
788792
pub struct EventDetails {
789793
pub id: String,
790794
pub payment_request_id: Option<String>,
795+
pub amount: FloatMajorUnit,
796+
pub currency: String,
791797
}
792798

793-
#[derive(Debug, Serialize, Deserialize)]
799+
#[derive(Debug, Serialize, Deserialize, Clone)]
794800
pub enum XenditEventType {
795801
#[serde(rename = "payment.succeeded")]
796802
PaymentSucceeded,

0 commit comments

Comments
 (0)