- inventar.md: 38 Artikel aus handschriftlicher Liste erfasst (Lebensmittel, Medikamente, Ausrüstung, Hygiene, Energie) - import-inventar.py: Python-Skript zum einmaligen PUT /api/inventory (UTF-8-safe via ensure_ascii=True, kein PowerShell-Encoding-Problem) - import-inventar.ps1: PowerShell-Variante (Umlaute via [char]-Variablen)
203 lines
10 KiB
PowerShell
203 lines
10 KiB
PowerShell
<#
|
||
.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)"
|