refactor: modularize legacy cooperation migration logic and implement grouping by name to handle duplicates

This commit is contained in:
Yoga Pangestu 2026-04-13 15:42:13 +07:00
parent 27a4ade00b
commit 5b0588a367

View File

@ -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.');
}
}