feat(connector): integrate payments void, sync and refund flows for Braintree (#73)

This commit is contained in:
Sahebjot singh
2022-12-13 13:03:25 +05:30
committed by GitHub
parent 7dca6f1e5a
commit b3fefeb2aa
5 changed files with 114 additions and 42 deletions

View File

@ -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,

View File

@ -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 },
})
}
}

View File

@ -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()

View File

@ -20,6 +20,7 @@ pub(crate) type Headers = Vec<(String, String)>;
pub enum Method {
Get,
Post,
Put,
Delete,
}