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}