Warenwirtschaft: Anforderungsrunde 12.06. — Plan V5.0 + AP-26/AP-25/AP-22

Neue Anforderungen (docs/) interpretiert und als Entwicklungsplan V5.0
(AP-20 bis AP-28) aufgenommen; erste drei Pakete umgesetzt:

AP-26 Ausschuss-Gründe konfigurierbar:
- Stammdaten-Tabelle disposal_reasons + CRUD unter Einstellungen → Allgemein
- StockDisposalController liest aktive DB-Gründe statt hartkodierter Liste
- Seeder übernimmt die bisherigen 6 Gründe idempotent

AP-25 Lieferbestand — Datum statt Tage:
- "Nicht vorrätig" wird über Datepicker "Wieder lieferbar ab" gepflegt;
  Resttage-Hinweis zählt täglich automatisch herunter
- Interne Bestellliste wieder kaufbar: Hinweis erscheint zusätzlich zu
  den Mengen-Buttons (VP entscheidet selbst)

AP-22 Produktbestand-Erweiterungen:
- Default-Sortierung nach Dringlichkeit, Status-Kopf toggelt
- Alle vier Status-Kacheln als Filter klickbar
- Neue Spalte "Verbrauch/Monat" (Ø Abgänge der letzten 6 Monate)
- Produkt-Flag "Im Produktbestand anzeigen" (products.show_in_product_stock)

Tests: 77 grün (DisposalReasonSettings 8, ProductOutOfStock 8,
ProductStock 13 + Regression). Hinweise-Doku + Plan-Protokoll fortgeschrieben;
nächster Schritt laut Plan: AP-21 (INCI-Erweiterungen).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-06-12 16:28:45 +00:00
parent a8f6fef38e
commit e53201f229
32 changed files with 1377 additions and 94 deletions

View file

@ -0,0 +1,33 @@
<?php
namespace Database\Factories;
use App\Models\DisposalReason;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<DisposalReason>
*/
class DisposalReasonFactory extends Factory
{
protected $model = DisposalReason::class;
/**
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'label' => $this->faker->unique()->randomElement([
'Bruch / Beschädigung',
'Verfall / MHD überschritten',
'Qualitätsmangel',
'Schwund / Inventurdifferenz',
'Muster / Testverbrauch',
'Sonstiges',
]),
'active' => true,
'pos' => 0,
];
}
}

View file

@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('disposal_reasons', function (Blueprint $table) {
$table->id();
$table->string('label');
$table->boolean('active')->default(true);
$table->unsignedTinyInteger('pos')->default(0);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('disposal_reasons');
}
};

View file

@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('products', function (Blueprint $table) {
// AP-22: Produkte (z. B. Abrechnungs-/Druckkosten-Positionen) aus dem Produktbestand ausblendbar.
$table->boolean('show_in_product_stock')->default(true)->after('critical_product_stock');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('products', function (Blueprint $table) {
$table->dropColumn('show_in_product_stock');
});
}
};

View file

@ -3,6 +3,7 @@
namespace Database\Seeders;
use App\Models\DeliveryTime;
use App\Models\DisposalReason;
use App\Models\Location;
use App\Models\MaterialQuality;
use App\Models\PackagingMaterial;
@ -71,5 +72,20 @@ class InventoryStammdatenSeeder extends Seeder
['days' => $deliveryTime['days'], 'active' => true, 'pos' => $pos]
);
}
$disposalReasons = [
'Bruch / Beschädigung',
'Verfall / MHD überschritten',
'Qualitätsmangel',
'Schwund / Inventurdifferenz',
'Muster / Testverbrauch',
'Sonstiges',
];
foreach ($disposalReasons as $pos => $label) {
DisposalReason::query()->firstOrCreate(
['label' => $label],
['active' => true, 'pos' => $pos]
);
}
}
}