diff --git a/api-reference/v1/openapi_spec_v1.json b/api-reference/v1/openapi_spec_v1.json index f1383e1761..ccd6d2e11b 100644 --- a/api-reference/v1/openapi_spec_v1.json +++ b/api-reference/v1/openapi_spec_v1.json @@ -9653,6 +9653,12 @@ "description": "Destination bank account number", "example": "9b95f84e-de61-460b-a14b-f23b4e71c97b", "nullable": true + }, + "expiry_date": { + "type": "string", + "description": "The expiration date and time for the Pix QR code in ISO 8601 format", + "example": "2025-09-10T10:11:12Z", + "nullable": true } } } @@ -26290,6 +26296,12 @@ "description": "Partially masked destination bank account number", "example": "********-****-460b-****-f23b4e71c97b", "nullable": true + }, + "expiry_date": { + "type": "string", + "description": "The expiration date and time for the Pix QR code in ISO 8601 format", + "example": "2025-09-10T10:11:12Z", + "nullable": true } } }, diff --git a/api-reference/v2/openapi_spec_v2.json b/api-reference/v2/openapi_spec_v2.json index 6928c873be..5550c859ca 100644 --- a/api-reference/v2/openapi_spec_v2.json +++ b/api-reference/v2/openapi_spec_v2.json @@ -6585,6 +6585,12 @@ "description": "Destination bank account number", "example": "9b95f84e-de61-460b-a14b-f23b4e71c97b", "nullable": true + }, + "expiry_date": { + "type": "string", + "description": "The expiration date and time for the Pix QR code in ISO 8601 format", + "example": "2025-09-10T10:11:12Z", + "nullable": true } } } @@ -20980,6 +20986,12 @@ "description": "Partially masked destination bank account number", "example": "********-****-460b-****-f23b4e71c97b", "nullable": true + }, + "expiry_date": { + "type": "string", + "description": "The expiration date and time for the Pix QR code in ISO 8601 format", + "example": "2025-09-10T10:11:12Z", + "nullable": true } } }, diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 3d91e73406..59c609a294 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -3441,6 +3441,11 @@ pub enum BankTransferData { /// Destination bank account number #[schema(value_type = Option, example = "9b95f84e-de61-460b-a14b-f23b4e71c97b")] 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")] + expiry_date: Option, }, Pse {}, LocalBankTransfer { diff --git a/crates/api_models/src/payments/additional_info.rs b/crates/api_models/src/payments/additional_info.rs index ab143975ea..099e055980 100644 --- a/crates/api_models/src/payments/additional_info.rs +++ b/crates/api_models/src/payments/additional_info.rs @@ -177,6 +177,11 @@ pub struct PixBankTransferAdditionalData { /// Partially masked destination bank account number #[schema(value_type = Option, example = "********-****-460b-****-f23b4e71c97b")] pub 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")] + pub expiry_date: Option, } #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] diff --git a/crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs b/crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs index d972c958b7..5a47dec7cd 100644 --- a/crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs @@ -291,6 +291,8 @@ pub struct AdyenPaymentRequest<'a> { splits: Option>, store: Option, device_fingerprint: Option>, + #[serde(with = "common_utils::custom_serde::iso8601::option")] + session_validity: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -2922,6 +2924,7 @@ impl store, splits, device_fingerprint, + session_validity: None, }) } } @@ -3005,6 +3008,7 @@ impl TryFrom<(&AdyenRouterData<&PaymentsAuthorizeRouterData>, &Card)> for AdyenP store, splits, device_fingerprint, + session_validity: None, }) } } @@ -3092,6 +3096,7 @@ impl store, splits, device_fingerprint, + session_validity: None, }; Ok(request) } @@ -3167,6 +3172,7 @@ impl TryFrom<(&AdyenRouterData<&PaymentsAuthorizeRouterData>, &VoucherData)> store, splits, device_fingerprint, + session_validity: None, }; Ok(request) } @@ -3213,6 +3219,46 @@ impl let delivery_address = get_address_info(item.router_data.get_optional_shipping()).and_then(Result::ok); let telephone_number = item.router_data.get_optional_billing_phone_number(); + let (session_validity, social_security_number) = match bank_transfer_data { + BankTransferData::Pix { + cpf, + cnpj, + expiry_date, + .. + } => { + // Validate expiry_date doesn't exceed 5 days from now + if let Some(expiry) = expiry_date { + let now = OffsetDateTime::now_utc(); + let max_expiry = now + Duration::days(5); + let max_expiry_primitive = + PrimitiveDateTime::new(max_expiry.date(), max_expiry.time()); + + if *expiry > max_expiry_primitive { + return Err(report!(errors::ConnectorError::InvalidDataFormat { + field_name: "expiry_date cannot be more than 5 days from now", + })); + } + } + + (*expiry_date, cpf.as_ref().or(cnpj.as_ref()).cloned()) + } + BankTransferData::LocalBankTransfer { .. } => (None, None), + BankTransferData::AchBankTransfer {} + | BankTransferData::SepaBankTransfer {} + | BankTransferData::BacsBankTransfer {} + | BankTransferData::MultibancoBankTransfer {} + | BankTransferData::PermataBankTransfer {} + | BankTransferData::BcaBankTransfer {} + | BankTransferData::BniVaBankTransfer {} + | BankTransferData::BriVaBankTransfer {} + | BankTransferData::CimbVaBankTransfer {} + | BankTransferData::DanamonVaBankTransfer {} + | BankTransferData::MandiriVaBankTransfer {} + | BankTransferData::Pse {} + | BankTransferData::InstantBankTransfer {} + | BankTransferData::InstantBankTransferFinland {} + | BankTransferData::InstantBankTransferPoland {} => (None, None), + }; let request = AdyenPaymentRequest { amount, @@ -3228,7 +3274,7 @@ impl shopper_name: None, shopper_locale: None, shopper_email: item.router_data.get_optional_billing_email(), - social_security_number: None, + social_security_number, telephone_number, billing_address, delivery_address, @@ -3243,6 +3289,7 @@ impl store, splits, device_fingerprint, + session_validity, }; Ok(request) } @@ -3319,6 +3366,7 @@ impl store, splits, device_fingerprint, + session_validity: None, }; Ok(request) } @@ -3399,6 +3447,7 @@ impl store, splits, device_fingerprint, + session_validity: None, }) } } @@ -3529,6 +3578,7 @@ impl TryFrom<(&AdyenRouterData<&PaymentsAuthorizeRouterData>, &WalletData)> store, splits, device_fingerprint, + session_validity: None, }) } } @@ -3618,6 +3668,7 @@ impl store, splits, device_fingerprint, + session_validity: None, }) } } @@ -3699,6 +3750,7 @@ impl store, splits, device_fingerprint, + session_validity: None, }) } } @@ -5945,6 +5997,7 @@ impl store, splits, device_fingerprint, + session_validity: None, }) } } diff --git a/crates/hyperswitch_domain_models/src/payment_method_data.rs b/crates/hyperswitch_domain_models/src/payment_method_data.rs index f2f8647936..b273ec4569 100644 --- a/crates/hyperswitch_domain_models/src/payment_method_data.rs +++ b/crates/hyperswitch_domain_models/src/payment_method_data.rs @@ -710,6 +710,8 @@ pub enum BankTransferData { source_bank_account_id: Option, /// Destination bank account UUID. destination_bank_account_id: Option, + /// The expiration date and time for the Pix QR code + expiry_date: Option, }, Pse {}, LocalBankTransfer { @@ -1618,12 +1620,14 @@ impl From for BankTransferData { cnpj, source_bank_account_id, destination_bank_account_id, + expiry_date, } => Self::Pix { pix_key, cpf, cnpj, source_bank_account_id, destination_bank_account_id, + expiry_date, }, api_models::payments::BankTransferData::Pse {} => Self::Pse {}, api_models::payments::BankTransferData::LocalBankTransfer { bank_code } => { @@ -1662,6 +1666,7 @@ impl From for api_models::payments::additional_info::BankTrans cnpj, source_bank_account_id, destination_bank_account_id, + expiry_date, } => Self::Pix(Box::new( api_models::payments::additional_info::PixBankTransferAdditionalData { pix_key: pix_key.map(MaskedBankAccount::from), @@ -1669,6 +1674,7 @@ impl From for api_models::payments::additional_info::BankTrans cnpj: cnpj.map(MaskedBankAccount::from), source_bank_account_id, destination_bank_account_id, + expiry_date, }, )), BankTransferData::Pse {} => Self::Pse {},