diff --git a/src/components/manifest/ManifestFormLine.jsx b/src/components/manifest/ManifestFormLine.jsx
index 8b59624..3828b57 100644
--- a/src/components/manifest/ManifestFormLine.jsx
+++ b/src/components/manifest/ManifestFormLine.jsx
@@ -30,8 +30,15 @@ import { articleSupplierAutomat } from '../../automats/articleDetailAutomat';
import { selectCompanyTaxrate } from '../../automats/companyAutomat';
import {
BORDER,
+ GREEN,
+ alpha,
} from '../../colors';
+const LOCKED_ROW_BG = alpha(GREEN, 0.08);
+const LOCKED_ROW_HOVER_BG = alpha(GREEN, 0.12);
+const LOCKED_CELL_BORDER = alpha(GREEN, 0.32);
+const LOCKED_CELL_BG = alpha(GREEN, 0.08);
+
class ManifestFormLine extends PureComponent {
constructor(props) {
super(props);
@@ -60,6 +67,16 @@ class ManifestFormLine extends PureComponent {
return props.line?.sku ? String(props.line.sku).trim() : null;
}
+ isFullyLedgered(props = this.props) {
+ const { ledgerLine, line } = props;
+ return Boolean(
+ ledgerLine?.isBooked ||
+ (ledgerLine && ledgerLine.targetAmount > 0 && ledgerLine.remainingAmount <= 0) ||
+ line?.isBooked ||
+ line?.is_booked
+ );
+ }
+
componentDidMount() {
this.subscribeArticle(this.getArticleSku());
}
@@ -125,7 +142,7 @@ class ManifestFormLine extends PureComponent {
}
handleRemove() {
- if (this.props.isOnShipment) return;
+ if (this.props.isOnShipment || this.isFullyLedgered()) return;
this.props.onRemove(this.props.line.key);
}
@@ -139,7 +156,8 @@ class ManifestFormLine extends PureComponent {
handleStartEdit(columnId) {
const { saving } = this.props;
- const isDisabled = saving || (columnId === 'sku' && Boolean(this.props.isOnShipment));
+ const isFullyLedgered = this.isFullyLedgered();
+ const isDisabled = saving || isFullyLedgered || (columnId === 'sku' && Boolean(this.props.isOnShipment));
if (isDisabled) return;
if (this.state.editingField !== columnId) {
this.setState({ editingField: columnId });
@@ -162,6 +180,7 @@ class ManifestFormLine extends PureComponent {
}
handleCreateArticle() {
+ if (this.isFullyLedgered()) return;
const { line, onCreateArticle } = this.props;
if (onCreateArticle) {
onCreateArticle(line);
@@ -169,6 +188,7 @@ class ManifestFormLine extends PureComponent {
}
handleSearchArticle() {
+ if (this.isFullyLedgered()) return;
const { line, onSearchArticle } = this.props;
if (onSearchArticle) {
onSearchArticle(line);
@@ -176,107 +196,14 @@ class ManifestFormLine extends PureComponent {
}
handleRemoveSupplierArticle() {
+ if (this.isFullyLedgered()) return;
const { line, supplierArticle, onRemoveSupplierArticle } = this.props;
if (onRemoveSupplierArticle) {
onRemoveSupplierArticle(line, supplierArticle);
}
}
- renderLedgerChip() {
- const { ledgerLine, onBookLine } = this.props;
- if (!ledgerLine) return null;
- const isBooked = ledgerLine.isBooked;
- const isPartial = !isBooked && ledgerLine.bookedAmount > 0;
- const isClickable = Boolean(onBookLine);
- const isTracked = Boolean(ledgerLine.trackStock);
- const tooltipTitle = isTracked
- ? isBooked
- ? `Vollständig im Lager gebucht: ${ledgerLine.bookedAmount} Stück (Klicken für Details)`
- : isPartial
- ? `Teilweise im Lager gebucht: ${ledgerLine.bookedAmount} von ${ledgerLine.targetAmount} Stück (Klicken zum Einbuchen dieser Position)`
- : `Noch nicht im Lager gebucht (${ledgerLine.targetAmount} Stück – Klicken zum Einbuchen dieser Position)`
- : isBooked
- ? `Vollständig im Ledger verbucht: ${ledgerLine.bookedAmount} Stück (Klicken für Details)`
- : isPartial
- ? `Teilweise im Ledger verbucht: ${ledgerLine.bookedAmount} von ${ledgerLine.targetAmount} Stück (Klicken zum Verbuchen dieser Position)`
- : `Noch nicht im Ledger verbucht (${ledgerLine.targetAmount} Stück – Klicken zum Verbuchen dieser Position)`;
-
- const label = isTracked
- ? isBooked
- ? `Lager: ${ledgerLine.bookedAmount} Stk. gebucht`
- : isPartial
- ? `Lager: ${ledgerLine.bookedAmount}/${ledgerLine.targetAmount} Stk.`
- : 'Lager: offen'
- : isBooked
- ? `Gebucht: ${ledgerLine.bookedAmount} Stk.`
- : isPartial
- ? `Gebucht: ${ledgerLine.bookedAmount}/${ledgerLine.targetAmount} Stk.`
- : null;
-
- if (!label) return null;
-
- return (
-
- {
- e.stopPropagation();
- onBookLine(ledgerLine);
- }
- : undefined
- }
- icon={
- isBooked ? (
-
- ) : (
-
- )
- }
- label={label}
- variant={isBooked ? 'outlined' : 'filled'}
- sx={{
- height: 22,
- fontSize: '0.7rem',
- fontWeight: 700,
- cursor: isClickable ? 'pointer' : 'default',
- ...(isBooked
- ? {
- bgcolor: 'rgba(21, 128, 61, 0.08)',
- color: '#15803d',
- borderColor: '#15803d',
- borderWidth: 1,
- borderStyle: 'solid',
- '&:hover': isClickable ? { bgcolor: 'rgba(21, 128, 61, 0.16)' } : undefined,
- }
- : isPartial
- ? {
- bgcolor: '#d97706',
- color: '#ffffff',
- border: 'none',
- '&:hover': isClickable ? { bgcolor: '#b45309' } : undefined,
- }
- : {
- bgcolor: 'primary.main',
- color: '#ffffff',
- border: 'none',
- '&:hover': isClickable ? { bgcolor: 'primary.dark' } : undefined,
- }),
- '& .MuiChip-label': {
- color: 'inherit',
- px: 0.75,
- },
- '& .MuiChip-icon': {
- color: 'inherit',
- },
- }}
- />
-
- );
- }
renderField(column, colIdx, totalCols) {
const { id, align, type } = column;
@@ -365,10 +292,13 @@ class ManifestFormLine extends PureComponent {
);
const isEditing = this.state.editingField === id;
- const isDisabled = saving || (id === 'sku' && Boolean(this.props.isOnShipment));
- const titleText = id === 'sku' && this.props.isOnShipment
- ? 'Artikel ist bereits auf einem Lieferschein und kann nicht geändert werden'
- : undefined;
+ const isFullyLedgered = this.isFullyLedgered();
+ const isDisabled = saving || isFullyLedgered || (id === 'sku' && Boolean(this.props.isOnShipment));
+ const titleText = isFullyLedgered
+ ? 'Position ist bereits vollständig im Ledger verbucht und kann nicht geändert werden'
+ : id === 'sku' && this.props.isOnShipment
+ ? 'Artikel ist bereits auf einem Lieferschein und kann nicht geändert werden'
+ : undefined;
if (isEditing) {
return (
@@ -456,9 +386,10 @@ class ManifestFormLine extends PureComponent {
this.handleStartEdit(id)}
- onFocus={() => this.handleStartEdit(id)}
+ onClick={isDisabled ? undefined : () => this.handleStartEdit(id)}
+ onFocus={isDisabled ? undefined : () => this.handleStartEdit(id)}
onKeyDown={(e) => {
+ if (isDisabled) return;
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
this.handleStartEdit(id);
@@ -485,11 +416,16 @@ class ManifestFormLine extends PureComponent {
? 'warning.main'
: isError
? 'error.main'
- : 'rgba(0, 0, 0, 0.23)',
+ : isFullyLedgered
+ ? LOCKED_CELL_BORDER
+ : 'rgba(0, 0, 0, 0.23)',
cursor: isDisabled ? 'default' : 'text',
touchAction: 'manipulation',
userSelect: 'none',
zIndex: 1,
+ ...(isFullyLedgered && !isFieldDirty && !isError && {
+ bgcolor: LOCKED_CELL_BG,
+ }),
...(isFieldDirty && {
bgcolor: 'rgba(237, 108, 2, 0.08)',
zIndex: 2,
@@ -943,13 +879,19 @@ class ManifestFormLine extends PureComponent {
>
{/* Unlink button at the front */}
{this.props.onRemoveSupplierArticle && supplierArticle.id != null && (
-
+
@@ -1095,8 +1037,6 @@ class ManifestFormLine extends PureComponent {
)}
)}
-
- {this.renderLedgerChip()}
);
}
@@ -1109,6 +1049,7 @@ class ManifestFormLine extends PureComponent {
size="small"
variant="text"
startIcon={}
+ disabled={this.isFullyLedgered()}
onClick={this.handleCreateArticle}
sx={{
fontSize: '0.7rem',
@@ -1131,6 +1072,7 @@ class ManifestFormLine extends PureComponent {
size="small"
variant="text"
startIcon={}
+ disabled={this.isFullyLedgered()}
onClick={this.handleSearchArticle}
sx={{
fontSize: '0.7rem',
@@ -1154,17 +1096,6 @@ class ManifestFormLine extends PureComponent {
? `Kein Lieferanten-Artikel für SKU „${rawSku}“ gefunden.`
: `Kein Artikel für SKU „${rawSku}“ gefunden.`}
- {this.renderLedgerChip()}
-
- );
- }
-
- if (this.props.ledgerLine) {
- const chip = this.renderLedgerChip();
- if (!chip) return null;
- return (
-
- {chip}
);
}
@@ -1174,12 +1105,24 @@ class ManifestFormLine extends PureComponent {
render() {
const { columns = LINE_COLUMNS, saving, ledgerLine } = this.props;
+ const isFullyLedgered = this.isFullyLedgered();
const secondLine = this.renderSecondLine();
return (
{/* Row 1: Editable Line Inputs */}
- td': { borderBottom: 'none', p: 0 } }}>
+ td': { borderBottom: 'none', p: 0 },
+ ...(isFullyLedgered && {
+ bgcolor: LOCKED_ROW_BG,
+ '&:hover': {
+ bgcolor: LOCKED_ROW_HOVER_BG,
+ },
+ }),
+ }}
+ >
{columns.map((col, colIdx) => (
@@ -1269,9 +1215,15 @@ class ManifestFormLine extends PureComponent {
@@ -1282,7 +1234,14 @@ class ManifestFormLine extends PureComponent {
{/* Row 2: Matched Supplier Article Details */}
{secondLine && (
- td': { pt: 0.25, pb: 0.75, borderBottom: 'none' } }}>
+ td': { pt: 0.25, pb: 0.75, borderBottom: 'none' },
+ ...(isFullyLedgered && {
+ bgcolor: LOCKED_ROW_BG,
+ }),
+ }}
+ >
{
const hasShippedLines = kind === 'order' && Array.isArray(shipments) && shipments.some((sh) => (sh.lines?.length || 0) > 0);
+ const hasLedgeredLines = kind === 'delivery' && Array.isArray(lines) && lines.some((line) => {
+ const ledgerLine = line?.id != null ? ledgerLinesById?.[line.id] : null;
+ return Boolean(
+ ledgerLine?.isBooked ||
+ (ledgerLine && ledgerLine.targetAmount > 0 && ledgerLine.remainingAmount <= 0) ||
+ (ledgerLine && ledgerLine.bookedAmount > 0) ||
+ line?.isBooked ||
+ line?.is_booked
+ );
+ });
+ const disabled = saving || !lines || lines.length === 0 || hasShippedLines || hasLedgeredLines;
+ const title = hasLedgeredLines
+ ? 'Lieferung enthält bereits im Ledger verbuchte Positionen'
+ : hasShippedLines
+ ? 'Auftrag enthält bereits ausgelieferte Positionen'
+ : 'Alle Zeilen entfernen';
return (
}
- disabled={saving || !lines || lines.length === 0 || hasShippedLines}
+ disabled={disabled}
onClick={onRemoveAllLines}
- title={hasShippedLines ? 'Auftrag enthält bereits ausgelieferte Positionen' : 'Alle Zeilen entfernen'}
+ title={title}
>
Alle Zeilen entfernen