#![allow(dead_code)] // Database utility functions may not all be used yet use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::fs; use std::path::Path; /// Stored registration data linked to payment intent /// This preserves all user form data until company creation after payment success /// NOTE: This uses file-based storage until we can add the model to heromodels #[derive(Debug, Clone, Serialize, Deserialize)] pub struct StoredRegistrationData { pub payment_intent_id: String, pub company_name: String, pub company_type: String, pub company_email: String, pub company_phone: String, pub company_website: Option, pub company_address: String, pub company_industry: Option, pub company_purpose: Option, pub fiscal_year_end: Option, pub shareholders: String, // JSON string of shareholders array pub payment_plan: String, pub created_at: i64, } /// File path for storing registration data const REGISTRATION_DATA_FILE: &str = "data/registration_data.json"; /// Ensure data directory exists fn ensure_data_directory() -> Result<(), String> { let data_dir = Path::new("data"); if !data_dir.exists() { fs::create_dir_all(data_dir) .map_err(|e| format!("Failed to create data directory: {}", e))?; } Ok(()) } /// Load all registration data from file fn load_registration_data() -> Result, String> { if !Path::new(REGISTRATION_DATA_FILE).exists() { return Ok(HashMap::new()); } let content = fs::read_to_string(REGISTRATION_DATA_FILE) .map_err(|e| format!("Failed to read registration data file: {}", e))?; let data: HashMap = serde_json::from_str(&content) .map_err(|e| format!("Failed to parse registration data: {}", e))?; Ok(data) } /// Save all registration data to file fn save_registration_data(data: &HashMap) -> Result<(), String> { ensure_data_directory()?; let content = serde_json::to_string_pretty(data) .map_err(|e| format!("Failed to serialize registration data: {}", e))?; fs::write(REGISTRATION_DATA_FILE, content) .map_err(|e| format!("Failed to write registration data file: {}", e))?; Ok(()) } impl StoredRegistrationData { /// Create new stored registration data pub fn new( payment_intent_id: String, company_name: String, company_type: String, company_email: String, company_phone: String, company_website: Option, company_address: String, company_industry: Option, company_purpose: Option, fiscal_year_end: Option, shareholders: String, payment_plan: String, ) -> Self { Self { payment_intent_id, company_name, company_type, company_email, company_phone, company_website, company_address, company_industry, company_purpose, fiscal_year_end, shareholders, payment_plan, created_at: chrono::Utc::now().timestamp(), } } } /// Store registration data linked to payment intent pub fn store_registration_data( payment_intent_id: String, data: crate::controllers::payment::CompanyRegistrationData, ) -> Result<(u32, StoredRegistrationData), String> { // Create stored registration data let stored_data = StoredRegistrationData::new( payment_intent_id.clone(), data.company_name, data.company_type, data.company_email .unwrap_or_else(|| "noemail@example.com".to_string()), data.company_phone .unwrap_or_else(|| "+1234567890".to_string()), data.company_website, data.company_address .unwrap_or_else(|| "No address provided".to_string()), data.company_industry, data.company_purpose, data.fiscal_year_end, data.shareholders, data.payment_plan, ); // Load existing data let mut all_data = load_registration_data()?; // Add new data all_data.insert(payment_intent_id.clone(), stored_data.clone()); // Save to file save_registration_data(&all_data)?; log::info!( "Stored registration data for payment intent {}", payment_intent_id ); // Return with a generated ID (timestamp-based) let id = chrono::Utc::now().timestamp() as u32; Ok((id, stored_data)) } /// Retrieve registration data by payment intent ID pub fn get_registration_data( payment_intent_id: &str, ) -> Result, String> { let all_data = load_registration_data()?; Ok(all_data.get(payment_intent_id).cloned()) } /// Get all stored registration data pub fn get_all_registration_data() -> Result, String> { let all_data = load_registration_data()?; Ok(all_data.into_values().collect()) } /// Delete registration data by payment intent ID pub fn delete_registration_data(payment_intent_id: &str) -> Result { let mut all_data = load_registration_data()?; if all_data.remove(payment_intent_id).is_some() { save_registration_data(&all_data)?; log::info!( "Deleted registration data for payment intent: {}", payment_intent_id ); Ok(true) } else { log::warn!( "Registration data not found for payment intent: {}", payment_intent_id ); Ok(false) } } /// Update registration data pub fn update_registration_data( payment_intent_id: &str, updated_data: StoredRegistrationData, ) -> Result, String> { let mut all_data = load_registration_data()?; all_data.insert(payment_intent_id.to_string(), updated_data.clone()); save_registration_data(&all_data)?; log::info!( "Updated registration data for payment intent: {}", payment_intent_id ); Ok(Some(updated_data)) } /// Convert StoredRegistrationData back to CompanyRegistrationData for processing pub fn stored_to_registration_data( stored: &StoredRegistrationData, ) -> crate::controllers::payment::CompanyRegistrationData { crate::controllers::payment::CompanyRegistrationData { company_name: stored.company_name.clone(), company_type: stored.company_type.clone(), company_email: Some(stored.company_email.clone()), company_phone: Some(stored.company_phone.clone()), company_website: stored.company_website.clone(), company_address: Some(stored.company_address.clone()), company_industry: stored.company_industry.clone(), company_purpose: stored.company_purpose.clone(), fiscal_year_end: stored.fiscal_year_end.clone(), shareholders: stored.shareholders.clone(), payment_plan: stored.payment_plan.clone(), } } #[cfg(test)] mod tests { use super::*; #[test] fn test_stored_registration_data_creation() { let data = StoredRegistrationData::new( "pi_test123".to_string(), "Test Company".to_string(), "Single FZC".to_string(), "test@example.com".to_string(), "+1234567890".to_string(), Some("https://example.com".to_string()), "123 Test St".to_string(), Some("Technology".to_string()), Some("Software development".to_string()), Some("December".to_string()), "[]".to_string(), "monthly".to_string(), ); assert_eq!(data.payment_intent_id, "pi_test123"); assert_eq!(data.company_name, "Test Company"); assert_eq!(data.company_type, "Single FZC"); assert_eq!(data.company_email, "test@example.com"); assert!(data.created_at > 0); } #[test] fn test_stored_to_registration_data_conversion() { let stored = StoredRegistrationData::new( "pi_test123".to_string(), "Test Company".to_string(), "Single FZC".to_string(), "test@example.com".to_string(), "+1234567890".to_string(), Some("https://example.com".to_string()), "123 Test St".to_string(), Some("Technology".to_string()), Some("Software development".to_string()), Some("December".to_string()), "[]".to_string(), "monthly".to_string(), ); let registration_data = stored_to_registration_data(&stored); assert_eq!(registration_data.company_name, "Test Company"); assert_eq!(registration_data.company_type, "Single FZC"); assert_eq!( registration_data.company_email, Some("test@example.com".to_string()) ); assert_eq!(registration_data.payment_plan, "monthly"); } }