diff --git a/src/components/article/ArticleView.jsx b/src/components/article/ArticleView.jsx index 20fe1b6..91a2e3f 100644 --- a/src/components/article/ArticleView.jsx +++ b/src/components/article/ArticleView.jsx @@ -101,7 +101,7 @@ class ArticleView extends PureComponent { article={article} /> - + diff --git a/src/components/article/boxes/ArticleViewStock.jsx b/src/components/article/boxes/ArticleViewStock.jsx index 6a4da4c..c7093ea 100644 --- a/src/components/article/boxes/ArticleViewStock.jsx +++ b/src/components/article/boxes/ArticleViewStock.jsx @@ -4,11 +4,13 @@ import Typography from '@mui/material/Typography'; import WarehouseIcon from '@mui/icons-material/Warehouse'; import EditOutlinedIcon from '@mui/icons-material/EditOutlined'; import LocalShippingOutlinedIcon from '@mui/icons-material/LocalShippingOutlined'; +import ShoppingCartOutlinedIcon from '@mui/icons-material/ShoppingCartOutlined'; import Tooltip from '@mui/material/Tooltip'; import { PanelTile } from 'dashgui/panels'; import { formatStock } from '../searchFormat'; import ArticleStockAdjustDialog from '../ArticleStockAdjustDialog'; import artikelAutomat, { getArticle } from '../../../automats/artikelAutomat'; +import { router } from '../../../appRouter'; import { GREEN_PANEL, PETROL_PANEL, @@ -96,6 +98,58 @@ function extractIncoming(articleData, isParent) { return items; } +function extractUndeliveredOrders(articleData, isParent) { + const items = []; + + const collect = (article, variantInfo = null) => { + if (!article) return; + + if (Array.isArray(article.undeliveredOrders)) { + for (const ord of article.undeliveredOrders) { + const amount = Number(ord?.amount) || 0; + if (amount > 0) { + items.push({ + orderId: ord.orderId, + orderNumber: ord.orderNumber || (ord.orderId ? `A-${ord.orderId}` : null), + date: ord.date || null, + customerName: ord.customerName || null, + amount, + variantSku: variantInfo?.sku || null, + variantName: variantInfo?.name || null, + }); + } + } + } + }; + + collect(articleData); + + if (isParent) { + const children = Array.isArray(articleData?.children) ? articleData.children : []; + for (const child of children) { + const fullChild = getArticle(child.sku) || child; + collect(fullChild, { + sku: fullChild.sku || child.sku, + name: fullChild.name || child.name, + }); + } + } + + items.sort((a, b) => { + if (a.date && b.date) { + const diff = new Date(a.date).getTime() - new Date(b.date).getTime(); + if (diff !== 0) return diff; + } else if (a.date) { + return -1; + } else if (b.date) { + return 1; + } + return (Number(a.orderId) || 0) - (Number(b.orderId) || 0); + }); + + return items; +} + export default class ArticleViewStock extends PureComponent { constructor(props) { super(props); @@ -104,6 +158,17 @@ export default class ArticleViewStock extends PureComponent { }; this.handleOpenAdjust = this.handleOpenAdjust.bind(this); this.handleCloseAdjust = this.handleCloseAdjust.bind(this); + this.handleOpenOrder = this.handleOpenOrder.bind(this); + } + + handleOpenOrder(orderId, event) { + if (!orderId) return; + if (event?.metaKey || event?.ctrlKey) { + window.open(`/auftrag/bestellung/${orderId}`, '_blank'); + return; + } + const nav = this.props.navigate || router.navigate; + void nav(`/auftrag/bestellung/${orderId}`); } componentDidMount() { @@ -205,6 +270,10 @@ export default class ArticleViewStock extends PureComponent { const totalIncoming = incomingItems.reduce((sum, inc) => sum + inc.amount, 0); const hasIncoming = totalIncoming > 0; + const undeliveredOrders = extractUndeliveredOrders(articleData, isParent); + const totalUndelivered = undeliveredOrders.reduce((sum, ord) => sum + ord.amount, 0); + const hasUndelivered = totalUndelivered > 0; + return ( <> - 0 ? 'text.primary' : 'text.secondary', - }} - > - {formatStock(totalStock)} - - {unit ? ( + 0 ? 'text.primary' : 'text.secondary', + }} > - {unit} + {formatStock(totalStock)} - ) : null} + {unit ? ( + + {unit} + + ) : null} + ) : ( @@ -374,8 +444,8 @@ export default class ArticleViewStock extends PureComponent { )} - {/* Bottom section: Per-warehouse breakdown & incoming shipments */} - {hasWarehouses || hasIncoming ? ( + {/* Bottom section: Per-warehouse breakdown, incoming shipments & open orders */} + {hasWarehouses || hasIncoming || hasUndelivered ? ( {incomingItems.map((inc, idx) => { const dateLabel = inc.date ? formatDate(inc.date) : null; - const label = [ + const labelParts = [ + inc.variantName, inc.supplierName || 'Lieferant', dateLabel, - ] - .filter(Boolean) - .join(' – '); + ].filter(Boolean); + const label = labelParts.join(' – '); return ( ) : null} + + {/* Undelivered / Open Customer Orders */} + {hasUndelivered ? ( + <> + {undeliveredOrders.map((ord, idx) => { + const dateLabel = ord.date ? formatDate(ord.date) : null; + const orderLabel = ord.orderNumber || (ord.orderId ? `Auftrag #${ord.orderId}` : 'Auftrag'); + const labelParts = [ + ord.variantName, + orderLabel, + ord.customerName, + dateLabel, + ].filter(Boolean); + const label = labelParts.join(' – '); + const tooltipText = ord.orderId + ? `Auftrag ${orderLabel}${ord.customerName ? ` (${ord.customerName})` : ''} öffnen` + : label; + + return ( + this.handleOpenOrder(ord.orderId, e)} + title={tooltipText} + sx={{ + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', + py: 0.35, + px: 0.75, + borderRadius: 1, + backgroundColor: VEIL_PANEL, + cursor: ord.orderId ? 'pointer' : 'default', + transition: 'background-color 0.15s ease', + '&:hover': ord.orderId ? { + backgroundColor: TINT_ROW_HOVER, + } : undefined, + }} + > + + + + {label} + + + + + -{formatStock(ord.amount)} + + + ); + })} + + ) : null} ) : null}