feat: Reimplement order and invoice management with new service and repository layers, introduce compression middleware, and update database schema.

This commit is contained in:
pbao9
2026-03-12 09:30:29 +07:00
parent 7f6264c87f
commit 1e09ccf17b
87 changed files with 2348 additions and 2612 deletions
@@ -18,13 +18,16 @@ return new class extends Migration {
$table->string('lastname', 255)->nullable();
$table->string('username', 100)->nullable();
$table->string('email', 100)->nullable();
$table->date('join_date')->nullable();
$table->date('birthday')->nullable();
$table->string('address')->nullable();
$table->string('phone', 20)->nullable();
$table->timestamp('email_verified_at')->nullable();
$table->string('password')->nullable();
$table->tinyInteger('status')->default(1);
$table->rememberToken();
$table->timestamps();
});
}
/**
@@ -1,43 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
//
Schema::create('domain',function (Blueprint $table){
$table->id()->autoIncrement();
$table->string('name',100)->nullable();
$table->integer('price')->nullable();
$table->integer('price_sale')->nullable();
$table->integer('renewal')->nullable();
$table->integer('transfer')->nullable();
$table->tinyInteger('auto_reg')->default(0);
$table->tinyInteger('type_id')->default(0)->index();
$table->tinyInteger('status')->default(1);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('domain',function (Blueprint $table){
$table->dropForeign('group_id');
$table->drop();
});
}
};
@@ -14,9 +14,16 @@ return new class extends Migration
public function up()
{
//
Schema::create('discount_customer',function (Blueprint $table) {
$table->bigInteger('discount_id')->default(0)->index();
$table->bigInteger('customer_id')->default(0)->index();
Schema::create('discount_customer', function (Blueprint $table) {
$table->foreignId('discount_id')
->constrained('discount')
->cascadeOnDelete();
$table->foreignId('customer_id')
->constrained('user')
->cascadeOnDelete();
$table->primary(['discount_id', 'customer_id']);
});
}
@@ -27,9 +34,6 @@ return new class extends Migration
*/
public function down()
{
Schema::table('discount_customer',function (Blueprint $table) {
$table->dropForeign(['discount_id','customer_id']);
$table->drop();
});
Schema::dropIfExists('discount_customer');
}
};
@@ -1,47 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
//
Schema::create('order', function (Blueprint $table) {
$table->id();
$table->string('order_num', 255)->unique()->nullable();
$table->bigInteger('customer_id')->default(0)->index();
$table->integer('date')->nullable();
$table->integer('user_id')->default(0);
$table->integer('discount_id')->default(0);
$table->integer('invoice_id')->default(0);
$table->integer('discount_value')->nullable();
$table->integer('amount')->nullable();
$table->text('note')->nullable();
$table->string('client_ip', 100)->nullable();
$table->tinyInteger('status')->default(0);
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
Schema::table('order', function (Blueprint $table) {
$table->dropForeign(['customer_id', 'discount_id']);
$table->drop();
});
}
};
@@ -1,51 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('invoice', function (Blueprint $table) {
$table->id();
$table->string('order_num', 255)->unique()->nullable();
$table->integer('date')->nullable();
$table->integer('due_date')->nullable();
$table->integer('date_paid')->nullable();
$table->integer('sub_total')->nullable();
$table->integer('tax')->nullable();
$table->integer('total')->nullable();
$table->bigInteger('customer_id')->default(0)->index();
$table->integer('order_id')->default(0)->index();
$table->text('note')->nullable();
$table->string('client_ip', 100)->nullable();
$table->string('vm_id')->nullable()->index();
$table->unsignedInteger('rebuild_count')->nullable()->default(0);
$table->tinyInteger('invoice_type')->default(1);
$table->integer('reminder_step')->default(3);
$table->tinyInteger('status')->default(0);
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('invoice', function (Blueprint $table) {
$table->dropForeign(['payment_id', 'customer_id']);
$table->drop();
});
}
};
@@ -1,33 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('domain_type',function (Blueprint $table) {
$table->id()->autoIncrement();
$table->string('name',255)->nullable();
$table->tinyInteger('status')->default(1);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('domain_type');
}
};
@@ -14,7 +14,7 @@ return new class extends Migration
public function up()
{
Schema::create('module_dns_server',function (Blueprint $table) {
$table->id()->autoIncrement();
$table->id();
$table->string('name',100)->default(0);
$table->string('user',100)->nullable();
$table->text('password')->nullable();
@@ -14,7 +14,7 @@ return new class extends Migration
public function up()
{
Schema::create('module_hosting_server',function (Blueprint $table) {
$table->id()->autoIncrement();
$table->id();
$table->string('name',100)->nullable();
$table->string('user',100)->nullable();
$table->string('apikey',100)->nullable();
@@ -14,7 +14,7 @@ return new class extends Migration
public function up()
{
Schema::create('module_hosting',function (Blueprint $table) {
$table->id()->autoIncrement();
$table->id();
$table->string('name',255)->nullable();
$table->bigInteger('order_id')->default(0)->index();
$table->integer('module_server_id')->default(0)->index();
@@ -14,7 +14,7 @@ return new class extends Migration
public function up()
{
Schema::create('module_vcenter',function (Blueprint $table) {
$table->id()->autoIncrement();
$table->id();
$table->string('host',100)->nullable();
$table->string('user',100)->nullable();
$table->text('password')->nullable();
@@ -13,7 +13,7 @@ return new class extends Migration {
public function up()
{
Schema::create('module_datacenter', function (Blueprint $table) {
$table->id()->autoIncrement();
$table->id();
$table->string('name', 255)->nullable();
$table->string('datacenter_id', 255)->nullable();
$table->foreignId('vcenter_id')->constrained('module_vcenter')->cascadeOnDelete()->nullable()->index();
@@ -14,7 +14,7 @@ return new class extends Migration
public function up()
{
Schema::create('module_folder',function (Blueprint $table) {
$table->id()->autoIncrement();
$table->id();
$table->string('name',255)->nullable();
$table->string('folder',255)->nullable();
$table->string('type',100)->nullable();
@@ -13,20 +13,30 @@ return new class extends Migration
*/
public function up()
{
Schema::create('module_ip_address',function (Blueprint $table) {
$table->id()->autoIncrement();
$table->string('vm_name',255)->nullable();
$table->unsignedBigInteger('module_network_id')->nullable();
$table->string('ip',100)->nullable();
$table->string('gateway',100)->nullable();
$table->string('netmask',100)->nullable();
$table->string('dns',100)->nullable();
$table->tinyInteger('status')->default(0)->comment('1: assign;0: free');
$table->timestamps();
$table->foreign('module_network_id', 'fk_module_ip_network')
->references('id')
->on('module_network')
Schema::create('module_ip_address', function (Blueprint $table) {
$table->id();
$table->string('vm_name')->nullable();
$table->foreignId('module_network_id')
->nullable()
->constrained('module_network')
->nullOnDelete();
$table->foreignId('module_host_id')
->nullable()
->constrained('module_host')
->nullOnDelete();
$table->string('ip')->nullable();
$table->string('gateway')->nullable();
$table->string('netmask')->nullable();
$table->string('dns')->nullable();
$table->tinyInteger('status')
->default(0)
->comment('1: assign; 0: free');
$table->timestamps();
});
}
@@ -14,7 +14,7 @@ return new class extends Migration
public function up()
{
Schema::create('module_snapshot_limit',function (Blueprint $table) {
$table->id()->autoIncrement();
$table->id();
$table->bigInteger('customer_id')->default(0)->index();
$table->integer('limit')->default(1);
$table->integer('used')->default(0);
@@ -13,23 +13,36 @@ return new class extends Migration
*/
public function up()
{
Schema::create('module_vmware',function (Blueprint $table) {
$table->id()->autoIncrement();
$table->string('name',255)->nullable();
$table->bigInteger('module_ip_address_id')->default(0)->index();
Schema::create('module_vmware', function (Blueprint $table) {
$table->id();
$table->string('name')->nullable();
$table->foreignId('module_ip_address')
->constrained('module_ip_address');
$table->foreignId('vcenter_id')
->constrained('module_vcenter');
$table->integer('port')->nullable();
$table->integer('order_id')->nullable();
$table->integer('first_payment')->nullable();
$table->integer('next_payment')->nullable();
$table->integer('next_due_date')->nullable();
$table->integer('next_invoice')->nullable();
$table->string('user',100)->nullable();
$table->string('user')->nullable();
$table->text('password')->nullable();
$table->string('hostname',100)->nullable();
$table->string('hostname')->nullable();
$table->string('vmware_id')->nullable();
$table->bigInteger('os_id')->default(0)->index();
$table->bigInteger('customer_id')->default(0)->index();
$table->tinyInteger('status')->default(1)->comment('1: Running;0:Off;2:Suspend');
$table->tinyInteger('status')
->default(1)
->comment('1: Running;0:Off;2:Suspend');
$table->timestamps();
});
}
@@ -14,7 +14,7 @@ return new class extends Migration
public function up()
{
Schema::create('module_snapshot', function (Blueprint $table) {
$table->id()->autoIncrement();
$table->id();
$table->string('name', 255)->nullable();
$table->bigInteger('customer_id')->default(0)->index();
$table->bigInteger('module_vmware_id')->default(0)->index();
@@ -1,42 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('order__order_item', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('order_id')->index();
$table->unsignedBigInteger('product_id')->nullable()->index();
$table->string('billing_cycle', 50)->nullable();
$table->integer('months')->default(0);
$table->unsignedBigInteger('os_id')->nullable()->index();
$table->string('server_name')->nullable();
$table->integer('quantity')->default(1);
$table->integer('price')->default(0);
$table->timestamps();
// Foreign Keys
$table->foreign('order_id')->references('id')->on('order')->onDelete('cascade');
$table->foreign('product_id')->references('id')->on('products')->onDelete('set null');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('order__order_item');
}
};
@@ -15,7 +15,7 @@ return new class extends Migration
{
//
Schema::create('staff_online',function (Blueprint $table) {
$table->id()->autoIncrement();
$table->id();
$table->string('sessions_id')->nullable();
$table->integer('user_id')->default(0)->index();
$table->integer('last_visited')->nullable();
@@ -1,41 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
//
Schema::create('invoice_item', function (Blueprint $table) {
$table->id()->autoIncrement();
$table->bigInteger('invoice_id')->default(0)->index();
$table->unsignedBigInteger('product_id')->nullable()->index();
$table->integer('months')->default(0);
$table->unsignedBigInteger('os_id')->nullable()->index();
$table->string('server_name')->nullable();
$table->integer('quantity')->default(1);
$table->tinyInteger('invoice_type')->default(1);
$table->integer('price')->default(0);
$table->string('product_type', 50)->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('invoice_item');
}
};
@@ -1,32 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('carts', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('product_id');
$table->unsignedBigInteger('customer_id');
$table->unsignedTinyInteger('type_product');
$table->integer('months')->default(0);
$table->timestamps();
$table->index(['customer_id', 'type_product', 'product_id']);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('carts');
}
};
@@ -1,34 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('order__order_addons', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('order_item_id')->index();
$table->unsignedBigInteger('addon_id')->index();
$table->unsignedInteger('qty')->default(1);
$table->unsignedInteger('price');
$table->timestamps();
// Foreign Keys
$table->foreign('order_item_id')->references('id')->on('order__order_item')->onDelete('cascade');
$table->foreign('addon_id')->references('id')->on('product_addon')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('order__order_addons');
}
};
@@ -1,30 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('invoice_addons', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('invoice_item_id')->index(); // FK đến order_items
$table->unsignedBigInteger('addon_id');
$table->unsignedInteger('qty')->default(1);
$table->unsignedInteger('price'); // đơn giá tại thời điểm mua
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('invoice_addons');
}
};
@@ -1,33 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('product_os', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('product_id')->index();
$table->integer('product_type')->nullable();
$table->unsignedBigInteger('os_id')->index();
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
$table->foreign('os_id')->references('id')->on('os')->onDelete('cascade');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('product_os');
}
};
@@ -1,29 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('carts', function (Blueprint $table) {
// Add single customer_id index for faster cart operations
$table->index('customer_id', 'carts_customer_id_index');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('carts', function (Blueprint $table) {
$table->dropIndex('carts_customer_id_index');
});
}
};
@@ -1,62 +0,0 @@
<?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
{
// 1. Thêm 3 cột tạm kiểu DATE
Schema::table('invoice', function (Blueprint $table) {
$table->date('date_tmp')->nullable()->after('date');
$table->date('due_date_tmp')->nullable()->after('due_date');
$table->date('date_paid_tmp')->nullable()->after('date_paid');
});
// 2. Chuyển giá trị từ INT → DATE
DB::statement("UPDATE invoice SET date_tmp = FROM_UNIXTIME(date) WHERE date IS NOT NULL");
DB::statement("UPDATE invoice SET due_date_tmp = FROM_UNIXTIME(due_date) WHERE due_date IS NOT NULL");
DB::statement("UPDATE invoice SET date_paid_tmp = FROM_UNIXTIME(date_paid) WHERE date_paid IS NOT NULL");
// 3. Xoá cột cũ
Schema::table('invoice', function (Blueprint $table) {
$table->dropColumn(['date', 'due_date', 'date_paid']);
});
// 4. Đổi tên cột tạm thành tên cũ
Schema::table('invoice', function (Blueprint $table) {
$table->renameColumn('date_tmp', 'date');
$table->renameColumn('due_date_tmp', 'due_date');
$table->renameColumn('date_paid_tmp', 'date_paid');
});
}
public function down(): void
{
// 1. Thêm 3 cột tạm kiểu INT
Schema::table('invoice', function (Blueprint $table) {
$table->integer('date_int')->nullable();
$table->integer('due_date_int')->nullable();
$table->integer('date_paid_int')->nullable();
});
// 2. Convert DATE → Unix timestamp
DB::statement("UPDATE invoice SET date_int = UNIX_TIMESTAMP(date) WHERE date IS NOT NULL");
DB::statement("UPDATE invoice SET due_date_int = UNIX_TIMESTAMP(due_date) WHERE due_date IS NOT NULL");
DB::statement("UPDATE invoice SET date_paid_int = UNIX_TIMESTAMP(date_paid) WHERE date_paid IS NOT NULL");
// 3. Xoá cột kiểu DATE
Schema::table('invoice', function (Blueprint $table) {
$table->dropColumn(['date', 'due_date', 'date_paid']);
});
// 4. Đổi tên lại
Schema::table('invoice', function (Blueprint $table) {
$table->renameColumn('date_int', 'date');
$table->renameColumn('due_date_int', 'due_date');
$table->renameColumn('date_paid_int', 'date_paid');
});
}
};
@@ -1,30 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('module_ip_address', function (Blueprint $table) {
$table->unsignedBigInteger('module_network_id')->nullable()->default(null)->change();
$table->foreign('module_network_id')->references('id')->on('module_network')->onDelete('set null');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('module_ip_address', function (Blueprint $table) {
$table->dropForeign(['module_network_id']);
$table->bigInteger('module_network_id')->default(0)->nullable(false)->change();
});
}
};
@@ -1,64 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
// 1. Modify columns to match referenced types (unsignedBigInteger) and make them nullable
Schema::table('order', function (Blueprint $table) {
$table->unsignedBigInteger('customer_id')->nullable()->default(null)->change();
$table->unsignedBigInteger('user_id')->nullable()->default(null)->change();
$table->unsignedBigInteger('discount_id')->nullable()->default(null)->change();
$table->unsignedBigInteger('invoice_id')->nullable()->default(null)->change();
});
// 2. Convert default 0 values to null to ensure foreign key integrity
DB::table('order')->where('customer_id', 0)->update(['customer_id' => null]);
DB::table('order')->where('user_id', 0)->update(['user_id' => null]);
DB::table('order')->where('discount_id', 0)->update(['discount_id' => null]);
DB::table('order')->where('invoice_id', 0)->update(['invoice_id' => null]);
// 3. Add foreign key constraints
Schema::table('order', function (Blueprint $table) {
$table->foreign('customer_id')->references('id')->on('customers')->onDelete('set null');
$table->foreign('user_id')->references('id')->on('user')->onDelete('set null');
$table->foreign('discount_id')->references('id')->on('discount')->onDelete('set null');
$table->foreign('invoice_id')->references('id')->on('invoice')->onDelete('set null');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('order', function (Blueprint $table) {
// Drop foreign keys
$table->dropForeign(['customer_id']);
$table->dropForeign(['user_id']);
$table->dropForeign(['discount_id']);
$table->dropForeign(['invoice_id']);
// Revert columns to previous state (integers/bigInteger with default 0)
// Note: This matches the original migration definitions
$table->bigInteger('customer_id')->default(0)->nullable(false)->change();
$table->integer('user_id')->default(0)->nullable(false)->change();
$table->integer('discount_id')->default(0)->nullable(false)->change();
$table->integer('invoice_id')->default(0)->nullable(false)->change();
});
// Restore 0 values where null (optional, but keeps consistency with down())
DB::table('order')->whereNull('customer_id')->update(['customer_id' => 0]);
DB::table('order')->whereNull('user_id')->update(['user_id' => 0]);
DB::table('order')->whereNull('discount_id')->update(['discount_id' => 0]);
DB::table('order')->whereNull('invoice_id')->update(['invoice_id' => 0]);
}
};
@@ -26,6 +26,9 @@ return new class extends Migration {
$table->boolean('is_system')->default(false); // vCLS, system VM
$table->timestamp('last_synced_at')->nullable();
$table->foreignId('datacenter_id')->constrained('module_datacenter')->nullable();
$table->foreignId('host_id')->nullable()->constrained('module_host');
$table->timestamps();
});
}
@@ -1,37 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('module_host', function (Blueprint $table) {
$table->unsignedBigInteger('module_datacenter_id')->nullable()->change();
$table->foreign('module_datacenter_id')
->references('id')
->on('module_datacenter')
->cascadeOnDelete();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('module_host', function (Blueprint $table) {
// Drop the foreign key first
$table->dropForeign(['module_datacenter_id']);
// Revert column type (assuming it was bigInteger with default 0 based on previous context)
$table->bigInteger('module_datacenter_id')->default(0)->change();
});
}
};
@@ -1,33 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('module_datacenter', function (Blueprint $table) {
//
$table->unsignedBigInteger('vcenter_id')->nullable()->change();
$table->foreign('vcenter_id')
->references('id')
->on('module_vcenter')
->cascadeOnDelete();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('module_datacenter', function (Blueprint $table) {
//
});
}
};
@@ -1,48 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('module_folder', function (Blueprint $table) {
$table->unsignedBigInteger('module_datacenter_id')->nullable()->change();
});
// Clean up orphan records that point to non-existent datacenters
DB::table('module_folder')
->whereNotNull('module_datacenter_id')
->whereNotExists(function ($query) {
$query->select(DB::raw(1))
->from('module_datacenter')
->whereColumn('module_folder.module_datacenter_id', 'module_datacenter.id');
})
->update(['module_datacenter_id' => null]);
Schema::table('module_folder', function (Blueprint $table) {
$table->foreign('module_datacenter_id')
->references('id')
->on('module_datacenter')
->cascadeOnDelete();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('module_folder', function (Blueprint $table) {
$table->dropForeign(['module_datacenter_id']);
// Revert changes if necessary, though restoring invalid data isn't possible.
// We just restore the foreign key constraint if that was the intent.
$table->foreign('module_datacenter_id')->references('id')->on('module_datacenter')->onDelete('cascade');
});
}
};
@@ -1,60 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
// Add support for new Product system to carts table
Schema::table('carts', function (Blueprint $table) {
if (!Schema::hasColumn('carts', 'billing_cycle')) {
$table->string('billing_cycle', 50)->nullable()->after('months')->comment('Billing cycle: monthly, semi_annually, annually, etc.');
}
if (!Schema::hasColumn('carts', 'product_pricing_id')) {
$table->unsignedBigInteger('product_pricing_id')->nullable()->after('billing_cycle')->comment('Link to product_pricings table');
$table->index('product_pricing_id');
}
// Make type_product nullable for new Product system
$table->integer('type_product')->nullable()->change();
});
// Add support for new Product system to order__order_item table
Schema::table('order__order_item', function (Blueprint $table) {
if (!Schema::hasColumn('order__order_item', 'billing_cycle')) {
$table->string('billing_cycle', 50)->nullable()->after('months')->comment('Billing cycle: monthly, semi_annually, annually, etc.');
}
if (!Schema::hasColumn('order__order_item', 'product_pricing_id')) {
$table->unsignedBigInteger('product_pricing_id')->nullable()->after('billing_cycle')->comment('Link to product_pricings table');
$table->index('product_pricing_id');
}
// Make product_type nullable for new Product system
if (Schema::hasColumn('order__order_item', 'product_type')) {
$table->string('product_type', 50)->nullable()->change();
}
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('carts', function (Blueprint $table) {
$table->dropColumn(['billing_cycle', 'product_pricing_id']);
// $table->dropIndex(['product_pricing_id']);
});
Schema::table('order__order_item', function (Blueprint $table) {
$table->dropColumn(['billing_cycle', 'product_pricing_id']);
// $table->dropIndex(['product_pricing_id']);
});
}
};
@@ -1,29 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('virtual_machines', function (Blueprint $table) {
$table->foreignId('host_id')->nullable()->after('datacenter_id')->constrained('module_host');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('virtual_machines', function (Blueprint $table) {
$table->dropForeign(['host_id']);
$table->dropColumn('host_id');
});
}
};
@@ -1,45 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
public function up()
{
// Schema::table('customers', function (Blueprint $table) {
// $table->softDeletes();
// });
// Schema::table('invoice', function (Blueprint $table) {
// $table->softDeletes();
// });
// Schema::table('order', function (Blueprint $table) {
// $table->softDeletes();
// });
// Schema::table('transaction', function (Blueprint $table) {
// $table->softDeletes();
// });
}
public function down()
{
Schema::table('customers', function (Blueprint $table) {
$table->dropSoftDeletes();
});
Schema::table('invoice', function (Blueprint $table) {
$table->dropSoftDeletes();
});
Schema::table('order', function (Blueprint $table) {
$table->dropSoftDeletes();
});
Schema::table('transaction', function (Blueprint $table) {
$table->dropSoftDeletes();
});
}
};
@@ -1,21 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
public function up()
{
// Schema::table('transaction', function (Blueprint $table) {
// $table->softDeletes();
// });
}
public function down()
{
Schema::table('transaction', function (Blueprint $table) {
$table->dropSoftDeletes();
});
}
};
@@ -1,28 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('product_os', function (Blueprint $table) {
$table->dropColumn('product_type');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('product_os', function (Blueprint $table) {
//
});
}
};
@@ -1,27 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('module_vmware', function (Blueprint $table) {
$table->unsignedBigInteger('vcenter_id')->nullable()->after('module_ip_address_id');
$table->foreign('vcenter_id')->references('id')->on('module_vcenter')->nullOnDelete();
});
}
public function down(): void
{
Schema::table('module_vmware', function (Blueprint $table) {
$table->dropForeign(['vcenter_id']);
$table->dropColumn('vcenter_id');
});
}
};
@@ -1,25 +0,0 @@
<?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
{
if (!Schema::hasColumn('invoice', 'auto_renew')) {
Schema::table('invoice', function (Blueprint $table) {
$table->boolean('auto_renew')->default(false)->after('status');
});
}
}
public function down(): void
{
if (Schema::hasColumn('invoice', 'auto_renew')) {
Schema::table('invoice', function (Blueprint $table) {
$table->dropColumn('auto_renew');
});
}
}
};
@@ -1,28 +0,0 @@
<?php
use App\Enums\Invoice\InvoiceStep;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('invoice', function (Blueprint $table) {
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('invoice', function (Blueprint $table) {
//
});
}
};
@@ -1,32 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('module_ip_address', function (Blueprint $table) {
$table->unsignedBigInteger('module_host_id')->nullable()->after('module_network_id');
$table->foreign('module_host_id', 'fk_module_ip_host')
->references('id')
->on('module_host')
->nullOnDelete();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('module_ip_address', function (Blueprint $table) {
//
});
}
};
@@ -1,24 +0,0 @@
<?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('user', function (Blueprint $table) {
$table->date('birthday')->nullable()->after('email');
$table->string('address')->nullable()->after('birthday');
$table->string('phone', 20)->nullable()->after('address');
});
}
public function down(): void
{
Schema::table('user', function (Blueprint $table) {
$table->dropColumn(['birthday', 'address', 'phone']);
});
}
};
@@ -1,31 +0,0 @@
<?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('invoice', function (Blueprint $table) {
$table->string('payment_method')->nullable()->after('status');
});
Schema::table('order', function (Blueprint $table) {
if (!Schema::hasColumn('order', 'payment_method')) {
$table->string('payment_method')->nullable()->after('status');
}
});
}
public function down(): void
{
Schema::table('invoice', function (Blueprint $table) {
$table->dropColumn('payment_method');
});
Schema::table('order', function (Blueprint $table) {
$table->dropColumn('payment_method');
});
}
};
@@ -1,21 +0,0 @@
<?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('order', function (Blueprint $table) {
$table->string('payment_proof')->nullable()->after('payment_method');
});
}
public function down(): void
{
Schema::table('order', function (Blueprint $table) {
$table->dropColumn('payment_proof');
});
}
};
@@ -1,24 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::rename('order__order_item', 'order_items');
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::rename('order_items', 'order__order_item');
}
};
@@ -1,28 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('order_items', function (Blueprint $table) {
$table->timestamp('expiry_date')->nullable()->after('months');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('order_items', function (Blueprint $table) {
$table->dropColumn('expiry_date');
});
}
};
@@ -0,0 +1,46 @@
<?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('orders', function (Blueprint $table) {
$table->id();
$table->string('order_num', 50)->unique()->comment('Human-readable order number e.g. ORD-20260311-00001');
$table->unsignedBigInteger('customer_id')->nullable()->index();
$table->unsignedBigInteger('user_id')->nullable()->index()->comment('Staff who created or processed the order');
$table->unsignedBigInteger('discount_id')->nullable()->index();
$table->unsignedBigInteger('sub_total')->default(0)->comment('Total before discount, in VND');
$table->unsignedBigInteger('discount_amount')->default(0);
$table->unsignedBigInteger('total')->default(0)->comment('Final amount due, in VND');
// 0=pending, 1=completed, 2=cancelled, 3=processing
$table->tinyInteger('status')->default(0)->index();
$table->string('payment_method', 100)->nullable();
$table->string('payment_proof')->nullable()->comment('Path to uploaded bank-transfer proof image');
$table->text('note')->nullable();
$table->string('client_ip', 45)->nullable();
$table->timestamps();
$table->softDeletes();
$table->foreign('customer_id')->references('id')->on('customers')->onDelete('set null');
$table->foreign('user_id')->references('id')->on('user')->onDelete('set null');
$table->foreign('discount_id')->references('id')->on('discount')->onDelete('set null');
});
}
public function down(): void
{
Schema::dropIfExists('orders');
}
};
@@ -0,0 +1,46 @@
<?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('order_items', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('order_id')->index();
$table->unsignedBigInteger('product_id')->nullable()->index();
$table->unsignedBigInteger('product_pricing_id')->nullable()->index()
->comment('Snapshot of product_pricings row at purchase time');
$table->unsignedBigInteger('os_id')->nullable()->index()
->comment('Selected OS for VPS orders');
$table->string('server_name', 255)->nullable()
->comment('Desired hostname entered by customer');
$table->string('billing_cycle', 30)->nullable()
->comment('monthly | quarterly | semi_annually | annually');
$table->unsignedSmallInteger('months')->default(0);
$table->unsignedInteger('quantity')->default(1);
$table->unsignedBigInteger('price')->default(0)
->comment('Unit price at time of order, in VND');
$table->json('addons_meta')->nullable()
->comment('Stores addon selections: [{addon_id, qty, price},...] — preserved until service provisioning');
$table->timestamps();
$table->foreign('order_id')->references('id')->on('orders')->onDelete('cascade');
$table->foreign('product_id')->references('id')->on('products')->onDelete('set null');
});
}
public function down(): void
{
Schema::dropIfExists('order_items');
}
};
@@ -0,0 +1,68 @@
<?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('invoices', function (Blueprint $table) {
$table->id();
$table->string('invoice_number', 50)->unique()
->comment('Human-readable e.g. INV-20260311-00001');
$table->unsignedBigInteger('customer_id')->index();
$table->unsignedBigInteger('order_id')->nullable()->index()
->comment('Originating order; null for manual/renewal invoices');
/**
* invoice_type:
* 1 = new service
* 2 = renewal
* 3 = upgrade / addon purchase
*/
$table->tinyInteger('invoice_type')->default(1)->index();
$table->unsignedBigInteger('sub_total')->default(0);
$table->unsignedBigInteger('discount_amount')->default(0);
$table->unsignedBigInteger('tax')->default(0);
$table->unsignedBigInteger('total')->default(0)->comment('Amount the customer must pay, in VND');
/**
* status:
* 1 = unpaid
* 2 = paid
* 3 = cancelled
* 4 = overdue
* 5 = refunded
*/
$table->tinyInteger('status')->default(1)->index();
$table->string('payment_method', 100)->nullable();
$table->boolean('auto_renew')->default(false);
$table->date('due_date')->nullable();
$table->timestamp('paid_at')->nullable();
$table->text('note')->nullable();
$table->string('client_ip', 45)->nullable();
$table->unsignedInteger('reminder_step')->default(0)
->comment('How many overdue reminders have been sent');
$table->timestamps();
$table->softDeletes();
$table->foreign('customer_id')->references('id')->on('customers')->onDelete('cascade');
$table->foreign('order_id')->references('id')->on('orders')->onDelete('set null');
});
}
public function down(): void
{
Schema::dropIfExists('invoices');
}
};
@@ -0,0 +1,46 @@
<?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('invoice_items', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('invoice_id')->index();
$table->unsignedBigInteger('product_id')->nullable()->index();
/**
* type:
* service — new or renewed service line
* addon — additional resource (extra IP, backup, etc.)
* upgrade — resource upgrade on existing service
*/
$table->string('type', 20)->default('service')->index()
->comment('service | addon | upgrade');
$table->string('description', 500)->nullable()
->comment('Human-readable line item label shown on invoice PDF');
$table->unsignedSmallInteger('months')->default(0);
$table->unsignedInteger('quantity')->default(1);
$table->unsignedBigInteger('unit_price')->default(0)->comment('Per-unit price, in VND');
$table->unsignedBigInteger('total_price')->default(0)->comment('unit_price × quantity');
$table->timestamps();
$table->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade');
$table->foreign('product_id')->references('id')->on('products')->onDelete('set null');
});
}
public function down(): void
{
Schema::dropIfExists('invoice_items');
}
};
@@ -0,0 +1,61 @@
<?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('services', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('customer_id')->index();
$table->unsignedBigInteger('product_id')->nullable()->index();
$table->unsignedBigInteger('order_item_id')->nullable()->index()
->comment('The specific order line that provisioned this service');
$table->unsignedBigInteger('invoice_id')->nullable()->index()
->comment('Most recent invoice that covers this service (renewal updates this)');
$table->string('vm_id')->nullable()->index()
->comment('VMware vCenter VM identifier (VPS only)');
$table->string('server_name', 255)->nullable()
->comment('Assigned hostname / domain');
/**
* status lifecycle:
* pending → awaiting provisioning after payment
* active → running normally
* suspended → overdue / policy violation
* expired → past expires_at, grace period ended
* cancelled → customer cancelled
* terminated → data wiped, permanent
*/
$table->string('status', 20)->default('pending')->index();
$table->boolean('auto_renew')->default(false);
$table->timestamp('started_at')->nullable();
$table->timestamp('expires_at')->nullable()->index();
$table->timestamp('suspended_at')->nullable();
$table->timestamp('cancelled_at')->nullable();
$table->text('note')->nullable();
$table->timestamps();
$table->softDeletes();
$table->foreign('customer_id')->references('id')->on('customers')->onDelete('cascade');
$table->foreign('product_id')->references('id')->on('products')->onDelete('set null');
$table->foreign('order_item_id')->references('id')->on('order_items')->onDelete('set null');
$table->foreign('invoice_id')->references('id')->on('invoices')->onDelete('set null');
});
}
public function down(): void
{
Schema::dropIfExists('services');
}
};
@@ -0,0 +1,45 @@
<?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('service_addons', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('service_id')->index();
/**
* VPS addon_types : cpu | ram | disk | bandwidth | ip
* Hosting addon_types: panel | backup | ssl | email_account
*
* addon_value stores the raw value as a string:
* cpu → "4" (vCPU count)
* ram → "8192" (MB)
* disk → "100" (GB)
* panel → "cpanel" | "directadmin" | "plesk"
* ssl → "1" (boolean flag)
*/
$table->string('addon_type', 50)->index()
->comment('cpu | ram | disk | bandwidth | ip | panel | backup | ssl');
$table->string('addon_value', 255)
->comment('Raw value: "4" for cpu, "8192" for ram MB, "cpanel" for panel');
$table->unsignedBigInteger('price')->default(0)
->comment('Monthly price of this addon at time of provisioning, in VND');
$table->timestamps();
$table->foreign('service_id')->references('id')->on('services')->onDelete('cascade');
});
}
public function down(): void
{
Schema::dropIfExists('service_addons');
}
};
@@ -10,16 +10,18 @@ return new class extends Migration
{
Schema::create('invoice_attachments', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('invoice_id')->index();
$table->string('filename'); // tên file gốc
$table->string('path'); // đường dẫn lưu trữ (storage)
$table->string('disk')->default('public');
$table->string('filename')->comment('Original uploaded filename');
$table->string('path')->comment('Storage path relative to disk root');
$table->string('disk', 50)->default('public');
$table->string('mime_type', 100)->nullable();
$table->unsignedBigInteger('size')->default(0); // bytes
$table->string('uploaded_by')->nullable(); // staff username/id
$table->unsignedBigInteger('size')->default(0)->comment('File size in bytes');
$table->string('uploaded_by', 100)->nullable()->comment('Staff username or ID');
$table->timestamps();
$table->foreign('invoice_id')->references('id')->on('invoice')->onDelete('cascade');
$table->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade');
});
}
+1 -7
View File
@@ -15,20 +15,14 @@ class DatabaseSeeder extends Seeder
*/
public function run(): void
{
$this->call(DomainTypeSeeder::class);
$this->call(GroupSeeder::class);
$this->call(Payment::class);
$this->call(AddonSeeder::class);
$this->call(BankTransferPaymentSeeder::class);
$this->call(RoleSeeder::class);
$this->call(RolesAndPermissions::class);
$user = User::find(1);
$user->assignRole('Full Administrator');
$this->call(SnapshotLimitedSeeder::class);
$this->call(TemplateSeeder::class);
$this->call(Setting::class);
$this->call(MenuSeeder::class);
$this->call(ControlPanelSeeder::class);
$this->call(VcenterSeeder::class);
$this->call(VPSProductSeeder::class);
}
}