Allowance check
This commit is contained in:
@@ -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');
|
||||
}
|
||||
}
|
||||
+43
@@ -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'));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user