diff --git a/api-reference/v1/openapi_spec_v1.json b/api-reference/v1/openapi_spec_v1.json index ffeb2178ea..835adefad8 100644 --- a/api-reference/v1/openapi_spec_v1.json +++ b/api-reference/v1/openapi_spec_v1.json @@ -9666,13 +9666,14 @@ "source_bank_account_id": { "type": "string", "description": "Source bank account number", - "example": "8b2812f0-d6c8-4073-97bb-9fa964d08bc5", + "example": "8b******-****-****-****-*******08bc5", "nullable": true }, "destination_bank_account_id": { "type": "string", - "description": "Destination bank account number", - "example": "9b95f84e-de61-460b-a14b-f23b4e71c97b", + "description": "Partially masked destination bank account number _Deprecated: Will be removed in next stable release._", + "deprecated": true, + "example": "********-****-460b-****-f23b4e71c97b", "nullable": true }, "expiry_date": { @@ -26349,7 +26350,8 @@ }, "destination_bank_account_id": { "type": "string", - "description": "Partially masked destination bank account number", + "description": "Partially masked destination bank account number _Deprecated: Will be removed in next stable release._", + "deprecated": true, "example": "********-****-460b-****-f23b4e71c97b", "nullable": true }, diff --git a/api-reference/v2/openapi_spec_v2.json b/api-reference/v2/openapi_spec_v2.json index 919c3ac457..80bef99675 100644 --- a/api-reference/v2/openapi_spec_v2.json +++ b/api-reference/v2/openapi_spec_v2.json @@ -6598,13 +6598,14 @@ "source_bank_account_id": { "type": "string", "description": "Source bank account number", - "example": "8b2812f0-d6c8-4073-97bb-9fa964d08bc5", + "example": "8b******-****-****-****-*******08bc5", "nullable": true }, "destination_bank_account_id": { "type": "string", - "description": "Destination bank account number", - "example": "9b95f84e-de61-460b-a14b-f23b4e71c97b", + "description": "Partially masked destination bank account number _Deprecated: Will be removed in next stable release._", + "deprecated": true, + "example": "********-****-460b-****-f23b4e71c97b", "nullable": true }, "expiry_date": { @@ -21066,7 +21067,8 @@ }, "destination_bank_account_id": { "type": "string", - "description": "Partially masked destination bank account number", + "description": "Partially masked destination bank account number _Deprecated: Will be removed in next stable release._", + "deprecated": true, "example": "********-****-460b-****-f23b4e71c97b", "nullable": true }, diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 3700b7faad..fed4f29c4d 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -3452,15 +3452,12 @@ pub enum BankTransferData { /// CNPJ is a Brazilian company tax identification number #[schema(value_type = Option, example = "74469027417312")] cnpj: Option>, - /// Source bank account number - #[schema(value_type = Option, example = "8b2812f0-d6c8-4073-97bb-9fa964d08bc5")] + #[schema(value_type = Option, example = "8b******-****-****-****-*******08bc5")] source_bank_account_id: Option, - - /// Destination bank account number - #[schema(value_type = Option, example = "9b95f84e-de61-460b-a14b-f23b4e71c97b")] + /// Partially masked destination bank account number _Deprecated: Will be removed in next stable release._ + #[schema(value_type = Option, example = "********-****-460b-****-f23b4e71c97b", deprecated)] destination_bank_account_id: Option, - /// The expiration date and time for the Pix QR code in ISO 8601 format #[schema(value_type = Option, example = "2025-09-10T10:11:12Z")] #[serde(default, with = "common_utils::custom_serde::iso8601::option")] diff --git a/crates/api_models/src/payments/additional_info.rs b/crates/api_models/src/payments/additional_info.rs index b6600d51d2..de7493cafc 100644 --- a/crates/api_models/src/payments/additional_info.rs +++ b/crates/api_models/src/payments/additional_info.rs @@ -178,8 +178,8 @@ pub struct PixBankTransferAdditionalData { #[schema(value_type = Option, example = "********-****-4073-****-9fa964d08bc5")] pub source_bank_account_id: Option, - /// Partially masked destination bank account number - #[schema(value_type = Option, example = "********-****-460b-****-f23b4e71c97b")] + /// Partially masked destination bank account number _Deprecated: Will be removed in next stable release._ + #[schema(value_type = Option, example = "********-****-460b-****-f23b4e71c97b", deprecated)] pub destination_bank_account_id: Option, /// The expiration date and time for the Pix QR code in ISO 8601 format diff --git a/crates/connector_configs/toml/development.toml b/crates/connector_configs/toml/development.toml index a174d3f8ee..2be1d25f6d 100644 --- a/crates/connector_configs/toml/development.toml +++ b/crates/connector_configs/toml/development.toml @@ -6085,7 +6085,12 @@ api_secret="Secret Key" [facilitapay.connector_auth.BodyKey] api_key="Password" key1="Username" - +[facilitapay.metadata.destination_account_number] + name="destination_account_number" + label="Destination Account Number" + placeholder="Enter Destination Account Number" + required=true + type="Text" [archipel] [archipel.connector_auth.HeaderKey] diff --git a/crates/connector_configs/toml/production.toml b/crates/connector_configs/toml/production.toml index b2e6a84de3..a939f93894 100644 --- a/crates/connector_configs/toml/production.toml +++ b/crates/connector_configs/toml/production.toml @@ -4653,6 +4653,13 @@ payment_method_type = "pix" api_key = "Password" key1 = "Username" +[facilitapay.metadata.destination_account_number] +name="destination_account_number" +label="Destination Account Number" +placeholder="Enter Destination Account Number" +required=true +type="Text" + [archipel] [archipel.connector_auth.HeaderKey] api_key = "Enter CA Certificate PEM" diff --git a/crates/connector_configs/toml/sandbox.toml b/crates/connector_configs/toml/sandbox.toml index d6722a7c55..b30c6cda28 100644 --- a/crates/connector_configs/toml/sandbox.toml +++ b/crates/connector_configs/toml/sandbox.toml @@ -6067,6 +6067,13 @@ payment_method_type = "pix" api_key = "Password" key1 = "Username" +[facilitapay.metadata.destination_account_number] +name="destination_account_number" +label="Destination Account Number" +placeholder="Enter Destination Account Number" +required=true +type="Text" + [archipel] [archipel.connector_auth.HeaderKey] api_key = "Enter CA Certificate PEM" diff --git a/crates/hyperswitch_connectors/src/connectors/facilitapay/transformers.rs b/crates/hyperswitch_connectors/src/connectors/facilitapay/transformers.rs index 185624e989..c0025fe44f 100644 --- a/crates/hyperswitch_connectors/src/connectors/facilitapay/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/facilitapay/transformers.rs @@ -3,6 +3,8 @@ use common_enums::{enums, PaymentMethod}; use common_utils::{ errors::CustomResult, ext_traits::{BytesExt, Encode}, + new_type::MaskedBankAccount, + pii, types::StringMajorUnit, }; use error_stack::ResultExt; @@ -18,6 +20,7 @@ use hyperswitch_interfaces::{ consts, errors, events::connector_api_logs::ConnectorEvent, types::Response, }; use masking::{ExposeInterface, Secret}; +use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; use url::Url; @@ -34,7 +37,7 @@ use super::{ }; use crate::{ types::{RefreshTokenRouterData, RefundsResponseRouterData, ResponseRouterData}, - utils::{is_payment_failure, missing_field_err, QrImage, RouterData as OtherRouterData}, + utils::{self, is_payment_failure, missing_field_err, QrImage, RouterData as OtherRouterData}, }; type Error = error_stack::Report; @@ -47,6 +50,65 @@ impl From<(StringMajorUnit, T)> for FacilitapayRouterData { } } +// Auth Struct +#[derive(Debug, Clone)] +pub struct FacilitapayAuthType { + pub(super) username: Secret, + pub(super) password: Secret, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct FacilitapayConnectorMetadataObject { + // pub destination_account_number: Secret, + pub destination_account_number: MaskedBankAccount, +} + +// Helper to build the request from Hyperswitch Auth Type +impl FacilitapayAuthRequest { + fn from_auth_type(auth: &FacilitapayAuthType) -> Self { + Self { + user: FacilitapayCredentials { + username: auth.username.clone(), + password: auth.password.clone(), + }, + } + } +} + +impl TryFrom<&ConnectorAuthType> for FacilitapayAuthType { + type Error = Error; + fn try_from(auth_type: &ConnectorAuthType) -> Result { + match auth_type { + ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self { + username: key1.to_owned(), + password: api_key.to_owned(), + }), + _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()), + } + } +} + +impl TryFrom<&RefreshTokenRouterData> for FacilitapayAuthRequest { + type Error = Error; + fn try_from(item: &RefreshTokenRouterData) -> Result { + let auth_type = FacilitapayAuthType::try_from(&item.connector_auth_type)?; + Ok(Self::from_auth_type(&auth_type)) + } +} + +impl TryFrom<&Option> for FacilitapayConnectorMetadataObject { + type Error = Error; + + fn try_from(meta_data: &Option) -> Result { + let metadata: Self = utils::to_connector_meta_from_secret(meta_data.clone()) + .change_context(errors::ConnectorError::InvalidConnectorConfig { + config: "merchant_connector_account.metadata", + })?; + + Ok(metadata) + } +} + impl TryFrom<&FacilitapayRouterData<&types::PaymentsAuthorizeRouterData>> for FacilitapayPaymentsRequest { @@ -54,11 +116,13 @@ impl TryFrom<&FacilitapayRouterData<&types::PaymentsAuthorizeRouterData>> fn try_from( item: &FacilitapayRouterData<&types::PaymentsAuthorizeRouterData>, ) -> Result { + let metadata = + FacilitapayConnectorMetadataObject::try_from(&item.router_data.connector_meta_data)?; + match item.router_data.request.payment_method_data.clone() { PaymentMethodData::BankTransfer(bank_transfer_data) => match *bank_transfer_data { BankTransferData::Pix { source_bank_account_id, - destination_bank_account_id, .. } => { // Set expiry time to 15 minutes from now @@ -80,11 +144,7 @@ impl TryFrom<&FacilitapayRouterData<&types::PaymentsAuthorizeRouterData>> }, )?, - to_bank_account_id: destination_bank_account_id.clone().ok_or( - errors::ConnectorError::MissingRequiredField { - field_name: "destination bank account id", - }, - )?, + to_bank_account_id: metadata.destination_account_number, currency: item.router_data.request.currency, exchange_currency: item.router_data.request.currency, value: item.amount.clone(), @@ -147,46 +207,6 @@ impl TryFrom<&FacilitapayRouterData<&types::PaymentsAuthorizeRouterData>> } } -// Helper to build the request from Hyperswitch Auth Type -impl FacilitapayAuthRequest { - fn from_auth_type(auth: &FacilitapayAuthType) -> Self { - Self { - user: FacilitapayCredentials { - username: auth.username.clone(), - password: auth.password.clone(), - }, - } - } -} - -// Auth Struct -#[derive(Debug, Clone)] -pub struct FacilitapayAuthType { - pub(super) username: Secret, - pub(super) password: Secret, -} - -impl TryFrom<&ConnectorAuthType> for FacilitapayAuthType { - type Error = Error; - fn try_from(auth_type: &ConnectorAuthType) -> Result { - match auth_type { - ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self { - username: key1.to_owned(), - password: api_key.to_owned(), - }), - _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()), - } - } -} - -impl TryFrom<&RefreshTokenRouterData> for FacilitapayAuthRequest { - type Error = Error; - fn try_from(item: &RefreshTokenRouterData) -> Result { - let auth_type = FacilitapayAuthType::try_from(&item.connector_auth_type)?; - Ok(Self::from_auth_type(&auth_type)) - } -} - fn convert_to_document_type(document_type: &str) -> Result { match document_type.to_lowercase().as_str() { "cc" => Ok(DocumentType::CedulaDeCiudadania), @@ -395,7 +415,13 @@ impl TryFrom ( - "payment_method_data.bank_transfer.pix.destination_bank_account_id".to_string(), - RequiredFieldInfo { - required_field: - "payment_method_data.bank_transfer.pix.destination_bank_account_id" - .to_string(), - display_name: "destination_bank_account_id".to_string(), - field_type: FieldType::UserDestinationBankAccountId, - value: None, - }, - ), Self::GiftCardNumber => ( "payment_method_data.gift_card.number".to_string(), RequiredFieldInfo { @@ -3309,7 +3297,6 @@ fn get_bank_transfer_required_fields() -> HashMap { } api_enums::Connector::Facilitapay => { facilitapay::transformers::FacilitapayAuthType::try_from(self.auth_type)?; + facilitapay::transformers::FacilitapayConnectorMetadataObject::try_from( + self.connector_meta_data, + )?; Ok(()) } api_enums::Connector::Fiserv => { diff --git a/cypress-tests/cypress/e2e/configs/Payment/Facilitapay.js b/cypress-tests/cypress/e2e/configs/Payment/Facilitapay.js index 2bab5f65eb..9c9e2d6751 100644 --- a/cypress-tests/cypress/e2e/configs/Payment/Facilitapay.js +++ b/cypress-tests/cypress/e2e/configs/Payment/Facilitapay.js @@ -44,8 +44,6 @@ export const connectorDetails = { // since we pass the same cpf number, the connector customer id will be updated instead of new ones being created cpf: "86665623580", source_bank_account_id: "739d6b0a-e92a-40fd-9f58-6d4cdeb699bb", - destination_bank_account_id: - "91f5cac1-9058-44b7-80e1-80c6f4a6f0bc", pix_qr_expiry: isoTimeTomorrow(), // 1 day expiration }, },