172 lines
6.1 KiB
PHP
172 lines
6.1 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class UpdateVoterDividenFromJson extends Command
|
|
{
|
|
protected $signature = 'voter:update-dividen-from-json
|
|
{--file=database/seeds/inject/dividen_yuransaham.json : Relative path from project root}
|
|
{--election_id= : Override election_id (default: latest in voter table)}
|
|
{--dry-run : Show what would change without updating}';
|
|
|
|
protected $description = 'Update voter saham/yuran and populate dividen_saham/dividen_yuran from JSON for latest election only';
|
|
|
|
public function handle()
|
|
{
|
|
$fileOpt = (string) $this->option('file');
|
|
$filePath = $this->resolvePath($fileOpt);
|
|
|
|
if (!is_file($filePath)) {
|
|
$this->error("❌ JSON file not found: {$filePath}");
|
|
return 1;
|
|
}
|
|
|
|
$electionId = $this->option('election_id');
|
|
$electionId = $electionId !== null && $electionId !== '' ? (int) $electionId : (int) DB::table('voter')->max('election_id');
|
|
|
|
if ($electionId <= 0) {
|
|
$this->error("❌ Cannot determine latest election_id (got {$electionId}).");
|
|
return 1;
|
|
}
|
|
|
|
$json = file_get_contents($filePath);
|
|
$rows = json_decode($json, true);
|
|
|
|
if (!is_array($rows)) {
|
|
$this->error("❌ Invalid JSON: expected array of rows.");
|
|
return 1;
|
|
}
|
|
|
|
$map = [];
|
|
foreach ($rows as $row) {
|
|
if (!is_array($row)) {
|
|
continue;
|
|
}
|
|
|
|
$noAnggota = isset($row['no_anggota']) ? trim((string) $row['no_anggota']) : '';
|
|
if ($noAnggota === '') {
|
|
continue;
|
|
}
|
|
|
|
$map[$noAnggota] = [
|
|
'saham' => $this->cleanNumber($row['saham'] ?? 0),
|
|
'yuran' => $this->cleanNumber($row['yuran'] ?? 0),
|
|
'dividen_saham' => $this->cleanNumber($row['dividen_saham'] ?? 0),
|
|
'dividen_yuran' => $this->cleanNumber($row['dividen_yuran'] ?? 0),
|
|
];
|
|
}
|
|
|
|
if (count($map) === 0) {
|
|
$this->error("❌ No usable rows found in JSON (missing no_anggota?).");
|
|
return 1;
|
|
}
|
|
|
|
$dryRun = (bool) $this->option('dry-run');
|
|
|
|
$this->info("Target election_id: {$electionId}");
|
|
$this->info("JSON members loaded: " . count($map));
|
|
$this->info($dryRun ? "Mode: DRY RUN (no DB updates)" : "Mode: UPDATE");
|
|
|
|
$totalInElection = (int) DB::table('voter')->where('election_id', $electionId)->count();
|
|
$this->info("Voters in election: {$totalInElection}");
|
|
|
|
$updated = 0;
|
|
$matched = 0;
|
|
$missingInJson = 0;
|
|
$unchanged = 0;
|
|
|
|
$bar = $this->output->createProgressBar(max(1, $totalInElection));
|
|
$bar->start();
|
|
|
|
DB::table('voter')
|
|
->select(['id', 'no_anggota', 'saham', 'yuran', 'dividen_saham', 'dividen_yuran'])
|
|
->where('election_id', $electionId)
|
|
->orderBy('id')
|
|
->chunkById(500, function ($chunk) use ($map, $dryRun, &$updated, &$matched, &$missingInJson, &$unchanged, $bar) {
|
|
foreach ($chunk as $voter) {
|
|
$noAnggota = $voter->no_anggota !== null ? trim((string) $voter->no_anggota) : '';
|
|
|
|
if ($noAnggota === '' || !array_key_exists($noAnggota, $map)) {
|
|
$missingInJson++;
|
|
$bar->advance();
|
|
continue;
|
|
}
|
|
|
|
$matched++;
|
|
$jsonRow = $map[$noAnggota];
|
|
|
|
$oldSaham = $voter->saham !== null ? (float) $voter->saham : 0.0;
|
|
$oldYuran = $voter->yuran !== null ? (float) $voter->yuran : 0.0;
|
|
$oldDividenSaham = $voter->dividen_saham !== null ? (float) $voter->dividen_saham : 0.0;
|
|
$oldDividenYuran = $voter->dividen_yuran !== null ? (float) $voter->dividen_yuran : 0.0;
|
|
|
|
if (
|
|
abs($oldSaham - $jsonRow['saham']) < 0.00001
|
|
&& abs($oldYuran - $jsonRow['yuran']) < 0.00001
|
|
&& abs($oldDividenSaham - $jsonRow['dividen_saham']) < 0.00001
|
|
&& abs($oldDividenYuran - $jsonRow['dividen_yuran']) < 0.00001
|
|
) {
|
|
$unchanged++;
|
|
$bar->advance();
|
|
continue;
|
|
}
|
|
|
|
if (!$dryRun) {
|
|
DB::table('voter')
|
|
->where('id', $voter->id)
|
|
->update([
|
|
'saham' => $jsonRow['saham'],
|
|
'yuran' => $jsonRow['yuran'],
|
|
'dividen_saham' => $jsonRow['dividen_saham'],
|
|
'dividen_yuran' => $jsonRow['dividen_yuran'],
|
|
'updated_at' => now(),
|
|
]);
|
|
}
|
|
|
|
$updated++;
|
|
$bar->advance();
|
|
}
|
|
}, 'id');
|
|
|
|
$bar->finish();
|
|
$this->line('');
|
|
|
|
$this->info("✅ Matched in JSON: {$matched}");
|
|
$this->info("✅ Updated: {$updated}" . ($dryRun ? " (would update)" : ""));
|
|
$this->info("✅ Unchanged: {$unchanged}");
|
|
$this->info("⚠️ Missing in JSON: {$missingInJson}");
|
|
|
|
return 0;
|
|
}
|
|
|
|
private function resolvePath(string $path): string
|
|
{
|
|
if (strpos($path, DIRECTORY_SEPARATOR) === 0) {
|
|
return $path;
|
|
}
|
|
|
|
return base_path($path);
|
|
}
|
|
|
|
private function cleanNumber($value): float
|
|
{
|
|
if ($value === null) {
|
|
return 0.0;
|
|
}
|
|
|
|
$value = (string) $value;
|
|
$value = str_replace(['RM', ',', ' '], '', $value);
|
|
|
|
if (preg_match('/^\((.*)\)$/', $value, $matches)) {
|
|
$value = $matches[1];
|
|
}
|
|
|
|
$value = preg_replace('/[^0-9\.\-]/', '', $value);
|
|
|
|
return is_numeric($value) ? (float) $value : 0.0;
|
|
}
|
|
}
|