feat: Enhance cooperation and reporting workflows with refined relationships, new payment management, and updated actions.

This commit is contained in:
Yoga Pangestu 2026-02-02 11:56:49 +07:00
parent 693d1f001c
commit 2d7f4ee0e8
25 changed files with 246 additions and 96 deletions

View File

@ -1,22 +0,0 @@
---
description: Automatic commit message generator and fast AI-powered commit for all current changes
---
// turbo-all
This workflow automatically stages all changes, generates a descriptive commit message, and commits them in one go.
### Steps:
1. **Stage All Changes**: Automatically stage all modified and new files.
```bash
git add .
```
2. **Analyze Changes**: Get the diff of staged changes to understand the context.
```bash
git diff --cached
```
3. **Generate & Commit**: Generate a professional message following [Conventional Commits](https://www.conventionalcommits.org/) and execute the commit.
```bash
git commit -m "<ai_generated_message>"
```

View File

@ -34,7 +34,7 @@ public function getColor(): string|array|null
self::PENDING => 'warning',
self::ASSIGNMENT => 'info',
self::VERIFICATION => 'primary',
self::PAYMENT => 'secondary',
self::PAYMENT => 'slate',
self::COMPLETED => 'success',
};
}

View File

@ -54,7 +54,7 @@ protected function setUp(): void
$record->update([
'payment_amount' => $totalPayment,
'payment_date' => now(),
'completed_at' => now(),
'status' => CooperationStatus::COMPLETED,
]);

View File

@ -23,7 +23,10 @@ protected function setUp(): void
->modalHeading('Lanjutkan ke Pembayaran?')
->modalDescription('Apakah Anda yakin ingin melanjutkan kerja sama ini ke tahap pembayaran? Pastikan semua laporan telah diverifikasi.')
->action(function (Cooperation $record): void {
$record->update(['status' => CooperationStatus::PAYMENT]);
$record->update([
'status' => CooperationStatus::PAYMENT,
'payment_date' => now()->toDateString(),
]);
CheerfulNotification::success(
'Tahap Pembayaran Dimulai! 💸✨',

View File

@ -34,7 +34,9 @@ protected function setUp(): void
->autocomplete(false)
->autofocus()
->nullable()
->url(),
->url()
->required()
->maxLength(200),
Textarea::make('description')
->label('Deskripsi')

View File

@ -4,8 +4,10 @@
use App\Enums\ApprovalStatus;
use App\Enums\CooperationStatus;
use App\Filament\Resources\Manage\Cooperations\CooperationResource;
use App\Filament\Support\CheerfulNotification;
use App\Models\CooperationMedia;
use App\Notifications\BroadcastNotification;
use Filament\Actions\Action;
use Filament\Forms\Components\SpatieMediaLibraryFileUpload;
use Filament\Forms\Components\Textarea;
@ -64,6 +66,19 @@ protected function setUp(): void
'Pembayaran Berhasil! 💸✨',
"Pembayaran untuk {$record->partnerMedia->name} telah berhasil dicatat."
)->send();
$partnerUser = $record->partnerMedia->company?->user;
if ($partnerUser) {
$partnerUser->notify(new BroadcastNotification([
'title' => 'Pembayaran Telah Dikirim! 💸✨',
'body' => "Halo! Pembayaran untuk kerja sama \"{$record->cooperation->title}\" telah berhasil dikirim oleh Admin. Silakan cek detailnya ya! 😊",
'action' => [
Action::make('view')
->label('Lihat')
->url(CooperationResource::getUrl('view', ['record' => $record->cooperation_id, 'relation' => 0])),
],
]));
}
})
->modalWidth(Width::Large);
}

View File

@ -32,28 +32,21 @@ protected function setUp(): void
->success()
->send();
// Notify all partners in this cooperation (since reports might be per media even if shared in DB)
$partners = $record->taskAssignment?->cooperation?->partnerMedia()
->wherePivot('status', ApprovalStatus::ACCEPTED)
->get();
foreach ($partners as $media) {
$partnerUser = $media->company?->user;
if ($partnerUser) {
$partnerUser->notify(new BroadcastNotification([
'title' => 'Mantap! Laporan Diterima 🎊✨',
'body' => "Hore! Laporan \"{$record->title}\" pada kerja sama \"{$record->taskAssignment->cooperation->title}\" telah disetujui oleh Admin. Satu langkah lebih dekat! 🚀",
'action' => [
Action::make('view')
->label('Lihat')
->url(CooperationResource::getUrl('view', ['record' => $record->taskAssignment->cooperation_id, 'relation' => 3])),
],
]));
}
$partnerUser = $record->mediaTaskAssignment?->partnerMedia?->company?->user;
if ($partnerUser) {
$partnerUser->notify(new BroadcastNotification([
'title' => 'Mantap! Laporan Diterima 🎊✨',
'body' => "Hore! Laporan \"{$record->title}\" pada kerja sama \"{$record->mediaTaskAssignment->taskAssignment->cooperation->title}\" telah disetujui oleh Admin. Satu langkah lebih dekat! 🚀",
'action' => [
Action::make('view')
->label('Lihat')
->url(CooperationResource::getUrl('view', ['record' => $record->mediaTaskAssignment->taskAssignment->cooperation_id, 'relation' => 3])),
],
]));
}
})
->visible(
fn (Report $record): bool => $record->taskAssignment?->cooperation?->status === CooperationStatus::VERIFICATION &&
fn (Report $record): bool => $record->mediaTaskAssignment?->taskAssignment?->cooperation?->status === CooperationStatus::VERIFICATION &&
! auth()->user()->hasRole(RoleEnum::PERUSAHAAN->value) &&
$record->status === ApprovalStatus::PENDING
);

View File

@ -42,28 +42,21 @@ protected function setUp(): void
->warning()
->send();
// Notify all partners in this cooperation (since we can't tell which specific one)
$partners = $record->taskAssignment?->cooperation?->partnerMedia()
->wherePivot('status', ApprovalStatus::ACCEPTED)
->get();
foreach ($partners as $media) {
$partnerUser = $media->company?->user;
if ($partnerUser) {
$partnerUser->notify(new BroadcastNotification([
'title' => 'Yah, Laporan Perlu Diperbaiki nih 📝',
'body' => "Halo! Laporan \"{$record->title}\" pada kerja sama \"{$record->taskAssignment->cooperation->title}\" ditolak oleh Admin. 💪\n\nCatatan Admin: {$data['reason']}",
'action' => [
Action::make('view')
->label('Lihat')
->url(CooperationResource::getUrl('view', ['record' => $record->taskAssignment->cooperation_id])),
],
]));
}
$partnerUser = $record->mediaTaskAssignment?->partnerMedia?->company?->user;
if ($partnerUser) {
$partnerUser->notify(new BroadcastNotification([
'title' => 'Yah, Laporan Ditolak 🙁',
'body' => "Halo! Laporan \"{$record->title}\" pada kerja sama \"{$record->mediaTaskAssignment->taskAssignment->cooperation->title}\" ditolak oleh Admin. 💪\n\nCatatan Admin: {$data['reason']}",
'action' => [
Action::make('view')
->label('Lihat')
->url(CooperationResource::getUrl('view', ['record' => $record->mediaTaskAssignment->taskAssignment->cooperation_id])),
],
]));
}
})
->visible(
fn (Report $record): bool => $record->taskAssignment?->cooperation?->status === CooperationStatus::VERIFICATION &&
fn (Report $record): bool => $record->mediaTaskAssignment?->taskAssignment?->cooperation?->status === CooperationStatus::VERIFICATION &&
! auth()->user()->hasRole(RoleEnum::PERUSAHAAN->value) &&
$record->status === ApprovalStatus::PENDING
)

View File

@ -8,6 +8,7 @@
use App\Filament\Resources\Manage\Cooperations\Pages\ListCooperations;
use App\Filament\Resources\Manage\Cooperations\Pages\ViewCooperation;
use App\Filament\Resources\Manage\Cooperations\RelationManagers\CooperationMediaRelationManager;
use App\Filament\Resources\Manage\Cooperations\RelationManagers\CooperationPaymentRelationManager;
use App\Filament\Resources\Manage\Cooperations\RelationManagers\CooperationProposalRelationManager;
use App\Filament\Resources\Manage\Cooperations\RelationManagers\ReportRelationManager;
use App\Filament\Resources\Manage\Cooperations\RelationManagers\TaskAssignmentRelationManager;
@ -120,6 +121,11 @@ public static function infolist(Schema $schema): Schema
->label('Tanggal Pembayaran')
->date('l, d F Y')
->placeholder('Belum dibayar'),
TextEntry::make('completed_at')
->label('Tanggal Selesai')
->date('l, d F Y')
->placeholder('Masih berjalan'),
]),
Grid::make(3)
@ -153,6 +159,7 @@ public static function getRelations(): array
CooperationProposalRelationManager::class,
TaskAssignmentRelationManager::class,
ReportRelationManager::class,
CooperationPaymentRelationManager::class,
];
}

View File

@ -19,6 +19,8 @@
class CooperationMediaRelationManager extends RelationManager
{
protected static ?string $recordTitleAttribute = 'partnerMedia.name';
protected static string $relationship = 'cooperationMedia';
protected static ?string $title = 'Media';
@ -59,7 +61,8 @@ public function table(Table $table): Table
->visible(fn (CooperationMedia $record): bool => $record->status === ApprovalStatus::ACCEPTED && $record->payment()->exists()),
])
->emptyStateIcon(Heroicon::Newspaper)
->emptyStateDescription('Tidak ada media yang diikutsertakan.');
->emptyStateDescription('Tidak ada media yang diikutsertakan.')
->defaultSort('created_at', 'desc');
}
public function infolist(Schema $infolist): Schema
@ -70,11 +73,11 @@ public function infolist(Schema $infolist): Schema
->schema([
TextEntry::make('payment.amount')
->label('Nominal')
->money('IDR'),
->money('IDR', decimalPlaces: 0),
TextEntry::make('payment.payment_date')
->label('Tanggal Bayar')
->dateTime(),
->dateTime('l, d F Y'),
]),
TextEntry::make('payment.description')

View File

@ -0,0 +1,74 @@
<?php
namespace App\Filament\Resources\Manage\Cooperations\RelationManagers;
use App\Enums\ApprovalStatus;
use App\Enums\RoleEnum;
use App\Models\CooperationPayment;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Model;
class CooperationPaymentRelationManager extends RelationManager
{
protected static ?string $recordTitleAttribute = 'description';
protected static string $relationship = 'payments';
protected static ?string $title = 'Pembayaran';
public static function canViewForRecord(Model $ownerRecord, string $pageClass): bool
{
if (! auth()->user()->hasRole(RoleEnum::PERUSAHAAN->value)) {
return false;
}
return $ownerRecord->cooperationMedia()
->whereHas('partnerMedia', function ($query) {
$query->whereHas('company', function ($query) {
$query->where('user_id', auth()->id());
});
})
->where('status', ApprovalStatus::ACCEPTED)
->exists();
}
public function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('amount')
->label('Nominal')
->money('IDR', decimalPlaces: 0),
TextColumn::make('payment_date')
->label('Tanggal Bayar')
->date('l, d F Y'),
TextColumn::make('description')
->label('Keterangan')
->limit(50),
ImageColumn::make('payment_proof')
->label('Bukti Pembayaran')
->getStateUsing(fn (CooperationPayment $record): ?string => optional($record->cooperationMedia->getMedia('cooperations')->where('custom_properties.doc_type', 'payment-proof')->sortByDesc('created_at')->first())->getPathRelativeToRoot())
->disk(config('filesystems.default')),
])
->filters([])
->headerActions([])
->recordActions([])
->emptyStateIcon(Heroicon::CreditCard)
->emptyStateDescription('Belum ada data pembayaran.')
->defaultSort('created_at', 'desc')
->modifyQueryUsing(function ($query) {
$user = auth()->user();
return $query->whereHas('cooperationMedia.partnerMedia.company', function ($q) use ($user) {
$q->where('user_id', $user->id);
});
});
}
}

View File

@ -23,6 +23,8 @@
class CooperationProposalRelationManager extends RelationManager
{
protected static ?string $recordTitleAttribute = 'e_catalog';
protected static string $relationship = 'proposal';
protected static ?string $title = 'Proposal';
@ -110,6 +112,7 @@ public function table(Table $table): Table
])
->emptyStateIcon(Heroicon::DocumentText)
->emptyStateDescription('Tidak ada proposal yang diajukan.')
->defaultSort('created_at', 'desc')
->modifyQueryUsing(function ($query) {
$user = auth()->user();

View File

@ -32,6 +32,11 @@ class ReportRelationManager extends RelationManager
protected static ?string $title = 'Laporan';
public function isReadOnly(): bool
{
return false;
}
public static function canViewForRecord(Model $ownerRecord, string $pageClass): bool
{
if (auth()->user()->hasRole(RoleEnum::PERUSAHAAN->value)) {
@ -48,13 +53,16 @@ public static function canViewForRecord(Model $ownerRecord, string $pageClass):
return true;
}
public function isReadOnly(): bool
{
return false;
}
public static function getBadge(Model $ownerRecord, string $pageClass): ?string
{
if (auth()->user()->hasRole(RoleEnum::PERUSAHAAN->value)) {
return $ownerRecord->reports()
->whereHas('mediaTaskAssignment.partnerMedia.company', function ($q) {
$q->where('user_id', auth()->id());
})
->count();
}
return $ownerRecord->reports()->count();
}
@ -106,6 +114,11 @@ public function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('mediaTaskAssignment.partnerMedia.name')
->label('Media')
->searchable()
->visible(! auth()->user()->hasRole(RoleEnum::PERUSAHAAN->value)),
TextColumn::make('title')
->label('Judul')
->searchable(),
@ -140,7 +153,17 @@ public function table(Table $table): Table
->modalWidth(Width::Large)
->modalHeading('Buat Laporan')
->mutateDataUsing(function (array $data): array {
$data['task_assignment_id'] = $this->getOwnerRecord()->taskAssignment?->id;
$taskAssignment = $this->getOwnerRecord()->taskAssignment;
if (auth()->user()->hasRole(RoleEnum::PERUSAHAAN->value)) {
$mediaTaskAssignment = $taskAssignment?->mediaTaskAssignments()
->whereHas('partnerMedia.company', function ($query) {
$query->where('user_id', auth()->id());
})
->first();
$data['media_task_assignment_id'] = $mediaTaskAssignment?->id;
}
return $data;
})
@ -185,12 +208,25 @@ public function table(Table $table): Table
&& $taskAssignment->start_date->toDateString() <= now()->toDateString()
&& $taskAssignment->end_date->toDateString() >= now()->toDateString()
&& $taskAssignment->reports()
->where('status', '!=', ApprovalStatus::REJECTED)
->whereHas('mediaTaskAssignment.partnerMedia.company', fn ($q) => $q->where('user_id', auth()->id()))
->where('reports.status', '!=', ApprovalStatus::REJECTED)
->count() < $taskAssignment->report_amount;
}),
])
->toolbarActions([])
->emptyStateIcon(Heroicon::InboxArrowDown)
->emptyStateDescription('Tidak ada laporan yang diajukan.');
->emptyStateDescription('Tidak ada laporan yang diajukan.')
->defaultSort('created_at', 'desc')
->modifyQueryUsing(function ($query) {
$user = auth()->user();
if (! $user->hasRole(RoleEnum::PERUSAHAAN->value)) {
return $query;
}
$query->whereHas('mediaTaskAssignment.partnerMedia.company', function ($q) use ($user) {
$q->where('user_id', $user->id);
});
});
}
}

View File

@ -132,6 +132,13 @@ public static function configure(Table $table): Table
->placeholder('Belum dibayar')
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('completed_at')
->label('Tanggal Selesai')
->date('l, d F Y')
->sortable()
->placeholder('Masih berjalan')
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('description')
->label('Deskripsi')
->searchable()

View File

@ -8,6 +8,7 @@
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\SoftDeletes;
@ -28,6 +29,7 @@ protected function casts(): array
'final_submission_date' => 'date',
'payment_amount' => 'integer',
'payment_date' => 'date',
'completed_at' => 'date',
'status' => CooperationStatus::class,
];
}
@ -62,30 +64,46 @@ protected function completed(Builder $query): void
$query->where('status', CooperationStatus::COMPLETED);
}
public function cooperationMedia(): HasOne
public function cooperationMedia(): HasMany
{
return $this->hasOne(CooperationMedia::class);
return $this->hasMany(CooperationMedia::class);
}
public function partnerMedia(): BelongsToMany
{
return $this->belongsToMany(PartnerMedia::class, 'cooperation_media')
->using(CooperationMedia::class)
->withPivot(['status'])
->withTimestamps();
}
public function proposal(): HasOne
public function proposal(): HasMany
{
return $this->hasOne(CooperationProposal::class);
return $this->hasMany(CooperationProposal::class);
}
public function reports(): HasManyThrough
{
return $this->hasManyThrough(Report::class, TaskAssignment::class);
return $this->hasManyThrough(
Report::class,
MediaTaskAssignment::class,
'task_assignment_id',
'media_task_assignment_id'
);
}
public function taskAssignment(): HasOne
{
return $this->hasOne(TaskAssignment::class);
}
public function payments(): HasManyThrough
{
return $this->hasManyThrough(
CooperationPayment::class,
CooperationMedia::class,
'cooperation_id',
'cooperation_media_id'
);
}
}

View File

@ -5,6 +5,7 @@
use App\Enums\ApprovalStatus;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Relations\Pivot;
use Swindon\FilamentHashids\Traits\HasHashid;
@ -38,4 +39,9 @@ public function rejectionReasons(): MorphMany
{
return $this->morphMany(RejectionReason::class, 'rejectable');
}
public function reports(): HasMany
{
return $this->hasMany(Report::class);
}
}

View File

@ -85,6 +85,7 @@ public function cooperationProposals(): HasMany
public function cooperations(): BelongsToMany
{
return $this->belongsToMany(Cooperation::class, 'cooperation_media')
->using(CooperationMedia::class)
->withPivot(['status'])
->withTimestamps();
}
@ -102,6 +103,7 @@ public function mediaTaskAssignments(): HasMany
public function taskAssignments(): BelongsToMany
{
return $this->belongsToMany(TaskAssignment::class, 'media_task_assignment')
->using(MediaTaskAssignment::class)
->withPivot(['status'])
->withTimestamps();
}

View File

@ -26,9 +26,9 @@ protected function casts(): array
];
}
public function taskAssignment(): BelongsTo
public function mediaTaskAssignment(): BelongsTo
{
return $this->belongsTo(TaskAssignment::class);
return $this->belongsTo(MediaTaskAssignment::class);
}
public function rejectionReasons(): MorphMany

View File

@ -7,6 +7,7 @@
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Swindon\FilamentHashids\Traits\HasHashid;
@ -29,9 +30,16 @@ public function cooperation(): BelongsTo
return $this->belongsTo(Cooperation::class);
}
public function reports(): HasMany
public function reports(): HasManyThrough
{
return $this->hasMany(Report::class);
return $this->hasManyThrough(
Report::class,
MediaTaskAssignment::class,
'task_assignment_id', // Foreign key di tabel media_task_assignment
'media_task_assignment_id', // Foreign key di tabel reports
'id', // Local key di tabel task_assignments
'id' // Local key di tabel media_task_assignment
);
}
public function rejectionReasons(): MorphMany
@ -44,9 +52,10 @@ public function mediaTaskAssignments(): HasMany
return $this->hasMany(MediaTaskAssignment::class);
}
public function partnerMedias(): BelongsToMany
public function partnerMedia(): BelongsToMany
{
return $this->belongsToMany(PartnerMedia::class, 'media_task_assignment')
->using(MediaTaskAssignment::class)
->withPivot(['status'])
->withTimestamps();
}

View File

@ -38,9 +38,9 @@ protected function casts(): array
public function canAccessPanel(Panel $panel): bool
{
// if ($this->company?->verificationRequest?->status === VerificationStatus::REJECTED) {
// return false;
// }
if ($this->company?->verificationRequest?->status === VerificationStatus::REJECTED) {
return false;
}
return $this->is_active === IsActive::ACTIVE;
}

View File

@ -20,7 +20,8 @@ public function up(): void
$table->text('description');
$table->unsignedInteger('payment_amount')->nullable();
$table->date('payment_date')->nullable();
$table->enum('status', [CooperationStatus::values()])->default(CooperationStatus::PENDING)->comment(CooperationStatus::comment());
$table->date('completed_at')->nullable();
$table->enum('status', CooperationStatus::values())->default(CooperationStatus::PENDING)->comment(CooperationStatus::comment());
$table->timestamp('created_at')->useCurrent();
$table->timestamp('updated_at')->nullable()->useCurrentOnUpdate();
$table->softDeletes();

View File

@ -18,7 +18,7 @@ public function up(): void
$table->id();
$table->foreignIdFor(Cooperation::class)->constrained()->cascadeOnDelete();
$table->foreignIdFor(PartnerMedia::class)->constrained()->cascadeOnDelete();
$table->enum('status', [ApprovalStatus::values()])->default(ApprovalStatus::PENDING)->comment(ApprovalStatus::comment());
$table->enum('status', ApprovalStatus::values())->default(ApprovalStatus::PENDING)->comment(ApprovalStatus::comment());
$table->timestamp('created_at')->useCurrent();
$table->timestamp('updated_at')->nullable()->useCurrentOnUpdate();
});

View File

@ -19,8 +19,8 @@ public function up(): void
$table->foreignIdFor(Cooperation::class)->constrained()->cascadeOnDelete();
$table->foreignIdFor(PartnerMedia::class)->constrained()->cascadeOnDelete();
$table->text('description')->nullable();
$table->string('e_catalog', 50)->nullable();
$table->enum('status', [ApprovalStatus::values()])->default(ApprovalStatus::PENDING)->comment(ApprovalStatus::comment());
$table->string('e_catalog', 200)->nullable();
$table->enum('status', ApprovalStatus::values())->default(ApprovalStatus::PENDING)->comment(ApprovalStatus::comment());
$table->timestamp('submitted_at')->useCurrent();
$table->timestamp('responded_at')->nullable();
$table->timestamp('created_at')->useCurrent();

View File

@ -18,7 +18,7 @@ public function up(): void
$table->id();
$table->foreignIdFor(TaskAssignment::class)->constrained()->cascadeOnDelete();
$table->foreignIdFor(PartnerMedia::class)->constrained()->cascadeOnDelete();
$table->enum('status', [ApprovalStatus::values()])->default(ApprovalStatus::PENDING)->comment(ApprovalStatus::comment());
$table->enum('status', ApprovalStatus::values())->default(ApprovalStatus::PENDING)->comment(ApprovalStatus::comment());
$table->timestamp('created_at')->useCurrent();
$table->timestamp('updated_at')->nullable()->useCurrentOnUpdate();
});

View File

@ -1,7 +1,7 @@
<?php
use App\Enums\ApprovalStatus;
use App\Models\TaskAssignment;
use App\Models\MediaTaskAssignment;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
@ -15,12 +15,12 @@ public function up(): void
{
Schema::create('reports', function (Blueprint $table) {
$table->id();
$table->foreignIdFor(TaskAssignment::class)->constrained()->cascadeOnDelete();
$table->foreignIdFor(MediaTaskAssignment::class)->constrained()->cascadeOnDelete();
$table->string('title', 200);
$table->date('publication_date');
$table->string('link', 50);
$table->text('description');
$table->enum('status', [ApprovalStatus::values()])->default(ApprovalStatus::PENDING)->comment(ApprovalStatus::comment());
$table->enum('status', ApprovalStatus::values())->default(ApprovalStatus::PENDING)->comment(ApprovalStatus::comment());
$table->timestamp('created_at')->useCurrent();
$table->timestamp('updated_at')->nullable()->useCurrentOnUpdate();
$table->softDeletes();