diff --git a/src/components/article/boxes/ArticleViewLists.jsx b/src/components/article/boxes/ArticleViewLists.jsx index fe93ed0..448df3f 100644 --- a/src/components/article/boxes/ArticleViewLists.jsx +++ b/src/components/article/boxes/ArticleViewLists.jsx @@ -45,7 +45,7 @@ import { alpha, } from '../../../colors'; -function getVariantDetails(child, allArticles, defaultTaxRate) { +function getVariantDetails(child, allArticles, defaultTaxRate, parentArticle) { const cached = child?.sku ? getArticle(child.sku) : null; const fromIndex = !cached && child?.sku ? (allArticles || []).find((a) => a.sku === child.sku) @@ -56,14 +56,30 @@ function getVariantDetails(child, allArticles, defaultTaxRate) { const gross = getArticleGross(merged, defaultTaxRate); const priceDisplay = gross != null && Number.isFinite(gross) ? formatPrice(gross) : null; - // 2. Stock & Unit + // 2. Stock tracking + const rawTrack = + merged.track_stock ?? + merged.trackStock ?? + child?.trackStock ?? + child?.track_stock ?? + parentArticle?.track_stock ?? + parentArticle?.trackStock; + + const trackStock = + rawTrack !== undefined + ? rawTrack !== false && rawTrack !== 0 && rawTrack !== '0' + : true; + + // 3. Stock & Unit let stockVal = null; - if (Array.isArray(merged.warehouses) && merged.warehouses.length > 0) { - stockVal = merged.warehouses.reduce((sum, wh) => sum + (Number(wh.stock) || 0), 0); - } else if (merged.stock != null && !Number.isNaN(Number(merged.stock))) { - stockVal = Number(merged.stock); - } else if (child?.stock != null && !Number.isNaN(Number(child.stock))) { - stockVal = Number(child.stock); + if (trackStock) { + if (Array.isArray(merged.warehouses) && merged.warehouses.length > 0) { + stockVal = merged.warehouses.reduce((sum, wh) => sum + (Number(wh.stock) || 0), 0); + } else if (merged.stock != null && !Number.isNaN(Number(merged.stock))) { + stockVal = Number(merged.stock); + } else if (child?.stock != null && !Number.isNaN(Number(child.stock))) { + stockVal = Number(child.stock); + } } const rawUnit = @@ -76,9 +92,9 @@ function getVariantDetails(child, allArticles, defaultTaxRate) { rawUnit && !['stk', 'stück', 'pc', 'stk.'].includes(rawUnit.trim().toLowerCase()) ? ` ${rawUnit}` : ''; - const stockDisplay = stockVal != null ? `${formatStock(stockVal)}${unit}` : null; + const stockDisplay = trackStock && stockVal != null ? `${formatStock(stockVal)}${unit}` : null; - // 3. EAN(s) + // 4. EAN(s) const eanCandidates = []; const rawEans = merged.eans ?? child?.eans; if (Array.isArray(rawEans)) { @@ -103,6 +119,7 @@ function getVariantDetails(child, allArticles, defaultTaxRate) { stockDisplay, primaryEan, allEans: eanCandidates, + trackStock, }; } @@ -199,7 +216,7 @@ export default class ArticleViewLists extends PureComponent { if (!this._cancelled && parent?.children) { this.ensureChildren(parent.children); } - }).catch(() => {}); + }).catch(() => { }); } void this.loadAllArticles(); @@ -220,7 +237,7 @@ export default class ArticleViewLists extends PureComponent { if (!this._cancelled && parent?.children) { this.ensureChildren(parent.children); } - }).catch(() => {}); + }).catch(() => { }); } else { const parent = getArticle(this.props.article.parentSku); if (parent?.children) { @@ -268,7 +285,7 @@ export default class ArticleViewLists extends PureComponent { if (!Array.isArray(children)) return; for (const child of children) { if (child?.sku && !getArticle(child.sku)) { - void artikelAutomat.actions.loadArticle(child.sku).catch(() => {}); + void artikelAutomat.actions.loadArticle(child.sku).catch(() => { }); } } } @@ -393,30 +410,41 @@ export default class ArticleViewLists extends PureComponent { const { selectedChildValueId, newChildText, isCustomChildValue, busy } = this.state; if (busy || !article?.sku) return; + const val = newChildText.trim(); const payload = {}; - if (isCustomChildValue) { - const val = newChildText.trim(); - if (!val) return; + + if (val && (isCustomChildValue || !selectedChildValueId)) { + payload.value = val; + } else if (selectedChildValueId) { + payload.attributeValueId = Number(selectedChildValueId); + } else if (val) { payload.value = val; } else { - if (!selectedChildValueId) return; - payload.attributeValueId = Number(selectedChildValueId); + return; } this.setState({ busy: true }); try { const api = this.getApi(); - await api.addChild(article.sku, payload); + const res = await api.addChild(article.sku, payload); if (this._cancelled) return; + if (res?.sku) { + void artikelAutomat.actions.loadArticle(res.sku).catch(() => { }); + } + await artikelAutomat.actions.reloadArticle(article.sku); if (this._cancelled) return; + void articleIndexAutomat.actions.reload().catch(() => { }); + void companyAutomat.actions.loadAttributes?.().catch?.(() => { }); + enqueueSnackbar('Variante erfolgreich angelegt.', { variant: 'success' }); this.setState({ busy: false, selectedChildValueId: '', newChildText: '', + isCustomChildValue: false, }); } catch (err) { if (this._cancelled) return; @@ -491,17 +519,17 @@ export default class ArticleViewLists extends PureComponent { const nextItems = existingIndex >= 0 ? currentItems.map((item, idx) => - idx === existingIndex ? { ...item, count: item.count + count } : item - ) + idx === existingIndex ? { ...item, count: item.count + count } : item + ) : [ - ...currentItems, - { - articleId: stuecklisteTargetArticle.id, - sku: stuecklisteTargetArticle.sku, - count, - sort: currentItems.length, - }, - ]; + ...currentItems, + { + articleId: stuecklisteTargetArticle.id, + sku: stuecklisteTargetArticle.sku, + count, + sort: currentItems.length, + }, + ]; this.setState({ busy: true }); try { @@ -615,20 +643,20 @@ export default class ArticleViewLists extends PureComponent { const nextOptions = existingIndex >= 0 ? currentOptions.map((opt, idx) => - idx === existingIndex - ? { ...opt, count: opt.count + count, mandated: Boolean(optionMandated) } - : opt - ) + idx === existingIndex + ? { ...opt, count: opt.count + count, mandated: Boolean(optionMandated) } + : opt + ) : [ - ...currentOptions, - { - articleId: optionTargetArticle.id, - sku: optionTargetArticle.sku, - count, - sort: currentOptions.length, - mandated: Boolean(optionMandated), - }, - ]; + ...currentOptions, + { + articleId: optionTargetArticle.id, + sku: optionTargetArticle.sku, + count, + sort: currentOptions.length, + mandated: Boolean(optionMandated), + }, + ]; this.setState({ busy: true }); try { @@ -834,70 +862,70 @@ export default class ArticleViewLists extends PureComponent { }} > {stuecklisteItems.map((item) => ( - + + + + + {item.name || item.sku} + + + {item.sku} + + + + + this.handleRemoveStuecklisteItem(item.sku)} sx={{ - display: 'flex', - alignItems: 'center', - justifyContent: 'space-between', - px: 1, - py: 0.4, - borderRadius: 1, - bgcolor: 'background.paper', - border: '1px solid', - borderColor: 'divider', + p: 0.25, + color: 'text.secondary', + '&:hover': { color: 'error.main' }, }} > - - - - - {item.name || item.sku} - - - {item.sku} - - - - - this.handleRemoveStuecklisteItem(item.sku)} - sx={{ - p: 0.25, - color: 'text.secondary', - '&:hover': { color: 'error.main' }, - }} - > - - - - )) + + + + )) } @@ -1044,81 +1072,81 @@ export default class ArticleViewLists extends PureComponent { }} > {optionsItems.map((opt) => ( - - - - - + + + + + {opt.name || opt.sku} + + + - {opt.name || opt.sku} - - - - {opt.sku} - - {opt.mandated ? ( - - ) : null} - + {opt.sku} + + {opt.mandated ? ( + + ) : null} - - this.handleRemoveOption(opt.sku)} - sx={{ - p: 0.25, - color: 'text.secondary', - '&:hover': { color: 'error.main' }, - }} - > - - - )) + + this.handleRemoveOption(opt.sku)} + sx={{ + p: 0.25, + color: 'text.secondary', + '&:hover': { color: 'error.main' }, + }} + > + + + + )) } @@ -1211,14 +1239,14 @@ export default class ArticleViewLists extends PureComponent { const siblings = hasSelf ? childrenList : [ - ...childrenList, - { - id: articleData.id, - sku: articleData.sku, - name: articleData.name, - attributeValue: variationValue, - }, - ]; + ...childrenList, + { + id: articleData.id, + sku: articleData.sku, + name: articleData.name, + attributeValue: variationValue, + }, + ]; return ( @@ -1348,7 +1376,8 @@ export default class ArticleViewLists extends PureComponent { stockDisplay, primaryEan, allEans, - } = getVariantDetails(sibling, allArticles, defaultTaxRate); + trackStock, + } = getVariantDetails(sibling, allArticles, defaultTaxRate, parentArticle); return ( 0 ? 'success.dark' : 'error.main', + color: !trackStock || stockVal == null ? 'text.disabled' : stockVal > 0 ? 'success.dark' : 'error.main', whiteSpace: 'nowrap', }} > @@ -1584,7 +1613,7 @@ export default class ArticleViewLists extends PureComponent { sx={{ fontSize: '0.74rem', fontWeight: 600, - color: stockVal == null ? 'text.disabled' : stockVal > 0 ? 'success.dark' : 'error.main', + color: !trackStock || stockVal == null ? 'text.disabled' : stockVal > 0 ? 'success.dark' : 'error.main', whiteSpace: 'nowrap', }} > @@ -1908,11 +1937,7 @@ export default class ArticleViewLists extends PureComponent { Varianten: - {children.length === 0 ? ( - - Noch keine Varianten angelegt. - - ) : ( + {children.length === 0 ? null : ( {children.map((child) => { const defaultTaxRate = this.state.company?.taxrate ?? companyAutomat.state.current?.taxrate ?? 19; @@ -1922,7 +1947,8 @@ export default class ArticleViewLists extends PureComponent { stockDisplay, primaryEan, allEans, - } = getVariantDetails(child, allArticles, defaultTaxRate); + trackStock, + } = getVariantDetails(child, allArticles, defaultTaxRate, articleData); return ( 0 ? 'success.dark' : 'error.main', + color: !trackStock || stockVal == null ? 'text.disabled' : stockVal > 0 ? 'success.dark' : 'error.main', whiteSpace: 'nowrap', }} > @@ -2077,7 +2103,6 @@ export default class ArticleViewLists extends PureComponent { size="small" disabled={busy} onClick={() => this.handleOpenRemoveDialog(child)} - title="Variante entfernen" sx={{ p: 0.35, color: 'text.secondary', @@ -2098,7 +2123,6 @@ export default class ArticleViewLists extends PureComponent { {isCustomChildValue || availableParentValues.length === 0 ? ( this.setState({ newChildText: e.target.value })} @@ -2143,34 +2167,31 @@ export default class ArticleViewLists extends PureComponent { )} - - - - {busy ? : } - - - + + {busy ? : } + {/* Toggle custom value / predefined value if values exist */} @@ -2205,16 +2226,16 @@ export default class ArticleViewLists extends PureComponent { )} {isStueckliste || - hasOptions || - activeCreatorMode === 'stueckliste' || - activeCreatorMode === 'options' + hasOptions || + activeCreatorMode === 'stueckliste' || + activeCreatorMode === 'options' ? this.renderCompoundManager( - isStueckliste, - hasOptions, - stuecklisteItems, - optionsItems, - selectableOtherArticles - ) + isStueckliste, + hasOptions, + stuecklisteItems, + optionsItems, + selectableOtherArticles + ) : this.renderStandardView(selectableAttributes, assignedAttributeIds)} @@ -2293,11 +2314,11 @@ export default class ArticleViewLists extends PureComponent { {confirmClearType === 'stueckliste' ? (hasOptions - ? 'Möchten Sie alle Komponenten aus dieser Stückliste entfernen? Die Optionen bleiben dabei erhalten.' - : 'Möchten Sie alle Komponenten aus dieser Stückliste entfernen und den Artikel wieder als Standard-Artikel führen?') + ? 'Möchten Sie alle Komponenten aus dieser Stückliste entfernen? Die Optionen bleiben dabei erhalten.' + : 'Möchten Sie alle Komponenten aus dieser Stückliste entfernen und den Artikel wieder als Standard-Artikel führen?') : (isStueckliste - ? 'Möchten Sie alle Optionen von diesem Artikel entfernen? Die Stückliste bleibt dabei erhalten.' - : 'Möchten Sie alle Optionen von diesem Artikel entfernen und ihn wieder als Standard-Artikel führen?')} + ? 'Möchten Sie alle Optionen von diesem Artikel entfernen? Die Stückliste bleibt dabei erhalten.' + : 'Möchten Sie alle Optionen von diesem Artikel entfernen und ihn wieder als Standard-Artikel führen?')}