# Design: Доработка товара — удаление «под заказ», обязательные quantity и категория **Дата:** 2026-05-15 **Статус:** На согласовании ## Цель Упростить модель товара: убрать концепцию «под заказ», сделать количество и категорию обязательными полями. Категория «Не указано» остаётся технической заглушкой для переноса товаров при удалении категории, но не видна в каталоге и не выбирается при редактировании. ## Архитектура изменений ### 1. База данных (Prisma) **Миграция:** - Перед удалением полей: все товары с `inStock = false` получают `quantity = 0` - Удалить поля `inStock` и `leadTimeDays` из модели `Product` - Статус наличия определяется исключительно по `quantity`: - `quantity > 0` → «В наличии» - `quantity = 0` → «Нет в наличии» **`server/prisma/schema.prisma`:** ```prisma model Product { // ... остальные поля без изменений ... quantity Int @default(0) // УДАЛЕНО: inStock Boolean @default(true) // УДАЛЕНО: leadTimeDays Int? category Category @relation(fields: [categoryId], references: [id], onDelete: Restrict) categoryId String // ... } ``` ### 2. Сервер — валидация и CRUD **`server/src/routes/api/admin-products.js`:** **CREATE (POST):** - `quantity` — required, `Int >= 0` (было nullable) - `categoryId` — required (было: при пустом → авто-назначение «Не указано») - Удалить валидацию `leadTimeDays` при `!inStock` - Удалить принудительную установку `quantity = 1` для «под заказ» - Вернуть 400: `'Укажите категорию'` если `categoryId` отсутствует **UPDATE (PATCH):** - `quantity` — required, `Int >= 0` (было nullable) - `categoryId` — required (было: при пустом → «Не указано») - Удалить логику очистки `leadTimeDays` при `inStock = true` - Удалить принудительную установку `quantity = 1` - Вернуть 400 при отсутствии `categoryId` **JSON Schema:** - `CREATE_PRODUCT_SCHEMA`: убрать `leadTimeDays`, сделать `quantity` required (убрать `nullable`) - `PATCH_PRODUCT_SCHEMA`: убрать `leadTimeDays`, `quantity` — если передан, то `>= 0` **`server/src/routes/api/public-catalog.js`:** - Удалить ветку `availability === 'in_stock'` и `availability === 'made_to_order'` - Фильтрация «в наличии» больше не нужна — все товары в каталоге ### 3. Клиент — админка (две страницы) **`client/src/pages/admin/ui/AdminPage.tsx`** и **`client/src/pages/admin-products/ui/AdminProductsPage.tsx`:** **FormState:** - Удалить `inStock: boolean` и `leadTimeDays: string` - `quantity: string` — без nullable-семантики **UI:** - Удалить Switch «В наличии / Под заказ» - Удалить TextField «Срок исполнения, дней» - TextField «Количество»: - Без helper «Оставьте пустым...» - Новый helper: «0 = нет в наличии» - Валидация: не может быть пустым, `parseInt >= 0` - Select «Категория»: - Удалить `` с «Не указано» - Валидация: не даёт сохранить без выбранной категории - Показать ошибку при попытке сохранить без категории **Submit-валидация:** - Удалить проверку `leadTimeDays` при `!inStock` - Добавить проверку: `categoryId` не пустой → blocking error - Добавить проверку: `quantity` не пустой → blocking error ### 4. Клиент — каталог **`client/src/entities/product/ui/ProductCard.tsx`:** - Удалить логику `'Под заказ · {leadTimeDays} дн.'` - Новый статус: - `quantity > 0` → «В наличии» (зелёный) - `quantity === 0` → «Нет в наличии» (серый/red) **`client/src/pages/product/ui/ProductPage.tsx`:** - Удалить chip `'Под заказ · {leadTimeDays} дн.'` - Удалить alert `'Этот товар изготавливается под заказ...'` - Статус определяется по `quantity` **`client/src/pages/checkout/ui/CheckoutPage.tsx`:** - Удалить определение made-to-order товаров в корзине - Удалить info alert о доставке после изготовления ### 5. Клиент — фильтры **`client/src/pages/home/lib/use-product-filters.ts`:** - Удалить `availability: 'all' | 'in_stock' | 'made_to_order'` из state - Удалить `availability` из параметров `fetchPublicProducts()` **`client/src/pages/home/ui/ProductFilters.tsx`:** - Удалить `ToggleButtonGroup` с `'all'`, `'in_stock'`, `'made_to_order'` - Удалить отображение категории «Не указано» из списка чипов (фильтр `cat.slug !== 'ne-ukazano'`) ### 6. Категория «Не указано» — что остаётся | Где | Что происходит | |---|---| | `server/src/lib/default-category.js` | **Остаётся** — функция `getOrCreateUnspecifiedCategory()` | | `server/src/index.js` | **Остаётся** — вызов при старте | | `server/src/routes/api/admin-categories.js` | **Остаётся** — нельзя удалить/переименовать; при удалении категории товары переезжают в «Не указано» | | Админка категорий | **Остаётся** — кнопка удаления заблокирована | | Фильтры каталога | **Скрыта** — не показывается в чипах | | Форма товара | **Скрыта** — не выбирается в Select | ## Статус товара — новая логика ``` quantity > 0 → «В наличии» (зелёный chip/badge) quantity = 0 → «Нет в наличии» (серый chip/badge) ``` Никаких других статусов. Поле `inStock` больше не существует. ## Файлы для изменения ### Сервер | Файл | Изменения | |---|---| | `server/prisma/schema.prisma` | Удалить `inStock`, `leadTimeDays` | | `server/src/routes/api/admin-products.js` | Валидация, schema, убрать логику под заказ | | `server/src/routes/api/public-catalog.js` | Убрать фильтр availability | ### Клиент | Файл | Изменения | |---|---| | `client/src/pages/admin/ui/AdminPage.tsx` | FormState, UI, валидация | | `client/src/pages/admin-products/ui/AdminProductsPage.tsx` | FormState, UI, валидация | | `client/src/entities/product/ui/ProductCard.tsx` | Статус по quantity | | `client/src/pages/product/ui/ProductPage.tsx` | Убрать под заказ UI | | `client/src/pages/checkout/ui/CheckoutPage.tsx` | Убрать made-to-order detection | | `client/src/pages/home/ui/ProductFilters.tsx` | Убрать availability toggle, скрыть «Не указано» | | `client/src/pages/home/lib/use-product-filters.ts` | Убрать `availability` | ## Миграция данных ```javascript // В Prisma migration: // 1. UPDATE Product SET quantity = 0 WHERE inStock = false // 2. ALTER TABLE Product DROP COLUMN inStock // 3. ALTER TABLE Product DROP COLUMN leadTimeDays ``` ## Тестирование **Сервер:** - CREATE без categoryId → 400 - CREATE без quantity → 400 - CREATE с quantity = 0 → OK - PATCH без categoryId → 400 - PATCH с quantity = 0 → OK **Клиент:** - Форма не сохраняется без категории - Форма не сохраняется без количества - Фильтры не содержат «Под заказ» и «Не указано» - Карточка товара показывает «Нет в наличии» при quantity = 0