///|
pub struct MaterialLot {
material_id : String
lot_id : String
quantity : Double
reserved : Double
lower_limit : Double
upper_limit : Double
status : String
} derive(Debug, ToJson)
///|
pub fn material_lot(
material_id~ : String,
lot_id~ : String,
quantity~ : Double,
lower_limit~ : Double,
upper_limit~ : Double,
) -> MaterialLot {
{
material_id,
lot_id,
quantity,
reserved: 0.0,
lower_limit,
upper_limit,
status: "available",
}
}
///|
pub fn available_quantity(lot : MaterialLot) -> Double {
(lot.quantity - lot.reserved).max(0.0)
}
///|
pub fn reserve_material(lot : MaterialLot, amount : Double) -> MaterialLot {
let reserved = (lot.reserved + amount.max(0.0)).min(lot.quantity)
{
..lot,
reserved,
status: if reserved >= lot.quantity {
"reserved"
} else {
"available"
},
}
}
///|
pub fn consume_material(lot : MaterialLot, amount : Double) -> MaterialLot {
let quantity = (lot.quantity - amount.max(0.0)).max(0.0)
let reserved = lot.reserved.min(quantity)
{
..lot,
quantity,
reserved,
status: if quantity <= 0.0 {
"depleted"
} else {
"available"
},
}
}
///|
pub fn material_is_in_range(lot : MaterialLot, value : Double) -> Bool {
value >= lot.lower_limit && value <= lot.upper_limit
}
///|
pub fn stock_total(lots : Array[MaterialLot]) -> Double {
let mut total = 0.0
for lot in lots {
total += lot.quantity
}
total
}
///|
pub fn stock_available(lots : Array[MaterialLot]) -> Double {
let mut total = 0.0
for lot in lots {
total += available_quantity(lot)
}
total
}
///|
pub fn stock_reserved(lots : Array[MaterialLot]) -> Double {
let mut total = 0.0
for lot in lots {
total += lot.reserved
}
total
}
///|
pub fn lots_for_material(
lots : Array[MaterialLot],
material_id : String,
) -> Array[MaterialLot] {
let result : Array[MaterialLot] = []
for lot in lots {
if lot.material_id == material_id {
result.push(lot)
}
}
result
}
///|
pub fn depleted_lot_count(lots : Array[MaterialLot]) -> Int {
let mut count = 0
for lot in lots {
if lot.status == "depleted" {
count += 1
}
}
count
}
///|
pub fn inventory_utilization(lots : Array[MaterialLot]) -> Double {
let total = stock_total(lots)
if total <= 0.0 {
0.0
} else {
stock_reserved(lots) / total
}
}
///|
pub fn reorder_needed(
lots : Array[MaterialLot],
reorder_point : Double,
) -> Bool {
stock_available(lots) < reorder_point
}
///|
pub fn lot_age_bucket(days : Int) -> String {
if days < 0 {
"invalid"
} else if days <= 7 {
"fresh"
} else if days <= 30 {
"standard"
} else {
"aged"
}
}
///|
pub fn fifo_lots(lots : Array[MaterialLot]) -> Array[MaterialLot] {
let result = lots.copy()
result.sort_by(fn(a, b) { if a.lot_id < b.lot_id { -1 } else { 1 } })
result
}