diff --git a/rmser-view/src/components/ocr/AddMatchForm.tsx b/rmser-view/src/components/ocr/AddMatchForm.tsx index 8dfc69a..1a0708b 100644 --- a/rmser-view/src/components/ocr/AddMatchForm.tsx +++ b/rmser-view/src/components/ocr/AddMatchForm.tsx @@ -1,13 +1,14 @@ import React, { useState, useMemo } from 'react'; -import { Card, Button, Flex, AutoComplete, InputNumber, Typography, Select } from 'antd'; +import { Card, Button, Flex, AutoComplete, InputNumber, Typography, Select, Divider } from 'antd'; import { PlusOutlined } from '@ant-design/icons'; import { CatalogSelect } from './CatalogSelect'; -import type { CatalogItem, UnmatchedItem, ProductSearchResult } from '../../services/types'; +import { CreateContainerModal } from '../invoices/CreateContainerModal'; // Импортируем модалку +import type { CatalogItem, UnmatchedItem, ProductSearchResult, ProductContainer } from '../../services/types'; const { Text } = Typography; interface Props { - catalog: CatalogItem[]; // Оставляем для совместимости, но CatalogSelect его больше не использует + catalog: CatalogItem[]; unmatched?: UnmatchedItem[]; onSave: (rawName: string, productId: string, quantity: number, containerId?: string) => void; isLoading: boolean; @@ -15,13 +16,19 @@ interface Props { export const AddMatchForm: React.FC = ({ catalog, unmatched = [], onSave, isLoading }) => { const [rawName, setRawName] = useState(''); + + // Состояния товара const [selectedProduct, setSelectedProduct] = useState(undefined); - // Сохраняем полный объект товара, полученный из поиска, чтобы иметь доступ к containers const [selectedProductData, setSelectedProductData] = useState(undefined); const [quantity, setQuantity] = useState(1); const [selectedContainer, setSelectedContainer] = useState(null); + // Состояние модалки создания фасовки + const [isModalOpen, setIsModalOpen] = useState(false); + + // --- Вычисляемые значения --- + const unmatchedOptions = useMemo(() => { return unmatched.map(item => ({ value: item.raw_name, @@ -29,32 +36,24 @@ export const AddMatchForm: React.FC = ({ catalog, unmatched = [], onSave, })); }, [unmatched]); - // Вычисляем активный товар: либо из результатов поиска, либо ищем в старом каталоге (если он передан) + // Активный продукт (из поиска или из старого каталога) const activeProduct = useMemo(() => { if (selectedProductData) return selectedProductData; if (selectedProduct && catalog.length > 0) { - // Приводим типы, так как CatalogItem расширяет ProductSearchResult return catalog.find(item => item.id === selectedProduct) as unknown as ProductSearchResult; } - return null; + return undefined; }, [selectedProduct, selectedProductData, catalog]); - // Хендлер смены товара: принимаем и ID, и объект - const handleProductChange = (val: string, productObj?: ProductSearchResult) => { - setSelectedProduct(val); - if (productObj) { - setSelectedProductData(productObj); - } - setSelectedContainer(null); - }; - + // Список контейнеров текущего товара const containers = useMemo(() => { return activeProduct?.containers || []; }, [activeProduct]); - // Берем единицу измерения с учетом новой структуры (main_unit) + // Базовая единица const baseUom = activeProduct?.main_unit?.name || activeProduct?.measure_unit || 'ед.'; + // Текстовое отображение текущей единицы const currentUomName = useMemo(() => { if (selectedContainer) { const cont = containers.find(c => c.id === selectedContainer); @@ -63,10 +62,23 @@ export const AddMatchForm: React.FC = ({ catalog, unmatched = [], onSave, return baseUom; }, [selectedContainer, containers, baseUom]); + const isButtonDisabled = !rawName.trim() || !selectedProduct || !quantity || quantity <= 0 || isLoading; + + // --- Хендлеры --- + + const handleProductChange = (val: string, productObj?: ProductSearchResult) => { + setSelectedProduct(val); + if (productObj) { + setSelectedProductData(productObj); + } + setSelectedContainer(null); + }; + const handleSubmit = () => { if (rawName.trim() && selectedProduct && quantity && quantity > 0) { onSave(rawName, selectedProduct, quantity, selectedContainer || undefined); + // Сброс формы setRawName(''); setSelectedProduct(undefined); setSelectedProductData(undefined); @@ -75,11 +87,32 @@ export const AddMatchForm: React.FC = ({ catalog, unmatched = [], onSave, } }; - const isButtonDisabled = !rawName.trim() || !selectedProduct || !quantity || quantity <= 0 || isLoading; + // Обработка создания новой фасовки + const handleContainerCreated = (newContainer: ProductContainer) => { + setIsModalOpen(false); + + // 1. Обновляем локальные данные продукта, добавляя новую фасовку в список + if (selectedProductData) { + setSelectedProductData({ + ...selectedProductData, + containers: [...(selectedProductData.containers || []), newContainer] + }); + } else if (activeProduct) { + // Если продукт был взят из общего catalog, создаем локальную копию + setSelectedProductData({ + ...activeProduct, + containers: [...(activeProduct.containers || []), newContainer] + }); + } + + // 2. Сразу выбираем созданную фасовку + setSelectedContainer(newContainer.id); + }; return ( + {/* Поле текста из чека */}
Текст из чека:
= ({ catalog, unmatched = [], onSave, />
+ {/* Выбор товара (Поиск) */}
Товар в iiko:
- {containers.length > 0 && ( + {/* Выбор фасовки (появляется только если есть активный товар) */} + {activeProduct && (
Единица измерения / Фасовка: