diff --git a/src/components/article/boxes/ArticleViewStock.jsx b/src/components/article/boxes/ArticleViewStock.jsx
index 42e3602..c6e49ba 100644
--- a/src/components/article/boxes/ArticleViewStock.jsx
+++ b/src/components/article/boxes/ArticleViewStock.jsx
@@ -3,7 +3,9 @@ import Box from '@mui/material/Box';
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 Tooltip from '@mui/material/Tooltip';
+import Chip from '@mui/material/Chip';
import { PanelTile } from 'dashgui/panels';
import { formatStock } from '../searchFormat';
import ArticleStockAdjustDialog from '../ArticleStockAdjustDialog';
@@ -18,6 +20,83 @@ import {
const SECOND_ROW_MIN_HEIGHT = 220;
+function formatDate(iso) {
+ if (!iso) return '';
+ const d = new Date(iso);
+ if (Number.isNaN(d.getTime())) return String(iso);
+ return d.toLocaleDateString('de-DE');
+}
+
+function extractIncoming(articleData, isParent) {
+ const items = [];
+
+ const collect = (article, variantInfo = null) => {
+ if (!article) return;
+
+ if (Array.isArray(article.incoming)) {
+ for (const inc of article.incoming) {
+ const amount = Number(inc?.amount) || 0;
+ if (amount > 0) {
+ items.push({
+ date: inc.date || null,
+ amount,
+ supplierName: inc.supplierName || null,
+ supplierSku: inc.sku || null,
+ pu: inc.pu || null,
+ variantSku: variantInfo?.sku || null,
+ variantName: variantInfo?.name || null,
+ });
+ }
+ }
+ }
+
+ if (Array.isArray(article.suppliers)) {
+ for (const sup of article.suppliers) {
+ if (Array.isArray(sup?.incoming)) {
+ for (const inc of sup.incoming) {
+ const amount = Number(inc?.amount) || 0;
+ if (amount > 0) {
+ items.push({
+ date: inc.date || null,
+ amount,
+ supplierName: sup.supplierName || null,
+ supplierSku: sup.sku || null,
+ pu: sup.pu || null,
+ 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) {
+ return new Date(a.date).getTime() - new Date(b.date).getTime();
+ }
+ if (a.date) return -1;
+ if (b.date) return 1;
+ return 0;
+ });
+
+ return items;
+}
+
export default class ArticleViewStock extends PureComponent {
constructor(props) {
super(props);
@@ -66,6 +145,40 @@ export default class ArticleViewStock extends PureComponent {
this.setState({ adjustOpen: false });
}
+ renderIncomingChip(totalIncoming, incomingItems, unit) {
+ const tooltipText = `${formatStock(totalIncoming)}${unit ? ` ${unit}` : ''} im Zulauf aus ${
+ incomingItems.length === 1
+ ? 'einer offenen Lieferung'
+ : `${incomingItems.length} offenen Lieferungen`
+ }`;
+
+ return (
+
+
+ }
+ label={`+${formatStock(totalIncoming)}${unit ? ` ${unit}` : ''} im Zulauf`}
+ onClick={(e) => e.stopPropagation()}
+ sx={{
+ fontWeight: 600,
+ fontSize: '0.75rem',
+ height: 22,
+ backgroundColor: VEIL_PANEL,
+ cursor: 'default',
+ '& .MuiChip-icon': {
+ color: 'text.secondary',
+ ml: '6px',
+ },
+ }}
+ />
+
+ );
+ }
+
render() {
const { article: articleData } = this.props;
const { adjustOpen } = this.state;
@@ -123,6 +236,10 @@ export default class ArticleViewStock extends PureComponent {
? rawUnit
: '';
+ const incomingItems = extractIncoming(articleData, isParent);
+ const totalIncoming = incomingItems.reduce((sum, inc) => sum + inc.amount, 0);
+ const hasIncoming = totalIncoming > 0;
+
return (
<>
{isParent ? (
- anyVariantTracksStock || totalVariantsStock > 0 ? (
-
+
+ {anyVariantTracksStock || totalVariantsStock > 0 ? (
Alle Varianten zusammen: {formatStock(totalVariantsStock)}
-
- ) : null
+ ) : null}
+ {hasIncoming ? (
+
+ {this.renderIncomingChip(totalIncoming, incomingItems, unit)}
+
+ ) : null}
+
) : isStueckliste ? (
-
-
-
+
+
+
+
+ 0 ? 'text.primary' : 'text.secondary',
+ }}
+ >
+ {formatStock(totalStock)}
+
+ {unit ? (
+
+ {unit}
+
+ ) : null}
+
+
+ Virtueller Bestand (aus Komponenten)
+
+
+
+ {hasIncoming ? (
+
+ {this.renderIncomingChip(totalIncoming, incomingItems, unit)}
+
+ ) : null}
+
+ ) : isTrackStock ? (
+
+
+
) : null}
-
- Virtueller Bestand (aus Komponenten)
-
-
-
- ) : isTrackStock ? (
-
+
+ {hasIncoming ? (
+
+ {this.renderIncomingChip(totalIncoming, incomingItems, unit)}
+
+ ) : null}
+
+ ) : (
+
0 ? 'text.primary' : 'text.secondary',
+ lineHeight: 1.2,
+ color: 'text.secondary',
}}
>
- {formatStock(totalStock)}
+ Keine Erfassung
+
+
+ Bestand wird nicht überwacht
- {unit ? (
-
- {unit}
-
- ) : null}
-
- ) : (
-
-
- Keine Erfassung
-
-
- Bestand wird nicht überwacht
-
+ {hasIncoming ? (
+
+ {this.renderIncomingChip(totalIncoming, incomingItems, unit)}
+
+ ) : null}
)}
- {/* Bottom section: Per-warehouse breakdown */}
- {isTrackStock && hasWarehouses ? (
+ {/* Bottom section: Per-warehouse breakdown & incoming shipments */}
+ {hasWarehouses || hasIncoming ? (
- {warehouses.map((wh) => (
-
-
-
+ {/* Warehouse stocks */}
+ {hasWarehouses ? (
+ <>
+ {hasIncoming ? (
- {wh.name}
+ Lagerorte
-
+ ) : null}
+ {warehouses.map((wh) => (
+
+
+
+
+ {wh.name}
+
+
+ 0
+ ? 'text.primary'
+ : 'text.secondary',
+ }}
+ >
+ {formatStock(wh.stock)}
+
+
+ ))}
+ >
+ ) : null}
+
+ {/* Incoming shipments */}
+ {hasIncoming ? (
+ <>
0
- ? 'text.primary'
- : 'text.secondary',
+ color: 'text.secondary',
+ textTransform: 'uppercase',
+ letterSpacing: 0.5,
+ px: 0.5,
+ mt: hasWarehouses ? 0.75 : 0,
+ mb: 0.1,
+ display: 'block',
}}
>
- {formatStock(wh.stock)}
+ Im Zulauf
-
- ))}
+ {incomingItems.map((inc, idx) => {
+ const dateLabel = inc.date ? formatDate(inc.date) : null;
+ const label = [
+ inc.supplierName || 'Lieferant',
+ dateLabel,
+ ]
+ .filter(Boolean)
+ .join(' – ');
+
+ return (
+
+
+
+
+ {label}
+
+
+
+
+ +{formatStock(inc.amount)}
+
+
+ );
+ })}
+ >
+ ) : null}
) : null}