Bagian 3 dari seri

Model, Relasi, dan Seeder Sistem Kasir Laravel

Diterbitkan 15 September 2026

Model produk

class Product extends Model
{
    protected $fillable = ['category_id', 'unit_id', 'sku', 'name', 'purchase_price', 'selling_price', 'stock', 'minimum_stock', 'is_active'];

    protected function casts(): array
    {
        return ['purchase_price' => 'decimal:2', 'selling_price' => 'decimal:2', 'is_active' => 'boolean'];
    }

    public function category() { return $this->belongsTo(Category::class); }
    public function unit() { return $this->belongsTo(Unit::class); }
    public function saleDetails() { return $this->hasMany(SaleDetail::class); }
    public function stockMovements() { return $this->hasMany(StockMovement::class); }
}

Model penjualan

class Sale extends Model
{
    protected $fillable = ['invoice_number', 'user_id', 'customer_id', 'sale_date', 'subtotal', 'discount', 'grand_total', 'paid_amount', 'change_amount', 'status', 'notes'];
    protected function casts(): array { return ['sale_date' => 'datetime']; }
    public function user() { return $this->belongsTo(User::class); }
    public function customer() { return $this->belongsTo(Customer::class); }
    public function details() { return $this->hasMany(SaleDetail::class); }
}

class SaleDetail extends Model
{
    protected $fillable = ['product_id', 'quantity', 'price', 'discount', 'subtotal'];
    public function sale() { return $this->belongsTo(Sale::class); }
    public function product() { return $this->belongsTo(Product::class); }
}

Model pembelian, pemasok, pelanggan, dan stok

Isi setiap file berikut secara lengkap. Semua file diawali <?php, namespace App\\Models, serta import Illuminate\\Database\\Eloquent\\Model.

app/Models/Purchase.php:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Purchase extends Model
{
    protected $fillable = ['invoice_number','supplier_id','user_id','purchase_date','grand_total','status'];
    protected function casts(): array { return ['purchase_date'=>'datetime','grand_total'=>'decimal:2']; }
    public function supplier() { return $this->belongsTo(Supplier::class); }
    public function user() { return $this->belongsTo(User::class); }
    public function details() { return $this->hasMany(PurchaseDetail::class); }
}

app/Models/PurchaseDetail.php:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class PurchaseDetail extends Model
{
    protected $fillable = ['product_id','quantity','price','subtotal'];
    protected function casts(): array { return ['price'=>'decimal:2','subtotal'=>'decimal:2']; }
    public function purchase() { return $this->belongsTo(Purchase::class); }
    public function product() { return $this->belongsTo(Product::class); }
}

app/Models/Supplier.php:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Supplier extends Model
{
    protected $fillable = ['name','phone','address'];
    public function purchases() { return $this->hasMany(Purchase::class); }
}

app/Models/Customer.php:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Customer extends Model
{
    protected $fillable = ['name','phone','address'];
    public function sales() { return $this->hasMany(Sale::class); }
}

app/Models/StockMovement.php:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class StockMovement extends Model
{
    protected $fillable = ['type','quantity_in','quantity_out','reference_type','reference_id','notes'];
    public function product() { return $this->belongsTo(Product::class); }
}

app/Models/Category.php dan app/Models/Unit.php:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
    protected $fillable = ['name'];
    public function products() { return $this->hasMany(Product::class); }
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Unit extends Model
{
    protected $fillable = ['name','symbol'];
    public function products() { return $this->hasMany(Product::class); }
}

Seeder

php artisan make:seeder KasirSeeder
public function run(): void
{
    $category = Category::firstOrCreate(['name' => 'Minuman']);
    $unit = Unit::firstOrCreate(['name' => 'Pieces'], ['symbol' => 'pcs']);

    Product::firstOrCreate(['sku' => 'BRG-001'], [
        'category_id' => $category->id,
        'unit_id' => $unit->id,
        'name' => 'Air Mineral',
        'purchase_price' => 2500,
        'selling_price' => 4000,
        'stock' => 20,
        'minimum_stock' => 5,
        'is_active' => true,
    ]);

    User::updateOrCreate(['email' => 'admin@example.com'], [
        'name' => 'Administrator', 'password' => Hash::make('admin12345'),
        'role' => 'admin', 'is_active' => true,
    ]);
}

Daftarkan pada DatabaseSeeder, lalu jalankan:

$this->call(KasirSeeder::class);
php artisan db:seed

Periksa data melalui halaman database dan pastikan relasi produk, kategori, serta satuan benar.

Lanjut: CRUD Master Data