mari kita implementasikan CRUD untuk Produk
// app\Http\Controllers\Inventory\ProductController.php
<?php
namespace App\Http\Controllers\Inventory;
use App\Http\Controllers\Controller;
use App\Models\Product;
use App\Models\Category;
use App\Models\Stock;
use Illuminate\Http\Request;
class ProductController extends Controller
{
public function index()
{
$products = Product::with(['category', 'stock'])->latest()->paginate(10);
return view('inventory.products.index', compact('products'));
}
public function create()
{
$categories = Category::all();
return view('inventory.products.create', compact('categories'));
}
public function store(Request $request)
{
$request->validate([
'name' => 'required|string|max:255',
'code' => 'required|string|unique:products',
'description' => 'nullable|string',
'price' => 'required|numeric|min:0',
'category_id' => 'required|exists:categories,id',
'initial_stock' => 'required|integer|min:0',
'minimum_stock' => 'required|integer|min:0'
]);
$product = Product::create([
'name' => $request->name,
'code' => $request->code,
'description' => $request->description,
'price' => $request->price,
'category_id' => $request->category_id
]);
// Buat stok awal
Stock::create([
'product_id' => $product->id,
'quantity' => $request->initial_stock,
'minimum_stock' => $request->minimum_stock
]);
return redirect()->route('products.index')
->with('success', 'Produk berhasil ditambahkan');
}
public function edit(Product $product)
{
$categories = Category::all();
return view('inventory.products.edit', compact('product', 'categories'));
}
public function update(Request $request, Product $product)
{
$request->validate([
'name' => 'required|string|max:255',
'code' => 'required|string|unique:products,code,' . $product->id,
'description' => 'nullable|string',
'price' => 'required|numeric|min:0',
'category_id' => 'required|exists:categories,id',
'minimum_stock' => 'required|integer|min:0'
]);
$product->update($request->except('minimum_stock'));
// Update minimum stock
$product->stock->update([
'minimum_stock' => $request->minimum_stock
]);
return redirect()->route('products.index')
->with('success', 'Produk berhasil diperbarui');
}
public function destroy(Product $product)
{
$product->delete();
return redirect()->route('products.index')
->with('success', 'Produk berhasil dihapus');
}
}
// routes\web.php
<?php
use App\Http\Controllers\Dashboard\DashboardController;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return redirect()->route('dashboard');
});
Route::middleware(['auth'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
// Tambahkan route untuk kategori
Route::resource('categories', \App\Http\Controllers\Inventory\CategoryController::class);
Route::resource('products', \App\Http\Controllers\Inventory\ProductController::class);
});
// resources\views\inventory\products\index.blade.php
<x-app-layout>
<x-slot name="header">
<div class="flex justify-between">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Produk') }}
</h2>
<a href="{{ route('products.create') }}" class="bg-blue-500 hover:bg-blue-700 text-black font-bold py-2 px-4 rounded">
Tambah Produk
</a>
</div>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg p-6">
@if(session('success'))
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative mb-4">
{{ session('success') }}
</div>
@endif
<table class="min-w-full divide-y divide-gray-200">
<thead>
<tr>
<th class="px-6 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Kode</th>
<th class="px-6 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Nama</th>
<th class="px-6 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Kategori</th>
<th class="px-6 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Harga</th>
<th class="px-6 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Stok</th>
<th class="px-6 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Aksi</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
@foreach($products as $product)
<tr>
<td class="px-6 py-4 whitespace-nowrap">{{ $product->code }}</td>
<td class="px-6 py-4 whitespace-nowrap">{{ $product->name }}</td>
<td class="px-6 py-4 whitespace-nowrap">{{ $product->category->name }}</td>
<td class="px-6 py-4 whitespace-nowrap">Rp {{ number_format($product->price, 0, ',', '.') }}</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full {{ $product->stock->quantity <= $product->stock->minimum_stock ? 'bg-red-100 text-red-800' : 'bg-green-100 text-green-800' }}">
{{ $product->stock->quantity }}
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
<a href="{{ route('products.edit', $product) }}" class="text-indigo-600 hover:text-indigo-900 mr-3">Edit</a>
<form action="{{ route('products.destroy', $product) }}" method="POST" class="inline">
@csrf
@method('DELETE')
<button type="submit" class="text-red-600 hover:text-red-900" onclick="return confirm('Apakah Anda yakin?')">
Hapus
</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
<div class="mt-4">
{{ $products->links() }}
</div>
</div>
</div>
</div>
</x-app-layout>
// resources\views\inventory\products\create.blade.php
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Tambah Produk') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg p-6">
<form action="{{ route('products.store') }}" method="POST">
@csrf
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="mb-4">
<label for="code" class="block text-gray-700 text-sm font-bold mb-2">Kode Produk</label>
<input type="text" name="code" id="code" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" required>
</div>
<div class="mb-4">
<label for="name" class="block text-gray-700 text-sm font-bold mb-2">Nama Produk</label>
<input type="text" name="name" id="name" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" required>
</div>
<div class="mb-4">
<label for="category_id" class="block text-gray-700 text-sm font-bold mb-2">Kategori</label>
<select name="category_id" id="category_id" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" required>
<option value="">Pilih Kategori</option>
@foreach($categories as $category)
<option value="{{ $category->id }}">{{ $category->name }}</option>
@endforeach
</select>
</div>
<div class="mb-4">
<label for="price" class="block text-gray-700 text-sm font-bold mb-2">Harga</label>
<input type="number" name="price" id="price" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" required>
</div>
<div class="mb-4">
<label for="initial_stock" class="block text-gray-700 text-sm font-bold mb-2">Stok Awal</label>
<input type="number" name="initial_stock" id="initial_stock" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" required>
</div>
<div class="mb-4">
<label for="minimum_stock" class="block text-gray-700 text-sm font-bold mb-2">Stok Minimum</label>
<input type="number" name="minimum_stock" id="minimum_stock" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" required>
</div>
</div>
<div class="mb-4">
<label for="description" class="block text-gray-700 text-sm font-bold mb-2">Deskripsi</label>
<textarea name="description" id="description" rows="3" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"></textarea>
</div>
<div class="flex items-center justify-between">
<button type="submit" class="bg-blue-500 hover:bg-blue-700 text-black font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline">
Simpan
</button>
<a href="{{ route('products.index') }}" class="text-gray-600 hover:text-gray-800">Batal</a>
</div>
</form>
</div>
</div>
</div>
</x-app-layout>
// resources\views\inventory\products\edit.blade.php
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Edit Produk') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg p-6">
<form action="{{ route('products.update', $product) }}" method="POST">
@csrf
@method('PUT')
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="mb-4">
<label for="code" class="block text-gray-700 text-sm font-bold mb-2">Kode Produk</label>
<input type="text" name="code" id="code" value="{{ $product->code }}" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" required>
</div>
<div class="mb-4">
<label for="name" class="block text-gray-700 text-sm font-bold mb-2">Nama Produk</label>
<input type="text" name="name" id="name" value="{{ $product->name }}" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" required>
</div>
<div class="mb-4">
<label for="category_id" class="block text-gray-700 text-sm font-bold mb-2">Kategori</label>
<select name="category_id" id="category_id" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" required>
@foreach($categories as $category)
<option value="{{ $category->id }}" {{ $product->category_id == $category->id ? 'selected' : '' }}>
{{ $category->name }}
</option>
@endforeach
</select>
</div>
<div class="mb-4">
<label for="price" class="block text-gray-700 text-sm font-bold mb-2">Harga</label>
<input type="number" name="price" id="price" value="{{ $product->price }}" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" required>
</div>
<div class="mb-4">
<label for="minimum_stock" class="block text-gray-700 text-sm font-bold mb-2">Stok Minimum</label>
<input type="number" name="minimum_stock" id="minimum_stock" value="{{ $product->stock->minimum_stock }}" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" required>
</div>
</div>
<div class="mb-4">
<label for="description" class="block text-gray-700 text-sm font-bold mb-2">Deskripsi</label>
<textarea name="description" id="description" rows="3" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline">{{ $product->description }}</textarea>
</div>
<div class="flex items-center justify-between">
<button type="submit" class="bg-blue-500 hover:bg-blue-700 text-black font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline">
Update
</button>
<a href="{{ route('products.index') }}" class="text-gray-600 hover:text-gray-800">Batal</a>
</div>
</form>
</div>
</div>
</div>
</x-app-layout>