mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 09:07:09 +08:00
feat(connector): [Boku] Template generation (#1760)
Co-authored-by: Prasunna Soppa <70575890+prasunna09@users.noreply.github.com>
This commit is contained in:
@ -18,6 +18,8 @@ THA = "THA" # Thailand country code
|
|||||||
ZAR = "ZAR" # South African Rand currency code
|
ZAR = "ZAR" # South African Rand currency code
|
||||||
passord = "passord" # name of a css class for adyen ui test
|
passord = "passord" # name of a css class for adyen ui test
|
||||||
klick = "klick" # Swedish word for clicks
|
klick = "klick" # Swedish word for clicks
|
||||||
|
optin = "optin" # Boku preflow name
|
||||||
|
optin_id = "optin_id" # Boku's id for optin flow
|
||||||
|
|
||||||
[default.extend-words]
|
[default.extend-words]
|
||||||
aci = "aci" # Name of a connector
|
aci = "aci" # Name of a connector
|
||||||
|
|||||||
@ -157,6 +157,7 @@ authorizedotnet.base_url = "https://apitest.authorize.net/xml/v1/request.api"
|
|||||||
bambora.base_url = "https://api.na.bambora.com"
|
bambora.base_url = "https://api.na.bambora.com"
|
||||||
bitpay.base_url = "https://test.bitpay.com"
|
bitpay.base_url = "https://test.bitpay.com"
|
||||||
bluesnap.base_url = "https://sandbox.bluesnap.com/"
|
bluesnap.base_url = "https://sandbox.bluesnap.com/"
|
||||||
|
boku.base_url = "https://country-api4-stage.boku.com"
|
||||||
braintree.base_url = "https://api.sandbox.braintreegateway.com/"
|
braintree.base_url = "https://api.sandbox.braintreegateway.com/"
|
||||||
cashtocode.base_url = "https://cluster05.api-test.cashtocode.com"
|
cashtocode.base_url = "https://cluster05.api-test.cashtocode.com"
|
||||||
checkout.base_url = "https://api.sandbox.checkout.com/"
|
checkout.base_url = "https://api.sandbox.checkout.com/"
|
||||||
|
|||||||
@ -61,6 +61,7 @@ cards = [
|
|||||||
"bambora",
|
"bambora",
|
||||||
"bitpay",
|
"bitpay",
|
||||||
"bluesnap",
|
"bluesnap",
|
||||||
|
"boku",
|
||||||
"braintree",
|
"braintree",
|
||||||
"checkout",
|
"checkout",
|
||||||
"coinbase",
|
"coinbase",
|
||||||
@ -120,6 +121,7 @@ authorizedotnet.base_url = "https://apitest.authorize.net/xml/v1/request.api"
|
|||||||
bambora.base_url = "https://api.na.bambora.com"
|
bambora.base_url = "https://api.na.bambora.com"
|
||||||
bitpay.base_url = "https://test.bitpay.com"
|
bitpay.base_url = "https://test.bitpay.com"
|
||||||
bluesnap.base_url = "https://sandbox.bluesnap.com/"
|
bluesnap.base_url = "https://sandbox.bluesnap.com/"
|
||||||
|
boku.base_url = "https://country-api4-stage.boku.com"
|
||||||
braintree.base_url = "https://api.sandbox.braintreegateway.com/"
|
braintree.base_url = "https://api.sandbox.braintreegateway.com/"
|
||||||
cashtocode.base_url = "https://cluster05.api-test.cashtocode.com"
|
cashtocode.base_url = "https://cluster05.api-test.cashtocode.com"
|
||||||
checkout.base_url = "https://api.sandbox.checkout.com/"
|
checkout.base_url = "https://api.sandbox.checkout.com/"
|
||||||
|
|||||||
@ -79,6 +79,7 @@ authorizedotnet.base_url = "https://apitest.authorize.net/xml/v1/request.api"
|
|||||||
bambora.base_url = "https://api.na.bambora.com"
|
bambora.base_url = "https://api.na.bambora.com"
|
||||||
bitpay.base_url = "https://test.bitpay.com"
|
bitpay.base_url = "https://test.bitpay.com"
|
||||||
bluesnap.base_url = "https://sandbox.bluesnap.com/"
|
bluesnap.base_url = "https://sandbox.bluesnap.com/"
|
||||||
|
boku.base_url = "https://country-api4-stage.boku.com"
|
||||||
braintree.base_url = "https://api.sandbox.braintreegateway.com/"
|
braintree.base_url = "https://api.sandbox.braintreegateway.com/"
|
||||||
cashtocode.base_url = "https://cluster05.api-test.cashtocode.com"
|
cashtocode.base_url = "https://cluster05.api-test.cashtocode.com"
|
||||||
checkout.base_url = "https://api.sandbox.checkout.com/"
|
checkout.base_url = "https://api.sandbox.checkout.com/"
|
||||||
@ -132,6 +133,7 @@ cards = [
|
|||||||
"bambora",
|
"bambora",
|
||||||
"bitpay",
|
"bitpay",
|
||||||
"bluesnap",
|
"bluesnap",
|
||||||
|
"boku",
|
||||||
"braintree",
|
"braintree",
|
||||||
"checkout",
|
"checkout",
|
||||||
"coinbase",
|
"coinbase",
|
||||||
|
|||||||
@ -78,6 +78,7 @@ pub enum Connector {
|
|||||||
Bitpay,
|
Bitpay,
|
||||||
Bambora,
|
Bambora,
|
||||||
Bluesnap,
|
Bluesnap,
|
||||||
|
// Boku, added as template code for future usage
|
||||||
Braintree,
|
Braintree,
|
||||||
Cashtocode,
|
Cashtocode,
|
||||||
Checkout,
|
Checkout,
|
||||||
@ -88,7 +89,7 @@ pub enum Connector {
|
|||||||
Fiserv,
|
Fiserv,
|
||||||
Forte,
|
Forte,
|
||||||
Globalpay,
|
Globalpay,
|
||||||
Globepay, // added as template code for future usage
|
Globepay,
|
||||||
Iatapay,
|
Iatapay,
|
||||||
Klarna,
|
Klarna,
|
||||||
Mollie,
|
Mollie,
|
||||||
@ -190,6 +191,7 @@ pub enum RoutableConnectors {
|
|||||||
Bitpay,
|
Bitpay,
|
||||||
Bambora,
|
Bambora,
|
||||||
Bluesnap,
|
Bluesnap,
|
||||||
|
// Boku, added as template code for future usage
|
||||||
Braintree,
|
Braintree,
|
||||||
Cashtocode,
|
Cashtocode,
|
||||||
Checkout,
|
Checkout,
|
||||||
|
|||||||
@ -437,6 +437,7 @@ pub struct Connectors {
|
|||||||
pub bambora: ConnectorParams,
|
pub bambora: ConnectorParams,
|
||||||
pub bitpay: ConnectorParams,
|
pub bitpay: ConnectorParams,
|
||||||
pub bluesnap: ConnectorParams,
|
pub bluesnap: ConnectorParams,
|
||||||
|
pub boku: ConnectorParams,
|
||||||
pub braintree: ConnectorParams,
|
pub braintree: ConnectorParams,
|
||||||
pub cashtocode: ConnectorParams,
|
pub cashtocode: ConnectorParams,
|
||||||
pub checkout: ConnectorParams,
|
pub checkout: ConnectorParams,
|
||||||
|
|||||||
@ -5,6 +5,7 @@ pub mod authorizedotnet;
|
|||||||
pub mod bambora;
|
pub mod bambora;
|
||||||
pub mod bitpay;
|
pub mod bitpay;
|
||||||
pub mod bluesnap;
|
pub mod bluesnap;
|
||||||
|
pub mod boku;
|
||||||
pub mod braintree;
|
pub mod braintree;
|
||||||
pub mod cashtocode;
|
pub mod cashtocode;
|
||||||
pub mod checkout;
|
pub mod checkout;
|
||||||
@ -49,7 +50,7 @@ pub mod zen;
|
|||||||
pub use self::dummyconnector::DummyConnector;
|
pub use self::dummyconnector::DummyConnector;
|
||||||
pub use self::{
|
pub use self::{
|
||||||
aci::Aci, adyen::Adyen, airwallex::Airwallex, authorizedotnet::Authorizedotnet,
|
aci::Aci, adyen::Adyen, airwallex::Airwallex, authorizedotnet::Authorizedotnet,
|
||||||
bambora::Bambora, bitpay::Bitpay, bluesnap::Bluesnap, braintree::Braintree,
|
bambora::Bambora, bitpay::Bitpay, bluesnap::Bluesnap, boku::Boku, braintree::Braintree,
|
||||||
cashtocode::Cashtocode, checkout::Checkout, coinbase::Coinbase, cryptopay::Cryptopay,
|
cashtocode::Cashtocode, checkout::Checkout, coinbase::Coinbase, cryptopay::Cryptopay,
|
||||||
cybersource::Cybersource, dlocal::Dlocal, fiserv::Fiserv, forte::Forte, globalpay::Globalpay,
|
cybersource::Cybersource, dlocal::Dlocal, fiserv::Fiserv, forte::Forte, globalpay::Globalpay,
|
||||||
globepay::Globepay, iatapay::Iatapay, klarna::Klarna, mollie::Mollie,
|
globepay::Globepay, iatapay::Iatapay, klarna::Klarna, mollie::Mollie,
|
||||||
|
|||||||
509
crates/router/src/connector/boku.rs
Normal file
509
crates/router/src/connector/boku.rs
Normal file
@ -0,0 +1,509 @@
|
|||||||
|
mod transformers;
|
||||||
|
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use error_stack::{IntoReport, ResultExt};
|
||||||
|
use masking::ExposeInterface;
|
||||||
|
use transformers as boku;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
configs::settings,
|
||||||
|
core::errors::{self, CustomResult},
|
||||||
|
headers,
|
||||||
|
services::{
|
||||||
|
self,
|
||||||
|
request::{self, Mask},
|
||||||
|
ConnectorIntegration,
|
||||||
|
},
|
||||||
|
types::{
|
||||||
|
self,
|
||||||
|
api::{self, ConnectorCommon, ConnectorCommonExt},
|
||||||
|
ErrorResponse, Response,
|
||||||
|
},
|
||||||
|
utils::{self, BytesExt},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Boku;
|
||||||
|
|
||||||
|
impl api::Payment for Boku {}
|
||||||
|
impl api::PaymentSession for Boku {}
|
||||||
|
impl api::ConnectorAccessToken for Boku {}
|
||||||
|
impl api::PreVerify for Boku {}
|
||||||
|
impl api::PaymentAuthorize for Boku {}
|
||||||
|
impl api::PaymentSync for Boku {}
|
||||||
|
impl api::PaymentCapture for Boku {}
|
||||||
|
impl api::PaymentVoid for Boku {}
|
||||||
|
impl api::Refund for Boku {}
|
||||||
|
impl api::RefundExecute for Boku {}
|
||||||
|
impl api::RefundSync for Boku {}
|
||||||
|
impl api::PaymentToken for Boku {}
|
||||||
|
|
||||||
|
impl
|
||||||
|
ConnectorIntegration<
|
||||||
|
api::PaymentMethodToken,
|
||||||
|
types::PaymentMethodTokenizationData,
|
||||||
|
types::PaymentsResponseData,
|
||||||
|
> for Boku
|
||||||
|
{
|
||||||
|
// Not Implemented (R)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Boku
|
||||||
|
where
|
||||||
|
Self: ConnectorIntegration<Flow, Request, Response>,
|
||||||
|
{
|
||||||
|
fn build_headers(
|
||||||
|
&self,
|
||||||
|
req: &types::RouterData<Flow, Request, Response>,
|
||||||
|
_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_string()
|
||||||
|
.into(),
|
||||||
|
)];
|
||||||
|
let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
|
||||||
|
header.append(&mut api_key);
|
||||||
|
Ok(header)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConnectorCommon for Boku {
|
||||||
|
fn id(&self) -> &'static str {
|
||||||
|
"boku"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn common_get_content_type(&self) -> &'static str {
|
||||||
|
"application/json"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str {
|
||||||
|
connectors.boku.base_url.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_auth_header(
|
||||||
|
&self,
|
||||||
|
auth_type: &types::ConnectorAuthType,
|
||||||
|
) -> CustomResult<Vec<(String, request::Maskable<String>)>, errors::ConnectorError> {
|
||||||
|
let auth = boku::BokuAuthType::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,
|
||||||
|
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
|
||||||
|
let response: boku::BokuErrorResponse = res
|
||||||
|
.response
|
||||||
|
.parse_struct("BokuErrorResponse")
|
||||||
|
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||||
|
|
||||||
|
Ok(ErrorResponse {
|
||||||
|
status_code: res.status_code,
|
||||||
|
code: response.code,
|
||||||
|
message: response.message,
|
||||||
|
reason: response.reason,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConnectorIntegration<api::Session, types::PaymentsSessionData, types::PaymentsResponseData>
|
||||||
|
for Boku
|
||||||
|
{
|
||||||
|
//TODO: implement sessions flow
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConnectorIntegration<api::AccessTokenAuth, types::AccessTokenRequestData, types::AccessToken>
|
||||||
|
for Boku
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConnectorIntegration<api::Verify, types::VerifyRequestData, types::PaymentsResponseData>
|
||||||
|
for Boku
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::PaymentsResponseData>
|
||||||
|
for Boku
|
||||||
|
{
|
||||||
|
fn get_headers(
|
||||||
|
&self,
|
||||||
|
req: &types::PaymentsAuthorizeRouterData,
|
||||||
|
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::PaymentsAuthorizeRouterData,
|
||||||
|
_connectors: &settings::Connectors,
|
||||||
|
) -> CustomResult<String, errors::ConnectorError> {
|
||||||
|
Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_request_body(
|
||||||
|
&self,
|
||||||
|
req: &types::PaymentsAuthorizeRouterData,
|
||||||
|
) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> {
|
||||||
|
let req_obj = boku::BokuPaymentsRequest::try_from(req)?;
|
||||||
|
let boku_req = types::RequestBody::log_and_get_request_body(
|
||||||
|
&req_obj,
|
||||||
|
utils::Encode::<boku::BokuPaymentsRequest>::encode_to_string_of_json,
|
||||||
|
)
|
||||||
|
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
||||||
|
Ok(Some(boku_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: boku::BokuPaymentsResponse = res
|
||||||
|
.response
|
||||||
|
.parse_struct("Boku 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 Boku
|
||||||
|
{
|
||||||
|
fn get_headers(
|
||||||
|
&self,
|
||||||
|
req: &types::PaymentsSyncRouterData,
|
||||||
|
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::PaymentsSyncRouterData,
|
||||||
|
_connectors: &settings::Connectors,
|
||||||
|
) -> CustomResult<String, errors::ConnectorError> {
|
||||||
|
Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_request(
|
||||||
|
&self,
|
||||||
|
req: &types::PaymentsSyncRouterData,
|
||||||
|
connectors: &settings::Connectors,
|
||||||
|
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
|
||||||
|
Ok(Some(
|
||||||
|
services::RequestBuilder::new()
|
||||||
|
.method(services::Method::Get)
|
||||||
|
.url(&types::PaymentsSyncType::get_url(self, req, connectors)?)
|
||||||
|
.attach_default_headers()
|
||||||
|
.headers(types::PaymentsSyncType::get_headers(self, req, connectors)?)
|
||||||
|
.build(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_response(
|
||||||
|
&self,
|
||||||
|
data: &types::PaymentsSyncRouterData,
|
||||||
|
res: Response,
|
||||||
|
) -> CustomResult<types::PaymentsSyncRouterData, errors::ConnectorError> {
|
||||||
|
let response: boku::BokuPaymentsResponse = res
|
||||||
|
.response
|
||||||
|
.parse_struct("boku PaymentsSyncResponse")
|
||||||
|
.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::Capture, types::PaymentsCaptureData, types::PaymentsResponseData>
|
||||||
|
for Boku
|
||||||
|
{
|
||||||
|
fn get_headers(
|
||||||
|
&self,
|
||||||
|
req: &types::PaymentsCaptureRouterData,
|
||||||
|
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::PaymentsCaptureRouterData,
|
||||||
|
_connectors: &settings::Connectors,
|
||||||
|
) -> CustomResult<String, errors::ConnectorError> {
|
||||||
|
Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_request_body(
|
||||||
|
&self,
|
||||||
|
_req: &types::PaymentsCaptureRouterData,
|
||||||
|
) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> {
|
||||||
|
Err(errors::ConnectorError::NotImplemented("get_request_body method".to_string()).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_request(
|
||||||
|
&self,
|
||||||
|
req: &types::PaymentsCaptureRouterData,
|
||||||
|
connectors: &settings::Connectors,
|
||||||
|
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
|
||||||
|
Ok(Some(
|
||||||
|
services::RequestBuilder::new()
|
||||||
|
.method(services::Method::Post)
|
||||||
|
.url(&types::PaymentsCaptureType::get_url(self, req, connectors)?)
|
||||||
|
.attach_default_headers()
|
||||||
|
.headers(types::PaymentsCaptureType::get_headers(
|
||||||
|
self, req, connectors,
|
||||||
|
)?)
|
||||||
|
.body(types::PaymentsCaptureType::get_request_body(self, req)?)
|
||||||
|
.build(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_response(
|
||||||
|
&self,
|
||||||
|
data: &types::PaymentsCaptureRouterData,
|
||||||
|
res: Response,
|
||||||
|
) -> CustomResult<types::PaymentsCaptureRouterData, errors::ConnectorError> {
|
||||||
|
let response: boku::BokuPaymentsResponse = res
|
||||||
|
.response
|
||||||
|
.parse_struct("Boku PaymentsCaptureResponse")
|
||||||
|
.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::Void, types::PaymentsCancelData, types::PaymentsResponseData>
|
||||||
|
for Boku
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsResponseData> for Boku {
|
||||||
|
fn get_headers(
|
||||||
|
&self,
|
||||||
|
req: &types::RefundsRouterData<api::Execute>,
|
||||||
|
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::RefundsRouterData<api::Execute>,
|
||||||
|
_connectors: &settings::Connectors,
|
||||||
|
) -> CustomResult<String, errors::ConnectorError> {
|
||||||
|
Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_request_body(
|
||||||
|
&self,
|
||||||
|
req: &types::RefundsRouterData<api::Execute>,
|
||||||
|
) -> CustomResult<Option<types::RequestBody>, errors::ConnectorError> {
|
||||||
|
let req_obj = boku::BokuRefundRequest::try_from(req)?;
|
||||||
|
let boku_req = types::RequestBody::log_and_get_request_body(
|
||||||
|
&req_obj,
|
||||||
|
utils::Encode::<boku::BokuRefundRequest>::encode_to_string_of_json,
|
||||||
|
)
|
||||||
|
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
||||||
|
Ok(Some(boku_req))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_request(
|
||||||
|
&self,
|
||||||
|
req: &types::RefundsRouterData<api::Execute>,
|
||||||
|
connectors: &settings::Connectors,
|
||||||
|
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
|
||||||
|
let request = services::RequestBuilder::new()
|
||||||
|
.method(services::Method::Post)
|
||||||
|
.url(&types::RefundExecuteType::get_url(self, req, connectors)?)
|
||||||
|
.attach_default_headers()
|
||||||
|
.headers(types::RefundExecuteType::get_headers(
|
||||||
|
self, req, connectors,
|
||||||
|
)?)
|
||||||
|
.body(types::RefundExecuteType::get_request_body(self, req)?)
|
||||||
|
.build();
|
||||||
|
Ok(Some(request))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_response(
|
||||||
|
&self,
|
||||||
|
data: &types::RefundsRouterData<api::Execute>,
|
||||||
|
res: Response,
|
||||||
|
) -> CustomResult<types::RefundsRouterData<api::Execute>, errors::ConnectorError> {
|
||||||
|
let response: boku::RefundResponse = res
|
||||||
|
.response
|
||||||
|
.parse_struct("boku RefundResponse")
|
||||||
|
.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::RSync, types::RefundsData, types::RefundsResponseData> for Boku {
|
||||||
|
fn get_headers(
|
||||||
|
&self,
|
||||||
|
req: &types::RefundSyncRouterData,
|
||||||
|
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::RefundSyncRouterData,
|
||||||
|
_connectors: &settings::Connectors,
|
||||||
|
) -> CustomResult<String, errors::ConnectorError> {
|
||||||
|
Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_request(
|
||||||
|
&self,
|
||||||
|
req: &types::RefundSyncRouterData,
|
||||||
|
connectors: &settings::Connectors,
|
||||||
|
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
|
||||||
|
Ok(Some(
|
||||||
|
services::RequestBuilder::new()
|
||||||
|
.method(services::Method::Get)
|
||||||
|
.url(&types::RefundSyncType::get_url(self, req, connectors)?)
|
||||||
|
.attach_default_headers()
|
||||||
|
.headers(types::RefundSyncType::get_headers(self, req, connectors)?)
|
||||||
|
.body(types::RefundSyncType::get_request_body(self, req)?)
|
||||||
|
.build(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_response(
|
||||||
|
&self,
|
||||||
|
data: &types::RefundSyncRouterData,
|
||||||
|
res: Response,
|
||||||
|
) -> CustomResult<types::RefundSyncRouterData, errors::ConnectorError> {
|
||||||
|
let response: boku::RefundResponse =
|
||||||
|
res.response
|
||||||
|
.parse_struct("boku RefundSyncResponse")
|
||||||
|
.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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl api::IncomingWebhook for Boku {
|
||||||
|
fn get_webhook_object_reference_id(
|
||||||
|
&self,
|
||||||
|
_request: &api::IncomingWebhookRequestDetails<'_>,
|
||||||
|
) -> CustomResult<api::webhooks::ObjectReferenceId, errors::ConnectorError> {
|
||||||
|
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_webhook_event_type(
|
||||||
|
&self,
|
||||||
|
_request: &api::IncomingWebhookRequestDetails<'_>,
|
||||||
|
) -> CustomResult<api::IncomingWebhookEvent, errors::ConnectorError> {
|
||||||
|
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_webhook_resource_object(
|
||||||
|
&self,
|
||||||
|
_request: &api::IncomingWebhookRequestDetails<'_>,
|
||||||
|
) -> CustomResult<serde_json::Value, errors::ConnectorError> {
|
||||||
|
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
|
||||||
|
}
|
||||||
|
}
|
||||||
196
crates/router/src/connector/boku/transformers.rs
Normal file
196
crates/router/src/connector/boku/transformers.rs
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
use masking::Secret;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
connector::utils::PaymentsAuthorizeRequestData,
|
||||||
|
core::errors,
|
||||||
|
types::{self, api, storage::enums},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Serialize, Eq, PartialEq)]
|
||||||
|
pub struct BokuPaymentsRequest {
|
||||||
|
amount: i64,
|
||||||
|
card: BokuCard,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Serialize, Eq, PartialEq)]
|
||||||
|
pub struct BokuCard {
|
||||||
|
name: Secret<String>,
|
||||||
|
number: cards::CardNumber,
|
||||||
|
expiry_month: Secret<String>,
|
||||||
|
expiry_year: Secret<String>,
|
||||||
|
cvc: Secret<String>,
|
||||||
|
complete: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&types::PaymentsAuthorizeRouterData> for BokuPaymentsRequest {
|
||||||
|
type Error = error_stack::Report<errors::ConnectorError>;
|
||||||
|
fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result<Self, Self::Error> {
|
||||||
|
match item.request.payment_method_data.clone() {
|
||||||
|
api::PaymentMethodData::Card(req_card) => {
|
||||||
|
let card = BokuCard {
|
||||||
|
name: req_card.card_holder_name,
|
||||||
|
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.request.is_auto_capture()?,
|
||||||
|
};
|
||||||
|
Ok(Self {
|
||||||
|
amount: item.request.amount,
|
||||||
|
card,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auth Struct
|
||||||
|
pub struct BokuAuthType {
|
||||||
|
pub(super) api_key: Secret<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&types::ConnectorAuthType> for BokuAuthType {
|
||||||
|
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: Secret::new(api_key.to_string()),
|
||||||
|
}),
|
||||||
|
_ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PaymentsResponse
|
||||||
|
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
pub enum BokuPaymentStatus {
|
||||||
|
Succeeded,
|
||||||
|
Failed,
|
||||||
|
#[default]
|
||||||
|
Processing,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<BokuPaymentStatus> for enums::AttemptStatus {
|
||||||
|
fn from(item: BokuPaymentStatus) -> Self {
|
||||||
|
match item {
|
||||||
|
BokuPaymentStatus::Succeeded => Self::Charged,
|
||||||
|
BokuPaymentStatus::Failed => Self::Failure,
|
||||||
|
BokuPaymentStatus::Processing => Self::Authorizing,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub struct BokuPaymentsResponse {
|
||||||
|
status: BokuPaymentStatus,
|
||||||
|
id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F, T>
|
||||||
|
TryFrom<types::ResponseRouterData<F, BokuPaymentsResponse, T, types::PaymentsResponseData>>
|
||||||
|
for types::RouterData<F, T, types::PaymentsResponseData>
|
||||||
|
{
|
||||||
|
type Error = error_stack::Report<errors::ConnectorError>;
|
||||||
|
fn try_from(
|
||||||
|
item: types::ResponseRouterData<F, BokuPaymentsResponse, T, types::PaymentsResponseData>,
|
||||||
|
) -> Result<Self, Self::Error> {
|
||||||
|
Ok(Self {
|
||||||
|
status: enums::AttemptStatus::from(item.response.status),
|
||||||
|
response: Ok(types::PaymentsResponseData::TransactionResponse {
|
||||||
|
resource_id: types::ResponseId::ConnectorTransactionId(item.response.id),
|
||||||
|
redirection_data: None,
|
||||||
|
mandate_reference: None,
|
||||||
|
connector_metadata: None,
|
||||||
|
network_txn_id: None,
|
||||||
|
connector_response_reference_id: None,
|
||||||
|
}),
|
||||||
|
..item.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// REFUND :
|
||||||
|
#[derive(Default, Debug, Serialize)]
|
||||||
|
pub struct BokuRefundRequest {
|
||||||
|
pub amount: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F> TryFrom<&types::RefundsRouterData<F>> for BokuRefundRequest {
|
||||||
|
type Error = error_stack::Report<errors::ConnectorError>;
|
||||||
|
fn try_from(item: &types::RefundsRouterData<F>) -> Result<Self, Self::Error> {
|
||||||
|
Ok(Self {
|
||||||
|
amount: item.request.refund_amount,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
match item {
|
||||||
|
RefundStatus::Succeeded => Self::Success,
|
||||||
|
RefundStatus::Failed => Self::Failure,
|
||||||
|
RefundStatus::Processing => Self::Pending,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct RefundResponse {
|
||||||
|
id: String,
|
||||||
|
status: RefundStatus,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<types::RefundsResponseRouterData<api::Execute, RefundResponse>>
|
||||||
|
for types::RefundsRouterData<api::Execute>
|
||||||
|
{
|
||||||
|
type Error = error_stack::Report<errors::ConnectorError>;
|
||||||
|
fn try_from(
|
||||||
|
item: types::RefundsResponseRouterData<api::Execute, RefundResponse>,
|
||||||
|
) -> Result<Self, Self::Error> {
|
||||||
|
Ok(Self {
|
||||||
|
response: Ok(types::RefundsResponseData {
|
||||||
|
connector_refund_id: item.response.id.to_string(),
|
||||||
|
refund_status: enums::RefundStatus::from(item.response.status),
|
||||||
|
}),
|
||||||
|
..item.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<types::RefundsResponseRouterData<api::RSync, RefundResponse>>
|
||||||
|
for types::RefundsRouterData<api::RSync>
|
||||||
|
{
|
||||||
|
type Error = error_stack::Report<errors::ConnectorError>;
|
||||||
|
fn try_from(
|
||||||
|
item: types::RefundsResponseRouterData<api::RSync, RefundResponse>,
|
||||||
|
) -> Result<Self, Self::Error> {
|
||||||
|
Ok(Self {
|
||||||
|
response: Ok(types::RefundsResponseData {
|
||||||
|
connector_refund_id: item.response.id.to_string(),
|
||||||
|
refund_status: enums::RefundStatus::from(item.response.status),
|
||||||
|
}),
|
||||||
|
..item.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub struct BokuErrorResponse {
|
||||||
|
pub status_code: u16,
|
||||||
|
pub code: String,
|
||||||
|
pub message: String,
|
||||||
|
pub reason: Option<String>,
|
||||||
|
}
|
||||||
@ -142,6 +142,7 @@ default_imp_for_complete_authorize!(
|
|||||||
connector::Adyen,
|
connector::Adyen,
|
||||||
connector::Bitpay,
|
connector::Bitpay,
|
||||||
connector::Braintree,
|
connector::Braintree,
|
||||||
|
connector::Boku,
|
||||||
connector::Cashtocode,
|
connector::Cashtocode,
|
||||||
connector::Checkout,
|
connector::Checkout,
|
||||||
connector::Coinbase,
|
connector::Coinbase,
|
||||||
@ -207,6 +208,7 @@ default_imp_for_create_customer!(
|
|||||||
connector::Authorizedotnet,
|
connector::Authorizedotnet,
|
||||||
connector::Bambora,
|
connector::Bambora,
|
||||||
connector::Bitpay,
|
connector::Bitpay,
|
||||||
|
connector::Boku,
|
||||||
connector::Braintree,
|
connector::Braintree,
|
||||||
connector::Cashtocode,
|
connector::Cashtocode,
|
||||||
connector::Checkout,
|
connector::Checkout,
|
||||||
@ -277,6 +279,7 @@ default_imp_for_connector_redirect_response!(
|
|||||||
connector::Aci,
|
connector::Aci,
|
||||||
connector::Adyen,
|
connector::Adyen,
|
||||||
connector::Bitpay,
|
connector::Bitpay,
|
||||||
|
connector::Boku,
|
||||||
connector::Braintree,
|
connector::Braintree,
|
||||||
connector::Cashtocode,
|
connector::Cashtocode,
|
||||||
connector::Coinbase,
|
connector::Coinbase,
|
||||||
@ -325,6 +328,7 @@ default_imp_for_connector_request_id!(
|
|||||||
connector::Bambora,
|
connector::Bambora,
|
||||||
connector::Bitpay,
|
connector::Bitpay,
|
||||||
connector::Bluesnap,
|
connector::Bluesnap,
|
||||||
|
connector::Boku,
|
||||||
connector::Braintree,
|
connector::Braintree,
|
||||||
connector::Cashtocode,
|
connector::Cashtocode,
|
||||||
connector::Checkout,
|
connector::Checkout,
|
||||||
@ -399,6 +403,7 @@ default_imp_for_accept_dispute!(
|
|||||||
connector::Bambora,
|
connector::Bambora,
|
||||||
connector::Bitpay,
|
connector::Bitpay,
|
||||||
connector::Bluesnap,
|
connector::Bluesnap,
|
||||||
|
connector::Boku,
|
||||||
connector::Braintree,
|
connector::Braintree,
|
||||||
connector::Cashtocode,
|
connector::Cashtocode,
|
||||||
connector::Coinbase,
|
connector::Coinbase,
|
||||||
@ -493,6 +498,7 @@ default_imp_for_file_upload!(
|
|||||||
connector::Bambora,
|
connector::Bambora,
|
||||||
connector::Bitpay,
|
connector::Bitpay,
|
||||||
connector::Bluesnap,
|
connector::Bluesnap,
|
||||||
|
connector::Boku,
|
||||||
connector::Braintree,
|
connector::Braintree,
|
||||||
connector::Cashtocode,
|
connector::Cashtocode,
|
||||||
connector::Coinbase,
|
connector::Coinbase,
|
||||||
@ -564,6 +570,7 @@ default_imp_for_submit_evidence!(
|
|||||||
connector::Bambora,
|
connector::Bambora,
|
||||||
connector::Bitpay,
|
connector::Bitpay,
|
||||||
connector::Bluesnap,
|
connector::Bluesnap,
|
||||||
|
connector::Boku,
|
||||||
connector::Braintree,
|
connector::Braintree,
|
||||||
connector::Cashtocode,
|
connector::Cashtocode,
|
||||||
connector::Cybersource,
|
connector::Cybersource,
|
||||||
@ -635,6 +642,7 @@ default_imp_for_defend_dispute!(
|
|||||||
connector::Bambora,
|
connector::Bambora,
|
||||||
connector::Bitpay,
|
connector::Bitpay,
|
||||||
connector::Bluesnap,
|
connector::Bluesnap,
|
||||||
|
connector::Boku,
|
||||||
connector::Braintree,
|
connector::Braintree,
|
||||||
connector::Cashtocode,
|
connector::Cashtocode,
|
||||||
connector::Cybersource,
|
connector::Cybersource,
|
||||||
@ -707,6 +715,7 @@ default_imp_for_pre_processing_steps!(
|
|||||||
connector::Bambora,
|
connector::Bambora,
|
||||||
connector::Bitpay,
|
connector::Bitpay,
|
||||||
connector::Bluesnap,
|
connector::Bluesnap,
|
||||||
|
connector::Boku,
|
||||||
connector::Braintree,
|
connector::Braintree,
|
||||||
connector::Cashtocode,
|
connector::Cashtocode,
|
||||||
connector::Checkout,
|
connector::Checkout,
|
||||||
@ -760,6 +769,7 @@ default_imp_for_payouts!(
|
|||||||
connector::Bambora,
|
connector::Bambora,
|
||||||
connector::Bitpay,
|
connector::Bitpay,
|
||||||
connector::Bluesnap,
|
connector::Bluesnap,
|
||||||
|
connector::Boku,
|
||||||
connector::Braintree,
|
connector::Braintree,
|
||||||
connector::Cashtocode,
|
connector::Cashtocode,
|
||||||
connector::Checkout,
|
connector::Checkout,
|
||||||
@ -832,6 +842,7 @@ default_imp_for_payouts_create!(
|
|||||||
connector::Bambora,
|
connector::Bambora,
|
||||||
connector::Bitpay,
|
connector::Bitpay,
|
||||||
connector::Bluesnap,
|
connector::Bluesnap,
|
||||||
|
connector::Boku,
|
||||||
connector::Braintree,
|
connector::Braintree,
|
||||||
connector::Cashtocode,
|
connector::Cashtocode,
|
||||||
connector::Checkout,
|
connector::Checkout,
|
||||||
@ -907,6 +918,7 @@ default_imp_for_payouts_eligibility!(
|
|||||||
connector::Bambora,
|
connector::Bambora,
|
||||||
connector::Bitpay,
|
connector::Bitpay,
|
||||||
connector::Bluesnap,
|
connector::Bluesnap,
|
||||||
|
connector::Boku,
|
||||||
connector::Braintree,
|
connector::Braintree,
|
||||||
connector::Cashtocode,
|
connector::Cashtocode,
|
||||||
connector::Checkout,
|
connector::Checkout,
|
||||||
@ -979,6 +991,7 @@ default_imp_for_payouts_fulfill!(
|
|||||||
connector::Bambora,
|
connector::Bambora,
|
||||||
connector::Bitpay,
|
connector::Bitpay,
|
||||||
connector::Bluesnap,
|
connector::Bluesnap,
|
||||||
|
connector::Boku,
|
||||||
connector::Braintree,
|
connector::Braintree,
|
||||||
connector::Cashtocode,
|
connector::Cashtocode,
|
||||||
connector::Checkout,
|
connector::Checkout,
|
||||||
@ -1051,6 +1064,7 @@ default_imp_for_payouts_cancel!(
|
|||||||
connector::Bambora,
|
connector::Bambora,
|
||||||
connector::Bitpay,
|
connector::Bitpay,
|
||||||
connector::Bluesnap,
|
connector::Bluesnap,
|
||||||
|
connector::Boku,
|
||||||
connector::Braintree,
|
connector::Braintree,
|
||||||
connector::Cashtocode,
|
connector::Cashtocode,
|
||||||
connector::Checkout,
|
connector::Checkout,
|
||||||
@ -1124,6 +1138,7 @@ default_imp_for_payouts_quote!(
|
|||||||
connector::Bambora,
|
connector::Bambora,
|
||||||
connector::Bitpay,
|
connector::Bitpay,
|
||||||
connector::Bluesnap,
|
connector::Bluesnap,
|
||||||
|
connector::Boku,
|
||||||
connector::Braintree,
|
connector::Braintree,
|
||||||
connector::Cashtocode,
|
connector::Cashtocode,
|
||||||
connector::Checkout,
|
connector::Checkout,
|
||||||
@ -1197,6 +1212,7 @@ default_imp_for_payouts_recipient!(
|
|||||||
connector::Bambora,
|
connector::Bambora,
|
||||||
connector::Bitpay,
|
connector::Bitpay,
|
||||||
connector::Bluesnap,
|
connector::Bluesnap,
|
||||||
|
connector::Boku,
|
||||||
connector::Braintree,
|
connector::Braintree,
|
||||||
connector::Cashtocode,
|
connector::Cashtocode,
|
||||||
connector::Checkout,
|
connector::Checkout,
|
||||||
|
|||||||
@ -279,6 +279,7 @@ impl ConnectorData {
|
|||||||
enums::Connector::Bambora => Ok(Box::new(&connector::Bambora)),
|
enums::Connector::Bambora => Ok(Box::new(&connector::Bambora)),
|
||||||
enums::Connector::Bitpay => Ok(Box::new(&connector::Bitpay)),
|
enums::Connector::Bitpay => Ok(Box::new(&connector::Bitpay)),
|
||||||
enums::Connector::Bluesnap => Ok(Box::new(&connector::Bluesnap)),
|
enums::Connector::Bluesnap => Ok(Box::new(&connector::Bluesnap)),
|
||||||
|
// enums::Connector::Boku => Ok(Box::new(&connector::Boku)), added as template code for future usage
|
||||||
enums::Connector::Braintree => Ok(Box::new(&connector::Braintree)),
|
enums::Connector::Braintree => Ok(Box::new(&connector::Braintree)),
|
||||||
enums::Connector::Cashtocode => Ok(Box::new(&connector::Cashtocode)),
|
enums::Connector::Cashtocode => Ok(Box::new(&connector::Cashtocode)),
|
||||||
enums::Connector::Checkout => Ok(Box::new(&connector::Checkout)),
|
enums::Connector::Checkout => Ok(Box::new(&connector::Checkout)),
|
||||||
|
|||||||
418
crates/router/tests/connectors/boku.rs
Normal file
418
crates/router/tests/connectors/boku.rs
Normal file
@ -0,0 +1,418 @@
|
|||||||
|
use masking::Secret;
|
||||||
|
use router::types::{self, api, storage::enums};
|
||||||
|
use test_utils::connector_auth;
|
||||||
|
|
||||||
|
use crate::utils::{self, ConnectorActions};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct BokuTest;
|
||||||
|
impl ConnectorActions for BokuTest {}
|
||||||
|
impl utils::Connector for BokuTest {
|
||||||
|
fn get_data(&self) -> types::api::ConnectorData {
|
||||||
|
use router::connector::Boku;
|
||||||
|
types::api::ConnectorData {
|
||||||
|
connector: Box::new(&Boku),
|
||||||
|
connector_name: types::Connector::DummyConnector1,
|
||||||
|
get_token: types::api::GetToken::Connector,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_auth_token(&self) -> types::ConnectorAuthType {
|
||||||
|
types::ConnectorAuthType::from(
|
||||||
|
connector_auth::ConnectorAuthentication::new()
|
||||||
|
.boku
|
||||||
|
.expect("Missing connector authentication configuration"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_name(&self) -> String {
|
||||||
|
"boku".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static CONNECTOR: BokuTest = BokuTest {};
|
||||||
|
|
||||||
|
fn get_default_payment_info() -> Option<utils::PaymentInfo> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn payment_method_details() -> Option<types::PaymentsAuthorizeData> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cards Positive Tests
|
||||||
|
// Creates a payment using the manual capture flow (Non 3DS).
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn should_only_authorize_payment() {
|
||||||
|
let response = CONNECTOR
|
||||||
|
.authorize_payment(payment_method_details(), get_default_payment_info())
|
||||||
|
.await
|
||||||
|
.expect("Authorize payment response");
|
||||||
|
assert_eq!(response.status, enums::AttemptStatus::Authorized);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Captures a payment using the manual capture flow (Non 3DS).
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn should_capture_authorized_payment() {
|
||||||
|
let response = CONNECTOR
|
||||||
|
.authorize_and_capture_payment(payment_method_details(), None, get_default_payment_info())
|
||||||
|
.await
|
||||||
|
.expect("Capture payment response");
|
||||||
|
assert_eq!(response.status, enums::AttemptStatus::Charged);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Partially captures a payment using the manual capture flow (Non 3DS).
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn should_partially_capture_authorized_payment() {
|
||||||
|
let response = CONNECTOR
|
||||||
|
.authorize_and_capture_payment(
|
||||||
|
payment_method_details(),
|
||||||
|
Some(types::PaymentsCaptureData {
|
||||||
|
amount_to_capture: 50,
|
||||||
|
..utils::PaymentCaptureType::default().0
|
||||||
|
}),
|
||||||
|
get_default_payment_info(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("Capture payment response");
|
||||||
|
assert_eq!(response.status, enums::AttemptStatus::Charged);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synchronizes a payment using the manual capture flow (Non 3DS).
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn should_sync_authorized_payment() {
|
||||||
|
let authorize_response = CONNECTOR
|
||||||
|
.authorize_payment(payment_method_details(), get_default_payment_info())
|
||||||
|
.await
|
||||||
|
.expect("Authorize payment response");
|
||||||
|
let txn_id = utils::get_connector_transaction_id(authorize_response.response);
|
||||||
|
let response = CONNECTOR
|
||||||
|
.psync_retry_till_status_matches(
|
||||||
|
enums::AttemptStatus::Authorized,
|
||||||
|
Some(types::PaymentsSyncData {
|
||||||
|
connector_transaction_id: router::types::ResponseId::ConnectorTransactionId(
|
||||||
|
txn_id.unwrap(),
|
||||||
|
),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
get_default_payment_info(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("PSync response");
|
||||||
|
assert_eq!(response.status, enums::AttemptStatus::Authorized,);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Voids a payment using the manual capture flow (Non 3DS).
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn should_void_authorized_payment() {
|
||||||
|
let response = CONNECTOR
|
||||||
|
.authorize_and_void_payment(
|
||||||
|
payment_method_details(),
|
||||||
|
Some(types::PaymentsCancelData {
|
||||||
|
connector_transaction_id: String::from(""),
|
||||||
|
cancellation_reason: Some("requested_by_customer".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
get_default_payment_info(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("Void payment response");
|
||||||
|
assert_eq!(response.status, enums::AttemptStatus::Voided);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refunds a payment using the manual capture flow (Non 3DS).
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn should_refund_manually_captured_payment() {
|
||||||
|
let response = CONNECTOR
|
||||||
|
.capture_payment_and_refund(
|
||||||
|
payment_method_details(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
get_default_payment_info(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
response.response.unwrap().refund_status,
|
||||||
|
enums::RefundStatus::Success,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Partially refunds a payment using the manual capture flow (Non 3DS).
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn should_partially_refund_manually_captured_payment() {
|
||||||
|
let response = CONNECTOR
|
||||||
|
.capture_payment_and_refund(
|
||||||
|
payment_method_details(),
|
||||||
|
None,
|
||||||
|
Some(types::RefundsData {
|
||||||
|
refund_amount: 50,
|
||||||
|
..utils::PaymentRefundType::default().0
|
||||||
|
}),
|
||||||
|
get_default_payment_info(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
response.response.unwrap().refund_status,
|
||||||
|
enums::RefundStatus::Success,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synchronizes a refund using the manual capture flow (Non 3DS).
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn should_sync_manually_captured_refund() {
|
||||||
|
let refund_response = CONNECTOR
|
||||||
|
.capture_payment_and_refund(
|
||||||
|
payment_method_details(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
get_default_payment_info(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let response = CONNECTOR
|
||||||
|
.rsync_retry_till_status_matches(
|
||||||
|
enums::RefundStatus::Success,
|
||||||
|
refund_response.response.unwrap().connector_refund_id,
|
||||||
|
None,
|
||||||
|
get_default_payment_info(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
response.response.unwrap().refund_status,
|
||||||
|
enums::RefundStatus::Success,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a payment using the automatic capture flow (Non 3DS).
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn should_make_payment() {
|
||||||
|
let authorize_response = CONNECTOR
|
||||||
|
.make_payment(payment_method_details(), get_default_payment_info())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synchronizes a payment using the automatic capture flow (Non 3DS).
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn should_sync_auto_captured_payment() {
|
||||||
|
let authorize_response = CONNECTOR
|
||||||
|
.make_payment(payment_method_details(), get_default_payment_info())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
|
||||||
|
let txn_id = utils::get_connector_transaction_id(authorize_response.response);
|
||||||
|
assert_ne!(txn_id, None, "Empty connector transaction id");
|
||||||
|
let response = CONNECTOR
|
||||||
|
.psync_retry_till_status_matches(
|
||||||
|
enums::AttemptStatus::Charged,
|
||||||
|
Some(types::PaymentsSyncData {
|
||||||
|
connector_transaction_id: router::types::ResponseId::ConnectorTransactionId(
|
||||||
|
txn_id.unwrap(),
|
||||||
|
),
|
||||||
|
capture_method: Some(enums::CaptureMethod::Automatic),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
get_default_payment_info(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(response.status, enums::AttemptStatus::Charged,);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refunds a payment using the automatic capture flow (Non 3DS).
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn should_refund_auto_captured_payment() {
|
||||||
|
let response = CONNECTOR
|
||||||
|
.make_payment_and_refund(payment_method_details(), None, get_default_payment_info())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
response.response.unwrap().refund_status,
|
||||||
|
enums::RefundStatus::Success,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Partially refunds a payment using the automatic capture flow (Non 3DS).
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn should_partially_refund_succeeded_payment() {
|
||||||
|
let refund_response = CONNECTOR
|
||||||
|
.make_payment_and_refund(
|
||||||
|
payment_method_details(),
|
||||||
|
Some(types::RefundsData {
|
||||||
|
refund_amount: 50,
|
||||||
|
..utils::PaymentRefundType::default().0
|
||||||
|
}),
|
||||||
|
get_default_payment_info(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
refund_response.response.unwrap().refund_status,
|
||||||
|
enums::RefundStatus::Success,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates multiple refunds against a payment using the automatic capture flow (Non 3DS).
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn should_refund_succeeded_payment_multiple_times() {
|
||||||
|
CONNECTOR
|
||||||
|
.make_payment_and_multiple_refund(
|
||||||
|
payment_method_details(),
|
||||||
|
Some(types::RefundsData {
|
||||||
|
refund_amount: 50,
|
||||||
|
..utils::PaymentRefundType::default().0
|
||||||
|
}),
|
||||||
|
get_default_payment_info(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synchronizes a refund using the automatic capture flow (Non 3DS).
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn should_sync_refund() {
|
||||||
|
let refund_response = CONNECTOR
|
||||||
|
.make_payment_and_refund(payment_method_details(), None, get_default_payment_info())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let response = CONNECTOR
|
||||||
|
.rsync_retry_till_status_matches(
|
||||||
|
enums::RefundStatus::Success,
|
||||||
|
refund_response.response.unwrap().connector_refund_id,
|
||||||
|
None,
|
||||||
|
get_default_payment_info(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
response.response.unwrap().refund_status,
|
||||||
|
enums::RefundStatus::Success,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cards Negative scenerios
|
||||||
|
// Creates a payment with incorrect CVC.
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn should_fail_payment_for_incorrect_cvc() {
|
||||||
|
let response = CONNECTOR
|
||||||
|
.make_payment(
|
||||||
|
Some(types::PaymentsAuthorizeData {
|
||||||
|
payment_method_data: types::api::PaymentMethodData::Card(api::Card {
|
||||||
|
card_cvc: Secret::new("12345".to_string()),
|
||||||
|
..utils::CCardType::default().0
|
||||||
|
}),
|
||||||
|
..utils::PaymentAuthorizeType::default().0
|
||||||
|
}),
|
||||||
|
get_default_payment_info(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
response.response.unwrap_err().message,
|
||||||
|
"Your card's security code is invalid.".to_string(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a payment with incorrect expiry month.
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn should_fail_payment_for_invalid_exp_month() {
|
||||||
|
let response = CONNECTOR
|
||||||
|
.make_payment(
|
||||||
|
Some(types::PaymentsAuthorizeData {
|
||||||
|
payment_method_data: types::api::PaymentMethodData::Card(api::Card {
|
||||||
|
card_exp_month: Secret::new("20".to_string()),
|
||||||
|
..utils::CCardType::default().0
|
||||||
|
}),
|
||||||
|
..utils::PaymentAuthorizeType::default().0
|
||||||
|
}),
|
||||||
|
get_default_payment_info(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
response.response.unwrap_err().message,
|
||||||
|
"Your card's expiration month is invalid.".to_string(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a payment with incorrect expiry year.
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn should_fail_payment_for_incorrect_expiry_year() {
|
||||||
|
let response = CONNECTOR
|
||||||
|
.make_payment(
|
||||||
|
Some(types::PaymentsAuthorizeData {
|
||||||
|
payment_method_data: types::api::PaymentMethodData::Card(api::Card {
|
||||||
|
card_exp_year: Secret::new("2000".to_string()),
|
||||||
|
..utils::CCardType::default().0
|
||||||
|
}),
|
||||||
|
..utils::PaymentAuthorizeType::default().0
|
||||||
|
}),
|
||||||
|
get_default_payment_info(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
response.response.unwrap_err().message,
|
||||||
|
"Your card's expiration year is invalid.".to_string(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Voids a payment using automatic capture flow (Non 3DS).
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn should_fail_void_payment_for_auto_capture() {
|
||||||
|
let authorize_response = CONNECTOR
|
||||||
|
.make_payment(payment_method_details(), get_default_payment_info())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
|
||||||
|
let txn_id = utils::get_connector_transaction_id(authorize_response.response);
|
||||||
|
assert_ne!(txn_id, None, "Empty connector transaction id");
|
||||||
|
let void_response = CONNECTOR
|
||||||
|
.void_payment(txn_id.unwrap(), None, get_default_payment_info())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
void_response.response.unwrap_err().message,
|
||||||
|
"You cannot cancel this PaymentIntent because it has a status of succeeded."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Captures a payment using invalid connector payment id.
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn should_fail_capture_for_invalid_payment() {
|
||||||
|
let capture_response = CONNECTOR
|
||||||
|
.capture_payment("123456789".to_string(), None, get_default_payment_info())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
capture_response.response.unwrap_err().message,
|
||||||
|
String::from("No such payment_intent: '123456789'")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refunds a payment with refund amount higher than payment amount.
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn should_fail_for_refund_amount_higher_than_payment_amount() {
|
||||||
|
let response = CONNECTOR
|
||||||
|
.make_payment_and_refund(
|
||||||
|
payment_method_details(),
|
||||||
|
Some(types::RefundsData {
|
||||||
|
refund_amount: 150,
|
||||||
|
..utils::PaymentRefundType::default().0
|
||||||
|
}),
|
||||||
|
get_default_payment_info(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
response.response.unwrap_err().message,
|
||||||
|
"Refund amount (₹1.50) is greater than charge amount (₹1.00)",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connector dependent test cases goes here
|
||||||
|
|
||||||
|
// [#478]: add unit tests for non 3DS, wallets & webhooks in connector tests
|
||||||
@ -19,6 +19,7 @@ mod bambora_ui;
|
|||||||
mod bitpay;
|
mod bitpay;
|
||||||
mod bluesnap;
|
mod bluesnap;
|
||||||
mod bluesnap_ui;
|
mod bluesnap_ui;
|
||||||
|
mod boku;
|
||||||
mod cashtocode;
|
mod cashtocode;
|
||||||
mod checkout;
|
mod checkout;
|
||||||
mod checkout_ui;
|
mod checkout_ui;
|
||||||
|
|||||||
@ -164,3 +164,7 @@ key1 = "PowerTranz-PowerTranzId"
|
|||||||
|
|
||||||
[stax]
|
[stax]
|
||||||
api_key="API Key"
|
api_key="API Key"
|
||||||
|
|
||||||
|
[boku]
|
||||||
|
api_key="API Key"
|
||||||
|
key1 = "transaction key"
|
||||||
@ -20,6 +20,7 @@ pub struct ConnectorAuthentication {
|
|||||||
pub bambora: Option<BodyKey>,
|
pub bambora: Option<BodyKey>,
|
||||||
pub bitpay: Option<HeaderKey>,
|
pub bitpay: Option<HeaderKey>,
|
||||||
pub bluesnap: Option<BodyKey>,
|
pub bluesnap: Option<BodyKey>,
|
||||||
|
pub boku: Option<BodyKey>,
|
||||||
pub cashtocode: Option<BodyKey>,
|
pub cashtocode: Option<BodyKey>,
|
||||||
pub checkout: Option<SignatureKey>,
|
pub checkout: Option<SignatureKey>,
|
||||||
pub coinbase: Option<HeaderKey>,
|
pub coinbase: Option<HeaderKey>,
|
||||||
|
|||||||
@ -66,6 +66,7 @@ authorizedotnet.base_url = "https://apitest.authorize.net/xml/v1/request.api"
|
|||||||
bambora.base_url = "https://api.na.bambora.com"
|
bambora.base_url = "https://api.na.bambora.com"
|
||||||
bitpay.base_url = "https://test.bitpay.com"
|
bitpay.base_url = "https://test.bitpay.com"
|
||||||
bluesnap.base_url = "https://sandbox.bluesnap.com/"
|
bluesnap.base_url = "https://sandbox.bluesnap.com/"
|
||||||
|
boku.base_url = "https://country-api4-stage.boku.com"
|
||||||
braintree.base_url = "https://api.sandbox.braintreegateway.com/"
|
braintree.base_url = "https://api.sandbox.braintreegateway.com/"
|
||||||
cashtocode.base_url = "https://cluster05.api-test.cashtocode.com"
|
cashtocode.base_url = "https://cluster05.api-test.cashtocode.com"
|
||||||
checkout.base_url = "https://api.sandbox.checkout.com/"
|
checkout.base_url = "https://api.sandbox.checkout.com/"
|
||||||
@ -118,6 +119,7 @@ cards = [
|
|||||||
"bambora",
|
"bambora",
|
||||||
"bitpay",
|
"bitpay",
|
||||||
"bluesnap",
|
"bluesnap",
|
||||||
|
"boku",
|
||||||
"braintree",
|
"braintree",
|
||||||
"checkout",
|
"checkout",
|
||||||
"coinbase",
|
"coinbase",
|
||||||
|
|||||||
@ -6,7 +6,7 @@ function find_prev_connector() {
|
|||||||
git checkout $self
|
git checkout $self
|
||||||
cp $self $self.tmp
|
cp $self $self.tmp
|
||||||
# Add new connector to existing list and sort it
|
# Add new connector to existing list and sort it
|
||||||
connectors=(aci adyen airwallex applepay authorizedotnet bambora bitpay bluesnap braintree cashtocode checkout coinbase cryptopay cybersource dlocal dummyconnector fiserv forte globalpay globepay iatapay klarna mollie multisafepay nexinets noon nuvei opayo opennode payeezy payme paypal payu powertranz rapyd shift4 stax stripe trustpay tsys wise worldline worldpay "$1")
|
connectors=(aci adyen airwallex applepay authorizedotnet bambora bitpay bluesnap boku braintree cashtocode checkout coinbase cryptopay cybersource dlocal dummyconnector fiserv forte globalpay globepay iatapay klarna mollie multisafepay nexinets noon nuvei opayo opennode payeezy payme paypal payu powertranz rapyd shift4 stax stripe trustpay tsys wise worldline worldpay "$1")
|
||||||
IFS=$'\n' sorted=($(sort <<<"${connectors[*]}")); unset IFS
|
IFS=$'\n' sorted=($(sort <<<"${connectors[*]}")); unset IFS
|
||||||
res=`echo ${sorted[@]}`
|
res=`echo ${sorted[@]}`
|
||||||
sed -i'' -e "s/^ connectors=.*/ connectors=($res \"\$1\")/" $self.tmp
|
sed -i'' -e "s/^ connectors=.*/ connectors=($res \"\$1\")/" $self.tmp
|
||||||
|
|||||||
Reference in New Issue
Block a user