feat: Add reminder functionality to ContractSigner model
- Added `last_reminder_mail_sent_at` field to track reminder timestamps. - Implemented `can_send_reminder` to check if a reminder can be sent based on a 30-minute cooldown. - Added `reminder_cooldown_remaining` to get remaining cooldown time. - Added `mark_reminder_sent` to update reminder timestamp. - Added example demonstrating reminder functionality in `legal_contract_example.rs`. - Added tests for reminder functionality in `test_reminder_functionality.rs`. - Updated Rhai scripts to include reminder-related functions and tests. - Improved formatting and clarity in example code.
This commit is contained in:
@@ -70,7 +70,7 @@ fn main() {
|
||||
.add_signer(signer2.clone())
|
||||
.add_revision(revision1.clone())
|
||||
.add_revision(revision2.clone());
|
||||
|
||||
|
||||
// The `#[model]` derive handles `created_at` and `updated_at` in `base_data`.
|
||||
// `base_data.touch()` might be called internally by setters or needs explicit call if fields are set directly.
|
||||
// For builder pattern, the final state of `base_data.updated_at` reflects the time of the last builder call if `touch()` is implicit.
|
||||
@@ -87,7 +87,7 @@ fn main() {
|
||||
|
||||
println!("\n--- Contract Details After Signing ---");
|
||||
println!("{:#?}", contract);
|
||||
|
||||
|
||||
println!("\n--- Accessing Specific Fields ---");
|
||||
println!("Contract Title: {}", contract.title);
|
||||
println!("Contract Status: {:?}", contract.status);
|
||||
@@ -97,7 +97,10 @@ fn main() {
|
||||
println!("Updated At (timestamp): {}", contract.base_data.modified_at); // From BaseModelData
|
||||
|
||||
if let Some(first_signer_details) = contract.signers.first() {
|
||||
println!("\nFirst Signer: {} ({})", first_signer_details.name, first_signer_details.email);
|
||||
println!(
|
||||
"\nFirst Signer: {} ({})",
|
||||
first_signer_details.name, first_signer_details.email
|
||||
);
|
||||
println!(" Status: {:?}", first_signer_details.status);
|
||||
if let Some(signed_time) = first_signer_details.signed_at {
|
||||
println!(" Signed At: {}", signed_time);
|
||||
@@ -110,6 +113,51 @@ fn main() {
|
||||
println!(" Created By: {}", latest_rev.created_by);
|
||||
println!(" Revision Created At: {}", latest_rev.created_at);
|
||||
}
|
||||
|
||||
|
||||
// Demonstrate reminder functionality
|
||||
println!("\n--- Reminder Functionality Demo ---");
|
||||
let current_time = current_timestamp_secs();
|
||||
|
||||
// Check if we can send reminders to signers
|
||||
for (i, signer) in contract.signers.iter().enumerate() {
|
||||
println!("\nSigner {}: {} ({})", i + 1, signer.name, signer.email);
|
||||
println!(" Status: {:?}", signer.status);
|
||||
|
||||
if signer.last_reminder_mail_sent_at.is_none() {
|
||||
println!(" Last reminder: Never sent");
|
||||
} else {
|
||||
println!(
|
||||
" Last reminder: {}",
|
||||
signer.last_reminder_mail_sent_at.unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
let can_send = signer.can_send_reminder(current_time);
|
||||
println!(" Can send reminder now: {}", can_send);
|
||||
|
||||
if let Some(remaining) = signer.reminder_cooldown_remaining(current_time) {
|
||||
println!(" Cooldown remaining: {} seconds", remaining);
|
||||
} else {
|
||||
println!(" No cooldown active");
|
||||
}
|
||||
}
|
||||
|
||||
// Simulate sending a reminder to the first signer
|
||||
if let Some(first_signer) = contract.signers.get_mut(0) {
|
||||
if first_signer.can_send_reminder(current_time) {
|
||||
println!("\nSimulating reminder sent to: {}", first_signer.name);
|
||||
first_signer.mark_reminder_sent(current_time);
|
||||
println!(
|
||||
" Reminder timestamp updated to: {}",
|
||||
first_signer.last_reminder_mail_sent_at.unwrap()
|
||||
);
|
||||
|
||||
// Check cooldown after sending
|
||||
if let Some(remaining) = first_signer.reminder_cooldown_remaining(current_time) {
|
||||
println!(" New cooldown: {} seconds (30 minutes)", remaining);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("\nLegal Contract Model demonstration complete.");
|
||||
}
|
||||
|
@@ -39,14 +39,17 @@ let signer1 = new_contract_signer(signer1_id, "Alice Wonderland", "alice@example
|
||||
print(`Signer 1 ID: ${signer1.id}, Name: ${signer1.name}, Email: ${signer1.email}`);
|
||||
print(`Signer 1 Status: ${signer1.status}, Comments: ${format_optional_string(signer1.comments, "N/A")}`);
|
||||
print(`Signer 1 Signed At: ${format_optional_int(signer1.signed_at, "Not signed")}`);
|
||||
print(`Signer 1 Last Reminder: ${format_optional_int(signer1.last_reminder_mail_sent_at, "Never sent")}`);
|
||||
|
||||
let signer2_id = "signer-uuid-002";
|
||||
let signer2 = new_contract_signer(signer2_id, "Bob The Builder", "bob@example.com")
|
||||
.status(SignerStatusConstants::Signed)
|
||||
.signed_at(1678886400) // Example timestamp
|
||||
.comments("Bob has already signed.");
|
||||
.comments("Bob has already signed.")
|
||||
.last_reminder_mail_sent_at(1678880000); // Example reminder timestamp
|
||||
|
||||
print(`Signer 2 ID: ${signer2.id}, Name: ${signer2.name}, Status: ${signer2.status}, Signed At: ${format_optional_int(signer2.signed_at, "N/A")}`);
|
||||
print(`Signer 2 Last Reminder: ${format_optional_int(signer2.last_reminder_mail_sent_at, "Never sent")}`);
|
||||
|
||||
// --- Test ContractRevision Model ---
|
||||
print("\n--- Testing ContractRevision Model ---");
|
||||
@@ -116,4 +119,31 @@ print("Updated Contract saved.");
|
||||
let final_retrieved_contract = get_contract_by_id(contract1_base_id);
|
||||
print(`Final Retrieved Contract - Status: ${final_retrieved_contract.status}, Description: '${final_retrieved_contract.description}'`);
|
||||
|
||||
// --- Test Reminder Functionality ---
|
||||
print("\n--- Testing Reminder Functionality ---");
|
||||
let current_time = 1678900000; // Example current timestamp
|
||||
|
||||
// Test reminder functionality on signers
|
||||
if final_retrieved_contract.signers.len() > 0 {
|
||||
let test_signer = final_retrieved_contract.signers[0];
|
||||
print(`Testing reminder for signer: ${test_signer.name}`);
|
||||
|
||||
let can_send = can_send_reminder(test_signer, current_time);
|
||||
print(`Can send reminder: ${can_send}`);
|
||||
|
||||
let cooldown_remaining = reminder_cooldown_remaining(test_signer, current_time);
|
||||
print(`Cooldown remaining: ${format_optional_int(cooldown_remaining, "No cooldown")}`);
|
||||
|
||||
// Simulate sending a reminder
|
||||
if can_send {
|
||||
print("Simulating reminder sent...");
|
||||
mark_reminder_sent(test_signer, current_time);
|
||||
print("Reminder timestamp updated");
|
||||
|
||||
// Check cooldown after sending
|
||||
let new_cooldown = reminder_cooldown_remaining(test_signer, current_time);
|
||||
print(`New cooldown: ${format_optional_int(new_cooldown, "No cooldown")} seconds`);
|
||||
}
|
||||
}
|
||||
|
||||
print("\nLegal Rhai example script finished.");
|
||||
|
108
heromodels/examples/test_reminder_functionality.rs
Normal file
108
heromodels/examples/test_reminder_functionality.rs
Normal file
@@ -0,0 +1,108 @@
|
||||
use heromodels::models::legal::{ContractSigner, SignerStatus};
|
||||
|
||||
// Helper function to get current timestamp
|
||||
fn current_timestamp_secs() -> u64 {
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_secs()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("Testing ContractSigner Reminder Functionality");
|
||||
println!("==============================================\n");
|
||||
|
||||
// Test 1: Create a new signer (should have no reminder timestamp)
|
||||
println!("Test 1: New signer creation");
|
||||
let mut signer = ContractSigner::new(
|
||||
"test-signer-001".to_string(),
|
||||
"Test User".to_string(),
|
||||
"test@example.com".to_string(),
|
||||
);
|
||||
|
||||
println!(" Signer created: {}", signer.name);
|
||||
println!(" Last reminder: {:?}", signer.last_reminder_mail_sent_at);
|
||||
assert_eq!(signer.last_reminder_mail_sent_at, None);
|
||||
println!(" ✓ New signer has no reminder timestamp\n");
|
||||
|
||||
// Test 2: Check if reminder can be sent (should be true for new signer)
|
||||
println!("Test 2: Can send reminder check");
|
||||
let current_time = current_timestamp_secs();
|
||||
let can_send = signer.can_send_reminder(current_time);
|
||||
println!(" Can send reminder: {}", can_send);
|
||||
assert!(can_send);
|
||||
println!(" ✓ New signer can receive reminders\n");
|
||||
|
||||
// Test 3: Check cooldown remaining (should be None for new signer)
|
||||
println!("Test 3: Cooldown remaining check");
|
||||
let cooldown = signer.reminder_cooldown_remaining(current_time);
|
||||
println!(" Cooldown remaining: {:?}", cooldown);
|
||||
assert_eq!(cooldown, None);
|
||||
println!(" ✓ New signer has no cooldown\n");
|
||||
|
||||
// Test 4: Mark reminder as sent
|
||||
println!("Test 4: Mark reminder as sent");
|
||||
signer.mark_reminder_sent(current_time);
|
||||
println!(" Reminder marked as sent at: {}", current_time);
|
||||
println!(" Last reminder timestamp: {:?}", signer.last_reminder_mail_sent_at);
|
||||
assert_eq!(signer.last_reminder_mail_sent_at, Some(current_time));
|
||||
println!(" ✓ Reminder timestamp updated correctly\n");
|
||||
|
||||
// Test 5: Check if reminder can be sent immediately after (should be false)
|
||||
println!("Test 5: Immediate retry check");
|
||||
let can_send_again = signer.can_send_reminder(current_time);
|
||||
println!(" Can send reminder immediately: {}", can_send_again);
|
||||
assert!(!can_send_again);
|
||||
println!(" ✓ Cannot send reminder immediately after sending\n");
|
||||
|
||||
// Test 6: Check cooldown remaining (should be 30 minutes)
|
||||
println!("Test 6: Cooldown after sending");
|
||||
let cooldown_after = signer.reminder_cooldown_remaining(current_time);
|
||||
println!(" Cooldown remaining: {:?} seconds", cooldown_after);
|
||||
assert_eq!(cooldown_after, Some(30 * 60)); // 30 minutes = 1800 seconds
|
||||
println!(" ✓ Cooldown is exactly 30 minutes\n");
|
||||
|
||||
// Test 7: Test after cooldown period
|
||||
println!("Test 7: After cooldown period");
|
||||
let future_time = current_time + (31 * 60); // 31 minutes later
|
||||
let can_send_later = signer.can_send_reminder(future_time);
|
||||
let cooldown_later = signer.reminder_cooldown_remaining(future_time);
|
||||
println!(" Time: {} (31 minutes later)", future_time);
|
||||
println!(" Can send reminder: {}", can_send_later);
|
||||
println!(" Cooldown remaining: {:?}", cooldown_later);
|
||||
assert!(can_send_later);
|
||||
assert_eq!(cooldown_later, None);
|
||||
println!(" ✓ Can send reminder after cooldown period\n");
|
||||
|
||||
// Test 8: Test builder pattern with reminder timestamp
|
||||
println!("Test 8: Builder pattern with reminder timestamp");
|
||||
let signer_with_reminder = ContractSigner::new(
|
||||
"test-signer-002".to_string(),
|
||||
"Another User".to_string(),
|
||||
"another@example.com".to_string(),
|
||||
)
|
||||
.status(SignerStatus::Pending)
|
||||
.last_reminder_mail_sent_at(current_time - (20 * 60)) // 20 minutes ago
|
||||
.comments("Test signer with reminder");
|
||||
|
||||
println!(" Signer: {}", signer_with_reminder.name);
|
||||
println!(" Last reminder: {:?}", signer_with_reminder.last_reminder_mail_sent_at);
|
||||
println!(" Can send reminder: {}", signer_with_reminder.can_send_reminder(current_time));
|
||||
|
||||
let remaining = signer_with_reminder.reminder_cooldown_remaining(current_time);
|
||||
println!(" Cooldown remaining: {:?} seconds", remaining);
|
||||
assert_eq!(remaining, Some(10 * 60)); // 10 minutes remaining
|
||||
println!(" ✓ Builder pattern works correctly\n");
|
||||
|
||||
// Test 9: Test clear reminder timestamp
|
||||
println!("Test 9: Clear reminder timestamp");
|
||||
let cleared_signer = signer_with_reminder.clear_last_reminder_mail_sent_at();
|
||||
println!(" Last reminder after clear: {:?}", cleared_signer.last_reminder_mail_sent_at);
|
||||
println!(" Can send reminder: {}", cleared_signer.can_send_reminder(current_time));
|
||||
assert_eq!(cleared_signer.last_reminder_mail_sent_at, None);
|
||||
assert!(cleared_signer.can_send_reminder(current_time));
|
||||
println!(" ✓ Clear reminder timestamp works correctly\n");
|
||||
|
||||
println!("All tests passed! ✅");
|
||||
println!("ContractSigner reminder functionality is working correctly.");
|
||||
}
|
Reference in New Issue
Block a user