This commit is contained in:
seb
2026-10-18 20:34:17 +02:00
parent ac9034685f
commit c211040cd3
3 changed files with 64 additions and 8 deletions

View File

@@ -220,6 +220,7 @@ class ManifestForm extends PureComponent {
void this.loadEdit(); void this.loadEdit();
} else { } else {
void this.loadPartiesOnly(); void this.loadPartiesOnly();
void ensureDocumentNumber(this.props.kind).catch(() => {});
} }
if (this.draftAutomat) { if (this.draftAutomat) {

View File

@@ -26,6 +26,8 @@ import { notifyError, notifyErrorMessage } from '../../utils/notify';
import entityAutomat from '../../automats/entityAutomat'; import entityAutomat from '../../automats/entityAutomat';
import customergroupAutomat from '../../automats/customergroupAutomat'; import customergroupAutomat from '../../automats/customergroupAutomat';
import supplierAutomat from '../../automats/supplierAutomat'; import supplierAutomat from '../../automats/supplierAutomat';
import numberAutomat from '../../automats/numberAutomat';
import { getNextDocumentNumber, ensureDocumentNumber } from '../../utils/documentNumber';
import { import {
SURFACE_RAISED, SURFACE_RAISED,
} from '../../colors'; } from '../../colors';
@@ -231,6 +233,40 @@ class ManifestHeader extends PureComponent {
this.props.onPdfUpload?.(file); this.props.onPdfUpload?.(file);
} }
componentDidMount() {
this._cancelled = false;
this.unsubNumber = numberAutomat.subscribe(this, () => {
this.forceUpdate();
});
void numberAutomat.actions.ensureLoaded().catch(() => {});
if (!this.props.number && this.props.docId == null) {
void ensureDocumentNumber(this.props.kind)
.then(() => {
if (!this._cancelled) this.forceUpdate();
})
.catch(() => {});
}
}
componentDidUpdate(prevProps) {
if (
!this.props.number &&
this.props.docId == null &&
(prevProps.kind !== this.props.kind || prevProps.docId !== this.props.docId)
) {
void ensureDocumentNumber(this.props.kind)
.then(() => {
if (!this._cancelled) this.forceUpdate();
})
.catch(() => {});
}
}
componentWillUnmount() {
this._cancelled = true;
this.unsubNumber?.();
}
render() { render() {
const { const {
kind, kind,
@@ -273,6 +309,9 @@ class ManifestHeader extends PureComponent {
const hasArticles = this.hasArticles(); const hasArticles = this.hasArticles();
const isEdit = docId != null; const isEdit = docId != null;
const previewNumber =
this.props.previewNumber ??
(!number && !isEdit ? getNextDocumentNumber(kind) : null);
const hasAttachments = Array.isArray(attachments) && attachments.length > 0; const hasAttachments = Array.isArray(attachments) && attachments.length > 0;
const hasParty = partyId != null && partyId !== ''; const hasParty = partyId != null && partyId !== '';
const partyValid = kind !== 'order' || hasParty; const partyValid = kind !== 'order' || hasParty;
@@ -400,12 +439,25 @@ class ManifestHeader extends PureComponent {
<SingleLineTextEdit <SingleLineTextEdit
size="small" size="small"
label="Nummer" label="Nummer"
value={number || ''} value={number || previewNumber || ''}
disabled disabled
placeholder="–" placeholder="–"
title={
!number && previewNumber
? 'Vorschau der nächsten Nummer (wird beim Speichern vergeben)'
: undefined
}
slotProps={{
inputLabel: { shrink: true },
}}
sx={{ sx={{
flex: { xs: '1 1 100%', sm: '1 1 120px' }, flex: { xs: '1 1 100%', sm: '1 1 120px' },
minWidth: { sm: 100 }, minWidth: { sm: 100 },
...(!number && previewNumber && {
'& .MuiInputBase-input.Mui-disabled': {
fontStyle: 'italic',
},
}),
}} }}
/> />
{useExternalNumber ? ( {useExternalNumber ? (

View File

@@ -1,6 +1,7 @@
import numberAutomat from '../automats/numberAutomat'; import numberAutomat from '../automats/numberAutomat';
import quoteAutomat from '../automats/quoteAutomat'; import quoteAutomat from '../automats/quoteAutomat';
import orderAutomat from '../automats/orderAutomat'; import orderAutomat from '../automats/orderAutomat';
import deliveryAutomat from '../automats/deliveryAutomat';
/** /**
* Formats a number pattern given prefix, padding width, and counter. * Formats a number pattern given prefix, padding width, and counter.
@@ -18,9 +19,9 @@ export function formatNumberPattern(prefix, padding, next) {
} }
/** /**
* Returns the next document number for quote or order based on company sequences. * Returns the next document number for quote, order, or delivery based on company sequences.
* *
* @param {'quote'|'order'|string} kind * @param {'quote'|'order'|'delivery'|string} kind
* @returns {string} * @returns {string}
*/ */
export function getNextDocumentNumber(kind) { export function getNextDocumentNumber(kind) {
@@ -42,7 +43,9 @@ export function getNextDocumentNumber(kind) {
let prefix = ''; let prefix = '';
let startNum = 1; let startNum = 1;
if ( if (kind === 'delivery') {
prefix = prefixStyle.startsWith('DEL-') ? 'DEL-' : (prefixStyle.startsWith('L-') ? 'L-' : 'LS-');
} else if (
prefixStyle.startsWith('ART-') || prefixStyle.startsWith('ART-') ||
prefixStyle.startsWith('LS-') || prefixStyle.startsWith('LS-') ||
prefixStyle.startsWith('KD-') || prefixStyle.startsWith('KD-') ||
@@ -69,8 +72,8 @@ export function getNextDocumentNumber(kind) {
prefix = kind === 'quote' ? 'ANG-' : (kind === 'order' ? 'AUF-' : ''); prefix = kind === 'quote' ? 'ANG-' : (kind === 'order' ? 'AUF-' : '');
} }
// Check existing docs from quoteAutomat / orderAutomat to avoid collisions // Check existing docs from quoteAutomat / orderAutomat / deliveryAutomat to avoid collisions
const listAutomat = kind === 'quote' ? quoteAutomat : (kind === 'order' ? orderAutomat : null); const listAutomat = kind === 'quote' ? quoteAutomat : (kind === 'order' ? orderAutomat : (kind === 'delivery' ? deliveryAutomat : null));
const existingDocs = Array.isArray(listAutomat?.state?.items) ? listAutomat.state.items : []; const existingDocs = Array.isArray(listAutomat?.state?.items) ? listAutomat.state.items : [];
let maxFound = startNum - 1; let maxFound = startNum - 1;
@@ -99,11 +102,11 @@ export function getNextDocumentNumber(kind) {
/** /**
* Asynchronously ensures required stores are loaded, then returns the next document number. * Asynchronously ensures required stores are loaded, then returns the next document number.
* *
* @param {'quote'|'order'|string} kind * @param {'quote'|'order'|'delivery'|string} kind
* @returns {Promise<string>} * @returns {Promise<string>}
*/ */
export async function ensureDocumentNumber(kind) { export async function ensureDocumentNumber(kind) {
const listAutomat = kind === 'quote' ? quoteAutomat : (kind === 'order' ? orderAutomat : null); const listAutomat = kind === 'quote' ? quoteAutomat : (kind === 'order' ? orderAutomat : (kind === 'delivery' ? deliveryAutomat : null));
await Promise.all([ await Promise.all([
numberAutomat.actions.ensureLoaded().catch(() => {}), numberAutomat.actions.ensureLoaded().catch(() => {}),
listAutomat?.actions?.ensureLoaded ? listAutomat.actions.ensureLoaded().catch(() => {}) : Promise.resolve(), listAutomat?.actions?.ensureLoaded ? listAutomat.actions.ensureLoaded().catch(() => {}) : Promise.resolve(),