update api register

This commit is contained in:
Wian Drs
2026-08-01 11:42:42 +07:00
parent b0d08211ec
commit 75342dc7b7
55 changed files with 2254 additions and 35 deletions
@@ -0,0 +1,100 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('voucher_agents', function (Blueprint $table) {
$table->id();
$table->uuid('uuid')->unique();
$table->foreignId('tenant_id')->constrained()->cascadeOnDelete();
$table->foreignId('user_id')->constrained()->restrictOnDelete();
$table->string('agent_code');
$table->string('payment_type', 20);
$table->string('price_mode', 20)->default('discount');
$table->decimal('discount_percent', 5, 2)->default(0);
$table->decimal('commission_percent', 5, 2)->default(0);
$table->decimal('credit_limit', 18, 2)->default(0);
$table->decimal('outstanding_balance', 18, 2)->default(0);
$table->string('status', 20)->default('active');
$table->text('notes')->nullable();
$table->timestamps();
$table->unique(['tenant_id', 'user_id']);
$table->unique(['tenant_id', 'agent_code']);
$table->index(['tenant_id', 'payment_type', 'status']);
});
Schema::create('voucher_sales', function (Blueprint $table) {
$table->id();
$table->uuid('uuid')->unique();
$table->string('sale_number')->unique();
$table->foreignId('tenant_id')->constrained()->cascadeOnDelete();
$table->foreignId('voucher_agent_id')->nullable()->constrained()->nullOnDelete();
$table->foreignId('nas_package_profile_id')->constrained()->restrictOnDelete();
$table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
$table->string('source', 30)->default('dashboard');
$table->unsignedInteger('quantity');
$table->decimal('unit_price', 18, 2);
$table->decimal('discount_amount', 18, 2)->default(0);
$table->decimal('total_amount', 18, 2);
$table->string('payment_status', 30)->default('paid');
$table->string('status', 30)->default('completed');
$table->json('pricing_snapshot')->nullable();
$table->text('notes')->nullable();
$table->timestamps();
$table->index(['tenant_id', 'status', 'created_at']);
$table->index(['voucher_agent_id', 'payment_status']);
});
Schema::create('hotspot_vouchers', function (Blueprint $table) {
$table->id();
$table->uuid('uuid')->unique();
$table->foreignId('tenant_id')->constrained()->cascadeOnDelete();
$table->foreignId('voucher_sale_id')->constrained()->cascadeOnDelete();
$table->foreignId('nas_package_profile_id')->constrained()->restrictOnDelete();
$table->foreignId('nas_mikrotik_id')->nullable()->constrained()->nullOnDelete();
$table->string('username');
$table->text('password');
$table->string('status', 30)->default('generated');
$table->string('sync_status', 30)->default('pending');
$table->string('external_reference')->nullable();
$table->timestamp('valid_until')->nullable();
$table->timestamp('activated_at')->nullable();
$table->timestamp('used_at')->nullable();
$table->timestamp('synced_at')->nullable();
$table->text('sync_error')->nullable();
$table->json('profile_snapshot')->nullable();
$table->timestamps();
$table->unique(['tenant_id', 'username']);
$table->index(['tenant_id', 'status', 'created_at']);
$table->index(['nas_mikrotik_id', 'sync_status']);
});
Schema::create('voucher_login_page_settings', function (Blueprint $table) {
$table->id();
$table->uuid('uuid')->unique();
$table->foreignId('tenant_id')->unique()->constrained()->cascadeOnDelete();
$table->foreignId('payment_gateway_account_id')->nullable()->constrained()->nullOnDelete();
$table->string('public_key')->unique();
$table->boolean('enabled')->default(false);
$table->string('title')->default('Beli Voucher Hotspot');
$table->string('theme_color', 20)->default('#ff8c00');
$table->json('allowed_package_profile_ids')->nullable();
$table->json('settings')->nullable();
$table->timestamp('enabled_at')->nullable();
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('voucher_login_page_settings');
Schema::dropIfExists('hotspot_vouchers');
Schema::dropIfExists('voucher_sales');
Schema::dropIfExists('voucher_agents');
}
};
@@ -0,0 +1,56 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('wallets', function (Blueprint $table) {
$table->foreignId('tenant_id')->nullable()->after('uuid')->constrained()->cascadeOnDelete();
$table->dropUnique('wallet_owner_type_unique');
});
DB::table('wallets')->where('owner_type', 'App\\Models\\Tenant')->orderBy('id')->each(function ($wallet) {
DB::table('wallets')->where('id', $wallet->id)->update([
'tenant_id' => $wallet->owner_id,
'wallet_type' => 'tenant_settlement',
]);
});
DB::table('wallets')->where('owner_type', 'App\\Models\\User')->orderBy('id')->each(function ($wallet) {
$tenantId = DB::table('user_tenants')->where('user_id', $wallet->owner_id)
->orderByDesc('is_default')->orderBy('id')->value('tenant_id');
if ($tenantId) {
DB::table('wallets')->where('id', $wallet->id)->update([
'tenant_id' => $tenantId,
'wallet_type' => 'deposit',
]);
} elseif ((float) $wallet->available_balance === 0.0 && (float) $wallet->pending_balance === 0.0 && (float) $wallet->locked_balance === 0.0) {
DB::table('wallets')->where('id', $wallet->id)->delete();
}
});
Schema::table('wallets', function (Blueprint $table) {
$table->unique(['owner_type', 'owner_id', 'tenant_id', 'wallet_type', 'currency'], 'wallet_owner_tenant_type_unique');
$table->index(['tenant_id', 'wallet_type', 'status']);
});
}
public function down(): void
{
Schema::table('wallets', function (Blueprint $table) {
$table->dropUnique('wallet_owner_tenant_type_unique');
$table->dropIndex(['tenant_id', 'wallet_type', 'status']);
});
DB::table('wallets')->where('wallet_type', 'deposit')->update(['wallet_type' => 'user']);
DB::table('wallets')->where('wallet_type', 'tenant_settlement')->update(['wallet_type' => 'tenant']);
Schema::table('wallets', function (Blueprint $table) {
$table->dropConstrainedForeignId('tenant_id');
$table->unique(['owner_type', 'owner_id', 'wallet_type', 'currency'], 'wallet_owner_type_unique');
});
}
};
@@ -0,0 +1,61 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->boolean('is_platform_staff')->default(false)->after('is_master')->index();
});
Schema::create('role_applications', function (Blueprint $table) {
$table->id();
$table->uuid('uuid')->unique();
$table->foreignId('applicant_user_id')->constrained('users')->cascadeOnDelete();
$table->foreignId('tenant_id')->nullable()->constrained()->cascadeOnDelete();
$table->string('application_type', 20);
$table->string('status', 30)->default('pending');
$table->json('payload');
$table->foreignId('reviewed_by')->nullable()->constrained('users')->nullOnDelete();
$table->text('review_notes')->nullable();
$table->timestamp('submitted_at');
$table->timestamp('reviewed_at')->nullable();
$table->timestamps();
$table->index(['applicant_user_id', 'status', 'submitted_at']);
$table->index(['application_type', 'tenant_id', 'status']);
});
Schema::create('customer_user_links', function (Blueprint $table) {
$table->id();
$table->foreignId('tenant_id')->constrained()->cascadeOnDelete();
$table->foreignId('customer_id')->constrained()->cascadeOnDelete();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->foreignId('linked_by')->nullable()->constrained('users')->nullOnDelete();
$table->string('relationship', 30)->default('owner');
$table->boolean('is_primary')->default(true);
$table->timestamps();
$table->unique(['customer_id', 'user_id']);
$table->index(['user_id', 'tenant_id']);
});
DB::table('customers')->whereNotNull('user_id')->orderBy('id')->each(function ($customer) {
DB::table('customer_user_links')->insertOrIgnore([
'tenant_id' => $customer->tenant_id, 'customer_id' => $customer->id,
'user_id' => $customer->user_id, 'relationship' => 'owner', 'is_primary' => true,
'created_at' => now(), 'updated_at' => now(),
]);
});
}
public function down(): void
{
Schema::dropIfExists('customer_user_links');
Schema::dropIfExists('role_applications');
Schema::table('users', fn (Blueprint $table) => $table->dropColumn('is_platform_staff'));
}
};
@@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('notification_channels', function (Blueprint $table) {
$table->dropForeign(['tenant_id']);
});
Schema::table('notification_channels', function (Blueprint $table) {
$table->unsignedBigInteger('tenant_id')->nullable()->change();
$table->foreign('tenant_id')->references('id')->on('tenants')->cascadeOnDelete();
});
}
public function down(): void
{
DB::table('notification_channels')->whereNull('tenant_id')->delete();
Schema::table('notification_channels', function (Blueprint $table) {
$table->dropForeign(['tenant_id']);
});
Schema::table('notification_channels', function (Blueprint $table) {
$table->unsignedBigInteger('tenant_id')->nullable(false)->change();
$table->foreign('tenant_id')->references('id')->on('tenants')->cascadeOnDelete();
});
}
};
@@ -0,0 +1,48 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('user_tenants', function (Blueprint $table) {
$table->string('role', 30)->default('customer')->after('tenant_id');
$table->index(['tenant_id', 'role']);
});
DB::table('user_tenants')
->whereIn('user_id', DB::table('users')->where('access_level', 'staff')->select('id'))
->update(['role' => 'staff']);
$ownerUsers = DB::table('users')->where('access_level', 'tenant_owner')->pluck('id');
foreach ($ownerUsers as $userId) {
$ownerTenantId = DB::table('user_tenants')
->where('user_id', $userId)
->orderByDesc('is_default')
->orderBy('id')
->value('tenant_id');
if ($ownerTenantId) {
DB::table('user_tenants')
->where('user_id', $userId)
->where('tenant_id', $ownerTenantId)
->update(['role' => 'tenant_owner']);
}
}
DB::statement("CREATE UNIQUE INDEX user_tenants_one_owner_per_user ON user_tenants (user_id) WHERE role = 'tenant_owner'");
}
public function down(): void
{
DB::statement('DROP INDEX IF EXISTS user_tenants_one_owner_per_user');
Schema::table('user_tenants', function (Blueprint $table) {
$table->dropIndex(['tenant_id', 'role']);
$table->dropColumn('role');
});
}
};
@@ -0,0 +1,53 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('notification_messages', function (Blueprint $table) {
$table->foreignId('tenant_id')->nullable()->change();
});
Schema::table('user_notifications', function (Blueprint $table) {
$table->foreignId('tenant_id')->nullable()->change();
});
Schema::create('system_notification_campaigns', function (Blueprint $table) {
$table->id();
$table->uuid('uuid')->unique();
$table->foreignId('tenant_id')->nullable()->constrained()->cascadeOnDelete();
$table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
$table->string('title');
$table->text('body');
$table->string('action_url')->nullable();
$table->string('icon')->default('cil-bell');
$table->json('audience');
$table->string('status', 30)->default('queued');
$table->unsignedInteger('estimated_recipients')->default(0);
$table->unsignedInteger('processed_recipients')->default(0);
$table->timestamp('completed_at')->nullable();
$table->timestamps();
$table->index(['tenant_id', 'status', 'created_at']);
});
Schema::table('user_notifications', function (Blueprint $table) {
$table->foreignId('system_notification_campaign_id')->nullable()
->after('notification_message_id')->constrained()->cascadeOnDelete();
$table->unique(['system_notification_campaign_id', 'user_id'], 'user_notifications_campaign_user_unique');
});
}
public function down(): void
{
Schema::table('user_notifications', function (Blueprint $table) {
$table->dropUnique('user_notifications_campaign_user_unique');
$table->dropConstrainedForeignId('system_notification_campaign_id');
});
Schema::dropIfExists('system_notification_campaigns');
Schema::table('user_notifications', fn (Blueprint $table) => $table->foreignId('tenant_id')->nullable(false)->change());
Schema::table('notification_messages', fn (Blueprint $table) => $table->foreignId('tenant_id')->nullable(false)->change());
}
};