Bagian 2 dari seri

Membuat Struktur Database Sistem Kasir Laravel

Diterbitkan 15 September 2026

Bagian ini membuat seluruh tabel bisnis. Buat model beserta migration:

php artisan make:model Category -m
php artisan make:model Unit -m
php artisan make:model Product -m
php artisan make:model Customer -m
php artisan make:model Supplier -m
php artisan make:model Purchase -m
php artisan make:model PurchaseDetail -m
php artisan make:model Sale -m
php artisan make:model SaleDetail -m
php artisan make:model StockMovement -m
php artisan make:model Setting -m

Tabel master

Schema::create('categories', function (Blueprint $table) {
    $table->id();
    $table->string('name')->unique();
    $table->timestamps();
});

Schema::create('units', function (Blueprint $table) {
    $table->id();
    $table->string('name')->unique();
    $table->string('symbol', 20);
    $table->timestamps();
});

Schema::create('products', function (Blueprint $table) {
    $table->id();
    $table->foreignId('category_id')->nullable()->constrained()->nullOnDelete();
    $table->foreignId('unit_id')->nullable()->constrained()->nullOnDelete();
    $table->string('sku', 50)->unique();
    $table->string('name');
    $table->decimal('purchase_price', 15, 2)->default(0);
    $table->decimal('selling_price', 15, 2)->default(0);
    $table->integer('stock')->default(0);
    $table->integer('minimum_stock')->default(0);
    $table->boolean('is_active')->default(true);
    $table->timestamps();
});

Schema::create('customers', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('phone', 30)->nullable();
    $table->text('address')->nullable();
    $table->timestamps();
});

Schema::create('suppliers', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('phone', 30)->nullable();
    $table->text('address')->nullable();
    $table->timestamps();
});

Tabel transaksi

Schema::create('sales', function (Blueprint $table) {
    $table->id();
    $table->string('invoice_number')->unique();
    $table->foreignId('user_id')->constrained()->restrictOnDelete();
    $table->foreignId('customer_id')->nullable()->constrained()->nullOnDelete();
    $table->timestamp('sale_date');
    $table->decimal('subtotal', 15, 2);
    $table->decimal('discount', 15, 2)->default(0);
    $table->decimal('grand_total', 15, 2);
    $table->decimal('paid_amount', 15, 2);
    $table->decimal('change_amount', 15, 2);
    $table->string('status', 20)->default('paid');
    $table->text('notes')->nullable();
    $table->timestamps();
});

Schema::create('sale_details', function (Blueprint $table) {
    $table->id();
    $table->foreignId('sale_id')->constrained()->cascadeOnDelete();
    $table->foreignId('product_id')->constrained()->restrictOnDelete();
    $table->integer('quantity');
    $table->decimal('price', 15, 2);
    $table->decimal('discount', 15, 2)->default(0);
    $table->decimal('subtotal', 15, 2);
    $table->timestamps();
});

Schema::create('purchases', function (Blueprint $table) {
    $table->id();
    $table->string('invoice_number')->unique();
    $table->foreignId('supplier_id')->nullable()->constrained()->nullOnDelete();
    $table->foreignId('user_id')->constrained()->restrictOnDelete();
    $table->timestamp('purchase_date');
    $table->decimal('grand_total', 15, 2);
    $table->string('status', 20)->default('received');
    $table->timestamps();
});

Schema::create('purchase_details', function (Blueprint $table) {
    $table->id();
    $table->foreignId('purchase_id')->constrained()->cascadeOnDelete();
    $table->foreignId('product_id')->constrained()->restrictOnDelete();
    $table->integer('quantity');
    $table->decimal('price', 15, 2);
    $table->decimal('subtotal', 15, 2);
    $table->timestamps();
});

Riwayat stok dan pengaturan

Schema::create('stock_movements', function (Blueprint $table) {
    $table->id();
    $table->foreignId('product_id')->constrained()->restrictOnDelete();
    $table->string('type', 20);
    $table->integer('quantity_in')->default(0);
    $table->integer('quantity_out')->default(0);
    $table->string('reference_type')->nullable();
    $table->unsignedBigInteger('reference_id')->nullable();
    $table->text('notes')->nullable();
    $table->timestamps();
});

Schema::create('settings', function (Blueprint $table) {
    $table->id();
    $table->string('key')->unique();
    $table->text('value')->nullable();
    $table->timestamps();
});

Pastikan urutan migration menempatkan tabel master sebelum tabel yang mempunyai foreign key. Kemudian jalankan:

php artisan migrate
php artisan migrate:status

Lanjut: Model, Relasi, dan Data Awal