Allowance check

This commit is contained in:
ISMAIL MASSERAN
2026-04-14 02:34:00 +00:00
parent 0c4d200839
commit 3775c4a876
100 changed files with 81493 additions and 3226 deletions
@@ -0,0 +1,68 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateAllowanceClaimCodesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('allowance_claim_codes', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedInteger('election_id');
$table->unsignedInteger('voter_id');
$table->string('method', 20)->default('cash'); // cash | bank
// Store hash only (never store plaintext code)
$table->string('code_hash', 255);
$table->string('code_last4', 10)->nullable();
$table->timestamp('expires_at')->nullable();
$table->timestamp('used_at')->nullable();
$table->unsignedInteger('used_by_admin_id')->nullable();
// Only one row per voter per election per method (regenerate by updating same row)
$table->unique(['election_id', 'voter_id', 'method'], 'allowance_claim_codes_unique');
$table->index(['election_id', 'method']);
$table->index(['voter_id', 'election_id']);
$table->index(['used_at']);
$table->foreign('election_id')
->references('id')
->on('election')
->onDelete('cascade');
$table->foreign('voter_id')
->references('id')
->on('voter')
->onDelete('cascade');
$table->foreign('used_by_admin_id')
->references('id')
->on('users')
->onDelete('set null');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('allowance_claim_codes');
}
}
@@ -0,0 +1,65 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateAllowancePayoutsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('allowance_payouts', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedInteger('election_id');
$table->unsignedInteger('voter_id');
// Allow future-proofing: cash for fizikal, bank for maya
$table->string('method', 20)->default('cash'); // cash | bank
$table->string('status', 20)->default('paid'); // paid | void | pending
// Store cents to avoid floating point issues
$table->unsignedInteger('amount_cents');
$table->char('currency', 3)->default('MYR');
// Officer/audit trail (admin user who performed the action)
$table->unsignedInteger('paid_by_admin_id')->nullable();
$table->timestamp('paid_at')->nullable();
$table->string('reference', 80)->nullable(); // optional bank ref / receipt no.
$table->text('note')->nullable();
// Prevent double-claim for the same election + method
$table->unique(['election_id', 'voter_id', 'method'], 'allowance_payouts_unique_claim');
$table->index(['election_id', 'method', 'status']);
$table->index(['voter_id', 'election_id']);
$table->foreign('election_id')
->references('id')
->on('election')
->onDelete('cascade');
$table->foreign('voter_id')
->references('id')
->on('voter')
->onDelete('cascade');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('allowance_payouts');
}
}
@@ -0,0 +1,43 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
class AddFizikalRegistrationVerifiedAtToVoterTable extends Migration
{
/**
* Physical attendees (kehadiran = 1) need admin confirmation before voting.
* NULL = not verified yet; non-NULL = verified at that time.
* Maya (kehadiran = 2) does not use this column for gating.
*
* @return void
*/
public function up()
{
if (! Schema::hasColumn('voter', 'fizikal_registration_verified_at')) {
Schema::table('voter', function (Blueprint $table) {
$table->timestamp('fizikal_registration_verified_at')->nullable()->after('kehadiran');
});
}
// Existing physical registrations are treated as already verified.
DB::table('voter')
->where('kehadiran', 1)
->whereNull('fizikal_registration_verified_at')
->update(['fizikal_registration_verified_at' => now()]);
}
/**
* @return void
*/
public function down()
{
if (Schema::hasColumn('voter', 'fizikal_registration_verified_at')) {
Schema::table('voter', function (Blueprint $table) {
$table->dropColumn('fizikal_registration_verified_at');
});
}
}
}
@@ -0,0 +1,38 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateActivityLogTable extends Migration
{
/**
* Run the migrations.
*/
public function up()
{
Schema::connection(config('activitylog.database_connection'))->create(config('activitylog.table_name'), function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('log_name')->nullable();
$table->text('description');
$table->unsignedBigInteger('subject_id')->nullable();
$table->string('subject_type')->nullable();
$table->unsignedBigInteger('causer_id')->nullable();
$table->string('causer_type')->nullable();
$table->json('properties')->nullable();
$table->timestamps();
$table->index('log_name');
$table->index(['subject_id', 'subject_type'], 'subject');
$table->index(['causer_id', 'causer_type'], 'causer');
});
}
/**
* Reverse the migrations.
*/
public function down()
{
Schema::connection(config('activitylog.database_connection'))->dropIfExists(config('activitylog.table_name'));
}
}