use crate::{
ValidationError, ValidationResult,
headers::{ApplicationHeader, BasicHeader, Trailer, UserHeader},
traits::SwiftMessageBody,
};
use serde::{Deserialize, Serialize};
use std::any::Any;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(
feature = "jsonschema",
derive(schemars::JsonSchema),
schemars(bound = "T: schemars::JsonSchema")
)]
pub struct SwiftMessage<T: SwiftMessageBody> {
pub basic_header: BasicHeader,
pub application_header: ApplicationHeader,
#[serde(skip_serializing_if = "Option::is_none")]
pub user_header: Option<UserHeader>,
#[serde(skip_serializing_if = "Option::is_none")]
pub trailer: Option<Trailer>,
pub message_type: String,
pub fields: T,
}
impl<T: SwiftMessageBody> SwiftMessage<T> {
pub fn has_reject_codes(&self) -> bool {
if let Some(ref user_header) = self.user_header
&& let Some(ref mur) = user_header.message_user_reference
&& mur.to_uppercase().contains("REJT")
{
return true;
}
if let Some(mt103_fields) =
(&self.fields as &dyn Any).downcast_ref::<crate::messages::MT103>()
{
return mt103_fields.has_reject_codes();
} else if let Some(mt202_fields) =
(&self.fields as &dyn Any).downcast_ref::<crate::messages::MT202>()
{
return mt202_fields.has_reject_codes();
} else if let Some(mt205_fields) =
(&self.fields as &dyn Any).downcast_ref::<crate::messages::MT205>()
{
return mt205_fields.has_reject_codes();
}
false
}
pub fn has_return_codes(&self) -> bool {
if let Some(ref user_header) = self.user_header
&& let Some(ref mur) = user_header.message_user_reference
&& mur.to_uppercase().contains("RETN")
{
return true;
}
if let Some(mt103_fields) =
(&self.fields as &dyn Any).downcast_ref::<crate::messages::MT103>()
{
return mt103_fields.has_return_codes();
} else if let Some(mt202_fields) =
(&self.fields as &dyn Any).downcast_ref::<crate::messages::MT202>()
{
return mt202_fields.has_return_codes();
} else if let Some(mt205_fields) =
(&self.fields as &dyn Any).downcast_ref::<crate::messages::MT205>()
{
return mt205_fields.has_return_codes();
}
false
}
pub fn is_cover_message(&self) -> bool {
if let Some(mt202_fields) =
(&self.fields as &dyn Any).downcast_ref::<crate::messages::MT202>()
{
return mt202_fields.is_cover_message();
}
if let Some(mt205_fields) =
(&self.fields as &dyn Any).downcast_ref::<crate::messages::MT205>()
{
return mt205_fields.is_cover_message();
}
false
}
pub fn is_stp_message(&self) -> bool {
if let Some(mt103_fields) =
(&self.fields as &dyn Any).downcast_ref::<crate::messages::MT103>()
{
return mt103_fields.is_stp_compliant();
}
false
}
pub fn validate(&self) -> ValidationResult {
let validation_errors = self.fields.validate_network_rules(false);
let errors: Vec<ValidationError> = validation_errors
.into_iter()
.map(|swift_error| {
let message = format!("{}", swift_error);
ValidationError::BusinessRuleValidation {
rule_name: swift_error.error_code().to_string(),
message,
}
})
.collect();
ValidationResult {
is_valid: errors.is_empty(),
errors,
warnings: Vec::new(),
}
}
pub fn to_mt_message(&self) -> String {
let mut swift_message = String::with_capacity(2200);
let block1 = &self.basic_header.to_string();
swift_message.push_str(&format!("{{1:{block1}}}\n"));
let block2 = &self.application_header.to_string();
swift_message.push_str(&format!("{{2:{block2}}}\n"));
if let Some(ref user_header) = self.user_header {
let block3 = &user_header.to_string();
swift_message.push_str(&format!("{{3:{block3}}}\n"));
}
let mut block4_content = self.fields.to_mt_string();
if block4_content.contains("\r\n") {
block4_content = block4_content.replace("\r\n", "\n");
}
let block4 = if block4_content.starts_with('\n') {
block4_content
} else {
format!("\n{}", block4_content)
};
swift_message.push_str(&format!("{{4:{block4}\n-}}\n"));
if let Some(ref trailer) = self.trailer {
let block5 = &trailer.to_string();
swift_message.push_str(&format!("{{5:{block5}}}\n"));
}
swift_message
}
}