feat(connector): Add connector cashtocode (#1429)

This commit is contained in:
BallaNitesh
2023-06-27 15:05:23 +05:30
committed by GitHub
parent 9969c930a9
commit 784847b08c
25 changed files with 888 additions and 26 deletions

View File

@ -385,6 +385,7 @@ pub struct Connectors {
pub bitpay: ConnectorParams,
pub bluesnap: ConnectorParams,
pub braintree: ConnectorParams,
pub cashtocode: ConnectorParams,
pub checkout: ConnectorParams,
pub coinbase: ConnectorParams,
pub cybersource: ConnectorParams,

View File

@ -6,6 +6,7 @@ pub mod bambora;
pub mod bitpay;
pub mod bluesnap;
pub mod braintree;
pub mod cashtocode;
pub mod checkout;
pub mod coinbase;
pub mod cybersource;
@ -40,10 +41,11 @@ pub mod zen;
pub use self::dummyconnector::DummyConnector;
pub use self::{
aci::Aci, adyen::Adyen, airwallex::Airwallex, authorizedotnet::Authorizedotnet,
bambora::Bambora, bitpay::Bitpay, bluesnap::Bluesnap, braintree::Braintree, checkout::Checkout,
coinbase::Coinbase, cybersource::Cybersource, dlocal::Dlocal, fiserv::Fiserv, forte::Forte,
globalpay::Globalpay, iatapay::Iatapay, klarna::Klarna, mollie::Mollie,
multisafepay::Multisafepay, nexinets::Nexinets, nmi::Nmi, noon::Noon, nuvei::Nuvei,
opennode::Opennode, payeezy::Payeezy, paypal::Paypal, payu::Payu, rapyd::Rapyd, shift4::Shift4,
stripe::Stripe, trustpay::Trustpay, worldline::Worldline, worldpay::Worldpay, zen::Zen,
bambora::Bambora, bitpay::Bitpay, bluesnap::Bluesnap, braintree::Braintree,
cashtocode::Cashtocode, checkout::Checkout, coinbase::Coinbase, cybersource::Cybersource,
dlocal::Dlocal, fiserv::Fiserv, forte::Forte, globalpay::Globalpay, iatapay::Iatapay,
klarna::Klarna, mollie::Mollie, multisafepay::Multisafepay, nexinets::Nexinets, nmi::Nmi,
noon::Noon, nuvei::Nuvei, opennode::Opennode, payeezy::Payeezy, paypal::Paypal, payu::Payu,
rapyd::Rapyd, shift4::Shift4, stripe::Stripe, trustpay::Trustpay, worldline::Worldline,
worldpay::Worldpay, zen::Zen,
};

View File

@ -298,6 +298,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for AciPaymentsRequest {
api::PaymentMethodData::Crypto(_)
| api::PaymentMethodData::BankDebit(_)
| api::PaymentMethodData::BankTransfer(_)
| api::PaymentMethodData::Reward(_)
| api::PaymentMethodData::MandatePayment => {
Err(errors::ConnectorError::NotSupported {
message: format!("{:?}", item.payment_method),

View File

@ -139,14 +139,12 @@ fn get_pm_and_subsequent_auth_detail(
api::PaymentMethodData::Crypto(_)
| api::PaymentMethodData::BankDebit(_)
| api::PaymentMethodData::MandatePayment
| api::PaymentMethodData::BankTransfer(_) => {
Err(errors::ConnectorError::NotSupported {
message: format!("{:?}", item.request.payment_method_data),
connector: "AuthorizeDotNet",
payment_experience: api_models::enums::PaymentExperience::RedirectToUrl
.to_string(),
})?
}
| api::PaymentMethodData::BankTransfer(_)
| api::PaymentMethodData::Reward(_) => Err(errors::ConnectorError::NotSupported {
message: format!("{:?}", item.request.payment_method_data),
connector: "AuthorizeDotNet",
payment_experience: api_models::enums::PaymentExperience::RedirectToUrl.to_string(),
})?,
},
}
}

View File

@ -0,0 +1,461 @@
mod transformers;
use std::fmt::Debug;
use error_stack::{IntoReport, ResultExt};
use transformers as cashtocode;
use crate::{
configs::settings,
connector::utils as conn_utils,
core::errors::{self, CustomResult},
db::StorageInterface,
headers,
services::{
self,
request::{self, Mask},
ConnectorIntegration,
},
types::{
self,
api::{self, ConnectorCommon, ConnectorCommonExt},
storage::{self},
ErrorResponse, Response,
},
utils::{self, ByteSliceExt, BytesExt},
};
#[derive(Debug, Clone)]
pub struct Cashtocode;
impl api::Payment for Cashtocode {}
impl api::PaymentSession for Cashtocode {}
impl api::ConnectorAccessToken for Cashtocode {}
impl api::PreVerify for Cashtocode {}
impl api::PaymentAuthorize for Cashtocode {}
impl api::PaymentSync for Cashtocode {}
impl api::PaymentCapture for Cashtocode {}
impl api::PaymentVoid for Cashtocode {}
impl api::PaymentToken for Cashtocode {}
impl api::Refund for Cashtocode {}
impl api::RefundExecute for Cashtocode {}
impl api::RefundSync for Cashtocode {}
fn get_auth_cashtocode(
payment_method_type: &Option<storage::enums::PaymentMethodType>,
auth_type: &types::ConnectorAuthType,
) -> CustomResult<Vec<(String, request::Maskable<String>)>, errors::ConnectorError> {
match payment_method_type
.clone()
.ok_or_else(conn_utils::missing_field_err("payment_method_type"))
{
Ok(reward_type) => match reward_type {
storage::enums::PaymentMethodType::ClassicReward => match auth_type {
types::ConnectorAuthType::BodyKey { api_key, .. } => Ok(vec![(
headers::AUTHORIZATION.to_string(),
format!("Basic {api_key}").into_masked(),
)]),
_ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
},
storage::enums::PaymentMethodType::Evoucher => match auth_type {
types::ConnectorAuthType::BodyKey { key1, .. } => Ok(vec![(
headers::AUTHORIZATION.to_string(),
format!("Basic {key1}").into_masked(),
)]),
_ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
},
_ => Err(error_stack::report!(errors::ConnectorError::NotSupported {
message: reward_type.to_string(),
connector: "cashtocode",
payment_experience: "Try with a different payment method".to_string(),
})),
},
Err(_) => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
}
}
impl
ConnectorIntegration<
api::PaymentMethodToken,
types::PaymentMethodTokenizationData,
types::PaymentsResponseData,
> for Cashtocode
{
// Not Implemented (R)
}
impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Cashtocode where
Self: ConnectorIntegration<Flow, Request, Response>
{
}
impl ConnectorCommon for Cashtocode {
fn id(&self) -> &'static str {
"cashtocode"
}
fn common_get_content_type(&self) -> &'static str {
"application/json"
}
fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str {
connectors.cashtocode.base_url.as_ref()
}
fn get_auth_header(
&self,
auth_type: &types::ConnectorAuthType,
) -> CustomResult<Vec<(String, request::Maskable<String>)>, errors::ConnectorError> {
let auth = cashtocode::CashtocodeAuthType::try_from(auth_type)
.change_context(errors::ConnectorError::FailedToObtainAuthType)?;
Ok(vec![(
headers::AUTHORIZATION.to_string(),
auth.api_key.into_masked(),
)])
}
fn build_error_response(
&self,
res: Response,
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
let response: cashtocode::CashtocodeErrorResponse = res
.response
.parse_struct("CashtocodeErrorResponse")
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
Ok(ErrorResponse {
status_code: res.status_code,
code: response.error.to_string(),
message: response.error_description,
reason: None,
})
}
}
impl ConnectorIntegration<api::Session, types::PaymentsSessionData, types::PaymentsResponseData>
for Cashtocode
{
//TODO: implement sessions flow
}
impl ConnectorIntegration<api::AccessTokenAuth, types::AccessTokenRequestData, types::AccessToken>
for Cashtocode
{
}
impl ConnectorIntegration<api::Verify, types::VerifyRequestData, types::PaymentsResponseData>
for Cashtocode
{
}
impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::PaymentsResponseData>
for Cashtocode
{
fn get_headers(
&self,
req: &types::PaymentsAuthorizeRouterData,
_connectors: &settings::Connectors,
) -> CustomResult<Vec<(String, request::Maskable<String>)>, errors::ConnectorError> {
let mut header = vec![(
headers::CONTENT_TYPE.to_string(),
types::PaymentsAuthorizeType::get_content_type(self)
.to_owned()
.into(),
)];
let auth_differentiator =
get_auth_cashtocode(&req.request.payment_method_type, &req.connector_auth_type);
let mut api_key = match auth_differentiator {
Ok(auth_type) => auth_type,
Err(err) => return Err(err),
};
header.append(&mut api_key);
Ok(header)
}
fn get_content_type(&self) -> &'static str {
self.common_get_content_type()
}
fn get_url(
&self,
_req: &types::PaymentsAuthorizeRouterData,
connectors: &settings::Connectors,
) -> CustomResult<String, errors::ConnectorError> {
Ok(format!(
"{}/merchant/paytokens",
connectors.cashtocode.base_url
))
}
fn get_request_body(
&self,
req: &types::PaymentsAuthorizeRouterData,
) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> {
let req_obj = cashtocode::CashtocodePaymentsRequest::try_from(req)?;
let cashtocode_req = types::RequestBody::log_and_get_request_body(
&req_obj,
utils::Encode::<cashtocode::CashtocodePaymentsRequest>::encode_to_string_of_json,
)
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
Ok(Some(cashtocode_req))
}
fn build_request(
&self,
req: &types::PaymentsAuthorizeRouterData,
connectors: &settings::Connectors,
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
Ok(Some(
services::RequestBuilder::new()
.method(services::Method::Post)
.url(&types::PaymentsAuthorizeType::get_url(
self, req, connectors,
)?)
.attach_default_headers()
.headers(types::PaymentsAuthorizeType::get_headers(
self, req, connectors,
)?)
.body(types::PaymentsAuthorizeType::get_request_body(self, req)?)
.build(),
))
}
fn handle_response(
&self,
data: &types::PaymentsAuthorizeRouterData,
res: Response,
) -> CustomResult<types::PaymentsAuthorizeRouterData, errors::ConnectorError> {
let response: cashtocode::CashtocodePaymentsResponse = res
.response
.parse_struct("Cashtocode PaymentsAuthorizeResponse")
.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::PSync, types::PaymentsSyncData, types::PaymentsResponseData>
for Cashtocode
{
fn build_request(
&self,
_req: &types::PaymentsSyncRouterData,
_connectors: &settings::Connectors,
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
Err(errors::ConnectorError::FlowNotSupported {
flow: "Payments Sync".to_string(),
connector: "Cashtocode".to_string(),
}
.into())
}
fn handle_response(
&self,
data: &types::PaymentsSyncRouterData,
res: Response,
) -> CustomResult<types::PaymentsSyncRouterData, errors::ConnectorError> {
types::RouterData::try_from(types::ResponseRouterData {
response: cashtocode::CashtocodePaymentsSyncResponse {},
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::Capture, types::PaymentsCaptureData, types::PaymentsResponseData>
for Cashtocode
{
fn build_request(
&self,
_req: &types::RouterData<
api::Capture,
types::PaymentsCaptureData,
types::PaymentsResponseData,
>,
_connectors: &settings::Connectors,
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
Err(errors::ConnectorError::FlowNotSupported {
flow: "Capture".to_string(),
connector: "Cashtocode".to_string(),
}
.into())
}
}
impl ConnectorIntegration<api::Void, types::PaymentsCancelData, types::PaymentsResponseData>
for Cashtocode
{
fn build_request(
&self,
_req: &types::RouterData<api::Void, types::PaymentsCancelData, types::PaymentsResponseData>,
_connectors: &settings::Connectors,
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
Err(errors::ConnectorError::FlowNotSupported {
flow: "Payments Cancel".to_string(),
connector: "Cashtocode".to_string(),
}
.into())
}
}
#[async_trait::async_trait]
impl api::IncomingWebhook for Cashtocode {
fn get_webhook_source_verification_signature(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
) -> CustomResult<Vec<u8>, errors::ConnectorError> {
let base64_signature = conn_utils::get_header_key_value("authorization", request.headers)?;
let signature = base64_signature.as_bytes().to_owned();
Ok(signature)
}
async fn get_webhook_source_verification_merchant_secret(
&self,
db: &dyn StorageInterface,
merchant_id: &str,
) -> CustomResult<Vec<u8>, errors::ConnectorError> {
let key = conn_utils::get_webhook_merchant_secret_key(self.id(), merchant_id);
let secret = match db.find_config_by_key(&key).await {
Ok(config) => Some(config),
Err(e) => {
crate::logger::warn!("Unable to fetch merchant webhook secret from DB: {:#?}", e);
None
}
};
Ok(secret
.map(|conf| conf.config.into_bytes())
.unwrap_or_default())
}
async fn verify_webhook_source(
&self,
db: &dyn StorageInterface,
request: &api::IncomingWebhookRequestDetails<'_>,
merchant_id: &str,
) -> CustomResult<bool, errors::ConnectorError> {
let signature = self
.get_webhook_source_verification_signature(request)
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
let secret = self
.get_webhook_source_verification_merchant_secret(db, merchant_id)
.await
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
let secret_auth = String::from_utf8(secret.to_vec())
.into_report()
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)
.attach_printable("Could not convert secret to UTF-8")?;
let signature_auth = String::from_utf8(signature.to_vec())
.into_report()
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)
.attach_printable("Could not convert secret to UTF-8")?;
Ok(signature_auth == secret_auth)
}
fn get_webhook_object_reference_id(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
let webhook: transformers::CashtocodeObjectId = request
.body
.parse_struct("CashtocodeObjectId")
.change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
api_models::payments::PaymentIdType::ConnectorTransactionId(webhook.transaction_id),
))
}
fn get_webhook_event_type(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
) -> CustomResult<api::IncomingWebhookEvent, errors::ConnectorError> {
Ok(api::IncomingWebhookEvent::PaymentIntentSuccess)
}
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
) -> CustomResult<serde_json::Value, errors::ConnectorError> {
let webhook: transformers::CashtocodeIncomingWebhook = request
.body
.parse_struct("CashtocodeIncomingWebhook")
.change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
let res_json =
utils::Encode::<transformers::CashtocodeIncomingWebhook>::encode_to_value(&webhook)
.change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
Ok(res_json)
}
fn get_webhook_api_response(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
) -> CustomResult<services::api::ApplicationResponse<serde_json::Value>, errors::ConnectorError>
{
let status = "EXECUTED".to_string();
let obj: transformers::CashtocodeObjectId = request
.body
.parse_struct("CashtocodeObjectId")
.change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
let response: serde_json::Value =
serde_json::json!({ "status": status, "transactionId" : obj.transaction_id});
Ok(services::api::ApplicationResponse::Json(response))
}
}
impl ConnectorIntegration<api::refunds::Execute, types::RefundsData, types::RefundsResponseData>
for Cashtocode
{
fn build_request(
&self,
_req: &types::RouterData<
api::refunds::Execute,
types::RefundsData,
types::RefundsResponseData,
>,
_connectors: &settings::Connectors,
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
Err(errors::ConnectorError::FlowNotSupported {
flow: "Refunds".to_string(),
connector: "Cashtocode".to_string(),
}
.into())
}
}
impl ConnectorIntegration<api::refunds::RSync, types::RefundsData, types::RefundsResponseData>
for Cashtocode
{
fn build_request(
&self,
_req: &types::RouterData<
api::refunds::RSync,
types::RefundsData,
types::RefundsResponseData,
>,
_connectors: &settings::Connectors,
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
Err(errors::ConnectorError::FlowNotSupported {
flow: "Refund Sync".to_string(),
connector: "Cashtocode".to_string(),
}
.into())
}
}

View File

@ -0,0 +1,226 @@
use common_utils::pii::Email;
use masking::Secret;
use serde::{Deserialize, Serialize};
use crate::{
connector::utils::RouterData,
core::errors,
services,
types::{self, api, storage::enums},
};
#[derive(Default, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CashtocodePaymentsRequest {
amount: i64,
transaction_id: String,
user_id: Secret<String>,
currency: enums::Currency,
first_name: Option<Secret<String>>,
last_name: Option<Secret<String>>,
user_alias: Secret<String>,
requested_url: String,
cancel_url: String,
email: Option<Email>,
mid: String,
}
pub struct CashToCodeMandatoryParams {
pub user_id: Secret<String>,
pub user_alias: Secret<String>,
pub requested_url: String,
pub cancel_url: String,
}
fn get_mid(
payment_method_data: &api::payments::PaymentMethodData,
) -> Result<String, errors::ConnectorError> {
match payment_method_data {
api_models::payments::PaymentMethodData::Reward(reward_data) => {
Ok(reward_data.merchant_id.to_string())
}
_ => Err(errors::ConnectorError::NotImplemented(
"Payment methods".to_string(),
)),
}
}
fn get_mandatory_params(
item: &types::PaymentsAuthorizeRouterData,
) -> Result<CashToCodeMandatoryParams, error_stack::Report<errors::ConnectorError>> {
let customer_id = item.get_customer_id()?;
let url = item.get_return_url()?;
Ok(CashToCodeMandatoryParams {
user_id: Secret::new(customer_id.to_owned()),
user_alias: Secret::new(customer_id),
requested_url: url.to_owned(),
cancel_url: url,
})
}
impl TryFrom<&types::PaymentsAuthorizeRouterData> for CashtocodePaymentsRequest {
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result<Self, Self::Error> {
let params: CashToCodeMandatoryParams = get_mandatory_params(item)?;
let mid = get_mid(&item.request.payment_method_data)?;
match item.payment_method {
storage_models::enums::PaymentMethod::Reward => Ok(Self {
amount: item.request.amount,
transaction_id: item.attempt_id.clone(),
currency: item.request.currency,
user_id: params.user_id,
first_name: None,
last_name: None,
user_alias: params.user_alias,
requested_url: params.requested_url,
cancel_url: params.cancel_url,
email: item.request.email.clone(),
mid,
}),
_ => Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into()),
}
}
}
pub struct CashtocodeAuthType {
pub(super) api_key: String,
}
impl TryFrom<&types::ConnectorAuthType> for CashtocodeAuthType {
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_string(),
}),
_ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum CashtocodePaymentStatus {
Succeeded,
#[default]
Processing,
}
impl From<CashtocodePaymentStatus> for enums::AttemptStatus {
fn from(item: CashtocodePaymentStatus) -> Self {
match item {
CashtocodePaymentStatus::Succeeded => Self::Charged,
CashtocodePaymentStatus::Processing => Self::AuthenticationPending,
}
}
}
#[derive(Debug, Deserialize, Clone)]
pub struct CashtocodeErrors {
pub message: String,
pub path: String,
#[serde(rename = "type")]
pub event_type: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CashtocodePaymentsResponse {
pub pay_url: String,
}
pub struct CashtocodePaymentsSyncResponse {}
impl<F, T>
TryFrom<
types::ResponseRouterData<F, CashtocodePaymentsResponse, T, types::PaymentsResponseData>,
> for types::RouterData<F, T, types::PaymentsResponseData>
{
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(
item: types::ResponseRouterData<
F,
CashtocodePaymentsResponse,
T,
types::PaymentsResponseData,
>,
) -> Result<Self, Self::Error> {
let redirection_data = services::RedirectForm::Form {
endpoint: item.response.pay_url.clone(),
method: services::Method::Post,
form_fields: Default::default(),
};
Ok(Self {
status: enums::AttemptStatus::AuthenticationPending,
response: Ok(types::PaymentsResponseData::TransactionResponse {
resource_id: types::ResponseId::ConnectorTransactionId(
item.data.attempt_id.clone(),
),
redirection_data: Some(redirection_data),
mandate_reference: None,
connector_metadata: None,
network_txn_id: None,
}),
..item.data
})
}
}
impl<F, T>
TryFrom<
types::ResponseRouterData<
F,
CashtocodePaymentsSyncResponse,
T,
types::PaymentsResponseData,
>,
> for types::RouterData<F, T, types::PaymentsResponseData>
{
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(
item: types::ResponseRouterData<
F,
CashtocodePaymentsSyncResponse,
T,
types::PaymentsResponseData,
>,
) -> Result<Self, Self::Error> {
Ok(Self {
status: enums::AttemptStatus::Charged,
response: Ok(types::PaymentsResponseData::TransactionResponse {
resource_id: types::ResponseId::ConnectorTransactionId(
item.data.attempt_id.clone(),
),
redirection_data: None,
mandate_reference: None,
connector_metadata: None,
network_txn_id: None,
}),
..item.data
})
}
}
#[derive(Debug, Deserialize)]
pub struct CashtocodeErrorResponse {
pub error: String,
pub error_description: String,
pub errors: Option<Vec<CashtocodeErrors>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CashtocodeIncomingWebhook {
pub amount: i64,
pub currency: String,
pub foreign_transaction_id: String,
#[serde(rename = "type")]
pub event_type: String,
pub transaction_id: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CashtocodeObjectId {
pub transaction_id: String,
}

View File

@ -2566,14 +2566,13 @@ impl
)),
}
}
api::PaymentMethodData::MandatePayment | api::PaymentMethodData::Crypto(_) => {
Err(errors::ConnectorError::NotSupported {
message: format!("{pm_type:?}"),
connector: "Stripe",
payment_experience: api_models::enums::PaymentExperience::RedirectToUrl
.to_string(),
})?
}
api::PaymentMethodData::MandatePayment
| api::PaymentMethodData::Crypto(_)
| api::PaymentMethodData::Reward(_) => Err(errors::ConnectorError::NotSupported {
message: format!("{pm_type:?}"),
connector: "Stripe",
payment_experience: api_models::enums::PaymentExperience::RedirectToUrl.to_string(),
})?,
}
}
}

View File

@ -142,6 +142,7 @@ default_imp_for_complete_authorize!(
connector::Authorizedotnet,
connector::Bitpay,
connector::Braintree,
connector::Cashtocode,
connector::Checkout,
connector::Coinbase,
connector::Cybersource,
@ -200,6 +201,7 @@ default_imp_for_create_customer!(
connector::Bambora,
connector::Bitpay,
connector::Braintree,
connector::Cashtocode,
connector::Checkout,
connector::Coinbase,
connector::Cybersource,
@ -262,6 +264,7 @@ default_imp_for_connector_redirect_response!(
connector::Authorizedotnet,
connector::Bitpay,
connector::Braintree,
connector::Cashtocode,
connector::Coinbase,
connector::Cybersource,
connector::Dlocal,
@ -301,6 +304,7 @@ default_imp_for_connector_request_id!(
connector::Bitpay,
connector::Bluesnap,
connector::Braintree,
connector::Cashtocode,
connector::Checkout,
connector::Coinbase,
connector::Cybersource,
@ -366,6 +370,7 @@ default_imp_for_accept_dispute!(
connector::Bitpay,
connector::Bluesnap,
connector::Braintree,
connector::Cashtocode,
connector::Coinbase,
connector::Cybersource,
connector::Dlocal,
@ -451,6 +456,7 @@ default_imp_for_file_upload!(
connector::Bitpay,
connector::Bluesnap,
connector::Braintree,
connector::Cashtocode,
connector::Coinbase,
connector::Cybersource,
connector::Dlocal,
@ -513,6 +519,7 @@ default_imp_for_submit_evidence!(
connector::Bitpay,
connector::Bluesnap,
connector::Braintree,
connector::Cashtocode,
connector::Cybersource,
connector::Coinbase,
connector::Dlocal,
@ -575,6 +582,7 @@ default_imp_for_defend_dispute!(
connector::Bitpay,
connector::Bluesnap,
connector::Braintree,
connector::Cashtocode,
connector::Cybersource,
connector::Coinbase,
connector::Dlocal,
@ -638,6 +646,7 @@ default_imp_for_pre_processing_steps!(
connector::Bitpay,
connector::Bluesnap,
connector::Braintree,
connector::Cashtocode,
connector::Checkout,
connector::Coinbase,
connector::Cybersource,

View File

@ -1271,6 +1271,7 @@ pub async fn make_pm_data<'a, F: Clone, R>(
(pm @ Some(api::PaymentMethodData::BankRedirect(_)), _) => Ok(pm.to_owned()),
(pm @ Some(api::PaymentMethodData::Crypto(_)), _) => Ok(pm.to_owned()),
(pm @ Some(api::PaymentMethodData::BankDebit(_)), _) => Ok(pm.to_owned()),
(pm @ Some(api::PaymentMethodData::Reward(_)), _) => Ok(pm.to_owned()),
(pm_opt @ Some(pm @ api::PaymentMethodData::BankTransfer(_)), _) => {
let token = vault::Vault::store_payment_method_data_in_locker(
state,

View File

@ -40,7 +40,6 @@ pub async fn payments_incoming_webhook_flow<W: api::OutgoingWebhookType>(
} else {
payments::CallConnectorAction::Trigger
};
let payments_response = match webhook_details.object_reference_id {
api_models::webhooks::ObjectReferenceId::PaymentId(id) => {
payments::payments_core::<api::PSync, api::PaymentsResponse, _, _, _>(

View File

@ -169,6 +169,7 @@ Never share your secret api keys. Keep them guarded and secure.
api_models::payments::WeChatPayRedirection,
api_models::payments::BankDebitBilling,
api_models::payments::CryptoData,
api_models::payments::RewardData,
api_models::payments::Address,
api_models::payments::BankRedirectData,
api_models::payments::BankRedirectBilling,

View File

@ -410,8 +410,9 @@ impl Webhooks {
.route(
web::post().to(receive_incoming_webhook::<webhook_type::OutgoingWebhook>),
)
.route(web::get().to(receive_incoming_webhook::<webhook_type::OutgoingWebhook>))
.route(
web::get().to(receive_incoming_webhook::<webhook_type::OutgoingWebhook>),
web::put().to(receive_incoming_webhook::<webhook_type::OutgoingWebhook>),
),
)
}

View File

@ -209,6 +209,7 @@ impl ConnectorData {
enums::Connector::Bitpay => Ok(Box::new(&connector::Bitpay)),
enums::Connector::Bluesnap => Ok(Box::new(&connector::Bluesnap)),
enums::Connector::Braintree => Ok(Box::new(&connector::Braintree)),
enums::Connector::Cashtocode => Ok(Box::new(&connector::Cashtocode)),
enums::Connector::Checkout => Ok(Box::new(&connector::Checkout)),
enums::Connector::Coinbase => Ok(Box::new(&connector::Coinbase)),
enums::Connector::Cybersource => Ok(Box::new(&connector::Cybersource)),