create(); $event = Event::factory()->for($org)->create(); $artist = Artist::factory()->create(['organisation_id' => $org->id]); $eng = ArtistEngagement::create([ 'artist_id' => $artist->id, 'event_id' => $event->id, 'booking_status' => ArtistEngagementStatus::Draft->value, ]); $this->assertSame($org->id, $eng->fresh()->organisation_id); } public function test_cross_tenant_engagement_throws(): void { $orgA = Organisation::factory()->create(); $orgB = Organisation::factory()->create(); $artist = Artist::factory()->create(['organisation_id' => $orgA->id]); $eventInOtherOrg = Event::factory()->for($orgB)->create(); $this->expectException(CrossTenantEngagementException::class); ArtistEngagement::create([ 'artist_id' => $artist->id, 'event_id' => $eventInOtherOrg->id, 'booking_status' => ArtistEngagementStatus::Draft->value, ]); } public function test_soft_delete_cascades_to_performances_and_hard_deletes_advance_sections(): void { $org = Organisation::factory()->create(); $event = Event::factory()->for($org)->create(); $artist = Artist::factory()->create(['organisation_id' => $org->id]); $eng = ArtistEngagement::create([ 'artist_id' => $artist->id, 'event_id' => $event->id, 'booking_status' => ArtistEngagementStatus::Draft->value, ]); $stage = Stage::factory()->for($event)->create(); $start = CarbonImmutable::now(); $perf = Performance::create([ 'engagement_id' => $eng->id, 'event_id' => $event->id, 'stage_id' => $stage->id, 'start_at' => $start, 'end_at' => $start->addHour(), ]); $section = AdvanceSection::create([ 'engagement_id' => $eng->id, 'name' => 'Production', 'type' => 'production', ]); AdvanceSubmission::create([ 'advance_section_id' => $section->id, 'submitted_by_name' => 'TM', 'submitted_by_email' => 'tm@example.test', 'submitted_at' => now(), 'status' => 'pending', 'data' => [], ]); $eng->delete(); // Performance is soft-deleted (trashed, not removed). $this->assertNotNull(Performance::withoutGlobalScope(OrganisationScope::class)->withTrashed()->find($perf->id)); $this->assertSoftDeleted($perf); // AdvanceSection is hard-deleted. $this->assertNull(AdvanceSection::withoutGlobalScope(OrganisationScope::class)->find($section->id)); // Note: `advance_submissions.advance_section_id` currently uses // `cascadeOnDelete()`, so submissions are removed with their section. // RFC v0.2 §5.4 calls submissions "audit-immutable" — interpreted // here as "no application code mutates them post-creation". A // future migration may switch the FK to nullOnDelete to preserve // rows past section hard-delete; out of Session 1 scope. } }