fix(inventory): robustare dedup vid skann + borttag pa startsidan
Dedup vid /v1/scans/:id/confirm matchade bara pa exakt (skiftlageskansligt) namn eller identiskt katalog-id, sa omfotografering av samma hylla skapade dubbletter. Ny normalizeItemName (gemener, accenter, storlek bort; behaller fetthalt-siffror) + matchning pa katalog-id ELLER normaliserat namn mot aktivt hushallslager. Mobil: 'Ta bort' fanns bara i Ditt kok. Lade borttag pa startsidans lager-rader (befintlig DELETE /v1/inventory/items/:id). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WZdew6cWn1MeHqoYWFfxzo
This commit is contained in:
@@ -7,6 +7,7 @@ import { confirmScanInputSchema, createScanInputSchema, idParamSchema } from "@a
|
||||
import { errors, parse } from "../lib/errors.js";
|
||||
import { emitEvent, requireActiveHousehold } from "../lib/helpers.js";
|
||||
import { consumeAiScan } from "../lib/entitlements.js";
|
||||
import { normalizeItemName } from "@app/inventory-engine";
|
||||
|
||||
/**
|
||||
* Skanningsflödet (spec §50):
|
||||
@@ -141,6 +142,23 @@ export async function scanRoutes(app: FastifyInstance) {
|
||||
|
||||
const created: string[] = [];
|
||||
const proposals = extractProposals(job);
|
||||
|
||||
// Aktiva varor i hushållet, för dubblett-hopslagning vid bekräftelse.
|
||||
const activeRows = await app.db
|
||||
.select({
|
||||
id: schema.inventoryItems.id,
|
||||
canonicalIngredientId: schema.inventoryItems.canonicalIngredientId,
|
||||
displayName: schema.inventoryItems.displayName,
|
||||
})
|
||||
.from(schema.inventoryItems)
|
||||
.where(
|
||||
and(
|
||||
eq(schema.inventoryItems.householdId, householdId),
|
||||
gt(schema.inventoryItems.quantity, 0),
|
||||
),
|
||||
);
|
||||
const activeItems = activeRows.map((r) => ({ ...r, norm: normalizeItemName(r.displayName) }));
|
||||
|
||||
for (const item of input.items) {
|
||||
const proposal = findProposal(proposals, item.tempId);
|
||||
await recordCorrection(app, job, item, proposal);
|
||||
@@ -150,25 +168,17 @@ export async function scanRoutes(app: FastifyInstance) {
|
||||
if (!locationId)
|
||||
throw errors.badRequest("storageLocationId saknas och ingen standardplats finns.");
|
||||
|
||||
// Dedup (#1): finns varan redan aktiv i hushållet? Uppdatera + hoppa över,
|
||||
// så överlappande foton / omfotografering inte skapar dubletter.
|
||||
const dedupCond = item.canonicalIngredientId
|
||||
? and(
|
||||
eq(schema.inventoryItems.householdId, householdId),
|
||||
eq(schema.inventoryItems.canonicalIngredientId, item.canonicalIngredientId),
|
||||
gt(schema.inventoryItems.quantity, 0),
|
||||
)
|
||||
: and(
|
||||
eq(schema.inventoryItems.householdId, householdId),
|
||||
isNull(schema.inventoryItems.canonicalIngredientId),
|
||||
eq(schema.inventoryItems.displayName, item.displayName),
|
||||
gt(schema.inventoryItems.quantity, 0),
|
||||
);
|
||||
const [dupe] = await app.db
|
||||
.select({ id: schema.inventoryItems.id })
|
||||
.from(schema.inventoryItems)
|
||||
.where(dedupCond)
|
||||
.limit(1);
|
||||
// Dedup (#1): slå ihop om varan redan finns aktiv i hushållet, så att
|
||||
// överlappande foton / omfotografering av samma hylla inte dubbellagras.
|
||||
// Matcha på katalog-id ELLER normaliserat namn — Vision skriver sällan
|
||||
// exakt samma namn två gånger ("Mjölk" vs "mjölk" vs "Mjölk 1L").
|
||||
const wantNorm = normalizeItemName(item.displayName);
|
||||
const dupe = activeItems.find(
|
||||
(r) =>
|
||||
(item.canonicalIngredientId != null &&
|
||||
r.canonicalIngredientId === item.canonicalIngredientId) ||
|
||||
r.norm === wantNorm,
|
||||
);
|
||||
if (dupe) {
|
||||
await app.db
|
||||
.update(schema.inventoryItems)
|
||||
|
||||
Reference in New Issue
Block a user