bollwerk/import-inventar.ps1
Jens Reinemann bed233521e feat: Krisenvorrats-Inventar digitalisiert und Import-Skript erstellt
- 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)
2026-05-17 23:21:07 +02:00

203 lines
10 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<#
.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)"