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}