Lagerorte per 10-Zeichen-Code statt fortlaufender ID; iOS-Einlagern ohne Kamerazwang

Lagerort-IDs sind jetzt ein zufaelliger 10-Zeichen-Code (wie die Einzelstueck-UIDs) statt einer fortlaufenden Zahl - so kollidiert die Stammdaten-Sicherung zwischen zwei Instanzen praktisch nie mehr, und der Code ist zugleich der Inhalt des QR /l/<code>. Alle Fremdschluessel (lots, movements, items, Mindestbestaende, parent_id) ziehen mit; die Umstellung laeuft einmalig und transaktional beim Serverstart (_migrate_locations_to_code) und rollt bei Fehlern komplett zurueck. Vor dem Deploy ein DB-Backup machen.

iOS-Einlagern oeffnet nicht mehr sofort die Kamera, sondern ein Formular mit Artikelsuche; die Kamera kommt erst per Button. Im Formular laesst sich der Lagerort zusaetzlich per /l/-QR scannen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-07-27 12:15:25 +02:00
parent 6e48cd0a7a
commit d518b4aa23
23 changed files with 507 additions and 220 deletions

View File

@@ -134,10 +134,10 @@ struct Product: Codable, Identifiable, Hashable {
/// Mindestbestand eines Produkts/einer Gruppe an einem Lagerort (Anzeige).
struct LocationMinStock: Codable, Hashable, Identifiable {
let locationId: Int
let locationId: String
let locationName: String?
let minStock: Double
var id: Int { locationId }
var id: String { locationId }
enum CodingKeys: String, CodingKey {
case minStock = "min_stock"
@@ -148,7 +148,7 @@ struct LocationMinStock: Codable, Hashable, Identifiable {
/// Ein Mindestbestand-Eintrag zum Speichern (Menge in Artikeleinheiten).
struct LocationMinStockIn: Codable {
let locationId: Int
let locationId: String
let minStock: Double
enum CodingKeys: String, CodingKey {
@@ -217,7 +217,7 @@ struct Lot: Codable, Identifiable, Hashable {
let quantity: Double
let bestBefore: String?
let bestBeforePrecision: String?
let locationId: Int?
let locationId: String?
enum CodingKeys: String, CodingKey {
case id, quantity
@@ -229,9 +229,9 @@ struct Lot: Codable, Identifiable, Hashable {
}
struct StorageLocation: Codable, Identifiable, Hashable {
let id: Int
let id: String
let name: String
let parentId: Int?
let parentId: String?
enum CodingKeys: String, CodingKey {
case id, name
@@ -243,7 +243,7 @@ struct CheckInLine: Codable {
let quantity: Double
let bestBefore: String?
let bestBeforePrecision: String
let locationId: Int?
let locationId: String?
enum CodingKeys: String, CodingKey {
case quantity
@@ -391,12 +391,12 @@ struct LocationNeedGroup: Codable, Identifiable {
}
struct LocationNeeds: Codable, Identifiable {
let locationId: Int
let locationId: String
let locationName: String
let products: [LocationNeedProduct]
let groups: [LocationNeedGroup]
var id: Int { locationId }
var id: String { locationId }
enum CodingKeys: String, CodingKey {
case products, groups
@@ -531,9 +531,9 @@ struct CategoryItem: Codable, Identifiable, Hashable {
/// Gemeinsame Form baumartiger Stammdaten (Kategorien, Lagerorte): eine flache
/// Liste mit Eltern-Verweis, aus der sich der Baum aufbauen lässt.
protocol TreeItem: Identifiable where ID == Int {
protocol TreeItem: Identifiable {
var name: String { get }
var parentId: Int? { get }
var parentId: ID? { get }
}
extension CategoryItem: TreeItem {}
@@ -580,7 +580,7 @@ struct ObjectCheckInRequest: Codable {
let productId: Int
let quantity: Double
let unit: String
let locationId: Int?
let locationId: String?
enum CodingKeys: String, CodingKey {
case quantity, unit
@@ -592,8 +592,8 @@ struct ObjectCheckInRequest: Codable {
struct RelocateRequest: Codable {
let productId: Int
let quantity: Double
let fromLocationId: Int?
let toLocationId: Int?
let fromLocationId: String?
let toLocationId: String?
enum CodingKeys: String, CodingKey {
case quantity
@@ -606,7 +606,7 @@ struct RelocateRequest: Codable {
struct RemoveRequest: Codable {
let productId: Int
let quantity: Double
let locationId: Int?
let locationId: String?
let reason: String
let note: String?
@@ -627,7 +627,7 @@ struct RemovalStat: Codable, Identifiable, Hashable {
struct RemovalHistoryItem: Codable, Identifiable, Hashable {
let reason: String
let quantity: Double
let locationId: Int?
let locationId: String?
let locationName: String?
let note: String?
let username: String?
@@ -681,7 +681,7 @@ struct Item: Codable, Identifiable, Hashable {
let id: Int
let uid: String
let productId: Int
let locationId: Int?
let locationId: String?
let locationName: String?
let shopId: Int?
let shopName: String?
@@ -757,7 +757,7 @@ struct ItemDocumentUpload: Codable {
struct ItemCreateRequest: Codable {
let count: Int
let locationId: Int?
let locationId: String?
let shopId: Int?
let acquiredOn: String?
let warrantyUntil: String?
@@ -776,7 +776,7 @@ struct ItemCreateRequest: Codable {
}
struct ItemUpdateRequest: Encodable {
var locationId: Int?
var locationId: String?
var shopId: Int?
var acquiredOn: String?
var warrantyUntil: String?
@@ -996,7 +996,7 @@ struct PackageType: Codable, Identifiable, Hashable {
struct NewLocationRequest: Codable {
let name: String
let parentId: Int?
let parentId: String?
enum CodingKeys: String, CodingKey {
case name
@@ -1008,7 +1008,7 @@ struct NewLocationRequest: Codable {
/// (auch `null` = oberste Ebene), damit auf oberste Ebene holen" ankommt.
struct LocationUpdateRequest: Codable {
let name: String
let parentId: Int?
let parentId: String?
enum CodingKeys: String, CodingKey {
case name