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:
@@ -15,19 +15,19 @@ struct ObjectStockSection: View {
|
||||
|
||||
enum StockSheet: Identifiable {
|
||||
case add
|
||||
case relocate(from: Int?)
|
||||
case remove(loc: Int?)
|
||||
case relocate(from: String?)
|
||||
case remove(loc: String?)
|
||||
var id: String {
|
||||
switch self {
|
||||
case .add: return "add"
|
||||
case .relocate(let f): return "relocate-\(f.map(String.init) ?? "none")"
|
||||
case .remove(let l): return "remove-\(l.map(String.init) ?? "none")"
|
||||
case .relocate(let f): return "relocate-\(f ?? "none")"
|
||||
case .remove(let l): return "remove-\(l ?? "none")"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var einheit: String { product.unitName.isEmpty ? "Stück" : product.unitName }
|
||||
private func ortName(_ id: Int?) -> String {
|
||||
private func ortName(_ id: String?) -> String {
|
||||
guard let id else { return "Ohne Lagerort" }
|
||||
return locations.first { $0.id == id }?.name ?? "Ort \(id)"
|
||||
}
|
||||
@@ -170,12 +170,12 @@ struct ObjectFieldRow: View {
|
||||
private struct LocationPicker: View {
|
||||
let title: String
|
||||
let locations: [StorageLocation]
|
||||
@Binding var selection: Int?
|
||||
@Binding var selection: String?
|
||||
|
||||
var body: some View {
|
||||
Picker(title, selection: $selection) {
|
||||
Text("– ohne Lagerort –").tag(Int?.none)
|
||||
ForEach(locations) { loc in Text(loc.name).tag(Int?.some(loc.id)) }
|
||||
Text("– ohne Lagerort –").tag(String?.none)
|
||||
ForEach(locations) { loc in Text(loc.name).tag(String?.some(loc.id)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -188,7 +188,7 @@ struct ObjectAddSheet: View {
|
||||
var perform: () async -> Void
|
||||
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
@State private var locationId: Int?
|
||||
@State private var locationId: String?
|
||||
@State private var quantity = ""
|
||||
@State private var busy = false
|
||||
@State private var error: String?
|
||||
@@ -229,12 +229,12 @@ struct ObjectAddSheet: View {
|
||||
struct ObjectRelocateSheet: View {
|
||||
let product: Product
|
||||
let locations: [StorageLocation]
|
||||
let initialFrom: Int?
|
||||
let initialFrom: String?
|
||||
var perform: () async -> Void
|
||||
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
@State private var fromId: Int?
|
||||
@State private var toId: Int?
|
||||
@State private var fromId: String?
|
||||
@State private var toId: String?
|
||||
@State private var quantity = ""
|
||||
@State private var busy = false
|
||||
@State private var error: String?
|
||||
@@ -277,11 +277,11 @@ struct ObjectRemoveSheet: View {
|
||||
let product: Product
|
||||
let locations: [StorageLocation]
|
||||
let einheit: String
|
||||
let initialLoc: Int?
|
||||
let initialLoc: String?
|
||||
var perform: () async -> Void
|
||||
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
@State private var locationId: Int?
|
||||
@State private var locationId: String?
|
||||
@State private var quantity = ""
|
||||
@State private var reason = "broken"
|
||||
@State private var note = ""
|
||||
|
||||
Reference in New Issue
Block a user