u
This commit is contained in:
@@ -80,44 +80,101 @@ export function emptyLine() {
|
||||
}
|
||||
|
||||
export function lineFromApi(row) {
|
||||
const netVal = row.netprice != null ? String(row.netprice) : row.net != null ? String(row.net) : '';
|
||||
const taxVal = row.taxrate != null ? String(row.taxrate) : row.tax != null ? String(row.tax) : '';
|
||||
return {
|
||||
id: row.id,
|
||||
key: `line-${row.id ?? `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`}`,
|
||||
amount: row.amount == null ? '' : String(row.amount),
|
||||
sku: row.sku ?? '',
|
||||
tax: row.tax == null ? '' : String(row.tax),
|
||||
tax: taxVal,
|
||||
rebate: row.rebate == null ? '' : String(row.rebate),
|
||||
net: row.net == null ? '' : String(row.net),
|
||||
net: netVal,
|
||||
name: row.name ?? '',
|
||||
pu: row.pu == null ? '' : String(row.pu),
|
||||
unit: row.unit ?? '',
|
||||
netprice: row.netprice != null ? String(row.netprice) : row.net != null ? String(row.net) : '',
|
||||
taxrate: row.taxrate != null ? String(row.taxrate) : row.tax != null ? String(row.tax) : '',
|
||||
netprice: netVal,
|
||||
taxrate: taxVal,
|
||||
};
|
||||
}
|
||||
|
||||
function parseNum(value) {
|
||||
export function parseNum(value) {
|
||||
if (value == null || value === '') return null;
|
||||
const n = Number(String(value).trim().replace(',', '.'));
|
||||
const cleaned = String(value).trim().replace('%', '').trim().replace(',', '.');
|
||||
if (cleaned === '') return null;
|
||||
const n = Number(cleaned);
|
||||
return Number.isFinite(n) ? n : null;
|
||||
}
|
||||
|
||||
export function getFirstVal(...vals) {
|
||||
for (const v of vals) {
|
||||
if (v != null && String(v).trim() !== '') return v;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function hasArticleLines(lines) {
|
||||
if (!Array.isArray(lines) || lines.length === 0) return false;
|
||||
return lines.some((l) => {
|
||||
if (!l) return false;
|
||||
const sku = String(l.sku ?? '').trim();
|
||||
const name = String(l.name ?? '').trim();
|
||||
const amount = String(l.amount ?? '').trim();
|
||||
const net = String(l.net ?? l.netprice ?? '').trim();
|
||||
return Boolean(sku || name || amount || net);
|
||||
});
|
||||
}
|
||||
|
||||
/** Build create/update line array. Throws Error on client validation. */
|
||||
export function buildLines(lines, { requireAtLeastOne }) {
|
||||
const outLines = [];
|
||||
for (const line of lines) {
|
||||
const errors = [];
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i];
|
||||
const sku = String(line.sku ?? '').trim();
|
||||
const name = String(line.name ?? '').trim();
|
||||
const amount = parseNum(line.amount);
|
||||
const net = parseNum(line.net ?? line.netprice);
|
||||
const tax = parseNum(line.tax ?? line.taxrate);
|
||||
const rebate = parseNum(line.rebate);
|
||||
const pu = parseNum(line.pu);
|
||||
const rawAmount = getFirstVal(line.amount, line.count);
|
||||
const amount = parseNum(rawAmount);
|
||||
const rawNet = getFirstVal(line.net, line.netprice, line.netPrice, line.eknetto);
|
||||
const net = parseNum(rawNet);
|
||||
const rawTax = getFirstVal(line.tax, line.taxrate, line.taxRate, line.mwst);
|
||||
const tax = parseNum(rawTax);
|
||||
const rebate = parseNum(getFirstVal(line.rebate));
|
||||
const rawPu = getFirstVal(line.pu, line.vpe);
|
||||
const pu = parseNum(rawPu);
|
||||
const blank =
|
||||
!sku && !name && amount == null && net == null && tax == null && rebate == null;
|
||||
if (blank) continue;
|
||||
if ((!sku && !name) || amount == null || net == null || tax == null) {
|
||||
throw new Error('Jede Zeile braucht SKU oder Name, Amount, Net und Taxrate.');
|
||||
|
||||
const missing = [];
|
||||
if (!sku && !name) {
|
||||
missing.push('Artikel (SKU oder Name)');
|
||||
}
|
||||
if (amount == null) {
|
||||
missing.push(rawAmount != null ? 'gültige Menge' : 'Menge');
|
||||
}
|
||||
if ('pu' in line && pu == null) {
|
||||
missing.push(rawPu != null ? 'gültige VPE (PU)' : 'VPE (PU)');
|
||||
}
|
||||
if (net == null) {
|
||||
missing.push(rawNet != null ? 'gültiger Nettopreis' : 'Nettopreis');
|
||||
}
|
||||
if (tax == null) {
|
||||
missing.push(rawTax != null ? 'gültiger Steuersatz' : 'Steuersatz');
|
||||
}
|
||||
|
||||
if (missing.length > 0) {
|
||||
const identifier = name || sku;
|
||||
const rowLabel = `Zeile ${i + 1}${identifier ? ` („${identifier}“)` : ''}`;
|
||||
const fieldsText =
|
||||
missing.length === 1
|
||||
? `${missing[0]} fehlt`
|
||||
: `${missing.slice(0, -1).join(', ')} und ${missing[missing.length - 1]} fehlen`;
|
||||
errors.push(`${rowLabel}: ${fieldsText}.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const row = { amount, net, taxrate: tax };
|
||||
if (sku) row.sku = sku;
|
||||
if (name) row.name = name;
|
||||
@@ -125,6 +182,18 @@ export function buildLines(lines, { requireAtLeastOne }) {
|
||||
if (pu != null) row.pu = pu;
|
||||
outLines.push(row);
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
if (errors.length <= 3) {
|
||||
throw new Error(errors.join(' '));
|
||||
}
|
||||
const visibleErrors = errors.slice(0, 3).join(' ');
|
||||
const remainingCount = errors.length - 3;
|
||||
throw new Error(
|
||||
`${visibleErrors} (und ${remainingCount} weitere fehlerhafte Zeile${remainingCount === 1 ? '' : 'n'})`,
|
||||
);
|
||||
}
|
||||
|
||||
if (requireAtLeastOne && outLines.length === 0) {
|
||||
throw new Error('Mindestens eine Artikelzeile nötig.');
|
||||
}
|
||||
@@ -480,14 +549,14 @@ export function manifestConfig(kind) {
|
||||
deletedMsg: 'Lieferung gelöscht.',
|
||||
confirmDelete: (number) => `Lieferung „${number}“ wirklich löschen?`,
|
||||
invalidId: 'Ungültige Lieferungs-ID.',
|
||||
partyGateMessage: 'Lieferant wählen, um Artikel zu erfassen.',
|
||||
partyGateMessage: null,
|
||||
getPathLabel: 'GET /api/delivery/:id',
|
||||
postPathLabel: 'POST /api/delivery',
|
||||
patchPathLabel: 'PATCH /api/delivery/:id',
|
||||
listColor: '#fed7aa',
|
||||
headerColor: '#fed7aa',
|
||||
linesColor: '#bbf7d0',
|
||||
requirePartyBeforeLines: true,
|
||||
requirePartyBeforeLines: false,
|
||||
updateCache: 'updateDelivery',
|
||||
listPromise: (ctx) => ctx.deliveries ?? ctx.deliveryPromise,
|
||||
partiesByIdFromList: (parties) =>
|
||||
|
||||
Reference in New Issue
Block a user