diff --git a/docs/article-types-matrix.md b/docs/article-types-matrix.md
index 15327fe..45cd4c4 100644
--- a/docs/article-types-matrix.md
+++ b/docs/article-types-matrix.md
@@ -74,7 +74,7 @@ Varianten bilden im System eine **Baum-Struktur** ab (z. B. für mehrdimensional
* **Hat Bestand?**:
- **Virtuell abgeleitet**: Ergibt sich dynamisch aus der kleinsten verfügbaren Komponentenmenge:
$$\text{Bestand}_{\text{Set}} = \min_{i} \left( \left\lfloor \frac{\text{Bestand}_i}{\text{Menge}_i} \right\rfloor \right)$$
- Bei Verkauf werden die Komponenten aus dem Lager abgebucht.
+ Bei Verkauf werden die Komponenten aus dem Lager abgebucht. **Manuelle Bestandsanpassungen (`POST /api/stock/adjust`) auf Stücklisten sind gesperrt** (HTTP 400), um eine künstliche Komponenten-Inflation zu verhindern. Inventur- und Bestandskorrekturen erfolgen direkt an den physischen Komponenten.
* **Eigene Eigenschaften (Hersteller, Kategorie)?**:
- **Ja**: Eigenständige Zuweisung von Marke (`brand_id`), Kategorien (`categoryarticle`), Name und Beschreibung.
* **Hat Lieferanten?**:
diff --git a/src/components/article/boxes/ArticleViewStock.jsx b/src/components/article/boxes/ArticleViewStock.jsx
index e43afcd..49a2397 100644
--- a/src/components/article/boxes/ArticleViewStock.jsx
+++ b/src/components/article/boxes/ArticleViewStock.jsx
@@ -32,8 +32,13 @@ export default class ArticleViewStock extends PureComponent {
const { article: articleData } = this.props;
const { adjustOpen } = this.state;
const isFather = Boolean(articleData?.isFather);
+ const isStueckliste = Boolean(
+ articleData?.articlelistId != null ||
+ (articleData?.articleListCount ?? 0) > 0 ||
+ articleData?.articlelist?.length > 0
+ );
const isTrackStock =
- !isFather && articleData?.track_stock !== false && articleData?.track_stock !== 0;
+ !isFather && !isStueckliste && articleData?.track_stock !== false && articleData?.track_stock !== 0;
const rawWarehouses = Array.isArray(articleData?.warehouses)
? articleData.warehouses
@@ -61,9 +66,9 @@ export default class ArticleViewStock extends PureComponent {
+ ) : isStueckliste ? (
+
+
+
+ 0 ? 'text.primary' : 'text.secondary',
+ }}
+ >
+ {formatStock(totalStock)}
+
+ {unit ? (
+
+ {unit}
+
+ ) : null}
+
+
+ Virtueller Bestand (aus Komponenten)
+
+
+
) : isTrackStock ? (
- {!isFather ? (
+ {!isFather && !isStueckliste ? (
!a.isFather && !a.is_father);
const trimmed = query.trim().toLowerCase();
const filtered = trimmed
- ? articles.filter((a) => {
+ ? bookableArticles.filter((a) => {
const skuMatch = a.sku?.toLowerCase().includes(trimmed);
const nameMatch = a.name?.toLowerCase().includes(trimmed);
const eanMatch = Array.isArray(a.eans)
@@ -122,7 +128,7 @@ export default class ArticleSearchDialog extends PureComponent {
: false;
return skuMatch || nameMatch || eanMatch;
})
- : articles.slice(0, 50);
+ : bookableArticles.slice(0, 50);
const rawSku = line?.sku != null ? String(line.sku).trim() : '';