tap_ivms101/
lib.rs

1//! # TAP IVMS 101 Implementation
2//!
3//! This crate provides a complete implementation of the IVMS 101.2023 data model
4//! for the Travel Asset Protocol (TAP). It includes all data structures, validation,
5//! and serialization support as defined in the interVASP Messaging Standard.
6//!
7//! ## Features
8//!
9//! - Complete IVMS 101.2023 data model implementation
10//! - Comprehensive validation for all data types
11//! - Serde JSON serialization/deserialization support
12//! - Builder patterns for easy construction
13//! - Type-safe enumerations for all IVMS code lists
14//! - ISO country code and currency code validation
15//!
16//! ## Example Usage
17//!
18//! ```rust
19//! use tap_ivms101::builder::*;
20//! use tap_ivms101::types::*;
21//! use tap_ivms101::message::*;
22//!
23//! # fn example() -> Result<(), Box<dyn std::error::Error>> {
24//! // Create a natural person
25//! let natural_person_name = NaturalPersonNameBuilder::new()
26//!     .legal_name("Smith", "John")
27//!     .build()?;
28//!
29//! let natural_person = NaturalPersonBuilder::new()
30//!     .name(natural_person_name)
31//!     .country_of_residence("US")
32//!     .build()?;
33//!
34//! // Create a legal person (VASP)
35//! let legal_person_name = LegalPersonNameBuilder::new()
36//!     .legal_name("Example VASP Inc.")
37//!     .build()?;
38//!
39//! let legal_person = LegalPersonBuilder::new()
40//!     .name(legal_person_name)
41//!     .lei("529900HNOAA1KXQJUQ27")?
42//!     .country_of_registration("US")
43//!     .build()?;
44//!
45//! // Create an IVMS message
46//! let ivms_message = IvmsMessageBuilder::new()
47//!     .originator(vec![Person::NaturalPerson(natural_person.clone())])
48//!     .beneficiary(vec![Person::NaturalPerson(natural_person)])
49//!     .originating_vasp(Person::LegalPerson(legal_person))
50//!     .transaction(
51//!         "100.00",
52//!         "USD",
53//!         TransactionDirection::Outgoing,
54//!         "tx-123",
55//!         "2024-01-15T10:30:00Z"
56//!     )?
57//!     .build()?;
58//!
59//! // Serialize to JSON
60//! let json = ivms_message.to_json_pretty()?;
61//! # Ok(())
62//! # }
63//! ```
64
65pub mod builder;
66pub mod error;
67pub mod message;
68pub mod person;
69pub mod types;
70pub mod validation;
71
72// Re-export main types for convenience
73pub use error::{Error, Result};
74pub use message::{IvmsMessage, Person};
75pub use person::{LegalPerson, NaturalPerson};
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80    use crate::builder::*;
81    use crate::types::*;
82
83    #[test]
84    fn test_create_natural_person() {
85        let name = NaturalPersonNameBuilder::new()
86            .legal_name("Doe", "John")
87            .build()
88            .unwrap();
89
90        let person = NaturalPersonBuilder::new()
91            .name(name)
92            .country_of_residence("US")
93            .build()
94            .unwrap();
95
96        assert!(person.validate().is_ok());
97    }
98
99    #[test]
100    fn test_create_legal_person() {
101        let name = LegalPersonNameBuilder::new()
102            .legal_name("Test Company Ltd.")
103            .build()
104            .unwrap();
105
106        let person = LegalPersonBuilder::new()
107            .name(name)
108            .lei("529900HNOAA1KXQJUQ27")
109            .unwrap()
110            .country_of_registration("GB")
111            .build()
112            .unwrap();
113
114        assert!(person.validate().is_ok());
115    }
116
117    #[test]
118    fn test_create_ivms_message() {
119        // Create originator
120        let originator_name = NaturalPersonNameBuilder::new()
121            .legal_name("Smith", "Alice")
122            .build()
123            .unwrap();
124
125        let originator_person = NaturalPersonBuilder::new()
126            .name(originator_name)
127            .build()
128            .unwrap();
129
130        // Create beneficiary
131        let beneficiary_name = NaturalPersonNameBuilder::new()
132            .legal_name("Jones", "Bob")
133            .build()
134            .unwrap();
135
136        let beneficiary_person = NaturalPersonBuilder::new()
137            .name(beneficiary_name)
138            .build()
139            .unwrap();
140
141        // Create VASP
142        let vasp_name = LegalPersonNameBuilder::new()
143            .legal_name("Example Exchange")
144            .build()
145            .unwrap();
146
147        let vasp = LegalPersonBuilder::new().name(vasp_name).build().unwrap();
148
149        // Create message
150        let message = IvmsMessageBuilder::new()
151            .originator(vec![Person::NaturalPerson(originator_person)])
152            .beneficiary(vec![Person::NaturalPerson(beneficiary_person)])
153            .originating_vasp(Person::LegalPerson(vasp))
154            .transaction(
155                "1000.50",
156                "USD",
157                TransactionDirection::Outgoing,
158                "tx-12345",
159                "2024-01-15T10:30:00Z",
160            )
161            .unwrap()
162            .build();
163
164        assert!(message.is_ok());
165        let message = message.unwrap();
166        assert!(message.validate().is_ok());
167
168        // Test serialization
169        let json = message.to_json();
170        assert!(json.is_ok());
171
172        // Test deserialization
173        let parsed = IvmsMessage::from_json(&json.unwrap());
174        assert!(parsed.is_ok());
175    }
176
177    #[test]
178    fn test_validation_errors() {
179        // Test empty name
180        let result = NaturalPersonNameBuilder::new().build();
181        assert!(result.is_err());
182
183        // Test invalid country code
184        let name = NaturalPersonNameBuilder::new()
185            .legal_name("Test", "User")
186            .build()
187            .unwrap();
188
189        let result = NaturalPersonBuilder::new()
190            .name(name)
191            .country_of_residence("USA") // Should be "US"
192            .build();
193
194        assert!(result.is_err());
195    }
196}