1use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9use crate::message::agent::TapParticipant;
10use crate::utils::NameHashable;
11
12#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
17pub struct Party {
18 #[serde(rename = "@id")]
20 pub id: String,
21
22 #[serde(flatten)]
26 pub metadata: HashMap<String, serde_json::Value>,
27}
28
29impl TapParticipant for Party {
30 fn id(&self) -> &str {
31 &self.id
32 }
33}
34
35impl Party {
36 pub fn new(id: &str) -> Self {
38 Self {
39 id: id.to_string(),
40 metadata: HashMap::new(),
41 }
42 }
43
44 pub fn with_metadata(id: &str, metadata: HashMap<String, serde_json::Value>) -> Self {
46 Self {
47 id: id.to_string(),
48 metadata,
49 }
50 }
51
52 pub fn add_metadata(&mut self, key: String, value: serde_json::Value) {
54 self.metadata.insert(key, value);
55 }
56
57 pub fn with_metadata_field(mut self, key: String, value: serde_json::Value) -> Self {
59 self.metadata.insert(key, value);
60 self
61 }
62
63 pub fn with_country(mut self, country_code: &str) -> Self {
65 self.metadata.insert(
66 "https://schema.org/addressCountry".to_string(),
67 serde_json::Value::String(country_code.to_string()),
68 );
69 self
70 }
71
72 pub fn with_lei(mut self, lei_code: &str) -> Self {
74 self.metadata.insert(
75 "https://schema.org/leiCode".to_string(),
76 serde_json::Value::String(lei_code.to_string()),
77 );
78 self
79 }
80
81 pub fn with_mcc(mut self, mcc: &str) -> Self {
83 self.metadata.insert(
84 "mcc".to_string(),
85 serde_json::Value::String(mcc.to_string()),
86 );
87 self
88 }
89
90 pub fn get_metadata(&self, key: &str) -> Option<&serde_json::Value> {
92 self.metadata.get(key)
93 }
94
95 pub fn country(&self) -> Option<String> {
97 self.get_metadata("https://schema.org/addressCountry")
98 .and_then(|v| v.as_str())
99 .map(|s| s.to_string())
100 }
101
102 pub fn lei_code(&self) -> Option<String> {
104 self.get_metadata("https://schema.org/leiCode")
105 .and_then(|v| v.as_str())
106 .map(|s| s.to_string())
107 }
108
109 pub fn mcc(&self) -> Option<String> {
111 self.get_metadata("mcc")
112 .and_then(|v| v.as_str())
113 .map(|s| s.to_string())
114 }
115
116 pub fn with_name_hash(mut self, name: &str) -> Self {
118 let hash = Self::hash_name(name);
119 self.metadata
120 .insert("nameHash".to_string(), serde_json::Value::String(hash));
121 self
122 }
123
124 pub fn name_hash(&self) -> Option<String> {
126 self.get_metadata("nameHash")
127 .and_then(|v| v.as_str())
128 .map(|s| s.to_string())
129 }
130
131 pub fn set_name_hash(&mut self, hash: String) {
133 self.metadata
134 .insert("nameHash".to_string(), serde_json::Value::String(hash));
135 }
136
137 pub fn with_name(mut self, name: &str) -> Self {
141 self.metadata.insert(
142 "name".to_string(),
143 serde_json::Value::String(name.to_string()),
144 );
145 self
146 }
147
148 pub fn name(&self) -> Option<&str> {
150 self.metadata.get("name").and_then(|v| v.as_str())
151 }
152
153 pub fn with_url(mut self, url: &str) -> Self {
155 self.metadata.insert(
156 "url".to_string(),
157 serde_json::Value::String(url.to_string()),
158 );
159 self
160 }
161
162 pub fn url(&self) -> Option<&str> {
164 self.metadata.get("url").and_then(|v| v.as_str())
165 }
166
167 pub fn with_logo(mut self, logo: &str) -> Self {
169 self.metadata.insert(
170 "logo".to_string(),
171 serde_json::Value::String(logo.to_string()),
172 );
173 self
174 }
175
176 pub fn logo(&self) -> Option<&str> {
178 self.metadata.get("logo").and_then(|v| v.as_str())
179 }
180
181 pub fn with_description(mut self, description: &str) -> Self {
183 self.metadata.insert(
184 "description".to_string(),
185 serde_json::Value::String(description.to_string()),
186 );
187 self
188 }
189
190 pub fn description(&self) -> Option<&str> {
192 self.metadata.get("description").and_then(|v| v.as_str())
193 }
194
195 pub fn with_email(mut self, email: &str) -> Self {
197 self.metadata.insert(
198 "email".to_string(),
199 serde_json::Value::String(email.to_string()),
200 );
201 self
202 }
203
204 pub fn email(&self) -> Option<&str> {
206 self.metadata.get("email").and_then(|v| v.as_str())
207 }
208
209 pub fn with_telephone(mut self, telephone: &str) -> Self {
211 self.metadata.insert(
212 "telephone".to_string(),
213 serde_json::Value::String(telephone.to_string()),
214 );
215 self
216 }
217
218 pub fn telephone(&self) -> Option<&str> {
220 self.metadata.get("telephone").and_then(|v| v.as_str())
221 }
222}
223
224impl NameHashable for Party {}
226
227#[cfg(test)]
228mod tests {
229 use super::*;
230 use serde_json;
231
232 #[test]
233 fn test_party_creation() {
234 let party = Party::new("did:example:alice");
235 assert_eq!(party.id, "did:example:alice");
236 assert!(party.metadata.is_empty());
237 }
238
239 #[test]
240 fn test_party_with_metadata() {
241 let mut metadata = HashMap::new();
242 metadata.insert(
243 "name".to_string(),
244 serde_json::Value::String("Alice".to_string()),
245 );
246
247 let party = Party::with_metadata("did:example:alice", metadata);
248 assert_eq!(party.id, "did:example:alice");
249 assert_eq!(
250 party.get_metadata("name").unwrap().as_str().unwrap(),
251 "Alice"
252 );
253 }
254
255 #[test]
256 fn test_party_with_country() {
257 let party = Party::new("did:example:alice").with_country("de");
258 assert_eq!(party.country().unwrap(), "de");
259 }
260
261 #[test]
262 fn test_party_with_lei() {
263 let party = Party::new("did:web:example.com").with_lei("LEI123456789");
264 assert_eq!(party.lei_code().unwrap(), "LEI123456789");
265 }
266
267 #[test]
268 fn test_party_with_mcc() {
269 let party = Party::new("did:web:merchant.com").with_mcc("5812");
270 assert_eq!(party.mcc().unwrap(), "5812");
271 }
272
273 #[test]
274 fn test_party_serialization() {
275 let party = Party::new("did:example:alice")
276 .with_country("de")
277 .with_lei("LEI123");
278
279 let json = serde_json::to_string(&party).unwrap();
280 let deserialized: Party = serde_json::from_str(&json).unwrap();
281
282 assert_eq!(party, deserialized);
283 assert_eq!(deserialized.country().unwrap(), "de");
284 assert_eq!(deserialized.lei_code().unwrap(), "LEI123");
285 }
286
287 #[test]
288 fn test_party_json_ld_format() {
289 let party = Party::new("did:example:alice").with_country("de");
290 let json = serde_json::to_value(&party).unwrap();
291
292 assert_eq!(json["@id"], "did:example:alice");
293 assert_eq!(json["https://schema.org/addressCountry"], "de");
294 }
295
296 #[test]
297 fn test_party_with_name_hash() {
298 let party = Party::new("did:example:alice").with_name_hash("Alice Lee");
299 assert_eq!(
300 party.name_hash().unwrap(),
301 "b117f44426c9670da91b563db728cd0bc8bafa7d1a6bb5e764d1aad2ca25032e"
302 );
303 }
304
305 #[test]
306 fn test_party_name_hash_serialization() {
307 let party = Party::new("did:example:alice")
308 .with_name_hash("Alice Lee")
309 .with_country("US");
310
311 let json = serde_json::to_value(&party).unwrap();
312 assert_eq!(json["@id"], "did:example:alice");
313 assert_eq!(
314 json["nameHash"],
315 "b117f44426c9670da91b563db728cd0bc8bafa7d1a6bb5e764d1aad2ca25032e"
316 );
317 assert_eq!(json["https://schema.org/addressCountry"], "US");
318 }
319
320 #[test]
323 fn test_party_with_name_field() {
324 let party = Party::new("did:example:alice").with_name("Alice Corporation");
325
326 assert_eq!(party.name(), Some("Alice Corporation"));
327
328 let json = serde_json::to_value(&party).unwrap();
330 assert_eq!(json["name"], "Alice Corporation");
331
332 let deserialized: Party = serde_json::from_value(json).unwrap();
334 assert_eq!(deserialized.name(), Some("Alice Corporation"));
335 }
336
337 #[test]
338 fn test_party_with_url_field() {
339 let party = Party::new("did:example:alice").with_url("https://alice.example.com");
340
341 assert_eq!(party.url(), Some("https://alice.example.com"));
342
343 let json = serde_json::to_value(&party).unwrap();
344 assert_eq!(json["url"], "https://alice.example.com");
345 }
346
347 #[test]
348 fn test_party_with_logo_field() {
349 let party = Party::new("did:example:alice").with_logo("https://alice.example.com/logo.png");
350
351 assert_eq!(party.logo(), Some("https://alice.example.com/logo.png"));
352
353 let json = serde_json::to_value(&party).unwrap();
354 assert_eq!(json["logo"], "https://alice.example.com/logo.png");
355 }
356
357 #[test]
358 fn test_party_with_description_field() {
359 let party =
360 Party::new("did:example:alice").with_description("A trusted financial institution");
361
362 assert_eq!(party.description(), Some("A trusted financial institution"));
363
364 let json = serde_json::to_value(&party).unwrap();
365 assert_eq!(json["description"], "A trusted financial institution");
366 }
367
368 #[test]
369 fn test_party_with_email_field() {
370 let party = Party::new("did:example:alice").with_email("contact@alice.example.com");
371
372 assert_eq!(party.email(), Some("contact@alice.example.com"));
373
374 let json = serde_json::to_value(&party).unwrap();
375 assert_eq!(json["email"], "contact@alice.example.com");
376 }
377
378 #[test]
379 fn test_party_with_telephone_field() {
380 let party = Party::new("did:example:alice").with_telephone("+1-555-0200");
381
382 assert_eq!(party.telephone(), Some("+1-555-0200"));
383
384 let json = serde_json::to_value(&party).unwrap();
385 assert_eq!(json["telephone"], "+1-555-0200");
386 }
387
388 #[test]
389 fn test_party_with_multiple_organization_fields() {
390 let party = Party::new("did:example:alice")
391 .with_name("Alice Corporation")
392 .with_url("https://alice.example.com")
393 .with_logo("https://alice.example.com/logo.png")
394 .with_description("A trusted financial institution")
395 .with_email("contact@alice.example.com")
396 .with_telephone("+1-555-0200")
397 .with_country("US")
398 .with_lei("123456789012345678");
399
400 assert_eq!(party.name(), Some("Alice Corporation"));
401 assert_eq!(party.url(), Some("https://alice.example.com"));
402 assert_eq!(party.logo(), Some("https://alice.example.com/logo.png"));
403 assert_eq!(party.description(), Some("A trusted financial institution"));
404 assert_eq!(party.email(), Some("contact@alice.example.com"));
405 assert_eq!(party.telephone(), Some("+1-555-0200"));
406 assert_eq!(party.country(), Some("US".to_string()));
407 assert_eq!(party.lei_code(), Some("123456789012345678".to_string()));
408
409 let json = serde_json::to_value(&party).unwrap();
411 assert_eq!(json["@id"], "did:example:alice");
412 assert_eq!(json["name"], "Alice Corporation");
413 assert_eq!(json["url"], "https://alice.example.com");
414 assert_eq!(json["logo"], "https://alice.example.com/logo.png");
415 assert_eq!(json["description"], "A trusted financial institution");
416 assert_eq!(json["email"], "contact@alice.example.com");
417 assert_eq!(json["telephone"], "+1-555-0200");
418 assert_eq!(json["https://schema.org/addressCountry"], "US");
419 assert_eq!(json["https://schema.org/leiCode"], "123456789012345678");
420
421 let deserialized: Party = serde_json::from_value(json).unwrap();
423 assert_eq!(deserialized.name(), Some("Alice Corporation"));
424 assert_eq!(deserialized.url(), Some("https://alice.example.com"));
425 assert_eq!(deserialized.country(), Some("US".to_string()));
426 }
427
428 #[test]
429 fn test_party_json_ld_compliance_with_organization_fields() {
430 let party = Party::new("did:example:alice")
431 .with_name("Alice Corporation")
432 .with_metadata_field(
433 "ivms101".to_string(),
434 serde_json::json!({
435 "naturalPerson": {
436 "name": {
437 "primaryIdentifier": "Smith",
438 "secondaryIdentifier": "Alice"
439 }
440 }
441 }),
442 );
443
444 let json = serde_json::to_value(&party).unwrap();
445
446 assert_eq!(json["@id"], "did:example:alice");
448 assert_eq!(json["name"], "Alice Corporation");
449 assert!(json["ivms101"]["naturalPerson"]["name"]["primaryIdentifier"].is_string());
450
451 assert!(json.get("metadata").is_none());
453 }
454
455 #[test]
456 fn test_party_with_ivms101_and_schema_org_fields() {
457 let party = Party::new("did:example:alice")
459 .with_name("Alice Corporation")
460 .with_country("US")
461 .with_metadata_field(
462 "ivms101".to_string(),
463 serde_json::json!({
464 "legalPerson": {
465 "name": {
466 "nameIdentifier": [{
467 "legalPersonName": "Alice Corporation",
468 "legalPersonNameIdentifierType": "LEGL"
469 }]
470 },
471 "nationalIdentification": {
472 "nationalIdentifier": "123456789",
473 "nationalIdentifierType": "LEIX"
474 }
475 }
476 }),
477 );
478
479 assert_eq!(party.name(), Some("Alice Corporation"));
480 assert_eq!(party.country(), Some("US".to_string()));
481
482 let json = serde_json::to_value(&party).unwrap();
483 assert_eq!(json["name"], "Alice Corporation");
484 assert_eq!(json["https://schema.org/addressCountry"], "US");
485 assert!(json["ivms101"]["legalPerson"]["name"]["nameIdentifier"].is_array());
486 }
487}