feat(cooperation): refactor workflow and implement payment system
- Refactored cooperation workflow to include manual status transitions. - Implemented payment tracking with CooperationPayment model and PayAction. - Updated UpdateCooperationStatusCommand for automatic assignment and verification transitions. - Removed deprecated date columns (assignment_deadline, verification_deadline). - Enhanced Filament UI with new actions (Complete, Proceed to Payment, Pay). - Added CooperationSeeder for testing purposes.
This commit is contained in:
parent
ad6335542e
commit
1d52463286
@ -40,7 +40,7 @@ public function handle()
|
||||
// 1. PENDING -> ASSIGNMENT (final_submission_date)
|
||||
// Automatically reject media that haven't responded
|
||||
$rejectedPendingMedia = CooperationMedia::whereHas('cooperation', function ($query) use ($today) {
|
||||
$query->pending()->whereDate('final_submission_date', '<=', $today);
|
||||
$query->pending()->whereDate('final_submission_date', '<', $today);
|
||||
})
|
||||
->pending()
|
||||
->update(['status' => ApprovalStatus::REJECTED]);
|
||||
@ -50,53 +50,37 @@ public function handle()
|
||||
}
|
||||
|
||||
$updatedPending = Cooperation::pending()
|
||||
->whereDate('final_submission_date', '<=', $today)
|
||||
->whereDate('final_submission_date', '<', $today)
|
||||
->update(['status' => CooperationStatus::ASSIGNMENT]);
|
||||
|
||||
if ($updatedPending > 0) {
|
||||
Log::info("Updated {$updatedPending} cooperations from PENDING to ASSIGNMENT.");
|
||||
}
|
||||
|
||||
// 2. ASSIGNMENT -> VERIFICATION (assignment_deadline)
|
||||
// Automatically reject media that haven't responded
|
||||
// 2. ASSIGNMENT -> VERIFICATION (taskAssignment->end_date)
|
||||
// Automatically reject media that haven't responded to the invitation
|
||||
$rejectedMedia = CooperationMedia::whereHas('cooperation', function ($query) use ($today) {
|
||||
$query->assignment()->whereDate('assignment_deadline', '<=', $today);
|
||||
$query->assignment()->whereHas('taskAssignment', function ($subQuery) use ($today) {
|
||||
$subQuery->whereDate('end_date', '<', $today);
|
||||
});
|
||||
})
|
||||
->pending()
|
||||
->update(['status' => ApprovalStatus::REJECTED]);
|
||||
|
||||
if ($rejectedMedia > 0) {
|
||||
Log::info("Updated {$rejectedMedia} media assignments to REJECTED because they didn't respond before the deadline.");
|
||||
Log::info("Updated {$rejectedMedia} media assignments to REJECTED because they didn't respond before the task deadline.");
|
||||
}
|
||||
|
||||
$updatedAssignment = Cooperation::assignment()
|
||||
->whereDate('assignment_deadline', '<=', $today)
|
||||
$updatedAssignment = Cooperation::where('status', CooperationStatus::ASSIGNMENT)
|
||||
->whereHas('taskAssignment', function ($query) use ($today) {
|
||||
$query->whereDate('end_date', '<', $today);
|
||||
})
|
||||
->update(['status' => CooperationStatus::VERIFICATION]);
|
||||
|
||||
if ($updatedAssignment > 0) {
|
||||
Log::info("Updated {$updatedAssignment} cooperations from ASSIGNMENT to VERIFICATION.");
|
||||
}
|
||||
|
||||
// 3. VERIFICATION -> PAYMENT (verification_deadline)
|
||||
// Automatically reject media that haven't responded
|
||||
$rejectedVerificationMedia = CooperationMedia::whereHas('cooperation', function ($query) use ($today) {
|
||||
$query->verification()->whereDate('verification_deadline', '<=', $today);
|
||||
})
|
||||
->pending()
|
||||
->update(['status' => ApprovalStatus::REJECTED]);
|
||||
|
||||
if ($rejectedVerificationMedia > 0) {
|
||||
Log::info("Updated {$rejectedVerificationMedia} media in VERIFICATION cooperations to REJECTED because they didn't respond before verification_deadline.");
|
||||
}
|
||||
|
||||
$updatedVerification = Cooperation::verification()
|
||||
->whereDate('verification_deadline', '<=', $today)
|
||||
->update(['status' => CooperationStatus::PAYMENT]);
|
||||
|
||||
if ($updatedVerification > 0) {
|
||||
Log::info("Updated {$updatedVerification} cooperations from VERIFICATION to PAYMENT.");
|
||||
}
|
||||
|
||||
$this->info('Cooperation statuses updated successfully.');
|
||||
|
||||
return Command::SUCCESS;
|
||||
|
||||
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Manage\Cooperations\Actions\Cooperation;
|
||||
|
||||
use App\Enums\CooperationStatus;
|
||||
use App\Filament\Support\CheerfulNotification;
|
||||
use App\Models\Cooperation;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
|
||||
class CompleteCooperationAction extends Action
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->label('Selesaikan Kerjasama')
|
||||
->icon(Heroicon::CheckBadge)
|
||||
->color('success')
|
||||
->requiresConfirmation()
|
||||
->modalHeading('Selesaikan Kerja Sama')
|
||||
->modalDescription('Apakah Anda yakin ingin menyelesaikan kerja sama ini? Pastikan semua pembayaran kepada media yang bekerja sama telah lunas.')
|
||||
->action(function (Cooperation $record): void {
|
||||
// Verify all accepted media are paid
|
||||
$acceptedMedia = $record->cooperationMedia()->accepted()->get();
|
||||
|
||||
if ($acceptedMedia->isEmpty()) {
|
||||
CheerfulNotification::danger(
|
||||
'Tidak Ada Media! ❌',
|
||||
'Tidak ada media yang menerima kerja sama ini. Tidak dapat diselesaikan.'
|
||||
)->send();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$unpaidMedia = $acceptedMedia->filter(function ($media) {
|
||||
return ! $media->payment()->exists();
|
||||
});
|
||||
|
||||
if ($unpaidMedia->isNotEmpty()) {
|
||||
CheerfulNotification::danger(
|
||||
'Pembayaran Belum Lunas! ⚠️',
|
||||
'Masih ada media yang belum dibayar. Harap selesaikan pembayaran untuk semua media yang menerima kerja sama.'
|
||||
)->send();
|
||||
|
||||
$this->halt();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate total payment from media payments
|
||||
$totalPayment = $acceptedMedia->sum(fn ($media) => $media->payment->amount);
|
||||
|
||||
$record->update([
|
||||
'payment_amount' => $totalPayment,
|
||||
'payment_date' => now(),
|
||||
'status' => CooperationStatus::COMPLETED,
|
||||
]);
|
||||
|
||||
CheerfulNotification::success(
|
||||
'Kerja Sama Selesai! 🎉✨',
|
||||
'Alhamdulillah! Kerja sama ini telah resmi diselesaikan. Terima kasih atas kerja samanya! 🙌😊'
|
||||
)->send();
|
||||
})
|
||||
->visible(function (Cooperation $record): bool {
|
||||
$user = auth()->user();
|
||||
|
||||
return $user && ! $user->hasRole('Perusahaan')
|
||||
&& $record->status === CooperationStatus::PAYMENT;
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -14,7 +14,6 @@
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Support\Enums\Width;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class CreateTaskAssignmentAction extends Action
|
||||
{
|
||||
@ -34,8 +33,7 @@ protected function setUp(): void
|
||||
->displayFormat('l, d F Y')
|
||||
->locale('id')
|
||||
->required()
|
||||
->minDate($record->final_submission_date)
|
||||
->autofocus(),
|
||||
->minDate($record->final_submission_date),
|
||||
|
||||
DatePicker::make('end_date')
|
||||
->label('Tanggal Selesai')
|
||||
@ -103,8 +101,7 @@ protected function setUp(): void
|
||||
->modalHeading('Buat Penugasan')
|
||||
->modalSubmitActionLabel('Simpan')
|
||||
->visible(function (Cooperation $record): bool {
|
||||
|
||||
$user = Auth::user();
|
||||
$user = auth()->user();
|
||||
|
||||
return $user && ! $user->hasRole('Perusahaan')
|
||||
&& ! $record->taskAssignment()->exists()
|
||||
|
||||
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Manage\Cooperations\Actions\Cooperation;
|
||||
|
||||
use App\Enums\ApprovalStatus;
|
||||
use App\Enums\CooperationStatus;
|
||||
use App\Filament\Support\CheerfulNotification;
|
||||
use App\Models\Cooperation;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
|
||||
class ProceedToPaymentAction extends Action
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->label('Lanjutkan ke Pembayaran')
|
||||
->icon(Heroicon::Banknotes)
|
||||
->color('success')
|
||||
->requiresConfirmation()
|
||||
->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]);
|
||||
|
||||
CheerfulNotification::success(
|
||||
'Tahap Pembayaran Dimulai! 💸✨',
|
||||
'Kerja sama telah dipindahkan ke tahap pembayaran. Silakan proses pembayarannya ya! 😊'
|
||||
)->send();
|
||||
})
|
||||
->visible(function (Cooperation $record): bool {
|
||||
$user = auth()->user();
|
||||
|
||||
if (! $user || $user->hasRole('Perusahaan') || $record->status !== CooperationStatus::VERIFICATION) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if all reports are verified (either Accepted or Rejected, not Pending)
|
||||
$reports = $record->reports;
|
||||
|
||||
if ($reports->isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $reports->every(fn ($report) => $report->status !== ApprovalStatus::PENDING);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -48,7 +48,6 @@ protected function setUp(): void
|
||||
}
|
||||
})
|
||||
->visible(function (Cooperation $record): bool {
|
||||
|
||||
$user = auth()->user();
|
||||
|
||||
if (! $user || ! $user->hasRole('Perusahaan')) {
|
||||
|
||||
@ -15,7 +15,6 @@
|
||||
use Filament\Support\Enums\Width;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class SendProposalAction extends Action
|
||||
@ -55,19 +54,19 @@ protected function setUp(): void
|
||||
$cooperationMedia = $record->cooperationMedia()
|
||||
->whereHas('partnerMedia', function (Builder $query): void {
|
||||
$query->whereHas('company', function (Builder $subQuery): void {
|
||||
$subQuery->where('user_id', Auth::id());
|
||||
$subQuery->where('user_id', auth()->id());
|
||||
});
|
||||
})
|
||||
->first();
|
||||
|
||||
if ($cooperationMedia) {
|
||||
$existingProposal = $record->proposals()
|
||||
$existingProposal = $record->proposal()
|
||||
->where('partner_media_id', $cooperationMedia->partner_media_id)
|
||||
->first();
|
||||
|
||||
$isRevision = (bool) $existingProposal;
|
||||
|
||||
$proposal = $record->proposals()->create([
|
||||
$proposal = $record->proposal()->create([
|
||||
'partner_media_id' => $cooperationMedia->partner_media_id,
|
||||
'description' => $data['description'],
|
||||
'e_catalog' => $data['e_catalog'],
|
||||
@ -99,8 +98,8 @@ protected function setUp(): void
|
||||
User::superAdmin()
|
||||
->get()
|
||||
->each(function ($admin) use ($isRevision, $record, $cooperationMedia): void {
|
||||
$user = auth()->user();
|
||||
|
||||
$user = Auth::user();
|
||||
$admin->notify(new BroadcastNotification([
|
||||
'title' => $isRevision ? 'Pembaruan Proposal Kerja Sama ✨' : 'Ada Proposal Kerja Sama Baru! 🚀',
|
||||
'body' => $isRevision
|
||||
@ -118,8 +117,7 @@ protected function setUp(): void
|
||||
->modalHeading('Proposal Kerja Sama')
|
||||
->modalSubmitActionLabel('Kirim Proposal')
|
||||
->visible(function (Cooperation $record): bool {
|
||||
|
||||
$user = Auth::user();
|
||||
$user = auth()->user();
|
||||
|
||||
if (! $user->hasRole('Perusahaan')) {
|
||||
return false;
|
||||
@ -128,15 +126,14 @@ protected function setUp(): void
|
||||
$cooperationMedia = $record->cooperationMedia()
|
||||
->whereHas('partnerMedia', function (Builder $query): void {
|
||||
$query->whereHas('company', function (Builder $subQuery): void {
|
||||
$subQuery->where('user_id', Auth::id());
|
||||
$subQuery->where('user_id', auth()->id());
|
||||
});
|
||||
})
|
||||
->first();
|
||||
|
||||
return $cooperationMedia
|
||||
&& $cooperationMedia->status === ApprovalStatus::ACCEPTED
|
||||
&& $record->initial_submission_date->toDateString() === now()->toDateString()
|
||||
&& ! $record->proposals()
|
||||
&& ! $record->proposal()
|
||||
->where('partner_media_id', $cooperationMedia->partner_media_id)
|
||||
->where(fn (Builder $q): Builder => $q->accepted()->orWhere(fn (Builder $q): Builder => $q->pending()))
|
||||
->exists();
|
||||
|
||||
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Manage\Cooperations\Actions\Media;
|
||||
|
||||
use App\Enums\ApprovalStatus;
|
||||
use App\Enums\CooperationStatus;
|
||||
use App\Filament\Support\CheerfulNotification;
|
||||
use App\Models\CooperationMedia;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Forms\Components\SpatieMediaLibraryFileUpload;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Support\Enums\Width;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Support\RawJs;
|
||||
|
||||
class PayAction extends Action
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->label('Bayar')
|
||||
->icon(Heroicon::CreditCard)
|
||||
->color('success')
|
||||
->visible(fn (CooperationMedia $record): bool => $record->cooperation->status === CooperationStatus::PAYMENT && ! $record->payment()->exists() && $record->status === ApprovalStatus::ACCEPTED)
|
||||
->schema([
|
||||
TextInput::make('amount')
|
||||
->label('Nominal Pembayaran')
|
||||
->placeholder('1,000,000')
|
||||
->autocomplete(false)
|
||||
->autofocus()
|
||||
->required()
|
||||
->mask(RawJs::make('$money($input)'))
|
||||
->prefix('Rp'),
|
||||
|
||||
SpatieMediaLibraryFileUpload::make('payment_proof')
|
||||
->label('Bukti Pembayaran')
|
||||
->disk(config('filesystems.default'))
|
||||
->acceptedFileTypes(['image/*'])
|
||||
->maxSize(1024 * 3)
|
||||
->collection('cooperations')
|
||||
->customProperties(fn (): array => [
|
||||
'feature' => 'cooperations',
|
||||
'date' => now()->toDateString(),
|
||||
'doc_type' => 'payment-proof',
|
||||
])
|
||||
->image()
|
||||
->required(),
|
||||
|
||||
Textarea::make('description')
|
||||
->label('Keterangan')
|
||||
->placeholder('...')
|
||||
->autocomplete(false),
|
||||
])
|
||||
->action(function (CooperationMedia $record, array $data): void {
|
||||
$record->payment()->create([
|
||||
'amount' => str_replace(['Rp ', ','], '', $data['amount']),
|
||||
'description' => $data['description'],
|
||||
'payment_date' => now(),
|
||||
]);
|
||||
|
||||
CheerfulNotification::success(
|
||||
'Pembayaran Berhasil! 💸✨',
|
||||
"Pembayaran untuk {$record->partnerMedia->name} telah berhasil dicatat."
|
||||
)->send();
|
||||
})
|
||||
->modalWidth(Width::Large);
|
||||
}
|
||||
}
|
||||
@ -3,6 +3,8 @@
|
||||
namespace App\Filament\Resources\Manage\Cooperations\Actions\Report;
|
||||
|
||||
use App\Enums\ApprovalStatus;
|
||||
use App\Enums\CooperationStatus;
|
||||
use App\Enums\RoleEnum;
|
||||
use App\Filament\Resources\Manage\Cooperations\CooperationResource;
|
||||
use App\Models\Report;
|
||||
use App\Notifications\BroadcastNotification;
|
||||
@ -50,6 +52,10 @@ protected function setUp(): void
|
||||
}
|
||||
}
|
||||
})
|
||||
->visible(fn (Report $record): bool => ! auth()->user()->hasRole('Perusahaan') && $record->status === ApprovalStatus::PENDING);
|
||||
->visible(
|
||||
fn (Report $record): bool => $record->taskAssignment?->cooperation?->status === CooperationStatus::VERIFICATION &&
|
||||
! auth()->user()->hasRole(RoleEnum::PERUSAHAAN->value) &&
|
||||
$record->status === ApprovalStatus::PENDING
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
namespace App\Filament\Resources\Manage\Cooperations\Actions\Report;
|
||||
|
||||
use App\Enums\ApprovalStatus;
|
||||
use App\Enums\CooperationStatus;
|
||||
use App\Enums\RoleEnum;
|
||||
use App\Filament\Resources\Manage\Cooperations\CooperationResource;
|
||||
use App\Models\Report;
|
||||
use App\Notifications\BroadcastNotification;
|
||||
@ -60,7 +62,11 @@ protected function setUp(): void
|
||||
}
|
||||
}
|
||||
})
|
||||
->visible(fn (Report $record): bool => ! auth()->user()->hasRole('Perusahaan') && $record->status === ApprovalStatus::PENDING)
|
||||
->visible(
|
||||
fn (Report $record): bool => $record->taskAssignment?->cooperation?->status === CooperationStatus::VERIFICATION &&
|
||||
! auth()->user()->hasRole(RoleEnum::PERUSAHAAN->value) &&
|
||||
$record->status === ApprovalStatus::PENDING
|
||||
)
|
||||
->modalWidth(Width::Large);
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,21 +106,16 @@ public static function infolist(Schema $schema): Schema
|
||||
->label('Tanggal Pengajuan Akhir')
|
||||
->date('l, d F Y'),
|
||||
|
||||
TextEntry::make('assignment_deadline')
|
||||
->label('Deadline Penugasan')
|
||||
TextEntry::make('taskAssignment.start_date')
|
||||
->label('Tanggal Mulai Penugasan')
|
||||
->date('l, d F Y')
|
||||
->placeholder('Belum ditentukan'),
|
||||
|
||||
TextEntry::make('verification_deadline')
|
||||
->label('Deadline Verifikasi')
|
||||
TextEntry::make('taskAssignment.end_date')
|
||||
->label('Tanggal Selesai Penugasan')
|
||||
->date('l, d F Y')
|
||||
->placeholder('Belum ditentukan'),
|
||||
|
||||
TextEntry::make('payment_amount')
|
||||
->label('Jumlah Pembayaran')
|
||||
->money('IDR')
|
||||
->placeholder('Belum ditentukan'),
|
||||
|
||||
TextEntry::make('payment_date')
|
||||
->label('Tanggal Pembayaran')
|
||||
->date('l, d F Y')
|
||||
@ -133,18 +128,19 @@ public static function infolist(Schema $schema): Schema
|
||||
->label('Template Proposal')
|
||||
->getStateUsing(fn (Cooperation $record): ?string => optional($record->getMedia('cooperations')->where('custom_properties.doc_type', 'proposal-template')->sortByDesc('created_at')->first())->getPathRelativeToRoot())
|
||||
->disk(config('filesystems.default'))
|
||||
->columnSpan(2),
|
||||
->columnSpan(2)
|
||||
->visible(fn (Cooperation $record): bool => $record->getMedia('cooperations')->where('custom_properties.doc_type', 'proposal-template')->isNotEmpty()),
|
||||
|
||||
ImageEntry::make('banner')
|
||||
->label('Banner')
|
||||
->getStateUsing(fn (Cooperation $record): ?string => optional($record->getMedia('cooperations')->where('custom_properties.doc_type', 'banner')->sortByDesc('created_at')->first())->getPathRelativeToRoot())
|
||||
->disk(config('filesystems.default'))
|
||||
->visible(fn (Cooperation $record): bool => $record->getMedia('cooperations')->isNotEmpty()),
|
||||
]),
|
||||
->visible(fn (Cooperation $record): bool => $record->getMedia('cooperations')->where('custom_properties.doc_type', 'banner')->isNotEmpty()),
|
||||
])
|
||||
->visible(fn (Cooperation $record): bool => $record->getMedia('cooperations')->where('custom_properties.doc_type', 'banner')->isNotEmpty() && $record->getMedia('cooperations')->where('custom_properties.doc_type', 'proposal-template')->isNotEmpty()),
|
||||
|
||||
TextEntry::make('description')
|
||||
->label('Deskripsi')
|
||||
->markdown(),
|
||||
->label('Deskripsi'),
|
||||
]),
|
||||
])
|
||||
->columns(1);
|
||||
|
||||
@ -2,263 +2,22 @@
|
||||
|
||||
namespace App\Filament\Resources\Manage\Cooperations\Pages;
|
||||
|
||||
use App\Enums\ApprovalStatus;
|
||||
use App\Filament\Resources\Manage\Cooperations\CooperationResource;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Infolists\Components\RepeatableEntry;
|
||||
use Filament\Infolists\Components\TextEntry;
|
||||
use Filament\Resources\Pages\ViewRecord;
|
||||
use Filament\Support\Enums\FontWeight;
|
||||
|
||||
class ViewCooperation extends ViewRecord
|
||||
{
|
||||
protected static string $resource = CooperationResource::class;
|
||||
|
||||
protected function getWorkflowSteps()
|
||||
{
|
||||
$record = $this->getRecord();
|
||||
|
||||
$steps = [
|
||||
[
|
||||
'step' => 1,
|
||||
'title' => 'Pengajuan Kerja Sama',
|
||||
'description' => 'Admin mengajukan kerja sama ke media',
|
||||
'status' => 'completed', // Always completed since we're viewing it
|
||||
'date' => $record->created_at?->format('d/m/Y H:i'),
|
||||
],
|
||||
[
|
||||
'step' => 2,
|
||||
'title' => 'Respon Media',
|
||||
'description' => 'Media menerima atau menolak pengajuan',
|
||||
'status' => $this->getMediaResponseStatus($record),
|
||||
'date' => $this->getMediaResponseDate($record),
|
||||
],
|
||||
[
|
||||
'step' => 3,
|
||||
'title' => 'Upload Proposal',
|
||||
'description' => 'Media mengupload dokumen proposal',
|
||||
'status' => $this->getProposalStatus($record),
|
||||
'date' => $this->getProposalDate($record),
|
||||
],
|
||||
[
|
||||
'step' => 4,
|
||||
'title' => 'Review Proposal',
|
||||
'description' => 'Admin mereview dan menyetujui proposal',
|
||||
'status' => $this->getProposalReviewStatus($record),
|
||||
'date' => $this->getProposalReviewDate($record),
|
||||
],
|
||||
[
|
||||
'step' => 5,
|
||||
'title' => 'Penugasan',
|
||||
'description' => 'Admin membuat task assignment',
|
||||
'status' => $this->getTaskStatus($record),
|
||||
'date' => $this->getTaskDate($record),
|
||||
],
|
||||
[
|
||||
'step' => 6,
|
||||
'title' => 'Upload Laporan',
|
||||
'description' => 'Media mengupload laporan',
|
||||
'status' => $this->getReportStatus($record),
|
||||
'date' => $this->getReportDate($record),
|
||||
],
|
||||
[
|
||||
'step' => 7,
|
||||
'title' => 'Selesai',
|
||||
'description' => 'Kerja sama telah selesai',
|
||||
'status' => $this->getCompletionStatus($record),
|
||||
'date' => $this->getCompletionDate($record),
|
||||
],
|
||||
];
|
||||
|
||||
return RepeatableEntry::make('workflow_steps')
|
||||
->label('')
|
||||
->schema([
|
||||
TextEntry::make('step')
|
||||
->label('Langkah')
|
||||
->formatStateUsing(fn (int $state): string => "Langkah {$state}")
|
||||
->weight(FontWeight::Bold),
|
||||
|
||||
TextEntry::make('title')
|
||||
->label('Judul'),
|
||||
|
||||
TextEntry::make('description')
|
||||
->label('Deskripsi'),
|
||||
|
||||
TextEntry::make('status')
|
||||
->label('Status')
|
||||
->badge()
|
||||
->color(fn (string $state): string => match ($state) {
|
||||
'completed' => 'success',
|
||||
'in_progress' => 'warning',
|
||||
'pending' => 'gray',
|
||||
'rejected' => 'danger',
|
||||
default => 'gray',
|
||||
})
|
||||
->formatStateUsing(fn (string $state): string => match ($state) {
|
||||
'completed' => 'Selesai',
|
||||
'in_progress' => 'Sedang Berjalan',
|
||||
'pending' => 'Menunggu',
|
||||
'rejected' => 'Ditolak',
|
||||
default => $state,
|
||||
}),
|
||||
|
||||
TextEntry::make('date')
|
||||
->label('Tanggal')
|
||||
->placeholder('Belum ada'),
|
||||
])
|
||||
->columns(5)
|
||||
->state($steps);
|
||||
}
|
||||
|
||||
protected function getMediaResponseStatus($record): string
|
||||
{
|
||||
$mediaStatuses = $record->cooperationMedia->pluck('status')->unique();
|
||||
|
||||
if ($mediaStatuses->contains(ApprovalStatus::ACCEPTED)) {
|
||||
return 'completed';
|
||||
}
|
||||
|
||||
if ($mediaStatuses->contains(ApprovalStatus::REJECTED)) {
|
||||
return 'rejected';
|
||||
}
|
||||
|
||||
return 'pending';
|
||||
}
|
||||
|
||||
protected function getMediaResponseDate($record)
|
||||
{
|
||||
$latestResponse = $record->cooperationMedia
|
||||
->whereNotNull('updated_at')
|
||||
->sortByDesc('updated_at')
|
||||
->first();
|
||||
|
||||
return $latestResponse?->updated_at?->format('d/m/Y H:i');
|
||||
}
|
||||
|
||||
protected function getProposalStatus($record): string
|
||||
{
|
||||
if ($record->proposals()->exists()) {
|
||||
return 'completed';
|
||||
}
|
||||
|
||||
return 'pending';
|
||||
}
|
||||
|
||||
protected function getProposalDate($record)
|
||||
{
|
||||
$latestProposal = $record->proposals->sortByDesc('created_at')->first();
|
||||
|
||||
return $latestProposal?->created_at?->format('d/m/Y H:i');
|
||||
}
|
||||
|
||||
protected function getProposalReviewStatus($record): string
|
||||
{
|
||||
$proposals = $record->proposals;
|
||||
|
||||
if ($record->proposals()->accepted()->exists()) {
|
||||
return 'completed';
|
||||
}
|
||||
|
||||
if ($record->proposals()->rejected()->exists()) {
|
||||
return 'rejected';
|
||||
}
|
||||
|
||||
if ($proposals->isNotEmpty()) {
|
||||
return 'in_progress';
|
||||
}
|
||||
|
||||
return 'pending';
|
||||
}
|
||||
|
||||
protected function getProposalReviewDate($record)
|
||||
{
|
||||
$latestProposal = $record->proposals->sortByDesc('updated_at')->first();
|
||||
|
||||
return $latestProposal?->updated_at?->format('d/m/Y H:i');
|
||||
}
|
||||
|
||||
protected function getTaskStatus($record): string
|
||||
{
|
||||
if ($record->taskAssignment()->exists()) {
|
||||
return 'completed';
|
||||
}
|
||||
|
||||
return 'pending';
|
||||
}
|
||||
|
||||
protected function getTaskDate($record)
|
||||
{
|
||||
return $record->taskAssignment?->created_at?->format('d/m/Y H:i');
|
||||
}
|
||||
|
||||
protected function getReportStatus($record): string
|
||||
{
|
||||
$task = $record->taskAssignment;
|
||||
|
||||
if (! $task) {
|
||||
return 'pending';
|
||||
}
|
||||
|
||||
$totalReports = $task->report_amount;
|
||||
$completedReports = $task->reports->count();
|
||||
|
||||
if ($completedReports >= $totalReports && $totalReports > 0) {
|
||||
return 'completed';
|
||||
}
|
||||
|
||||
if ($completedReports > 0) {
|
||||
return 'in_progress';
|
||||
}
|
||||
|
||||
return 'pending';
|
||||
}
|
||||
|
||||
protected function getReportDate($record)
|
||||
{
|
||||
$latestReport = $record->taskAssignment?->reports
|
||||
->sortByDesc('created_at')
|
||||
->first();
|
||||
|
||||
return $latestReport?->created_at?->format('d/m/Y H:i');
|
||||
}
|
||||
|
||||
protected function getCompletionStatus($record): string
|
||||
{
|
||||
// Logic for completion - could be based on all reports accepted, etc.
|
||||
return 'pending';
|
||||
}
|
||||
|
||||
protected function getCompletionDate($record)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Action::make('back')
|
||||
->label('Kembali')
|
||||
->url(fn (): string => static::getResource()::getUrl('index'))
|
||||
->url(ListCooperations::getUrl())
|
||||
->outlined()
|
||||
->color('secondary'),
|
||||
];
|
||||
}
|
||||
|
||||
protected function canMarkAsCompleted(): bool
|
||||
{
|
||||
$record = $this->getRecord();
|
||||
|
||||
$task = $record->taskAssignment;
|
||||
|
||||
if (! $task) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$reportCount = $task->reports()->count();
|
||||
if ($reportCount < $task->report_amount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,11 +2,15 @@
|
||||
|
||||
namespace App\Filament\Resources\Manage\Cooperations\RelationManagers;
|
||||
|
||||
use App\Filament\Resources\Manage\Partners\PartnerResource;
|
||||
use App\Enums\ApprovalStatus;
|
||||
use App\Filament\Resources\Manage\Cooperations\Actions\Media\PayAction;
|
||||
use App\Models\CooperationMedia;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Infolists\Components\ImageEntry;
|
||||
use Filament\Infolists\Components\TextEntry;
|
||||
use Filament\Resources\RelationManagers\RelationManager;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Schemas\Components\Grid;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
@ -30,12 +34,16 @@ public static function getBadge(Model $ownerRecord, string $pageClass): ?string
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->recordTitleAttribute('partnerMedia.name')
|
||||
->columns([
|
||||
TextColumn::make('partnerMedia.name')
|
||||
->label('Nama')
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('payment.amount')
|
||||
->label('Jumlah Pembayaran')
|
||||
->money('IDR', decimalPlaces: 0)
|
||||
->placeholder('Belum ditentukan'),
|
||||
|
||||
TextColumn::make('status')
|
||||
->label('Status')
|
||||
->badge(),
|
||||
@ -43,15 +51,38 @@ public function table(Table $table): Table
|
||||
->filters([])
|
||||
->headerActions([])
|
||||
->recordActions([
|
||||
Action::make('view')
|
||||
->label('Lihat')
|
||||
->icon(Heroicon::Eye)
|
||||
->url(function (CooperationMedia $record): string {
|
||||
return PartnerResource::getUrl('view', [
|
||||
'record' => $record->partnerMedia->company->user_id,
|
||||
]);
|
||||
}),
|
||||
PayAction::make('pay'),
|
||||
|
||||
ViewAction::make()
|
||||
->visible(fn (CooperationMedia $record): bool => $record->status === ApprovalStatus::ACCEPTED && $record->payment()->exists()),
|
||||
])
|
||||
->recordAction(null);
|
||||
}
|
||||
|
||||
public function infolist(Schema $infolist): Schema
|
||||
{
|
||||
return $infolist
|
||||
->components([
|
||||
Grid::make(2)
|
||||
->schema([
|
||||
TextEntry::make('payment.amount')
|
||||
->label('Nominal')
|
||||
->money('IDR'),
|
||||
|
||||
TextEntry::make('payment.payment_date')
|
||||
->label('Tanggal Bayar')
|
||||
->dateTime(),
|
||||
]),
|
||||
|
||||
TextEntry::make('payment.description')
|
||||
->label('Keterangan')
|
||||
->visible(fn (CooperationMedia $record): bool => $record->description !== null),
|
||||
|
||||
ImageEntry::make('payment_proof')
|
||||
->label('Bukti Pembayaran')
|
||||
->getStateUsing(fn (CooperationMedia $record): ?string => optional($record->getMedia('cooperations')->where('custom_properties.doc_type', 'payment-proof')->sortByDesc('created_at')->first())->getPathRelativeToRoot())
|
||||
->disk(config('filesystems.default')),
|
||||
])
|
||||
->columns(1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
namespace App\Filament\Resources\Manage\Cooperations\RelationManagers;
|
||||
|
||||
use App\Enums\ApprovalStatus;
|
||||
use App\Enums\RoleEnum;
|
||||
use App\Filament\Resources\Manage\Cooperations\Actions\Proposal\AcceptAction;
|
||||
use App\Filament\Resources\Manage\Cooperations\Actions\Proposal\RejectAction;
|
||||
use App\Models\CooperationProposal;
|
||||
@ -16,14 +17,36 @@
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Joaopaulolndev\FilamentPdfViewer\Infolists\Components\PdfViewerEntry;
|
||||
|
||||
class CooperationProposalRelationManager extends RelationManager
|
||||
{
|
||||
protected static string $relationship = 'proposals';
|
||||
protected static string $relationship = 'proposal';
|
||||
|
||||
protected static ?string $title = 'Proposal';
|
||||
|
||||
public static function canViewForRecord(Model $ownerRecord, string $pageClass): bool
|
||||
{
|
||||
if (auth()->user()->hasRole(RoleEnum::PERUSAHAAN->value)) {
|
||||
return $ownerRecord->cooperationMedia()
|
||||
->whereHas('partnerMedia', function ($query) {
|
||||
$query->whereHas('company', function ($query) {
|
||||
$query->where('user_id', auth()->id());
|
||||
});
|
||||
})
|
||||
->where('status', ApprovalStatus::ACCEPTED)
|
||||
->exists();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function getBadge(Model $ownerRecord, string $pageClass): ?string
|
||||
{
|
||||
return $ownerRecord->proposal()->count();
|
||||
}
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
namespace App\Filament\Resources\Manage\Cooperations\RelationManagers;
|
||||
|
||||
use App\Enums\ApprovalStatus;
|
||||
use App\Enums\CooperationStatus;
|
||||
use App\Enums\RoleEnum;
|
||||
use App\Filament\Resources\Manage\Cooperations\Actions\Report\AcceptAction;
|
||||
use App\Filament\Resources\Manage\Cooperations\Actions\Report\RejectAction;
|
||||
use App\Filament\Resources\Manage\Cooperations\CooperationResource;
|
||||
@ -22,7 +24,6 @@
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class ReportRelationManager extends RelationManager
|
||||
{
|
||||
@ -30,6 +31,22 @@ class ReportRelationManager extends RelationManager
|
||||
|
||||
protected static ?string $title = 'Laporan';
|
||||
|
||||
public static function canViewForRecord(Model $ownerRecord, string $pageClass): bool
|
||||
{
|
||||
if (auth()->user()->hasRole(RoleEnum::PERUSAHAAN->value)) {
|
||||
return $ownerRecord->cooperationMedia()
|
||||
->whereHas('partnerMedia', function ($query) {
|
||||
$query->whereHas('company', function ($query) {
|
||||
$query->where('user_id', auth()->id());
|
||||
});
|
||||
})
|
||||
->where('status', ApprovalStatus::ACCEPTED)
|
||||
->exists();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isReadOnly(): bool
|
||||
{
|
||||
return false;
|
||||
@ -138,8 +155,8 @@ public function table(Table $table): Table
|
||||
User::superAdmin()
|
||||
->get()
|
||||
->each(function ($admin) use ($record): void {
|
||||
$user = auth()->user();
|
||||
|
||||
$user = Auth::user();
|
||||
$admin->notify(new BroadcastNotification([
|
||||
'title' => 'Ada Laporan Baru! 📝✨',
|
||||
'body' => "Halo Admin! {$user->name} baru saja mengirimkan laporan \"{$record->title}\" untuk kerja sama \"{$this->getOwnerRecord()->title}\". Yuk, dicek! 😊",
|
||||
@ -152,8 +169,7 @@ public function table(Table $table): Table
|
||||
});
|
||||
})
|
||||
->visible(function (): bool {
|
||||
|
||||
$user = Auth::user();
|
||||
$user = auth()->user();
|
||||
|
||||
if (! $user || ! $user->hasRole('Perusahaan')) {
|
||||
return false;
|
||||
@ -165,9 +181,10 @@ public function table(Table $table): Table
|
||||
return false;
|
||||
}
|
||||
|
||||
return $taskAssignment->reports()
|
||||
->where('status', '!=', ApprovalStatus::REJECTED)
|
||||
->count() < $taskAssignment->report_amount;
|
||||
return $this->getOwnerRecord()->status === CooperationStatus::ASSIGNMENT
|
||||
&& $taskAssignment->reports()
|
||||
->where('status', '!=', ApprovalStatus::REJECTED)
|
||||
->count() < $taskAssignment->report_amount;
|
||||
}),
|
||||
])
|
||||
->toolbarActions([]);
|
||||
|
||||
@ -3,20 +3,17 @@
|
||||
namespace App\Filament\Resources\Manage\Cooperations\RelationManagers;
|
||||
|
||||
use App\Enums\ApprovalStatus;
|
||||
use App\Enums\RoleEnum;
|
||||
use App\Filament\Actions\Cheerful\CreateAction;
|
||||
use App\Filament\Actions\Cheerful\DeleteAction;
|
||||
use App\Filament\Actions\Cheerful\EditAction;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Resources\RelationManagers\RelationManager;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class TaskAssignmentRelationManager extends RelationManager
|
||||
{
|
||||
@ -24,58 +21,25 @@ class TaskAssignmentRelationManager extends RelationManager
|
||||
|
||||
protected static ?string $title = 'Penugasan';
|
||||
|
||||
public function form(Schema $schema): Schema
|
||||
public static function canViewForRecord(Model $ownerRecord, string $pageClass): bool
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
DatePicker::make('start_date')
|
||||
->label('Tanggal Mulai')
|
||||
->required()
|
||||
->native(false)
|
||||
->autocomplete(false)
|
||||
->autofocus(),
|
||||
if (auth()->user()->hasRole(RoleEnum::PERUSAHAAN->value)) {
|
||||
return $ownerRecord->cooperationMedia()
|
||||
->whereHas('partnerMedia', function ($query) {
|
||||
$query->whereHas('company', function ($query) {
|
||||
$query->where('user_id', auth()->id());
|
||||
});
|
||||
})
|
||||
->where('status', ApprovalStatus::ACCEPTED)
|
||||
->exists();
|
||||
}
|
||||
|
||||
DatePicker::make('end_date')
|
||||
->label('Tanggal Selesai')
|
||||
->required()
|
||||
->native(false)
|
||||
->after('start_date')
|
||||
->autocomplete(false),
|
||||
return true;
|
||||
}
|
||||
|
||||
Textarea::make('task_description')
|
||||
->label('Deskripsi Tugas')
|
||||
->required()
|
||||
->rows(4)
|
||||
->maxLength(65535)
|
||||
->autocomplete(false),
|
||||
|
||||
TextInput::make('report_amount')
|
||||
->label('Jumlah Laporan')
|
||||
->numeric()
|
||||
->required()
|
||||
->minValue(1)
|
||||
->default(1)
|
||||
->autocomplete(false),
|
||||
|
||||
Select::make('partner_media_ids')
|
||||
->label('Media yang Ditugaskan')
|
||||
->relationship('partnerMedia', 'name')
|
||||
->multiple()
|
||||
->preload()
|
||||
->required()
|
||||
->autocomplete(false),
|
||||
|
||||
Select::make('status')
|
||||
->options(ApprovalStatus::options())
|
||||
->required()
|
||||
->default(ApprovalStatus::PENDING),
|
||||
|
||||
Textarea::make('rejection_reason')
|
||||
->label('Alasan Penolakan')
|
||||
->rows(3)
|
||||
->columnSpanFull()
|
||||
->autocomplete(false),
|
||||
]);
|
||||
public static function getBadge(Model $ownerRecord, string $pageClass): ?string
|
||||
{
|
||||
return $ownerRecord->taskAssignment()->count();
|
||||
}
|
||||
|
||||
public function table(Table $table): Table
|
||||
@ -107,7 +71,7 @@ public function table(Table $table): Table
|
||||
->visible(function (): bool {
|
||||
$cooperation = $this->getOwnerRecord();
|
||||
|
||||
return $cooperation->proposals()->accepted()->exists()
|
||||
return $cooperation->proposal()->accepted()->exists()
|
||||
&& ! $cooperation->taskAssignment()->exists();
|
||||
})
|
||||
->successNotification(
|
||||
|
||||
@ -8,7 +8,9 @@
|
||||
use App\Filament\Actions\DefaultBulkActions;
|
||||
use App\Filament\Columns\TimestampColumns;
|
||||
use App\Filament\Resources\Manage\Cooperations\Actions\Cooperation\AcceptAction;
|
||||
use App\Filament\Resources\Manage\Cooperations\Actions\Cooperation\CompleteCooperationAction;
|
||||
use App\Filament\Resources\Manage\Cooperations\Actions\Cooperation\CreateTaskAssignmentAction;
|
||||
use App\Filament\Resources\Manage\Cooperations\Actions\Cooperation\ProceedToPaymentAction;
|
||||
use App\Filament\Resources\Manage\Cooperations\Actions\Cooperation\RejectAction;
|
||||
use App\Filament\Resources\Manage\Cooperations\Actions\Cooperation\SendProposalAction;
|
||||
use App\Models\Cooperation;
|
||||
@ -61,22 +63,6 @@ public static function configure(Table $table): Table
|
||||
)
|
||||
),
|
||||
|
||||
TextColumn::make('assignment_deadline')
|
||||
->label('Deadline Penugasan')
|
||||
->searchable()
|
||||
->sortable()
|
||||
->date('l, d F Y')
|
||||
->placeholder('Belum ditentukan')
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
|
||||
TextColumn::make('verification_deadline')
|
||||
->label('Deadline Verifikasi')
|
||||
->searchable()
|
||||
->sortable()
|
||||
->date('l, d F Y')
|
||||
->placeholder('Belum ditentukan')
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
|
||||
TextColumn::make('status')
|
||||
->searchable()
|
||||
->sortable()
|
||||
@ -158,6 +144,10 @@ public static function configure(Table $table): Table
|
||||
|
||||
CreateTaskAssignmentAction::make('createTaskAssignment'),
|
||||
|
||||
ProceedToPaymentAction::make('proceedToPayment'),
|
||||
|
||||
CompleteCooperationAction::make('completeCooperation'),
|
||||
|
||||
EditAction::make()
|
||||
->visible(fn (): bool => ! auth()->user()->hasRole('Perusahaan')),
|
||||
|
||||
|
||||
@ -26,8 +26,6 @@ protected function casts(): array
|
||||
return [
|
||||
'initial_submission_date' => 'date',
|
||||
'final_submission_date' => 'date',
|
||||
'assignment_deadline' => 'date',
|
||||
'verification_deadline' => 'date',
|
||||
'payment_amount' => 'integer',
|
||||
'payment_date' => 'date',
|
||||
'status' => CooperationStatus::class,
|
||||
@ -64,9 +62,9 @@ protected function completed(Builder $query): void
|
||||
$query->where('status', CooperationStatus::COMPLETED);
|
||||
}
|
||||
|
||||
public function proposals(): HasMany
|
||||
public function proposal(): HasOne
|
||||
{
|
||||
return $this->hasMany(CooperationProposal::class);
|
||||
return $this->hasOne(CooperationProposal::class);
|
||||
}
|
||||
|
||||
public function taskAssignment(): HasOne
|
||||
|
||||
@ -7,12 +7,15 @@
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||
use Illuminate\Database\Eloquent\Relations\Pivot;
|
||||
use Spatie\MediaLibrary\HasMedia;
|
||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||
|
||||
class CooperationMedia extends Pivot
|
||||
class CooperationMedia extends Pivot implements HasMedia
|
||||
{
|
||||
use HasFactory;
|
||||
use HasFactory, InteractsWithMedia;
|
||||
|
||||
protected $table = 'cooperation_media';
|
||||
|
||||
@ -57,4 +60,9 @@ public function rejectionReasons(): MorphMany
|
||||
{
|
||||
return $this->morphMany(RejectionReason::class, 'rejectable');
|
||||
}
|
||||
|
||||
public function payment(): HasOne
|
||||
{
|
||||
return $this->hasOne(CooperationPayment::class, 'cooperation_media_id');
|
||||
}
|
||||
}
|
||||
|
||||
29
app/Models/CooperationPayment.php
Normal file
29
app/Models/CooperationPayment.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Spatie\MediaLibrary\HasMedia;
|
||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||
|
||||
class CooperationPayment extends Model implements HasMedia
|
||||
{
|
||||
use HasFactory, InteractsWithMedia;
|
||||
|
||||
protected $guarded = ['id'];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'amount' => 'integer',
|
||||
'payment_date' => 'datetime',
|
||||
];
|
||||
}
|
||||
|
||||
public function cooperationMedia(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(CooperationMedia::class);
|
||||
}
|
||||
}
|
||||
@ -17,8 +17,6 @@ public function up(): void
|
||||
$table->string('title', 200);
|
||||
$table->date('initial_submission_date');
|
||||
$table->date('final_submission_date');
|
||||
$table->date('assignment_deadline')->nullable();
|
||||
$table->date('verification_deadline')->nullable();
|
||||
$table->text('description');
|
||||
$table->unsignedInteger('payment_amount')->nullable();
|
||||
$table->date('payment_date')->nullable();
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use App\Models\CooperationMedia;
|
||||
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('cooperation_payments', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignIdFor(CooperationMedia::class)->constrained()->cascadeOnDelete();
|
||||
$table->unsignedInteger('amount');
|
||||
$table->text('description')->nullable();
|
||||
$table->date('payment_date')->useCurrent();
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
$table->timestamp('updated_at')->nullable()->useCurrentOnUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('cooperation_payments');
|
||||
}
|
||||
};
|
||||
36
database/seeders/CooperationSeeder.php
Normal file
36
database/seeders/CooperationSeeder.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Enums\ApprovalStatus;
|
||||
use App\Enums\CooperationStatus;
|
||||
use App\Models\Cooperation;
|
||||
use App\Models\PartnerMedia;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class CooperationSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$cooperation = Cooperation::create([
|
||||
'title' => 'Kerja Sama Media '.now()->format('Y'),
|
||||
'description' => 'Kerja sama media untuk penyebarluasan informasi publik.',
|
||||
'initial_submission_date' => now()->subDay(),
|
||||
'final_submission_date' => now(),
|
||||
'status' => CooperationStatus::PENDING,
|
||||
]);
|
||||
|
||||
$verifiedMedia = PartnerMedia::verified()->get();
|
||||
|
||||
foreach ($verifiedMedia as $media) {
|
||||
$cooperation->partnerMedia()->attach($media->id, [
|
||||
'status' => ApprovalStatus::PENDING,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user