Kleiner Anpassungen / Aktualisierung Dokumentation

This commit is contained in:
2026-08-11 18:51:59 +02:00
parent da688bb294
commit 1d295796b4
15 changed files with 1948 additions and 1421 deletions

View File

@@ -1118,6 +1118,7 @@ body.modal-open { overflow: hidden; }
}
.modal-card .add-fields { margin-top: .6rem; }
.modal-card .add-select { margin-top: .5rem; }
.modal-card .menu-actions { margin-top: 1.2rem; }
.modal-card .menu-actions button.primary { margin-top: 0; }

View File

@@ -70,7 +70,14 @@ export function parseCents(text) {
}
export function parseQuantity(text) {
const cleaned = String(text).trim().replace(",", ".");
// Leerzeichen und Tausenderpunkte entfernen, Komma als Dezimaltrenner.
// Die Punkte fallen weg, weil eine Eingabe wie "1.500" im Deutschen
// eintausendfünfhundert meint - und weil formatQuantity keine
// Tausendertrennung mehr erzeugt, bleibt kein anderer Fall übrig.
const cleaned = String(text)
.trim()
.replace(/[\s\u00a0.]/g, "")
.replace(",", ".");
if (!cleaned) return null;
const value = Number(cleaned);
return Number.isFinite(value) && value >= 0 ? value : null;
@@ -100,5 +107,13 @@ export function formatQuantity(value) {
if (value === null || value === undefined) return "";
const num = Number(value);
if (!Number.isFinite(num)) return String(value);
return num.toLocaleString("de-DE", { maximumFractionDigits: 3 });
// OHNE Tausendertrennung. Der Wert landet auch in Eingabefeldern, und
// parseQuantity liest den deutschen Tausenderpunkt als Dezimalpunkt:
// Aus einer 1000-Gramm-Packung wurde beim Bearbeiten eine mit 1 Gramm.
// Bei Mengen bringt die Trennung ohnehin wenig - "1000 g" liest sich
// gut genug.
return num.toLocaleString("de-DE", {
maximumFractionDigits: 3,
useGrouping: false,
});
}

View File

@@ -652,7 +652,14 @@ export async function listDetailView(
// Sonst bestätigen lassen - auch bei einem Treffer in der
// Produktdatenbank. Fremde Angaben sollen nicht ungeprüft in den
// eigenen Artikelstamm wandern.
const confirmed = await confirmScan(lookup);
// Auswahl aus der Eingabezeile als Vorbelegung mitgeben; was der
// Dialog zurückliefert, gilt.
const confirmed = await confirmScan(lookup, {
markets,
categories,
market: marketField ? marketField.value : null,
category: categoryField ? categoryField.value : null,
});
if (!confirmed) return;
await change("item.create", {
@@ -662,10 +669,8 @@ export async function listDetailView(
pack_size: parseQuantity(confirmed.packSize),
pack_unit: confirmed.packUnit || null,
variant: confirmed.variant || null,
...(marketField && marketField.value
? { market_id: marketField.value } : {}),
...(categoryField && categoryField.value
? { category_id: categoryField.value } : {}),
...(confirmed.marketId ? { market_id: confirmed.marketId } : {}),
...(confirmed.categoryId ? { category_id: confirmed.categoryId } : {}),
});
}

View File

@@ -6,15 +6,23 @@
// und sie ändern können, bevor sie im eigenen Bestand landen.
"use strict";
import { el } from "../dom.js";
import { el, formatQuantity } from "../dom.js";
/**
* @param {object} lookup Antwort von /api/lists/{id}/barcode/{code}
* @returns {Promise<{name: string, quantity: string, unit: string, variant: string}|null>}
* @param {object} context
* @param {Array} context.markets Märkte der Liste
* @param {Array} context.categories Warengruppen der Liste
* @param {string|null} context.market Vorauswahl aus der Eingabezeile
* @param {string|null} context.category dito
* @returns {Promise<{name, count, packSize, packUnit, variant,
* marketId, categoryId}|null>}
*/
export function confirmScan(lookup) {
export function confirmScan(lookup, context = {}) {
return new Promise((resolve) => {
const known = lookup.found && lookup.source === "openfoodfacts";
const markets = context.markets || [];
const categories = context.categories || [];
const nameField = el("input", {
type: "text",
@@ -33,8 +41,10 @@ export function confirmScan(lookup) {
const qtyField = el("input.qty", {
type: "text",
inputMode: "decimal",
value: lookup.pack_size != null
? String(lookup.pack_size).replace(".", ",") : "",
// formatQuantity statt roher Zeichenkette: Die API liefert
// "200.000", und "200,000" im Feld sieht nach zweihunderttausend
// aus.
value: lookup.pack_size != null ? formatQuantity(lookup.pack_size) : "",
placeholder: "Gebinde",
title: "Packungsgröße",
});
@@ -51,6 +61,29 @@ export function confirmScan(lookup) {
placeholder: "Eigenschaft",
});
// Warengruppe und Markt wie in der Eingabezeile - der gescannte
// Artikel soll ohne Nacharbeit an der richtigen Stelle landen.
// Vorbelegt mit dem, was im Formular schon ausgewählt war.
const categoryField = categories.length
? el("select.category-select", { title: "Warengruppe" },
el("option", { value: "" }, "— Vorgabe des Artikels —"),
categories.map((c) => el("option", { value: c.id }, c.name)))
: null;
if (categoryField && context.category
&& categories.some((c) => c.id === context.category)) {
categoryField.value = context.category;
}
const marketField = markets.length
? el("select.market-select", { title: "Markt" },
el("option", { value: "" }, "— Vorgabe des Artikels —"),
markets.map((m) => el("option", { value: m.id }, m.name)))
: null;
if (marketField && context.market
&& markets.some((m) => m.id === context.market)) {
marketField.value = context.market;
}
function accept() {
const name = nameField.value.trim();
if (!name) {
@@ -63,6 +96,8 @@ export function confirmScan(lookup) {
packSize: qtyField.value,
packUnit: unitField.value.trim(),
variant: variantField.value.trim(),
marketId: marketField ? marketField.value || null : null,
categoryId: categoryField ? categoryField.value || null : null,
});
}
@@ -83,6 +118,8 @@ export function confirmScan(lookup) {
el("label", {}, "Name"), nameField,
el("div.add-fields", {}, countField, qtyField, unitField, variantField),
categoryField ? el("div.add-select", {}, categoryField) : null,
marketField ? el("div.add-select", {}, marketField) : null,
el("div.menu-actions", {},
el("button.primary", { type: "button", onclick: accept }, "Hinzufügen"),

View File

@@ -5,7 +5,7 @@
// Bei jeder Änderung an den Dateien unten hochzählen. Der Wert entscheidet,
// wann alte Zwischenspeicher verworfen werden.
const VERSION = "v32";
const VERSION = "v33";
const SHELL_CACHE = `einkaufsapp-shell-${VERSION}`;
const SHELL = [