u
This commit is contained in:
@@ -27,6 +27,7 @@ import CloseIcon from '@mui/icons-material/Close';
|
|||||||
import Inventory2OutlinedIcon from '@mui/icons-material/Inventory2Outlined';
|
import Inventory2OutlinedIcon from '@mui/icons-material/Inventory2Outlined';
|
||||||
import CheckCircleOutlineOutlinedIcon from '@mui/icons-material/CheckCircleOutlineOutlined';
|
import CheckCircleOutlineOutlinedIcon from '@mui/icons-material/CheckCircleOutlineOutlined';
|
||||||
import WarehouseIcon from '@mui/icons-material/Warehouse';
|
import WarehouseIcon from '@mui/icons-material/Warehouse';
|
||||||
|
import AddIcon from '@mui/icons-material/Add';
|
||||||
import { enqueueSnackbar } from 'notistack';
|
import { enqueueSnackbar } from 'notistack';
|
||||||
import { notifyError } from '../../utils/notify';
|
import { notifyError } from '../../utils/notify';
|
||||||
import { formatDate } from './manifestConfig';
|
import { formatDate } from './manifestConfig';
|
||||||
@@ -34,7 +35,8 @@ import {
|
|||||||
fetchDeliveryLedgerSummary,
|
fetchDeliveryLedgerSummary,
|
||||||
bookDeliveryLines,
|
bookDeliveryLines,
|
||||||
} from '../../utils/deliveryLedger';
|
} from '../../utils/deliveryLedger';
|
||||||
import { getArticle } from '../../automats/artikelAutomat';
|
import { formatStock } from '../article/searchFormat';
|
||||||
|
import artikelAutomat, { getArticle } from '../../automats/artikelAutomat';
|
||||||
import warehouseAutomat from '../../automats/warehouseAutomat';
|
import warehouseAutomat from '../../automats/warehouseAutomat';
|
||||||
import { supplier as supplierApi } from '../../api';
|
import { supplier as supplierApi } from '../../api';
|
||||||
import deliveryEditorAutomat, { buildSupplierArticlesMap } from '../../automats/deliveryEditorAutomat';
|
import deliveryEditorAutomat, { buildSupplierArticlesMap } from '../../automats/deliveryEditorAutomat';
|
||||||
@@ -141,6 +143,7 @@ export default class BookDeliveryDialog extends PureComponent {
|
|||||||
selectedWarehouseId: initialWarehouses.length === 1 ? initialWarehouses[0].id : '',
|
selectedWarehouseId: initialWarehouses.length === 1 ? initialWarehouses[0].id : '',
|
||||||
warehouseError: null,
|
warehouseError: null,
|
||||||
supplierArticlesMap: initialSupplierMap,
|
supplierArticlesMap: initialSupplierMap,
|
||||||
|
enablingTrackStockBySku: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
this.handleAmountChange = this.handleAmountChange.bind(this);
|
this.handleAmountChange = this.handleAmountChange.bind(this);
|
||||||
@@ -149,6 +152,7 @@ export default class BookDeliveryDialog extends PureComponent {
|
|||||||
this.handleBookAll = this.handleBookAll.bind(this);
|
this.handleBookAll = this.handleBookAll.bind(this);
|
||||||
this.handleResetAmounts = this.handleResetAmounts.bind(this);
|
this.handleResetAmounts = this.handleResetAmounts.bind(this);
|
||||||
this.handleConfirmBook = this.handleConfirmBook.bind(this);
|
this.handleConfirmBook = this.handleConfirmBook.bind(this);
|
||||||
|
this.handleEnableTrackStock = this.handleEnableTrackStock.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadSupplierArticlesIfNeeded() {
|
loadSupplierArticlesIfNeeded() {
|
||||||
@@ -175,6 +179,9 @@ export default class BookDeliveryDialog extends PureComponent {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
this.unsubArticle = artikelAutomat.subscribe(() => {
|
||||||
|
this.forceUpdate();
|
||||||
|
});
|
||||||
void warehouseAutomat.actions.load().catch(() => {});
|
void warehouseAutomat.actions.load().catch(() => {});
|
||||||
this.loadSupplierArticlesIfNeeded();
|
this.loadSupplierArticlesIfNeeded();
|
||||||
|
|
||||||
@@ -185,6 +192,75 @@ export default class BookDeliveryDialog extends PureComponent {
|
|||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.unsubWarehouse?.();
|
this.unsubWarehouse?.();
|
||||||
|
this.unsubArticle?.();
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleEnableTrackStock(line, targetSku) {
|
||||||
|
if (!targetSku) return;
|
||||||
|
this.setState((prev) => ({
|
||||||
|
enablingTrackStockBySku: {
|
||||||
|
...prev.enablingTrackStockBySku,
|
||||||
|
[targetSku]: true,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
try {
|
||||||
|
await artikelAutomat.actions.setTrackStock(targetSku, true);
|
||||||
|
this.setState((prev) => {
|
||||||
|
if (!prev.summary?.lines) {
|
||||||
|
return {
|
||||||
|
enablingTrackStockBySku: {
|
||||||
|
...prev.enablingTrackStockBySku,
|
||||||
|
[targetSku]: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const updatedLines = prev.summary.lines.map((l) => {
|
||||||
|
const rawSku = l.sku ? String(l.sku).trim() : '';
|
||||||
|
const lineOwnSku = l.articleSku || l.article?.sku || '';
|
||||||
|
if (
|
||||||
|
l.id === line.id ||
|
||||||
|
rawSku === targetSku ||
|
||||||
|
lineOwnSku === targetSku ||
|
||||||
|
(l.article && String(l.article.sku) === targetSku)
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
...l,
|
||||||
|
trackStock: true,
|
||||||
|
article: l.article
|
||||||
|
? { ...l.article, track_stock: true }
|
||||||
|
: { sku: targetSku, track_stock: true },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
summary: {
|
||||||
|
...prev.summary,
|
||||||
|
hasTrackStock: true,
|
||||||
|
lines: updatedLines,
|
||||||
|
},
|
||||||
|
enablingTrackStockBySku: {
|
||||||
|
...prev.enablingTrackStockBySku,
|
||||||
|
[targetSku]: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
enqueueSnackbar(`Lagerbestand für „${targetSku}“ aktiviert.`, { variant: 'success' });
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[BookDeliveryDialog] Failed to enable track_stock:', err);
|
||||||
|
enqueueSnackbar(
|
||||||
|
err?.message || `Fehler beim Aktivieren des Lagerbestands für „${targetSku}“.`,
|
||||||
|
{ variant: 'error' }
|
||||||
|
);
|
||||||
|
this.setState((prev) => ({
|
||||||
|
enablingTrackStockBySku: {
|
||||||
|
...prev.enablingTrackStockBySku,
|
||||||
|
[targetSku]: false,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
@@ -472,7 +548,7 @@ export default class BookDeliveryDialog extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderLinesTable() {
|
renderLinesTable() {
|
||||||
const { summary, amountsToBook, isBooking, supplierArticlesMap } = this.state;
|
const { summary, amountsToBook, isBooking, supplierArticlesMap, enablingTrackStockBySku } = this.state;
|
||||||
const lines = summary?.lines || [];
|
const lines = summary?.lines || [];
|
||||||
|
|
||||||
if (lines.length === 0) {
|
if (lines.length === 0) {
|
||||||
@@ -493,6 +569,7 @@ export default class BookDeliveryDialog extends PureComponent {
|
|||||||
<TableCell sx={{ fontWeight: 600 }}>Eigene SKU</TableCell>
|
<TableCell sx={{ fontWeight: 600 }}>Eigene SKU</TableCell>
|
||||||
<TableCell sx={{ fontWeight: 600 }}>EAN</TableCell>
|
<TableCell sx={{ fontWeight: 600 }}>EAN</TableCell>
|
||||||
<TableCell sx={{ fontWeight: 600 }}>Artikel</TableCell>
|
<TableCell sx={{ fontWeight: 600 }}>Artikel</TableCell>
|
||||||
|
<TableCell align="right" sx={{ fontWeight: 600 }}>Bestand</TableCell>
|
||||||
<TableCell align="right" sx={{ fontWeight: 600 }}>Liefermenge</TableCell>
|
<TableCell align="right" sx={{ fontWeight: 600 }}>Liefermenge</TableCell>
|
||||||
<TableCell align="right" sx={{ fontWeight: 600 }}>Bereits gebucht</TableCell>
|
<TableCell align="right" sx={{ fontWeight: 600 }}>Bereits gebucht</TableCell>
|
||||||
<TableCell align="right" sx={{ fontWeight: 600, width: 140 }}>Jetzt verbuchen</TableCell>
|
<TableCell align="right" sx={{ fontWeight: 600, width: 140 }}>Jetzt verbuchen</TableCell>
|
||||||
@@ -512,6 +589,46 @@ export default class BookDeliveryDialog extends PureComponent {
|
|||||||
line.article ||
|
line.article ||
|
||||||
(ownSku && ownSku !== '–' ? getArticle(ownSku) : null) ||
|
(ownSku && ownSku !== '–' ? getArticle(ownSku) : null) ||
|
||||||
(line.sku ? getArticle(line.sku) : null);
|
(line.sku ? getArticle(line.sku) : null);
|
||||||
|
const targetSku =
|
||||||
|
cachedArticle?.sku ||
|
||||||
|
(ownSku && ownSku !== '–' ? ownSku : null) ||
|
||||||
|
(line.sku ? String(line.sku).trim() : null);
|
||||||
|
|
||||||
|
if (targetSku && !cachedArticle) {
|
||||||
|
void artikelAutomat.actions.loadArticle(targetSku).catch(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
|
const isTracked =
|
||||||
|
Boolean(line.trackStock) ||
|
||||||
|
(cachedArticle?.track_stock !== undefined
|
||||||
|
? cachedArticle.track_stock !== false &&
|
||||||
|
cachedArticle.track_stock !== 0 &&
|
||||||
|
cachedArticle.track_stock !== '0'
|
||||||
|
: false);
|
||||||
|
|
||||||
|
const isEnablingThis = targetSku ? Boolean(enablingTrackStockBySku?.[targetSku]) : false;
|
||||||
|
|
||||||
|
let currentStock = null;
|
||||||
|
if (cachedArticle) {
|
||||||
|
if (Array.isArray(cachedArticle.warehouses) && cachedArticle.warehouses.length > 0) {
|
||||||
|
currentStock = cachedArticle.warehouses.reduce(
|
||||||
|
(sum, wh) => sum + (Number(wh.stock) || 0),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
} else if (cachedArticle.stock != null) {
|
||||||
|
currentStock = Number(cachedArticle.stock);
|
||||||
|
}
|
||||||
|
} else if (line.stock != null) {
|
||||||
|
currentStock = Number(line.stock);
|
||||||
|
}
|
||||||
|
|
||||||
|
const warehouseBreakdown =
|
||||||
|
Array.isArray(cachedArticle?.warehouses) && cachedArticle.warehouses.length > 0
|
||||||
|
? cachedArticle.warehouses
|
||||||
|
.map((w) => `${w.name || 'Lager'}: ${formatStock(w.stock ?? 0)}`)
|
||||||
|
.join(' • ')
|
||||||
|
: null;
|
||||||
|
|
||||||
const eans = line.ean
|
const eans = line.ean
|
||||||
? [line.ean]
|
? [line.ean]
|
||||||
: line.eans || cachedArticle?.eans || cachedArticle?.articleean || [];
|
: line.eans || cachedArticle?.eans || cachedArticle?.articleean || [];
|
||||||
@@ -539,6 +656,57 @@ export default class BookDeliveryDialog extends PureComponent {
|
|||||||
{line.name || '–'}
|
{line.name || '–'}
|
||||||
</Typography>
|
</Typography>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
<TableCell align="right" title={warehouseBreakdown || undefined}>
|
||||||
|
{isTracked ? (
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
sx={{
|
||||||
|
fontFamily: 'monospace',
|
||||||
|
fontSize: '0.85rem',
|
||||||
|
color: 'text.primary',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{currentStock != null ? formatStock(currentStock) : '0'}
|
||||||
|
</Typography>
|
||||||
|
) : targetSku ? (
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
variant="outlined"
|
||||||
|
color="primary"
|
||||||
|
disabled={isBooking || isEnablingThis}
|
||||||
|
onClick={() => this.handleEnableTrackStock(line, targetSku)}
|
||||||
|
startIcon={
|
||||||
|
isEnablingThis ? (
|
||||||
|
<CircularProgress size={12} color="inherit" />
|
||||||
|
) : (
|
||||||
|
<AddIcon sx={{ fontSize: 13 }} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
sx={{
|
||||||
|
height: 22,
|
||||||
|
fontSize: '0.68rem',
|
||||||
|
textTransform: 'none',
|
||||||
|
py: 0,
|
||||||
|
px: 0.75,
|
||||||
|
minWidth: 'auto',
|
||||||
|
fontWeight: 600,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Aktivieren
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
sx={{
|
||||||
|
fontFamily: 'monospace',
|
||||||
|
fontSize: '0.85rem',
|
||||||
|
color: 'text.disabled',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
—
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
<TableCell align="right">
|
<TableCell align="right">
|
||||||
<Typography variant="body2" sx={{ fontWeight: 600 }}>
|
<Typography variant="body2" sx={{ fontWeight: 600 }}>
|
||||||
{line.targetAmount}
|
{line.targetAmount}
|
||||||
|
|||||||
@@ -212,7 +212,9 @@ class ManifestFormLine extends PureComponent {
|
|||||||
? `Gebucht: ${ledgerLine.bookedAmount} Stk.`
|
? `Gebucht: ${ledgerLine.bookedAmount} Stk.`
|
||||||
: isPartial
|
: isPartial
|
||||||
? `Gebucht: ${ledgerLine.bookedAmount}/${ledgerLine.targetAmount} Stk.`
|
? `Gebucht: ${ledgerLine.bookedAmount}/${ledgerLine.targetAmount} Stk.`
|
||||||
: 'Verbuchen: offen';
|
: null;
|
||||||
|
|
||||||
|
if (!label) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip title={tooltipTitle}>
|
<Tooltip title={tooltipTitle}>
|
||||||
@@ -1158,9 +1160,11 @@ class ManifestFormLine extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.props.ledgerLine) {
|
if (this.props.ledgerLine) {
|
||||||
|
const chip = this.renderLedgerChip();
|
||||||
|
if (!chip) return null;
|
||||||
return (
|
return (
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, py: 0.25 }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, py: 0.25 }}>
|
||||||
{this.renderLedgerChip()}
|
{chip}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user