///|
/// A component of a kit. The item can name a part or another kit.
pub(all) struct ItemNeed {
item : String
quantity : Int32
}
///|
/// A vendor's fixed size pack, priced in cents in the manifest's currency.
pub(all) struct PackOption {
id : String
quantity : Int32
cost_cents : Int32
}
///|
pub(all) struct Part {
id : String
stock : Int32
packs : Array[PackOption]
}
///|
pub(all) struct Kit {
id : String
items : Array[ItemNeed]
}
///|
pub(all) struct Order {
id : String
kit : String
quantity : Int32
}
///|
/// An inventory snapshot and orders in descending priority.
pub(all) struct Manifest {
parts : Array[Part]
kits : Array[Kit]
orders : Array[Order]
}
///|
pub(all) struct PartIssue {
part : String
units_per_kit : Int32
available_before : Int32
required : Int32
issued : Int32
limits_order : Bool
}
///|
pub(all) struct OrderPlan {
id : String
kit : String
requested : Int32
buildable : Int32
items : Array[PartIssue]
}
///|
pub(all) struct PartBalance {
part : String
stock : Int32
required : Int32
issued : Int32
remaining_stock : Int32
shortage : Int32
}
///|
pub(all) struct Allocation {
orders : Array[OrderPlan]
parts : Array[PartBalance]
}
///|
pub(all) struct PackCount {
id : String
quantity : Int32
count : Int32
unit_cost_cents : Int32
}
///|
pub(all) struct Purchase {
shortage : Int32
ordered : Int32
cost_cents : Int64
packs : Array[PackCount]
}
///|
/// A missing recommendation identifies a part with no purchasing options.
pub(all) struct PurchaseLine {
part : String
shortage : Int32
purchase : Purchase?
}
///|
pub(all) struct Plan {
allocation : Allocation
purchases : Array[PurchaseLine]
purchase_total_cents : Int64
purchase_complete : Bool
}
///|
pub(all) enum OutputFormat {
JsonReport
PickCsv
BuyCsv
}
///|
pub(all) suberror PlanError {
Invalid(String)
}
///|
let max_quantity : Int32 = 1_000_000
///|
fn id_alphanumeric(c : Char) -> Bool {
(c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')
}
///|
// This alphabet also keeps identifiers inert as cells in the CSV reports.
fn valid_id(id : String) -> Bool {
if id.length() < 1 || id.length() > 64 {
return false
}
for i, c in id {
if !id_alphanumeric(c) && (i == 0 || (c != '_' && c != '-' && c != '.')) {
return false
}
}
true
}