3942890d6f
- BUGG: kitchen hamtade ?limit=500 men schemat tillat max 200 -> 400-fel nar man gick in i matlager / tryckte "+N till". Hojer inventoryQuerySchema.limit till 500. - Hem: tar bort den roriga inline-listan (matlager lag kvar under Hemma). Ersatts med ett "Matlager"-kort med genvagsknappar per plats (Kyl/Frys/Skafferi) + "Allt". - Matlager-skarmen: grupperad per plats med rubrik + antal, sorterad pa namn, plats-filter via chips ELLER djuplank (?loc=), sok, markera flera, massradering. - Byter skarmtitel "Ditt kok" -> "Matlager". - Fixar aven en latent hooks-ordningsbugg i home (useFocusEffect efter early return).
82 lines
3.5 KiB
TypeScript
82 lines
3.5 KiB
TypeScript
import { z } from "zod";
|
|
import { DATE_KINDS, INVENTORY_SOURCES, INVENTORY_TRANSACTION_TYPES } from "@app/shared-types";
|
|
import { dateStringSchema, quantitySchema, unitSchema, uuidSchema } from "./common.js";
|
|
|
|
export const createInventoryItemInputSchema = z.object({
|
|
canonicalIngredientId: z.string().max(80).optional(),
|
|
productId: uuidSchema.optional(),
|
|
displayName: z.string().min(1).max(120).trim(),
|
|
brand: z.string().max(80).optional(),
|
|
quantity: quantitySchema,
|
|
unit: unitSchema,
|
|
storageLocationId: uuidSchema,
|
|
sublocation: z.string().max(60).optional(),
|
|
purchasedAt: dateStringSchema.optional(),
|
|
openedAt: dateStringSchema.optional(),
|
|
bestBeforeDate: dateStringSchema.optional(),
|
|
useByDate: dateStringSchema.optional(),
|
|
dateKind: z.enum(DATE_KINDS).optional(),
|
|
frozenAt: dateStringSchema.optional(),
|
|
priceMinor: z.number().int().min(0).max(10_000_000).optional(),
|
|
source: z.enum(INVENTORY_SOURCES).default("manual_search"),
|
|
});
|
|
export type CreateInventoryItemInput = z.infer<typeof createInventoryItemInputSchema>;
|
|
|
|
export const updateInventoryItemInputSchema = createInventoryItemInputSchema.partial().extend({
|
|
verifiedByUser: z.boolean().optional(),
|
|
});
|
|
export type UpdateInventoryItemInput = z.infer<typeof updateInventoryItemInputSchema>;
|
|
|
|
/** Manuell lagertransaktion, t.ex. "använde 300 g" eller "slängde resten". */
|
|
export const inventoryTransactionInputSchema = z.object({
|
|
type: z.enum(INVENTORY_TRANSACTION_TYPES),
|
|
quantityDelta: z.number().refine((v) => v !== 0, "Delta får inte vara 0"),
|
|
note: z.string().max(200).optional(),
|
|
});
|
|
export type InventoryTransactionInput = z.infer<typeof inventoryTransactionInputSchema>;
|
|
|
|
export const inventoryQuerySchema = z.object({
|
|
storageLocationId: uuidSchema.optional(),
|
|
expiryStatus: z.enum(["fresh", "use_soon", "expiring", "expired", "unknown"]).optional(),
|
|
search: z.string().max(80).optional(),
|
|
limit: z.coerce.number().int().min(1).max(500).default(100),
|
|
offset: z.coerce.number().int().min(0).default(0),
|
|
});
|
|
export type InventoryQuery = z.infer<typeof inventoryQuerySchema>;
|
|
|
|
/** Naturligt-språklig fritextsökning i hushållslagret (spec §8). */
|
|
export const inventoryNaturalSearchQuerySchema = z.object({
|
|
q: z.string().min(1).max(80).trim(),
|
|
languageTag: z.string().min(2).max(35).default("sv-SE"),
|
|
limit: z.coerce.number().int().min(1).max(20).default(5),
|
|
});
|
|
export type InventoryNaturalSearchQuery = z.infer<typeof inventoryNaturalSearchQuerySchema>;
|
|
|
|
export const reconciliationStartInputSchema = z.object({
|
|
maxItems: z.coerce.number().int().min(1).max(50).optional(),
|
|
});
|
|
export type ReconciliationStartInput = z.infer<typeof reconciliationStartInputSchema>;
|
|
|
|
export const reconciliationResolveInputSchema = z.object({
|
|
action: z.enum(["exists", "depleted", "uncertain"]),
|
|
quantity: z.number().min(0).optional(),
|
|
note: z.string().max(200).optional(),
|
|
});
|
|
export type ReconciliationResolveInput = z.infer<typeof reconciliationResolveInputSchema>;
|
|
|
|
export const scanDiffApplyInputSchema = z.object({
|
|
idempotencyKey: z.string().max(64).optional(),
|
|
rows: z.array(
|
|
z.object({
|
|
kind: z.enum(["new_item", "moved", "quantity_changed", "depleted"]),
|
|
previousItemId: z.string().uuid().optional(),
|
|
displayName: z.string().min(1).max(120),
|
|
unit: z.string().max(20),
|
|
newQuantity: z.number().min(0).optional(),
|
|
newLocationId: z.string().uuid().optional(),
|
|
confidence: z.number().min(0).max(1),
|
|
}),
|
|
),
|
|
});
|
|
export type ScanDiffApplyInput = z.infer<typeof scanDiffApplyInputSchema>;
|