mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +08:00
feat(connector): integrate payments void, sync and refund flows for Braintree (#73)
This commit is contained in:
@ -246,7 +246,7 @@ impl
|
||||
res: Bytes,
|
||||
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
|
||||
let response: braintree::ErrorResponse = res
|
||||
.parse_struct("Error Response")
|
||||
.parse_struct("Braintree Error Response")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
|
||||
Ok(ErrorResponse {
|
||||
@ -271,7 +271,7 @@ impl
|
||||
logger::debug!(payment_sync_response=?res);
|
||||
let response: braintree::BraintreePaymentsResponse = res
|
||||
.response
|
||||
.parse_struct("braintree PaymentsResponse")
|
||||
.parse_struct("Braintree PaymentsResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
types::RouterData::try_from(types::ResponseRouterData {
|
||||
response,
|
||||
@ -356,7 +356,7 @@ impl
|
||||
) -> CustomResult<types::PaymentsAuthorizeRouterData, errors::ConnectorError> {
|
||||
let response: braintree::BraintreePaymentsResponse = res
|
||||
.response
|
||||
.parse_struct("Braintree Payments Response")
|
||||
.parse_struct("Braintree PaymentsResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
logger::debug!(braintreepayments_create_response=?response);
|
||||
types::ResponseRouterData {
|
||||
@ -375,7 +375,7 @@ impl
|
||||
logger::debug!(braintreepayments_create_response=?res);
|
||||
|
||||
let response: braintree::ErrorResponse = res
|
||||
.parse_struct("ErrorResponse")
|
||||
.parse_struct("Braintree ErrorResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
Ok(ErrorResponse {
|
||||
code: consts::NO_ERROR_CODE.to_string(),
|
||||
@ -394,50 +394,94 @@ impl
|
||||
{
|
||||
fn get_headers(
|
||||
&self,
|
||||
_req: &types::PaymentsCancelRouterData,
|
||||
req: &types::PaymentsCancelRouterData,
|
||||
) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
|
||||
Err(errors::ConnectorError::NotImplemented("braintree".to_string()).into())
|
||||
let mut headers = vec![
|
||||
(
|
||||
headers::CONTENT_TYPE.to_string(),
|
||||
types::PaymentsAuthorizeType::get_content_type(self).to_string(),
|
||||
),
|
||||
(headers::X_ROUTER.to_string(), "test".to_string()),
|
||||
(headers::X_API_VERSION.to_string(), "6".to_string()),
|
||||
(headers::ACCEPT.to_string(), "application/json".to_string()),
|
||||
];
|
||||
let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
|
||||
headers.append(&mut api_key);
|
||||
Ok(headers)
|
||||
}
|
||||
|
||||
fn get_content_type(&self) -> &'static str {
|
||||
""
|
||||
"application/json"
|
||||
}
|
||||
|
||||
fn get_url(
|
||||
&self,
|
||||
_req: &types::PaymentsCancelRouterData,
|
||||
_connectors: Connectors,
|
||||
req: &types::PaymentsCancelRouterData,
|
||||
connectors: Connectors,
|
||||
) -> CustomResult<String, errors::ConnectorError> {
|
||||
Err(errors::ConnectorError::NotImplemented("braintree".to_string()).into())
|
||||
let auth_type = braintree::BraintreeAuthType::try_from(&req.connector_auth_type)
|
||||
.change_context(errors::ConnectorError::FailedToObtainAuthType)?;
|
||||
Ok(format!(
|
||||
"{}merchants/{}/transactions/{}/void",
|
||||
self.base_url(connectors),
|
||||
auth_type.merchant_account,
|
||||
req.request.connector_transaction_id
|
||||
))
|
||||
}
|
||||
|
||||
fn build_request(
|
||||
&self,
|
||||
req: &types::PaymentsCancelRouterData,
|
||||
connectors: Connectors,
|
||||
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
|
||||
Ok(Some(
|
||||
services::RequestBuilder::new()
|
||||
.method(services::Method::Put)
|
||||
.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 get_error_response(
|
||||
&self,
|
||||
res: Bytes,
|
||||
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
|
||||
let response: braintree::ErrorResponse = res
|
||||
.parse_struct("Braintree ErrorResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
|
||||
Ok(ErrorResponse {
|
||||
code: consts::NO_ERROR_CODE.to_string(),
|
||||
message: response.api_error_response.message,
|
||||
reason: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn get_request_body(
|
||||
&self,
|
||||
_req: &types::PaymentsCancelRouterData,
|
||||
) -> CustomResult<Option<String>, errors::ConnectorError> {
|
||||
Err(errors::ConnectorError::NotImplemented("braintree".to_string()).into())
|
||||
}
|
||||
fn build_request(
|
||||
&self,
|
||||
_req: &types::PaymentsCancelRouterData,
|
||||
_connectors: Connectors,
|
||||
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
|
||||
Err(errors::ConnectorError::NotImplemented("braintree".to_string()).into())
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn handle_response(
|
||||
&self,
|
||||
_data: &types::PaymentsCancelRouterData,
|
||||
_res: Response,
|
||||
data: &types::PaymentsCancelRouterData,
|
||||
res: Response,
|
||||
) -> CustomResult<types::PaymentsCancelRouterData, errors::ConnectorError> {
|
||||
Err(errors::ConnectorError::NotImplemented("braintree".to_string()).into())
|
||||
}
|
||||
|
||||
fn get_error_response(
|
||||
&self,
|
||||
_res: Bytes,
|
||||
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
|
||||
Err(errors::ConnectorError::NotImplemented("braintree".to_string()).into())
|
||||
logger::debug!(payment_sync_response=?res);
|
||||
let response: braintree::BraintreePaymentsResponse = res
|
||||
.response
|
||||
.parse_struct("Braintree PaymentsVoidResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
types::RouterData::try_from(types::ResponseRouterData {
|
||||
response,
|
||||
data: data.clone(),
|
||||
http_code: res.status_code,
|
||||
})
|
||||
.change_context(errors::ConnectorError::ResponseHandlingFailed)
|
||||
}
|
||||
}
|
||||
|
||||
@ -467,23 +511,32 @@ impl services::ConnectorIntegration<api::Execute, types::RefundsData, types::Ref
|
||||
}
|
||||
|
||||
fn get_content_type(&self) -> &'static str {
|
||||
""
|
||||
"application/json"
|
||||
}
|
||||
|
||||
fn get_url(
|
||||
&self,
|
||||
_req: &types::RefundsRouterData<api::Execute>,
|
||||
_connectors: Connectors,
|
||||
req: &types::RefundsRouterData<api::Execute>,
|
||||
connectors: Connectors,
|
||||
) -> CustomResult<String, errors::ConnectorError> {
|
||||
Err(errors::ConnectorError::NotImplemented("braintree".to_string()).into())
|
||||
let auth_type = BraintreeAuthType::try_from(&req.connector_auth_type)
|
||||
.change_context(errors::ConnectorError::FailedToObtainAuthType)?;
|
||||
let connector_payment_id = req.request.connector_transaction_id.clone();
|
||||
Ok(format!(
|
||||
"{}merchants/{}/transactions/{}",
|
||||
self.base_url(connectors),
|
||||
auth_type.merchant_account,
|
||||
connector_payment_id
|
||||
))
|
||||
}
|
||||
|
||||
fn get_request_body(
|
||||
&self,
|
||||
req: &types::RefundsRouterData<api::Execute>,
|
||||
) -> CustomResult<Option<String>, errors::ConnectorError> {
|
||||
let braintree_req = utils::Encode::<braintree::RefundRequest>::convert_and_url_encode(req)
|
||||
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
||||
let braintree_req =
|
||||
utils::Encode::<braintree::BraintreeRefundRequest>::convert_and_url_encode(req)
|
||||
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
||||
Ok(Some(braintree_req))
|
||||
}
|
||||
|
||||
@ -509,7 +562,7 @@ impl services::ConnectorIntegration<api::Execute, types::RefundsData, types::Ref
|
||||
logger::debug!(target: "router::connector::braintree", response=?res);
|
||||
let response: braintree::RefundResponse = res
|
||||
.response
|
||||
.parse_struct("braintree RefundResponse")
|
||||
.parse_struct("Braintree RefundResponse")
|
||||
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
||||
types::ResponseRouterData {
|
||||
response,
|
||||
@ -584,7 +637,7 @@ impl services::ConnectorIntegration<api::RSync, types::RefundsData, types::Refun
|
||||
logger::debug!(target: "router::connector::braintree", response=?res);
|
||||
let response: braintree::RefundResponse = res
|
||||
.response
|
||||
.parse_struct("braintree RefundResponse")
|
||||
.parse_struct("Braintree RefundResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
types::ResponseRouterData {
|
||||
response,
|
||||
|
||||
@ -44,11 +44,15 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for BraintreePaymentsRequest {
|
||||
fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result<Self, Self::Error> {
|
||||
match item.request.payment_method_data {
|
||||
api::PaymentMethod::Card(ref ccard) => {
|
||||
let submit_for_settlement = matches!(
|
||||
item.request.capture_method,
|
||||
Some(enums::CaptureMethod::Automatic) | None
|
||||
);
|
||||
let braintree_payment_request = TransactionBody {
|
||||
amount: item.request.amount.to_string(),
|
||||
device_data: DeviceData {},
|
||||
options: PaymentOptions {
|
||||
submit_for_settlement: true,
|
||||
submit_for_settlement,
|
||||
},
|
||||
credit_card: Card {
|
||||
number: ccard.card_number.peek().clone(),
|
||||
@ -62,7 +66,9 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for BraintreePaymentsRequest {
|
||||
transaction: braintree_payment_request,
|
||||
})
|
||||
}
|
||||
_ => Err(errors::ConnectorError::RequestEncodingFailed.into()),
|
||||
_ => Err(
|
||||
errors::ConnectorError::NotImplemented("Current Payment Method".to_string()).into(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -140,6 +146,7 @@ impl<F, T>
|
||||
>,
|
||||
) -> Result<Self, Self::Error> {
|
||||
Ok(types::RouterData {
|
||||
status: enums::AttemptStatus::from(item.response.transaction.status),
|
||||
response: Ok(types::PaymentsResponseData::TransactionResponse {
|
||||
resource_id: types::ResponseId::ConnectorTransactionId(
|
||||
item.response.transaction.id,
|
||||
@ -223,12 +230,21 @@ pub struct ApiErrorResponse {
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize)]
|
||||
pub struct RefundRequest {}
|
||||
pub struct BraintreeRefundRequest {
|
||||
transaction: Amount,
|
||||
}
|
||||
|
||||
impl<F> TryFrom<&types::RefundsRouterData<F>> for RefundRequest {
|
||||
type Error = error_stack::Report<errors::ParsingError>;
|
||||
#[derive(Default, Debug, Serialize, Clone)]
|
||||
pub struct Amount {
|
||||
amount: Option<String>,
|
||||
}
|
||||
|
||||
impl<F> TryFrom<&types::RefundsRouterData<F>> for BraintreeRefundRequest {
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
fn try_from(_item: &types::RefundsRouterData<F>) -> Result<Self, Self::Error> {
|
||||
Ok(RefundRequest {})
|
||||
Ok(BraintreeRefundRequest {
|
||||
transaction: Amount { amount: None },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -229,6 +229,7 @@ async fn send_request(
|
||||
.await
|
||||
}
|
||||
|
||||
Method::Put => client.put(url).add_headers(headers).send().await,
|
||||
Method::Delete => client.delete(url).add_headers(headers).send().await,
|
||||
}
|
||||
.into_report()
|
||||
|
||||
@ -20,6 +20,7 @@ pub(crate) type Headers = Vec<(String, String)>;
|
||||
pub enum Method {
|
||||
Get,
|
||||
Post,
|
||||
Put,
|
||||
Delete,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user