Files
kaunter/app/Console/Commands/MoveShorakaFinancings.php
T

79 lines
3.9 KiB
PHP

<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use RuntimeException;
class MoveShorakaFinancings extends Command
{
protected $signature = 'shoraka:move-financings {--source=mysql} {--apply : Copy records; default only checks}';
protected $description = 'Copy and verify financing records to shoraka_master without deleting the source';
public function handle()
{
$sourceName = $this->option('source');
$targetName = 'shoraka_master';
$source = DB::connection($sourceName);
$target = DB::connection($targetName);
if ($sourceName === $targetName || ($source->getConfig('host') === $target->getConfig('host')
&& $source->getDatabaseName() === $target->getDatabaseName()
&& $source->getConfig('port') === $target->getConfig('port'))) {
$this->error('Source and target must be different databases.');
return 1;
}
if (!Schema::connection($sourceName)->hasTable('shoraka_financings')
|| !Schema::connection($targetName)->hasTable('shoraka_financings')) {
$this->error('Create the target table using the API master migration first. Source and target tables are required.');
return 1;
}
if ($this->option('apply') && !app()->isDownForMaintenance()) {
$this->error('Stop traffic on every counter instance and run artisan down before applying the transfer.');
return 1;
}
if ($source->table('shoraka_financings')->where('state', 'PROCESSING')->exists()) {
$this->error('PROCESSING records require reconciliation before transfer.');
return 1;
}
$count = $source->table('shoraka_financings')->count();
if (!$this->option('apply')) {
$this->info($count . ' source records. Check only; no data was copied.');
return 0;
}
try {
$target->transaction(function () use ($source, $target) {
$source->table('shoraka_financings')->orderBy('id')->chunkById(200, function ($rows) use ($target) {
foreach ($rows as $row) {
$data = (array) $row;
unset($data['id']); // IDs may overlap across counter databases.
$key = ['kodcaw' => $row->kodcaw, 'norujukan' => $row->norujukan];
$existing = $target->table('shoraka_financings')->where($key)->first();
if (!$existing) {
$target->table('shoraka_financings')->insert($data);
$existing = $target->table('shoraka_financings')->where($key)->first();
}
foreach ($data as $field => $value) {
$actual = $existing->$field;
if ($field === 'context') {
if (json_decode($actual, true) != json_decode($value, true)) {
throw new RuntimeException('Conflicting context: ' . $row->kodcaw . '/' . $row->norujukan);
}
} elseif ((string) $actual !== (string) $value) {
throw new RuntimeException('Conflicting field ' . $field . ': ' . $row->kodcaw . '/' . $row->norujukan);
}
}
}
});
});
} catch (\Throwable $exception) {
$this->error('Transfer rolled back. ' . $exception->getMessage());
return 1;
}
$this->info($count . ' source records copied and verified. Source retained.');
$this->info('Ensure shoraka.financing_connection is shoraka_master and reload configuration before reopening traffic.');
return 0;
}
}