use serde::{Deserialize, Serialize};
use crate::error::{MppError, Result};
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ChargeRequest {
pub amount: String,
pub currency: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub recipient: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub expires: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(rename = "externalId", skip_serializing_if = "Option::is_none")]
pub external_id: Option<String>,
#[serde(rename = "methodDetails", skip_serializing_if = "Option::is_none")]
pub method_details: Option<serde_json::Value>,
}
impl ChargeRequest {
pub fn parse_amount(&self) -> Result<u128> {
self.amount
.parse()
.map_err(|_| MppError::InvalidAmount(format!("Invalid amount: {}", self.amount)))
}
pub fn validate_max_amount(&self, max_amount: &str) -> Result<()> {
let amount = self.parse_amount()?;
let max: u128 = max_amount
.parse()
.map_err(|_| MppError::InvalidAmount(format!("Invalid max amount: {}", max_amount)))?;
if amount > max {
return Err(MppError::AmountExceedsMax {
required: amount,
max,
});
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_charge_request_serialization() {
let req = ChargeRequest {
amount: "10000".to_string(),
currency: "0x123".to_string(),
recipient: Some("0x456".to_string()),
expires: Some("2024-01-01T00:00:00Z".to_string()),
description: None,
external_id: None,
method_details: Some(serde_json::json!({
"chainId": 42431,
"feePayer": true
})),
};
let json = serde_json::to_string(&req).unwrap();
assert!(json.contains("\"amount\":\"10000\""));
assert!(json.contains("\"methodDetails\""));
assert!(json.contains("\"chainId\":42431"));
let parsed: ChargeRequest = serde_json::from_str(&json).unwrap();
assert_eq!(parsed.amount, "10000");
}
#[test]
fn test_parse_amount() {
let req = ChargeRequest {
amount: "1000000".to_string(),
..Default::default()
};
assert_eq!(req.parse_amount().unwrap(), 1_000_000u128);
let invalid = ChargeRequest {
amount: "not-a-number".to_string(),
..Default::default()
};
assert!(invalid.parse_amount().is_err());
}
#[test]
fn test_validate_max_amount() {
let req = ChargeRequest {
amount: "1000".to_string(),
..Default::default()
};
assert!(req.validate_max_amount("2000").is_ok());
assert!(req.validate_max_amount("1000").is_ok());
assert!(req.validate_max_amount("500").is_err());
}
}