rain_sdk/api/applications.rs
1//! Applications API
2//!
3//! This module provides functionality to manage company and user applications in the Rain API.
4//!
5//! # Examples
6//!
7//! This module provides functionality to manage company and user applications.
8//!
9//! See the individual function documentation for examples.
10
11use crate::client::RainClient;
12use crate::error::Result;
13use crate::models::applications::*;
14use uuid::Uuid;
15
16impl RainClient {
17 // ============================================================================
18 // Company Application Methods
19 // ============================================================================
20
21 /// Create a company application
22 ///
23 /// # Arguments
24 ///
25 /// * `request` - The company application request
26 ///
27 /// # Returns
28 ///
29 /// Returns a [`CompanyApplicationResponse`] containing the application information.
30 ///
31 /// # Errors
32 ///
33 /// This method can return the following errors:
34 /// - `400` - Invalid request
35 /// - `401` - Invalid authorization
36 /// - `500` - Internal server error
37 ///
38 /// # Examples
39 ///
40 /// ```no_run
41 /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
42 /// use rain_sdk::models::applications::*;
43 /// use rain_sdk::models::common::*;
44 ///
45 /// # #[cfg(feature = "async")]
46 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
47 /// let config = Config::new(Environment::Dev);
48 /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
49 /// let client = RainClient::new(config, auth)?;
50 ///
51 /// // Note: In practice, you would populate all required fields.
52 /// // This is a simplified example - see the full struct definitions for required fields.
53 /// # let request = todo!();
54 /// let application = client.create_company_application(&request).await?;
55 /// # Ok(())
56 /// # }
57 /// ```
58 #[cfg(feature = "async")]
59 pub async fn create_company_application(
60 &self,
61 request: &CreateCompanyApplicationRequest,
62 ) -> Result<CompanyApplicationResponse> {
63 let path = "/applications/company";
64 self.post(path, request).await
65 }
66
67 /// Get a company application by ID
68 ///
69 /// # Arguments
70 ///
71 /// * `company_id` - The unique identifier of the company
72 ///
73 /// # Returns
74 ///
75 /// Returns a [`CompanyApplicationResponse`] containing the application information.
76 ///
77 /// # Errors
78 ///
79 /// This method can return the following errors:
80 /// - `401` - Invalid authorization
81 /// - `404` - Company not found
82 /// - `500` - Internal server error
83 ///
84 /// # Examples
85 ///
86 /// ```no_run
87 /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
88 /// use uuid::Uuid;
89 ///
90 /// # #[cfg(feature = "async")]
91 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
92 /// let config = Config::new(Environment::Dev);
93 /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
94 /// let client = RainClient::new(config, auth)?;
95 ///
96 /// let company_id = Uuid::new_v4();
97 /// let application = client.get_company_application(&company_id).await?;
98 /// # Ok(())
99 /// # }
100 /// ```
101 #[cfg(feature = "async")]
102 pub async fn get_company_application(
103 &self,
104 company_id: &Uuid,
105 ) -> Result<CompanyApplicationResponse> {
106 let path = format!("/applications/company/{company_id}");
107 self.get(&path).await
108 }
109
110 /// Update a company application
111 ///
112 /// # Arguments
113 ///
114 /// * `company_id` - The unique identifier of the company
115 /// * `request` - The update request
116 ///
117 /// # Returns
118 ///
119 /// Returns a [`CompanyApplicationResponse`] containing the updated application information.
120 ///
121 /// # Errors
122 ///
123 /// This method can return the following errors:
124 /// - `400` - Invalid request
125 /// - `401` - Invalid authorization
126 /// - `404` - Company not found
127 /// - `500` - Internal server error
128 ///
129 /// # Examples
130 ///
131 /// ```no_run
132 /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
133 /// use rain_sdk::models::applications::UpdateCompanyApplicationRequest;
134 /// use uuid::Uuid;
135 ///
136 /// # #[cfg(feature = "async")]
137 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
138 /// let config = Config::new(Environment::Dev);
139 /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
140 /// let client = RainClient::new(config, auth)?;
141 ///
142 /// let company_id = Uuid::new_v4();
143 /// let request = UpdateCompanyApplicationRequest {
144 /// name: Some("Updated Name".to_string()),
145 /// address: None,
146 /// entity: None,
147 /// };
148 /// let application = client.update_company_application(&company_id, &request).await?;
149 /// # Ok(())
150 /// # }
151 /// ```
152 #[cfg(feature = "async")]
153 pub async fn update_company_application(
154 &self,
155 company_id: &Uuid,
156 request: &UpdateCompanyApplicationRequest,
157 ) -> Result<CompanyApplicationResponse> {
158 let path = format!("/applications/company/{company_id}");
159 self.patch(&path, request).await
160 }
161
162 /// Update an ultimate beneficial owner
163 ///
164 /// # Arguments
165 ///
166 /// * `company_id` - The unique identifier of the company
167 /// * `ubo_id` - The unique identifier of the ultimate beneficial owner
168 /// * `request` - The update request
169 ///
170 /// # Returns
171 ///
172 /// Returns a [`CompanyApplicationResponse`] containing the updated application information.
173 ///
174 /// # Errors
175 ///
176 /// This method can return the following errors:
177 /// - `400` - Invalid request
178 /// - `401` - Invalid authorization
179 /// - `404` - Company or UBO not found
180 /// - `500` - Internal server error
181 ///
182 /// # Examples
183 ///
184 /// ```no_run
185 /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
186 /// use rain_sdk::models::applications::UpdateUltimateBeneficialOwnerRequest;
187 /// use uuid::Uuid;
188 ///
189 /// # #[cfg(feature = "async")]
190 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
191 /// let config = Config::new(Environment::Dev);
192 /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
193 /// let client = RainClient::new(config, auth)?;
194 ///
195 /// let company_id = Uuid::new_v4();
196 /// let ubo_id = Uuid::new_v4();
197 /// let request = UpdateUltimateBeneficialOwnerRequest {
198 /// first_name: Some("John".to_string()),
199 /// last_name: Some("Doe".to_string()),
200 /// birth_date: None,
201 /// national_id: None,
202 /// country_of_issue: None,
203 /// email: None,
204 /// address: None,
205 /// };
206 /// let application = client.update_ultimate_beneficial_owner(&company_id, &ubo_id, &request).await?;
207 /// # Ok(())
208 /// # }
209 /// ```
210 #[cfg(feature = "async")]
211 pub async fn update_ultimate_beneficial_owner(
212 &self,
213 company_id: &Uuid,
214 ubo_id: &Uuid,
215 request: &UpdateUltimateBeneficialOwnerRequest,
216 ) -> Result<CompanyApplicationResponse> {
217 let path = format!("/applications/company/{company_id}/ubo/{ubo_id}");
218 self.patch(&path, request).await
219 }
220
221 /// Upload a document for a company application
222 ///
223 /// # Arguments
224 ///
225 /// * `company_id` - The unique identifier of the company
226 /// * `params` - Document upload parameters
227 ///
228 /// # Returns
229 ///
230 /// Returns a success response.
231 ///
232 /// # Examples
233 ///
234 /// ```no_run
235 /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
236 /// use rain_sdk::models::applications::DocumentUploadParams;
237 /// use uuid::Uuid;
238 ///
239 /// # #[cfg(feature = "async")]
240 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
241 /// let config = Config::new(Environment::Dev);
242 /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
243 /// let client = RainClient::new(config, auth)?;
244 ///
245 /// let company_id = Uuid::new_v4();
246 /// let params = DocumentUploadParams {
247 /// document_type: "directorsRegistry".to_string(),
248 /// side: "front".to_string(),
249 /// country: Some("US".to_string()),
250 /// country_code: Some("US".to_string()),
251 /// name: Some("Document Name".to_string()),
252 /// file_path: "/path/to/file.pdf".to_string(),
253 /// };
254 /// client.upload_company_document(&company_id, ¶ms).await?;
255 /// # Ok(())
256 /// # }
257 /// ```
258 #[cfg(feature = "async")]
259 pub async fn upload_company_document(
260 &self,
261 company_id: &Uuid,
262 params: &DocumentUploadParams,
263 ) -> Result<serde_json::Value> {
264 let path = format!("/applications/company/{company_id}/document");
265 let form = self.build_company_document_form(params)?;
266 self.put_multipart(&path, form).await
267 }
268
269 /// Upload a document for an ultimate beneficial owner
270 ///
271 /// # Arguments
272 ///
273 /// * `company_id` - The unique identifier of the company
274 /// * `ubo_id` - The unique identifier of the ultimate beneficial owner
275 /// * `params` - Document upload parameters
276 ///
277 /// # Returns
278 ///
279 /// Returns a success response.
280 ///
281 /// # Examples
282 ///
283 /// ```no_run
284 /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
285 /// use rain_sdk::models::applications::DocumentUploadParams;
286 /// use uuid::Uuid;
287 ///
288 /// # #[cfg(feature = "async")]
289 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
290 /// let config = Config::new(Environment::Dev);
291 /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
292 /// let client = RainClient::new(config, auth)?;
293 ///
294 /// let company_id = Uuid::new_v4();
295 /// let ubo_id = Uuid::new_v4();
296 /// let params = DocumentUploadParams {
297 /// document_type: "idCard".to_string(),
298 /// side: "front".to_string(),
299 /// country: Some("US".to_string()),
300 /// country_code: Some("US".to_string()),
301 /// name: None,
302 /// file_path: "/path/to/file.pdf".to_string(),
303 /// };
304 /// client.upload_ubo_document(&company_id, &ubo_id, ¶ms).await?;
305 /// # Ok(())
306 /// # }
307 /// ```
308 #[cfg(feature = "async")]
309 pub async fn upload_ubo_document(
310 &self,
311 company_id: &Uuid,
312 ubo_id: &Uuid,
313 params: &DocumentUploadParams,
314 ) -> Result<serde_json::Value> {
315 let path = format!("/applications/company/{company_id}/ubo/{ubo_id}/document");
316 let form = self.build_user_document_form(params)?;
317 self.put_multipart(&path, form).await
318 }
319
320 // ============================================================================
321 // User Application Methods
322 // ============================================================================
323
324 /// Create a user application
325 ///
326 /// This method supports three verification methods (oneOf in OpenAPI spec):
327 /// 1. **Using Sumsub Share Token**: Provide only `sumsub_share_token`
328 /// 2. **Using Persona Share Token**: Provide only `persona_share_token`
329 /// 3. **Using API**: Provide full person data (all `IssuingApplicationPerson` fields)
330 ///
331 /// Exactly one verification method must be provided. The API will validate this at runtime.
332 ///
333 /// # Arguments
334 ///
335 /// * `request` - The user application request
336 ///
337 /// # Returns
338 ///
339 /// Returns a [`UserApplicationResponse`] containing the application information.
340 ///
341 /// # Errors
342 ///
343 /// This method can return the following errors:
344 /// - `400` - Invalid request
345 /// - `401` - Invalid authorization
346 /// - `500` - Internal server error
347 ///
348 /// # Examples
349 ///
350 /// ## Using Sumsub Share Token
351 ///
352 /// ```no_run
353 /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
354 /// use rain_sdk::models::applications::CreateUserApplicationRequest;
355 ///
356 /// # #[cfg(feature = "async")]
357 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
358 /// let config = Config::new(Environment::Dev);
359 /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
360 /// let client = RainClient::new(config, auth)?;
361 ///
362 /// let request = CreateUserApplicationRequest {
363 /// // Verification method: Sumsub Share Token
364 /// sumsub_share_token: Some("your-sumsub-token".to_string()),
365 /// persona_share_token: None,
366 /// // Person data fields should be None when using tokens
367 /// id: None,
368 /// first_name: None,
369 /// last_name: None,
370 /// birth_date: None,
371 /// national_id: None,
372 /// country_of_issue: None,
373 /// email: None,
374 /// phone_country_code: None,
375 /// phone_number: None,
376 /// address: None,
377 /// // Required fields
378 /// ip_address: "127.0.0.1".to_string(),
379 /// occupation: "Engineer".to_string(),
380 /// annual_salary: "100000".to_string(),
381 /// account_purpose: "Business".to_string(),
382 /// expected_monthly_volume: "5000".to_string(),
383 /// is_terms_of_service_accepted: true,
384 /// // Optional fields
385 /// wallet_address: None,
386 /// solana_address: None,
387 /// tron_address: None,
388 /// stellar_address: None,
389 /// chain_id: None,
390 /// contract_address: None,
391 /// source_key: None,
392 /// has_existing_documents: None,
393 /// };
394 /// let application = client.create_user_application(&request).await?;
395 /// # Ok(())
396 /// # }
397 /// ```
398 ///
399 /// ## Using Persona Share Token
400 ///
401 /// ```no_run
402 /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
403 /// use rain_sdk::models::applications::CreateUserApplicationRequest;
404 ///
405 /// # #[cfg(feature = "async")]
406 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
407 /// let config = Config::new(Environment::Dev);
408 /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
409 /// let client = RainClient::new(config, auth)?;
410 ///
411 /// let request = CreateUserApplicationRequest {
412 /// // Verification method: Persona Share Token
413 /// sumsub_share_token: None,
414 /// persona_share_token: Some("your-persona-token".to_string()),
415 /// // Person data fields should be None when using tokens
416 /// id: None,
417 /// first_name: None,
418 /// last_name: None,
419 /// birth_date: None,
420 /// national_id: None,
421 /// country_of_issue: None,
422 /// email: None,
423 /// phone_country_code: None,
424 /// phone_number: None,
425 /// address: None,
426 /// // Required fields
427 /// ip_address: "127.0.0.1".to_string(),
428 /// occupation: "Engineer".to_string(),
429 /// annual_salary: "100000".to_string(),
430 /// account_purpose: "Business".to_string(),
431 /// expected_monthly_volume: "5000".to_string(),
432 /// is_terms_of_service_accepted: true,
433 /// // Optional fields
434 /// wallet_address: None,
435 /// solana_address: None,
436 /// tron_address: None,
437 /// stellar_address: None,
438 /// chain_id: None,
439 /// contract_address: None,
440 /// source_key: None,
441 /// has_existing_documents: None,
442 /// };
443 /// let application = client.create_user_application(&request).await?;
444 /// # Ok(())
445 /// # }
446 /// ```
447 ///
448 /// ## Using Full API (IssuingApplicationPerson)
449 ///
450 /// ```no_run
451 /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
452 /// use rain_sdk::models::applications::CreateUserApplicationRequest;
453 /// use rain_sdk::models::common::Address;
454 ///
455 /// # #[cfg(feature = "async")]
456 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
457 /// let config = Config::new(Environment::Dev);
458 /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
459 /// let client = RainClient::new(config, auth)?;
460 ///
461 /// let request = CreateUserApplicationRequest {
462 /// // Verification method: Full API - no tokens
463 /// sumsub_share_token: None,
464 /// persona_share_token: None,
465 /// // Person data fields (required for API method)
466 /// id: None, // Optional: only if application was previously initiated
467 /// first_name: Some("John".to_string()),
468 /// last_name: Some("Doe".to_string()),
469 /// birth_date: Some("2000-01-01".to_string()),
470 /// national_id: Some("123456789".to_string()),
471 /// country_of_issue: Some("US".to_string()),
472 /// email: Some("john@example.com".to_string()),
473 /// phone_country_code: Some("1".to_string()),
474 /// phone_number: Some("5555555555".to_string()),
475 /// address: Some(Address {
476 /// line1: "123 Main St".to_string(),
477 /// line2: None,
478 /// city: "New York".to_string(),
479 /// region: "NY".to_string(),
480 /// postal_code: "10001".to_string(),
481 /// country_code: "US".to_string(),
482 /// country: None,
483 /// }),
484 /// // Required fields
485 /// ip_address: "127.0.0.1".to_string(),
486 /// occupation: "Engineer".to_string(),
487 /// annual_salary: "100000".to_string(),
488 /// account_purpose: "Business".to_string(),
489 /// expected_monthly_volume: "5000".to_string(),
490 /// is_terms_of_service_accepted: true,
491 /// // Optional fields
492 /// wallet_address: None,
493 /// solana_address: None,
494 /// tron_address: None,
495 /// stellar_address: None,
496 /// chain_id: None,
497 /// contract_address: None,
498 /// source_key: None,
499 /// has_existing_documents: None,
500 /// };
501 /// let application = client.create_user_application(&request).await?;
502 /// # Ok(())
503 /// # }
504 /// ```
505 #[cfg(feature = "async")]
506 pub async fn create_user_application(
507 &self,
508 request: &CreateUserApplicationRequest,
509 ) -> Result<UserApplicationResponse> {
510 let path = "/applications/user";
511 self.post(path, request).await
512 }
513
514 /// Initiate a user application
515 ///
516 /// # Arguments
517 ///
518 /// * `request` - The initiate user application request
519 ///
520 /// # Returns
521 ///
522 /// Returns a [`UserApplicationResponse`] containing the application information.
523 ///
524 /// # Errors
525 ///
526 /// This method can return the following errors:
527 /// - `400` - Invalid request
528 /// - `401` - Invalid authorization
529 /// - `500` - Internal server error
530 ///
531 /// # Examples
532 ///
533 /// ```no_run
534 /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
535 /// use rain_sdk::models::applications::InitiateUserApplicationRequest;
536 ///
537 /// # #[cfg(feature = "async")]
538 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
539 /// let config = Config::new(Environment::Dev);
540 /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
541 /// let client = RainClient::new(config, auth)?;
542 ///
543 /// let request = InitiateUserApplicationRequest {
544 /// first_name: Some("John".to_string()),
545 /// last_name: Some("Doe".to_string()),
546 /// email: Some("john@example.com".to_string()),
547 /// wallet_address: None,
548 /// };
549 /// let application = client.initiate_user_application(&request).await?;
550 /// # Ok(())
551 /// # }
552 /// ```
553 #[cfg(feature = "async")]
554 pub async fn initiate_user_application(
555 &self,
556 request: &InitiateUserApplicationRequest,
557 ) -> Result<UserApplicationResponse> {
558 let path = "/applications/user/initiate";
559 self.post(path, request).await
560 }
561
562 /// Get a user application by ID
563 ///
564 /// # Arguments
565 ///
566 /// * `user_id` - The unique identifier of the user
567 ///
568 /// # Returns
569 ///
570 /// Returns a [`UserApplicationResponse`] containing the application information.
571 ///
572 /// # Errors
573 ///
574 /// This method can return the following errors:
575 /// - `401` - Invalid authorization
576 /// - `404` - User not found
577 /// - `500` - Internal server error
578 ///
579 /// # Examples
580 ///
581 /// ```no_run
582 /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
583 /// use uuid::Uuid;
584 ///
585 /// # #[cfg(feature = "async")]
586 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
587 /// let config = Config::new(Environment::Dev);
588 /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
589 /// let client = RainClient::new(config, auth)?;
590 ///
591 /// let user_id = Uuid::new_v4();
592 /// let application = client.get_user_application(&user_id).await?;
593 /// # Ok(())
594 /// # }
595 /// ```
596 #[cfg(feature = "async")]
597 pub async fn get_user_application(&self, user_id: &Uuid) -> Result<UserApplicationResponse> {
598 let path = format!("/applications/user/{user_id}");
599 self.get(&path).await
600 }
601
602 /// Update a user application
603 ///
604 /// # Arguments
605 ///
606 /// * `user_id` - The unique identifier of the user
607 /// * `request` - The update request
608 ///
609 /// # Returns
610 ///
611 /// Returns a [`UserApplicationResponse`] containing the updated application information.
612 ///
613 /// # Errors
614 ///
615 /// This method can return the following errors:
616 /// - `400` - Invalid request
617 /// - `401` - Invalid authorization
618 /// - `404` - User not found
619 /// - `500` - Internal server error
620 ///
621 /// # Examples
622 ///
623 /// ```no_run
624 /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
625 /// use rain_sdk::models::applications::UpdateUserApplicationRequest;
626 /// use uuid::Uuid;
627 ///
628 /// # #[cfg(feature = "async")]
629 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
630 /// let config = Config::new(Environment::Dev);
631 /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
632 /// let client = RainClient::new(config, auth)?;
633 ///
634 /// let user_id = Uuid::new_v4();
635 /// let request = UpdateUserApplicationRequest {
636 /// first_name: Some("John".to_string()),
637 /// last_name: None,
638 /// birth_date: None,
639 /// national_id: None,
640 /// country_of_issue: None,
641 /// address: None,
642 /// ip_address: None,
643 /// occupation: None,
644 /// annual_salary: None,
645 /// account_purpose: None,
646 /// expected_monthly_volume: None,
647 /// is_terms_of_service_accepted: None,
648 /// has_existing_documents: None,
649 /// };
650 /// let application = client.update_user_application(&user_id, &request).await?;
651 /// # Ok(())
652 /// # }
653 /// ```
654 #[cfg(feature = "async")]
655 pub async fn update_user_application(
656 &self,
657 user_id: &Uuid,
658 request: &UpdateUserApplicationRequest,
659 ) -> Result<UserApplicationResponse> {
660 let path = format!("/applications/user/{user_id}");
661 self.patch(&path, request).await
662 }
663
664 /// Upload a document for a user application
665 ///
666 /// # Arguments
667 ///
668 /// * `user_id` - The unique identifier of the user
669 /// * `params` - Document upload parameters
670 ///
671 /// # Returns
672 ///
673 /// Returns a success response.
674 ///
675 /// # Examples
676 ///
677 /// ```no_run
678 /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
679 /// use rain_sdk::models::applications::DocumentUploadParams;
680 /// use uuid::Uuid;
681 ///
682 /// # #[cfg(feature = "async")]
683 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
684 /// let config = Config::new(Environment::Dev);
685 /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
686 /// let client = RainClient::new(config, auth)?;
687 ///
688 /// let user_id = Uuid::new_v4();
689 /// let params = DocumentUploadParams {
690 /// document_type: "idCard".to_string(),
691 /// side: "front".to_string(),
692 /// country: Some("US".to_string()),
693 /// country_code: Some("US".to_string()),
694 /// name: Some("ID Card".to_string()),
695 /// file_path: "/path/to/file.pdf".to_string(),
696 /// };
697 /// client.upload_user_document(&user_id, ¶ms).await?;
698 /// # Ok(())
699 /// # }
700 /// ```
701 #[cfg(feature = "async")]
702 pub async fn upload_user_document(
703 &self,
704 user_id: &Uuid,
705 params: &DocumentUploadParams,
706 ) -> Result<serde_json::Value> {
707 let path = format!("/applications/user/{user_id}/document");
708 let form = self.build_user_document_form(params)?;
709 self.put_multipart(&path, form).await
710 }
711
712 // ============================================================================
713 // Helper Methods
714 // ============================================================================
715
716 #[cfg(feature = "async")]
717 fn build_company_document_form(
718 &self,
719 params: &DocumentUploadParams,
720 ) -> Result<reqwest::multipart::Form> {
721 use std::fs;
722
723 let file_bytes = fs::read(¶ms.file_path).map_err(|e| {
724 crate::error::RainError::Other(anyhow::anyhow!("Failed to read file: {e}"))
725 })?;
726
727 let file_name = params
728 .file_path
729 .split('/')
730 .next_back()
731 .unwrap_or("document")
732 .to_string();
733
734 let part = reqwest::multipart::Part::bytes(file_bytes)
735 .file_name(file_name)
736 .mime_str("application/octet-stream")
737 .map_err(|e| {
738 crate::error::RainError::Other(anyhow::anyhow!("Invalid MIME type: {e}"))
739 })?;
740
741 let mut form = reqwest::multipart::Form::new()
742 .part("document", part)
743 .text("type", params.document_type.clone())
744 .text("side", params.side.clone());
745
746 if let Some(ref name) = params.name {
747 form = form.text("name", name.clone());
748 }
749
750 if let Some(ref country) = params.country {
751 form = form.text("country", country.clone());
752 }
753
754 if let Some(ref country_code) = params.country_code {
755 form = form.text("countryCode", country_code.clone());
756 }
757
758 Ok(form)
759 }
760
761 #[cfg(feature = "async")]
762 fn build_user_document_form(
763 &self,
764 params: &DocumentUploadParams,
765 ) -> Result<reqwest::multipart::Form> {
766 use std::fs;
767
768 let file_bytes = fs::read(¶ms.file_path).map_err(|e| {
769 crate::error::RainError::Other(anyhow::anyhow!("Failed to read file: {e}"))
770 })?;
771
772 let file_name = params
773 .file_path
774 .split('/')
775 .next_back()
776 .unwrap_or("document")
777 .to_string();
778
779 let part = reqwest::multipart::Part::bytes(file_bytes)
780 .file_name(file_name)
781 .mime_str("application/octet-stream")
782 .map_err(|e| {
783 crate::error::RainError::Other(anyhow::anyhow!("Invalid MIME type: {e}"))
784 })?;
785
786 let mut form = reqwest::multipart::Form::new()
787 .part("document", part)
788 .text("type", params.document_type.clone())
789 .text("side", params.side.clone());
790
791 if let Some(ref name) = params.name {
792 form = form.text("name", name.clone());
793 }
794
795 if let Some(ref country) = params.country {
796 form = form.text("country", country.clone());
797 }
798
799 if let Some(ref country_code) = params.country_code {
800 form = form.text("countryCode", country_code.clone());
801 }
802
803 Ok(form)
804 }
805
806 // ============================================================================
807 // Blocking Methods
808 // ============================================================================
809
810 /// Create a company application (blocking)
811 #[cfg(feature = "sync")]
812 pub fn create_company_application_blocking(
813 &self,
814 request: &CreateCompanyApplicationRequest,
815 ) -> Result<CompanyApplicationResponse> {
816 let path = "/applications/company";
817 self.post_blocking(path, request)
818 }
819
820 /// Get a company application by ID (blocking)
821 #[cfg(feature = "sync")]
822 pub fn get_company_application_blocking(
823 &self,
824 company_id: &Uuid,
825 ) -> Result<CompanyApplicationResponse> {
826 let path = format!("/applications/company/{company_id}");
827 self.get_blocking(&path)
828 }
829
830 /// Update a company application (blocking)
831 #[cfg(feature = "sync")]
832 pub fn update_company_application_blocking(
833 &self,
834 company_id: &Uuid,
835 request: &UpdateCompanyApplicationRequest,
836 ) -> Result<CompanyApplicationResponse> {
837 let path = format!("/applications/company/{company_id}");
838 self.patch_blocking(&path, request)
839 }
840
841 /// Update an ultimate beneficial owner (blocking)
842 #[cfg(feature = "sync")]
843 pub fn update_ultimate_beneficial_owner_blocking(
844 &self,
845 company_id: &Uuid,
846 ubo_id: &Uuid,
847 request: &UpdateUltimateBeneficialOwnerRequest,
848 ) -> Result<CompanyApplicationResponse> {
849 let path = format!("/applications/company/{company_id}/ubo/{ubo_id}");
850 self.patch_blocking(&path, request)
851 }
852
853 /// Create a user application (blocking)
854 #[cfg(feature = "sync")]
855 pub fn create_user_application_blocking(
856 &self,
857 request: &CreateUserApplicationRequest,
858 ) -> Result<UserApplicationResponse> {
859 let path = "/applications/user";
860 self.post_blocking(path, request)
861 }
862
863 /// Initiate a user application (blocking)
864 #[cfg(feature = "sync")]
865 pub fn initiate_user_application_blocking(
866 &self,
867 request: &InitiateUserApplicationRequest,
868 ) -> Result<UserApplicationResponse> {
869 let path = "/applications/user/initiate";
870 self.post_blocking(path, request)
871 }
872
873 /// Get a user application by ID (blocking)
874 #[cfg(feature = "sync")]
875 pub fn get_user_application_blocking(&self, user_id: &Uuid) -> Result<UserApplicationResponse> {
876 let path = format!("/applications/user/{user_id}");
877 self.get_blocking(&path)
878 }
879
880 /// Update a user application (blocking)
881 #[cfg(feature = "sync")]
882 pub fn update_user_application_blocking(
883 &self,
884 user_id: &Uuid,
885 request: &UpdateUserApplicationRequest,
886 ) -> Result<UserApplicationResponse> {
887 let path = format!("/applications/user/{user_id}");
888 self.patch_blocking(&path, request)
889 }
890}