diff --git a/ios/Sources/Models.swift b/ios/Sources/Models.swift index 67d821d..54e0553 100644 --- a/ios/Sources/Models.swift +++ b/ios/Sources/Models.swift @@ -494,6 +494,12 @@ struct ProductUpdateRequest: Encodable { var shopId: Int? = nil var productUrl: String? = nil var fieldValues: [String: String?]? = nil + // Mindestbestand nur senden, wenn ausdrücklich gewünscht – sonst bliebe der + // erfasste Modus (z.B. „5 kg") sonst erhalten und wird nicht überschrieben. + var minStock: Double? = nil + var minStockInPackages: Bool? = nil + var minStockUnitId: Int? = nil + var sendMinStock = false enum CodingKeys: String, CodingKey { case name, brand @@ -505,6 +511,9 @@ struct ProductUpdateRequest: Encodable { case shopId = "shop_id" case productUrl = "product_url" case fieldValues = "field_values" + case minStock = "min_stock" + case minStockInPackages = "min_stock_in_packages" + case minStockUnitId = "min_stock_unit_id" } func encode(to encoder: Encoder) throws { @@ -520,6 +529,11 @@ struct ProductUpdateRequest: Encodable { try container.encode(productUrl, forKey: .productUrl) // Feldwerte nur senden, wenn gesetzt – sonst nichts an den Feldern ändern. if let fieldValues { try container.encode(fieldValues, forKey: .fieldValues) } + if sendMinStock { + try container.encode(minStock, forKey: .minStock) + try container.encode(minStockInPackages, forKey: .minStockInPackages) + try container.encode(minStockUnitId, forKey: .minStockUnitId) + } } } diff --git a/ios/Sources/ProductDetailView.swift b/ios/Sources/ProductDetailView.swift index 1569dcb..e0d5691 100644 --- a/ios/Sources/ProductDetailView.swift +++ b/ios/Sources/ProductDetailView.swift @@ -28,6 +28,8 @@ struct ProductDetailView: View { // Gegenstände (Non-Food): Bezugsquelle, Link, Lagerorte und eigene Felder. @State private var shopId: Int? @State private var productUrl = "" + // Gesamt-Mindestbestand (nur Gegenstände; Menge in Stück/Artikeleinheit). + @State private var minStock = "" @State private var shops: [ShopItem] = [] @State private var locations: [StorageLocation] = [] @State private var fieldDefs: [FieldDefinition] = [] @@ -51,6 +53,7 @@ struct ProductDetailView: View { if current.isObject { if !current.isIndividual, shopId != current.shopId { return true } if productUrl != (current.productUrl ?? "") { return true } + if minStock != (current.minStockDisplay.map { formatAmount($0) } ?? "") { return true } if fieldValues != Self.stringValues(current.fieldValues) { return true } } else { if packageSize != (current.packageSize.map { formatAmount($0) } ?? "") { return true } @@ -158,6 +161,12 @@ struct ProductDetailView: View { } } + if current.isObject { + Section("Mindestbestand") { + QuantityField(label: "Gesamt (Stück)", text: $minStock) + } + } + Section { NavigationLink { ProductLocationMinView(product: current) { await reload() } @@ -267,6 +276,7 @@ struct ProductDetailView: View { categoryId = current.categoryId shopId = current.shopId productUrl = current.productUrl ?? "" + minStock = current.minStockDisplay.map { formatAmount($0) } ?? "" fieldValues = Self.stringValues(current.fieldValues) } @@ -318,7 +328,12 @@ struct ProductDetailView: View { // Einzelstücke tragen den Shop je Stück – nichts ans Modell. shopId: current.isIndividual ? nil : shopId, productUrl: productUrl.isEmpty ? nil : productUrl, - fieldValues: fv + fieldValues: fv, + minStock: Double(minStock.replacingOccurrences(of: ",", with: ".")) + .map { $0 * current.articleUnitFactor }, + minStockInPackages: (current.packageSize ?? 0) > 0, + minStockUnitId: nil, + sendMinStock: true ) ) fieldValues = Self.stringValues(current.fieldValues) diff --git a/web/src/pages/ProductForm.jsx b/web/src/pages/ProductForm.jsx index 9bb88fe..61f34b7 100644 --- a/web/src/pages/ProductForm.jsx +++ b/web/src/pages/ProductForm.jsx @@ -446,7 +446,14 @@ export default function ProductForm() { Object.entries(fieldValues).forEach(([k, v]) => { if (erlaubt.has(String(k))) fv[k] = v; }); - return { ...base, individual: form.individual, field_values: fv }; + // Auch Gegenstände dürfen einen Mindestbestand haben (Verbrauchsmaterial): + // gleiche Umrechnung wie bei Lebensmitteln, für Stück-Artikel = Stückzahl. + return { + ...base, individual: form.individual, field_values: fv, + min_stock: minBase, + min_stock_unit_id: sel === "package" || sel === "" ? null : Number(sel), + min_stock_in_packages: sel === "package", + }; } return { ...base, @@ -803,6 +810,36 @@ export default function ProductForm() { +
+ Bedarf je Lagerort (z.B. Ferienhaus, Zuhause), zusätzlich zum Gesamt-Mindestbestand. Menge in Stück. +
+