April 2026 waren Wirtschaft Feedback

This commit is contained in:
Kevin Adametz 2026-04-10 17:14:38 +02:00
parent 02f2a4c23e
commit 9ce711d6b2
167 changed files with 25278 additions and 8518 deletions

View file

@ -0,0 +1,49 @@
<?php
namespace Database\Seeders;
use App\Models\Location;
use App\Models\MaterialQuality;
use App\Models\PackagingMaterial;
use Illuminate\Database\Seeder;
class InventoryStammdatenSeeder extends Seeder
{
public function run(): void
{
$locations = ['Köln', 'Waldböl'];
foreach ($locations as $name) {
Location::query()->firstOrCreate(
['name' => $name],
['active' => true]
);
}
$qualities = [
'konventionell',
'bio kaltgepresst',
'bio raffiniert',
'konventionell kaltgepresst',
'konventionell raffiniert',
];
foreach ($qualities as $pos => $name) {
MaterialQuality::query()->firstOrCreate(
['name' => $name],
['pos' => $pos]
);
}
$materials = [
'Glas',
'Holz/Bambus',
'Pappe/Papier',
'Kunststoff',
];
foreach ($materials as $pos => $name) {
PackagingMaterial::query()->firstOrCreate(
['name' => $name],
['pos' => $pos]
);
}
}
}

View file

@ -0,0 +1,315 @@
<?php
namespace Database\Seeders;
use App\Models\Country;
use App\Models\Ingredient;
use App\Models\Location;
use App\Models\PackagingItem;
use App\Models\PackagingMaterial;
use App\Models\StockEntry;
use App\Models\Supplier;
use App\Models\SupplierCategory;
use App\User;
use Illuminate\Database\Seeder;
/**
* Befüllt Stammdaten der Warenwirtschaft mit erkennbaren Demo-/Testinhalten.
* Ruft zuerst {@see InventoryStammdatenSeeder} auf (Lagerorte, Qualitäten, Verpackungsmaterialien).
*
* Aufruf: php artisan db:seed --class=InventoryStammdatenTestSeeder
*/
class InventoryStammdatenTestSeeder extends Seeder
{
public function run(): void
{
$this->call(InventoryStammdatenSeeder::class);
$countryDe = Country::query()->firstOrCreate(
['code' => 'DE'],
[
'phone' => '49',
'en' => 'Germany',
'de' => 'Deutschland',
'es' => 'Alemania',
'fr' => 'Allemagne',
'it' => 'Germania',
'ru' => 'Германия',
'active' => true,
]
);
$locationExtra = Location::query()->firstOrCreate(
['name' => 'Demo Test-Zentrallager'],
['active' => true]
);
$catRohstoffe = SupplierCategory::query()->firstOrCreate(
['name' => 'Demo Rohstoffe'],
['pos' => 1]
);
$catVerpackung = SupplierCategory::query()->firstOrCreate(
['name' => 'Demo Verpackung & Zubehör'],
['pos' => 2]
);
$catDienst = SupplierCategory::query()->firstOrCreate(
['name' => 'Demo Dienstleistung'],
['pos' => 3]
);
$supplierOele = Supplier::query()->firstOrCreate(
['name' => 'Demo-Lieferant Naturöle GmbH'],
[
'url' => 'https://demo-naturoele.example.test',
'contact_person' => 'Erika Beispiel',
'email' => 'einkauf@demo-naturoele.example.test',
'phone' => '+49 221 5550100',
'country_id' => $countryDe->id,
'notes' => 'Seeder-Testdaten Rohstoffe (Öle, Butter).',
'active' => true,
]
);
$supplierOele->supplierCategories()->sync([
$catRohstoffe->id,
$catVerpackung->id,
]);
$supplierGlas = Supplier::query()->firstOrCreate(
['name' => 'Demo Verpackung Glas & Co.'],
[
'url' => 'https://demo-glas.example.test',
'contact_person' => 'Tom Test',
'email' => 'vertrieb@demo-glas.example.test',
'phone' => '+49 211 5550200',
'country_id' => $countryDe->id,
'notes' => 'Seeder-Testdaten Flaschen und Gläser.',
'active' => true,
]
);
$supplierGlas->supplierCategories()->sync([
$catVerpackung->id,
]);
$supplierLogistik = Supplier::query()->firstOrCreate(
['name' => 'Demo Logistik Partner'],
[
'url' => null,
'contact_person' => 'Lisa Versand',
'email' => 'buero@demo-logistik.example.test',
'phone' => '+49 40 5550300',
'country_id' => $countryDe->id,
'notes' => 'Seeder-Testdaten Kartons, Versandmaterial.',
'active' => true,
]
);
$supplierLogistik->supplierCategories()->sync([
$catVerpackung->id,
$catDienst->id,
]);
$materialGlas = PackagingMaterial::query()->where('name', 'Glas')->first();
$materialKunststoff = PackagingMaterial::query()->where('name', 'Kunststoff')->first();
$materialPappe = PackagingMaterial::query()->where('name', 'Pappe/Papier')->first();
if ($materialGlas) {
PackagingItem::query()->firstOrCreate(
['name' => 'Demo Braunglasflasche 30 ml'],
[
'packaging_material_id' => $materialGlas->id,
'supplier_id' => $supplierGlas->id,
'category' => 'packaging',
'weight_grams' => 45.5,
'min_stock_alert' => 200,
'product_id' => null,
'active' => true,
]
);
PackagingItem::query()->firstOrCreate(
['name' => 'Demo Tropferflasche Klarglas 10 ml'],
[
'packaging_material_id' => $materialGlas->id,
'supplier_id' => $supplierGlas->id,
'category' => 'packaging',
'weight_grams' => 22,
'min_stock_alert' => 500,
'product_id' => null,
'active' => true,
]
);
}
if ($materialKunststoff) {
PackagingItem::query()->firstOrCreate(
['name' => 'Demo Pumpspender 150 ml (PET)'],
[
'packaging_material_id' => $materialKunststoff->id,
'supplier_id' => $supplierGlas->id,
'category' => 'packaging',
'weight_grams' => 28.75,
'min_stock_alert' => 150,
'product_id' => null,
'active' => true,
]
);
}
if ($materialPappe) {
PackagingItem::query()->firstOrCreate(
['name' => 'Demo Faltschachtel S (bedruckt)'],
[
'packaging_material_id' => $materialPappe->id,
'supplier_id' => $supplierLogistik->id,
'category' => 'packaging',
'weight_grams' => 12,
'min_stock_alert' => 1000,
'product_id' => null,
'active' => true,
]
);
PackagingItem::query()->firstOrCreate(
['name' => 'Demo Versandkarton S'],
[
'packaging_material_id' => $materialPappe->id,
'supplier_id' => $supplierLogistik->id,
'category' => 'shipping_office',
'weight_grams' => 95,
'min_stock_alert' => 300,
'product_id' => null,
'active' => true,
]
);
PackagingItem::query()->firstOrCreate(
['name' => 'Demo Etikett Front 50×80 mm'],
[
'packaging_material_id' => $materialPappe->id,
'supplier_id' => $supplierOele->id,
'category' => 'label',
'weight_grams' => 1.2,
'min_stock_alert' => 5000,
'product_id' => null,
'active' => true,
]
);
}
$locationKoln = Location::query()->where('name', 'Köln')->first() ?? $locationExtra;
$orderUser = User::query()->firstOrCreate(
['email' => 'demo-wareneingang@example.test'],
[
'password' => bcrypt('password'),
'admin' => 7,
'confirmed' => true,
'active' => true,
'wizard' => 100,
'blocked' => false,
]
);
$ingShea = Ingredient::query()->firstOrCreate(
['name' => 'Demo Wareneingang Shea Butter'],
[
'trans_name' => '',
'inci' => 'Butyrospermum Parkii Butter',
'trans_inci' => '',
'effect' => '',
'trans_effect' => '',
'active' => true,
'pos' => 0,
]
);
$ingMandel = Ingredient::query()->firstOrCreate(
['name' => 'Demo Wareneingang Mandelöl'],
[
'trans_name' => '',
'inci' => 'Prunus Amygdalus Dulcis Oil',
'trans_inci' => '',
'effect' => '',
'trans_effect' => '',
'active' => true,
'pos' => 0,
]
);
StockEntry::factory()->create([
'ingredient_id' => $ingShea->id,
'supplier_id' => $supplierOele->id,
'location_id' => $locationKoln->id,
'ordered_by' => $orderUser->id,
'ordered_at' => now()->subDays(5)->format('Y-m-d'),
'ordered_quantity' => 10000,
'price_per_kg' => 8.5,
'entry_type' => 'ingredient',
'unit' => 'gram',
'packaging_item_id' => null,
'status' => 'pending',
]);
StockEntry::factory()->create([
'ingredient_id' => $ingMandel->id,
'supplier_id' => $supplierOele->id,
'location_id' => $locationKoln->id,
'ordered_by' => $orderUser->id,
'ordered_at' => now()->subDays(12)->format('Y-m-d'),
'ordered_quantity' => 5000,
'price_per_kg' => 9.95,
'entry_type' => 'ingredient',
'unit' => 'gram',
'packaging_item_id' => null,
'status' => 'pending',
]);
$demoPackagingItem = PackagingItem::query()
->where('name', 'like', 'Demo %')
->where('category', 'packaging')
->first();
if ($demoPackagingItem !== null) {
StockEntry::query()->create([
'entry_type' => 'packaging',
'ingredient_id' => null,
'packaging_item_id' => $demoPackagingItem->id,
'supplier_id' => $supplierGlas->id,
'location_id' => $locationKoln->id,
'unit' => 'piece',
'ordered_by' => $orderUser->id,
'ordered_at' => now()->subDays(2)->format('Y-m-d'),
'ordered_quantity' => 480,
'price_per_kg' => null,
'price_total' => 612.0,
'received_by' => null,
'received_at' => null,
'received_quantity' => null,
'batch_number' => null,
'best_before' => null,
'quality_id' => null,
'status' => 'pending',
]);
}
StockEntry::factory()->received()->create([
'ingredient_id' => $ingMandel->id,
'supplier_id' => $supplierOele->id,
'location_id' => $locationKoln->id,
'ordered_by' => $orderUser->id,
'ordered_at' => now()->subMonths(2)->format('Y-m-d'),
'ordered_quantity' => 3000,
'price_per_kg' => 9.5,
'entry_type' => 'ingredient',
'unit' => 'gram',
'packaging_item_id' => null,
]);
$this->command?->info(sprintf(
'Inventory-Stammdaten-Test: DE (countries.id=%d), Lagerort „%s“ (id=%d), Lieferanten-IDs %d / %d / %d; Verpackungsartikel mit Präfix „Demo …“; Demo-Wareneingänge (stock_entries) mit User %s.',
$countryDe->id,
$locationExtra->name,
$locationExtra->id,
$supplierOele->id,
$supplierGlas->id,
$supplierLogistik->id,
$orderUser->email
));
}
}

View file

@ -0,0 +1,234 @@
<?php
namespace Database\Seeders;
use App\Models\Ingredient;
use App\Models\Location;
use App\Models\PackagingItem;
use App\Models\Product;
use App\Models\Production;
use App\Models\StockEntry;
use App\Models\Supplier;
use App\Services\ProductionService;
use App\User;
use Illuminate\Database\Seeder;
/**
* Demo-Daten für Phase 5 (Produktion): Rezeptur, eingegangene Chargen, Beispiel-Produktionsläufe.
* Baut auf {@see InventoryStammdatenTestSeeder} auf (Demo-Rohstoffe, Lagerort Köln, Verpackung).
*
* Aufruf: php artisan db:seed --class=ProductionDemoSeeder
*/
class ProductionDemoSeeder extends Seeder
{
public function run(): void
{
$this->call(InventoryStammdatenTestSeeder::class);
$location = Location::query()->where('name', 'Köln')->first()
?? Location::query()->where('name', 'Demo Test-Zentrallager')->first()
?? Location::query()->first();
if ($location === null) {
$this->command?->error('ProductionDemoSeeder: Kein Lagerort gefunden.');
return;
}
$ingShea = Ingredient::query()->where('name', 'Demo Wareneingang Shea Butter')->first();
$ingMandel = Ingredient::query()->where('name', 'Demo Wareneingang Mandelöl')->first();
if ($ingShea === null || $ingMandel === null) {
$this->command?->error('ProductionDemoSeeder: Demo-Inhaltsstoffe fehlen (Shea/Mandel).');
return;
}
$supplierOele = Supplier::query()->where('name', 'Demo-Lieferant Naturöle GmbH')->first();
if ($supplierOele === null) {
$this->command?->error('ProductionDemoSeeder: Demo-Lieferant fehlt.');
return;
}
$orderUser = User::query()->where('email', 'demo-wareneingang@example.test')->first();
if ($orderUser === null) {
$this->command?->error('ProductionDemoSeeder: User demo-wareneingang@example.test fehlt.');
return;
}
$sheaStock = StockEntry::query()
->where('ingredient_id', $ingShea->id)
->where('location_id', $location->id)
->where('status', 'received')
->orderByDesc('id')
->first();
if ($sheaStock === null) {
$sheaStock = StockEntry::factory()->received()->create([
'ingredient_id' => $ingShea->id,
'supplier_id' => $supplierOele->id,
'location_id' => $location->id,
'ordered_by' => $orderUser->id,
'ordered_at' => now()->subMonths(3)->format('Y-m-d'),
'ordered_quantity' => 8000,
'price_per_kg' => 8.5,
'entry_type' => 'ingredient',
'unit' => 'gram',
'packaging_item_id' => null,
'batch_number' => 'DEMO-SHEA-PROD',
'best_before' => now()->addMonths(18)->format('Y-m-d'),
]);
}
$mandelStock = StockEntry::query()
->where('ingredient_id', $ingMandel->id)
->where('location_id', $location->id)
->where('status', 'received')
->orderByDesc('received_at')
->orderByDesc('id')
->first();
if ($mandelStock === null) {
$mandelStock = StockEntry::factory()->received()->create([
'ingredient_id' => $ingMandel->id,
'supplier_id' => $supplierOele->id,
'location_id' => $location->id,
'ordered_by' => $orderUser->id,
'ordered_at' => now()->subMonths(2)->format('Y-m-d'),
'ordered_quantity' => 5000,
'price_per_kg' => 9.5,
'entry_type' => 'ingredient',
'unit' => 'gram',
'packaging_item_id' => null,
'batch_number' => 'DEMO-MANDEL-PROD',
'best_before' => now()->addMonths(20)->format('Y-m-d'),
]);
}
$bottle = PackagingItem::query()->where('name', 'Demo Braunglasflasche 30 ml')->first();
$product = Product::query()->firstOrCreate(
['name' => 'Demo Produktion Handcreme 30 ml'],
[
'title' => 'Demo Produktion Handcreme 30 ml',
'active' => true,
'shelf_life_type' => null,
'shelf_life_months' => null,
]
);
if ($product->p_ingredients()->count() === 0) {
$product->p_ingredients()->sync([
$ingShea->id => ['pos' => 0, 'gram' => 20, 'factor' => 1],
$ingMandel->id => ['pos' => 1, 'gram' => 15, 'factor' => 1],
]);
}
if ($bottle !== null && $product->packagings()->count() === 0) {
$product->packagings()->sync([
$bottle->id => ['quantity' => 1, 'pos' => 0],
]);
}
$service = app(ProductionService::class);
if (! Production::query()->where('product_id', $product->id)->exists()) {
$qty = 10;
$service->store(
[
'product_id' => $product->id,
'location_id' => $location->id,
'produced_at' => now()->subDays(3)->format('Y-m-d'),
'quantity' => $qty,
'notes' => 'Seeder: Demo-Produktionslauf (Shea + Mandel, Braunglas).',
],
[
[
'ingredient_id' => $ingShea->id,
'stock_entry_id' => $sheaStock->id,
'quantity_used' => (string) (20 * 1 * $qty),
],
[
'ingredient_id' => $ingMandel->id,
'stock_entry_id' => $mandelStock->id,
'quantity_used' => (string) (15 * 1 * $qty),
],
],
$orderUser->id
);
}
$mhdStock = StockEntry::query()
->where('ingredient_id', $ingMandel->id)
->where('location_id', $location->id)
->where('status', 'received')
->where('batch_number', 'DEMO-MHD-WARNUNG')
->first();
if ($mhdStock === null) {
$mhdStock = StockEntry::factory()->received()->create([
'ingredient_id' => $ingMandel->id,
'supplier_id' => $supplierOele->id,
'location_id' => $location->id,
'ordered_by' => $orderUser->id,
'ordered_at' => now()->subYear()->format('Y-m-d'),
'ordered_quantity' => 500,
'price_per_kg' => 9.5,
'entry_type' => 'ingredient',
'unit' => 'gram',
'packaging_item_id' => null,
'batch_number' => 'DEMO-MHD-WARNUNG',
'best_before' => '2027-06-01',
'received_at' => now()->subMonths(6)->format('Y-m-d'),
]);
}
$productMhd = Product::query()->firstOrCreate(
['name' => 'Demo Produktion MHD-Warnung (Test)'],
[
'title' => 'Demo MHD-Warnung',
'active' => true,
'shelf_life_type' => 'fixed',
'shelf_life_months' => 24,
]
);
if ($productMhd->p_ingredients()->count() === 0) {
$productMhd->p_ingredients()->sync([
$ingMandel->id => ['pos' => 0, 'gram' => 10, 'factor' => 1],
]);
}
if (! Production::query()->where('product_id', $productMhd->id)->exists()) {
$service->store(
[
'product_id' => $productMhd->id,
'location_id' => $location->id,
'produced_at' => '2026-03-01',
'quantity' => 1,
'notes' => 'Seeder: MHD-Warnung (Rohstoff-MHD vor Produkt-Ende).',
],
[
[
'ingredient_id' => $ingMandel->id,
'stock_entry_id' => $mhdStock->id,
'quantity_used' => '10',
],
],
$orderUser->id
);
}
$this->command?->info(sprintf(
'ProductionDemoSeeder: Produkt „%s“ (id=%d), MHD-Demo „%s“ (id=%d), Lagerort %s (id=%d).',
$product->name,
$product->id,
$productMhd->name,
$productMhd->id,
$location->name,
$location->id
));
}
}