Datenmodell Kern: Projekt, PFA, Vertrag, LV, Nachtrag, Dokument
- Mandant, Auftragnehmer, Projekt mit Suchreihenfolge, Abschnitt (PFA), Vertrag, Leistungsverzeichnis, Nachtrag (MKA nur als Bezug), Nachtragsposition, Dokument - Projektmitglieder mit Projektrolle, Freigaben für vertrauliche Dokumente - Mandant, Land und Projekt werden vom übergeordneten Datensatz übernommen; Fehlzuordnungen über Mandanten oder Projekte hinweg werden abgewiesen - Feste Morph-Map, Factories, Demodaten (Musterbahn, PFA 1–4, N14/N16/N21), Tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
ca09d23a78
commit
6aac8b0a16
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Datenmodell;
|
||||
|
||||
use App\Enums\DokumentKategorie;
|
||||
use App\Enums\NachtragStatus;
|
||||
use App\Enums\Projektrolle;
|
||||
use App\Models\Abschnitt;
|
||||
use App\Models\Auftragnehmer;
|
||||
use App\Models\Dokument;
|
||||
use App\Models\Nachtrag;
|
||||
use App\Models\Nachtragsposition;
|
||||
use App\Models\Projekt;
|
||||
use App\Models\User;
|
||||
use App\Models\Vertrag;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class BeziehungenTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_auftragnehmer_kann_in_mehreren_abschnitten_vertraege_haben(): void
|
||||
{
|
||||
$projekt = Projekt::factory()->create();
|
||||
$auftragnehmer = Auftragnehmer::factory()->create(['mandant_id' => $projekt->mandant_id]);
|
||||
[$pfa3, $pfa4] = Abschnitt::factory()->count(2)->create(['projekt_id' => $projekt->id]);
|
||||
|
||||
Vertrag::factory()->create(['abschnitt_id' => $pfa3->id, 'auftragnehmer_id' => $auftragnehmer->id]);
|
||||
Vertrag::factory()->create(['abschnitt_id' => $pfa4->id, 'auftragnehmer_id' => $auftragnehmer->id]);
|
||||
|
||||
$this->assertEqualsCanonicalizing(
|
||||
[$pfa3->id, $pfa4->id],
|
||||
$auftragnehmer->vertraege()->pluck('abschnitt_id')->all(),
|
||||
);
|
||||
$this->assertSame(2, $projekt->vertraege()->count());
|
||||
}
|
||||
|
||||
public function test_nachtrag_hat_mka_bezug_status_und_positionen_in_reihenfolge(): void
|
||||
{
|
||||
$nachtrag = Nachtrag::factory()->create(['mka_bezug' => ['MKA 131', 'MKA 133']]);
|
||||
Nachtragsposition::factory()->create(['nachtrag_id' => $nachtrag->id, 'oz' => 'N1.0020', 'sortierung' => 2]);
|
||||
Nachtragsposition::factory()->create(['nachtrag_id' => $nachtrag->id, 'oz' => 'N1.0010', 'sortierung' => 1]);
|
||||
|
||||
$nachtrag = $nachtrag->fresh();
|
||||
|
||||
$this->assertNotNull($nachtrag);
|
||||
$this->assertSame(['MKA 131', 'MKA 133'], $nachtrag->mka_bezug);
|
||||
$this->assertSame(NachtragStatus::Eingegangen, $nachtrag->status);
|
||||
$this->assertSame(['N1.0010', 'N1.0020'], $nachtrag->positionen->pluck('oz')->all());
|
||||
}
|
||||
|
||||
public function test_nachtragsnummer_ist_je_vertrag_eindeutig(): void
|
||||
{
|
||||
$vertrag = Vertrag::factory()->create();
|
||||
Nachtrag::factory()->create(['vertrag_id' => $vertrag->id, 'nummer' => 'N14']);
|
||||
|
||||
$this->expectException(QueryException::class);
|
||||
|
||||
Nachtrag::factory()->create(['vertrag_id' => $vertrag->id, 'nummer' => 'N14']);
|
||||
}
|
||||
|
||||
public function test_projektmitglieder_haben_eine_rolle(): void
|
||||
{
|
||||
$projekt = Projekt::factory()->create();
|
||||
$leiterin = User::factory()->create();
|
||||
$leser = User::factory()->create();
|
||||
$aussenstehend = User::factory()->create();
|
||||
|
||||
$projekt->mitglieder()->attach($leiterin, ['rolle' => Projektrolle::Projektleiter->value]);
|
||||
$projekt->mitglieder()->attach($leser, ['rolle' => Projektrolle::Leser->value]);
|
||||
|
||||
$this->assertSame(Projektrolle::Projektleiter, $projekt->rolleVon($leiterin));
|
||||
$this->assertSame(Projektrolle::Leser, $projekt->rolleVon($leser));
|
||||
$this->assertNull($projekt->rolleVon($aussenstehend));
|
||||
$this->assertTrue($leiterin->projekte()->whereKey($projekt->id)->exists());
|
||||
}
|
||||
|
||||
public function test_vertrauliches_dokument_hat_benannte_freigaben(): void
|
||||
{
|
||||
$nachtrag = Nachtrag::factory()->create();
|
||||
$dokument = Dokument::factory()->zu($nachtrag, DokumentKategorie::Anlage)->vertraulich()->create();
|
||||
$berechtigt = User::factory()->create();
|
||||
|
||||
$dokument->freigaben()->attach($berechtigt);
|
||||
|
||||
$this->assertTrue($dokument->vertraulich);
|
||||
$this->assertSame([$berechtigt->id], $dokument->freigaben()->pluck('users.id')->all());
|
||||
$this->assertSame(1, $nachtrag->dokumente()->count());
|
||||
}
|
||||
|
||||
public function test_archiviertes_projekt_wird_erkannt(): void
|
||||
{
|
||||
$this->assertTrue(Projekt::factory()->archiviert()->create()->istArchiviert());
|
||||
$this->assertFalse(Projekt::factory()->create()->istArchiviert());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Datenmodell;
|
||||
|
||||
use App\Enums\Projektrolle;
|
||||
use App\Models\Nachtrag;
|
||||
use App\Models\Projekt;
|
||||
use App\Models\User;
|
||||
use Database\Seeders\DemoSeeder;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class DemoSeederTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_demodaten_entsprechen_den_beispielen_und_lassen_sich_wiederholt_einspielen(): void
|
||||
{
|
||||
$testbenutzer = User::factory()->create(['email' => 'test@example.com']);
|
||||
|
||||
$this->seed(DemoSeeder::class);
|
||||
$this->seed(DemoSeeder::class);
|
||||
|
||||
$projekt = Projekt::query()->where('name', DemoSeeder::PROJEKT)->sole();
|
||||
$this->assertSame(['PFA 1', 'PFA 2', 'PFA 3', 'PFA 4'], $projekt->abschnitte->pluck('bezeichnung')->all());
|
||||
$this->assertSame(8, $projekt->vertraege()->count());
|
||||
$this->assertSame(['N14', 'N16', 'N21'], $projekt->nachtraege()->orderBy('nummer')->pluck('nummer')->all());
|
||||
$this->assertSame(['MKA 131', 'MKA 133'], Nachtrag::query()->where('nummer', 'N21')->sole()->mka_bezug);
|
||||
$this->assertSame(Projektrolle::Projektleiter, $projekt->rolleVon($testbenutzer));
|
||||
$this->assertSame($projekt->mandant_id, $testbenutzer->fresh()?->mandant_id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Datenmodell;
|
||||
|
||||
use App\Models\Abschnitt;
|
||||
use App\Models\Nachtrag;
|
||||
use App\Models\Nachtragsposition;
|
||||
use App\Models\Projekt;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class LoeschenTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_projekt_mit_abschnitten_laesst_sich_nicht_loeschen(): void
|
||||
{
|
||||
$abschnitt = Abschnitt::factory()->create();
|
||||
|
||||
$this->expectException(QueryException::class);
|
||||
|
||||
$abschnitt->projekt->delete();
|
||||
}
|
||||
|
||||
public function test_nachtragspositionen_werden_mit_dem_nachtrag_geloescht(): void
|
||||
{
|
||||
$nachtrag = Nachtrag::factory()->create();
|
||||
Nachtragsposition::factory()->count(3)->create(['nachtrag_id' => $nachtrag->id]);
|
||||
|
||||
$nachtrag->delete();
|
||||
|
||||
$this->assertSame(0, Nachtragsposition::query()->count());
|
||||
}
|
||||
|
||||
public function test_geloeschter_benutzer_verschwindet_aus_projekt_und_zuweisung(): void
|
||||
{
|
||||
$projekt = Projekt::factory()->create();
|
||||
$benutzer = User::factory()->create();
|
||||
$projekt->mitglieder()->attach($benutzer, ['rolle' => 'bearbeiter']);
|
||||
$nachtrag = Nachtrag::factory()->create(['zugewiesen_an' => $benutzer->id]);
|
||||
|
||||
$benutzer->delete();
|
||||
|
||||
$this->assertSame(0, $projekt->mitglieder()->count());
|
||||
$this->assertNull($nachtrag->fresh()?->zugewiesen_an);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Datenmodell;
|
||||
|
||||
use App\Enums\DokumentKategorie;
|
||||
use App\Enums\Land;
|
||||
use App\Models\Abschnitt;
|
||||
use App\Models\Auftragnehmer;
|
||||
use App\Models\Dokument;
|
||||
use App\Models\Leistungsverzeichnis;
|
||||
use App\Models\Mandant;
|
||||
use App\Models\Nachtrag;
|
||||
use App\Models\Nachtragsposition;
|
||||
use App\Models\Projekt;
|
||||
use App\Models\Vertrag;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use LogicException;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ZuordnungTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_mandant_land_und_projekt_werden_die_kette_hinunter_uebernommen(): void
|
||||
{
|
||||
$projekt = Projekt::factory()->create(['land' => Land::AT]);
|
||||
$abschnitt = Abschnitt::factory()->create(['projekt_id' => $projekt->id]);
|
||||
$vertrag = Vertrag::factory()->create(['abschnitt_id' => $abschnitt->id]);
|
||||
$lv = Leistungsverzeichnis::factory()->create(['vertrag_id' => $vertrag->id]);
|
||||
$nachtrag = Nachtrag::factory()->create(['vertrag_id' => $vertrag->id]);
|
||||
$position = Nachtragsposition::factory()->create(['nachtrag_id' => $nachtrag->id]);
|
||||
|
||||
foreach ([$abschnitt, $vertrag, $lv, $nachtrag, $position] as $datensatz) {
|
||||
$this->assertSame($projekt->mandant_id, $datensatz->mandant_id, $datensatz::class);
|
||||
$this->assertSame(Land::AT, $datensatz->land, $datensatz::class);
|
||||
$this->assertSame($projekt->id, $datensatz->projekt_id, $datensatz::class);
|
||||
}
|
||||
}
|
||||
|
||||
public function test_dokument_uebernimmt_die_zuordnung_vom_lv(): void
|
||||
{
|
||||
$lv = Leistungsverzeichnis::factory()->create();
|
||||
|
||||
$dokument = Dokument::factory()->zu($lv, DokumentKategorie::LvX86)->create();
|
||||
|
||||
$this->assertSame($lv->projekt_id, $dokument->projekt_id);
|
||||
$this->assertSame($lv->mandant_id, $dokument->mandant_id);
|
||||
$this->assertTrue($dokument->dokumentable?->is($lv));
|
||||
$this->assertSame('leistungsverzeichnis', $dokument->dokumentable_type);
|
||||
}
|
||||
|
||||
public function test_allgemeines_dokument_ohne_projekt_braucht_mandant_und_land(): void
|
||||
{
|
||||
$mandant = Mandant::factory()->create();
|
||||
|
||||
$dokument = Dokument::factory()->create([
|
||||
'projekt_id' => null,
|
||||
'mandant_id' => $mandant->id,
|
||||
'land' => Land::DE,
|
||||
'kategorie' => DokumentKategorie::Vorlage,
|
||||
]);
|
||||
|
||||
$this->assertNull($dokument->projekt_id);
|
||||
$this->assertSame($mandant->id, $dokument->mandant_id);
|
||||
}
|
||||
|
||||
public function test_vertrag_mit_auftragnehmer_eines_anderen_mandanten_wird_abgewiesen(): void
|
||||
{
|
||||
$abschnitt = Abschnitt::factory()->create();
|
||||
$fremderAuftragnehmer = Auftragnehmer::factory()->create();
|
||||
|
||||
$this->expectException(LogicException::class);
|
||||
|
||||
Vertrag::factory()->create([
|
||||
'abschnitt_id' => $abschnitt->id,
|
||||
'auftragnehmer_id' => $fremderAuftragnehmer->id,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_abweichender_mandant_beim_anlegen_wird_abgewiesen(): void
|
||||
{
|
||||
$projekt = Projekt::factory()->create();
|
||||
$andererMandant = Mandant::factory()->create();
|
||||
|
||||
$this->expectException(LogicException::class);
|
||||
|
||||
Abschnitt::factory()->create([
|
||||
'projekt_id' => $projekt->id,
|
||||
'mandant_id' => $andererMandant->id,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_nachtrag_laesst_sich_nicht_in_ein_anderes_projekt_verschieben(): void
|
||||
{
|
||||
$nachtrag = Nachtrag::factory()->create();
|
||||
$vertragInAnderemProjekt = Vertrag::factory()->create();
|
||||
|
||||
$this->expectException(LogicException::class);
|
||||
|
||||
$nachtrag->update(['vertrag_id' => $vertragInAnderemProjekt->id]);
|
||||
}
|
||||
|
||||
public function test_nachtrag_darf_innerhalb_des_projekts_den_vertrag_wechseln(): void
|
||||
{
|
||||
$nachtrag = Nachtrag::factory()->create();
|
||||
$abschnitt = $nachtrag->vertrag->abschnitt;
|
||||
$andererVertrag = Vertrag::factory()->create(['abschnitt_id' => $abschnitt->id]);
|
||||
|
||||
$nachtrag->update(['vertrag_id' => $andererVertrag->id]);
|
||||
|
||||
$this->assertSame($andererVertrag->id, $nachtrag->fresh()?->vertrag_id);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user