1use crate::error::{ParseError, Result};
4use crate::StatementType;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum FlexSchemaVersion {
9 V3,
11 Unknown,
13}
14
15pub fn detect_version(xml: &str) -> Result<FlexSchemaVersion> {
41 if let Some(pos) = xml.find("version=\"") {
43 let version_start = pos + 9; if let Some(version_end) = xml[version_start..].find('"') {
45 let version_str = &xml[version_start..version_start + version_end];
46 return match version_str {
47 "3" => Ok(FlexSchemaVersion::V3),
48 _ => Ok(FlexSchemaVersion::Unknown),
49 };
50 }
51 }
52
53 Ok(FlexSchemaVersion::V3)
55}
56
57pub fn detect_statement_type(xml: &str) -> Result<StatementType> {
81 let xml_trimmed = xml
83 .trim_start()
84 .trim_start_matches("<?xml")
85 .trim_start()
86 .trim_start_matches(|c: char| c != '<');
87
88 if xml_trimmed.starts_with("<FlexQueryResponse") {
90 Ok(StatementType::Activity)
92 } else if xml_trimmed.starts_with("<TradeConfirmationStatement") {
93 Ok(StatementType::TradeConfirmation)
95 } else if xml_trimmed.starts_with("<FlexStatement") {
96 Ok(StatementType::Activity)
98 } else {
99 Err(ParseError::XmlError {
100 message: format!(
101 "Cannot detect statement type from XML root element: {}",
102 &xml_trimmed.chars().take(100).collect::<String>()
103 ),
104 location: None,
105 })
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn test_detect_version_v3() {
115 let xml = r#"<FlexQueryResponse version="3" queryName="test">"#;
116 let version = detect_version(xml).unwrap();
117 assert_eq!(version, FlexSchemaVersion::V3);
118 }
119
120 #[test]
121 fn test_detect_version_no_attribute() {
122 let xml = r#"<FlexQueryResponse queryName="test">"#;
123 let version = detect_version(xml).unwrap();
124 assert_eq!(version, FlexSchemaVersion::V3);
126 }
127
128 #[test]
129 fn test_detect_version_unknown() {
130 let xml = r#"<FlexQueryResponse version="4" queryName="test">"#;
131 let version = detect_version(xml).unwrap();
132 assert_eq!(version, FlexSchemaVersion::Unknown);
133 }
134
135 #[test]
136 fn test_detect_statement_type_activity() {
137 let xml = r#"<?xml version="1.0" encoding="UTF-8"?>
138<FlexQueryResponse queryName="test" type="AF">
139 <FlexStatements />
140</FlexQueryResponse>"#;
141 let stmt_type = detect_statement_type(xml).unwrap();
142 assert_eq!(stmt_type, StatementType::Activity);
143 }
144
145 #[test]
146 fn test_detect_statement_type_trade_confirmation() {
147 let xml = r#"<?xml version="1.0" encoding="UTF-8"?>
148<TradeConfirmationStatement accountId="U123">
149 <Trades />
150</TradeConfirmationStatement>"#;
151 let stmt_type = detect_statement_type(xml).unwrap();
152 assert_eq!(stmt_type, StatementType::TradeConfirmation);
153 }
154
155 #[test]
156 fn test_detect_statement_type_direct_flex_statement() {
157 let xml = r#"<FlexStatement accountId="U123" fromDate="2025-01-01" toDate="2025-01-31">"#;
158 let stmt_type = detect_statement_type(xml).unwrap();
159 assert_eq!(stmt_type, StatementType::Activity);
160 }
161
162 #[test]
163 fn test_detect_statement_type_invalid() {
164 let xml = r#"<Invalid>XML</Invalid>"#;
165 let result = detect_statement_type(xml);
166 assert!(result.is_err());
167 }
168}