Sales
Sales closes the commercial cycle of cheese and milk: every line of a sale is tied to one concrete cheese batch or to one direct-sale milk pool, so selling draws down that batch's stock, or that pool's liters, on its own — nobody has to write it down twice. A customer is optional — a sale with no customer is an "occasional sale" — and the price always starts from a suggestion, never a made-up number. Reports for sales by period, by product, top buyers and total losses, plus the reverse traceability each batch already carried: from the sold line all the way back to the cows whose milk went into it.
Terms
- Sale line tied to a batch
- Every item in a sale sells kilograms from one concrete cheese batch, not from a product in general — you pick the product, then the batch, and last the kilograms and the price. That link is what lets stock come down from the exact right place, and later lets every sold kilogram be traced back to the milk and cows behind it. Each batch in the picker is named the way the cheese Stock tab names it, by the day and milking of its milk, followed by its remaining kilograms and its batch number: "Friday · afternoon · 12.5 kg (20261002-1)"; a batch with no milk recorded shows the day alone.Where it appears: Dashboard → Sales → Sales → New sale
- Milk line
- A sale line can be cheese or milk: each line's "Type" select decides. A milk line sells liters from a direct-sale pool — the milk set aside with that destination when a milking was closed — picked in "Milk pool" (each option shows the day, the shift and the liters it has left), and carries liters and a price per liter. Only pools of milkings closed and dated within the 7 days before the sale, inclusive, show up; selling draws the pool down exactly as a cheese batch consumes it, and a sale can never ask for more liters than the pool has left.Where it appears: Dashboard → Sales → Sales → New sale
- Occasional sale
- A sale with no customer attached, for a passing buyer not worth adding to the catalog. It is not a special customer stored in the database — it is picking the "Occasional sale (no customer)" option in the customer select. In reports, every occasional sale in the period is grouped into one single "Occasional" row, never listed one by one.Where it appears: Dashboard → Sales → Sales → New sale
- Suggested price
- Picking the product suggests a price per kilogram on its own: first the product's own price if it has one configured, otherwise the farm's general cheese price. If neither exists, nothing is suggested and the price has to be typed by hand — zero is never proposed just because the data is missing. The suggestion is an editable starting point, not a fixed price: whatever gets saved is what was actually negotiated that day. On a milk line the suggested price per liter is the farm's configured milk price; if there is none, the field stays empty and is typed by hand.Where it appears: Dashboard → Sales → Sales → New sale
- Overselling blocked
- A sale can never ask for more kilograms than a batch has left — it is rejected, the same as a stock adjustment that would take a batch negative. A batch that is already sold out simply does not appear as an option when building the sale.Where it appears: Dashboard → Sales → Sales → New sale
- Editing or deleting a sale
- Editing a sale's items annuls its previous stock movements (and the liters its milk lines took from their pools) and creates new ones from the corrected data — stock ends up exactly as if the original sale had never moved those kilograms. Deleting a sale annuls all of its movements and gives the stock back to the batches and the liters back to the milk pools involved; the sale disappears from the list, but the record is kept for the audit trail.Where it appears: Dashboard → Sales → Sales
- Return (v1)
- For now, a cheese return is recorded as a positive stock adjustment on the Cheesemaking Stock tab (reason "return"), not as part of the original sale — the sale that led to the return stays unlinked to that adjustment. This is a deliberate limitation of this first version: stock gets corrected either way, but the sale-to-return link is left for later.Where it appears: Dashboard → Cheesemaking → Stock → Adjust
- Customer
- A saved buyer with a name, phone, email and optional notes — the name cannot repeat within the same farm (case-insensitive). A customer can be deactivated once they stop buying without losing the history of their past sales, and reactivated later if they come back.Where it appears: Dashboard → Sales → Customers
- Sales reports
- Four views over the same period: sales by period (cheese kilograms and revenue grouped by day, week or month), sales by product (kilograms, revenue and the real average price actually charged for each cheese — never a made-up zero when there are no kilograms to average — plus, apart, one "Milk" row in liters with its own average price per liter), top buyers (with every occasional sale grouped into one row), and total losses (the period's negative stock adjustments, grouped by reason). Revenue always includes milk; kilograms and liters are never added together.Where it appears: Dashboard → Sales → Reports
- A sale's reverse traceability
- From a sale's detail, every line links to the batch it sold and that batch's already-existing traceability tree: which milk pools the batch consumed, which milking session each pool came from, and which cows contributed those liters. Selling does not create new traceability — it reuses exactly what the batch already had since it was produced.Where it appears: Dashboard → Sales → Sales → Sale detail
- Sales permissions
- Viewing customers, sales and reports requires the sales read permission; creating or editing customers and sales additionally requires the write permission. The Viewer and Accountant roles can only look (the Accountant cannot create or edit a sale); Owner, Manager and Worker can also register and edit. The Veterinarian does not see Sales (see Team and roles).Where it appears: Dashboard → Sales (all three tabs)
Flows
Recording a sale
Pick a date and customer
A customer from the catalog, or "occasional sale" if there is none
Add items
Cheese: product → batch (day, milking, remaining kilograms and number) → kilograms → suggested price, editable. Milk: direct-sale pool (liters available) → liters → price per liter suggested from the farm's milk price
The total computes itself
Never stored on its own; always the sum of the active lines
Save
Each line creates its own outbound movement on its batch's stock
Correcting an already-saved sale
Open the sale
From the sales list
Edit the items
The previous movements annul themselves once the new ones are saved
Or delete the whole sale
Annuls every movement; each batch gets its stock back
Reviewing where a sale came from
Open the sale detail
From the sales list
Follow a line's link
Goes to the batch that sold those kilograms
Open the traceability tree
That batch's milk pools, milking sessions and cows
Frequently asked questions
Why does every sale line ask for a batch instead of just a product?
Because the stock that gets drawn down belongs to one concrete batch, not a generic product total — and that link is what later lets every sold kilogram be traced back to the milk and cows that produced it. Picking the product first just filters which batches show up.
What happens if I try to sell more kilograms than a batch has left?
It gets rejected. Just like a stock adjustment that would take a batch negative, a sale cannot overdraw its stock — and a batch that is already sold out does not even show up as an option.
How is the suggested price computed when I add a line?
First it looks for the product's own price per kilogram; if it has none, it falls back to the farm's general cheese price. If neither exists, nothing is suggested — never a made-up zero — and the price has to be typed by hand. The suggestion can always be edited before saving.
What is an "occasional sale" and why do reports group it?
It is a sale with no customer attached, for passing buyers. Since there is no identity behind it to compare across sales, the top-buyers report groups them all into one "Occasional" row instead of treating each as an individual buyer.
What happens to stock if I edit or delete a sale?
Editing the items annuls the sale's previous stock movements and creates new ones from the corrected data. Deleting the sale annuls every movement, giving those kilograms back to the batches involved — the sale disappears from the list, but the record is kept for the audit trail. The same goes for milk lines: editing or deleting annuls the draw from the direct-sale pool and the liters go back to the pool.
Where do I record a cheese return?
On the Cheesemaking Stock tab, as a positive adjustment with reason "return". For now that return is not linked back to the original sale that caused it — that is a known limitation of this first version, not an oversight.
What happens if there were no sales in the chosen period?
Each of the four reports shows "No data for this period" instead of an empty or zeroed-out table. The "—" that sometimes shows in the average price per product is a defensive guard in the calculation, not something you would actually see: it would only appear for a product with zero kilograms sold, and a product with no sales in the period never produces a row in the first place.
How do I sell the milk I set aside for direct sale?
When closing the milking, split the liters that will be sold to the "Direct sale" destination. Then, in New sale, switch the line's type to Milk, pick the pool (day and shift) and type the liters and the price per liter — only pools of milkings closed and dated within the 7 days before the sale, inclusive, show up. On the milking screen, the pool's card shows how much was sold and how much is left; while any of a milking's milk is sold, that milking cannot be reopened.