///|
pub(all) struct ProjectedOrder {
id : String
kit : String
requested : Int32
buildable_now : Int32
buildable_after_priced_purchases : Int32
}
///|
pub(all) struct Projection {
orders : Array[ProjectedOrder]
purchase_complete : Bool
purchase_total_cents : Int64
}
///|
/// Reallocate from the original stock plus all priced purchases, in the same
/// order priority. An earlier order that becomes buildable can leave fewer
/// parts for a later order. Unpriced shortages are never added to stock.
pub fn project_after_purchase(
manifest : Manifest,
) -> Projection raise PlanError {
let current = plan(manifest)
let purchased : Map[String, Int32] = Map([])
for line in current.purchases {
if line.purchase is Some(purchase) {
purchased[line.part] = purchase.ordered
}
}
let now = current.allocation.orders
let after = if purchased.is_empty() {
now
} else {
let parts = manifest.parts.map(part => {
let available = part.stock.to_int64() +
purchased.get(part.id).unwrap_or(0).to_int64()
// Total demand per part is already bounded by max_quantity. Additional
// surplus above that bound cannot affect any order's buildability.
let stock = if available > max_quantity.to_int64() {
max_quantity
} else {
available.to_int()
}
{ ..part, stock, }
})
allocate({ ..manifest, parts, }).orders
}
let orders : Array[ProjectedOrder] = []
for index, order in now {
orders.push({
id: order.id,
kit: order.kit,
requested: order.requested,
buildable_now: order.buildable,
buildable_after_priced_purchases: after[index].buildable,
})
}
{
orders,
purchase_complete: current.purchase_complete,
purchase_total_cents: current.purchase_total_cents,
}
}