use heromodels::db::Collection; use heromodels::db::hero::OurDB; use heromodels::models::biz::{BusinessType, Company, CompanyStatus, Payment, PaymentStatus}; use heromodels_core::Model; use std::sync::Arc; fn create_test_db() -> Arc { let timestamp = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap() .as_nanos(); let path = format!("/tmp/payment_test_{}", timestamp); // Clean up any existing database at this path let _ = std::fs::remove_dir_all(&path); Arc::new(OurDB::new(path, true).expect("Failed to create test database")) } #[test] fn test_payment_creation() { let payment = Payment::new( "pi_test_123".to_string(), 1, "monthly".to_string(), 100.0, 50.0, 150.0, ); assert_eq!(payment.payment_intent_id, "pi_test_123"); assert_eq!(payment.company_id, 1); assert_eq!(payment.payment_plan, "monthly"); assert_eq!(payment.setup_fee, 100.0); assert_eq!(payment.monthly_fee, 50.0); assert_eq!(payment.total_amount, 150.0); assert_eq!(payment.currency, "usd"); assert_eq!(payment.status, PaymentStatus::Pending); assert_eq!(payment.stripe_customer_id, None); assert!(payment.created_at > 0); assert_eq!(payment.completed_at, None); } #[test] fn test_payment_status_default() { let payment = Payment::new( "pi_test".to_string(), 1, "yearly".to_string(), 500.0, 99.0, 1688.0, ); assert_eq!(payment.status, PaymentStatus::Pending); assert!(payment.is_pending()); assert!(!payment.is_processing()); assert!(!payment.is_completed()); assert!(!payment.has_failed()); assert!(!payment.is_refunded()); } #[test] fn test_payment_processing() { let payment = Payment::new( "pi_processing_test".to_string(), 1, "monthly".to_string(), 150.0, 60.0, 210.0, ); let processing_payment = payment.process_payment(); assert_eq!(processing_payment.status, PaymentStatus::Processing); assert!(processing_payment.is_processing()); assert!(!processing_payment.is_pending()); assert!(!processing_payment.is_completed()); assert!(!processing_payment.has_failed()); assert!(!processing_payment.is_refunded()); } #[test] fn test_payment_completion() { let payment = Payment::new( "pi_complete_test".to_string(), 1, "monthly".to_string(), 200.0, 75.0, 275.0, ); let stripe_customer_id = Some("cus_test_123".to_string()); let completed_payment = payment.complete_payment(stripe_customer_id.clone()); assert_eq!(completed_payment.status, PaymentStatus::Completed); assert_eq!(completed_payment.stripe_customer_id, stripe_customer_id); assert!(completed_payment.is_completed()); assert!(!completed_payment.is_pending()); assert!(!completed_payment.has_failed()); assert!(!completed_payment.is_refunded()); assert!(completed_payment.completed_at.is_some()); assert!(completed_payment.completed_at.unwrap() > 0); } #[test] fn test_payment_failure() { let payment = Payment::new( "pi_fail_test".to_string(), 1, "yearly".to_string(), 300.0, 60.0, 1020.0, ); let failed_payment = payment.fail_payment(); assert_eq!(failed_payment.status, PaymentStatus::Failed); assert!(failed_payment.has_failed()); assert!(!failed_payment.is_completed()); assert!(!failed_payment.is_pending()); assert!(!failed_payment.is_refunded()); } #[test] fn test_payment_refund() { let payment = Payment::new( "pi_refund_test".to_string(), 1, "monthly".to_string(), 150.0, 45.0, 195.0, ); // First complete the payment let completed_payment = payment.complete_payment(Some("cus_refund_test".to_string())); assert!(completed_payment.is_completed()); // Then refund it let refunded_payment = completed_payment.refund_payment(); assert_eq!(refunded_payment.status, PaymentStatus::Refunded); assert!(refunded_payment.is_refunded()); assert!(!refunded_payment.is_completed()); assert!(!refunded_payment.is_pending()); assert!(!refunded_payment.has_failed()); } #[test] fn test_payment_builder_pattern() { let custom_timestamp = 1640995200; // Jan 1, 2022 let payment = Payment::new( "pi_builder_test".to_string(), 1, "monthly".to_string(), 100.0, 50.0, 150.0, ) .payment_plan("yearly".to_string()) .setup_fee(500.0) .monthly_fee(99.0) .total_amount(1688.0) .currency("eur".to_string()) .stripe_customer_id(Some("cus_builder_test".to_string())) .created_at(custom_timestamp) .completed_at(Some(custom_timestamp + 3600)); assert_eq!(payment.payment_plan, "yearly"); assert_eq!(payment.setup_fee, 500.0); assert_eq!(payment.monthly_fee, 99.0); assert_eq!(payment.total_amount, 1688.0); assert_eq!(payment.currency, "eur"); assert_eq!( payment.stripe_customer_id, Some("cus_builder_test".to_string()) ); assert_eq!(payment.created_at, custom_timestamp); assert_eq!(payment.completed_at, Some(custom_timestamp + 3600)); } #[test] fn test_payment_database_persistence() { let db = create_test_db(); let payment = Payment::new( "pi_db_test".to_string(), 1, "monthly".to_string(), 200.0, 60.0, 260.0, ); // Save payment let (payment_id, saved_payment) = db.set(&payment).expect("Failed to save payment"); assert!(payment_id > 0); assert_eq!(saved_payment.payment_intent_id, "pi_db_test"); // Retrieve payment let retrieved_payment: Payment = db .get_by_id(payment_id) .expect("Failed to get payment") .unwrap(); assert_eq!(retrieved_payment.payment_intent_id, "pi_db_test"); assert_eq!(retrieved_payment.company_id, 1); assert_eq!(retrieved_payment.status, PaymentStatus::Pending); } #[test] fn test_payment_status_transitions() { let db = create_test_db(); let payment = Payment::new( "pi_transition_test".to_string(), 1, "yearly".to_string(), 400.0, 80.0, 1360.0, ); let (payment_id, mut payment) = db.set(&payment).expect("Failed to save payment"); // Test pending -> completed payment = payment.complete_payment(Some("cus_transition_test".to_string())); let (_, mut payment) = db.set(&payment).expect("Failed to update payment"); assert!(payment.is_completed()); // Test completed -> refunded payment = payment.refund_payment(); let (_, payment) = db.set(&payment).expect("Failed to update payment"); assert!(payment.is_refunded()); // Verify final state in database let final_payment: Payment = db .get_by_id(payment_id) .expect("Failed to get payment") .unwrap(); assert_eq!(final_payment.status, PaymentStatus::Refunded); } #[test] fn test_payment_timestamps() { let payment = Payment::new( "pi_timestamp_test".to_string(), 1, "monthly".to_string(), 100.0, 50.0, 150.0, ); let initial_created_at = payment.base_data.created_at; let initial_modified_at = payment.base_data.modified_at; // Complete payment (should update modified_at) let completed_payment = payment.complete_payment(Some("cus_timestamp_test".to_string())); assert_eq!(completed_payment.base_data.created_at, initial_created_at); assert!(completed_payment.base_data.modified_at >= initial_modified_at); } #[test] fn test_company_payment_integration() { let db = create_test_db(); // Create company with default PendingPayment status let company = Company::new( "Integration Test Corp".to_string(), "ITC-001".to_string(), chrono::Utc::now().timestamp(), ) .email("test@integration.com".to_string()) .business_type(BusinessType::Starter); let (company_id, company) = db.set(&company).expect("Failed to save company"); assert_eq!(company.status, CompanyStatus::PendingPayment); // Create payment for the company let payment = Payment::new( "pi_integration_test".to_string(), company_id, "monthly".to_string(), 250.0, 55.0, 305.0, ); let (_payment_id, payment) = db.set(&payment).expect("Failed to save payment"); assert_eq!(payment.company_id, company_id); // Complete payment let completed_payment = payment.complete_payment(Some("cus_integration_test".to_string())); let (_, completed_payment) = db .set(&completed_payment) .expect("Failed to update payment"); // Update company status to Active let active_company = company.status(CompanyStatus::Active); let (_, active_company) = db.set(&active_company).expect("Failed to update company"); // Verify final states assert!(completed_payment.is_completed()); assert_eq!(active_company.status, CompanyStatus::Active); // Verify relationship assert_eq!(completed_payment.company_id, active_company.get_id()); }