NOVUS / RESTAURANT

Documentation

A product record, end to end

What the record id in the address really selects, what each headline metric prints when its input is missing, and why a drawn price history is not proof of a comparable price.

Last reviewed against the product on .

A product page is not a page about one invoice line. It is the page for one comparison group, and the purchase record id in the address is only the way in.

What the address actually names

The address ends in a purchase record id, but the page is assembled from every imported row that shares that row's supplier, item name, unit and currency. Any record id inside that group opens the identical page. The purchases table links by the row you clicked; the dashboard, the price changes table and the weekly report all link by the latest row in the group. Those are the same destination, not two views of it.

The grouping key is not this page's invention, and it is described in full in how a price change is detected. What matters here is the consequence: the header prints the supplier, the currency and the unit as an exact boundary, because everything below the header is true only inside that boundary.

A record id belonging to another organization does not resolve. Purchase rows are filtered to your organization before any grouping happens, so an id you are not entitled to read is not found rather than partially rendered.

The four headline metrics

What each headline metric shows, and the words it prints instead of a number
MetricWhat it showsPrinted when the input is missing
Current unit priceThe unit price on the most recent purchase date in the groupUnavailable
Previous unit priceThe unit price on the purchase date before that oneNo baseline
Price movementCurrent minus previous, with a percentage badge beside itNo baseline
Weekly impactThe movement multiplied by your observed weekly quantityNeeds quantity

Measured from the metric row in app/app/products/[recordId]/page.tsx and buildProduct in src/lib/purchasing/intelligence.ts.

None of those four is ever estimated. A missing input produces the words above and nothing else, which is the same rule the price changes table follows.

The percentage badge and the money figure can disagree

The badge beside the price movement is a percentage, and a percentage needs a previous price above zero to divide by. Where a previous price of exactly zero was imported, the movement still prints as money and the badge next to it reads "No baseline". The two are not contradicting each other; one of them simply cannot be formed.

Your purchasing, and the window behind it

Usage window
0, or 7 to 56 days
0 when nothing falls in the 56-day lookback, otherwise your observed span, floored at 7
Weekly quantity
Window quantity / weeks
only rows carrying a quantity above zero
Weekly spend
Window total / weeks
every row in the window, quantity or not
Annualized run rate
Weekly spend x 52
the window projected forward, not a forecast
Purchase rows
The whole group
not only the rows inside the window

Measured from buildProduct and observedWindowDays in src/lib/purchasing/intelligence.ts.

Two of those are counted differently on purpose, and the difference shows up on this panel more often than anywhere else on the site. Weekly spend uses every row in the window. Weekly quantity uses only the rows that carried a readable quantity above zero. A file that imports totals cleanly but quantities poorly therefore produces a confident spend figure beside an unavailable quantity, and the weekly impact above goes with the quantity.

The row count is the size of the whole group rather than the window, so a product bought heavily two years ago and twice last month shows a large row count beside a small weekly figure. That is the correct reading of both, not a disagreement between them.

The window itself is anchored to your most recent purchase date anywhere in the organization, not to today. A product you have stopped buying eventually falls outside it entirely, at which point the window reports no length, the weekly quantity is unavailable and the weekly spend is nothing. The panel is then describing history rather than current usage, and the price metrics above it are unaffected.

The price history line

One price is kept per purchase date, and the most recent of those dates are plotted oldest to newest. With fewer than two dates there is no line at all, and the panel says so rather than drawing a single point and letting it imply a trend.

Dates plotted
52 at most
one unit price per distinct purchase date
Dates needed
2
below that the panel prints a message instead of a line
Dates labelled
2
the first and the last, at the ends of the axis

Measured from buildProduct in src/lib/purchasing/intelligence.ts and the PriceHistory component in app/app/products/[recordId]/page.tsx.

A drawn line is not proof of a comparable price

A group whose unit or currency is missing is not comparison eligible. Its current and previous unit prices are withheld, its movement and weekly impact are withheld, and the header prints the boundary as unspecified. The chart is still drawn, because the history is built from any row with a resolvable unit price, and money elsewhere on the page prints with a currency missing note rather than a symbol.

So a healthy looking line above a column of withheld metrics is the expected appearance of an import problem, not a display fault. The import contract is where that is fixed, and it is fixed at the file rather than on this page.

The comparable supplier panel

Where a cheaper supplier exists for the same item, unit and currency, a panel appears naming that supplier and a potential weekly figure, with a link through to the evidence. It appears only when this product is the dearer side of the pair. Open the cheaper product and there is no panel, because nothing is being proposed about it.

The panel is also subject to review. Once an administrator rejects a proposed match, it stops appearing here as well as on the savings surface, and the link that used to reach its evidence stops resolving. A savings record covers what that panel leads to and who decides it.

What this page does not claim

The imported history is your purchasing evidence, not a supplier contract feed, and the weekly figures are observed run rates ending at your most recent purchase date rather than at today. Pack sizes are never converted, so a case that quietly became smaller while keeping its unit text reads here as a price rise. Checking the pack is still the first thing to do with any row that surprises you.

Where to look next

How a price change is detected owns the grouping key and the weekly impact arithmetic that this page displays for a single product. What a saving claims sets out the comparison behind the supplier panel. For the same evidence assembled across every product at once, see reading the dashboard.