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.
This commit is contained in:
		@@ -6,7 +6,9 @@ print("DB instance will be implicitly passed to DB functions.");
 | 
			
		||||
 | 
			
		||||
// --- Enum Constants ---
 | 
			
		||||
print("\n--- Enum Constants ---");
 | 
			
		||||
print(`CompanyStatus PendingPayment: ${CompanyStatusConstants::PendingPayment}`);
 | 
			
		||||
print(`CompanyStatus Active: ${CompanyStatusConstants::Active}`);
 | 
			
		||||
print(`CompanyStatus Suspended: ${CompanyStatusConstants::Suspended}`);
 | 
			
		||||
print(`CompanyStatus Inactive: ${CompanyStatusConstants::Inactive}`);
 | 
			
		||||
print(`BusinessType Coop: ${BusinessTypeConstants::Coop}`);
 | 
			
		||||
print(`BusinessType Global: ${BusinessTypeConstants::Global}`);
 | 
			
		||||
@@ -28,18 +30,46 @@ let company1 = new_company(company1_name, company1_reg, company1_inc_date)
 | 
			
		||||
    .business_type(BusinessTypeConstants::Global)
 | 
			
		||||
    .industry("Technology")
 | 
			
		||||
    .description("Leading provider of innovative tech solutions.")
 | 
			
		||||
    .status(CompanyStatusConstants::Active)
 | 
			
		||||
    // Note: status defaults to PendingPayment for new companies
 | 
			
		||||
    .fiscal_year_end("12-31")
 | 
			
		||||
    .set_base_created_at(1672531200)
 | 
			
		||||
    .set_base_modified_at(1672531205);
 | 
			
		||||
 | 
			
		||||
print(`Company 1 Name: ${company1.name}, Status: ${company1.status}`);
 | 
			
		||||
print(`Company 1 Name: ${company1.name}, Status: ${company1.status} (default for new companies)`);
 | 
			
		||||
print(`Company 1 Email: ${company1.email}, Industry: ${company1.industry}`);
 | 
			
		||||
// Save the company to the database
 | 
			
		||||
print("\nSaving company1 to database...");
 | 
			
		||||
company1 = set_company(company1); // Capture the company with the DB-assigned ID
 | 
			
		||||
print("Company1 saved.");
 | 
			
		||||
 | 
			
		||||
// Demonstrate payment flow for the company
 | 
			
		||||
print("\n--- Payment Processing for Company ---");
 | 
			
		||||
print("Creating payment record for company registration...");
 | 
			
		||||
let payment_intent_id = `pi_demo_${company1.id}`;
 | 
			
		||||
let payment = new_payment(
 | 
			
		||||
    payment_intent_id,
 | 
			
		||||
    company1.id,
 | 
			
		||||
    "yearly",
 | 
			
		||||
    500.0,  // Setup fee
 | 
			
		||||
    99.0,   // Monthly fee
 | 
			
		||||
    1688.0  // Total amount (setup + 12 months)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
payment = set_payment(payment);
 | 
			
		||||
print(`Payment created: ${payment.payment_intent_id}, Status: ${payment.status}`);
 | 
			
		||||
 | 
			
		||||
// Simulate successful payment processing
 | 
			
		||||
print("Processing payment...");
 | 
			
		||||
payment = payment.complete_payment(`cus_demo_${company1.id}`);
 | 
			
		||||
payment = set_payment(payment);
 | 
			
		||||
print(`Payment completed: ${payment.status}`);
 | 
			
		||||
 | 
			
		||||
// Update company status to Active after successful payment
 | 
			
		||||
print("Updating company status to Active after payment...");
 | 
			
		||||
company1 = company1.status(CompanyStatusConstants::Active);
 | 
			
		||||
company1 = set_company(company1);
 | 
			
		||||
print(`Company status updated: ${company1.status}`);
 | 
			
		||||
 | 
			
		||||
// Retrieve the company
 | 
			
		||||
print(`\nRetrieving company by ID (${company1.id})...`);
 | 
			
		||||
let retrieved_company = get_company_by_id(company1.id);
 | 
			
		||||
@@ -97,10 +127,11 @@ print(`Retrieved Shareholder 2: ${retrieved_sh2.name}, Type: ${retrieved_sh2.typ
 | 
			
		||||
print("\n--- Testing Update for Company ---");
 | 
			
		||||
let updated_company = retrieved_company
 | 
			
		||||
    .description("Leading global provider of cutting-edge technology solutions and services.")
 | 
			
		||||
    .status(CompanyStatusConstants::Active)
 | 
			
		||||
    // Note: Company is already Active from payment processing above
 | 
			
		||||
    .phone("+1-555-0199"); // Assume modified_at would be updated by set_company
 | 
			
		||||
 | 
			
		||||
print(`Updated Company - Name: ${updated_company.name}, New Phone: ${updated_company.phone}`);
 | 
			
		||||
print(`Company Status: ${updated_company.status} (already Active from payment)`);
 | 
			
		||||
set_company(updated_company);
 | 
			
		||||
print("Updated Company saved.");
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										229
									
								
								heromodels/examples/biz_rhai/payment_flow.rhai
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										229
									
								
								heromodels/examples/biz_rhai/payment_flow.rhai
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,229 @@
 | 
			
		||||
// Payment Flow Rhai Example
 | 
			
		||||
// This script demonstrates the complete payment flow for company registration
 | 
			
		||||
// using the Rhai scripting interface.
 | 
			
		||||
 | 
			
		||||
print("=== Payment Flow Rhai Example ===");
 | 
			
		||||
print("Demonstrating company registration with payment integration");
 | 
			
		||||
print("");
 | 
			
		||||
 | 
			
		||||
// --- Step 1: Create Company with Pending Payment Status ---
 | 
			
		||||
print("Step 1: Creating company with pending payment status");
 | 
			
		||||
 | 
			
		||||
let company_name = "InnovateTech Solutions";
 | 
			
		||||
let company_reg = "REG-ITS-2024-001";
 | 
			
		||||
let company_inc_date = 1704067200; // Jan 1, 2024
 | 
			
		||||
 | 
			
		||||
// Create company (status defaults to PendingPayment)
 | 
			
		||||
let company = new_company(company_name, company_reg, company_inc_date)
 | 
			
		||||
    .email("contact@innovatetech.com")
 | 
			
		||||
    .phone("+1-555-0199")
 | 
			
		||||
    .website("https://innovatetech.com")
 | 
			
		||||
    .address("456 Innovation Blvd, Tech Valley, TV 67890")
 | 
			
		||||
    .business_type(BusinessTypeConstants::Starter)
 | 
			
		||||
    .industry("Software Development")
 | 
			
		||||
    .description("Cutting-edge software solutions for modern businesses")
 | 
			
		||||
    .fiscal_year_end("12-31");
 | 
			
		||||
 | 
			
		||||
print(`  Company: ${company.name}`);
 | 
			
		||||
print(`  Status: ${company.status} (default for new companies)`);
 | 
			
		||||
print(`  Registration: ${company.registration_number}`);
 | 
			
		||||
print(`  Email: ${company.email}`);
 | 
			
		||||
 | 
			
		||||
// Save company to database
 | 
			
		||||
company = set_company(company);
 | 
			
		||||
print(`  Saved with ID: ${company.id}`);
 | 
			
		||||
print("");
 | 
			
		||||
 | 
			
		||||
// --- Step 2: Create Payment Record ---
 | 
			
		||||
print("Step 2: Creating payment record");
 | 
			
		||||
 | 
			
		||||
let payment_intent_id = `pi_rhai_${timestamp()}`;
 | 
			
		||||
let payment_plan = "yearly";
 | 
			
		||||
let setup_fee = 750.0;
 | 
			
		||||
let monthly_fee = 149.0;
 | 
			
		||||
let total_amount = setup_fee + (monthly_fee * 12.0); // Setup + 12 months
 | 
			
		||||
 | 
			
		||||
let payment = new_payment(
 | 
			
		||||
    payment_intent_id,
 | 
			
		||||
    company.id,
 | 
			
		||||
    payment_plan,
 | 
			
		||||
    setup_fee,
 | 
			
		||||
    monthly_fee,
 | 
			
		||||
    total_amount
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
print(`  Payment Intent ID: ${payment.payment_intent_id}`);
 | 
			
		||||
print(`  Company ID: ${payment.company_id}`);
 | 
			
		||||
print(`  Payment Plan: ${payment.payment_plan}`);
 | 
			
		||||
print(`  Setup Fee: $${payment.setup_fee}`);
 | 
			
		||||
print(`  Monthly Fee: $${payment.monthly_fee}`);
 | 
			
		||||
print(`  Total Amount: $${payment.total_amount}`);
 | 
			
		||||
print(`  Status: ${payment.status} (default for new payments)`);
 | 
			
		||||
 | 
			
		||||
// Save payment to database
 | 
			
		||||
payment = set_payment(payment);
 | 
			
		||||
print(`  Saved with ID: ${payment.id}`);
 | 
			
		||||
print("");
 | 
			
		||||
 | 
			
		||||
// --- Step 3: Process Payment Successfully ---
 | 
			
		||||
print("Step 3: Processing payment...");
 | 
			
		||||
 | 
			
		||||
// Simulate payment processing
 | 
			
		||||
print("  Contacting payment processor...");
 | 
			
		||||
print("  Validating payment details...");
 | 
			
		||||
print("  Processing transaction...");
 | 
			
		||||
 | 
			
		||||
// Complete the payment with Stripe customer ID
 | 
			
		||||
let stripe_customer_id = `cus_rhai_${timestamp()}`;
 | 
			
		||||
payment = payment.complete_payment(stripe_customer_id);
 | 
			
		||||
 | 
			
		||||
print("  Payment completed successfully!");
 | 
			
		||||
print(`  New Status: ${payment.status}`);
 | 
			
		||||
print(`  Stripe Customer ID: ${payment.stripe_customer_id}`);
 | 
			
		||||
 | 
			
		||||
// Save updated payment
 | 
			
		||||
payment = set_payment(payment);
 | 
			
		||||
print("");
 | 
			
		||||
 | 
			
		||||
// --- Step 4: Update Company Status to Active ---
 | 
			
		||||
print("Step 4: Updating company status to Active");
 | 
			
		||||
 | 
			
		||||
company = company.status(CompanyStatusConstants::Active);
 | 
			
		||||
print(`  Company: ${company.name}`);
 | 
			
		||||
print(`  New Status: ${company.status}`);
 | 
			
		||||
 | 
			
		||||
// Save updated company
 | 
			
		||||
company = set_company(company);
 | 
			
		||||
print("  Company status updated successfully!");
 | 
			
		||||
print("");
 | 
			
		||||
 | 
			
		||||
// --- Step 5: Verify Payment Status ---
 | 
			
		||||
print("Step 5: Payment status verification");
 | 
			
		||||
print(`  Is payment completed? ${payment.is_completed()}`);
 | 
			
		||||
print(`  Is payment pending? ${payment.is_pending()}`);
 | 
			
		||||
print(`  Has payment failed? ${payment.has_failed()}`);
 | 
			
		||||
print(`  Is payment refunded? ${payment.is_refunded()}`);
 | 
			
		||||
print("");
 | 
			
		||||
 | 
			
		||||
// --- Step 6: Retrieve Data from Database ---
 | 
			
		||||
print("Step 6: Verifying data from database");
 | 
			
		||||
 | 
			
		||||
let retrieved_company = get_company_by_id(company.id);
 | 
			
		||||
print(`  Retrieved Company: ${retrieved_company.name}`);
 | 
			
		||||
print(`  Status: ${retrieved_company.status}`);
 | 
			
		||||
 | 
			
		||||
let retrieved_payment = get_payment_by_id(payment.id);
 | 
			
		||||
print(`  Retrieved Payment: ${retrieved_payment.payment_intent_id}`);
 | 
			
		||||
print(`  Status: ${retrieved_payment.status}`);
 | 
			
		||||
print(`  Total: $${retrieved_payment.total_amount}`);
 | 
			
		||||
print("");
 | 
			
		||||
 | 
			
		||||
// --- Step 7: Demonstrate Failed Payment Scenario ---
 | 
			
		||||
print("Step 7: Demonstrating failed payment scenario");
 | 
			
		||||
 | 
			
		||||
// Create another company for failed payment demo
 | 
			
		||||
let failed_company = new_company(
 | 
			
		||||
    "FailureDemo Corp",
 | 
			
		||||
    "REG-FDC-2024-002",
 | 
			
		||||
    1704067200
 | 
			
		||||
)
 | 
			
		||||
.email("demo@failurecorp.com")
 | 
			
		||||
.business_type(BusinessTypeConstants::Single)
 | 
			
		||||
.industry("Consulting");
 | 
			
		||||
 | 
			
		||||
failed_company = set_company(failed_company);
 | 
			
		||||
print(`  Created company: ${failed_company.name}`);
 | 
			
		||||
print(`  Status: ${failed_company.status} (pending payment)`);
 | 
			
		||||
 | 
			
		||||
// Create payment that will fail
 | 
			
		||||
let failed_payment_intent = `pi_fail_${timestamp()}`;
 | 
			
		||||
let failed_payment = new_payment(
 | 
			
		||||
    failed_payment_intent,
 | 
			
		||||
    failed_company.id,
 | 
			
		||||
    "monthly",
 | 
			
		||||
    300.0,
 | 
			
		||||
    59.0,
 | 
			
		||||
    359.0
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
failed_payment = set_payment(failed_payment);
 | 
			
		||||
 | 
			
		||||
// Simulate payment failure
 | 
			
		||||
print("  Simulating payment failure...");
 | 
			
		||||
failed_payment = failed_payment.fail_payment();
 | 
			
		||||
failed_payment = set_payment(failed_payment);
 | 
			
		||||
 | 
			
		||||
print(`  Failed Company: ${failed_company.name}`);
 | 
			
		||||
print(`  Company Status: ${failed_company.status} (remains pending)`);
 | 
			
		||||
print(`  Payment Status: ${failed_payment.status}`);
 | 
			
		||||
print(`  Payment failed: ${failed_payment.has_failed()}`);
 | 
			
		||||
print("");
 | 
			
		||||
 | 
			
		||||
// --- Step 8: Demonstrate Payment Refund ---
 | 
			
		||||
print("Step 8: Demonstrating payment refund scenario");
 | 
			
		||||
 | 
			
		||||
// Create a payment to refund
 | 
			
		||||
let refund_company = new_company(
 | 
			
		||||
    "RefundDemo Inc",
 | 
			
		||||
    "REG-RDI-2024-003",
 | 
			
		||||
    1704067200
 | 
			
		||||
)
 | 
			
		||||
.email("refund@demo.com")
 | 
			
		||||
.business_type(BusinessTypeConstants::Twin);
 | 
			
		||||
 | 
			
		||||
refund_company = set_company(refund_company);
 | 
			
		||||
 | 
			
		||||
let refund_payment = new_payment(
 | 
			
		||||
    `pi_refund_${timestamp()}`,
 | 
			
		||||
    refund_company.id,
 | 
			
		||||
    "monthly",
 | 
			
		||||
    200.0,
 | 
			
		||||
    39.0,
 | 
			
		||||
    239.0
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
refund_payment = set_payment(refund_payment);
 | 
			
		||||
 | 
			
		||||
// First complete the payment
 | 
			
		||||
refund_payment = refund_payment.complete_payment(`cus_refund_${timestamp()}`);
 | 
			
		||||
refund_payment = set_payment(refund_payment);
 | 
			
		||||
print(`  Payment completed: ${refund_payment.is_completed()}`);
 | 
			
		||||
 | 
			
		||||
// Then refund it
 | 
			
		||||
refund_payment = refund_payment.refund_payment();
 | 
			
		||||
refund_payment = set_payment(refund_payment);
 | 
			
		||||
 | 
			
		||||
print(`  Payment refunded: ${refund_payment.is_refunded()}`);
 | 
			
		||||
print(`  Refund Status: ${refund_payment.status}`);
 | 
			
		||||
print("");
 | 
			
		||||
 | 
			
		||||
// --- Summary ---
 | 
			
		||||
print("=== Payment Flow Example Complete ===");
 | 
			
		||||
print("Summary of demonstrated features:");
 | 
			
		||||
print("✓ Company creation with PendingPayment status (default)");
 | 
			
		||||
print("✓ Payment record creation and database persistence");
 | 
			
		||||
print("✓ Successful payment processing and status updates");
 | 
			
		||||
print("✓ Company status transition from PendingPayment to Active");
 | 
			
		||||
print("✓ Payment status verification methods");
 | 
			
		||||
print("✓ Database retrieval and verification");
 | 
			
		||||
print("✓ Failed payment scenario handling");
 | 
			
		||||
print("✓ Payment refund processing");
 | 
			
		||||
print("");
 | 
			
		||||
print("Key Payment Statuses:");
 | 
			
		||||
print("- Pending: Initial state for new payments");
 | 
			
		||||
print("- Completed: Payment successfully processed");
 | 
			
		||||
print("- Failed: Payment processing failed");
 | 
			
		||||
print("- Refunded: Previously completed payment was refunded");
 | 
			
		||||
print("");
 | 
			
		||||
print("Key Company Statuses:");
 | 
			
		||||
print("- PendingPayment: Default for new companies (awaiting payment)");
 | 
			
		||||
print("- Active: Payment completed, company is operational");
 | 
			
		||||
print("- Suspended: Company temporarily suspended");
 | 
			
		||||
print("- Inactive: Company deactivated");
 | 
			
		||||
 | 
			
		||||
// Helper function to get current timestamp
 | 
			
		||||
fn timestamp() {
 | 
			
		||||
    // This would normally return current timestamp
 | 
			
		||||
    // For demo purposes, we'll use a static value
 | 
			
		||||
    1704067200
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										220
									
								
								heromodels/examples/biz_rhai/payment_flow_example.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								heromodels/examples/biz_rhai/payment_flow_example.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,220 @@
 | 
			
		||||
// Payment Flow Rhai Example Runner
 | 
			
		||||
// This example runs the payment_flow.rhai script to demonstrate
 | 
			
		||||
// the payment integration using Rhai scripting.
 | 
			
		||||
 | 
			
		||||
use heromodels::db::hero::OurDB;
 | 
			
		||||
use heromodels::models::biz::register_biz_rhai_module;
 | 
			
		||||
use rhai::Engine;
 | 
			
		||||
use std::sync::Arc;
 | 
			
		||||
 | 
			
		||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
 | 
			
		||||
    println!("=== Payment Flow Rhai Example Runner ===");
 | 
			
		||||
    println!("Running payment flow demonstration using Rhai scripting\n");
 | 
			
		||||
 | 
			
		||||
    // Initialize database
 | 
			
		||||
    let db = Arc::new(
 | 
			
		||||
        OurDB::new("/tmp/payment_flow_rhai_example", true)
 | 
			
		||||
            .map_err(|e| format!("DB Error: {}", e))?,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Create and configure Rhai engine
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
    // Register the business models module with the engine
 | 
			
		||||
    register_biz_rhai_module(&mut engine, Arc::clone(&db));
 | 
			
		||||
 | 
			
		||||
    // Add a timestamp function for the Rhai script
 | 
			
		||||
    engine.register_fn("timestamp", || -> i64 { chrono::Utc::now().timestamp() });
 | 
			
		||||
 | 
			
		||||
    // Read and execute the Rhai script
 | 
			
		||||
    let script_path = "examples/biz_rhai/payment_flow.rhai";
 | 
			
		||||
 | 
			
		||||
    match std::fs::read_to_string(script_path) {
 | 
			
		||||
        Ok(script_content) => {
 | 
			
		||||
            println!("Executing Rhai script: {}\n", script_path);
 | 
			
		||||
 | 
			
		||||
            match engine.eval::<()>(&script_content) {
 | 
			
		||||
                Ok(_) => {
 | 
			
		||||
                    println!("\n✅ Rhai script executed successfully!");
 | 
			
		||||
                }
 | 
			
		||||
                Err(e) => {
 | 
			
		||||
                    eprintln!("❌ Error executing Rhai script: {}", e);
 | 
			
		||||
                    return Err(Box::new(e));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            eprintln!("❌ Error reading script file {}: {}", script_path, e);
 | 
			
		||||
            println!("Note: Make sure to run this example from the project root directory.");
 | 
			
		||||
            return Err(Box::new(e));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    println!("\n=== Example Complete ===");
 | 
			
		||||
    println!("The payment flow has been successfully demonstrated using Rhai scripting.");
 | 
			
		||||
    println!("This shows how the payment integration can be used in scripted environments.");
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use heromodels::db::Collection;
 | 
			
		||||
    use heromodels::models::biz::{Company, CompanyStatus, Payment, PaymentStatus};
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_rhai_payment_integration() -> Result<(), Box<dyn std::error::Error>> {
 | 
			
		||||
        // Test that we can create and manipulate payment objects through Rhai
 | 
			
		||||
        let db_config = OurDBConfig {
 | 
			
		||||
            path: "/tmp/test_rhai_payment".to_string(),
 | 
			
		||||
            incremental_mode: true,
 | 
			
		||||
            file_size: None,
 | 
			
		||||
            keysize: None,
 | 
			
		||||
            reset: Some(true),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let db = Arc::new(OurDB::new(db_config)?);
 | 
			
		||||
        let mut engine = Engine::new();
 | 
			
		||||
        register_biz_rhai_module(&mut engine, Arc::clone(&db));
 | 
			
		||||
 | 
			
		||||
        // Test creating a company through Rhai
 | 
			
		||||
        let company_script = r#"
 | 
			
		||||
            let company = new_company("Test Company", "TEST-001", 1704067200)
 | 
			
		||||
                .email("test@example.com")
 | 
			
		||||
                .status(CompanyStatusConstants::PendingPayment);
 | 
			
		||||
            company = set_company(company);
 | 
			
		||||
            company.id
 | 
			
		||||
        "#;
 | 
			
		||||
 | 
			
		||||
        let company_id: i64 = engine.eval(company_script)?;
 | 
			
		||||
        assert!(company_id > 0);
 | 
			
		||||
 | 
			
		||||
        // Test creating a payment through Rhai
 | 
			
		||||
        let payment_script = format!(
 | 
			
		||||
            r#"
 | 
			
		||||
            let payment = new_payment("pi_test_123", {}, "monthly", 100.0, 50.0, 150.0);
 | 
			
		||||
            payment = set_payment(payment);
 | 
			
		||||
            payment.id
 | 
			
		||||
        "#,
 | 
			
		||||
            company_id
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let payment_id: i64 = engine.eval(&payment_script)?;
 | 
			
		||||
        assert!(payment_id > 0);
 | 
			
		||||
 | 
			
		||||
        // Test completing payment through Rhai
 | 
			
		||||
        let complete_script = format!(
 | 
			
		||||
            r#"
 | 
			
		||||
            let payment = get_payment_by_id({});
 | 
			
		||||
            payment = payment.complete_payment("cus_test_123");
 | 
			
		||||
            payment = set_payment(payment);
 | 
			
		||||
            payment.is_completed()
 | 
			
		||||
        "#,
 | 
			
		||||
            payment_id
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let is_completed: bool = engine.eval(&complete_script)?;
 | 
			
		||||
        assert!(is_completed);
 | 
			
		||||
 | 
			
		||||
        // Verify in database
 | 
			
		||||
        let payment: Payment = db.get_by_id(payment_id as u32)?.unwrap();
 | 
			
		||||
        assert_eq!(payment.status, PaymentStatus::Completed);
 | 
			
		||||
        assert_eq!(payment.stripe_customer_id, Some("cus_test_123".to_string()));
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_payment_status_constants() -> Result<(), Box<dyn std::error::Error>> {
 | 
			
		||||
        // Test that payment status constants are available in Rhai
 | 
			
		||||
        let db_config = OurDBConfig {
 | 
			
		||||
            path: "/tmp/test_payment_constants".to_string(),
 | 
			
		||||
            incremental_mode: true,
 | 
			
		||||
            file_size: None,
 | 
			
		||||
            keysize: None,
 | 
			
		||||
            reset: Some(true),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let db = Arc::new(OurDB::new(db_config)?);
 | 
			
		||||
        let mut engine = Engine::new();
 | 
			
		||||
        register_biz_rhai_module(&mut engine, Arc::clone(&db));
 | 
			
		||||
 | 
			
		||||
        // Test that we can access payment status constants
 | 
			
		||||
        let constants_script = r#"
 | 
			
		||||
            let payment = new_payment("pi_test", 1, "monthly", 100.0, 50.0, 150.0);
 | 
			
		||||
            
 | 
			
		||||
            // Test status transitions
 | 
			
		||||
            payment = payment.status(PaymentStatusConstants::Pending);
 | 
			
		||||
            let is_pending = payment.is_pending();
 | 
			
		||||
            
 | 
			
		||||
            payment = payment.status(PaymentStatusConstants::Completed);
 | 
			
		||||
            let is_completed = payment.is_completed();
 | 
			
		||||
            
 | 
			
		||||
            payment = payment.status(PaymentStatusConstants::Failed);
 | 
			
		||||
            let has_failed = payment.has_failed();
 | 
			
		||||
            
 | 
			
		||||
            payment = payment.status(PaymentStatusConstants::Refunded);
 | 
			
		||||
            let is_refunded = payment.is_refunded();
 | 
			
		||||
            
 | 
			
		||||
            [is_pending, is_completed, has_failed, is_refunded]
 | 
			
		||||
        "#;
 | 
			
		||||
 | 
			
		||||
        let results: Vec<bool> = engine.eval(constants_script)?;
 | 
			
		||||
        assert_eq!(results, vec![true, true, true, true]);
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_company_status_integration() -> Result<(), Box<dyn std::error::Error>> {
 | 
			
		||||
        // Test the integration between company and payment status
 | 
			
		||||
        let db_config = OurDBConfig {
 | 
			
		||||
            path: "/tmp/test_status_integration".to_string(),
 | 
			
		||||
            incremental_mode: true,
 | 
			
		||||
            file_size: None,
 | 
			
		||||
            keysize: None,
 | 
			
		||||
            reset: Some(true),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let db = Arc::new(OurDB::new(db_config)?);
 | 
			
		||||
        let mut engine = Engine::new();
 | 
			
		||||
        register_biz_rhai_module(&mut engine, Arc::clone(&db));
 | 
			
		||||
 | 
			
		||||
        let integration_script = r#"
 | 
			
		||||
            // Create company (defaults to PendingPayment)
 | 
			
		||||
            let company = new_company("Integration Test", "INT-001", 1704067200);
 | 
			
		||||
            company = set_company(company);
 | 
			
		||||
            
 | 
			
		||||
            // Create payment
 | 
			
		||||
            let payment = new_payment("pi_int_test", company.id, "yearly", 500.0, 99.0, 1688.0);
 | 
			
		||||
            payment = set_payment(payment);
 | 
			
		||||
            
 | 
			
		||||
            // Complete payment
 | 
			
		||||
            payment = payment.complete_payment("cus_int_test");
 | 
			
		||||
            payment = set_payment(payment);
 | 
			
		||||
            
 | 
			
		||||
            // Update company to active
 | 
			
		||||
            company = company.status(CompanyStatusConstants::Active);
 | 
			
		||||
            company = set_company(company);
 | 
			
		||||
            
 | 
			
		||||
            [payment.is_completed(), company.status]
 | 
			
		||||
        "#;
 | 
			
		||||
 | 
			
		||||
        let results: Vec<rhai::Dynamic> = engine.eval(integration_script)?;
 | 
			
		||||
 | 
			
		||||
        // Check that payment is completed
 | 
			
		||||
        assert!(results[0].as_bool().unwrap());
 | 
			
		||||
 | 
			
		||||
        // Check that company status is Active (we can't directly compare enum in Rhai result)
 | 
			
		||||
        // So we'll verify by retrieving from database
 | 
			
		||||
        let companies: Vec<Company> = db.get_all()?;
 | 
			
		||||
        let company = companies
 | 
			
		||||
            .into_iter()
 | 
			
		||||
            .find(|c| c.name == "Integration Test")
 | 
			
		||||
            .unwrap();
 | 
			
		||||
        assert_eq!(company.status, CompanyStatus::Active);
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										214
									
								
								heromodels/examples/payment_flow_example.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										214
									
								
								heromodels/examples/payment_flow_example.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,214 @@
 | 
			
		||||
// Payment Flow Example
 | 
			
		||||
// This example demonstrates the complete payment flow for company registration,
 | 
			
		||||
// including company creation with pending payment status, payment processing,
 | 
			
		||||
// and status transitions.
 | 
			
		||||
 | 
			
		||||
use heromodels::models::biz::{BusinessType, Company, CompanyStatus, Payment};
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    println!("=== Payment Flow Example ===");
 | 
			
		||||
    println!("Demonstrating company registration with payment integration\n");
 | 
			
		||||
 | 
			
		||||
    // Step 1: Create a company with pending payment status
 | 
			
		||||
    println!("Step 1: Creating company with pending payment status");
 | 
			
		||||
    let company = Company::new(
 | 
			
		||||
        "TechStart Inc.".to_string(),
 | 
			
		||||
        "REG-TS-2024-001".to_string(),
 | 
			
		||||
        chrono::Utc::now().timestamp(),
 | 
			
		||||
    )
 | 
			
		||||
    .email("contact@techstart.com".to_string())
 | 
			
		||||
    .phone("+1-555-0123".to_string())
 | 
			
		||||
    .website("https://techstart.com".to_string())
 | 
			
		||||
    .address("123 Startup Ave, Innovation City, IC 12345".to_string())
 | 
			
		||||
    .business_type(BusinessType::Starter)
 | 
			
		||||
    .industry("Technology".to_string())
 | 
			
		||||
    .description("A promising tech startup focused on AI solutions".to_string())
 | 
			
		||||
    // Note: status defaults to PendingPayment, so we don't need to set it explicitly
 | 
			
		||||
    .fiscal_year_end("12-31".to_string());
 | 
			
		||||
 | 
			
		||||
    println!("  Company: {}", company.name);
 | 
			
		||||
    println!("  Status: {:?}", company.status);
 | 
			
		||||
    println!("  Registration: {}", company.registration_number);
 | 
			
		||||
    println!("  Company created successfully!\n");
 | 
			
		||||
 | 
			
		||||
    // Step 2: Create a payment record for the company
 | 
			
		||||
    println!("Step 2: Creating payment record");
 | 
			
		||||
    let payment_intent_id = format!("pi_test_{}", chrono::Utc::now().timestamp());
 | 
			
		||||
    let payment = Payment::new(
 | 
			
		||||
        payment_intent_id.clone(),
 | 
			
		||||
        1, // Mock company ID for this example
 | 
			
		||||
        "yearly".to_string(),
 | 
			
		||||
        500.0,  // Setup fee
 | 
			
		||||
        99.0,   // Monthly fee
 | 
			
		||||
        1688.0, // Total amount (setup + 12 months)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    println!("  Payment Intent ID: {}", payment.payment_intent_id);
 | 
			
		||||
    println!("  Company ID: {}", payment.company_id);
 | 
			
		||||
    println!("  Payment Plan: {}", payment.payment_plan);
 | 
			
		||||
    println!("  Setup Fee: ${:.2}", payment.setup_fee);
 | 
			
		||||
    println!("  Monthly Fee: ${:.2}", payment.monthly_fee);
 | 
			
		||||
    println!("  Total Amount: ${:.2}", payment.total_amount);
 | 
			
		||||
    println!("  Status: {:?}", payment.status);
 | 
			
		||||
    println!("  Payment record created successfully!\n");
 | 
			
		||||
 | 
			
		||||
    // Step 3: Simulate payment processing
 | 
			
		||||
    println!("Step 3: Processing payment...");
 | 
			
		||||
 | 
			
		||||
    // Simulate some processing time
 | 
			
		||||
    std::thread::sleep(std::time::Duration::from_millis(100));
 | 
			
		||||
 | 
			
		||||
    // Complete the payment with Stripe customer ID
 | 
			
		||||
    let stripe_customer_id = Some(format!("cus_test_{}", chrono::Utc::now().timestamp()));
 | 
			
		||||
    let completed_payment = payment.complete_payment(stripe_customer_id.clone());
 | 
			
		||||
 | 
			
		||||
    println!("  Payment completed successfully!");
 | 
			
		||||
    println!("  New Status: {:?}", completed_payment.status);
 | 
			
		||||
    println!(
 | 
			
		||||
        "  Stripe Customer ID: {:?}",
 | 
			
		||||
        completed_payment.stripe_customer_id
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Step 4: Update company status to Active
 | 
			
		||||
    println!("\nStep 4: Updating company status to Active");
 | 
			
		||||
    let active_company = company.status(CompanyStatus::Active);
 | 
			
		||||
 | 
			
		||||
    println!("  Company: {}", active_company.name);
 | 
			
		||||
    println!("  New Status: {:?}", active_company.status);
 | 
			
		||||
    println!("  Company status updated successfully!\n");
 | 
			
		||||
 | 
			
		||||
    // Step 5: Demonstrate payment status checks
 | 
			
		||||
    println!("Step 5: Payment status verification");
 | 
			
		||||
    println!(
 | 
			
		||||
        "  Is payment completed? {}",
 | 
			
		||||
        completed_payment.is_completed()
 | 
			
		||||
    );
 | 
			
		||||
    println!("  Is payment pending? {}", completed_payment.is_pending());
 | 
			
		||||
    println!("  Has payment failed? {}", completed_payment.has_failed());
 | 
			
		||||
    println!("  Is payment refunded? {}", completed_payment.is_refunded());
 | 
			
		||||
 | 
			
		||||
    // Step 6: Demonstrate failed payment scenario
 | 
			
		||||
    println!("\nStep 6: Demonstrating failed payment scenario");
 | 
			
		||||
 | 
			
		||||
    // Create another company
 | 
			
		||||
    let failed_company = Company::new(
 | 
			
		||||
        "FailCorp Ltd.".to_string(),
 | 
			
		||||
        "REG-FC-2024-002".to_string(),
 | 
			
		||||
        chrono::Utc::now().timestamp(),
 | 
			
		||||
    )
 | 
			
		||||
    .email("contact@failcorp.com".to_string())
 | 
			
		||||
    .business_type(BusinessType::Single)
 | 
			
		||||
    .industry("Consulting".to_string());
 | 
			
		||||
 | 
			
		||||
    // Create payment for failed scenario
 | 
			
		||||
    let failed_payment_intent = format!("pi_fail_{}", chrono::Utc::now().timestamp());
 | 
			
		||||
    let failed_payment = Payment::new(
 | 
			
		||||
        failed_payment_intent,
 | 
			
		||||
        2, // Mock company ID
 | 
			
		||||
        "monthly".to_string(),
 | 
			
		||||
        250.0,
 | 
			
		||||
        49.0,
 | 
			
		||||
        299.0,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Simulate payment failure
 | 
			
		||||
    let failed_payment = failed_payment.fail_payment();
 | 
			
		||||
 | 
			
		||||
    println!("  Failed Company: {}", failed_company.name);
 | 
			
		||||
    println!(
 | 
			
		||||
        "  Company Status: {:?} (remains pending)",
 | 
			
		||||
        failed_company.status
 | 
			
		||||
    );
 | 
			
		||||
    println!("  Payment Status: {:?}", failed_payment.status);
 | 
			
		||||
    println!("  Payment failed: {}", failed_payment.has_failed());
 | 
			
		||||
 | 
			
		||||
    println!("\n=== Payment Flow Example Complete ===");
 | 
			
		||||
    println!("Summary:");
 | 
			
		||||
    println!("- Created companies with PendingPayment status by default");
 | 
			
		||||
    println!("- Processed successful payment and updated company to Active");
 | 
			
		||||
    println!("- Demonstrated failed payment scenario");
 | 
			
		||||
    println!("- All operations completed successfully without database persistence");
 | 
			
		||||
    println!("- For database examples, see the Rhai examples or unit tests");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_payment_flow() {
 | 
			
		||||
        // Test the basic payment flow without database persistence
 | 
			
		||||
        let company = Company::new(
 | 
			
		||||
            "Test Company".to_string(),
 | 
			
		||||
            "TEST-001".to_string(),
 | 
			
		||||
            chrono::Utc::now().timestamp(),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Verify default status is PendingPayment
 | 
			
		||||
        assert_eq!(company.status, CompanyStatus::PendingPayment);
 | 
			
		||||
 | 
			
		||||
        // Create payment
 | 
			
		||||
        let payment = Payment::new(
 | 
			
		||||
            "pi_test_123".to_string(),
 | 
			
		||||
            1, // Mock company ID
 | 
			
		||||
            "monthly".to_string(),
 | 
			
		||||
            100.0,
 | 
			
		||||
            50.0,
 | 
			
		||||
            150.0,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Verify default payment status is Pending
 | 
			
		||||
        assert_eq!(payment.status, PaymentStatus::Pending);
 | 
			
		||||
        assert!(payment.is_pending());
 | 
			
		||||
        assert!(!payment.is_completed());
 | 
			
		||||
 | 
			
		||||
        // Complete payment
 | 
			
		||||
        let completed_payment = payment.complete_payment(Some("cus_test_123".to_string()));
 | 
			
		||||
        assert_eq!(completed_payment.status, PaymentStatus::Completed);
 | 
			
		||||
        assert!(completed_payment.is_completed());
 | 
			
		||||
        assert!(!completed_payment.is_pending());
 | 
			
		||||
 | 
			
		||||
        // Update company status
 | 
			
		||||
        let active_company = company.status(CompanyStatus::Active);
 | 
			
		||||
        assert_eq!(active_company.status, CompanyStatus::Active);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_payment_failure() {
 | 
			
		||||
        let payment = Payment::new(
 | 
			
		||||
            "pi_fail_123".to_string(),
 | 
			
		||||
            1,
 | 
			
		||||
            "yearly".to_string(),
 | 
			
		||||
            500.0,
 | 
			
		||||
            99.0,
 | 
			
		||||
            1688.0,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let failed_payment = payment.fail_payment();
 | 
			
		||||
        assert_eq!(failed_payment.status, PaymentStatus::Failed);
 | 
			
		||||
        assert!(failed_payment.has_failed());
 | 
			
		||||
        assert!(!failed_payment.is_completed());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_payment_refund() {
 | 
			
		||||
        let payment = Payment::new(
 | 
			
		||||
            "pi_refund_123".to_string(),
 | 
			
		||||
            1,
 | 
			
		||||
            "monthly".to_string(),
 | 
			
		||||
            250.0,
 | 
			
		||||
            49.0,
 | 
			
		||||
            299.0,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // First complete the payment
 | 
			
		||||
        let completed_payment = payment.complete_payment(Some("cus_123".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());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user