refactor(shoraka): move financing records to master database
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,11 @@ use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class ShorakaFinancing extends Model
|
||||
{
|
||||
public function getConnectionName()
|
||||
{
|
||||
return $this->connection ?: config('shoraka.financing_connection');
|
||||
}
|
||||
|
||||
protected $guarded = [];
|
||||
protected $casts = ['context' => 'array'];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user