use super::swift_utils::{
format_swift_amount_for_currency, parse_amount_with_currency, parse_currency_non_commodity,
};
use crate::errors::ParseError;
use crate::traits::SwiftField;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
pub struct Field33B {
pub currency: String,
pub amount: f64,
}
impl SwiftField for Field33B {
fn parse(input: &str) -> crate::Result<Self>
where
Self: Sized,
{
if input.len() < 4 {
return Err(ParseError::InvalidFormat {
message: format!(
"Field 33B must be at least 4 characters, found {}",
input.len()
),
});
}
let currency = parse_currency_non_commodity(&input[0..3])?;
let amount_str = &input[3..];
if amount_str.is_empty() {
return Err(ParseError::InvalidFormat {
message: "Field 33B amount cannot be empty".to_string(),
});
}
let amount = parse_amount_with_currency(amount_str, ¤cy)?;
if amount <= 0.0 {
return Err(ParseError::InvalidFormat {
message: "Field 33B amount must be greater than zero".to_string(),
});
}
Ok(Field33B { currency, amount })
}
fn to_swift_string(&self) -> String {
format!(
":33B:{}{}",
self.currency,
format_swift_amount_for_currency(self.amount, &self.currency)
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_field33b_valid() {
let field = Field33B::parse("USD1250,00").unwrap();
assert_eq!(field.currency, "USD");
assert_eq!(field.amount, 1250.00);
assert_eq!(field.to_swift_string(), ":33B:USD1250,00");
let field = Field33B::parse("EUR950,50").unwrap();
assert_eq!(field.currency, "EUR");
assert_eq!(field.amount, 950.50);
let field = Field33B::parse("JPY125000").unwrap();
assert_eq!(field.currency, "JPY");
assert_eq!(field.amount, 125000.0);
}
#[test]
fn test_field33b_invalid() {
assert!(Field33B::parse("12A100").is_err());
assert!(Field33B::parse("US100").is_err());
assert!(Field33B::parse("USD0").is_err());
assert!(Field33B::parse("USD-100").is_err());
assert!(Field33B::parse("USD").is_err());
}
}