- feature
- shop
- features
- shop-catalog, shop-suppliers, shop-customers, shop-orders, shop-paid, shop-cancelled
Shop: the model and its rules¶
Products in categories, the suppliers they come from, customers and their orders. When an order is paid its quantities come off stock; if a paid order is cancelled they go back.
$enum OrderStatus (new, paid, shipped, cancelled)
$class Category (
@key id: String,
@label name: String,
parent: <>Category?,
) @tooltip("A shelf in the shop; a category can sit inside another")
$class Supplier (
@key id: String,
@label name: String,
email: String?,
leadDays: Int = 7,
) @tooltip("Who we buy a product from")
$class Product (
@key sku: String,
@label name: String,
category: <>Category,
supplier: <>Supplier?,
price: Number,
cost: Number,
stock: Int = 0,
reorderAt: Int = 5,
@calc(price - cost) margin: Number,
@calc(stock <= reorderAt) low: Boolean,
) @tooltip("Something we sell")
$class Customer (
@key id: String,
@label name: String,
email: String?,
since: Date?,
) @tooltip("Someone who buys from us")
$class OrderLine (
product: <>Product,
qty: Int,
price: Number,
)
$class Order (
@key id: String,
placed: Date,
customer: <>Customer,
status: OrderStatus = new,
lines: OrderLine*,
stockTaken: Boolean = false,
@calc((lines ?? []) fold (acc = 0) (l => acc + l.qty * l.price)) total: Number,
) @tooltip("A customer's order: what they bought, and where it stands")
Rules¶
An order that is made or changed is checked: paid, and its stock not yet taken, takes it; cancelled after it was taken puts it back. stockTaken makes sure each happens once.
$when diesel.entity.on.created (category, key) if (category is "Order") {
shop.orderChanged (key = key)
}
$when diesel.entity.on.updated (category, key) if (category is "Order") {
shop.orderChanged (key = key)
}
$when shop.orderChanged (key: String) {
o = dom.find (cls = "Order", key = key)
lines = o.lines ?? []
if (o.status is "paid" and not (o.stockTaken ?? false)) {
if (sizeOf(lines) > 0) {
shop.restock (lines = lines, sign = -1)
}
dom.upsert (cls = "Order", entity = o + {stockTaken: true})
}
if (o.status is "cancelled" and (o.stockTaken ?? false)) {
if (sizeOf(lines) > 0) {
shop.restock (lines = lines, sign = 1)
}
dom.upsert (cls = "Order", entity = o + {stockTaken: false})
}
}
$when shop.restock (lines, sign: Int) {
l = lines[0]
p = dom.find (cls = "Product", key = l.product)
dom.upsert (cls = "Product", entity = p + {stock: p.stock + sign * l.qty})
rest = slice(x = lines, from = 1)
if (sizeOf(rest) > 0) {
shop.restock (lines = rest, sign = sign)
}
}