diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 3b85644553d..a4f052549bd 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -2019,7 +2019,7 @@ pub struct BankTransferNextStepsData { #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, ToSchema)] pub struct VoucherNextStepData { /// Voucher expiry date and time - pub expires_at: Option, + pub expires_at: Option, /// Reference number required for the transaction pub reference: String, /// Url to download the payment instruction @@ -2087,8 +2087,8 @@ pub struct MultibancoTransferInstructions { #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, ToSchema)] pub struct DokuBankTransferInstructions { - #[schema(value_type = String, example = "2023-07-26T17:33:00-07-21")] - pub expires_at: Option, + #[schema(value_type = String, example = "1707091200000")] + pub expires_at: Option, #[schema(value_type = String, example = "122385736258")] pub reference: Secret, #[schema(value_type = String)] diff --git a/crates/common_utils/src/custom_serde.rs b/crates/common_utils/src/custom_serde.rs index edbfa143a66..e4608c4f371 100644 --- a/crates/common_utils/src/custom_serde.rs +++ b/crates/common_utils/src/custom_serde.rs @@ -84,6 +84,53 @@ pub mod iso8601 { }) } } + /// Use the well-known ISO 8601 format which is without timezone when serializing and deserializing an + /// [`Option`][PrimitiveDateTime]. + /// + /// [PrimitiveDateTime]: ::time::PrimitiveDateTime + pub mod option_without_timezone { + use serde::{de, Deserialize, Serialize}; + use time::macros::format_description; + + use super::*; + + /// Serialize an [`Option`] using the well-known ISO 8601 format which is without timezone. + pub fn serialize( + date_time: &Option, + serializer: S, + ) -> Result + where + S: Serializer, + { + date_time + .map(|date_time| { + let format = + format_description!("[year]-[month]-[day]T[hour]:[minute]:[second]"); + date_time.assume_utc().format(format) + }) + .transpose() + .map_err(S::Error::custom)? + .serialize(serializer) + } + + /// Deserialize an [`Option`] from its ISO 8601 representation. + pub fn deserialize<'a, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'a>, + { + Option::deserialize(deserializer)? + .map(|time_string| { + let format = + format_description!("[year]-[month]-[day]T[hour]:[minute]:[second]"); + PrimitiveDateTime::parse(time_string, format).map_err(|_| { + de::Error::custom(format!( + "Failed to parse PrimitiveDateTime from {time_string}" + )) + }) + }) + .transpose() + } + } } /// Use the UNIX timestamp when serializing and deserializing an diff --git a/crates/router/src/connector/adyen/transformers.rs b/crates/router/src/connector/adyen/transformers.rs index 8da5d15c444..b141634d46f 100644 --- a/crates/router/src/connector/adyen/transformers.rs +++ b/crates/router/src/connector/adyen/transformers.rs @@ -370,7 +370,12 @@ pub struct AdyenPtsAction { reference: String, download_url: Option, payment_method_type: PaymentType, - expires_at: Option, + #[serde(rename = "expiresAt")] + #[serde( + default, + with = "common_utils::custom_serde::iso8601::option_without_timezone" + )] + expires_at: Option, initial_amount: Option, pass_creation_token: Option, total_amount: Option, @@ -3434,6 +3439,10 @@ pub fn get_present_to_shopper_metadata( response: &PresentToShopperResponse, ) -> errors::CustomResult, errors::ConnectorError> { let reference = response.action.reference.clone(); + let expires_at = response + .action + .expires_at + .map(|time| utils::get_timestamp_in_milliseconds(&time)); match response.action.payment_method_type { PaymentType::Alfamart @@ -3446,7 +3455,7 @@ pub fn get_present_to_shopper_metadata( | PaymentType::Seicomart | PaymentType::PayEasy => { let voucher_data = payments::VoucherNextStepData { - expires_at: response.action.expires_at.clone(), + expires_at, reference, download_url: response.action.download_url.clone(), instructions_url: response.action.instructions_url.clone(), @@ -3470,7 +3479,7 @@ pub fn get_present_to_shopper_metadata( Box::new(payments::DokuBankTransferInstructions { reference: Secret::new(response.action.reference.clone()), instructions_url: response.action.instructions_url.clone(), - expires_at: response.action.expires_at.clone(), + expires_at, }), ); diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index d516eeed4cc..9afd5182529 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -7738,7 +7738,7 @@ "properties": { "expires_at": { "type": "string", - "example": "2023-07-26T17:33:00-07-21" + "example": "1707091200000" }, "reference": { "type": "string",