db/heromodels/tests/payment.rs
Mahmoud-Emad af83035d89 feat: Add new Rhai example demonstrating payment flow
- Add a new Rhai example showcasing complete payment flow
  for company registration. This includes company creation,
  payment record creation, successful payment processing,
  status updates, and handling failed and refunded payments.
- Add new example demonstrating payment integration in Rhai
  scripting.  This example showcases the usage of various
  payment status methods and verifies data from the database
  after processing payments.
- Add new examples to Cargo.toml to facilitate building and
  running the examples.  This makes it easier to integrate
  and test payment functionality using Rhai scripting.
2025-06-25 18:39:47 +03:00

314 lines
9.1 KiB
Rust

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<OurDB> {
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());
}