From 9821b484123c168bb5922af890eed74f371ba89b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CPeteroche=E2=80=9D?= <“petergoddey08l@gmail.com”> Date: Thu, 22 Jan 2026 17:12:37 +0100 Subject: [PATCH] Asset Maintenance and Service History Contract --- contracts/Cargo.lock | 7 + contracts/Cargo.toml | 1 + contracts/asset-maintenance/Cargo.toml | 13 + contracts/asset-maintenance/src/lib.rs | 549 ++++++++++ contracts/asset-maintenance/src/test.rs | 182 ++++ .../test/test_alerts_and_stats.1.json | 339 ++++++ ...test_init_and_provider_registration.1.json | 475 +++++++++ .../test/test_maintenance_lifecycle.1.json | 985 ++++++++++++++++++ .../test/test_warranty_and_claims.1.json | 329 ++++++ 9 files changed, 2880 insertions(+) create mode 100644 contracts/asset-maintenance/Cargo.toml create mode 100644 contracts/asset-maintenance/src/lib.rs create mode 100644 contracts/asset-maintenance/src/test.rs create mode 100644 contracts/asset-maintenance/test_snapshots/test/test_alerts_and_stats.1.json create mode 100644 contracts/asset-maintenance/test_snapshots/test/test_init_and_provider_registration.1.json create mode 100644 contracts/asset-maintenance/test_snapshots/test/test_maintenance_lifecycle.1.json create mode 100644 contracts/asset-maintenance/test_snapshots/test/test_warranty_and_claims.1.json diff --git a/contracts/Cargo.lock b/contracts/Cargo.lock index 6af4fd0..70ea63e 100644 --- a/contracts/Cargo.lock +++ b/contracts/Cargo.lock @@ -150,6 +150,13 @@ dependencies = [ "rand", ] +[[package]] +name = "asset-maintenance" +version = "0.1.0" +dependencies = [ + "soroban-sdk", +] + [[package]] name = "autocfg" version = "1.5.0" diff --git a/contracts/Cargo.toml b/contracts/Cargo.toml index 4032239..9604e21 100644 --- a/contracts/Cargo.toml +++ b/contracts/Cargo.toml @@ -2,6 +2,7 @@ resolver = "2" members = [ "./hello-world", + "./asset-maintenance", ] [workspace.dependencies] diff --git a/contracts/asset-maintenance/Cargo.toml b/contracts/asset-maintenance/Cargo.toml new file mode 100644 index 0000000..d0d91ef --- /dev/null +++ b/contracts/asset-maintenance/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "asset-maintenance" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +soroban-sdk = { workspace = true } + +[dev-dependencies] +soroban-sdk = { workspace = true, features = ["testutils"] } diff --git a/contracts/asset-maintenance/src/lib.rs b/contracts/asset-maintenance/src/lib.rs new file mode 100644 index 0000000..1bc42af --- /dev/null +++ b/contracts/asset-maintenance/src/lib.rs @@ -0,0 +1,549 @@ +#![no_std] +use soroban_sdk::{ + contract, contractimpl, contracttype, symbol_short, Address, Env, String, Vec, +}; + +mod test; + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum MaintenanceType { + Preventive, + Corrective, + Emergency, + Inspection, + Upgrade, + Calibration, +} + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum AlertType { + ServiceDue, + WarrantyExpiring, + IssueDetected, +} + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum AlertSeverity { + Low, + Medium, + High, + Critical, +} + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum WarrantyStatus { + Active, + Expired, + Voided, +} + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum PriorityLevel { + Low, + Medium, + High, + Urgent, +} + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct MaintenanceRecord { + pub record_id: u64, + pub asset_id: u64, + pub maintenance_type: MaintenanceType, + pub provider: Address, + pub technician_id: String, + pub service_date: u64, + pub duration_hours: u32, + pub description: String, + pub parts_replaced: Vec, + pub labor_cost: i128, + pub parts_cost: i128, + pub total_cost: i128, + pub location: String, + pub condition_before: u32, // 1-10 + pub condition_after: u32, // 1-10 + pub issues_found: String, + pub issues_resolved: String, + pub next_recommendation: String, + pub documents_ipfs: Vec, + pub quality_rating: u32, // 1-10 + pub timestamp: u64, +} + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ScheduledMaintenance { + pub asset_id: u64, + pub maintenance_type: MaintenanceType, + pub frequency_days: u32, + pub last_service_date: u64, + pub next_service_due: u64, + pub provider_assigned: Address, + pub reminder_days: u32, + pub auto_schedule: bool, + pub priority: PriorityLevel, + pub estimated_cost: i128, + pub estimated_duration: u32, + pub required_parts: Vec, + pub special_instructions: String, +} + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ProviderProfile { + pub address: Address, + pub name: String, + pub specialization: Vec, + pub certification_details: String, + pub total_services: u32, + pub average_rating: u32, // scaled by 100 or something if fractional, but requirement says 1-10 + pub registration_timestamp: u64, + pub is_active: bool, + pub contact_hash: String, + pub service_area: String, +} + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct WarrantyInfo { + pub asset_id: u64, + pub provider: String, + pub warranty_type: String, // Manufacturer, Extended, Third-party + pub start_date: u64, + pub end_date: u64, + pub coverage_details: String, + pub terms_hash: String, + pub claim_count: u32, + pub max_claims: u32, + pub status: WarrantyStatus, + pub is_transferable: bool, +} + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct MaintenanceAlert { + pub asset_id: u64, + pub alert_type: AlertType, + pub severity: AlertSeverity, + pub message: String, + pub due_date: u64, + pub acknowledged: bool, + pub acknowledged_by: Address, + pub created_at: u64, +} + +#[contracttype] +pub enum DataKey { + Admin, + AssetRegistry, + Provider(Address), + MaintenanceHistory(u64), // asset_id -> Vec + MaintenanceSchedule(u64), // asset_id -> ScheduledMaintenance + Warranty(u64), // asset_id -> WarrantyInfo + Alerts(u64), // asset_id -> Vec + AssetStats(u64), // asset_id -> AssetStats (downtime, total cost, etc.) +} + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AssetStats { + pub total_cost: i128, + pub total_downtime_hours: u64, + pub service_count: u32, + pub health_score: u32, // 1-100 +} + +#[contract] +pub struct AssetMaintenanceContract; + +#[contractimpl] +impl AssetMaintenanceContract { + pub fn init(env: Env, admin: Address, registry: Address) { + if env.storage().persistent().has(&DataKey::Admin) { + panic!("already initialized"); + } + env.storage().persistent().set(&DataKey::Admin, &admin); + env.storage() + .persistent() + .set(&DataKey::AssetRegistry, ®istry); + } + + pub fn register_provider(env: Env, provider: ProviderProfile) { + let admin: Address = env.storage().persistent().get(&DataKey::Admin).unwrap(); + admin.require_auth(); + + env.storage() + .persistent() + .set(&DataKey::Provider(provider.address.clone()), &provider); + } + + pub fn deactivate_provider(env: Env, provider_address: Address) { + let admin: Address = env.storage().persistent().get(&DataKey::Admin).unwrap(); + admin.require_auth(); + + if let Some(mut provider) = env + .storage() + .persistent() + .get::<_, ProviderProfile>(&DataKey::Provider(provider_address.clone())) + { + provider.is_active = false; + env.storage() + .persistent() + .set(&DataKey::Provider(provider_address), &provider); + } + } + + pub fn add_maintenance_record(env: Env, record: MaintenanceRecord) { + // Auth check: provider must be the one adding the record + record.provider.require_auth(); + + // 1. Verify provider is registered and active + let provider_data: ProviderProfile = env + .storage() + .persistent() + .get(&DataKey::Provider(record.provider.clone())) + .expect("provider not registered"); + if !provider_data.is_active { + panic!("provider is inactive"); + } + + // 2. Validation Rules + if record.service_date > env.ledger().timestamp() { + panic!("service date cannot be in future"); + } + if record.labor_cost < 0 || record.parts_cost < 0 || record.total_cost < 0 { + panic!("cost values must be non-negative"); + } + if record.labor_cost + record.parts_cost != record.total_cost { + panic!("labor + parts cost must equal total cost"); + } + if record.condition_before < 1 + || record.condition_before > 10 + || record.condition_after < 1 + || record.condition_after > 10 + { + panic!("condition ratings must be 1-10"); + } + if record.quality_rating < 1 || record.quality_rating > 10 { + panic!("quality rating must be 1-10"); + } + + // 3. Verify asset exists + if !Self::verify_asset_exists(&env, record.asset_id) { + panic!("asset does not exist"); + } + + // 4. Update Maintenance History + let mut history = env + .storage() + .persistent() + .get::<_, Vec>(&DataKey::MaintenanceHistory(record.asset_id)) + .unwrap_or(Vec::new(&env)); + history.push_back(record.clone()); + env.storage() + .persistent() + .set(&DataKey::MaintenanceHistory(record.asset_id), &history); + + // 5. Update Asset Stats + let mut stats = env + .storage() + .persistent() + .get::<_, AssetStats>(&DataKey::AssetStats(record.asset_id)) + .unwrap_or(AssetStats { + total_cost: 0, + total_downtime_hours: 0, + service_count: 0, + health_score: 100, // Start with 100 + }); + + stats.total_cost += record.total_cost; + stats.total_downtime_hours += record.duration_hours as u64; + stats.service_count += 1; + // Recalculate health score (placeholder for now, will implement properly later) + stats.health_score = Self::calculate_health_score(&env, record.asset_id); + + env.storage() + .persistent() + .set(&DataKey::AssetStats(record.asset_id), &stats); + + // 6. Emit Event + env.events().publish( + (symbol_short!("MaintRec"), record.asset_id), + (record.record_id, record.provider, env.ledger().timestamp()), + ); + } + + pub fn get_maintenance_history(env: Env, asset_id: u64) -> Vec { + env.storage() + .persistent() + .get(&DataKey::MaintenanceHistory(asset_id)) + .unwrap_or(Vec::new(&env)) + } + + pub fn schedule_maintenance(env: Env, owner: Address, schedule: ScheduledMaintenance) { + owner.require_auth(); + // Asset owner check (placeholder - assuming caller is owner or admin) + // In a real system, we'd check if owner is truly the owner via Registry + if schedule.frequency_days == 0 { + panic!("frequency must be positive"); + } + + env.storage() + .persistent() + .set(&DataKey::MaintenanceSchedule(schedule.asset_id), &schedule); + + env.events().publish( + (symbol_short!("MaintSch"), schedule.asset_id), + (schedule.next_service_due, env.ledger().timestamp()), + ); + } + + pub fn update_maintenance_schedule(env: Env, owner: Address, schedule: ScheduledMaintenance) { + // Update existing schedule + if !env + .storage() + .persistent() + .has(&DataKey::MaintenanceSchedule(schedule.asset_id)) + { + panic!("no schedule exists for asset"); + } + Self::schedule_maintenance(env, owner, schedule); + } + + pub fn get_upcoming_maintenance(env: Env, asset_id: u64) -> Option { + env.storage() + .persistent() + .get(&DataKey::MaintenanceSchedule(asset_id)) + } + + pub fn complete_scheduled_maintenance(env: Env, asset_id: u64, record: MaintenanceRecord) { + // 1. Add record + Self::add_maintenance_record(env.clone(), record.clone()); + + // 2. Update schedule if auto-schedule is on + if let Some(mut schedule) = env + .storage() + .persistent() + .get::<_, ScheduledMaintenance>(&DataKey::MaintenanceSchedule(asset_id)) + { + if schedule.auto_schedule { + schedule.last_service_date = record.service_date; + schedule.next_service_due = + record.service_date + (schedule.frequency_days as u64 * 86400); + env.storage() + .persistent() + .set(&DataKey::MaintenanceSchedule(asset_id), &schedule); + } + } + + env.events().publish( + (symbol_short!("MaintCmp"), asset_id), + (record.record_id, record.provider, env.ledger().timestamp()), + ); + } + + pub fn add_warranty_information(env: Env, warranty: WarrantyInfo) { + if warranty.end_date <= warranty.start_date { + panic!("warranty dates invalid"); + } + env.storage() + .persistent() + .set(&DataKey::Warranty(warranty.asset_id), &warranty); + + env.events().publish( + (symbol_short!("WarrAdd"), warranty.asset_id), + (warranty.end_date, env.ledger().timestamp()), + ); + } + + pub fn update_warranty_information(env: Env, warranty: WarrantyInfo) { + if !env + .storage() + .persistent() + .has(&DataKey::Warranty(warranty.asset_id)) + { + panic!("no warranty exists for asset"); + } + Self::add_warranty_information(env, warranty); + } + + pub fn get_provider_details(env: Env, provider_address: Address) -> Option { + env.storage() + .persistent() + .get(&DataKey::Provider(provider_address)) + } + + pub fn get_warranty(env: Env, asset_id: u64) -> Option { + env.storage().persistent().get(&DataKey::Warranty(asset_id)) + } + + pub fn file_warranty_claim(env: Env, asset_id: u64, claim_amount: i128) { + let mut warranty: WarrantyInfo = env + .storage() + .persistent() + .get(&DataKey::Warranty(asset_id)) + .expect("no warranty found"); + + if warranty.status != WarrantyStatus::Active { + panic!("warranty is not active"); + } + if env.ledger().timestamp() > warranty.end_date { + panic!("warranty has expired"); + } + if warranty.claim_count >= warranty.max_claims { + panic!("max claims reached"); + } + + warranty.claim_count += 1; + env.storage() + .persistent() + .set(&DataKey::Warranty(asset_id), &warranty); + + env.events().publish( + (symbol_short!("WarrClm"), asset_id), + (claim_amount, env.ledger().timestamp()), + ); + } + + pub fn create_maintenance_alert(env: Env, alert: MaintenanceAlert) { + let mut alerts = env + .storage() + .persistent() + .get::<_, Vec>(&DataKey::Alerts(alert.asset_id)) + .unwrap_or(Vec::new(&env)); + alerts.push_back(alert.clone()); + env.storage() + .persistent() + .set(&DataKey::Alerts(alert.asset_id), &alerts); + + env.events().publish( + (symbol_short!("AlertCr"), alert.asset_id), + (alert.alert_type, alert.severity, env.ledger().timestamp()), + ); + } + + pub fn acknowledge_maintenance_alert(env: Env, asset_id: u64, alert_index: u32, by: Address) { + by.require_auth(); + let mut alerts: Vec = env + .storage() + .persistent() + .get(&DataKey::Alerts(asset_id)) + .expect("no alerts found"); + + if let Some(mut alert) = alerts.get(alert_index) { + alert.acknowledged = true; + alert.acknowledged_by = by; + alerts.set(alert_index, alert); + env.storage() + .persistent() + .set(&DataKey::Alerts(asset_id), &alerts); + } + } + + pub fn get_alerts(env: Env, asset_id: u64) -> Vec { + env.storage() + .persistent() + .get(&DataKey::Alerts(asset_id)) + .unwrap_or(Vec::new(&env)) + } + + pub fn calculate_total_maintenance_cost(env: Env, asset_id: u64) -> i128 { + let stats = Self::get_asset_stats(env, asset_id); + stats.total_cost + } + + pub fn calculate_asset_downtime(env: Env, asset_id: u64) -> u64 { + let stats = Self::get_asset_stats(env, asset_id); + stats.total_downtime_hours + } + + pub fn get_asset_health_score(env: Env, asset_id: u64) -> u32 { + let stats = Self::get_asset_stats(env, asset_id); + stats.health_score + } + + pub fn get_asset_stats(env: Env, asset_id: u64) -> AssetStats { + env.storage() + .persistent() + .get(&DataKey::AssetStats(asset_id)) + .unwrap_or(AssetStats { + total_cost: 0, + total_downtime_hours: 0, + service_count: 0, + health_score: 100, + }) + } + + pub fn is_maintenance_cost_excessive(env: Env, asset_id: u64, threshold: i128) -> bool { + let stats = Self::get_asset_stats(env, asset_id); + stats.total_cost > threshold + } + + pub fn get_overdue_maintenance(env: Env, asset_id: u64) -> bool { + if let Some(schedule) = env + .storage() + .persistent() + .get::<_, ScheduledMaintenance>(&DataKey::MaintenanceSchedule(asset_id)) + { + return env.ledger().timestamp() > schedule.next_service_due; + } + false + } + + fn calculate_health_score(env: &Env, asset_id: u64) -> u32 { + let history = env + .storage() + .persistent() + .get::<_, Vec>(&DataKey::MaintenanceHistory(asset_id)) + .unwrap_or(Vec::new(env)); + + if history.is_empty() { + return 100; + } + + let mut total_quality = 0; + let mut improvement_score = 0; + let mut preventive_count = 0; + + for record in history.iter() { + total_quality += record.quality_rating; + if record.condition_after > record.condition_before { + improvement_score += 5; + } + if let MaintenanceType::Preventive = record.maintenance_type { + preventive_count += 1; + } + } + + let avg_quality = (total_quality * 10) / history.len(); // Scale to 100 + let preventive_ratio = (preventive_count * 100) / history.len(); + + // Weighted Score: 40% Quality, 30% Preventive Ratio, 30% Improvement/Condition + let mut score = (avg_quality * 4 / 10) + (preventive_ratio * 3 / 10) + (improvement_score); + + // Penalty for overdue + if let Some(schedule) = env + .storage() + .persistent() + .get::<_, ScheduledMaintenance>(&DataKey::MaintenanceSchedule(asset_id)) + { + if env.ledger().timestamp() > schedule.next_service_due { + let days_overdue = (env.ledger().timestamp() - schedule.next_service_due) / 86400; + let penalty = (days_overdue as u32 * 2).min(30); + score = score.saturating_sub(penalty); + } + } + + score.min(100).max(0) + } + + fn verify_asset_exists(_env: &Env, _asset_id: u64) -> bool { + true + } +} diff --git a/contracts/asset-maintenance/src/test.rs b/contracts/asset-maintenance/src/test.rs new file mode 100644 index 0000000..ff3e32c --- /dev/null +++ b/contracts/asset-maintenance/src/test.rs @@ -0,0 +1,182 @@ +#![cfg(test)] +extern crate std; + +use super::*; +use soroban_sdk::testutils::Address as _; +use soroban_sdk::{vec, Address, Env, String}; + +#[test] +fn test_init_and_provider_registration() { + let env = Env::default(); + let contract_id = env.register_contract(None, AssetMaintenanceContract); + let client = AssetMaintenanceContractClient::new(&env, &contract_id); + + let admin = Address::generate(&env); + let registry = Address::generate(&env); + + client.init(&admin, ®istry); + + let provider_addr = Address::generate(&env); + let provider = ProviderProfile { + address: provider_addr.clone(), + name: String::from_str(&env, "Service Corp"), + specialization: vec![&env, String::from_str(&env, "Engines")], + certification_details: String::from_str(&env, "ISO9001"), + total_services: 0, + average_rating: 0, + registration_timestamp: env.ledger().timestamp(), + is_active: true, + contact_hash: String::from_str(&env, "hash"), + service_area: String::from_str(&env, "Global"), + }; + + env.mock_all_auths(); + client.register_provider(&provider); + + let fetched = client.get_provider_details(&provider_addr).unwrap(); + assert_eq!(fetched.name, String::from_str(&env, "Service Corp")); + assert_eq!(fetched.is_active, true); + + client.deactivate_provider(&provider_addr); + let deactivated = client.get_provider_details(&provider_addr).unwrap(); + assert_eq!(deactivated.is_active, false); +} + +#[test] +fn test_maintenance_lifecycle() { + let env = Env::default(); + env.mock_all_auths(); + + let contract_id = env.register_contract(None, AssetMaintenanceContract); + let client = AssetMaintenanceContractClient::new(&env, &contract_id); + + let admin = Address::generate(&env); + let registry = Address::generate(&env); + client.init(&admin, ®istry); + + let provider_addr = Address::generate(&env); + let provider = ProviderProfile { + address: provider_addr.clone(), + name: String::from_str(&env, "Service Corp"), + specialization: vec![&env, String::from_str(&env, "Engines")], + certification_details: String::from_str(&env, "ISO9001"), + total_services: 0, + average_rating: 0, + registration_timestamp: env.ledger().timestamp(), + is_active: true, + contact_hash: String::from_str(&env, "hash"), + service_area: String::from_str(&env, "Global"), + }; + client.register_provider(&provider); + + let asset_id = 101u64; + let record = MaintenanceRecord { + record_id: 1, + asset_id, + maintenance_type: MaintenanceType::Preventive, + provider: provider_addr.clone(), + technician_id: String::from_str(&env, "TECH-01"), + service_date: env.ledger().timestamp(), + duration_hours: 4, + description: String::from_str(&env, "Regular Checkup"), + parts_replaced: vec![&env, String::from_str(&env, "Filter")], + labor_cost: 100, + parts_cost: 50, + total_cost: 150, + location: String::from_str(&env, "Main Shop"), + condition_before: 7, + condition_after: 9, + issues_found: String::from_str(&env, "None"), + issues_resolved: String::from_str(&env, "N/A"), + next_recommendation: String::from_str(&env, "Check in 6 months"), + documents_ipfs: vec![&env, String::from_str(&env, "ipfs://abc")], + quality_rating: 10, + timestamp: env.ledger().timestamp(), + }; + + client.add_maintenance_record(&record); + + let history = client.get_maintenance_history(&asset_id); + assert_eq!(history.len(), 1); + assert_eq!(history.get(0).unwrap().total_cost, 150); + + let health = client.get_asset_health_score(&asset_id); + // Based on our algorithm: avg_quality(100) * 0.4 + preventive_ratio(100) * 0.3 + improvement(5) = 40+30+5 = 75? + // Wait: avg_quality scaling: (10*10)/1 = 100. preventive_ratio: (1*100)/1 = 100. improvement_score = 5. + // score = (100*4/10) + (100*3/10) + 5 = 40 + 30 + 5 = 75. + assert_eq!(health, 75); +} + +#[test] +fn test_warranty_and_claims() { + let env = Env::default(); + env.mock_all_auths(); + + let contract_id = env.register_contract(None, AssetMaintenanceContract); + let client = AssetMaintenanceContractClient::new(&env, &contract_id); + + let admin = Address::generate(&env); + let registry = Address::generate(&env); + client.init(&admin, ®istry); + + let asset_id = 102u64; + let warranty = WarrantyInfo { + asset_id, + provider: String::from_str(&env, "OEM"), + warranty_type: String::from_str(&env, "Manufacturer"), + start_date: env.ledger().timestamp(), + end_date: env.ledger().timestamp() + 31536000, // 1 year + coverage_details: String::from_str(&env, "Full"), + terms_hash: String::from_str(&env, "hash"), + claim_count: 0, + max_claims: 2, + status: WarrantyStatus::Active, + is_transferable: true, + }; + + client.add_warranty_information(&warranty); + client.file_warranty_claim(&asset_id, &500); + + // Verify claim count + // (We don't have a get_warranty yet, but we can add it or check if it throws error for 3rd claim) + client.file_warranty_claim(&asset_id, &300); +} + +#[test] +fn test_alerts_and_stats() { + let env = Env::default(); + env.mock_all_auths(); + + let contract_id = env.register_contract(None, AssetMaintenanceContract); + let client = AssetMaintenanceContractClient::new(&env, &contract_id); + + let admin = Address::generate(&env); + let registry = Address::generate(&env); + client.init(&admin, ®istry); + + let asset_id = 103u64; + let alert = MaintenanceAlert { + asset_id, + alert_type: AlertType::ServiceDue, + severity: AlertSeverity::High, + message: String::from_str(&env, "Service due soon"), + due_date: env.ledger().timestamp() + 86400, + acknowledged: false, + acknowledged_by: admin.clone(), // Doesn't matter for initial state + created_at: env.ledger().timestamp(), + }; + + client.create_maintenance_alert(&alert); + let alerts = client.get_alerts(&asset_id); + assert_eq!(alerts.len(), 1); + + client.acknowledge_maintenance_alert(&asset_id, &0, &admin); + let acknowledged_alerts = client.get_alerts(&asset_id); + assert_eq!(acknowledged_alerts.get(0).unwrap().acknowledged, true); + + // Test stats + let stats = client.get_asset_stats(&asset_id); + assert_eq!(stats.service_count, 0); // No service yet + + assert_eq!(client.is_maintenance_cost_excessive(&asset_id, &1000), false); +} diff --git a/contracts/asset-maintenance/test_snapshots/test/test_alerts_and_stats.1.json b/contracts/asset-maintenance/test_snapshots/test/test_alerts_and_stats.1.json new file mode 100644 index 0000000..18fe594 --- /dev/null +++ b/contracts/asset-maintenance/test_snapshots/test/test_alerts_and_stats.1.json @@ -0,0 +1,339 @@ +{ + "generators": { + "address": 3, + "nonce": 0 + }, + "auth": [ + [], + [], + [], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "acknowledge_maintenance_alert", + "args": [ + { + "u64": 103 + }, + { + "u32": 0 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [], + [] + ], + "ledger": { + "protocol_version": 22, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "durability": "persistent", + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "Alerts" + }, + { + "u64": 103 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "Alerts" + }, + { + "u64": 103 + } + ] + }, + "durability": "persistent", + "val": { + "vec": [ + { + "map": [ + { + "key": { + "symbol": "acknowledged" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "acknowledged_by" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "alert_type" + }, + "val": { + "vec": [ + { + "symbol": "ServiceDue" + } + ] + } + }, + { + "key": { + "symbol": "asset_id" + }, + "val": { + "u64": 103 + } + }, + { + "key": { + "symbol": "created_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "due_date" + }, + "val": { + "u64": 86400 + } + }, + { + "key": { + "symbol": "message" + }, + "val": { + "string": "Service due soon" + } + }, + { + "key": { + "symbol": "severity" + }, + "val": { + "vec": [ + { + "symbol": "High" + } + ] + } + } + ] + } + ] + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "AssetRegistry" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "AssetRegistry" + } + ] + }, + "durability": "persistent", + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": null + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/asset-maintenance/test_snapshots/test/test_init_and_provider_registration.1.json b/contracts/asset-maintenance/test_snapshots/test/test_init_and_provider_registration.1.json new file mode 100644 index 0000000..b9e6056 --- /dev/null +++ b/contracts/asset-maintenance/test_snapshots/test/test_init_and_provider_registration.1.json @@ -0,0 +1,475 @@ +{ + "generators": { + "address": 4, + "nonce": 0 + }, + "auth": [ + [], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "register_provider", + "args": [ + { + "map": [ + { + "key": { + "symbol": "address" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + }, + { + "key": { + "symbol": "average_rating" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "certification_details" + }, + "val": { + "string": "ISO9001" + } + }, + { + "key": { + "symbol": "contact_hash" + }, + "val": { + "string": "hash" + } + }, + { + "key": { + "symbol": "is_active" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "Service Corp" + } + }, + { + "key": { + "symbol": "registration_timestamp" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "service_area" + }, + "val": { + "string": "Global" + } + }, + { + "key": { + "symbol": "specialization" + }, + "val": { + "vec": [ + { + "string": "Engines" + } + ] + } + }, + { + "key": { + "symbol": "total_services" + }, + "val": { + "u32": 0 + } + } + ] + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "deactivate_provider", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 22, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "durability": "persistent", + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "AssetRegistry" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "AssetRegistry" + } + ] + }, + "durability": "persistent", + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "Provider" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "Provider" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "address" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + }, + { + "key": { + "symbol": "average_rating" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "certification_details" + }, + "val": { + "string": "ISO9001" + } + }, + { + "key": { + "symbol": "contact_hash" + }, + "val": { + "string": "hash" + } + }, + { + "key": { + "symbol": "is_active" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "Service Corp" + } + }, + { + "key": { + "symbol": "registration_timestamp" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "service_area" + }, + "val": { + "string": "Global" + } + }, + { + "key": { + "symbol": "specialization" + }, + "val": { + "vec": [ + { + "string": "Engines" + } + ] + } + }, + { + "key": { + "symbol": "total_services" + }, + "val": { + "u32": 0 + } + } + ] + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": null + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/asset-maintenance/test_snapshots/test/test_maintenance_lifecycle.1.json b/contracts/asset-maintenance/test_snapshots/test/test_maintenance_lifecycle.1.json new file mode 100644 index 0000000..d213fed --- /dev/null +++ b/contracts/asset-maintenance/test_snapshots/test/test_maintenance_lifecycle.1.json @@ -0,0 +1,985 @@ +{ + "generators": { + "address": 4, + "nonce": 0 + }, + "auth": [ + [], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "register_provider", + "args": [ + { + "map": [ + { + "key": { + "symbol": "address" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + }, + { + "key": { + "symbol": "average_rating" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "certification_details" + }, + "val": { + "string": "ISO9001" + } + }, + { + "key": { + "symbol": "contact_hash" + }, + "val": { + "string": "hash" + } + }, + { + "key": { + "symbol": "is_active" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "Service Corp" + } + }, + { + "key": { + "symbol": "registration_timestamp" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "service_area" + }, + "val": { + "string": "Global" + } + }, + { + "key": { + "symbol": "specialization" + }, + "val": { + "vec": [ + { + "string": "Engines" + } + ] + } + }, + { + "key": { + "symbol": "total_services" + }, + "val": { + "u32": 0 + } + } + ] + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "add_maintenance_record", + "args": [ + { + "map": [ + { + "key": { + "symbol": "asset_id" + }, + "val": { + "u64": 101 + } + }, + { + "key": { + "symbol": "condition_after" + }, + "val": { + "u32": 9 + } + }, + { + "key": { + "symbol": "condition_before" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "description" + }, + "val": { + "string": "Regular Checkup" + } + }, + { + "key": { + "symbol": "documents_ipfs" + }, + "val": { + "vec": [ + { + "string": "ipfs://abc" + } + ] + } + }, + { + "key": { + "symbol": "duration_hours" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "symbol": "issues_found" + }, + "val": { + "string": "None" + } + }, + { + "key": { + "symbol": "issues_resolved" + }, + "val": { + "string": "N/A" + } + }, + { + "key": { + "symbol": "labor_cost" + }, + "val": { + "i128": { + "hi": 0, + "lo": 100 + } + } + }, + { + "key": { + "symbol": "location" + }, + "val": { + "string": "Main Shop" + } + }, + { + "key": { + "symbol": "maintenance_type" + }, + "val": { + "vec": [ + { + "symbol": "Preventive" + } + ] + } + }, + { + "key": { + "symbol": "next_recommendation" + }, + "val": { + "string": "Check in 6 months" + } + }, + { + "key": { + "symbol": "parts_cost" + }, + "val": { + "i128": { + "hi": 0, + "lo": 50 + } + } + }, + { + "key": { + "symbol": "parts_replaced" + }, + "val": { + "vec": [ + { + "string": "Filter" + } + ] + } + }, + { + "key": { + "symbol": "provider" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + }, + { + "key": { + "symbol": "quality_rating" + }, + "val": { + "u32": 10 + } + }, + { + "key": { + "symbol": "record_id" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "service_date" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "technician_id" + }, + "val": { + "string": "TECH-01" + } + }, + { + "key": { + "symbol": "timestamp" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "total_cost" + }, + "val": { + "i128": { + "hi": 0, + "lo": 150 + } + } + } + ] + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [] + ], + "ledger": { + "protocol_version": 22, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "durability": "persistent", + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "AssetRegistry" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "AssetRegistry" + } + ] + }, + "durability": "persistent", + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "AssetStats" + }, + { + "u64": 101 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "AssetStats" + }, + { + "u64": 101 + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "health_score" + }, + "val": { + "u32": 75 + } + }, + { + "key": { + "symbol": "service_count" + }, + "val": { + "u32": 1 + } + }, + { + "key": { + "symbol": "total_cost" + }, + "val": { + "i128": { + "hi": 0, + "lo": 150 + } + } + }, + { + "key": { + "symbol": "total_downtime_hours" + }, + "val": { + "u64": 4 + } + } + ] + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "MaintenanceHistory" + }, + { + "u64": 101 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "MaintenanceHistory" + }, + { + "u64": 101 + } + ] + }, + "durability": "persistent", + "val": { + "vec": [ + { + "map": [ + { + "key": { + "symbol": "asset_id" + }, + "val": { + "u64": 101 + } + }, + { + "key": { + "symbol": "condition_after" + }, + "val": { + "u32": 9 + } + }, + { + "key": { + "symbol": "condition_before" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "description" + }, + "val": { + "string": "Regular Checkup" + } + }, + { + "key": { + "symbol": "documents_ipfs" + }, + "val": { + "vec": [ + { + "string": "ipfs://abc" + } + ] + } + }, + { + "key": { + "symbol": "duration_hours" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "symbol": "issues_found" + }, + "val": { + "string": "None" + } + }, + { + "key": { + "symbol": "issues_resolved" + }, + "val": { + "string": "N/A" + } + }, + { + "key": { + "symbol": "labor_cost" + }, + "val": { + "i128": { + "hi": 0, + "lo": 100 + } + } + }, + { + "key": { + "symbol": "location" + }, + "val": { + "string": "Main Shop" + } + }, + { + "key": { + "symbol": "maintenance_type" + }, + "val": { + "vec": [ + { + "symbol": "Preventive" + } + ] + } + }, + { + "key": { + "symbol": "next_recommendation" + }, + "val": { + "string": "Check in 6 months" + } + }, + { + "key": { + "symbol": "parts_cost" + }, + "val": { + "i128": { + "hi": 0, + "lo": 50 + } + } + }, + { + "key": { + "symbol": "parts_replaced" + }, + "val": { + "vec": [ + { + "string": "Filter" + } + ] + } + }, + { + "key": { + "symbol": "provider" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + }, + { + "key": { + "symbol": "quality_rating" + }, + "val": { + "u32": 10 + } + }, + { + "key": { + "symbol": "record_id" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "service_date" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "technician_id" + }, + "val": { + "string": "TECH-01" + } + }, + { + "key": { + "symbol": "timestamp" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "total_cost" + }, + "val": { + "i128": { + "hi": 0, + "lo": 150 + } + } + } + ] + } + ] + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "Provider" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "Provider" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "address" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + }, + { + "key": { + "symbol": "average_rating" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "certification_details" + }, + "val": { + "string": "ISO9001" + } + }, + { + "key": { + "symbol": "contact_hash" + }, + "val": { + "string": "hash" + } + }, + { + "key": { + "symbol": "is_active" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "Service Corp" + } + }, + { + "key": { + "symbol": "registration_timestamp" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "service_area" + }, + "val": { + "string": "Global" + } + }, + { + "key": { + "symbol": "specialization" + }, + "val": { + "vec": [ + { + "string": "Engines" + } + ] + } + }, + { + "key": { + "symbol": "total_services" + }, + "val": { + "u32": 0 + } + } + ] + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": null + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/asset-maintenance/test_snapshots/test/test_warranty_and_claims.1.json b/contracts/asset-maintenance/test_snapshots/test/test_warranty_and_claims.1.json new file mode 100644 index 0000000..6ff456d --- /dev/null +++ b/contracts/asset-maintenance/test_snapshots/test/test_warranty_and_claims.1.json @@ -0,0 +1,329 @@ +{ + "generators": { + "address": 3, + "nonce": 0 + }, + "auth": [ + [], + [], + [], + [], + [] + ], + "ledger": { + "protocol_version": 22, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "durability": "persistent", + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "AssetRegistry" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "AssetRegistry" + } + ] + }, + "durability": "persistent", + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "Warranty" + }, + { + "u64": 102 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "Warranty" + }, + { + "u64": 102 + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "asset_id" + }, + "val": { + "u64": 102 + } + }, + { + "key": { + "symbol": "claim_count" + }, + "val": { + "u32": 2 + } + }, + { + "key": { + "symbol": "coverage_details" + }, + "val": { + "string": "Full" + } + }, + { + "key": { + "symbol": "end_date" + }, + "val": { + "u64": 31536000 + } + }, + { + "key": { + "symbol": "is_transferable" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "max_claims" + }, + "val": { + "u32": 2 + } + }, + { + "key": { + "symbol": "provider" + }, + "val": { + "string": "OEM" + } + }, + { + "key": { + "symbol": "start_date" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "status" + }, + "val": { + "vec": [ + { + "symbol": "Active" + } + ] + } + }, + { + "key": { + "symbol": "terms_hash" + }, + "val": { + "string": "hash" + } + }, + { + "key": { + "symbol": "warranty_type" + }, + "val": { + "string": "Manufacturer" + } + } + ] + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": null + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [ + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "WarrClm" + }, + { + "u64": 102 + } + ], + "data": { + "vec": [ + { + "i128": { + "hi": 0, + "lo": 300 + } + }, + { + "u64": 0 + } + ] + } + } + } + }, + "failed_call": false + } + ] +} \ No newline at end of file