This commit is contained in:
seb
2026-10-16 23:53:09 +02:00
parent 82db75ac0f
commit b3a81efe46
8 changed files with 2099 additions and 443 deletions

View File

@@ -47,7 +47,6 @@ export default class BookDeliveryDialog extends PureComponent {
let initialAmounts = {};
if (Array.isArray(props.summary?.lines)) {
for (const line of props.summary.lines) {
if (!line.trackStock) continue;
if (props.prefillLineId != null) {
initialAmounts[line.id] =
line.id === props.prefillLineId
@@ -175,7 +174,6 @@ export default class BookDeliveryDialog extends PureComponent {
const amounts = {};
if (Array.isArray(summary?.lines)) {
for (const line of summary.lines) {
if (!line.trackStock) continue;
if (prefillLineId != null) {
amounts[line.id] =
line.id === prefillLineId
@@ -210,7 +208,6 @@ export default class BookDeliveryDialog extends PureComponent {
if (!summary?.lines) return;
const amounts = {};
for (const line of summary.lines) {
if (!line.trackStock) continue;
amounts[line.id] = line.remainingAmount > 0 ? line.remainingAmount : 0;
}
this.setState({ amountsToBook: amounts });
@@ -221,7 +218,6 @@ export default class BookDeliveryDialog extends PureComponent {
if (!summary?.lines) return;
const amounts = {};
for (const line of summary.lines) {
if (!line.trackStock) continue;
amounts[line.id] = 0;
}
this.setState({ amountsToBook: amounts });
@@ -229,16 +225,16 @@ export default class BookDeliveryDialog extends PureComponent {
async handleConfirmBook() {
const { delivery, onBookSuccess, onClose } = this.props;
const { summary, amountsToBook, transactionText } = this.state;
const { summary, amountsToBook, transactionText, selectedWarehouseId } = this.state;
if (!summary?.lines) return;
const linesToBook = summary.lines
.filter((line) => line.trackStock)
.map((line) => ({
manifestarticleId: line.id,
sku: line.sku,
name: line.name,
amount: Number(amountsToBook[line.id] || 0),
trackStock: Boolean(line.trackStock),
}))
.filter((l) => l.amount > 0);
@@ -247,8 +243,8 @@ export default class BookDeliveryDialog extends PureComponent {
return;
}
const { selectedWarehouseId } = this.state;
if (!selectedWarehouseId) {
const hasTracked = linesToBook.some((l) => l.trackStock);
if (hasTracked && !selectedWarehouseId) {
this.setState({ warehouseError: 'Bitte wählen Sie ein Ziellager aus.' });
enqueueSnackbar('Bitte wählen Sie ein Ziellager aus.', { variant: 'warning' });
return;
@@ -265,7 +261,7 @@ export default class BookDeliveryDialog extends PureComponent {
const totalBookedQty = linesToBook.reduce((sum, l) => sum + l.amount, 0);
enqueueSnackbar(
`${linesToBook.length} Position${linesToBook.length === 1 ? '' : 'en'} (${totalBookedQty} Stk.) erfolgreich ins Lager gebucht.`,
`${linesToBook.length} Position${linesToBook.length === 1 ? '' : 'en'} (${totalBookedQty} Stk.) erfolgreich gebucht.`,
{ variant: 'success' }
);
@@ -387,12 +383,12 @@ export default class BookDeliveryDialog extends PureComponent {
renderLinesTable() {
const { summary, amountsToBook, isBooking } = this.state;
const lines = (summary?.lines || []).filter((l) => l.trackStock);
const lines = summary?.lines || [];
if (lines.length === 0) {
return (
<Alert severity="info" sx={{ my: 2 }}>
Diese Lieferung enthält keine lagergeführten Artikel zum Einbuchen.
Diese Lieferung enthält keine Positionen zum Verbuchen.
</Alert>
);
}
@@ -406,7 +402,7 @@ export default class BookDeliveryDialog extends PureComponent {
<TableCell sx={{ fontWeight: 600 }}>Artikel</TableCell>
<TableCell align="right" sx={{ fontWeight: 600 }}>Liefermenge</TableCell>
<TableCell align="right" sx={{ fontWeight: 600 }}>Bereits gebucht</TableCell>
<TableCell align="right" sx={{ fontWeight: 600, width: 140 }}>Jetzt einbuchen</TableCell>
<TableCell align="right" sx={{ fontWeight: 600, width: 140 }}>Jetzt verbuchen</TableCell>
</TableRow>
</TableHead>
<TableBody>
@@ -420,9 +416,19 @@ export default class BookDeliveryDialog extends PureComponent {
{line.sku || '–'}
</TableCell>
<TableCell sx={{ maxWidth: 280 }}>
<Typography variant="body2" sx={{ fontWeight: 500 }} noWrap>
{line.name || '–'}
</Typography>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<Typography variant="body2" sx={{ fontWeight: 500 }} noWrap>
{line.name || '–'}
</Typography>
{!line.trackStock && (
<Chip
size="small"
label="Ohne Lagerbestand"
variant="outlined"
sx={{ fontSize: '0.7rem', height: 20, color: 'text.secondary', borderColor: 'divider' }}
/>
)}
</Box>
</TableCell>
<TableCell align="right">
<Typography variant="body2" sx={{ fontWeight: 600 }}>
@@ -493,8 +499,14 @@ export default class BookDeliveryDialog extends PureComponent {
warehouseError,
} = this.state;
const lines = (summary?.lines || []).filter((l) => l.trackStock);
const hasTrackStock = lines.length > 0;
const lines = summary?.lines || [];
const hasLines = lines.length > 0;
const hasTrackStock = lines.some((l) => l.trackStock);
const linesWithAmountsToBook = lines.filter(
(l) => Number(amountsToBook[l.id]) > 0
);
const hasTrackedLinesToBook = linesWithAmountsToBook.some((l) => l.trackStock);
const prefillLine =
this.props.prefillLineId != null
? lines.find((l) => l.id === this.props.prefillLineId)
@@ -503,12 +515,10 @@ export default class BookDeliveryDialog extends PureComponent {
(sum, l) => sum + (Number(amountsToBook[l.id]) || 0),
0
);
const countLinesToBook = lines.filter(
(l) => Number(amountsToBook[l.id]) > 0
).length;
const isFullyBooked = hasTrackStock && summary?.status === 'booked';
const countLinesToBook = linesWithAmountsToBook.length;
const isFullyBooked = hasLines && summary?.status === 'booked';
const selectedWarehouse = warehouses.find((w) => w.id === selectedWarehouseId);
const isWarehouseMissing = !selectedWarehouseId;
const isWarehouseMissing = hasTrackedLinesToBook && !selectedWarehouseId;
return (
<AppDialog
@@ -528,7 +538,7 @@ export default class BookDeliveryDialog extends PureComponent {
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<Inventory2OutlinedIcon color="primary" />
<Typography variant="h6" component="span" sx={{ fontWeight: 600 }}>
Lieferung {delivery?.number || ''} ins Lager buchen
Lieferung {delivery?.number || ''} verbuchen
</Typography>
</Box>
<IconButton size="small" onClick={onClose} disabled={isBooking}>
@@ -552,13 +562,13 @@ export default class BookDeliveryDialog extends PureComponent {
<>
{prefillLine && (
<Alert severity="info" sx={{ mb: 2 }}>
Vorausgewählt zum Einbuchen: Position{' '}
Vorausgewählt zum Verbuchen: Position{' '}
<strong>{prefillLine.sku ? `SKU ${prefillLine.sku}` : prefillLine.name}</strong> ({amountsToBook[prefillLine.id] || 0} Stk.). Andere Positionen stehen auf 0.
</Alert>
)}
{this.renderLinesTable()}
{!isFullyBooked && hasTrackStock && (
{!isFullyBooked && hasLines && (
<Box sx={{ display: 'flex', gap: 1, mb: 2 }}>
<Button
size="small"
@@ -580,13 +590,13 @@ export default class BookDeliveryDialog extends PureComponent {
</Box>
)}
{hasTrackStock && warehouses.length === 0 && !isFullyBooked && (
{hasTrackedLinesToBook && warehouses.length === 0 && !isFullyBooked && (
<Alert severity="error" sx={{ mb: 2 }}>
Es ist noch kein Lager eingerichtet. Bitte legen Sie unter „Artikel → Lager“ zuerst ein Lager an.
Es ist noch kein Lager eingerichtet. Für lagergeführte Artikel legen Sie bitte unter „Artikel → Lager“ zuerst ein Lager an.
</Alert>
)}
{hasTrackStock && (
{hasLines && (
<Box
sx={{
display: 'flex',
@@ -595,44 +605,52 @@ export default class BookDeliveryDialog extends PureComponent {
flexDirection: { xs: 'column', sm: 'row' },
}}
>
<FormControl
size="small"
required
error={Boolean(warehouseError)}
disabled={isBooking || isFullyBooked}
sx={{ minWidth: { sm: 240 }, flex: { sm: '0 0 auto' } }}
>
<InputLabel id="warehouse-select-label">Ziellager *</InputLabel>
<Select
labelId="warehouse-select-label"
id="warehouse-select"
value={selectedWarehouseId ?? ''}
label="Ziellager *"
onChange={this.handleWarehouseChange}
startAdornment={
<WarehouseIcon
sx={{ mr: 1, color: 'text.secondary', fontSize: 20 }}
/>
}
{hasTrackStock && (
<FormControl
size="small"
required={hasTrackedLinesToBook}
error={Boolean(warehouseError)}
disabled={isBooking || isFullyBooked}
sx={{ minWidth: { sm: 240 }, flex: { sm: '0 0 auto' } }}
>
{warehouses.length === 0 ? (
<MenuItem value="" disabled>
Keine Lager vorhanden
</MenuItem>
) : (
warehouses.map((wh) => (
<MenuItem key={wh.id} value={wh.id}>
{wh.name}
<InputLabel id="warehouse-select-label">
Ziellager {hasTrackedLinesToBook ? '*' : ''}
</InputLabel>
<Select
labelId="warehouse-select-label"
id="warehouse-select"
value={selectedWarehouseId ?? ''}
label={`Ziellager ${hasTrackedLinesToBook ? '*' : ''}`}
onChange={this.handleWarehouseChange}
startAdornment={
<WarehouseIcon
sx={{ mr: 1, color: 'text.secondary', fontSize: 20 }}
/>
}
>
{warehouses.length === 0 ? (
<MenuItem value="" disabled>
Keine Lager vorhanden
</MenuItem>
))
) : (
warehouses.map((wh) => (
<MenuItem key={wh.id} value={wh.id}>
{wh.name}
</MenuItem>
))
)}
</Select>
{warehouseError ? (
<FormHelperText>{warehouseError}</FormHelperText>
) : (
<FormHelperText>
{hasTrackedLinesToBook
? 'Pflichtfeld: Ziellager für lagergeführte Artikel'
: 'Ziellager (optional)'}
</FormHelperText>
)}
</Select>
{warehouseError ? (
<FormHelperText>{warehouseError}</FormHelperText>
) : (
<FormHelperText>Pflichtfeld: Ziellager für die Buchung</FormHelperText>
)}
</FormControl>
</FormControl>
)}
<TextField
fullWidth
@@ -648,26 +666,29 @@ export default class BookDeliveryDialog extends PureComponent {
{isFullyBooked ? (
<Alert severity="success" icon={<CheckCircleOutlineOutlinedIcon />}>
Alle Artikel dieser Lieferung sind bereits vollständig im Lager verbucht.
Alle Positionen dieser Lieferung sind bereits vollständig im Ledger verbucht.
</Alert>
) : hasTrackStock && totalToBook > 0 ? (
<Alert severity={selectedWarehouseId ? 'info' : 'warning'}>
{selectedWarehouseId ? (
) : countLinesToBook > 0 ? (
<Alert severity={isWarehouseMissing ? 'warning' : 'info'}>
{isWarehouseMissing ? (
<>
Es werden <strong>{totalToBook} Stück</strong> für{' '}
<strong>{countLinesToBook} Position{countLinesToBook === 1 ? '' : 'en'}</strong> als Lagerzugang (DELIVERY) in das Lager{' '}
<strong>„{selectedWarehouse?.name || '–'}“</strong> gebucht.
Bitte wählen Sie ein <strong>Ziellager</strong> aus, um die lagergeführten Artikel zu buchen.
</>
) : (
<>
Bitte wählen Sie ein <strong>Ziellager</strong> aus, um die Buchung von{' '}
<strong>{totalToBook} Stück</strong> durchzuführen.
Es werden <strong>{totalToBook} Stück</strong> für{' '}
<strong>{countLinesToBook} Position{countLinesToBook === 1 ? '' : 'en'}</strong>{' '}
{hasTrackedLinesToBook && selectedWarehouse ? (
<>in das Lager <strong>„{selectedWarehouse?.name || '–'}“</strong> verbucht.</>
) : (
<>als Dokumentenbuchung im Ledger verbucht (ohne Lagerbestandsführung).</>
)}
</>
)}
</Alert>
) : hasTrackStock ? (
) : hasLines ? (
<Alert severity="warning">
Wählen Sie mindestens eine Menge größer als 0 aus, um den Lagerzugang zu buchen.
Wählen Sie mindestens eine Menge größer als 0 aus, um Positionen zu verbuchen.
</Alert>
) : null}
</>
@@ -679,7 +700,7 @@ export default class BookDeliveryDialog extends PureComponent {
{isFullyBooked ? 'Schließen' : 'Abbrechen'}
</Button>
{!isFullyBooked && lines.length > 0 && (
{!isFullyBooked && hasLines && (
<Button
variant="contained"
color="primary"
@@ -694,7 +715,7 @@ export default class BookDeliveryDialog extends PureComponent {
}
sx={{ minWidth: 160, fontWeight: 600 }}
>
{isBooking ? 'Wird gebucht...' : 'Jetzt ins Lager buchen'}
{isBooking ? 'Wird gebucht...' : 'Jetzt verbuchen'}
</Button>
)}
</DialogActions>

File diff suppressed because it is too large Load Diff