Repository: juspay/hyperswitch
File: crates/api_models/src/revenue_recovery_data_backfill.rs (Rust)

Code before:
    pub cutoff_time: Option<String>,
}

#[derive(Debug, Serialize, Deserialize)]
pub enum RedisKeyType {
    Status, // for customer:{id}:status
    Tokens, // for customer:{id}:tokens
}

#[derive(Debug, Deserialize)]
pub struct GetRedisDataQuery {
    pub key_type: RedisKeyType,
}

#[derive(Debug, Serialize)]
pub struct RedisDataResponse {
    pub exists: bool,
    pub ttl_seconds: i64,
    pub data: Option<serde_json::Value>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct UpdateTokenStatusRequest {
    pub connector_customer_id: String,
    pub payment_processor_token: Secret<String, PhoneNumberStrategy>,
    pub scheduled_at: Option<String>,
    pub is_hard_decline: Option<bool>,
    pub error_code: Option<String>,
}

#[derive(Debug, Serialize)]
pub struct UpdateTokenStatusResponse {
    pub updated: bool,
    pub message: String,
}

impl std::fmt::Display for BackfillError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::InvalidCardType(msg) => write!(f, "Invalid card type: {}", msg),
            Self::DatabaseError(msg) => write!(f, "Database error: {}", msg),
            Self::RedisError(msg) => write!(f, "Redis error: {}", msg),
            Self::CsvParsingError(msg) => write!(f, "CSV parsing error: {}", msg),
            Self::FileProcessingError(msg) => write!(f, "File processing error: {}", msg),
        }
    }
}

impl std::error::Error for BackfillError {}

impl ResponseError for BackfillError {

Review comment (suggestion):
```suggestion
    pub scheduled_at: Option<PrimitiveDateTime>,
```

Code after:
    pub cutoff_time: Option<String>,
}

#[derive(Debug, Serialize, Deserialize)]
pub enum RedisKeyType {
    Status, // for customer:{id}:status
    Tokens, // for customer:{id}:tokens
}

#[derive(Debug, Deserialize)]
pub struct GetRedisDataQuery {
    pub key_type: RedisKeyType,
}

#[derive(Debug, Serialize)]
pub struct RedisDataResponse {
    pub exists: bool,
    pub ttl_seconds: i64,
    pub data: Option<serde_json::Value>,
}

#[derive(Debug, Serialize)]
pub enum ScheduledAtUpdate {
    SetToNull,
    SetToDateTime(PrimitiveDateTime),
}

impl<'de> Deserialize<'de> for ScheduledAtUpdate {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let value = serde_json::Value::deserialize(deserializer)?;

        match value {
            serde_json::Value::String(s) => {
                if s.to_lowercase() == "null" {
                    Ok(Self::SetToNull)
                } else {
                    // Parse as datetime using iso8601 deserializer
                    common_utils::custom_serde::iso8601::deserialize(
                        &mut serde_json::Deserializer::from_str(&format!("\"{}\"", s)),
                    )
                    .map(Self::SetToDateTime)
                    .map_err(serde::de::Error::custom)
                }
            }
            _ => Err(serde::de::Error::custom(
                "Expected null variable or datetime iso8601 ",
            )),
        }