<# .SYNOPSIS Importiert das Bollwerk-Vorratsinventar in den Server (einmaliger PUT). Verwendet App-Default-Kategorien (IDs 1-7) und Default-Location Keller (ID 1). .PARAMETER BaseUrl Server-URL. Standard: https://bollwerk.online .PARAMETER AdminUser Admin-Benutzername. Standard: admin .EXAMPLE .\import-inventar.ps1 .\import-inventar.ps1 -BaseUrl "http://localhost:8080" #> param( [string]$BaseUrl = "https://bollwerk.online", [string]$AdminUser = "admin" ) $ErrorActionPreference = "Stop" # --------------------------------------------------------------------------- # Umlaute via [char] - PS 5.1 liest .ps1-Dateien als ANSI/CP1252. # UTF-8-Umlaute im Quelltext wuerden den Parser brechen (byte 0xB6 = Pilcrow). # --------------------------------------------------------------------------- $oe = [char]246 # o-Umlaut $ue = [char]252 # u-Umlaut $ae = [char]228 # a-Umlaut $ss = [char]223 # scharfes S $ag = [char]224 # a-grave (fuer "a 2300 kcal", "a 20 ml") # --------------------------------------------------------------------------- # Passwort sicher einlesen (erscheint NICHT in der History) # --------------------------------------------------------------------------- $secure = Read-Host "Admin-Passwort fuer '$AdminUser' @ $BaseUrl" -AsSecureString $AdminPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto( [Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure) ) # --------------------------------------------------------------------------- # HTTP-Hilfsfunktion (identisch mit run-integration-tests.ps1 – UTF-8-safe) # --------------------------------------------------------------------------- function Invoke-Api { param( [string]$Method, [string]$Path, [object]$Body = $null, [string]$Token = $null ) $headers = @{ "Content-Type" = "application/json" } if ($Token) { $headers["Authorization"] = "Bearer $Token" } $bodyJson = if ($Body) { $Body | ConvertTo-Json -Depth 10 -Compress } else { $null } if ($bodyJson) { $sb = [System.Text.StringBuilder]::new($bodyJson.Length * 2) foreach ($ch in $bodyJson.ToCharArray()) { if ([int]$ch -gt 127) { [void]$sb.Append('\u{0:x4}' -f [int]$ch) } else { [void]$sb.Append($ch) } } $bodyJson = $sb.ToString() } $response = Invoke-RestMethod -Method $Method -Uri "$BaseUrl$Path" ` -Body $bodyJson -Headers $headers -ErrorAction Stop return $response } # --------------------------------------------------------------------------- # 1. Login # --------------------------------------------------------------------------- Write-Host "Logge ein als '$AdminUser'..." -ForegroundColor Cyan $auth = Invoke-Api -Method POST -Path "/api/auth/login" -Body @{ username = $AdminUser password = $AdminPassword } $token = $auth.accessToken Write-Host " Token erhalten." -ForegroundColor Green # --------------------------------------------------------------------------- # 2. Vorhandenes Inventar pruefen # --------------------------------------------------------------------------- Write-Host "Pruefe vorhandenes Inventar..." -ForegroundColor Cyan $existing = Invoke-Api -Method GET -Path "/api/inventory" -Token $token if ($existing.items.Count -gt 0) { Write-Host "" Write-Host " WARNUNG: Das Inventar enthaelt bereits $($existing.items.Count) Artikel!" -ForegroundColor Yellow $confirm = Read-Host " Ueberschreiben? (ja/nein)" if ($confirm -ne "ja") { Write-Host "Abgebrochen." -ForegroundColor Red exit 1 } } # --------------------------------------------------------------------------- # 3. Inventar-Daten definieren (aus inventar.md, Stand Mai 2026) # --------------------------------------------------------------------------- $now = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds() function NewItem($name, $catId, $qty, $unit, $expiry, $kcal, $notes) { @{ id = [System.Guid]::NewGuid().ToString() name = $name categoryId = $catId quantity = [double]$qty unit = $unit unitPrice = 0.0 kcalPerUnit = $kcal expiryDate = $expiry locationId = 1 notes = if ($notes) { $notes } else { "" } lastUpdated = $now } } # App-Default-Kategorien (IDs aus SeedDatabaseUseCase) $categories = @( @{ id = 1; name = "Lebensmittel" } @{ id = 2; name = "Wasser" } @{ id = 3; name = "Medikamente" } @{ id = 4; name = "Ausr${ue}stung" } @{ id = 5; name = "Hygiene" } @{ id = 6; name = "Energie & Licht" } @{ id = 7; name = "Dokumente" } ) # App-Default-Lagerort $locations = @( @{ id = 1; name = "Keller" } ) $items = @( # -- Lebensmittel: Getreide & Huelsenfruechte (cat 1) -------------------- NewItem "Dinkelkorn" 1 16 "Beutel" $null $null "Jahrgang 2019, vakuumiert" NewItem "Weizen (Naturland)" 1 36 "kg" $null $null "Jahrgang 2023" NewItem "Dinkel" 1 40 "kg" $null $null "Jahrgang 2023" NewItem "Bio-Weizen" 1 18 "kg" $null $null "Jahrgang 2019" NewItem "Bio-Weizen (Neu)" 1 200 "kg" $null $null "Jahrgang 05/2026, Kunststoffbehaelter, O2-Absorber, Trockenmittel, lose luftdicht" NewItem "Gr${ue}ne Erbsen" 1 10 "kg" $null $null "Jahrgang 2019" NewItem "Gelbe Sch${ae}lerbsen" 1 10 "kg" $null $null "Jahrgang 2019" NewItem "Berglinsen (1 kg)" 1 1 "Pkg." "2021-12-31" $null "MHD abgelaufen" NewItem "Berglinsen (500 g)" 1 4 "Pkg." "2023-12-31" $null "MHD abgelaufen" NewItem "Wei${ss}e Bohnen" 1 2 "Pkg." "2022-12-31" $null "MHD abgelaufen" NewItem "Jodsalz" 1 25 "kg" $null $null "" # -- Lebensmittel: Konserven (cat 1) ------------------------------------- NewItem "Kondensmilch gezuckert (Dovgan)" 1 88 "Dosen" $null $null "MHD pruefen" NewItem "Corned Beef (Exeter)" 1 48 "Dosen" $null $null "MHD pruefen" NewItem "Gesch${ae}lte Tomaten" 1 5 "Dosen" $null $null "2x 2,5 kg, MHD abgelaufen" NewItem "Tomatenmark (200 g)" 1 24 "Dosen" $null $null "MHD abgelaufen" NewItem "Sardinen" 1 5 "Dosen" $null $null "MHD abgelaufen" NewItem "Heringsfilet in Tomatenso${ss}e" 1 11 "Dosen" $null $null "MHD abgelaufen" NewItem "Thunfisch gro${ss} (900 g)" 1 3 "Dosen" $null $null "MHD abgelaufen" NewItem "Thunfisch klein" 1 9 "Dosen" $null $null "MHD abgelaufen" NewItem "Brathering Filet" 1 2 "Dosen" $null $null "MHD abgelaufen" NewItem "Dosenbrot" 1 6 "Dosen" $null $null "MHD abgelaufen" # -- Lebensmittel: Oele & Fette (cat 1) ---------------------------------- NewItem "Oliven${oe}l (750 ml)" 1 3 "Flaschen" "2022-12-31" $null "MHD abgelaufen" NewItem "Avocado${oe}l (250 ml)" 1 3 "Flaschen" "2026-12-31" $null "MHD 2026, pruefen" NewItem "Sonnenblumen${oe}l (1 L)" 1 3 "Flaschen" "2021-12-31" $null "MHD abgelaufen" NewItem "Sonnenblumen${oe}l (500 ml)" 1 1 "Flaschen" "2023-12-31" $null "MHD abgelaufen" # -- Lebensmittel: Getraenke (cat 1) ------------------------------------- NewItem "Instant-Kaffee" 1 12 "Stk." "2024-12-31" $null "MHD abgelaufen" NewItem "Trek'N'Eat Peronin" 1 8 "Stk." "2024-12-31" $null "MHD abgelaufen" # -- Lebensmittel: Notfallrationen (cat 1) -------------------------------- NewItem "Conserva-Set" 1 30 "Manntage" $null 2300 "${ag} 2300 kcal/Tag, conserva.de" NewItem "NRG-5 Katadyn (Neubestand)" 1 96 "Tagesrationen" "2036-04-30" 2300 "4x24, Produktion April 2026" NewItem "NRG-5 Katadyn (Altbestand)" 1 19 "Tagesrationen" "2029-01-31" 2300 "Produktion 2019, 5 Rationen verbraucht" # -- Medikamente (cat 3) ------------------------------------------------- NewItem "Vitamine" 3 960 "Stk." $null $null "3x240 + 2x120 Tabletten" # -- Ausruestung (cat 4) ------------------------------------------------- NewItem "PMR-Funkger${ae}t (Midland G9 Pro)" 4 2 "Stk." $null $null "" # -- Hygiene (cat 5) ----------------------------------------------------- NewItem "Shampoo Mini" 5 50 "Stk." $null $null "${ag} 20 ml" NewItem "Ethanol" 5 30 "Liter" $null $null "" NewItem "Isopropanol" 5 4 "Liter" $null $null "" NewItem "Methanol" 5 1 "Liter" $null $null "" NewItem "Desinfektionsmittel" 5 5 "Liter" $null $null "" # -- Energie & Licht (cat 6) --------------------------------------------- NewItem "Petroleum" 6 50 "Liter" $null $null "" ) $inventory = @{ version = 1 categories = $categories locations = $locations items = $items settings = @() deletedItemIds = @() } # --------------------------------------------------------------------------- # 4. PUT /api/inventory # --------------------------------------------------------------------------- Write-Host "Lade $($items.Count) Artikel in $($categories.Count) Kategorien hoch..." -ForegroundColor Cyan $result = Invoke-Api -Method PUT -Path "/api/inventory" -Body $inventory -Token $token Write-Host "" Write-Host "Fertig!" -ForegroundColor Green Write-Host " Artikel hochgeladen : $($result.items.Count)" Write-Host " Kategorien : $($result.categories.Count)" Write-Host " Lagerorte : $($result.locations.Count)"