feat(timetable): Artist domain — 7 enums + 9 Eloquent models

Enums under App\Enums\Artist\ (PascalCase per FormBuilder convention,
snake_case wire values per RFC):
- ArtistEngagementStatus (D9, 9 states + Dutch labels)
- BumaHandledBy (D26)
- FeeType, PaymentStatus
- AdvanceSectionType, AdvanceSectionSubmissionStatus, AdvanceSubmissionStatus

Models:
- Artist (org-scoped, slug-unique-per-org via creating boot hook)
- ArtistEngagement (per-event booking, denorm organisation_id)
- Genre, Stage (event-scoped, ordered scope), StageDay (Pivot, int PK)
- Performance (engagement-scoped, isParked() helper)
- AdvanceSection, AdvanceSubmission, ArtistContact (primary scope)

OrganisationScope wired:
- Direct organisation_id: Artist, Genre, ArtistEngagement
- FK-chain via tenantScopeStrategy(): Stage→Event, Performance→Engagement,
  AdvanceSection→Engagement, AdvanceSubmission→Section→Engagement,
  ArtistContact→Artist, StageDay→Stage→Event

Soft-deletes: Artist, ArtistEngagement, Performance (per RFC §5.4).
LogsActivity baseline (logFillable+dontSubmitEmptyLogs) on all business
models — actual mutation surfaces wire LogOptions in Session 2+.

Inverse relations added on Organisation, Event, Company.
companies.handles_buma cast added.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-08 18:00:28 +02:00
parent 0c03c449c3
commit 9ccf1eaceb
19 changed files with 933 additions and 1 deletions

View File

@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace App\Enums\Artist;
/**
* Submission lifecycle status for an AdvanceSection.
*
* Per RFC-TIMETABLE v0.2 §5.3 (`advance_sections.submission_status`
* column).
*/
enum AdvanceSectionSubmissionStatus: string
{
case Open = 'open';
case Pending = 'pending';
case Submitted = 'submitted';
case Approved = 'approved';
case Declined = 'declined';
}

View File

@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace App\Enums\Artist;
/**
* Type-categorisation for an AdvanceSection.
*
* Per RFC-TIMETABLE v0.2 §5.3 (`advance_sections.type` column).
* Section labels live in the `name` column; this enum classifies
* the section for downstream behaviour (rendering, defaults).
*/
enum AdvanceSectionType: string
{
case GuestList = 'guest_list';
case Contacts = 'contacts';
case Production = 'production';
case Custom = 'custom';
}

View File

@@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace App\Enums\Artist;
/**
* Review status for an individual AdvanceSubmission row.
*
* Per RFC-TIMETABLE v0.2 §5.3 (`advance_submissions.status`).
*/
enum AdvanceSubmissionStatus: string
{
case Pending = 'pending';
case Accepted = 'accepted';
case Declined = 'declined';
}

View File

@@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace App\Enums\Artist;
/**
* Booking status for an ArtistEngagement (per-event booking).
*
* Per RFC-TIMETABLE v0.2 D9 9 states. `Cancelled`, `Rejected`,
* `Declined` are three distinct end-states for reporting.
*/
enum ArtistEngagementStatus: string
{
case Draft = 'draft';
case Requested = 'requested';
case Option = 'option';
case Offered = 'offered';
case Confirmed = 'confirmed';
case Contracted = 'contracted';
case Cancelled = 'cancelled';
case Rejected = 'rejected';
case Declined = 'declined';
public function label(): string
{
return match ($this) {
self::Draft => 'Concept',
self::Requested => 'Aangevraagd',
self::Option => 'Optie',
self::Offered => 'Aanbod uit',
self::Confirmed => 'Bevestigd',
self::Contracted => 'Gecontracteerd',
self::Cancelled => 'Geannuleerd',
self::Rejected => 'Afgewezen',
self::Declined => 'Bedankt',
};
}
}

View File

@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace App\Enums\Artist;
/**
* Who handles BUMA reporting/payment for a given engagement.
*
* Per RFC-TIMETABLE v0.2 D26.
*/
enum BumaHandledBy: string
{
case Organisation = 'organisation';
case BookingAgency = 'booking_agency';
case NotApplicable = 'not_applicable';
public function label(): string
{
return match ($this) {
self::Organisation => 'Organisatie',
self::BookingAgency => 'Boekingsagent',
self::NotApplicable => 'Niet van toepassing',
};
}
}

View File

@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace App\Enums\Artist;
/**
* Deal-fee structure for an ArtistEngagement.
*
* Per RFC-TIMETABLE v0.2 §5.3 (`fee_type` column).
*/
enum FeeType: string
{
case Flat = 'flat';
case DoorSplit = 'door_split';
case GuaranteePlusSplit = 'guarantee_plus_split';
public function label(): string
{
return match ($this) {
self::Flat => 'Vaste fee',
self::DoorSplit => 'Door split',
self::GuaranteePlusSplit => 'Garantie + split',
};
}
}

View File

@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace App\Enums\Artist;
/**
* Payment progress for an ArtistEngagement.
*
* Per RFC-TIMETABLE v0.2 §5.3 (`payment_status` column).
*/
enum PaymentStatus: string
{
case None = 'none';
case DepositPaid = 'deposit_paid';
case PaidInFull = 'paid_in_full';
public function label(): string
{
return match ($this) {
self::None => 'Geen betaling',
self::DepositPaid => 'Aanbetaling voldaan',
self::PaidInFull => 'Volledig voldaan',
};
}
}