Hello @dresvert!
We have a template that gets close to what you are describing: Restaurant Custom Orders - Grist.
- The top-left widget has orders. Select one to see the associated items.
- The bottom-left widget has items for the selected order. There is a count of each item.
- The bottom-right widget shows ingredients for the selected item. (These can be configured separately in the Menu Items page.)
- The hardest part is the formula in the top-right widget which collects all ingredients from all items for the selected order. The output looks like this:
Asparagus — 6 lb
Black Pepper (3 tsp) — 0.5 oz
Butter (104 tbsp) — 52 oz
Eggs — 69 EA
Flour — 4.55 lb
Goat Cheese (16.5 cup) — 132 oz
Heavy Cream (3.5 cup) — 28 oz
Milk (15.5 cup) — 0.97 G
Mushrooms (7 cup) — 56 oz
Olive Oil (20 tbsp) — 10 oz
Onions — 1.75 lb
Parsley — 1.5 lb
Salt (15.5 tsp) — 2.58 oz
Constructing this output takes some work.
Firstly, the relational structure is used to construct some Reference Lists – like you mention, but they are constructed using formulas.
- There is one to collect items for a Bill of Materials record (visible here), with the formula
BOM_Items.lookupRecords(Order=$id)
.
- Another collects ingredients for a Menu Item (visible here), with the formula
Ingredients.lookupRecords(Menu_Item=$id)
. (BTW, this is a common type of lookup in Grist, described here: reverse lookups.)
Then there is a hidden Ingredients
column in the Bill of Materials table that collects all the ingredients for the order, taking into account the quantity of each item. (You can see it in the Raw Data page here.) That formula is more involved, using some real Python to construct a Python dictionary that maps each product to total quantity needed:
amounts = {}
for item in $Items:
for r in item.Item.Ingredients:
amounts[r.Product] = amounts.get(r.Product, 0) + r.Quantity * item.Quantity
amounts
Using this, the formula for the final “Full List” focuses on formatting, particularly to give a useful summary in terms of units (and that perhaps doesn’t need to be as complicated in your case):
'\n'.join(sorted(
"{}{} — {:g} {}".format(product.Name,
("" if product.Recipe_Unit == product.Pack_Unit else
" ({:g} {})".format(quantity, product.Recipe_Unit)
),
ROUND(quantity * product.Pack_Units_in_Recipe_Unit, 2), product.Pack_Unit,
)
for (product, quantity) in $Ingredients.items()
))
Admittedly this is complex. Maybe you can get what you need based on this template. But don’t hesitate to ask here if you need more help. If you build up using non-sensitive data, and can link-share your document, that would make it easier to suggest specific solutions.