feat(connector): [PlaceToPay] Implement Cards for PlaceToPay (#3117)

Signed-off-by: chikke srujan <121822803+srujanchikke@users.noreply.github.com>
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
chikke srujan
2023-12-17 13:25:53 +05:30
committed by GitHub
parent 62c0c47e99
commit 107c66fec3
7 changed files with 483 additions and 131 deletions

View File

@ -4,21 +4,21 @@ use std::fmt::Debug;
use common_utils::request::RequestContent;
use error_stack::{IntoReport, ResultExt};
use masking::ExposeInterface;
use transformers as placetopay;
use crate::{
configs::settings,
connector::utils::{self},
core::errors::{self, CustomResult},
headers,
services::{
self,
request::{self, Mask},
request::{self},
ConnectorIntegration, ConnectorValidation,
},
types::{
self,
api::{self, ConnectorCommon, ConnectorCommonExt},
api::{self, enums, ConnectorCommon, ConnectorCommonExt},
ErrorResponse, Response,
},
utils::BytesExt,
@ -86,18 +86,6 @@ impl ConnectorCommon for Placetopay {
connectors.placetopay.base_url.as_ref()
}
fn get_auth_header(
&self,
auth_type: &types::ConnectorAuthType,
) -> CustomResult<Vec<(String, request::Maskable<String>)>, errors::ConnectorError> {
let auth = placetopay::PlacetopayAuthType::try_from(auth_type)
.change_context(errors::ConnectorError::FailedToObtainAuthType)?;
Ok(vec![(
headers::AUTHORIZATION.to_string(),
auth.api_key.expose().into_masked(),
)])
}
fn build_error_response(
&self,
res: Response,
@ -109,16 +97,32 @@ impl ConnectorCommon for Placetopay {
Ok(ErrorResponse {
status_code: res.status_code,
code: response.code,
message: response.message,
reason: response.reason,
code: response.status.reason.to_owned(),
message: response.status.message.to_owned(),
reason: Some(response.status.message),
attempt_status: None,
connector_transaction_id: None,
})
}
}
impl ConnectorValidation for Placetopay {}
impl ConnectorValidation for Placetopay {
fn validate_capture_method(
&self,
capture_method: Option<enums::CaptureMethod>,
) -> CustomResult<(), errors::ConnectorError> {
let capture_method = capture_method.unwrap_or_default();
match capture_method {
enums::CaptureMethod::Manual => Ok(()),
enums::CaptureMethod::Automatic
| enums::CaptureMethod::ManualMultiple
| enums::CaptureMethod::Scheduled => Err(utils::construct_not_supported_error_report(
capture_method,
self.id(),
)),
}
}
}
impl ConnectorIntegration<api::Session, types::PaymentsSessionData, types::PaymentsResponseData>
for Placetopay
@ -157,9 +161,9 @@ impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::P
fn get_url(
&self,
_req: &types::PaymentsAuthorizeRouterData,
_connectors: &settings::Connectors,
connectors: &settings::Connectors,
) -> CustomResult<String, errors::ConnectorError> {
Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
Ok(format!("{}/process", self.base_url(connectors)))
}
fn get_request_body(
@ -206,7 +210,7 @@ impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::P
) -> CustomResult<types::PaymentsAuthorizeRouterData, errors::ConnectorError> {
let response: placetopay::PlacetopayPaymentsResponse = res
.response
.parse_struct("Placetopay PaymentsAuthorizeResponse")
.parse_struct("Placetopay PlacetopayPaymentsResponse")
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
types::RouterData::try_from(types::ResponseRouterData {
response,
@ -241,9 +245,18 @@ impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsRe
fn get_url(
&self,
_req: &types::PaymentsSyncRouterData,
_connectors: &settings::Connectors,
connectors: &settings::Connectors,
) -> CustomResult<String, errors::ConnectorError> {
Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
Ok(format!("{}/query", self.base_url(connectors)))
}
fn get_request_body(
&self,
req: &types::PaymentsSyncRouterData,
_connectors: &settings::Connectors,
) -> CustomResult<RequestContent, errors::ConnectorError> {
let req_obj = placetopay::PlacetopayPsyncRequest::try_from(req)?;
Ok(RequestContent::Json(Box::new(req_obj)))
}
fn build_request(
@ -253,10 +266,13 @@ impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsRe
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
Ok(Some(
services::RequestBuilder::new()
.method(services::Method::Get)
.method(services::Method::Post)
.url(&types::PaymentsSyncType::get_url(self, req, connectors)?)
.attach_default_headers()
.headers(types::PaymentsSyncType::get_headers(self, req, connectors)?)
.set_body(types::PaymentsSyncType::get_request_body(
self, req, connectors,
)?)
.build(),
))
}
@ -303,17 +319,18 @@ impl ConnectorIntegration<api::Capture, types::PaymentsCaptureData, types::Payme
fn get_url(
&self,
_req: &types::PaymentsCaptureRouterData,
_connectors: &settings::Connectors,
connectors: &settings::Connectors,
) -> CustomResult<String, errors::ConnectorError> {
Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
Ok(format!("{}/transaction", self.base_url(connectors)))
}
fn get_request_body(
&self,
_req: &types::PaymentsCaptureRouterData,
req: &types::PaymentsCaptureRouterData,
_connectors: &settings::Connectors,
) -> CustomResult<RequestContent, errors::ConnectorError> {
Err(errors::ConnectorError::NotImplemented("get_request_body method".to_string()).into())
let req_obj = placetopay::PlacetopayNextActionRequest::try_from(req)?;
Ok(RequestContent::Json(Box::new(req_obj)))
}
fn build_request(
@ -363,6 +380,75 @@ impl ConnectorIntegration<api::Capture, types::PaymentsCaptureData, types::Payme
impl ConnectorIntegration<api::Void, types::PaymentsCancelData, types::PaymentsResponseData>
for Placetopay
{
fn get_headers(
&self,
req: &types::PaymentsCancelRouterData,
connectors: &settings::Connectors,
) -> CustomResult<Vec<(String, request::Maskable<String>)>, errors::ConnectorError> {
self.build_headers(req, connectors)
}
fn get_content_type(&self) -> &'static str {
self.common_get_content_type()
}
fn get_url(
&self,
_req: &types::PaymentsCancelRouterData,
connectors: &settings::Connectors,
) -> CustomResult<String, errors::ConnectorError> {
Ok(format!("{}/transaction", self.base_url(connectors)))
}
fn get_request_body(
&self,
req: &types::PaymentsCancelRouterData,
_connectors: &settings::Connectors,
) -> CustomResult<RequestContent, errors::ConnectorError> {
let req_obj = placetopay::PlacetopayNextActionRequest::try_from(req)?;
Ok(RequestContent::Json(Box::new(req_obj)))
}
fn build_request(
&self,
req: &types::PaymentsCancelRouterData,
connectors: &settings::Connectors,
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
Ok(Some(
services::RequestBuilder::new()
.method(services::Method::Post)
.url(&types::PaymentsVoidType::get_url(self, req, connectors)?)
.attach_default_headers()
.headers(types::PaymentsVoidType::get_headers(self, req, connectors)?)
.set_body(types::PaymentsVoidType::get_request_body(
self, req, connectors,
)?)
.build(),
))
}
fn handle_response(
&self,
data: &types::PaymentsCancelRouterData,
res: Response,
) -> CustomResult<types::PaymentsCancelRouterData, errors::ConnectorError> {
let response: placetopay::PlacetopayPaymentsResponse = res
.response
.parse_struct("Placetopay PaymentCancelResponse")
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
types::RouterData::try_from(types::ResponseRouterData {
response,
data: data.clone(),
http_code: res.status_code,
})
}
fn get_error_response(
&self,
res: Response,
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
self.build_error_response(res)
}
}
impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsResponseData>
@ -383,9 +469,9 @@ impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsRespon
fn get_url(
&self,
_req: &types::RefundsRouterData<api::Execute>,
_connectors: &settings::Connectors,
connectors: &settings::Connectors,
) -> CustomResult<String, errors::ConnectorError> {
Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
Ok(format!("{}/transaction", self.base_url(connectors)))
}
fn get_request_body(
@ -393,13 +479,7 @@ impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsRespon
req: &types::RefundsRouterData<api::Execute>,
_connectors: &settings::Connectors,
) -> CustomResult<RequestContent, errors::ConnectorError> {
let connector_router_data = placetopay::PlacetopayRouterData::try_from((
&self.get_currency_unit(),
req.request.currency,
req.request.refund_amount,
req,
))?;
let req_obj = placetopay::PlacetopayRefundRequest::try_from(&connector_router_data)?;
let req_obj = placetopay::PlacetopayRefundRequest::try_from(req)?;
Ok(RequestContent::Json(Box::new(req_obj)))
}
@ -427,9 +507,9 @@ impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsRespon
data: &types::RefundsRouterData<api::Execute>,
res: Response,
) -> CustomResult<types::RefundsRouterData<api::Execute>, errors::ConnectorError> {
let response: placetopay::RefundResponse = res
let response: placetopay::PlacetopayRefundResponse = res
.response
.parse_struct("placetopay RefundResponse")
.parse_struct("placetopay PlacetopayRefundResponse")
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
types::RouterData::try_from(types::ResponseRouterData {
response,
@ -464,9 +544,18 @@ impl ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponse
fn get_url(
&self,
_req: &types::RefundSyncRouterData,
_connectors: &settings::Connectors,
connectors: &settings::Connectors,
) -> CustomResult<String, errors::ConnectorError> {
Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
Ok(format!("{}/query", self.base_url(connectors)))
}
fn get_request_body(
&self,
req: &types::RefundsRouterData<api::RSync>,
_connectors: &settings::Connectors,
) -> CustomResult<RequestContent, errors::ConnectorError> {
let req_obj = placetopay::PlacetopayRsyncRequest::try_from(req)?;
Ok(RequestContent::Json(Box::new(req_obj)))
}
fn build_request(
@ -492,9 +581,9 @@ impl ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponse
data: &types::RefundSyncRouterData,
res: Response,
) -> CustomResult<types::RefundSyncRouterData, errors::ConnectorError> {
let response: placetopay::RefundResponse = res
let response: placetopay::PlacetopayRefundResponse = res
.response
.parse_struct("placetopay RefundSyncResponse")
.parse_struct("placetopay PlacetopayRefundResponse")
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
types::RouterData::try_from(types::ResponseRouterData {
response,

View File

@ -1,14 +1,23 @@
use masking::Secret;
use api_models::payments;
use common_utils::date_time;
use diesel_models::enums;
use error_stack::{IntoReport, ResultExt};
use masking::{PeekInterface, Secret};
use ring::digest;
use serde::{Deserialize, Serialize};
use crate::{
connector::utils::PaymentsAuthorizeRequestData,
connector::utils::{
self, BrowserInformationData, CardData, PaymentsAuthorizeRequestData,
PaymentsSyncRequestData, RouterData,
},
consts,
core::errors,
types::{self, api, storage::enums},
types::{self, api, storage::enums as storage_enums},
};
pub struct PlacetopayRouterData<T> {
pub amount: i64, // The type of amount that a connector accepts, for example, String, i64, f64, etc.
pub amount: i64,
pub router_data: T,
}
@ -36,19 +45,65 @@ impl<T>
}
}
#[derive(Default, Debug, Serialize, Eq, PartialEq)]
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PlacetopayPaymentsRequest {
amount: i64,
auth: PlacetopayAuth,
payment: PlacetopayPayment,
instrument: PlacetopayInstrument,
ip_address: Secret<String, common_utils::pii::IpAddress>,
user_agent: String,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum PlacetopayAuthorizeAction {
Checkin,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PlacetopayAuthType {
login: Secret<String>,
tran_key: Secret<String>,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PlacetopayAuth {
login: Secret<String>,
tran_key: Secret<String>,
nonce: String,
seed: String,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PlacetopayPayment {
reference: String,
description: String,
amount: PlacetopayAmount,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PlacetopayAmount {
currency: storage_enums::Currency,
total: i64,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PlacetopayInstrument {
card: PlacetopayCard,
}
#[derive(Default, Debug, Serialize, Eq, PartialEq)]
#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct PlacetopayCard {
number: cards::CardNumber,
expiry_month: Secret<String>,
expiry_year: Secret<String>,
cvc: Secret<String>,
complete: bool,
expiration: Secret<String>,
cvv: Secret<String>,
}
impl TryFrom<&PlacetopayRouterData<&types::PaymentsAuthorizeRouterData>>
@ -58,65 +113,132 @@ impl TryFrom<&PlacetopayRouterData<&types::PaymentsAuthorizeRouterData>>
fn try_from(
item: &PlacetopayRouterData<&types::PaymentsAuthorizeRouterData>,
) -> Result<Self, Self::Error> {
let browser_info = item.router_data.request.get_browser_info()?;
let ip_address = browser_info.get_ip_address()?;
let user_agent = browser_info.get_user_agent()?;
let auth = PlacetopayAuth::try_from(&item.router_data.connector_auth_type)?;
let payment = PlacetopayPayment {
reference: item.router_data.connector_request_reference_id.clone(),
description: item.router_data.get_description()?,
amount: PlacetopayAmount {
currency: item.router_data.request.currency,
total: item.amount,
},
};
match item.router_data.request.payment_method_data.clone() {
api::PaymentMethodData::Card(req_card) => {
payments::PaymentMethodData::Card(req_card) => {
let card = PlacetopayCard {
number: req_card.card_number,
expiry_month: req_card.card_exp_month,
expiry_year: req_card.card_exp_year,
cvc: req_card.card_cvc,
complete: item.router_data.request.is_auto_capture()?,
number: req_card.card_number.clone(),
expiration: req_card
.clone()
.get_card_expiry_month_year_2_digit_with_delimiter("/".to_owned()),
cvv: req_card.card_cvc.clone(),
};
Ok(Self {
amount: item.amount.to_owned(),
card,
ip_address,
user_agent,
auth,
payment,
instrument: PlacetopayInstrument {
card: card.to_owned(),
},
})
}
_ => Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into()),
payments::PaymentMethodData::Wallet(_)
| payments::PaymentMethodData::CardRedirect(_)
| payments::PaymentMethodData::PayLater(_)
| payments::PaymentMethodData::BankRedirect(_)
| payments::PaymentMethodData::BankDebit(_)
| payments::PaymentMethodData::BankTransfer(_)
| payments::PaymentMethodData::Crypto(_)
| payments::PaymentMethodData::MandatePayment
| payments::PaymentMethodData::Reward
| payments::PaymentMethodData::Upi(_)
| payments::PaymentMethodData::Voucher(_)
| payments::PaymentMethodData::GiftCard(_)
| payments::PaymentMethodData::CardToken(_) => {
Err(errors::ConnectorError::NotImplemented(
utils::get_unimplemented_payment_method_error_message("Placetopay"),
)
.into())
}
}
}
}
// Auth Struct
pub struct PlacetopayAuthType {
pub(super) api_key: Secret<String>,
impl TryFrom<&types::ConnectorAuthType> for PlacetopayAuth {
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(auth_type: &types::ConnectorAuthType) -> Result<Self, Self::Error> {
let placetopay_auth = PlacetopayAuthType::try_from(auth_type)?;
let nonce_bytes = utils::generate_random_bytes(16);
let now = error_stack::IntoReport::into_report(date_time::date_as_yyyymmddthhmmssmmmz())
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
let seed = format!("{}+00:00", now.split_at(now.len() - 5).0);
let mut context = digest::Context::new(&digest::SHA256);
context.update(&nonce_bytes);
context.update(seed.as_bytes());
context.update(placetopay_auth.tran_key.peek().as_bytes());
let encoded_digest = base64::Engine::encode(&consts::BASE64_ENGINE, context.finish());
let nonce = base64::Engine::encode(&consts::BASE64_ENGINE, &nonce_bytes);
Ok(Self {
login: placetopay_auth.login,
tran_key: encoded_digest.into(),
nonce,
seed,
})
}
}
impl TryFrom<&types::ConnectorAuthType> for PlacetopayAuthType {
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(auth_type: &types::ConnectorAuthType) -> Result<Self, Self::Error> {
match auth_type {
types::ConnectorAuthType::HeaderKey { api_key } => Ok(Self {
api_key: api_key.to_owned(),
}),
_ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
if let types::ConnectorAuthType::BodyKey { api_key, key1 } = auth_type {
Ok(Self {
login: api_key.to_owned(),
tran_key: key1.to_owned(),
})
} else {
Err(errors::ConnectorError::FailedToObtainAuthType)?
}
}
}
// PaymentsResponse
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum PlacetopayPaymentStatus {
Succeeded,
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum PlacetopayStatus {
Ok,
Failed,
#[default]
Processing,
Approved,
Rejected,
Pending,
PendingValidation,
PendingProcess,
}
impl From<PlacetopayPaymentStatus> for enums::AttemptStatus {
fn from(item: PlacetopayPaymentStatus) -> Self {
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PlacetopayStatusResponse {
status: PlacetopayStatus,
}
impl From<PlacetopayStatus> for enums::AttemptStatus {
fn from(item: PlacetopayStatus) -> Self {
match item {
PlacetopayPaymentStatus::Succeeded => Self::Charged,
PlacetopayPaymentStatus::Failed => Self::Failure,
PlacetopayPaymentStatus::Processing => Self::Authorizing,
PlacetopayStatus::Approved | PlacetopayStatus::Ok => Self::Authorized,
PlacetopayStatus::Failed | PlacetopayStatus::Rejected => Self::Failure,
PlacetopayStatus::Pending
| PlacetopayStatus::PendingValidation
| PlacetopayStatus::PendingProcess => Self::Authorizing,
}
}
}
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PlacetopayPaymentsResponse {
status: PlacetopayPaymentStatus,
id: String,
status: PlacetopayStatusResponse,
internal_reference: u64,
}
impl<F, T>
@ -134,9 +256,11 @@ impl<F, T>
>,
) -> Result<Self, Self::Error> {
Ok(Self {
status: enums::AttemptStatus::from(item.response.status),
status: enums::AttemptStatus::from(item.response.status.status),
response: Ok(types::PaymentsResponseData::TransactionResponse {
resource_id: types::ResponseId::ConnectorTransactionId(item.response.id),
resource_id: types::ResponseId::ConnectorTransactionId(
item.response.internal_reference.to_string(),
),
redirection_data: None,
mandate_reference: None,
connector_metadata: None,
@ -148,61 +272,76 @@ impl<F, T>
})
}
}
// REFUND :
// Type definition for RefundRequest
#[derive(Default, Debug, Serialize)]
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PlacetopayRefundRequest {
pub amount: i64,
auth: PlacetopayAuth,
internal_reference: u64,
action: PlacetopayNextAction,
}
impl<F> TryFrom<&PlacetopayRouterData<&types::RefundsRouterData<F>>> for PlacetopayRefundRequest {
impl<F> TryFrom<&types::RefundsRouterData<F>> for PlacetopayRefundRequest {
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(
item: &PlacetopayRouterData<&types::RefundsRouterData<F>>,
) -> Result<Self, Self::Error> {
fn try_from(item: &types::RefundsRouterData<F>) -> Result<Self, Self::Error> {
let auth = PlacetopayAuth::try_from(&item.connector_auth_type)?;
let internal_reference = item
.request
.connector_transaction_id
.parse::<u64>()
.into_report()
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
let action = PlacetopayNextAction::Refund;
Ok(Self {
amount: item.amount.to_owned(),
auth,
internal_reference,
action,
})
}
}
// Type definition for Refund Response
#[allow(dead_code)]
#[derive(Debug, Serialize, Default, Deserialize, Clone)]
pub enum RefundStatus {
Succeeded,
Failed,
#[default]
Processing,
}
impl From<RefundStatus> for enums::RefundStatus {
fn from(item: RefundStatus) -> Self {
impl From<PlacetopayRefundStatus> for enums::RefundStatus {
fn from(item: PlacetopayRefundStatus) -> Self {
match item {
RefundStatus::Succeeded => Self::Success,
RefundStatus::Failed => Self::Failure,
RefundStatus::Processing => Self::Pending,
PlacetopayRefundStatus::Refunded => Self::Success,
PlacetopayRefundStatus::Failed | PlacetopayRefundStatus::Rejected => Self::Failure,
PlacetopayRefundStatus::Pending | PlacetopayRefundStatus::PendingProcess => {
Self::Pending
}
}
}
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct RefundResponse {
id: String,
status: RefundStatus,
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PlacetopayRefundResponse {
status: PlacetopayRefundStatus,
internal_reference: u64,
}
impl TryFrom<types::RefundsResponseRouterData<api::Execute, RefundResponse>>
#[derive(Debug, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum PlacetopayRefundStatus {
Refunded,
Rejected,
Failed,
Pending,
PendingProcess,
}
impl TryFrom<types::RefundsResponseRouterData<api::Execute, PlacetopayRefundResponse>>
for types::RefundsRouterData<api::Execute>
{
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(
item: types::RefundsResponseRouterData<api::Execute, RefundResponse>,
item: types::RefundsResponseRouterData<api::Execute, PlacetopayRefundResponse>,
) -> Result<Self, Self::Error> {
Ok(Self {
response: Ok(types::RefundsResponseData {
connector_refund_id: item.response.id.to_string(),
connector_refund_id: item.response.internal_reference.to_string(),
refund_status: enums::RefundStatus::from(item.response.status),
}),
..item.data
@ -210,16 +349,40 @@ impl TryFrom<types::RefundsResponseRouterData<api::Execute, RefundResponse>>
}
}
impl TryFrom<types::RefundsResponseRouterData<api::RSync, RefundResponse>>
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PlacetopayRsyncRequest {
auth: PlacetopayAuth,
internal_reference: u64,
}
impl TryFrom<&types::RefundsRouterData<api::RSync>> for PlacetopayRsyncRequest {
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(item: &types::RefundsRouterData<api::RSync>) -> Result<Self, Self::Error> {
let auth = PlacetopayAuth::try_from(&item.connector_auth_type)?;
let internal_reference = item
.request
.connector_transaction_id
.parse::<u64>()
.into_report()
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
Ok(Self {
auth,
internal_reference,
})
}
}
impl TryFrom<types::RefundsResponseRouterData<api::RSync, PlacetopayRefundResponse>>
for types::RefundsRouterData<api::RSync>
{
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(
item: types::RefundsResponseRouterData<api::RSync, RefundResponse>,
item: types::RefundsResponseRouterData<api::RSync, PlacetopayRefundResponse>,
) -> Result<Self, Self::Error> {
Ok(Self {
response: Ok(types::RefundsResponseData {
connector_refund_id: item.response.id.to_string(),
connector_refund_id: item.response.internal_reference.to_string(),
refund_status: enums::RefundStatus::from(item.response.status),
}),
..item.data
@ -227,10 +390,104 @@ impl TryFrom<types::RefundsResponseRouterData<api::RSync, RefundResponse>>
}
}
#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PlacetopayErrorResponse {
pub status_code: u16,
pub code: String,
pub message: String,
pub reason: Option<String>,
pub status: PlacetopayError,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PlacetopayError {
pub status: PlacetopayErrorStatus,
pub message: String,
pub reason: String,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum PlacetopayErrorStatus {
Failed,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PlacetopayPsyncRequest {
auth: PlacetopayAuth,
internal_reference: u64,
}
impl TryFrom<&types::PaymentsSyncRouterData> for PlacetopayPsyncRequest {
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(item: &types::PaymentsSyncRouterData) -> Result<Self, Self::Error> {
let auth = PlacetopayAuth::try_from(&item.connector_auth_type)?;
let internal_reference = item
.request
.get_connector_transaction_id()?
.parse::<u64>()
.into_report()
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
Ok(Self {
auth,
internal_reference,
})
}
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PlacetopayNextActionRequest {
auth: PlacetopayAuth,
internal_reference: u64,
action: PlacetopayNextAction,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum PlacetopayNextAction {
Refund,
Void,
Process,
Checkout,
}
impl TryFrom<&types::PaymentsCaptureRouterData> for PlacetopayNextActionRequest {
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(item: &types::PaymentsCaptureRouterData) -> Result<Self, Self::Error> {
let auth = PlacetopayAuth::try_from(&item.connector_auth_type)?;
let internal_reference = item
.request
.connector_transaction_id
.parse::<u64>()
.into_report()
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
let action = PlacetopayNextAction::Checkout;
Ok(Self {
auth,
internal_reference,
action,
})
}
}
impl TryFrom<&types::PaymentsCancelRouterData> for PlacetopayNextActionRequest {
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(item: &types::PaymentsCancelRouterData) -> Result<Self, Self::Error> {
let auth = PlacetopayAuth::try_from(&item.connector_auth_type)?;
let internal_reference = item
.request
.connector_transaction_id
.parse::<u64>()
.into_report()
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
let action = PlacetopayNextAction::Void;
Ok(Self {
auth,
internal_reference,
action,
})
}
}

View File

@ -1630,6 +1630,12 @@ pub fn is_manual_capture(capture_method: Option<enums::CaptureMethod>) -> bool {
|| capture_method == Some(enums::CaptureMethod::ManualMultiple)
}
pub fn generate_random_bytes(length: usize) -> Vec<u8> {
// returns random bytes of length n
let mut rng = rand::thread_rng();
(0..length).map(|_| rand::Rng::gen(&mut rng)).collect()
}
pub fn validate_currency(
request_currency: types::storage::enums::Currency,
merchant_config_currency: Option<types::storage::enums::Currency>,