diff --git a/crates/router/src/connector/checkout.rs b/crates/router/src/connector/checkout.rs index 23e9442e92..6165038f34 100644 --- a/crates/router/src/connector/checkout.rs +++ b/crates/router/src/connector/checkout.rs @@ -271,50 +271,92 @@ impl { fn get_headers( &self, - _req: &types::PaymentsCancelRouterData, + req: &types::PaymentsCancelRouterData, ) -> CustomResult, errors::ConnectorError> { - Err(errors::ConnectorError::NotImplemented("checkout".to_string()).into()) - } - - fn get_content_type(&self) -> &'static str { - "" + let mut header = vec![ + ( + headers::CONTENT_TYPE.to_string(), + types::PaymentsVoidType::get_content_type(self).to_string(), + ), + (headers::X_ROUTER.to_string(), "test".to_string()), + ]; + let mut api_key = self.get_auth_header(&req.connector_auth_type)?; + header.append(&mut api_key); + Ok(header) } fn get_url( &self, - _req: &types::PaymentsCancelRouterData, - _connectors: Connectors, + req: &types::PaymentsCancelRouterData, + connectors: Connectors, ) -> CustomResult { - Err(errors::ConnectorError::NotImplemented("checkout".to_string()).into()) + Ok(format!( + "{}payments/{}/voids", + self.base_url(connectors), + &req.request.connector_transaction_id + )) } fn get_request_body( &self, - _req: &types::PaymentsCancelRouterData, + req: &types::PaymentsCancelRouterData, ) -> CustomResult, errors::ConnectorError> { - Err(errors::ConnectorError::NotImplemented("checkout".to_string()).into()) + let checkout_req = utils::Encode::::convert_and_encode(req) + .change_context(errors::ConnectorError::RequestEncodingFailed)?; + Ok(Some(checkout_req)) } fn build_request( &self, - _req: &types::PaymentsCancelRouterData, - _connectors: Connectors, + req: &types::PaymentsCancelRouterData, + connectors: Connectors, ) -> CustomResult, errors::ConnectorError> { - Err(errors::ConnectorError::NotImplemented("checkout".to_string()).into()) + Ok(Some( + services::RequestBuilder::new() + .method(services::Method::Post) + .url(&types::PaymentsVoidType::get_url(self, req, connectors)?) + .headers(types::PaymentsVoidType::get_headers(self, req)?) + .body(types::PaymentsVoidType::get_request_body(self, req)?) + .build(), + )) } fn handle_response( &self, - _data: &types::PaymentsCancelRouterData, - _res: Response, + data: &types::PaymentsCancelRouterData, + res: Response, ) -> CustomResult { - Err(errors::ConnectorError::NotImplemented("checkout".to_string()).into()) + let mut response: checkout::PaymentVoidResponse = res + .response + .parse_struct("PaymentVoidResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + response.status = res.status_code; + logger::debug!(payments_create_response=?response); + types::RouterData::try_from(types::ResponseRouterData { + response, + data: data.clone(), + http_code: res.status_code, + }) + .change_context(errors::ConnectorError::ResponseHandlingFailed) } fn get_error_response( &self, - _res: Bytes, + res: Bytes, ) -> CustomResult { - Err(errors::ConnectorError::NotImplemented("checkout".to_string()).into()) + let response: checkout::ErrorResponse = res + .parse_struct("ErrorResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + Ok(ErrorResponse { + code: response + .error_codes + .unwrap_or_else(|| vec![consts::NO_ERROR_CODE.to_string()]) + //Considered all the codes here but have to look into the exact no.of codes + .join(" & "), + message: response + .error_type + .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()), + reason: None, + }) } } diff --git a/crates/router/src/connector/checkout/transformers.rs b/crates/router/src/connector/checkout/transformers.rs index d52e17c740..f8ef090af5 100644 --- a/crates/router/src/connector/checkout/transformers.rs +++ b/crates/router/src/connector/checkout/transformers.rs @@ -46,6 +46,7 @@ pub struct PaymentsRequest { pub three_ds: CheckoutThreeDS, #[serde(flatten)] pub return_url: ReturnUrl, + pub capture: bool, } #[derive(Debug, Serialize)] @@ -100,6 +101,11 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PaymentsRequest { .map(|return_url| format!("{return_url}?status=failure")), }; + let capture = matches!( + item.request.capture_method, + Some(enums::CaptureMethod::Automatic) + ); + let source_var = Source::Card(CardSource { source_type: Some("card".to_owned()), number: ccard.map(|x| x.card_number.clone()), @@ -116,6 +122,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PaymentsRequest { processing_channel_id, three_ds, return_url, + capture, }) } } @@ -131,12 +138,21 @@ pub enum CheckoutPaymentStatus { Captured, } -impl From for enums::AttemptStatus { - fn from(item: CheckoutPaymentStatus) -> Self { - match item { - CheckoutPaymentStatus::Authorized | CheckoutPaymentStatus::Captured => { - enums::AttemptStatus::Charged +impl From<(CheckoutPaymentStatus, Option)> for enums::AttemptStatus { + fn from(item: (CheckoutPaymentStatus, Option)) -> Self { + let status = item.0; + let capture_method = item.1; + match status { + CheckoutPaymentStatus::Authorized => { + if capture_method == Some(enums::CaptureMethod::Automatic) + || capture_method.is_none() + { + enums::AttemptStatus::Charged + } else { + enums::AttemptStatus::Authorized + } } + CheckoutPaymentStatus::Captured => enums::AttemptStatus::Charged, CheckoutPaymentStatus::Declined => enums::AttemptStatus::Failure, CheckoutPaymentStatus::Pending => enums::AttemptStatus::Authorizing, CheckoutPaymentStatus::CardVerified => enums::AttemptStatus::Pending, @@ -161,13 +177,12 @@ pub struct PaymentsResponse { #[serde(rename = "_links")] links: Links, } -impl - TryFrom> - for types::RouterData +impl TryFrom> + for types::PaymentsAuthorizeRouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData, + item: types::PaymentsResponseRouterData, ) -> Result { let redirection_url = item .response @@ -188,7 +203,10 @@ impl ), }); Ok(types::RouterData { - status: enums::AttemptStatus::from(item.response.status), + status: enums::AttemptStatus::from(( + item.response.status, + item.data.request.capture_method, + )), response: Ok(types::PaymentsResponseData { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), redirect: redirection_data.is_some(), @@ -199,6 +217,76 @@ impl } } +impl TryFrom> + for types::PaymentsSyncRouterData +{ + type Error = error_stack::Report; + fn try_from( + item: types::PaymentsSyncResponseRouterData, + ) -> Result { + Ok(types::RouterData { + status: enums::AttemptStatus::from((item.response.status, None)), + response: Ok(types::PaymentsResponseData { + resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), + //TODO: Add redirection details here + redirection_data: None, + redirect: false, + }), + ..item.data + }) + } +} + +#[derive(Clone, Default, Debug, Eq, PartialEq, Serialize)] +pub struct PaymentVoidRequest { + reference: String, +} +#[derive(Clone, Default, Debug, Eq, PartialEq, Deserialize)] +pub struct PaymentVoidResponse { + #[serde(skip)] + pub(super) status: u16, + action_id: String, + reference: String, +} +impl From<&PaymentVoidResponse> for enums::AttemptStatus { + fn from(item: &PaymentVoidResponse) -> enums::AttemptStatus { + if item.status == 202 { + Self::Voided + } else { + Self::VoidFailed + } + } +} + +impl TryFrom> + for types::PaymentsCancelRouterData +{ + type Error = error_stack::Report; + fn try_from( + item: types::PaymentsCancelResponseRouterData, + ) -> Result { + let response = &item.response; + Ok(types::RouterData { + response: Ok(types::PaymentsResponseData { + resource_id: types::ResponseId::ConnectorTransactionId(response.action_id.clone()), + redirect: false, + redirection_data: None, + }), + status: response.into(), + ..item.data + }) + } +} + +impl TryFrom<&types::PaymentsCancelRouterData> for PaymentVoidRequest { + type Error = error_stack::Report; + fn try_from(item: &types::PaymentsCancelRouterData) -> Result { + Ok(Self { + reference: item.request.connector_transaction_id.clone(), + }) + } +} + #[derive(Clone, Debug, Serialize, Deserialize)] pub struct RefundRequest { amount: Option, diff --git a/crates/router/src/core/payments/operations/payment_session.rs b/crates/router/src/core/payments/operations/payment_session.rs index 84391a9983..ebdfc92744 100644 --- a/crates/router/src/core/payments/operations/payment_session.rs +++ b/crates/router/src/core/payments/operations/payment_session.rs @@ -216,7 +216,7 @@ where _txn_id: &str, _payment_attempt: &storage::PaymentAttempt, _request: &Option, - _token: Option, + _token: &Option, ) -> RouterResult<( BoxedOperation<'a, F, api::PaymentsSessionRequest>, Option, diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index 6dc3d1fb4c..cb34e60793 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -31,6 +31,8 @@ pub type PaymentsResponseRouterData = ResponseRouterData; pub type PaymentsCancelResponseRouterData = ResponseRouterData; +pub type PaymentsSyncResponseRouterData = + ResponseRouterData; pub type RefundsResponseRouterData = ResponseRouterData;