///|
pub struct MaintenancePlan {
asset_id : String
interval_days : Int
last_service_day : Int
next_service_day : Int
runtime_hours : Double
runtime_limit : Double
open_actions : Int
status : String
} derive(Debug, ToJson)
///|
pub fn maintenance_plan(
asset_id~ : String,
interval_days~ : Int,
last_service_day~ : Int,
runtime_hours~ : Double,
runtime_limit~ : Double,
open_actions~ : Int,
) -> MaintenancePlan {
{
asset_id,
interval_days: interval_days.max(1),
last_service_day,
next_service_day: last_service_day + interval_days.max(1),
runtime_hours,
runtime_limit,
open_actions: open_actions.max(0),
status: "scheduled",
}
}
///|
pub fn maintenance_due(plan : MaintenancePlan, current_day : Int) -> Bool {
current_day >= plan.next_service_day ||
plan.runtime_hours >= plan.runtime_limit
}
///|
pub fn maintenance_overdue_days(
plan : MaintenancePlan,
current_day : Int,
) -> Int {
(current_day - plan.next_service_day).max(0)
}
///|
pub fn maintenance_runtime_margin(plan : MaintenancePlan) -> Double {
plan.runtime_limit - plan.runtime_hours
}
///|
pub fn maintenance_risk(plan : MaintenancePlan) -> String {
if plan.open_actions > 0 || maintenance_runtime_margin(plan) <= 0.0 {
"critical"
} else if maintenance_runtime_margin(plan) < plan.runtime_limit * 0.2 {
"watch"
} else {
"normal"
}
}
///|
pub fn record_service(
plan : MaintenancePlan,
service_day : Int,
runtime_hours : Double,
) -> MaintenancePlan {
{
..plan,
last_service_day: service_day,
next_service_day: service_day + plan.interval_days,
runtime_hours,
open_actions: 0,
status: "scheduled",
}
}
///|
pub fn add_maintenance_action(plan : MaintenancePlan) -> MaintenancePlan {
{ ..plan, open_actions: plan.open_actions + 1, status: "action_required" }
}
///|
pub fn maintenance_action_count(plans : Array[MaintenancePlan]) -> Int {
let mut count = 0
for plan in plans {
count += plan.open_actions
}
count
}
///|
pub fn due_maintenance_count(
plans : Array[MaintenancePlan],
current_day : Int,
) -> Int {
let mut count = 0
for plan in plans {
if maintenance_due(plan, current_day) {
count += 1
}
}
count
}
///|
pub fn critical_maintenance_count(plans : Array[MaintenancePlan]) -> Int {
let mut count = 0
for plan in plans {
if maintenance_risk(plan) == "critical" {
count += 1
}
}
count
}
///|
pub fn plans_for_asset(
plans : Array[MaintenancePlan],
asset_id : String,
) -> Array[MaintenancePlan] {
let result : Array[MaintenancePlan] = []
for plan in plans {
if plan.asset_id == asset_id {
result.push(plan)
}
}
result
}
///|
pub fn maintenance_compliance(
plans : Array[MaintenancePlan],
current_day : Int,
) -> Double {
if plans.length() == 0 {
1.0
} else {
(plans.length() - due_maintenance_count(plans, current_day)).to_double() /
plans.length().to_double()
}
}
///|
pub fn maintenance_runtime_utilization(plan : MaintenancePlan) -> Double {
if plan.runtime_limit <= 0.0 {
0.0
} else {
plan.runtime_hours / plan.runtime_limit
}
}
///|
pub fn maintenance_priority(
plan : MaintenancePlan,
current_day : Int,
) -> Double {
let overdue = maintenance_overdue_days(plan, current_day).to_double()
overdue +
plan.open_actions.to_double() * 2.0 +
maintenance_runtime_utilization(plan)
}
///|
pub fn sort_maintenance_plans(
plans : Array[MaintenancePlan],
current_day : Int,
) -> Array[MaintenancePlan] {
let result = plans.copy()
result.sort_by(fn(a, b) {
if maintenance_priority(a, current_day) >
maintenance_priority(b, current_day) {
-1
} else {
1
}
})
result
}
///|
pub fn maintenance_status_counts(plans : Array[MaintenancePlan]) -> Array[Int] {
let scheduled = 0
let action = 0
let critical = 0
let mut s = scheduled
let mut a = action
let mut c = critical
for plan in plans {
if plan.status == "scheduled" {
s += 1
}
if plan.status == "action_required" {
a += 1
}
if maintenance_risk(plan) == "critical" {
c += 1
}
}
[s, a, c]
}
///|
pub fn planned_service_days(plans : Array[MaintenancePlan]) -> Array[Int] {
let result : Array[Int] = []
for plan in plans {
result.push(plan.next_service_day)
}
result
}