import numberAutomat from '../automats/numberAutomat'; import quoteAutomat from '../automats/quoteAutomat'; import orderAutomat from '../automats/orderAutomat'; /** * Formats a number pattern given prefix, padding width, and counter. * * @param {string} [prefix=''] * @param {number} [padding=0] * @param {number} [next=1] * @returns {string} */ export function formatNumberPattern(prefix, padding, next) { const pad = Math.max(0, Number(padding) || 0); const num = Math.max(1, Number(next) || 1); const numStr = pad > 0 ? String(num).padStart(pad, '0') : String(num); return `${prefix ?? ''}${numStr}`; } /** * Returns the next document number for quote or order based on company sequences. * * @param {'quote'|'order'|string} kind * @returns {string} */ export function getNextDocumentNumber(kind) { const numbers = numberAutomat.state.items ?? []; const seq = numbers.find((r) => r.type === kind); if (seq) { return formatNumberPattern(seq.prefix, seq.padding, seq.next); } // Detect style from existing company sequences (sku, delivery, entity) const skuSeq = numbers.find((r) => r.type === 'sku'); const deliverySeq = numbers.find((r) => r.type === 'delivery'); const entitySeq = numbers.find((r) => r.type === 'entity'); const refSeq = skuSeq || deliverySeq || entitySeq; const pad = refSeq ? Math.max(0, Number(refSeq.padding) || 0) : 6; const prefixStyle = refSeq?.prefix ?? ''; let prefix = ''; let startNum = 1; if ( prefixStyle.startsWith('ART-') || prefixStyle.startsWith('LS-') || prefixStyle.startsWith('KD-') || prefixStyle.endsWith('-') ) { // Standard German ERP prefix style (ART-, KD-, LS-, KORR-) prefix = kind === 'quote' ? 'ANG-' : (kind === 'order' ? 'AUF-' : ''); } else if ( prefixStyle.startsWith('SKU-') || prefixStyle.startsWith('DEL-') || prefixStyle.startsWith('C-') ) { prefix = kind === 'quote' ? 'Q-' : (kind === 'order' ? 'ORD-' : ''); } else if ( prefixStyle.startsWith('A-') || prefixStyle.startsWith('L-') || prefixStyle.startsWith('K-') ) { prefix = kind === 'quote' ? 'AG-' : (kind === 'order' ? 'AU-' : ''); } else if (!prefixStyle && refSeq?.next >= 10000) { prefix = ''; startNum = kind === 'quote' ? 40001 : 50001; } else { prefix = kind === 'quote' ? 'ANG-' : (kind === 'order' ? 'AUF-' : ''); } // Check existing docs from quoteAutomat / orderAutomat to avoid collisions const listAutomat = kind === 'quote' ? quoteAutomat : (kind === 'order' ? orderAutomat : null); const existingDocs = Array.isArray(listAutomat?.state?.items) ? listAutomat.state.items : []; let maxFound = startNum - 1; for (const doc of existingDocs) { if (!doc || typeof doc !== 'object') continue; const docNum = String(doc.number ?? '').trim(); if (!docNum) continue; if (prefix && docNum.startsWith(prefix)) { const rest = docNum.slice(prefix.length); const parsed = parseInt(rest, 10); if (!Number.isNaN(parsed) && parsed > maxFound) { maxFound = parsed; } } else if (!prefix) { const parsed = parseInt(docNum, 10); if (!Number.isNaN(parsed) && parsed >= startNum && parsed > maxFound) { maxFound = parsed; } } } const nextVal = maxFound >= startNum ? maxFound + 1 : startNum; return formatNumberPattern(prefix, pad, nextVal); } /** * Asynchronously ensures required stores are loaded, then returns the next document number. * * @param {'quote'|'order'|string} kind * @returns {Promise} */ export async function ensureDocumentNumber(kind) { const listAutomat = kind === 'quote' ? quoteAutomat : (kind === 'order' ? orderAutomat : null); await Promise.all([ numberAutomat.actions.ensureLoaded().catch(() => {}), listAutomat?.actions?.ensureLoaded ? listAutomat.actions.ensureLoaded().catch(() => {}) : Promise.resolve(), ]); return getNextDocumentNumber(kind); }