177 lines
5.4 KiB
PHP
177 lines
5.4 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\API\v1\Voter;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Controllers\Util;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
/**
|
|
* Import keanggotaan JSON (match by no_anggota) into voter money columns for the current election.
|
|
* Expected row keys: no_anggota, pelaburan, pelaburan_2, saham, yuran. Null/empty → 0.
|
|
*/
|
|
class ImportKeanggotaanJsonController extends Controller
|
|
{
|
|
private const UPDATABLE_FIELDS = [
|
|
'pelaburan',
|
|
'pelaburan_2',
|
|
'saham',
|
|
'yuran',
|
|
];
|
|
|
|
public function __invoke(Request $request)
|
|
{
|
|
$this->validate($request, [
|
|
'file' => 'required|file|max:10240',
|
|
]);
|
|
|
|
$file = $request->file('file');
|
|
$extension = strtolower($file->getClientOriginalExtension() ?: '');
|
|
if ($extension !== 'json') {
|
|
return response()->json([
|
|
'status' => 'failed',
|
|
'message' => 'Fail mestilah format .json.',
|
|
], 422);
|
|
}
|
|
|
|
$raw = file_get_contents($file->getRealPath());
|
|
$rows = json_decode($raw, true);
|
|
|
|
if (!is_array($rows)) {
|
|
return response()->json([
|
|
'status' => 'failed',
|
|
'message' => 'JSON tidak sah. Jangkaan array objek.',
|
|
], 422);
|
|
}
|
|
|
|
$map = [];
|
|
foreach ($rows as $row) {
|
|
if (!is_array($row)) {
|
|
continue;
|
|
}
|
|
|
|
$noAnggota = isset($row['no_anggota']) ? trim((string) $row['no_anggota']) : '';
|
|
if ($noAnggota === '') {
|
|
continue;
|
|
}
|
|
|
|
$payload = [];
|
|
foreach (self::UPDATABLE_FIELDS as $field) {
|
|
if (array_key_exists($field, $row)) {
|
|
$payload[$field] = $this->cleanNumber($row[$field]);
|
|
}
|
|
}
|
|
|
|
if (count($payload) === 0) {
|
|
continue;
|
|
}
|
|
|
|
$map[$noAnggota] = $payload;
|
|
}
|
|
|
|
if (count($map) === 0) {
|
|
return response()->json([
|
|
'status' => 'failed',
|
|
'message' => 'Tiada baris sah dalam JSON (perlu no_anggota dan sekurang-kurangnya satu medan).',
|
|
], 422);
|
|
}
|
|
|
|
$electionId = (int) Util::getCurrentElection();
|
|
if ($electionId <= 0) {
|
|
return response()->json([
|
|
'status' => 'failed',
|
|
'message' => 'Tidak dapat mengenal pasti election semasa.',
|
|
], 422);
|
|
}
|
|
|
|
$stats = [
|
|
'election_id' => $electionId,
|
|
'json_rows' => count($map),
|
|
'matched' => 0,
|
|
'updated' => 0,
|
|
'unchanged' => 0,
|
|
'missing_in_voter' => 0,
|
|
'missing_in_json' => 0,
|
|
];
|
|
|
|
$matchedKeys = [];
|
|
|
|
DB::table('voter')
|
|
->select(array_merge(['id', 'no_anggota'], self::UPDATABLE_FIELDS))
|
|
->where('election_id', $electionId)
|
|
->orderBy('id')
|
|
->chunkById(500, function ($chunk) use ($map, &$stats, &$matchedKeys) {
|
|
foreach ($chunk as $voter) {
|
|
$noAnggota = $voter->no_anggota !== null ? trim((string) $voter->no_anggota) : '';
|
|
|
|
if ($noAnggota === '' || !array_key_exists($noAnggota, $map)) {
|
|
$stats['missing_in_json']++;
|
|
continue;
|
|
}
|
|
|
|
$stats['matched']++;
|
|
$matchedKeys[$noAnggota] = true;
|
|
$jsonRow = $map[$noAnggota];
|
|
|
|
$update = [];
|
|
foreach ($jsonRow as $field => $newValue) {
|
|
$oldValue = $voter->{$field} !== null ? (float) $voter->{$field} : 0.0;
|
|
if (abs($oldValue - $newValue) >= 0.00001) {
|
|
$update[$field] = $newValue;
|
|
}
|
|
}
|
|
|
|
if (count($update) === 0) {
|
|
$stats['unchanged']++;
|
|
continue;
|
|
}
|
|
|
|
$update['updated_at'] = now();
|
|
DB::table('voter')->where('id', $voter->id)->update($update);
|
|
$stats['updated']++;
|
|
}
|
|
}, 'id');
|
|
|
|
foreach ($map as $noAnggota => $_payload) {
|
|
if (!isset($matchedKeys[$noAnggota])) {
|
|
$stats['missing_in_voter']++;
|
|
}
|
|
}
|
|
|
|
activity()
|
|
->withProperties([
|
|
'election_id' => $electionId,
|
|
'filename' => $file->getClientOriginalName(),
|
|
'stats' => $stats,
|
|
'ip' => $request->ip(),
|
|
'user_agent' => $request->userAgent(),
|
|
])
|
|
->log('import keanggotaan json');
|
|
|
|
return response()->json([
|
|
'status' => 'success',
|
|
'message' => 'Import keanggotaan berjaya.',
|
|
'data' => $stats,
|
|
]);
|
|
}
|
|
|
|
private function cleanNumber($value): float
|
|
{
|
|
if ($value === null || $value === '') {
|
|
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;
|
|
}
|
|
}
|