iOS: Einzelstücke (UID/QR) + Scan öffnet das Stück; Seed ohne Modell-Kaufdatum
iOS-Parität zum Web: Item-Modell + API, Einzelstueck-Liste in der Produkt- Detailansicht (anlegen, je-Stueck Lagerort/Kaufdatum/Garantie/Bezugsquelle/Notiz aendern, entfernen mit Grund, QR je Stueck via CoreImage). Anlegen-Formular hat den Schalter "Einzelstuecke". Der Scanner erkennt Einzelstueck-QR (…/i/<UID>) und oeffnet direkt das Stueck. Seed: "Kaufdatum"/"Garantie bis" nicht mehr als Modell-Felder auf Elektronik - diese Angaben gehoeren je Einzelstueck ans Item, nicht ans Modell. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -74,9 +74,11 @@ struct Product: Codable, Identifiable, Hashable {
|
||||
let productUrl: String?
|
||||
/// Selbst definierte Feldwerte: {feld_id (als Text): Wert}.
|
||||
let fieldValues: [String: String?]?
|
||||
/// Gegenstand als Einzelstücke (Items mit UID/QR) statt als Menge geführt.
|
||||
let individual: Bool?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id, barcode, name, brand, stock, kind, barcodes, tracking
|
||||
case id, barcode, name, brand, stock, kind, barcodes, tracking, individual
|
||||
case datePrecision = "date_precision"
|
||||
case categoryId = "category_id"
|
||||
case categoryName = "category_name"
|
||||
@@ -99,6 +101,8 @@ struct Product: Codable, Identifiable, Hashable {
|
||||
|
||||
/// Gegenstand (Menge je Lagerort) statt Lebensmittel (Chargen/MHD)?
|
||||
var isObject: Bool { tracking == "object" }
|
||||
/// Gegenstand, der als Einzelstücke (UID/QR) geführt wird?
|
||||
var isIndividual: Bool { individual == true }
|
||||
|
||||
/// Bezeichnung der Artikeleinheit (Gebinde, sonst Produkteinheit).
|
||||
var articleUnitLabel: String {
|
||||
@@ -264,9 +268,10 @@ struct NewProductRequest: Codable {
|
||||
let datePrecision: String
|
||||
let groupId: Int?
|
||||
let categoryId: Int?
|
||||
var individual: Bool? = nil
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case barcode, name, brand
|
||||
case barcode, name, brand, individual
|
||||
case imageUrl = "image_url"
|
||||
case baseUnit = "base_unit"
|
||||
case packageSize = "package_size"
|
||||
@@ -564,6 +569,86 @@ enum RemovalReasons {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Einzelstücke (Items mit UID/QR)
|
||||
|
||||
struct Item: Codable, Identifiable, Hashable {
|
||||
let id: Int
|
||||
let uid: String
|
||||
let productId: Int
|
||||
let locationId: Int?
|
||||
let locationName: String?
|
||||
let shopId: Int?
|
||||
let shopName: String?
|
||||
let acquiredOn: String? // "yyyy-MM-dd"
|
||||
let warrantyUntil: String?
|
||||
let note: String?
|
||||
let createdAt: String
|
||||
let productName: String?
|
||||
let productBrand: String?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id, uid, note
|
||||
case productId = "product_id"
|
||||
case locationId = "location_id"
|
||||
case locationName = "location_name"
|
||||
case shopId = "shop_id"
|
||||
case shopName = "shop_name"
|
||||
case acquiredOn = "acquired_on"
|
||||
case warrantyUntil = "warranty_until"
|
||||
case createdAt = "created_at"
|
||||
case productName = "product_name"
|
||||
case productBrand = "product_brand"
|
||||
}
|
||||
}
|
||||
|
||||
struct ItemCreateRequest: Codable {
|
||||
let count: Int
|
||||
let locationId: Int?
|
||||
let shopId: Int?
|
||||
let acquiredOn: String?
|
||||
let warrantyUntil: String?
|
||||
let note: String?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case count, note
|
||||
case locationId = "location_id"
|
||||
case shopId = "shop_id"
|
||||
case acquiredOn = "acquired_on"
|
||||
case warrantyUntil = "warranty_until"
|
||||
}
|
||||
}
|
||||
|
||||
struct ItemUpdateRequest: Encodable {
|
||||
var locationId: Int?
|
||||
var shopId: Int?
|
||||
var acquiredOn: String?
|
||||
var warrantyUntil: String?
|
||||
var note: String?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case note
|
||||
case locationId = "location_id"
|
||||
case shopId = "shop_id"
|
||||
case acquiredOn = "acquired_on"
|
||||
case warrantyUntil = "warranty_until"
|
||||
}
|
||||
|
||||
// Immer alle Felder senden (auch null), damit sich ein Feld leeren lässt.
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var c = encoder.container(keyedBy: CodingKeys.self)
|
||||
try c.encode(locationId, forKey: .locationId)
|
||||
try c.encode(shopId, forKey: .shopId)
|
||||
try c.encode(acquiredOn, forKey: .acquiredOn)
|
||||
try c.encode(warrantyUntil, forKey: .warrantyUntil)
|
||||
try c.encode(note, forKey: .note)
|
||||
}
|
||||
}
|
||||
|
||||
struct ItemRemoveRequest: Codable {
|
||||
let reason: String
|
||||
let note: String?
|
||||
}
|
||||
|
||||
// MARK: - Uebersicht und Verlauf
|
||||
|
||||
/// Kennzahlen der Startseite (GET /dashboard/stats).
|
||||
|
||||
Reference in New Issue
Block a user