feat: KitchenStock light UI, Gemma 31B AI, supermarket store filters & 130+ vegan products

This commit is contained in:
KitchenStock
2026-07-26 20:08:16 +02:00
commit 83fcf6909c
81 changed files with 17001 additions and 0 deletions
+148
View File
@@ -0,0 +1,148 @@
-- Migration 00003: Transactional Stock Adjustment RPC (adjust_product_stock with FEFO)
CREATE OR REPLACE FUNCTION public.adjust_product_stock(
p_household_id UUID,
p_product_id UUID,
p_quantity_change NUMERIC,
p_reason public.stock_movement_reason,
p_batch_id UUID DEFAULT NULL,
p_note TEXT DEFAULT NULL
)
RETURNS NUMERIC
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
v_user_id UUID;
v_total_before NUMERIC := 0.0;
v_total_after NUMERIC := 0.0;
v_target_batch RECORD;
v_remaining_to_deduct NUMERIC;
v_deduct_amount NUMERIC;
BEGIN
v_user_id := auth.uid();
-- 1. Check permissions
IF NOT public.has_household_role(p_household_id, ARRAY['MEMBER', 'ADMIN', 'OWNER']::public.household_role[]) THEN
RAISE EXCEPTION 'PERMISSION_DENIED: User is not authorized to modify stock in household %', p_household_id;
END IF;
-- 2. Lock product and calculate current total stock
PERFORM 1 FROM public.products WHERE id = p_product_id AND household_id = p_household_id FOR UPDATE;
SELECT COALESCE(SUM(quantity), 0.0) INTO v_total_before
FROM public.inventory_batches
WHERE household_id = p_household_id AND product_id = p_product_id;
-- 3. Check for negative stock
IF (v_total_before + p_quantity_change) < 0 THEN
RAISE EXCEPTION 'INSUFFICIENT_STOCK: Required quantity reduction exceeds current total stock (%)', v_total_before;
END IF;
-- 4. Apply changes
IF p_batch_id IS NOT NULL THEN
-- Target specific batch
SELECT * INTO v_target_batch
FROM public.inventory_batches
WHERE id = p_batch_id AND product_id = p_product_id AND household_id = p_household_id
FOR UPDATE;
IF NOT FOUND THEN
RAISE EXCEPTION 'BATCH_NOT_FOUND: Specified batch % does not exist', p_batch_id;
END IF;
IF (v_target_batch.quantity + p_quantity_change) < 0 THEN
RAISE EXCEPTION 'INSUFFICIENT_BATCH_STOCK: Batch quantity cannot be reduced below 0';
END IF;
UPDATE public.inventory_batches
SET quantity = quantity + p_quantity_change,
updated_at = NOW()
WHERE id = p_batch_id;
ELSE
-- No explicit batch provided
IF p_quantity_change > 0 THEN
-- Increase stock: Add to default batch (batch without expiration_date or newest) or create new batch
SELECT id INTO p_batch_id
FROM public.inventory_batches
WHERE household_id = p_household_id
AND product_id = p_product_id
AND expiration_date IS NULL
ORDER BY created_at DESC
LIMIT 1;
IF p_batch_id IS NOT NULL THEN
UPDATE public.inventory_batches
SET quantity = quantity + p_quantity_change,
updated_at = NOW()
WHERE id = p_batch_id;
ELSE
INSERT INTO public.inventory_batches (household_id, product_id, quantity)
VALUES (p_household_id, p_product_id, p_quantity_change)
RETURNING id INTO p_batch_id;
END IF;
ELSIF p_quantity_change < 0 THEN
-- FEFO Deduction (First Expire, First Out)
v_remaining_to_deduct := ABS(p_quantity_change);
FOR v_target_batch IN
SELECT id, quantity
FROM public.inventory_batches
WHERE household_id = p_household_id
AND product_id = p_product_id
AND quantity > 0
ORDER BY
expiration_date ASC NULLS LAST,
created_at ASC
FOR UPDATE
LOOP
IF v_remaining_to_deduct <= 0 THEN
EXIT;
END IF;
v_deduct_amount := LEAST(v_target_batch.quantity, v_remaining_to_deduct);
UPDATE public.inventory_batches
SET quantity = quantity - v_deduct_amount,
updated_at = NOW()
WHERE id = v_target_batch.id;
v_remaining_to_deduct := v_remaining_to_deduct - v_deduct_amount;
END LOOP;
END IF;
END IF;
-- 5. Calculate new total stock
SELECT COALESCE(SUM(quantity), 0.0) INTO v_total_after
FROM public.inventory_batches
WHERE household_id = p_household_id AND product_id = p_product_id;
-- 6. Insert stock_movements record
INSERT INTO public.stock_movements (
household_id,
product_id,
batch_id,
quantity_before,
quantity_change,
quantity_after,
reason,
note,
created_by
) VALUES (
p_household_id,
p_product_id,
p_batch_id,
v_total_before,
p_quantity_change,
v_total_after,
p_reason,
p_note,
v_user_id
);
RETURN v_total_after;
END;
$$;