use crate::errors::{ParseError, SwiftValidationError};
use crate::fields::*;
use crate::parser::MessageParser;
use crate::parser::utils::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
pub struct MT205 {
#[serde(rename = "20")]
pub transaction_reference: Field20,
#[serde(rename = "21")]
pub related_reference: Field21NoOption,
#[serde(rename = "13C", skip_serializing_if = "Option::is_none")]
pub time_indication: Option<Vec<Field13C>>,
#[serde(rename = "23B", skip_serializing_if = "Option::is_none")]
pub bank_operation_code: Option<Field23B>,
#[serde(rename = "32A")]
pub value_date_amount: Field32A,
#[serde(rename = "33B", skip_serializing_if = "Option::is_none")]
pub instructed_amount: Option<Field33B>,
#[serde(flatten, skip_serializing_if = "Option::is_none")]
pub ordering_institution: Option<Field52OrderingInstitution>,
#[serde(flatten, skip_serializing_if = "Option::is_none")]
pub senders_correspondent: Option<Field53>,
#[serde(flatten, skip_serializing_if = "Option::is_none")]
pub receivers_correspondent: Option<Field54>,
#[serde(flatten, skip_serializing_if = "Option::is_none")]
pub intermediary: Option<Field56>,
#[serde(flatten, skip_serializing_if = "Option::is_none")]
pub account_with_institution: Option<Field57>,
#[serde(flatten)]
pub beneficiary_institution: Field58,
#[serde(rename = "72", skip_serializing_if = "Option::is_none")]
pub sender_to_receiver: Option<Field72>,
}
impl MT205 {
pub fn parse_from_block4(block4: &str) -> Result<Self, ParseError> {
let mut parser = MessageParser::new(block4, "205");
let transaction_reference = parser.parse_field::<Field20>("20")?;
let related_reference = parser.parse_field::<Field21NoOption>("21")?;
parser = parser.with_duplicates(true);
let mut time_indications = Vec::new();
while let Ok(field) = parser.parse_field::<Field13C>("13C") {
time_indications.push(field);
}
parser = parser.with_duplicates(false);
let time_indication = if time_indications.is_empty() {
None
} else {
Some(time_indications)
};
let bank_operation_code = parser.parse_optional_field::<Field23B>("23B")?;
let value_date_amount = parser.parse_field::<Field32A>("32A")?;
let instructed_amount = parser.parse_optional_field::<Field33B>("33B")?;
let ordering_institution =
parser.parse_optional_variant_field::<Field52OrderingInstitution>("52")?;
let senders_correspondent = parser.parse_optional_variant_field::<Field53>("53")?;
let receivers_correspondent = parser.parse_optional_variant_field::<Field54>("54")?;
let intermediary = parser.parse_optional_variant_field::<Field56>("56")?;
let account_with_institution = parser.parse_optional_variant_field::<Field57>("57")?;
let beneficiary_institution = parser.parse_variant_field::<Field58>("58")?;
let sender_to_receiver = parser.parse_optional_field::<Field72>("72")?;
Ok(MT205 {
transaction_reference,
related_reference,
time_indication,
bank_operation_code,
value_date_amount,
instructed_amount,
ordering_institution,
senders_correspondent,
receivers_correspondent,
intermediary,
account_with_institution,
beneficiary_institution,
sender_to_receiver,
})
}
pub fn has_reject_codes(&self) -> bool {
if let Some(ref info) = self.sender_to_receiver {
info.information
.iter()
.any(|line| line.contains("/REJT/") || line.contains("/RJT/"))
} else {
false
}
}
pub fn has_return_codes(&self) -> bool {
if let Some(ref info) = self.sender_to_receiver {
info.information
.iter()
.any(|line| line.contains("/RETN/") || line.contains("/RET/"))
} else {
false
}
}
pub fn is_cover_message(&self) -> bool {
if let Some(ref info) = self.sender_to_receiver {
info.information
.iter()
.any(|line| line.contains("/COV/") || line.contains("/COVER/"))
} else {
false
}
}
fn validate_c1_intermediary_account_with(&self) -> Option<SwiftValidationError> {
if self.intermediary.is_some() && self.account_with_institution.is_none() {
return Some(SwiftValidationError::content_error(
"C81",
"57a",
"",
"Field 57a (Account With Institution) is mandatory when field 56a (Intermediary) is present",
"If field 56a is present, then field 57a must also be present",
));
}
None
}
pub fn validate_network_rules(&self, stop_on_first_error: bool) -> Vec<SwiftValidationError> {
let mut all_errors = Vec::new();
if let Some(error) = self.validate_c1_intermediary_account_with() {
all_errors.push(error);
if stop_on_first_error {
return all_errors;
}
}
all_errors
}
}
impl crate::traits::SwiftMessageBody for MT205 {
fn message_type() -> &'static str {
"205"
}
fn parse_from_block4(block4: &str) -> Result<Self, crate::errors::ParseError> {
Self::parse_from_block4(block4)
}
fn to_mt_string(&self) -> String {
let mut result = String::new();
append_field(&mut result, &self.transaction_reference);
append_field(&mut result, &self.related_reference);
append_vec_field(&mut result, &self.time_indication);
append_optional_field(&mut result, &self.bank_operation_code);
append_field(&mut result, &self.value_date_amount);
append_optional_field(&mut result, &self.instructed_amount);
append_optional_field(&mut result, &self.ordering_institution);
append_optional_field(&mut result, &self.senders_correspondent);
append_optional_field(&mut result, &self.receivers_correspondent);
append_optional_field(&mut result, &self.intermediary);
append_optional_field(&mut result, &self.account_with_institution);
append_field(&mut result, &self.beneficiary_institution);
append_optional_field(&mut result, &self.sender_to_receiver);
finalize_mt_string(result, false)
}
fn validate_network_rules(&self, stop_on_first_error: bool) -> Vec<SwiftValidationError> {
MT205::validate_network_rules(self, stop_on_first_error)
}
}