# hospitality.recipe-cost
Costs a recipe the way a kitchen costing sheet does: what each ingredient costs
in the recipe, the total, and the cost of one portion.
For each ingredient:
1. **Convert** the quantity the recipe needs into the unit the pack is sold in,
with `units.convert` (250 g of a 1.5 kg bag is 0.25 kg). Count items use the
unit `each`, which only converts to `each` (3 eggs from a tray of 12).
2. **Gross up for yield.** `quantity` is the usable amount the recipe needs
after trimming and peeling. `yieldBasisPoints` is the usable share of what
is bought: 400 g of peeled carrots at an 8000 (80%) yield means buying 500 g.
A common mistake multiplies by the yield instead, costing 320 g.
3. **Price it** as that share of the pack price, in one exact division, rounded
half-up to the minor unit.
The total is the sum of the rounded line costs, so the sheet adds up, and the
portion cost is the total divided by `portions`, rounded half-up.
## Precision
Quantities and pack sizes are decimal text (`"0.75"`), never floats. The
converted quantity is carried to 9 decimal places of the pack unit, a
microgram of a kilogram pack, and everything after that is exact integer
arithmetic. Pack sizes may have at most 6 decimal places and 15 digits. An
ingredient whose cost cannot be held exactly (beyond 2^53 minor units) is an
error rather than a rounded guess.
A line under half a penny (a pinch of salt) costs 0. Kitchens that want those
counted usually add a "sundries" line as a fixed amount.
## Errors
- Units must be ones `units.convert` knows (`g`, `kg`, `mL`, `L`, `oz`, `lb`,
`floz_imp`...) or `each`, and a quantity and its pack must be the same
dimension: oil costed in grams but bought by the litre needs a density,
which this does not guess.
- `yieldBasisPoints` is 1 to 10000, `portions` at least 1, pack prices not
negative, and every pack price in `currency`.
1.0.1 fixes Python accepting a trailing newline in quantity and packSize; adds tests.