Skip to content

Commit cf92e1a

Browse files
authored
feat(connector): [jpmorgan] implement refund flow (#8436)
1 parent 46709ae commit cf92e1a

File tree

3 files changed

+59
-72
lines changed

3 files changed

+59
-72
lines changed

crates/hyperswitch_connectors/src/connectors/jpmorgan.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -665,9 +665,9 @@ impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Jpmorga
665665
fn get_url(
666666
&self,
667667
_req: &RefundsRouterData<Execute>,
668-
_connectors: &Connectors,
668+
connectors: &Connectors,
669669
) -> CustomResult<String, errors::ConnectorError> {
670-
Err(errors::ConnectorError::NotImplemented("Refunds".to_string()).into())
670+
Ok(format!("{}/refunds", self.base_url(connectors)))
671671
}
672672

673673
fn get_request_body(

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

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -272,18 +272,10 @@ pub struct JpmorganPaymentsResponse {
272272
#[serde(rename_all = "camelCase")]
273273
pub struct Merchant {
274274
merchant_id: Option<String>,
275-
merchant_software: MerchantSoftware,
275+
merchant_software: JpmorganMerchantSoftware,
276276
merchant_category_code: Option<String>,
277277
}
278278

279-
#[derive(Default, Debug, Serialize, Deserialize)]
280-
#[serde(rename_all = "camelCase")]
281-
pub struct MerchantSoftware {
282-
company_name: Secret<String>,
283-
product_name: Secret<String>,
284-
version: Option<Secret<String>>,
285-
}
286-
287279
#[derive(Default, Debug, Deserialize, Serialize)]
288280
#[serde(rename_all = "camelCase")]
289281
pub struct PaymentMethodType {
@@ -522,18 +514,31 @@ pub struct TransactionData {
522514
pub struct JpmorganRefundRequest {
523515
pub merchant: MerchantRefundReq,
524516
pub amount: MinorUnit,
517+
pub currency: common_enums::Currency,
525518
}
526519

527520
#[derive(Default, Debug, Serialize, Deserialize)]
528521
#[serde(rename_all = "camelCase")]
529522
pub struct MerchantRefundReq {
530-
pub merchant_software: MerchantSoftware,
523+
pub merchant_software: JpmorganMerchantSoftware,
531524
}
532525

533526
impl<F> TryFrom<&JpmorganRouterData<&RefundsRouterData<F>>> for JpmorganRefundRequest {
534527
type Error = error_stack::Report<errors::ConnectorError>;
535-
fn try_from(_item: &JpmorganRouterData<&RefundsRouterData<F>>) -> Result<Self, Self::Error> {
536-
Err(errors::ConnectorError::NotImplemented("Refunds".to_string()).into())
528+
fn try_from(item: &JpmorganRouterData<&RefundsRouterData<F>>) -> Result<Self, Self::Error> {
529+
let merchant_software = JpmorganMerchantSoftware {
530+
company_name: String::from("JPMC").into(),
531+
product_name: String::from("Hyperswitch").into(),
532+
};
533+
let merchant = MerchantRefundReq { merchant_software };
534+
let amount = item.amount;
535+
let currency = item.router_data.request.currency;
536+
537+
Ok(Self {
538+
merchant,
539+
amount,
540+
currency,
541+
})
537542
}
538543
}
539544

@@ -552,7 +557,6 @@ pub struct JpmorganRefundResponse {
552557
pub remaining_refundable_amount: Option<i64>,
553558
}
554559

555-
#[allow(dead_code)]
556560
#[derive(Debug, Serialize, Default, Deserialize, Clone)]
557561
pub enum RefundStatus {
558562
Succeeded,
@@ -571,24 +575,23 @@ impl From<RefundStatus> for common_enums::RefundStatus {
571575
}
572576
}
573577

574-
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
575-
pub struct RefundResponse {
576-
id: String,
577-
status: RefundStatus,
578-
}
579-
580-
pub fn refund_status_from_transaction_state(
581-
transaction_state: JpmorganTransactionState,
582-
) -> common_enums::RefundStatus {
583-
match transaction_state {
584-
JpmorganTransactionState::Voided | JpmorganTransactionState::Closed => {
585-
common_enums::RefundStatus::Success
586-
}
587-
JpmorganTransactionState::Declined | JpmorganTransactionState::Error => {
588-
common_enums::RefundStatus::Failure
589-
}
590-
JpmorganTransactionState::Pending | JpmorganTransactionState::Authorized => {
591-
common_enums::RefundStatus::Pending
578+
impl From<(JpmorganResponseStatus, JpmorganTransactionState)> for RefundStatus {
579+
fn from(
580+
(response_status, transaction_state): (JpmorganResponseStatus, JpmorganTransactionState),
581+
) -> Self {
582+
match response_status {
583+
JpmorganResponseStatus::Success => match transaction_state {
584+
JpmorganTransactionState::Voided | JpmorganTransactionState::Closed => {
585+
Self::Succeeded
586+
}
587+
JpmorganTransactionState::Declined | JpmorganTransactionState::Error => {
588+
Self::Failed
589+
}
590+
JpmorganTransactionState::Pending | JpmorganTransactionState::Authorized => {
591+
Self::Processing
592+
}
593+
},
594+
JpmorganResponseStatus::Denied | JpmorganResponseStatus::Error => Self::Failed,
592595
}
593596
}
594597
}
@@ -607,9 +610,11 @@ impl TryFrom<RefundsResponseRouterData<Execute, JpmorganRefundResponse>>
607610
.transaction_id
608611
.clone()
609612
.ok_or(errors::ConnectorError::ResponseHandlingFailed)?,
610-
refund_status: refund_status_from_transaction_state(
613+
refund_status: RefundStatus::from((
614+
item.response.response_status,
611615
item.response.transaction_state,
612-
),
616+
))
617+
.into(),
613618
}),
614619
..item.data
615620
})
@@ -638,9 +643,11 @@ impl TryFrom<RefundsResponseRouterData<RSync, JpmorganRefundSyncResponse>>
638643
Ok(Self {
639644
response: Ok(RefundsResponseData {
640645
connector_refund_id: item.response.transaction_id.clone(),
641-
refund_status: refund_status_from_transaction_state(
646+
refund_status: RefundStatus::from((
647+
item.response.response_status,
642648
item.response.transaction_state,
643-
),
649+
))
650+
.into(),
644651
}),
645652
..item.data
646653
})

cypress-tests/cypress/e2e/configs/Payment/Jpmorgan.js

Lines changed: 15 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -200,79 +200,59 @@ export const connectorDetails = {
200200
Void: voidCase,
201201
VoidAfterConfirm: voidCase,
202202
Refund: {
203-
Configs: {
204-
TRIGGER_SKIP: true,
205-
},
206203
Request: {
207204
amount: 6000,
208205
},
209206
Response: {
210-
status: 501,
207+
status: 200,
211208
body: {
212-
type: "invalid_request",
213-
message: "Refunds is not implemented",
214-
code: "IR_00",
209+
reason: "FRAUD",
210+
status: "pending",
215211
},
216212
},
217213
},
218214
manualPaymentRefund: {
219-
Configs: {
220-
TRIGGER_SKIP: true,
221-
},
222215
Request: {
223216
amount: 6000,
224217
},
225218
Response: {
226-
status: 501,
219+
status: 200,
227220
body: {
228-
type: "invalid_request",
229-
message: "Refunds is not implemented",
230-
code: "IR_00",
221+
reason: "FRAUD",
222+
status: "pending",
231223
},
232224
},
233225
},
234226
manualPaymentPartialRefund: {
235-
Configs: {
236-
TRIGGER_SKIP: true,
237-
},
238227
Request: {
239228
amount: 2000,
240229
},
241230
Response: {
242-
status: 501,
231+
status: 200,
243232
body: {
244-
type: "invalid_request",
245-
message: "Refunds is not implemented",
246-
code: "IR_00",
233+
reason: "FRAUD",
234+
status: "pending",
247235
},
248236
},
249237
},
250238
PartialRefund: {
251-
Configs: {
252-
TRIGGER_SKIP: true,
253-
},
254239
Request: {
255240
amount: 2000,
256241
},
257242
Response: {
258-
status: 501,
243+
status: 200,
259244
body: {
260-
type: "invalid_request",
261-
message: "Refunds is not implemented",
262-
code: "IR_00",
245+
reason: "FRAUD",
246+
status: "pending",
263247
},
264248
},
265249
},
266250
SyncRefund: {
267-
Configs: {
268-
TRIGGER_SKIP: true,
269-
},
270251
Response: {
271-
status: 404,
252+
status: 200,
272253
body: {
273-
type: "invalid_request",
274-
message: "Refund does not exist in our records.",
275-
code: "HE_02",
254+
reason: "FRAUD",
255+
status: "succeeded",
276256
},
277257
},
278258
},

0 commit comments

Comments
 (0)