diff --git a/app/Console/Commands/MigrateCooperationCommand.php b/app/Console/Commands/MigrateCooperationCommand.php index 1b0d418..3abb791 100644 --- a/app/Console/Commands/MigrateCooperationCommand.php +++ b/app/Console/Commands/MigrateCooperationCommand.php @@ -5,235 +5,316 @@ use App\Enums\ApprovalStatus; use App\Enums\CooperationStatus; use Illuminate\Console\Command; +use Illuminate\Support\Carbon; +use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; -use Illuminate\Support\Str; class MigrateCooperationCommand extends Command { - /** - * The name and signature of the console command. - * - * @var string - */ protected $signature = 'migrate:cooperation'; - /** - * The console command description. - * - * @var string - */ - protected $description = 'Migrate cooperation data, proposals, and orders from legacy database'; + protected $description = 'Migrate cooperation data from legacy database'; /** - * Execute the console command. + * Map: legacy media_cooperation id => new cooperation_id + * Dipakai untuk lookup saat migrate proposals */ - public function handle() + private array $legacyCoopMap = []; + + public function handle(): void { - $this->info('Starting comprehensive cooperation and report migration...'); + $this->migrateMediaOrders(); + $this->migrateMediaCooperation(); + $this->migrateProposals(); + $this->migrateReports(); + } - $legacyConn = DB::connection('mysql_second'); - $offset = 10000; + private function migrateMediaOrders(): void + { + $this->info('Migrating media_orders → cooperations...'); - // 1. Migrate media_orders -> cooperations & task_assignments - $this->info('Migrating media_orders...'); - $legacyOrders = $legacyConn->table('media_orders')->get(); - $this->withProgressBar($legacyOrders, function ($legacy) { - $status = $legacy->deleted_at ? CooperationStatus::COMPLETED->value : CooperationStatus::ASSIGNMENT->value; + $groups = DB::connection('mysql_second') + ->table('media_orders') + ->whereNull('deleted_at') + ->orderBy('id') + ->get() + ->groupBy(fn ($item) => strtolower(trim($item->name))); - DB::table('cooperations')->updateOrInsert( - ['id' => $legacy->id], - [ - 'title' => Str::limit($legacy->name, 200), - 'initial_submission_date' => $legacy->begin, - 'final_submission_date' => $legacy->end, - 'description' => $legacy->description ?? '-', - 'status' => $status, - 'created_at' => $legacy->created_at ?? now(), - 'updated_at' => $legacy->updated_at ?? now(), - 'deleted_at' => $legacy->deleted_at, - ] + foreach ($groups as $group) { + $first = $group->first(); + $cooperationId = $this->insertCooperation( + name: $first->name, + description: $first->description, + initialDate: $group->min('begin'), + finalDate: $group->max('end'), + status: CooperationStatus::COMPLETED->value, + completedAt: $group->max('end'), ); - // Task Assignment - DB::table('task_assignments')->updateOrInsert( - ['id' => $legacy->id], - [ - 'cooperation_id' => $legacy->id, - 'start_date' => $legacy->begin, - 'end_date' => $legacy->end, - 'task_description' => $legacy->description ?? '-', - 'report_amount' => $legacy->amount_report ?? 1, - 'created_at' => $legacy->created_at ?? now(), - 'updated_at' => $legacy->updated_at ?? now(), - ] + $this->insertCooperationMedia( + group: $group, + cooperationId: $cooperationId, + approvalStatus: ApprovalStatus::ACCEPTED->value, ); - // Pivot Media - if ($legacy->media) { - $mediaIds = explode(',', $legacy->media); - $statuses = explode(',', $legacy->status); - foreach ($mediaIds as $index => $mediaId) { - $mediaId = trim($mediaId); - if (empty($mediaId)) { - continue; - } + $startDate = Carbon::parse($group->max('end'))->addDay(); + $endDate = $startDate->copy()->addDays(7); - $mediaStatus = isset($statuses[$index]) ? trim($statuses[$index]) : '1'; - $approval = $this->mapApprovalStatus($mediaStatus); + DB::table('task_assignments')->insert([ + 'cooperation_id' => $cooperationId, + 'start_date' => $startDate->toDateString(), + 'end_date' => $endDate->toDateString(), + 'task_description' => $first->description ?? '', + 'report_amount' => $group->sum('amount_report') ?: 1, + 'created_at' => now(), + 'updated_at' => now(), + ]); - DB::table('cooperation_media')->updateOrInsert( - ['cooperation_id' => $legacy->id, 'partner_media_id' => $mediaId], - ['status' => $approval, 'created_at' => $legacy->created_at ?? now(), 'updated_at' => $legacy->updated_at ?? now()] - ); + $taskAssignmentId = (int) DB::getPdo()->lastInsertId(); - DB::table('media_task_assignment')->updateOrInsert( - ['task_assignment_id' => $legacy->id, 'partner_media_id' => $mediaId], - ['status' => $approval, 'created_at' => $legacy->created_at ?? now(), 'updated_at' => $legacy->updated_at ?? now()] - ); - } + $this->insertMediaTaskAssignment( + cooperationId: $cooperationId, + taskAssignmentId: $taskAssignmentId, + approvalStatus: ApprovalStatus::ACCEPTED->value, + ); + + $this->info("Merged {$group->count()} rows → {$first->name}"); + } + + $this->info('media_orders migration done.'); + } + + private function migrateMediaCooperation(): void + { + $this->info('Migrating media_cooperation → cooperations...'); + + $groups = DB::connection('mysql_second') + ->table('media_cooperation') + ->whereNull('deleted_at') + ->orderBy('id') + ->get() + ->groupBy(fn ($item) => strtolower(trim($item->name))); + + foreach ($groups as $group) { + $first = $group->first(); + $cooperationId = $this->insertCooperation( + name: $first->name, + description: $first->description, + initialDate: $group->min('begin'), + finalDate: $group->max('end'), + status: CooperationStatus::PENDING->value, + completedAt: null, + ); + + $this->insertCooperationMedia( + group: $group, + cooperationId: $cooperationId, + approvalStatus: ApprovalStatus::PENDING->value, + ); + + $startDate = Carbon::parse($group->max('end'))->addDay(); + $endDate = $startDate->copy()->addDays(7); + + DB::table('task_assignments')->insert([ + 'cooperation_id' => $cooperationId, + 'start_date' => $startDate->toDateString(), + 'end_date' => $endDate->toDateString(), + 'task_description' => $first->description ?? '', + 'report_amount' => 1, + 'created_at' => now(), + 'updated_at' => now(), + ]); + + $taskAssignmentId = (int) DB::getPdo()->lastInsertId(); + + $this->insertMediaTaskAssignment( + cooperationId: $cooperationId, + taskAssignmentId: $taskAssignmentId, + approvalStatus: ApprovalStatus::PENDING->value, + ); + + // Simpan mapping legacy id → new cooperation_id untuk dipakai saat migrate proposals + foreach ($group as $item) { + $this->legacyCoopMap[$item->id] = $cooperationId; } - }); - $this->newLine(); - // 2. Migrate media_cooperation -> cooperations & task_assignments - $this->info('Migrating media_cooperation...'); - $legacyCoops = $legacyConn->table('media_cooperation')->get(); - $this->withProgressBar($legacyCoops, function ($legacy) use ($offset) { - $newId = $legacy->id + $offset; - $status = $legacy->deleted_at ? CooperationStatus::COMPLETED->value : CooperationStatus::PENDING->value; + $this->info("Merged {$group->count()} rows → {$first->name}"); + } - DB::table('cooperations')->updateOrInsert( - ['id' => $newId], - [ - 'title' => Str::limit($legacy->name, 200), - 'initial_submission_date' => $legacy->begin, - 'final_submission_date' => $legacy->end, - 'description' => $legacy->description ?? '-', - 'status' => $status, - 'created_at' => $legacy->created_at ?? now(), - 'updated_at' => $legacy->updated_at ?? now(), - 'deleted_at' => $legacy->deleted_at, - ] - ); + $this->info('media_cooperation migration done.'); + } - // Task Assignment - DB::table('task_assignments')->updateOrInsert( - ['id' => $newId], - [ - 'cooperation_id' => $newId, - 'start_date' => $legacy->begin, - 'end_date' => $legacy->end, - 'task_description' => $legacy->description ?? '-', - 'report_amount' => 1, - 'created_at' => $legacy->created_at ?? now(), - 'updated_at' => $legacy->updated_at ?? now(), - ] - ); + private function migrateProposals(): void + { + $this->info('Migrating propose_media_cooperation → cooperation_proposals...'); - // Pivot Media - if ($legacy->media) { - $mediaIds = explode(',', $legacy->media); - foreach ($mediaIds as $mediaId) { - $mediaId = trim($mediaId); - if (empty($mediaId)) { - continue; - } + $proposals = DB::connection('mysql_second') + ->table('propose_media_cooperation') + ->whereNull('deleted_at') + ->get(); - DB::table('cooperation_media')->updateOrInsert( - ['cooperation_id' => $newId, 'partner_media_id' => $mediaId], - ['status' => ApprovalStatus::PENDING->value, 'created_at' => $legacy->created_at ?? now(), 'updated_at' => $legacy->updated_at ?? now()] - ); + foreach ($proposals as $proposal) { + $cooperationId = $this->legacyCoopMap[$proposal->media_cooperation_id] ?? null; - DB::table('media_task_assignment')->updateOrInsert( - ['task_assignment_id' => $newId, 'partner_media_id' => $mediaId], - ['status' => ApprovalStatus::PENDING->value, 'created_at' => $legacy->created_at ?? now(), 'updated_at' => $legacy->updated_at ?? now()] - ); - } + if (! $cooperationId) { + $this->warn("cooperation not found for proposal {$proposal->id} (media_cooperation_id: {$proposal->media_cooperation_id})"); + + continue; } - }); - $this->newLine(); - // 3. Migrate proposals - $this->info('Migrating proposals...'); - $legacyProposals = $legacyConn->table('propose_media_cooperation')->get(); - $this->withProgressBar($legacyProposals, function ($legacy) use ($offset) { - $media = DB::table('partner_media') + $partnerMediaId = DB::table('partner_media') ->join('companies', 'partner_media.company_id', '=', 'companies.id') - ->where('companies.user_id', $legacy->enhancer) - ->select('partner_media.id') - ->first(); + ->where('companies.user_id', $proposal->enhancer) + ->value('partner_media.id'); - if (! $media) { - return; + if (! $partnerMediaId) { + $this->warn("partner_media not found for proposal {$proposal->id} (enhancer/user_id: {$proposal->enhancer})"); + + continue; } - DB::table('cooperation_proposals')->updateOrInsert( - ['id' => $legacy->id], - [ - 'cooperation_id' => $legacy->media_cooperation_id + $offset, - 'partner_media_id' => $media->id, - 'description' => $legacy->rejection_reason ?? '-', - 'e_catalog' => Str::limit($legacy->e_catalog, 200), - 'status' => $this->mapApprovalStatus($legacy->status), - 'submitted_at' => $legacy->created_at ?? now(), - 'responded_at' => $legacy->updated_at, - 'created_at' => $legacy->created_at ?? now(), - 'updated_at' => $legacy->updated_at ?? now(), - ] - ); - }); - $this->newLine(); + DB::table('cooperation_proposals')->insert([ + 'cooperation_id' => $cooperationId, + 'partner_media_id' => $partnerMediaId, + 'description' => null, + 'e_catalog' => null, + 'status' => $this->mapApprovalStatus($proposal->status), + 'submitted_at' => $proposal->created_at ?? now(), + 'responded_at' => $proposal->updated_at, + 'created_at' => $proposal->created_at ?? now(), + 'updated_at' => $proposal->updated_at ?? now(), + ]); + } - // 4. Migrate reports - $this->info('Migrating reports...'); - $legacyReports = $legacyConn->table('reports')->get(); - $this->withProgressBar($legacyReports, function ($legacy) { - // Find media_task_assignment_id - // We assume media_order in reports refers to media_orders table primarily - $assignment = DB::table('media_task_assignment') - ->where('task_assignment_id', $legacy->media_order) - ->where('partner_media_id', $legacy->media) - ->first(); - - if (! $assignment) { - return; - } - - DB::table('reports')->updateOrInsert( - ['id' => $legacy->id], - [ - 'media_task_assignment_id' => $assignment->id, - 'title' => $legacy->title, - 'publication_date' => $legacy->broadcast ?? $legacy->created_at ?? now(), - 'link' => Str::limit($legacy->link, 50), - 'description' => 'Legacy Proof: '.($legacy->proof ?? '-'), - 'status' => $this->mapReportStatus($legacy->status), - 'created_at' => $legacy->created_at ?? now(), - 'updated_at' => $legacy->updated_at ?? now(), - 'deleted_at' => $legacy->deleted_at, - ] - ); - }); - $this->newLine(); - - $this->info('Cooperation and report migration completed!'); + $this->info('proposals migration done.'); } - private function mapApprovalStatus($legacy): int + // ========================================================= + // Helper Methods + // ========================================================= + + private function insertCooperation( + string $name, + ?string $description, + string $initialDate, + string $finalDate, + string $status, + ?string $completedAt, + ): int { + DB::table('cooperations')->insert([ + 'title' => $name, + 'initial_submission_date' => $initialDate, + 'final_submission_date' => $finalDate, + 'description' => $description ?? '', + 'payment_amount' => null, + 'payment_date' => null, + 'completed_at' => $completedAt, + 'status' => $status, + 'created_at' => now(), + 'updated_at' => now(), + ]); + + return (int) DB::getPdo()->lastInsertId(); + } + + private function insertCooperationMedia( + Collection $group, + int $cooperationId, + string $approvalStatus, + ): void { + $validMediaIds = DB::table('partner_media')->pluck('id')->toArray(); + + $mediaIds = collect(); + + foreach ($group as $item) { + if (! $item->media) { + continue; + } + $mediaIds = $mediaIds->merge(explode(',', $item->media)); + } + + $mediaIds + ->map(fn ($id) => (int) $id) + ->filter(fn ($id) => in_array($id, $validMediaIds)) + ->unique() + ->each(function ($mediaId) use ($cooperationId, $approvalStatus) { + DB::table('cooperation_media')->insert([ + 'cooperation_id' => $cooperationId, + 'partner_media_id' => $mediaId, + 'status' => $approvalStatus, + 'created_at' => now(), + 'updated_at' => now(), + ]); + }); + } + + private function mapApprovalStatus(string $legacy): string { - return match ((string) $legacy) { - '1', '4' => ApprovalStatus::ACCEPTED->value, - '2', '0' => ApprovalStatus::REJECTED->value, // Assume 0 is rejected/inactive in some contexts, but let's see + return match ($legacy) { + 'accepted' => ApprovalStatus::ACCEPTED->value, + 'rejected' => ApprovalStatus::REJECTED->value, default => ApprovalStatus::PENDING->value, }; } - private function mapReportStatus($legacy): int + private function insertMediaTaskAssignment( + int $cooperationId, + int $taskAssignmentId, + string $approvalStatus, + ): void { + $mediaIds = DB::table('cooperation_media') + ->where('cooperation_id', $cooperationId) + ->pluck('partner_media_id'); + + foreach ($mediaIds as $partnerMediaId) { + DB::table('media_task_assignment')->insert([ + 'task_assignment_id' => $taskAssignmentId, + 'partner_media_id' => $partnerMediaId, + 'status' => $approvalStatus, + 'created_at' => now(), + 'updated_at' => now(), + ]); + } + } + + private function migrateReports(): void { - return match ((string) $legacy) { - '1' => ApprovalStatus::ACCEPTED->value, - '2' => ApprovalStatus::REJECTED->value, - default => ApprovalStatus::PENDING->value, - }; + $this->info('Migrating reports → reports...'); + + $legacyReports = DB::connection('mysql_second') + ->table('reports') + ->whereNull('deleted_at') + ->get(); + + foreach ($legacyReports as $legacy) { + // Cari media_task_assignment berdasarkan partner_media_id + // dan task_assignment yang berelasi ke cooperation dengan tanggal yang sesuai + $mediaTaskAssignment = DB::table('media_task_assignment') + ->join('task_assignments', 'media_task_assignment.task_assignment_id', '=', 'task_assignments.id') + ->where('media_task_assignment.partner_media_id', $legacy->media) + ->whereDate('task_assignments.start_date', '<=', $legacy->broadcast) + ->whereDate('task_assignments.end_date', '>=', $legacy->broadcast) + ->select('media_task_assignment.id') + ->first(); + + if (! $mediaTaskAssignment) { + $this->warn("media_task_assignment not found for report {$legacy->id}"); + + continue; + } + + DB::table('reports')->insert([ + 'media_task_assignment_id' => $mediaTaskAssignment->id, + 'title' => $legacy->title, + 'publication_date' => $legacy->broadcast, + 'link' => $legacy->link, + 'description' => $legacy->proof ?? '', + 'status' => $this->mapApprovalStatus($legacy->status), + 'created_at' => $legacy->created_at ?? now(), + 'updated_at' => $legacy->updated_at ?? now(), + ]); + } + + $this->info('reports migration done.'); } }