swift_mt_message/fields/field26t.rs
1use crate::{SwiftField, ValidationError, ValidationResult};
2use serde::{Deserialize, Serialize};
3
4/// # Field 26T: Transaction Type Code
5///
6/// ## Overview
7/// Field 26T contains a transaction type code that categorizes the nature of the transaction
8/// according to EUROSTAT Balance of Payments (BoP) guidelines. This field is mandatory for
9/// statistical reporting purposes and helps financial institutions classify cross-border
10/// transactions for regulatory compliance and economic analysis.
11///
12/// ## Format Specification
13/// **Format**: `3!c`
14/// - **3!c**: Exactly 3 alphanumeric characters
15/// - **Character set**: A-Z, 0-9 (uppercase letters and digits)
16/// - **Case handling**: Automatically converted to uppercase
17/// - **Validation**: Must be exactly 3 characters, alphanumeric only
18///
19/// ## EUROSTAT Balance of Payments Categories
20/// The transaction type codes follow EUROSTAT BoP methodology for statistical classification:
21///
22/// ### Goods (A-series)
23/// - **A01**: General merchandise on a gross basis - Standard trade in goods
24/// - **A02**: Goods for processing - Goods sent for processing abroad
25/// - **A03**: Repairs on goods - Repair services on movable goods
26///
27/// ### Services (B-series)
28/// - **B01**: Manufacturing services on physical inputs owned by others
29/// - **B02**: Maintenance and repair services n.i.e. (not included elsewhere)
30/// - **B03**: Transport services - Passenger and freight transport
31///
32/// ### Primary Income (C-series)
33/// - **C01**: Compensation of employees - Wages, salaries, and benefits
34/// - **C02**: Investment income - Dividends, interest, and other investment returns
35///
36/// ### Secondary Income (D-series)
37/// - **D01**: General government transfers - Government-to-government transfers
38/// - **D02**: Other sectors transfers - Private transfers and remittances
39///
40/// ### Capital Account (E-series)
41/// - **E01**: Capital transfers - Non-financial asset transfers
42/// - **E02**: Acquisition/disposal of non-produced, non-financial assets
43///
44/// ### Financial Account (F-series)
45/// - **F01**: Direct investment - Foreign direct investment flows
46/// - **F02**: Portfolio investment - Securities and equity investments
47/// - **F03**: Financial derivatives - Derivative instruments
48/// - **F04**: Other investment - Loans, deposits, and other financial instruments
49/// - **F05**: Reserve assets - Central bank reserves
50///
51/// ## Usage Context
52/// Field 26T is used in various SWIFT MT message types for statistical reporting:
53/// - **MT103**: Single Customer Credit Transfer (when required by regulation)
54/// - **MT202**: General Financial Institution Transfer
55/// - **MT202COV**: Cover for customer credit transfer
56/// - **MT205**: Financial Institution Transfer for its Own Account
57/// - **Cross-border payments**: Mandatory for EU and many other jurisdictions
58///
59/// ### Business Applications
60/// - **Statistical reporting**: Balance of payments statistics compilation
61/// - **Regulatory compliance**: Meeting central bank reporting requirements
62/// - **Economic analysis**: Supporting macroeconomic policy decisions
63/// - **Risk management**: Transaction categorization for risk assessment
64/// - **Audit trails**: Enhanced transaction tracking and classification
65/// - **Automated processing**: STP routing based on transaction type
66///
67/// ## Regulatory Framework
68/// Field 26T supports compliance with various regulatory requirements:
69///
70/// ### European Union
71/// - **ECB Regulation**: European Central Bank balance of payments reporting
72/// - **EUROSTAT methodology**: Statistical classification standards
73/// - **National implementations**: Country-specific BoP reporting requirements
74///
75/// ### International Standards
76/// - **IMF BPM6**: International Monetary Fund Balance of Payments Manual
77/// - **OECD guidelines**: Organisation for Economic Co-operation and Development
78/// - **BIS reporting**: Bank for International Settlements requirements
79///
80/// ## Validation Rules
81/// 1. **Length**: Must be exactly 3 characters
82/// 2. **Character set**: Only alphanumeric characters (A-Z, 0-9)
83/// 3. **Case**: Automatically normalized to uppercase
84/// 4. **Format compliance**: Must follow EUROSTAT BoP code structure
85/// 5. **Non-empty**: Cannot be empty or whitespace only
86///
87/// ## Network Validated Rules (SWIFT Standards)
88/// - Transaction type code must be exactly 3 characters (Error: T26)
89/// - Must contain only alphanumeric characters (Error: T61)
90/// - Should follow recognized BoP classification (Warning: recommended practice)
91/// - Must be consistent with transaction nature (Error: T40)
92///
93///
94/// ## Examples
95/// ```text
96/// :26T:A01
97/// └─── General merchandise trade
98///
99/// :26T:C02
100/// └─── Investment income (dividends, interest)
101///
102/// :26T:F01
103/// └─── Foreign direct investment
104///
105/// :26T:D02
106/// └─── Private transfers/remittances
107/// ```
108///
109
110#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
111pub struct Field26T {
112 /// Transaction type code (exactly 3 alphanumeric characters)
113 ///
114 /// Specifies the transaction type according to EUROSTAT Balance of Payments
115 /// guidelines for statistical reporting and regulatory compliance.
116 ///
117 /// **Format**: Exactly 3 uppercase alphanumeric characters
118 /// **Character set**: A-Z, 0-9 only
119 /// **Case handling**: Automatically converted to uppercase
120 ///
121 /// # Standard Categories
122 /// - **A-series**: Goods (A01, A02, A03)
123 /// - **B-series**: Services (B01, B02, B03)
124 /// - **C-series**: Primary Income (C01, C02)
125 /// - **D-series**: Secondary Income (D01, D02)
126 /// - **E-series**: Capital Account (E01, E02)
127 /// - **F-series**: Financial Account (F01-F05)
128 ///
129 /// # Examples
130 /// - `"A01"` - General merchandise on a gross basis
131 /// - `"C02"` - Investment income
132 /// - `"F01"` - Direct investment
133 /// - `"D02"` - Other sectors transfers
134 pub transaction_type_code: String,
135}
136
137impl SwiftField for Field26T {
138 fn parse(value: &str) -> Result<Self, crate::ParseError> {
139 let content = if let Some(stripped) = value.strip_prefix(":26T:") {
140 stripped // Remove ":26T:" prefix
141 } else if let Some(stripped) = value.strip_prefix("26T:") {
142 stripped // Remove "26T:" prefix
143 } else {
144 value
145 };
146
147 if content.is_empty() {
148 return Err(crate::ParseError::InvalidFieldFormat {
149 field_tag: "26T".to_string(),
150 message: "Field content cannot be empty after removing tag".to_string(),
151 });
152 }
153
154 Self::new(content)
155 }
156
157 fn to_swift_string(&self) -> String {
158 format!(":26T:{}", self.transaction_type_code)
159 }
160
161 fn validate(&self) -> ValidationResult {
162 let mut errors = Vec::new();
163
164 // Validate length (3 characters)
165 if self.transaction_type_code.len() != 3 {
166 errors.push(ValidationError::LengthValidation {
167 field_tag: "26T".to_string(),
168 expected: "3 characters".to_string(),
169 actual: self.transaction_type_code.len(),
170 });
171 }
172
173 // Validate not empty
174 if self.transaction_type_code.is_empty() {
175 errors.push(ValidationError::ValueValidation {
176 field_tag: "26T".to_string(),
177 message: "Transaction type code cannot be empty".to_string(),
178 });
179 }
180
181 // Validate characters (alphanumeric)
182 if !self
183 .transaction_type_code
184 .chars()
185 .all(|c| c.is_alphanumeric() && c.is_ascii())
186 {
187 errors.push(ValidationError::FormatValidation {
188 field_tag: "26T".to_string(),
189 message: "Transaction type code must contain only alphanumeric characters"
190 .to_string(),
191 });
192 }
193
194 ValidationResult {
195 is_valid: errors.is_empty(),
196 errors,
197 warnings: Vec::new(),
198 }
199 }
200
201 fn format_spec() -> &'static str {
202 "3!c"
203 }
204}
205
206impl Field26T {
207 /// Create a new Field26T with validation
208 pub fn new(transaction_type_code: impl Into<String>) -> crate::Result<Self> {
209 let code = transaction_type_code.into().trim().to_uppercase();
210
211 if code.is_empty() {
212 return Err(crate::ParseError::InvalidFieldFormat {
213 field_tag: "26T".to_string(),
214 message: "Transaction type code cannot be empty".to_string(),
215 });
216 }
217
218 if code.len() != 3 {
219 return Err(crate::ParseError::InvalidFieldFormat {
220 field_tag: "26T".to_string(),
221 message: "Transaction type code must be exactly 3 characters".to_string(),
222 });
223 }
224
225 // Validate characters (alphanumeric)
226 if !code.chars().all(|c| c.is_alphanumeric() && c.is_ascii()) {
227 return Err(crate::ParseError::InvalidFieldFormat {
228 field_tag: "26T".to_string(),
229 message: "Transaction type code must contain only alphanumeric characters"
230 .to_string(),
231 });
232 }
233
234 Ok(Field26T {
235 transaction_type_code: code,
236 })
237 }
238
239 /// Get the transaction type code
240 ///
241 /// Returns the 3-character transaction type code that specifies
242 /// the nature of the transaction for BoP classification.
243 ///
244 /// # Returns
245 /// A string slice containing the transaction type code in uppercase
246 ///
247 /// # Example
248 /// ```rust
249 /// # use swift_mt_message::fields::Field26T;
250 /// let field = Field26T::new("A01").unwrap();
251 /// assert_eq!(field.code(), "A01");
252 /// ```
253 pub fn code(&self) -> &str {
254 &self.transaction_type_code
255 }
256
257 /// Check if this is a valid EUROSTAT BoP code format
258 ///
259 /// Validates that the code follows the basic format requirements
260 /// for EUROSTAT Balance of Payments classification.
261 ///
262 /// # Returns
263 /// `true` if the code format is valid
264 ///
265 /// # Example
266 /// ```rust
267 /// # use swift_mt_message::fields::Field26T;
268 /// let field = Field26T::new("A01").unwrap();
269 /// assert!(field.is_valid_format());
270 /// ```
271 pub fn is_valid_format(&self) -> bool {
272 self.transaction_type_code.len() == 3
273 && self
274 .transaction_type_code
275 .chars()
276 .all(|c| c.is_alphanumeric() && c.is_ascii())
277 }
278
279 /// Get the BoP category for this transaction type
280 ///
281 /// Returns the main Balance of Payments category that this
282 /// transaction type belongs to.
283 ///
284 /// # Returns
285 /// BoP category as a string
286 ///
287 /// # Example
288 /// ```rust
289 /// # use swift_mt_message::fields::Field26T;
290 /// let field = Field26T::new("A01").unwrap();
291 /// assert_eq!(field.bop_category(), "Goods");
292 /// ```
293 pub fn bop_category(&self) -> &'static str {
294 match self.transaction_type_code.chars().next() {
295 Some('A') => "Goods",
296 Some('B') => "Services",
297 Some('C') => "Primary Income",
298 Some('D') => "Secondary Income",
299 Some('E') => "Capital Account",
300 Some('F') => "Financial Account",
301 _ => "Other",
302 }
303 }
304
305 /// Check if this is a goods transaction
306 ///
307 /// Determines if the transaction type represents trade in goods
308 /// according to BoP classification.
309 ///
310 /// # Returns
311 /// `true` if this is a goods transaction (A-series)
312 ///
313 /// # Example
314 /// ```rust
315 /// # use swift_mt_message::fields::Field26T;
316 /// let goods = Field26T::new("A01").unwrap();
317 /// assert!(goods.is_goods_transaction());
318 ///
319 /// let service = Field26T::new("B01").unwrap();
320 /// assert!(!service.is_goods_transaction());
321 /// ```
322 pub fn is_goods_transaction(&self) -> bool {
323 self.transaction_type_code.starts_with('A')
324 }
325
326 /// Check if this is a services transaction
327 ///
328 /// Determines if the transaction type represents trade in services
329 /// according to BoP classification.
330 ///
331 /// # Returns
332 /// `true` if this is a services transaction (B-series)
333 ///
334 /// # Example
335 /// ```rust
336 /// # use swift_mt_message::fields::Field26T;
337 /// let service = Field26T::new("B03").unwrap();
338 /// assert!(service.is_services_transaction());
339 /// ```
340 pub fn is_services_transaction(&self) -> bool {
341 self.transaction_type_code.starts_with('B')
342 }
343
344 /// Check if this is an income transaction
345 ///
346 /// Determines if the transaction type represents income flows
347 /// (primary or secondary income) according to BoP classification.
348 ///
349 /// # Returns
350 /// `true` if this is an income transaction (C or D series)
351 ///
352 /// # Example
353 /// ```rust
354 /// # use swift_mt_message::fields::Field26T;
355 /// let income = Field26T::new("C02").unwrap();
356 /// assert!(income.is_income_transaction());
357 ///
358 /// let transfer = Field26T::new("D02").unwrap();
359 /// assert!(transfer.is_income_transaction());
360 /// ```
361 pub fn is_income_transaction(&self) -> bool {
362 self.transaction_type_code.starts_with('C') || self.transaction_type_code.starts_with('D')
363 }
364
365 /// Check if this is a financial transaction
366 ///
367 /// Determines if the transaction type represents financial flows
368 /// according to BoP classification.
369 ///
370 /// # Returns
371 /// `true` if this is a financial transaction (F-series)
372 ///
373 /// # Example
374 /// ```rust
375 /// # use swift_mt_message::fields::Field26T;
376 /// let financial = Field26T::new("F01").unwrap();
377 /// assert!(financial.is_financial_transaction());
378 /// ```
379 pub fn is_financial_transaction(&self) -> bool {
380 self.transaction_type_code.starts_with('F')
381 }
382
383 /// Check if this is a capital account transaction
384 ///
385 /// Determines if the transaction type represents capital account flows
386 /// according to BoP classification.
387 ///
388 /// # Returns
389 /// `true` if this is a capital account transaction (E-series)
390 ///
391 /// # Example
392 /// ```rust
393 /// # use swift_mt_message::fields::Field26T;
394 /// let capital = Field26T::new("E01").unwrap();
395 /// assert!(capital.is_capital_transaction());
396 /// ```
397 pub fn is_capital_transaction(&self) -> bool {
398 self.transaction_type_code.starts_with('E')
399 }
400
401 /// Check if this transaction requires enhanced reporting
402 ///
403 /// Determines if the transaction type typically requires additional
404 /// documentation or enhanced reporting for regulatory purposes.
405 ///
406 /// # Returns
407 /// `true` if enhanced reporting is typically required
408 ///
409 /// # Example
410 /// ```rust
411 /// # use swift_mt_message::fields::Field26T;
412 /// let investment = Field26T::new("F01").unwrap();
413 /// assert!(investment.requires_enhanced_reporting());
414 /// ```
415 pub fn requires_enhanced_reporting(&self) -> bool {
416 matches!(
417 self.transaction_type_code.as_str(),
418 "F01" | "F02" | "F03" | "F05" | "E01" | "E02"
419 )
420 }
421
422 /// Get the reporting priority level
423 ///
424 /// Returns the priority level for statistical reporting based on
425 /// the transaction type. Higher numbers indicate higher priority.
426 ///
427 /// # Returns
428 /// Priority level (1=low, 2=normal, 3=high, 4=critical)
429 ///
430 /// # Example
431 /// ```rust
432 /// # use swift_mt_message::fields::Field26T;
433 /// let reserves = Field26T::new("F05").unwrap();
434 /// assert_eq!(reserves.reporting_priority(), 4);
435 /// ```
436 pub fn reporting_priority(&self) -> u8 {
437 match self.transaction_type_code.as_str() {
438 "F05" => 4, // Reserve assets - critical
439 "F01" | "F02" | "F03" => 3, // Investment flows - high
440 "E01" | "E02" => 3, // Capital account - high
441 "A01" | "A02" | "A03" => 2, // Goods - normal
442 "B01" | "B02" | "B03" => 2, // Services - normal
443 "C01" | "C02" => 2, // Primary income - normal
444 "D01" | "D02" => 1, // Secondary income - low
445 "F04" => 2, // Other investment - normal
446 _ => 1, // Unknown - low
447 }
448 }
449
450 /// Get human-readable description based on common EUROSTAT BoP codes
451 ///
452 /// Returns a detailed description of what this transaction type represents
453 /// in the context of Balance of Payments classification.
454 ///
455 /// # Returns
456 /// A descriptive string
457 ///
458 /// # Example
459 /// ```rust
460 /// # use swift_mt_message::fields::Field26T;
461 /// let field = Field26T::new("A01").unwrap();
462 /// println!("{}", field.description());
463 /// ```
464 pub fn description(&self) -> &'static str {
465 match self.transaction_type_code.as_str() {
466 // Common EUROSTAT Balance of Payments codes
467 "A01" => "Goods - General merchandise on a gross basis",
468 "A02" => "Goods - Goods for processing",
469 "A03" => "Goods - Repairs on goods",
470 "B01" => "Services - Manufacturing services on physical inputs owned by others",
471 "B02" => "Services - Maintenance and repair services n.i.e.",
472 "B03" => "Services - Transport",
473 "C01" => "Primary income - Compensation of employees",
474 "C02" => "Primary income - Investment income",
475 "D01" => "Secondary income - General government",
476 "D02" => "Secondary income - Other sectors",
477 "E01" => "Capital account - Capital transfers",
478 "E02" => "Capital account - Acquisition/disposal of non-produced, non-financial assets",
479 "F01" => "Financial account - Direct investment",
480 "F02" => "Financial account - Portfolio investment",
481 "F03" => "Financial account - Financial derivatives",
482 "F04" => "Financial account - Other investment",
483 "F05" => "Financial account - Reserve assets",
484 _ => "Transaction type code (refer to EUROSTAT BoP guidelines)",
485 }
486 }
487
488 /// Get the statistical significance level
489 ///
490 /// Returns the statistical significance of this transaction type
491 /// for macroeconomic analysis and policy making.
492 ///
493 /// # Returns
494 /// Significance level description
495 ///
496 /// # Example
497 /// ```rust
498 /// # use swift_mt_message::fields::Field26T;
499 /// let field = Field26T::new("F01").unwrap();
500 /// assert_eq!(field.statistical_significance(), "High - Key economic indicator");
501 /// ```
502 pub fn statistical_significance(&self) -> &'static str {
503 match self.transaction_type_code.as_str() {
504 "F01" | "F02" | "F05" => "High - Key economic indicator",
505 "A01" | "B03" | "C02" => "High - Major economic component",
506 "A02" | "A03" | "B01" | "B02" => "Medium - Significant for trade analysis",
507 "C01" | "F03" | "F04" => "Medium - Important for financial analysis",
508 "D01" | "E01" | "E02" => "Medium - Relevant for fiscal analysis",
509 "D02" => "Low - Supplementary indicator",
510 _ => "Variable - Depends on specific code definition",
511 }
512 }
513
514 /// Check if this code is well-formed according to BoP standards
515 ///
516 /// Performs additional validation beyond basic format checking,
517 /// ensuring the code follows EUROSTAT BoP classification principles.
518 ///
519 /// # Returns
520 /// `true` if the code is well-formed
521 ///
522 /// # Example
523 /// ```rust
524 /// # use swift_mt_message::fields::Field26T;
525 /// let good_code = Field26T::new("A01").unwrap();
526 /// assert!(good_code.is_well_formed());
527 ///
528 /// let unknown_code = Field26T::new("Z99").unwrap();
529 /// assert!(!unknown_code.is_well_formed());
530 /// ```
531 pub fn is_well_formed(&self) -> bool {
532 // Check if it follows the standard BoP category structure
533 if let Some('A' | 'B' | 'C' | 'D' | 'E' | 'F') = self.transaction_type_code.chars().next() {
534 // Check if the remaining characters are digits (standard pattern)
535 self.transaction_type_code[1..]
536 .chars()
537 .all(|c| c.is_ascii_digit())
538 } else {
539 false
540 }
541 }
542
543 /// Get comprehensive transaction details
544 ///
545 /// Returns a detailed description including the transaction type code,
546 /// BoP category, description, and statistical significance.
547 ///
548 /// # Returns
549 /// Formatted string with comprehensive details
550 ///
551 /// # Example
552 /// ```rust
553 /// # use swift_mt_message::fields::Field26T;
554 /// let field = Field26T::new("F01").unwrap();
555 /// println!("{}", field.comprehensive_description());
556 /// ```
557 pub fn comprehensive_description(&self) -> String {
558 format!(
559 "{} ({}): {} - Significance: {}",
560 self.transaction_type_code,
561 self.bop_category(),
562 self.description(),
563 self.statistical_significance()
564 )
565 }
566}
567
568impl std::fmt::Display for Field26T {
569 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
570 write!(f, "{}", self.transaction_type_code)
571 }
572}
573
574#[cfg(test)]
575mod tests {
576 use super::*;
577
578 #[test]
579 fn test_field26t_creation() {
580 let field = Field26T::new("A01").unwrap();
581 assert_eq!(field.transaction_type_code, "A01");
582 assert_eq!(field.code(), "A01");
583 }
584
585 #[test]
586 fn test_field26t_parse() {
587 let field = Field26T::parse("B02").unwrap();
588 assert_eq!(field.transaction_type_code, "B02");
589 }
590
591 #[test]
592 fn test_field26t_parse_with_prefix() {
593 let field = Field26T::parse(":26T:C01").unwrap();
594 assert_eq!(field.transaction_type_code, "C01");
595
596 let field = Field26T::parse("26T:D02").unwrap();
597 assert_eq!(field.transaction_type_code, "D02");
598 }
599
600 #[test]
601 fn test_field26t_case_normalization() {
602 let field = Field26T::new("c03").unwrap();
603 assert_eq!(field.transaction_type_code, "C03");
604 }
605
606 #[test]
607 fn test_field26t_invalid_length() {
608 let result = Field26T::new("AB"); // Too short
609 assert!(result.is_err());
610
611 let result = Field26T::new("ABCD"); // Too long
612 assert!(result.is_err());
613 }
614
615 #[test]
616 fn test_field26t_invalid_characters() {
617 let result = Field26T::new("A@1"); // Invalid character @
618 assert!(result.is_err());
619
620 let result = Field26T::new("A-1"); // Invalid character -
621 assert!(result.is_err());
622
623 let result = Field26T::new("A.1"); // Invalid character .
624 assert!(result.is_err());
625 }
626
627 #[test]
628 fn test_field26t_empty() {
629 let result = Field26T::new("");
630 assert!(result.is_err());
631
632 let result = Field26T::new(" ");
633 assert!(result.is_err());
634 }
635
636 #[test]
637 fn test_field26t_to_swift_string() {
638 let field = Field26T::new("D04").unwrap();
639 assert_eq!(field.to_swift_string(), ":26T:D04");
640 }
641
642 #[test]
643 fn test_field26t_validation() {
644 let field = Field26T::new("E05").unwrap();
645 let result = field.validate();
646 assert!(result.is_valid);
647
648 let invalid_field = Field26T {
649 transaction_type_code: "INVALID".to_string(),
650 };
651 let result = invalid_field.validate();
652 assert!(!result.is_valid);
653 }
654
655 #[test]
656 fn test_field26t_format_spec() {
657 assert_eq!(Field26T::format_spec(), "3!c");
658 }
659
660 #[test]
661 fn test_field26t_display() {
662 let field = Field26T::new("F06").unwrap();
663 assert_eq!(format!("{}", field), "F06");
664 }
665
666 #[test]
667 fn test_field26t_is_valid_format() {
668 let field = Field26T::new("A01").unwrap();
669 assert!(field.is_valid_format());
670
671 let invalid_field = Field26T {
672 transaction_type_code: "INVALID".to_string(),
673 };
674 assert!(!invalid_field.is_valid_format());
675 }
676
677 #[test]
678 fn test_field26t_descriptions() {
679 let field = Field26T::new("A01").unwrap();
680 assert_eq!(
681 field.description(),
682 "Goods - General merchandise on a gross basis"
683 );
684
685 let field = Field26T::new("B03").unwrap();
686 assert_eq!(field.description(), "Services - Transport");
687
688 let field = Field26T::new("F01").unwrap();
689 assert_eq!(field.description(), "Financial account - Direct investment");
690
691 let field = Field26T::new("XYZ").unwrap();
692 assert_eq!(
693 field.description(),
694 "Transaction type code (refer to EUROSTAT BoP guidelines)"
695 );
696 }
697
698 #[test]
699 fn test_field26t_common_codes() {
700 // Test some common EUROSTAT BoP codes
701 let codes = ["A01", "A02", "B01", "C01", "D01", "E01", "F01"];
702
703 for code in codes {
704 let field = Field26T::new(code).unwrap();
705 assert_eq!(field.code(), code);
706 assert!(field.is_valid_format());
707 assert!(!field.description().is_empty());
708 }
709 }
710
711 #[test]
712 fn test_field26t_bop_categories() {
713 let test_cases = [
714 ("A01", "Goods"),
715 ("B02", "Services"),
716 ("C01", "Primary Income"),
717 ("D02", "Secondary Income"),
718 ("E01", "Capital Account"),
719 ("F01", "Financial Account"),
720 ("Z99", "Other"),
721 ];
722
723 for (code, expected_category) in test_cases {
724 let field = Field26T::new(code).unwrap();
725 assert_eq!(
726 field.bop_category(),
727 expected_category,
728 "Category mismatch for code {}",
729 code
730 );
731 }
732 }
733
734 #[test]
735 fn test_field26t_transaction_type_checks() {
736 // Goods transactions
737 let goods_codes = ["A01", "A02", "A03"];
738 for code in goods_codes {
739 let field = Field26T::new(code).unwrap();
740 assert!(
741 field.is_goods_transaction(),
742 "Code {} should be goods transaction",
743 code
744 );
745 assert!(!field.is_services_transaction());
746 assert!(!field.is_income_transaction());
747 assert!(!field.is_financial_transaction());
748 assert!(!field.is_capital_transaction());
749 }
750
751 // Services transactions
752 let services_codes = ["B01", "B02", "B03"];
753 for code in services_codes {
754 let field = Field26T::new(code).unwrap();
755 assert!(
756 field.is_services_transaction(),
757 "Code {} should be services transaction",
758 code
759 );
760 assert!(!field.is_goods_transaction());
761 assert!(!field.is_income_transaction());
762 assert!(!field.is_financial_transaction());
763 assert!(!field.is_capital_transaction());
764 }
765
766 // Income transactions
767 let income_codes = ["C01", "C02", "D01", "D02"];
768 for code in income_codes {
769 let field = Field26T::new(code).unwrap();
770 assert!(
771 field.is_income_transaction(),
772 "Code {} should be income transaction",
773 code
774 );
775 assert!(!field.is_goods_transaction());
776 assert!(!field.is_services_transaction());
777 assert!(!field.is_financial_transaction());
778 assert!(!field.is_capital_transaction());
779 }
780
781 // Financial transactions
782 let financial_codes = ["F01", "F02", "F03", "F04", "F05"];
783 for code in financial_codes {
784 let field = Field26T::new(code).unwrap();
785 assert!(
786 field.is_financial_transaction(),
787 "Code {} should be financial transaction",
788 code
789 );
790 assert!(!field.is_goods_transaction());
791 assert!(!field.is_services_transaction());
792 assert!(!field.is_income_transaction());
793 assert!(!field.is_capital_transaction());
794 }
795
796 // Capital transactions
797 let capital_codes = ["E01", "E02"];
798 for code in capital_codes {
799 let field = Field26T::new(code).unwrap();
800 assert!(
801 field.is_capital_transaction(),
802 "Code {} should be capital transaction",
803 code
804 );
805 assert!(!field.is_goods_transaction());
806 assert!(!field.is_services_transaction());
807 assert!(!field.is_income_transaction());
808 assert!(!field.is_financial_transaction());
809 }
810 }
811
812 #[test]
813 fn test_field26t_enhanced_reporting_requirements() {
814 let enhanced_codes = ["F01", "F02", "F03", "F05", "E01", "E02"];
815 for code in enhanced_codes {
816 let field = Field26T::new(code).unwrap();
817 assert!(
818 field.requires_enhanced_reporting(),
819 "Code {} should require enhanced reporting",
820 code
821 );
822 }
823
824 let standard_codes = ["A01", "B01", "C01", "D01", "F04"];
825 for code in standard_codes {
826 let field = Field26T::new(code).unwrap();
827 assert!(
828 !field.requires_enhanced_reporting(),
829 "Code {} should not require enhanced reporting",
830 code
831 );
832 }
833 }
834
835 #[test]
836 fn test_field26t_reporting_priority() {
837 let test_cases = [
838 ("F05", 4), // Reserve assets - critical
839 ("F01", 3), // Direct investment - high
840 ("F02", 3), // Portfolio investment - high
841 ("F03", 3), // Financial derivatives - high
842 ("E01", 3), // Capital transfers - high
843 ("E02", 3), // Non-produced assets - high
844 ("A01", 2), // General merchandise - normal
845 ("B01", 2), // Manufacturing services - normal
846 ("C01", 2), // Compensation of employees - normal
847 ("F04", 2), // Other investment - normal
848 ("D01", 1), // Government transfers - low
849 ("D02", 1), // Other sectors transfers - low
850 ("Z99", 1), // Unknown - low
851 ];
852
853 for (code, expected_priority) in test_cases {
854 let field = Field26T::new(code).unwrap();
855 assert_eq!(
856 field.reporting_priority(),
857 expected_priority,
858 "Priority mismatch for code {}",
859 code
860 );
861 }
862 }
863
864 #[test]
865 fn test_field26t_statistical_significance() {
866 let high_significance = ["F01", "F02", "F05", "A01", "B03", "C02"];
867 for code in high_significance {
868 let field = Field26T::new(code).unwrap();
869 let significance = field.statistical_significance();
870 assert!(
871 significance.starts_with("High"),
872 "Code {} should have high significance, got: {}",
873 code,
874 significance
875 );
876 }
877
878 let medium_significance = ["A02", "B01", "C01", "F03", "D01", "E01"];
879 for code in medium_significance {
880 let field = Field26T::new(code).unwrap();
881 let significance = field.statistical_significance();
882 assert!(
883 significance.starts_with("Medium"),
884 "Code {} should have medium significance, got: {}",
885 code,
886 significance
887 );
888 }
889
890 let low_significance = ["D02"];
891 for code in low_significance {
892 let field = Field26T::new(code).unwrap();
893 let significance = field.statistical_significance();
894 assert!(
895 significance.starts_with("Low"),
896 "Code {} should have low significance, got: {}",
897 code,
898 significance
899 );
900 }
901 }
902
903 #[test]
904 fn test_field26t_well_formed_validation() {
905 // Well-formed codes (standard BoP structure)
906 let well_formed_codes = [
907 "A01", "A02", "A03", "B01", "B02", "B03", "C01", "C02", "D01", "D02", "E01", "E02",
908 "F01", "F02", "F03", "F04", "F05",
909 ];
910 for code in well_formed_codes {
911 let field = Field26T::new(code).unwrap();
912 assert!(
913 field.is_well_formed(),
914 "Code {} should be well-formed",
915 code
916 );
917 }
918
919 // Poorly formed codes (don't follow standard structure)
920 let poorly_formed_codes = ["Z99", "ABC", "12A", "A0A"];
921 for code in poorly_formed_codes {
922 let field = Field26T::new(code).unwrap();
923 assert!(
924 !field.is_well_formed(),
925 "Code {} should not be well-formed",
926 code
927 );
928 }
929 }
930
931 #[test]
932 fn test_field26t_comprehensive_description() {
933 let field = Field26T::new("F01").unwrap();
934 let desc = field.comprehensive_description();
935 assert!(desc.contains("F01"));
936 assert!(desc.contains("Financial Account"));
937 assert!(desc.contains("Direct investment"));
938 assert!(desc.contains("High - Key economic indicator"));
939 }
940
941 #[test]
942 fn test_field26t_serialization() {
943 let field = Field26T::new("A01").unwrap();
944 let serialized = serde_json::to_string(&field).unwrap();
945 let deserialized: Field26T = serde_json::from_str(&serialized).unwrap();
946
947 assert_eq!(field.code(), deserialized.code());
948 assert_eq!(field.bop_category(), deserialized.bop_category());
949 assert_eq!(field.description(), deserialized.description());
950 assert_eq!(
951 field.statistical_significance(),
952 deserialized.statistical_significance()
953 );
954 }
955
956 #[test]
957 fn test_field26t_business_logic_combinations() {
958 // Test combinations of business logic
959 let field = Field26T::new("F01").unwrap(); // Direct investment
960 assert!(field.is_financial_transaction());
961 assert!(field.requires_enhanced_reporting());
962 assert_eq!(field.reporting_priority(), 3);
963 assert_eq!(
964 field.statistical_significance(),
965 "High - Key economic indicator"
966 );
967 assert!(field.is_well_formed());
968
969 let field = Field26T::new("D02").unwrap(); // Other sectors transfers
970 assert!(field.is_income_transaction());
971 assert!(!field.requires_enhanced_reporting());
972 assert_eq!(field.reporting_priority(), 1);
973 assert_eq!(
974 field.statistical_significance(),
975 "Low - Supplementary indicator"
976 );
977 assert!(field.is_well_formed());
978 }
979
980 #[test]
981 fn test_field26t_edge_cases() {
982 // Test edge cases and boundary conditions
983 let field = Field26T::new("F05").unwrap(); // Reserve assets
984 assert_eq!(field.reporting_priority(), 4); // Highest priority
985 assert!(field.requires_enhanced_reporting());
986 assert!(field.is_financial_transaction());
987
988 // Test unknown but valid format
989 let field = Field26T::new("G01").unwrap();
990 assert_eq!(field.bop_category(), "Other");
991 assert!(!field.is_well_formed());
992 assert_eq!(field.reporting_priority(), 1);
993 }
994
995 #[test]
996 fn test_field26t_real_world_scenarios() {
997 // Scenario 1: International trade transaction
998 let trade = Field26T::new("A01").unwrap();
999 assert_eq!(
1000 trade.description(),
1001 "Goods - General merchandise on a gross basis"
1002 );
1003 assert!(trade.is_goods_transaction());
1004 assert_eq!(trade.reporting_priority(), 2);
1005 assert!(!trade.requires_enhanced_reporting());
1006
1007 // Scenario 2: Foreign direct investment
1008 let fdi = Field26T::new("F01").unwrap();
1009 assert_eq!(fdi.description(), "Financial account - Direct investment");
1010 assert!(fdi.is_financial_transaction());
1011 assert_eq!(fdi.reporting_priority(), 3);
1012 assert!(fdi.requires_enhanced_reporting());
1013
1014 // Scenario 3: Personal remittance
1015 let remittance = Field26T::new("D02").unwrap();
1016 assert_eq!(remittance.description(), "Secondary income - Other sectors");
1017 assert!(remittance.is_income_transaction());
1018 assert_eq!(remittance.reporting_priority(), 1);
1019 assert!(!remittance.requires_enhanced_reporting());
1020
1021 // Scenario 4: Central bank reserves
1022 let reserves = Field26T::new("F05").unwrap();
1023 assert_eq!(reserves.description(), "Financial account - Reserve assets");
1024 assert!(reserves.is_financial_transaction());
1025 assert_eq!(reserves.reporting_priority(), 4);
1026 assert!(reserves.requires_enhanced_reporting());
1027 }
1028}