Only estimate remaining after first audit, not from purchase date
Build and push image / build (push) Successful in 53s

Before any audit, bulk items show their full original weight with no
decay applied. The linear decay model only kicks in after the first
audit provides an actual data point. This prevents freshly added,
unopened items from showing misleading consumption estimates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-08 09:36:29 -04:00
parent b088953133
commit 564cae253a
2 changed files with 4 additions and 5 deletions
+1 -1
View File
@@ -294,7 +294,7 @@ export function ProductDetail({
{cfg?.unit}). Re-audit to update. {cfg?.unit}). Re-audit to update.
</div> </div>
)} )}
{item.containerWeight != null && ( {item.containerWeight != null && last && (
<div <div
style={{ style={{
fontSize: 11, fontSize: 11,
+3 -4
View File
@@ -211,16 +211,15 @@ export const helpers = {
return p.countLastAudit ?? p.countOriginal; return p.countLastAudit ?? p.countOriginal;
} }
const last = this.lastAudit(p); const last = this.lastAudit(p);
const baseDate = last ? last.date : p.purchaseDate; if (!last) return p.weight;
const baseValue = last ? last.value : p.weight;
const daysSinceBase = Math.max( const daysSinceBase = Math.max(
0, 0,
Math.floor((+new Date(today) - +new Date(baseDate)) / 86_400_000), Math.floor((+new Date(today) - +new Date(last.date)) / 86_400_000),
); );
const expectedLifespan = const expectedLifespan =
p.type === "Flower" ? 35 : p.type === "Concentrate" ? 40 : 90; p.type === "Flower" ? 35 : p.type === "Concentrate" ? 40 : 90;
const dailyBurn = p.weight / expectedLifespan; const dailyBurn = p.weight / expectedLifespan;
return Math.max(0, baseValue - dailyBurn * daysSinceBase); return Math.max(0, last.value - dailyBurn * daysSinceBase);
}, },
pctRemaining(p: Item, today = TODAY_STR): number { pctRemaining(p: Item, today = TODAY_STR): number {
if (p.kind === "discrete") { if (p.kind === "discrete") {