u
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -64,7 +64,20 @@ export {
|
||||
buildArticleIndex,
|
||||
selectArticleIndexItems,
|
||||
} from './articleIndexAutomat';
|
||||
export { default as deliveryAutomat } from './deliveryAutomat';
|
||||
export {
|
||||
default as deliveryAutomat,
|
||||
CHUNK_SIZE as DELIVERY_CHUNK_SIZE,
|
||||
MAX_LRU_CHUNKS as DELIVERY_MAX_LRU_CHUNKS,
|
||||
selectDeliveries,
|
||||
selectDeliveryTotal,
|
||||
selectDeliveryUnfilteredTotal,
|
||||
selectDeliveryPagination,
|
||||
selectOnlyUnbooked,
|
||||
isDeliveryBooked,
|
||||
getDeliveryUnbookedCount,
|
||||
getChunkStats as getDeliveryChunkStats,
|
||||
subscribeChunkStats as subscribeDeliveryChunkStats,
|
||||
} from './deliveryAutomat';
|
||||
export { default as quoteAutomat } from './quoteAutomat';
|
||||
export {
|
||||
default as orderAutomat,
|
||||
|
||||
@@ -32,6 +32,7 @@ import warehouseAutomat from './warehouseAutomat';
|
||||
import attributeAutomat from './attributeAutomat';
|
||||
import propertyAutomat from './propertyAutomat';
|
||||
import supplierAutomat from './supplierAutomat';
|
||||
import deliveryAutomat from './deliveryAutomat';
|
||||
import orderAutomat from './orderAutomat';
|
||||
import quoteAutomat from './quoteAutomat';
|
||||
import shipmentAutomat from './shipmentAutomat';
|
||||
@@ -264,6 +265,12 @@ function connect() {
|
||||
});
|
||||
});
|
||||
|
||||
addTrackedListener(es, 'delivery', () => {
|
||||
void deliveryAutomat.actions.reload().catch((err) => {
|
||||
console.error('[sse] delivery refresh failed', err);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -40,17 +40,20 @@ import orderAutomat, {
|
||||
} from '../automats/orderAutomat';
|
||||
import quoteAutomat from '../automats/quoteAutomat';
|
||||
import shipmentAutomat from '../automats/shipmentAutomat';
|
||||
import deliveryAutomat from '../automats/deliveryAutomat';
|
||||
import { formatPrice } from '../utils/price';
|
||||
|
||||
function getAutomatFor(target) {
|
||||
if (target === 'quote') return quoteAutomat;
|
||||
if (target === 'shipment') return shipmentAutomat;
|
||||
if (target === 'delivery') return deliveryAutomat;
|
||||
return orderAutomat;
|
||||
}
|
||||
|
||||
function getInitialTarget() {
|
||||
if (typeof window !== 'undefined') {
|
||||
const p = window.location.pathname;
|
||||
if (p.startsWith('/lieferung')) return 'delivery';
|
||||
if (p.startsWith('/auftrag/ausliefern')) return 'shipment';
|
||||
if (p.startsWith('/auftrag/bestellung')) return 'order';
|
||||
if (p.startsWith('/auftrag')) return 'quote';
|
||||
@@ -296,6 +299,10 @@ class ChunkCacheMonitor extends PureComponent {
|
||||
if (p.onlyUnpaid) automat.actions.setOnlyUnpaid(true);
|
||||
if (p.onlyUndelivered) automat.actions.setOnlyUndelivered(true);
|
||||
}
|
||||
if (this.state.target === 'delivery') {
|
||||
if (p.onlyUnbooked) automat.actions.setOnlyUnbooked(true);
|
||||
if (p.supplierId) automat.actions.setSupplierId(p.supplierId);
|
||||
}
|
||||
if (this.state.target === 'shipment') {
|
||||
if (p.stateFilter) automat.actions.setStateFilter(p.stateFilter);
|
||||
}
|
||||
@@ -723,11 +730,15 @@ class ChunkCacheMonitor extends PureComponent {
|
||||
{chunkOrders.map(({ item: order, index }) => {
|
||||
const isOrd = this.state.target === 'order';
|
||||
const isShip = this.state.target === 'shipment';
|
||||
const isDeliv = this.state.target === 'delivery';
|
||||
const paid = isOrd ? isOrderPaid(order) : false;
|
||||
const delivered = isOrd ? isOrderDelivered(order) : false;
|
||||
const gross = order.grossTotal != null ? Number(order.grossTotal) : (order.lines ? orderGrossTotal(order.lines) : 0);
|
||||
const customer = order.customerName || (order.entityId ? `Kunde #${order.entityId}` : '–');
|
||||
const customer = isDeliv
|
||||
? (order.supplierName || (order.supplierId ? `Lieferant #${order.supplierId}` : '–'))
|
||||
: (order.customerName || (order.entityId ? `Kunde #${order.entityId}` : '–'));
|
||||
const posCount = order.positions != null ? order.positions : (order.lines?.length ?? 0);
|
||||
const unbooked = order.ledger?.unbookedPositions ?? 0;
|
||||
|
||||
return (
|
||||
<Box
|
||||
@@ -780,6 +791,14 @@ class ChunkCacheMonitor extends PureComponent {
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{isDeliv && (
|
||||
<Chip
|
||||
size="small"
|
||||
label={unbooked === 0 ? 'Gebucht' : `${unbooked} Ungebucht`}
|
||||
color={unbooked === 0 ? 'success' : 'warning'}
|
||||
sx={{ height: 20, fontSize: '0.7rem' }}
|
||||
/>
|
||||
)}
|
||||
{isShip && (
|
||||
<>
|
||||
<Chip
|
||||
@@ -1072,6 +1091,14 @@ class ChunkCacheMonitor extends PureComponent {
|
||||
onClick={() => this.switchTarget('order')}
|
||||
sx={{ cursor: 'pointer', height: 24, fontSize: '0.72rem', fontWeight: this.state.target === 'order' ? 700 : 500 }}
|
||||
/>
|
||||
<Chip
|
||||
size="small"
|
||||
color={this.state.target === 'delivery' ? 'primary' : 'default'}
|
||||
variant={this.state.target === 'delivery' ? 'filled' : 'outlined'}
|
||||
label="Lieferungen (deliveryAutomat)"
|
||||
onClick={() => this.switchTarget('delivery')}
|
||||
sx={{ cursor: 'pointer', height: 24, fontSize: '0.72rem', fontWeight: this.state.target === 'delivery' ? 700 : 500 }}
|
||||
/>
|
||||
<Chip
|
||||
size="small"
|
||||
color={this.state.target === 'shipment' ? 'primary' : 'default'}
|
||||
|
||||
@@ -124,8 +124,8 @@ export async function fetchDeliveryLedgerSummary(deliveryId, { deliveryApi = def
|
||||
});
|
||||
const bookedAmount = deliveryEntries.reduce((sum, e) => sum + Number(e.amount || 0), 0);
|
||||
const targetAmount = Number(line.amount || 0);
|
||||
const remainingAmount = trackStock ? Math.max(0, targetAmount - bookedAmount) : 0;
|
||||
const isBooked = trackStock ? (targetAmount > 0 ? bookedAmount >= targetAmount : bookedAmount > 0) : true;
|
||||
const remainingAmount = Math.max(0, targetAmount - bookedAmount);
|
||||
const isBooked = targetAmount > 0 ? bookedAmount >= targetAmount : bookedAmount > 0;
|
||||
|
||||
return {
|
||||
...line,
|
||||
@@ -134,21 +134,20 @@ export async function fetchDeliveryLedgerSummary(deliveryId, { deliveryApi = def
|
||||
remainingAmount,
|
||||
isBooked,
|
||||
trackStock,
|
||||
isBookable: trackStock,
|
||||
isBookable: true,
|
||||
ledgerEntries: deliveryEntries,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
const stockLines = linesWithLedger.filter((l) => l.trackStock);
|
||||
const totalPositions = stockLines.length;
|
||||
const bookedPositions = stockLines.filter((l) => l.isBooked).length;
|
||||
const totalQuantity = stockLines.reduce((sum, l) => sum + l.targetAmount, 0);
|
||||
const bookedQuantity = stockLines.reduce((sum, l) => sum + l.bookedAmount, 0);
|
||||
const hasTrackStock = stockLines.length > 0;
|
||||
const totalPositions = linesWithLedger.length;
|
||||
const bookedPositions = linesWithLedger.filter((l) => l.isBooked).length;
|
||||
const totalQuantity = linesWithLedger.reduce((sum, l) => sum + l.targetAmount, 0);
|
||||
const bookedQuantity = linesWithLedger.reduce((sum, l) => sum + l.bookedAmount, 0);
|
||||
const hasTrackStock = linesWithLedger.some((l) => l.trackStock);
|
||||
|
||||
let status;
|
||||
if (!hasTrackStock) {
|
||||
if (totalPositions === 0) {
|
||||
status = 'empty';
|
||||
} else if (bookedPositions === totalPositions && bookedQuantity >= totalQuantity) {
|
||||
status = 'booked';
|
||||
@@ -176,8 +175,8 @@ export async function fetchDeliveryLedgerSummary(deliveryId, { deliveryApi = def
|
||||
*
|
||||
* @param {Object} params
|
||||
* @param {Object} params.delivery - The delivery object (used for transaction memo and fallback)
|
||||
* @param {Array<{ manifestarticleId?: number, id?: number, amount: number, sku?: string }>} params.linesToBook
|
||||
* @param {number|string} params.warehouseId - Mandatory warehouse ID
|
||||
* @param {Array<{ manifestarticleId?: number, id?: number, amount: number, sku?: string, trackStock?: boolean }>} params.linesToBook
|
||||
* @param {number|string} [params.warehouseId] - Warehouse ID (mandatory only when at least one line tracks stock)
|
||||
* @param {Object} [params.stockApi]
|
||||
* @param {string} [params.transactionText]
|
||||
* @returns {Promise<Array<Object>>}
|
||||
@@ -189,15 +188,17 @@ export async function bookDeliveryLines({
|
||||
stockApi = defaultStockApi,
|
||||
transactionText,
|
||||
}) {
|
||||
const numericWarehouseId = Number(warehouseId);
|
||||
if (!numericWarehouseId || numericWarehouseId <= 0) {
|
||||
throw new Error('Bitte wählen Sie ein Lager aus.');
|
||||
}
|
||||
|
||||
if (!Array.isArray(linesToBook) || linesToBook.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const numericWarehouseId = Number(warehouseId) || null;
|
||||
const hasTrackedLines = linesToBook.some((l) => l.trackStock);
|
||||
|
||||
if (hasTrackedLines && (!numericWarehouseId || numericWarehouseId <= 0)) {
|
||||
throw new Error('Bitte wählen Sie ein Lager aus.');
|
||||
}
|
||||
|
||||
const memo = String(
|
||||
transactionText != null && transactionText !== ''
|
||||
? transactionText
|
||||
|
||||
@@ -136,7 +136,9 @@ export function getMaxDocumentNumber(kind = 'quote') {
|
||||
const prefixStyle = refSeq?.prefix ?? '';
|
||||
|
||||
let prefix = '';
|
||||
if (
|
||||
if (kind === 'delivery') {
|
||||
prefix = prefixStyle.startsWith('DEL-') ? 'DEL-' : (prefixStyle.startsWith('L-') ? 'L-' : 'LS-');
|
||||
} else if (
|
||||
prefixStyle.startsWith('ART-') ||
|
||||
prefixStyle.startsWith('LS-') ||
|
||||
prefixStyle.startsWith('KD-') ||
|
||||
|
||||
Reference in New Issue
Block a user