Skip to content

Commit 5c37952

Browse files
author
Aniket Burman
committed
Record back
1 parent 13c621a commit 5c37952

File tree

4 files changed

+194
-3
lines changed

4 files changed

+194
-3
lines changed

crates/hyperswitch_connectors/src/connectors/recurly.rs

+103-2
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,11 @@ use masking::{ExposeInterface, Mask};
4040
use transformers as recurly;
4141

4242
use crate::{constants::headers, types::ResponseRouterData, utils};
43-
43+
use hyperswitch_domain_models::types::RevenueRecoveryRecordBackRouterData;
44+
use hyperswitch_domain_models::router_flow_types::RecoveryRecordBack;
45+
use hyperswitch_domain_models::router_request_types::revenue_recovery::RevenueRecoveryRecordBackRequest;
46+
use hyperswitch_domain_models::router_response_types::revenue_recovery::RevenueRecoveryRecordBackResponse;
47+
use crate::connectors::recurly::transformers::RecurlyRecordStatus;
4448
#[derive(Clone)]
4549
pub struct Recurly {
4650
amount_converter: &'static (dyn AmountConvertor<Output = StringMinorUnit> + Sync),
@@ -66,7 +70,8 @@ impl api::Refund for Recurly {}
6670
impl api::RefundExecute for Recurly {}
6771
impl api::RefundSync for Recurly {}
6872
impl api::PaymentToken for Recurly {}
69-
73+
#[cfg(all(feature = "v2", feature = "revenue_recovery"))]
74+
impl api::revenue_recovery::RevenueRecoveryRecordBack for Recurly {}
7075
impl ConnectorIntegration<PaymentMethodToken, PaymentMethodTokenizationData, PaymentsResponseData>
7176
for Recurly
7277
{
@@ -541,6 +546,102 @@ impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Recurly {
541546
}
542547
}
543548

549+
impl
550+
ConnectorIntegration<
551+
RecoveryRecordBack,
552+
RevenueRecoveryRecordBackRequest,
553+
RevenueRecoveryRecordBackResponse,
554+
> for Recurly
555+
{
556+
fn get_headers(
557+
&self,
558+
req: &RevenueRecoveryRecordBackRouterData,
559+
connectors: &Connectors,
560+
) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
561+
self.build_headers(req, connectors)
562+
}
563+
fn get_url(
564+
&self,
565+
req: &RevenueRecoveryRecordBackRouterData,
566+
connectors: &Connectors,
567+
) -> CustomResult<String, errors::ConnectorError> {
568+
let invoice_id = req
569+
.request
570+
.merchant_reference_id
571+
.get_string_repr()
572+
.to_string();
573+
574+
let status = RecurlyRecordStatus::try_from(req.request.attempt_status)
575+
.map_err(|_| errors::ConnectorError::NotSupported {
576+
message: "Invalid attempt status for Recurly".to_string(),
577+
connector: "recurly",
578+
})?;
579+
580+
581+
let status_endpoint = match status {
582+
RecurlyRecordStatus::Success => "mark_successful",
583+
RecurlyRecordStatus::Failure => "mark_failed",
584+
};
585+
586+
Ok(format!(
587+
"{}/invoices/{}/{}",
588+
self.base_url(connectors),
589+
invoice_id,
590+
status_endpoint
591+
))
592+
}
593+
594+
fn get_content_type(&self) -> &'static str {
595+
self.common_get_content_type()
596+
}
597+
598+
fn build_request(
599+
&self,
600+
req: &RevenueRecoveryRecordBackRouterData,
601+
connectors: &Connectors,
602+
) -> CustomResult<Option<Request>, errors::ConnectorError> {
603+
Ok(Some(
604+
RequestBuilder::new()
605+
.method(Method::Put)
606+
.url(&types::RevenueRecoveryRecordBackType::get_url(
607+
self, req, connectors,
608+
)?)
609+
.attach_default_headers()
610+
.headers(types::RevenueRecoveryRecordBackType::get_headers(
611+
self, req, connectors,
612+
)?)
613+
.build(),
614+
))
615+
}
616+
617+
fn handle_response(
618+
&self,
619+
data: &RevenueRecoveryRecordBackRouterData,
620+
event_builder: Option<&mut ConnectorEvent>,
621+
res: Response,
622+
) -> CustomResult<RevenueRecoveryRecordBackRouterData, errors::ConnectorError> {
623+
let response: recurly::RecurlyRecordbackResponse = res
624+
.response
625+
.parse_struct("recurly RecurlyRecordbackResponse")
626+
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
627+
event_builder.map(|i| i.set_response_body(&response));
628+
router_env::logger::info!(connector_response=?response);
629+
RouterData::try_from(ResponseRouterData {
630+
response,
631+
data: data.clone(),
632+
http_code: res.status_code,
633+
})
634+
}
635+
636+
fn get_error_response(
637+
&self,
638+
res: Response,
639+
event_builder: Option<&mut ConnectorEvent>,
640+
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
641+
self.build_error_response(res, event_builder)
642+
}
643+
}
644+
544645
#[async_trait::async_trait]
545646
impl webhooks::IncomingWebhook for Recurly {
546647
fn get_webhook_object_reference_id(

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

+89
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ use crate::{
1616
types::{RefundsResponseRouterData, ResponseRouterData},
1717
utils::PaymentsAuthorizeRequestData,
1818
};
19+
use hyperswitch_domain_models::router_flow_types::RecoveryRecordBack;
20+
use hyperswitch_domain_models::router_request_types::revenue_recovery::RevenueRecoveryRecordBackRequest;
21+
use hyperswitch_domain_models::router_response_types::revenue_recovery::RevenueRecoveryRecordBackResponse;
22+
use hyperswitch_domain_models::types::RevenueRecoveryRecordBackRouterData;
1923

2024
//TODO: Fill the struct with respective fields
2125
pub struct RecurlyRouterData<T> {
@@ -226,3 +230,88 @@ pub struct RecurlyErrorResponse {
226230
pub message: String,
227231
pub reason: Option<String>,
228232
}
233+
234+
#[derive(Debug, Serialize, Clone, Copy)]
235+
#[serde(rename_all = "snake_case")]
236+
pub enum RecurlyRecordStatus {
237+
Success,
238+
Failure,
239+
}
240+
241+
#[cfg(all(feature = "v2", feature = "revenue_recovery"))]
242+
impl TryFrom<enums::AttemptStatus> for RecurlyRecordStatus {
243+
type Error = error_stack::Report<errors::ConnectorError>;
244+
fn try_from(status: enums::AttemptStatus) -> Result<Self, Self::Error> {
245+
match status {
246+
enums::AttemptStatus::Charged
247+
| enums::AttemptStatus::PartialCharged
248+
| enums::AttemptStatus::PartialChargedAndChargeable => Ok(Self::Success),
249+
enums::AttemptStatus::Failure
250+
| enums::AttemptStatus::CaptureFailed
251+
| enums::AttemptStatus::RouterDeclined => Ok(Self::Failure),
252+
enums::AttemptStatus::AuthenticationFailed
253+
| enums::AttemptStatus::Started
254+
| enums::AttemptStatus::AuthenticationPending
255+
| enums::AttemptStatus::AuthenticationSuccessful
256+
| enums::AttemptStatus::Authorized
257+
| enums::AttemptStatus::AuthorizationFailed
258+
| enums::AttemptStatus::Authorizing
259+
| enums::AttemptStatus::CodInitiated
260+
| enums::AttemptStatus::Voided
261+
| enums::AttemptStatus::VoidInitiated
262+
| enums::AttemptStatus::CaptureInitiated
263+
| enums::AttemptStatus::VoidFailed
264+
| enums::AttemptStatus::AutoRefunded
265+
| enums::AttemptStatus::Unresolved
266+
| enums::AttemptStatus::Pending
267+
| enums::AttemptStatus::PaymentMethodAwaited
268+
| enums::AttemptStatus::ConfirmationAwaited
269+
| enums::AttemptStatus::DeviceDataCollectionPending => {
270+
Err(errors::ConnectorError::NotSupported {
271+
message: "Record back flow is only supported for terminal status".to_string(),
272+
connector: "recurly",
273+
}
274+
.into())
275+
}
276+
}
277+
}
278+
}
279+
280+
#[derive(Debug, Deserialize, Serialize, Clone)]
281+
pub struct RecurlyRecordbackResponse {
282+
pub invoice: RecurlyRecordbackInvoice,
283+
}
284+
285+
#[derive(Debug, Deserialize, Serialize, Clone)]
286+
pub struct RecurlyRecordbackInvoice {
287+
pub id: common_utils::id_type::PaymentReferenceId,
288+
}
289+
290+
impl
291+
TryFrom<
292+
ResponseRouterData<
293+
RecoveryRecordBack,
294+
RecurlyRecordbackResponse,
295+
RevenueRecoveryRecordBackRequest,
296+
RevenueRecoveryRecordBackResponse,
297+
>,
298+
> for RevenueRecoveryRecordBackRouterData
299+
{
300+
type Error = error_stack::Report<errors::ConnectorError>;
301+
fn try_from(
302+
item: ResponseRouterData<
303+
RecoveryRecordBack,
304+
RecurlyRecordbackResponse,
305+
RevenueRecoveryRecordBackRequest,
306+
RevenueRecoveryRecordBackResponse,
307+
>,
308+
) -> Result<Self, Self::Error> {
309+
let merchant_reference_id = item.response.invoice.id;
310+
Ok(Self {
311+
response: Ok(RevenueRecoveryRecordBackResponse {
312+
merchant_reference_id,
313+
}),
314+
..item.data
315+
})
316+
}
317+
}

crates/hyperswitch_connectors/src/default_implementations.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3678,7 +3678,7 @@ default_imp_for_revenue_recovery_record_back!(
36783678
connectors::Placetopay,
36793679
connectors::Rapyd,
36803680
connectors::Razorpay,
3681-
connectors::Recurly,
3681+
// connectors::Recurly,
36823682
connectors::Redsys,
36833683
connectors::Shift4,
36843684
connectors::Stax,
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
pub struct GetAdditionalRevenueRecoveryDetails;
2+
#[derive(Clone)]
23
pub struct RecoveryRecordBack;

0 commit comments

Comments
 (0)