417 lines
23 KiB
PHP
417 lines
23 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers; // Deklarasi namespace untuk kelas kontroler ini. Ini membantu mengorganisir kode dan mencegah konflik nama kelas.
|
|
|
|
use App\Models\RawMaterial; // Mengimpor model `RawMaterial`. Model ini merepresentasikan tabel 'raw_materials' di database dan digunakan untuk berinteraksi dengan data bahan baku.
|
|
use App\Models\RawMaterialLog; // Mengimpor model `RawMaterialLog`. Model ini merepresentasikan tabel 'raw_material_logs' dan digunakan untuk mencatat setiap perubahan stok bahan baku (misalnya, masuk, keluar, penyesuaian).
|
|
use App\Models\Supplier; // Mengimpor model `Supplier`. Meskipun tidak digunakan secara langsung di semua metode yang ditampilkan, model ini mungkin digunakan di bagian lain aplikasi atau untuk tampilan terkait (misalnya, di form pembelian untuk memilih supplier).
|
|
use Illuminate\Http\Request; // Mengimpor kelas `Request`. Objek Request digunakan untuk mengakses data yang dikirimkan melalui permintaan HTTP (seperti data dari form, parameter URL, dll.).
|
|
use Illuminate\Support\Facades\DB; // Mengimpor facade `DB`. Ini menyediakan metode untuk berinteraksi langsung dengan database, termasuk menjalankan transaksi database. Transaksi sangat penting untuk memastikan beberapa operasi database berhasil atau gagal secara bersamaan (atomik).
|
|
|
|
class RawMaterialController extends Controller // Deklarasi kelas `RawMaterialController` yang mewarisi (extends) dari kelas `Controller` dasar Laravel. Ini memberikan akses ke berbagai fitur dasar kontroler.
|
|
{
|
|
/**
|
|
* Metode `index()`: Menampilkan daftar semua bahan baku.
|
|
* Metode ini berfungsi sebagai halaman utama untuk manajemen bahan baku, menampilkan semua item yang tersedia.
|
|
*
|
|
* @return \Illuminate\View\View Mengembalikan instance view Laravel yang akan ditampilkan ke pengguna.
|
|
*/
|
|
public function index()
|
|
{
|
|
// Mengambil semua data bahan baku dari tabel 'raw_materials'.
|
|
// `RawMaterial::orderBy('name')` mengurutkan hasil berdasarkan kolom 'name' secara ascending (A-Z).
|
|
// `->get()` mengeksekusi query dan mengembalikan koleksi (Collection) dari objek RawMaterial.
|
|
$materials = RawMaterial::orderBy('created_at', 'desc')->get();
|
|
|
|
// Mengirim data bahan baku ($materials) ke view.
|
|
// `view('raw-materials.index')` merujuk ke file view Blade di `resources/views/raw-materials/index.blade.php`.
|
|
// `compact('materials')` adalah cara singkat untuk mengirim variabel `$materials` ke view dengan nama yang sama.
|
|
return view('raw-materials.index', compact('materials'));
|
|
}
|
|
|
|
/**
|
|
* Metode `create()`: Menampilkan form untuk membuat bahan baku baru.
|
|
* Metode ini bertanggung jawab untuk menampilkan antarmuka pengguna untuk menambahkan bahan baku baru ke sistem.
|
|
*
|
|
* @return \Illuminate\View\View Mengembalikan instance view Laravel yang berisi form.
|
|
*/
|
|
public function create()
|
|
{
|
|
// Mengirim pengguna ke view 'raw-materials.create', yang berisi form input untuk data bahan baku baru.
|
|
// View ini biasanya ada di `resources/views/raw-materials/create.blade.php`.
|
|
return view('raw-materials.create');
|
|
}
|
|
|
|
/**
|
|
* Metode `store()`: Menyimpan data bahan baku baru yang dikirim dari form `create()`.
|
|
* Metode ini menerima data dari permintaan POST dan menyimpannya ke database setelah validasi.
|
|
*
|
|
* @param \Illuminate\Http\Request $request Objek Request yang berisi semua data input dari form.
|
|
* @return \Illuminate\Http\RedirectResponse Mengarahkan pengguna kembali ke halaman lain dengan pesan status.
|
|
*/
|
|
public function store(Request $request)
|
|
{
|
|
// Melakukan validasi data yang diterima dari request.
|
|
// Ini memastikan bahwa data yang masuk ke database sesuai dengan aturan yang ditentukan.
|
|
$request->validate([
|
|
'name' => 'required|string', // Nama bahan baku wajib diisi.
|
|
'stock' => 'required|numeric|min:0', // Stok wajib diisi, harus berupa angka, dan tidak boleh kurang dari 0.
|
|
'unit' => 'required', // Satuan (misalnya, kg, liter) wajib diisi.
|
|
'price' => 'required|numeric|min:0', // Harga wajib diisi, harus berupa angka, dan tidak boleh kurang dari 0.
|
|
'description' => 'nullable', // Deskripsi boleh kosong (tidak wajib).
|
|
'type' => 'required|in:in,adjustment' // Tipe transaksi awal harus 'in' (masuk) atau 'adjustment' (penyesuaian).
|
|
]);
|
|
|
|
if (RawMaterial::where('name', $request['name'])->exists()) {
|
|
return back()->with('error', 'Nama bahan baku sudah ada. Silakan gunakan nama yang berbeda.')->withInput();
|
|
}
|
|
// Membuat entri bahan baku baru di tabel 'raw_materials' menggunakan data yang tervalidasi.
|
|
// `RawMaterial::create()` adalah metode Eloquent yang membuat dan menyimpan record baru ke database.
|
|
$material = RawMaterial::create([
|
|
'name' => $request->name, // Mengambil nilai 'name' dari request.
|
|
'description' => $request->description, // Mengambil nilai 'description' dari request.
|
|
'stock' => $request->stock, // Mengambil nilai 'stock' dari request.
|
|
'unit' => $request->unit, // Mengambil nilai 'unit' dari request.
|
|
'price' => $request->price, // Mengambil nilai 'price' dari request.
|
|
'minimum_stock' => 10 // Menetapkan nilai default 'minimum_stock' menjadi 10.
|
|
]);
|
|
|
|
// Memeriksa apakah stok awal yang dimasukkan lebih dari 0.
|
|
if ($material->stock > 0) {
|
|
// Jika stok lebih dari 0, buat log di tabel 'raw_material_logs'.
|
|
// Ini mencatat entri awal bahan baku ke dalam sistem.
|
|
RawMaterialLog::create([
|
|
'raw_material_id' => $material->id, // ID bahan baku yang baru saja dibuat.
|
|
'user_id' => auth()->id(), // ID pengguna yang sedang login (yang melakukan operasi ini).
|
|
'type' => $request->type, // Tipe log, diambil dari input 'type' form (e.g., 'in' atau 'adjustment').
|
|
'quantity' => $material->stock, // Kuantitas stok yang dicatat dalam log.
|
|
'price' => $material->price, // Harga per unit bahan baku saat log dibuat.
|
|
'subtotal' => $material->stock * $material->price, // Subtotal (kuantitas * harga).
|
|
// Catatan log disesuaikan berdasarkan tipe: 'Stok awal bahan baku' jika 'in', 'Penyesuaian stok awal' jika 'adjustment'.
|
|
'notes' => $request->type === 'in' ? 'Stok awal bahan baku' : 'Penyesuaian stok awal'
|
|
]);
|
|
}
|
|
|
|
// Mengarahkan pengguna kembali ke halaman index bahan baku setelah operasi berhasil.
|
|
// `with('success', ...)` menambahkan pesan flash 'success' yang bisa ditampilkan di view.
|
|
return redirect()->route('raw-materials.index')
|
|
->with('success', 'Bahan baku berhasil ditambahkan.');
|
|
}
|
|
|
|
/**
|
|
* Metode `edit()`: Menampilkan form untuk mengedit bahan baku yang sudah ada.
|
|
* Metode ini mengambil data bahan baku berdasarkan ID dan menyediakannya untuk pengeditan.
|
|
*
|
|
* @param \App\Models\RawMaterial $rawMaterial Ini adalah fitur Route Model Binding Laravel. Laravel secara otomatis mencari objek `RawMaterial` berdasarkan ID yang ada di URL dan menyuntikkannya ke metode ini.
|
|
* @return \Illuminate\View\View Mengembalikan instance view Laravel yang berisi form pengeditan.
|
|
*/
|
|
public function edit(RawMaterial $rawMaterial)
|
|
{
|
|
// Mengirim data bahan baku ($rawMaterial) yang akan diedit ke view.
|
|
// View ini biasanya ada di `resources/views/raw-materials/edit.blade.php`.
|
|
return view('raw-materials.edit', compact('rawMaterial'));
|
|
}
|
|
|
|
/**
|
|
* Metode `update()`: Memperbarui data bahan baku yang sudah ada.
|
|
* Metode ini menerima data dari form pengeditan dan memperbarui record di database.
|
|
*
|
|
* @param \Illuminate\Http\Request $request Objek Request yang berisi data input yang diperbarui.
|
|
* @param \App\Models\RawMaterial $rawMaterial Objek RawMaterial yang akan diperbarui (didapat dari Route Model Binding).
|
|
* @return \Illuminate\Http\RedirectResponse Mengarahkan pengguna kembali dengan pesan status.
|
|
*/
|
|
public function update(Request $request, RawMaterial $rawMaterial)
|
|
{
|
|
// Melakukan validasi data yang diterima untuk pembaruan.
|
|
// Aturannya mirip dengan `store()`, dengan tambahan `minimum_stock`.
|
|
$request->validate([
|
|
'name' => 'required',
|
|
'stock' => 'required|numeric|min:0',
|
|
'unit' => 'required',
|
|
'price' => 'required|numeric|min:0',
|
|
'minimum_stock' => 'required|numeric|min:0',
|
|
'description' => 'nullable'
|
|
]);
|
|
|
|
// Memeriksa apakah ada perubahan pada nilai stok.
|
|
// Jika stok yang diinputkan berbeda dengan stok yang ada di database saat ini, maka buat log perubahan.
|
|
if ($request->stock != $rawMaterial->stock) {
|
|
// Menghitung selisih antara stok baru dan stok lama.
|
|
$difference = $request->stock - $rawMaterial->stock;
|
|
// Menentukan tipe log: 'in' jika stok bertambah, 'out' jika stok berkurang.
|
|
$type = $difference > 0 ? 'in' : 'out';
|
|
// Mengambil nilai absolut dari selisih untuk kuantitas log.
|
|
$quantity = abs($difference);
|
|
|
|
// Membuat entri log di tabel 'raw_material_logs' untuk mencatat penyesuaian stok.
|
|
RawMaterialLog::create([
|
|
'raw_material_id' => $rawMaterial->id, // ID bahan baku yang stoknya diubah.
|
|
'user_id' => auth()->id(), // ID pengguna yang melakukan perubahan.
|
|
'type' => $type, // Tipe log ('in' atau 'out').
|
|
'quantity' => $quantity, // Jumlah kuantitas yang berubah.
|
|
'price' => $request->price, // Harga per unit saat perubahan (diambil dari input form).
|
|
'subtotal' => $quantity * $request->price, // Subtotal perubahan.
|
|
'notes' => 'Penyesuaian stok melalui edit bahan baku' // Catatan default untuk log ini.
|
|
]);
|
|
}
|
|
|
|
// Memperbarui data bahan baku di database dengan semua data dari request.
|
|
// `update($request->all())` akan memperbarui semua kolom yang ada di `$request->all()` yang sesuai dengan fillable di model.
|
|
$rawMaterial->update($request->all());
|
|
|
|
// Mengarahkan kembali ke halaman index bahan baku dengan pesan sukses.
|
|
return redirect()->route('raw-materials.index')
|
|
->with('success', 'Data bahan baku berhasil diperbarui.');
|
|
}
|
|
|
|
/**
|
|
* Metode `destroy()`: Menghapus bahan baku dari database.
|
|
* Metode ini digunakan untuk menghapus record bahan baku secara permanen.
|
|
*
|
|
* @param \App\Models\RawMaterial $rawMaterial Objek RawMaterial yang akan dihapus.
|
|
* @return \Illuminate\Http\RedirectResponse Mengarahkan pengguna kembali dengan pesan status.
|
|
*/
|
|
public function destroy(RawMaterial $rawMaterial)
|
|
{
|
|
// Menghapus data bahan baku dari database.
|
|
$rawMaterial->delete();
|
|
|
|
// Mengarahkan kembali ke halaman index bahan baku dengan pesan sukses.
|
|
return redirect()->route('raw-materials.index')
|
|
->with('success', 'Bahan baku sudah di hapus.');
|
|
}
|
|
|
|
/**
|
|
* Metode `adjustStock()`: Menyesuaikan stok bahan baku (menambah atau mengurangi).
|
|
* Metode ini dirancang untuk penyesuaian stok manual (misalnya, koreksi inventaris), bukan untuk pembelian.
|
|
*
|
|
* @param \Illuminate\Http\Request $request Objek Request yang berisi data penyesuaian stok.
|
|
* @param \App\Models\RawMaterial $rawMaterial Objek RawMaterial yang stoknya akan disesuaikan.
|
|
* @return \Illuminate\Http\RedirectResponse Mengarahkan pengguna kembali dengan pesan status.
|
|
*/
|
|
public function adjustStock(Request $request, RawMaterial $rawMaterial)
|
|
{
|
|
// Melakukan validasi input untuk penyesuaian stok.
|
|
$validated = $request->validate([
|
|
'type' => 'required|in:in,out', // Tipe penyesuaian: 'in' (masuk) atau 'out' (keluar).
|
|
'quantity' => 'required|numeric|min:1', // Kuantitas penyesuaian, harus angka positif.
|
|
'notes' => 'nullable', // Catatan penyesuaian (opsional).
|
|
]);
|
|
|
|
// Menggunakan transaksi database (`DB::transaction`).
|
|
// Ini penting untuk menjaga integritas data: jika ada langkah yang gagal, semua perubahan dalam blok ini akan dibatalkan.
|
|
DB::transaction(function () use ($rawMaterial, $validated) {
|
|
// Menghitung subtotal berdasarkan harga bahan baku saat ini dan kuantitas yang disesuaikan.
|
|
$subtotal = $rawMaterial->price * $validated['quantity'];
|
|
|
|
// Logika penyesuaian stok:
|
|
if ($validated['type'] === 'in') {
|
|
// Jika tipe adalah 'in' (masuk), tambahkan kuantitas ke stok bahan baku.
|
|
$rawMaterial->increment('stock', $validated['quantity']);
|
|
} else {
|
|
// Jika tipe adalah 'out' (keluar), kurangi kuantitas dari stok.
|
|
// Penting: Lakukan pemeriksaan stok untuk mencegah stok negatif.
|
|
if ($rawMaterial->stock < $validated['quantity']) {
|
|
// Jika stok tidak mencukupi, lemparkan Exception (ini akan memicu rollback transaksi).
|
|
throw new \Exception('Insufficient stock.');
|
|
}
|
|
// Kurangi stok bahan baku.
|
|
$rawMaterial->decrement('stock', $validated['quantity']);
|
|
}
|
|
|
|
// Mencatat log penyesuaian stok di tabel 'raw_material_logs'.
|
|
RawMaterialLog::create([
|
|
'raw_material_id' => $rawMaterial->id, // ID bahan baku yang disesuaikan.
|
|
'user_id' => auth()->id(), // ID pengguna yang melakukan penyesuaian.
|
|
'type' => $validated['type'], // Tipe penyesuaian ('in' atau 'out').
|
|
'quantity' => $validated['quantity'], // Kuantitas yang disesuaikan.
|
|
'price' => $rawMaterial->price, // Harga bahan baku saat itu (dari database).
|
|
'subtotal' => $subtotal, // Subtotal penyesuaian.
|
|
'notes' => $validated['notes'] // Catatan dari pengguna.
|
|
]);
|
|
});
|
|
|
|
// Mengarahkan kembali ke halaman index bahan baku dengan pesan sukses.
|
|
return redirect()->route('raw-materials.index')
|
|
->with('success', 'Stock adjusted successfully.');
|
|
}
|
|
|
|
/**
|
|
* Metode `report()`: Menampilkan laporan log bahan baku (mutasi stok).
|
|
* Metode ini memungkinkan pengguna melihat riwayat perubahan stok dengan filter tertentu.
|
|
*
|
|
* @param \Illuminate\Http\Request $request Objek Request yang berisi filter (tanggal, ID bahan baku).
|
|
* @return \Illuminate\View\View Mengembalikan view laporan dengan data log.
|
|
*/
|
|
public function report(Request $request)
|
|
{
|
|
// Membangun query dasar untuk mengambil log bahan baku.
|
|
// `with(['rawMaterial', 'user.admin', 'user.karyawan'])` memuat relasi terkait (bahan baku, pengguna, admin/karyawan yang terkait dengan pengguna)
|
|
// untuk menghindari N+1 query problem dan menampilkan detail yang relevan di laporan.
|
|
// `orderBy('created_at', 'desc')` mengurutkan log berdasarkan waktu pembuatan terbaru.
|
|
$query = RawMaterialLog::with(['rawMaterial', 'user.admin', 'user.karyawan'])
|
|
->orderBy('created_at', 'desc');
|
|
|
|
// Menerapkan filter berdasarkan tanggal mulai jika `start_date` ada di request.
|
|
if ($request->filled('start_date')) {
|
|
$query->whereDate('created_at', '>=', $request->start_date);
|
|
}
|
|
|
|
// Menerapkan filter berdasarkan tanggal selesai jika `end_date` ada di request.
|
|
if ($request->filled('end_date')) {
|
|
$query->whereDate('created_at', '<=', $request->end_date);
|
|
}
|
|
|
|
// Menerapkan filter berdasarkan ID bahan baku jika `material_id` ada di request.
|
|
if ($request->filled('material_id')) {
|
|
$query->where('raw_material_id', $request->material_id);
|
|
}
|
|
|
|
// Mengeksekusi query dan mendapatkan hasil log.
|
|
$logs = $query->get();
|
|
// Filter agar hanya log yang bahan bakunya masih ada yang ditampilkan
|
|
$logs = $logs->filter(function($log) {
|
|
return $log->rawMaterial !== null;
|
|
});
|
|
// Mengambil semua bahan baku untuk digunakan dalam dropdown filter di tampilan laporan.
|
|
$materials = RawMaterial::orderBy('name')->get();
|
|
|
|
// Mengirim data log dan daftar bahan baku ke view 'raw-materials.report'.
|
|
return view('raw-materials.report', compact('logs', 'materials'));
|
|
}
|
|
|
|
/**
|
|
* Metode `lowStock()`: Menampilkan daftar bahan baku dengan stok rendah.
|
|
* Metode ini berguna untuk mengidentifikasi bahan baku yang perlu segera di-restock.
|
|
*
|
|
* @return \Illuminate\View\View Mengembalikan view yang menampilkan bahan baku stok rendah.
|
|
*/
|
|
public function lowStock()
|
|
{
|
|
// minimum stok jika jumlah di field stok lebih kesil atau sama dengan jumlah di field minimum_stock
|
|
$materials = RawMaterial::whereRaw('stock <= minimum_stock')
|
|
->orderBy('name')
|
|
->get();
|
|
|
|
// Mengirim data bahan baku stok rendah ke view 'raw-materials.low-stock'.
|
|
return view('raw-materials.low-stock', compact('materials'));
|
|
}
|
|
|
|
/**
|
|
* Metode `purchase()`: Menampilkan form untuk mencatat pembelian bahan baku.
|
|
* Metode ini menyediakan antarmuka untuk mencatat pembelian bahan baku baru dari supplier.
|
|
*
|
|
* @return \Illuminate\View\View Mengembalikan view form pembelian.
|
|
*/
|
|
public function purchase()
|
|
{
|
|
// Mengambil semua bahan baku untuk dropdown pilihan di form pembelian.
|
|
$materials = RawMaterial::orderBy('name')->get();
|
|
// Mengambil semua supplier (pemasok) untuk dropdown pilihan di form pembelian.
|
|
$suppliers = Supplier::orderBy('name')->get();
|
|
|
|
// Mengirim data bahan baku dan supplier ke view 'raw-materials.purchase'.
|
|
return view('raw-materials.purchase', compact('materials', 'suppliers'));
|
|
}
|
|
|
|
/**
|
|
* Metode `storePurchase()`: Menyimpan data pembelian bahan baku.
|
|
* Metode ini memproses data dari form pembelian, memperbarui stok, dan mencatat log pembelian.
|
|
*
|
|
* @param \Illuminate\Http\Request $request Objek Request yang berisi data pembelian.
|
|
* @return \Illuminate\Http\RedirectResponse Mengarahkan pengguna kembali dengan pesan sukses.
|
|
*/
|
|
public function storePurchase(Request $request)
|
|
{
|
|
// Melakukan validasi input untuk data pembelian.
|
|
// 'items' diharapkan berupa array, dan setiap item dalam array tersebut harus memiliki 'material_id', 'quantity', dan 'subtotal' yang valid.
|
|
$validated = $request->validate([
|
|
'items' => 'required|array', // 'items' wajib ada dan harus berupa array.
|
|
'items.*.material_id' => 'required|exists:raw_materials,id', // Setiap item harus memiliki 'material_id' yang valid (ada di tabel 'raw_materials').
|
|
'items.*.quantity' => 'required|numeric|min:0.01', // Kuantitas wajib, harus angka, minimal 0.01.
|
|
'items.*.subtotal' => 'required|numeric|min:1', // Subtotal wajib, harus angka, minimal 1.
|
|
'notes' => 'nullable|string' // Catatan pembelian (opsional).
|
|
]);
|
|
|
|
// Menggunakan transaksi database (`DB::transaction`).
|
|
// Ini memastikan bahwa semua pembaruan stok dan log pembelian untuk semua item berjalan secara atomik.
|
|
// Jika ada masalah saat memproses satu item, semua perubahan akan dibatalkan.
|
|
DB::transaction(function () use ($validated) {
|
|
// Melakukan iterasi (loop) untuk setiap item bahan baku yang dibeli.
|
|
foreach ($validated['items'] as $item) {
|
|
// Mencari objek RawMaterial berdasarkan 'material_id' dari item yang dibeli.
|
|
// `findOrFail()` akan melempar error 404 jika bahan baku tidak ditemukan.
|
|
$material = RawMaterial::findOrFail($item['material_id']);
|
|
// Menghitung harga per unit baru. Ini penting karena harga beli bisa bervariasi.
|
|
// `round(..., 2)` membulatkan hasil ke dua tempat desimal.
|
|
$newPrice = round($item['subtotal'] / $item['quantity'], 2);
|
|
|
|
// Memperbarui stok dan harga di tabel `raw_materials`.
|
|
$material->update([
|
|
'stock' => $material->stock + $item['quantity'], // Menambahkan kuantitas yang dibeli ke stok yang ada.
|
|
'price' => $newPrice // Memperbarui harga bahan baku dengan harga rata-rata baru dari pembelian ini.
|
|
]);
|
|
|
|
// Membuat entri log di tabel `raw_material_logs` untuk mencatat transaksi pembelian ini.
|
|
RawMaterialLog::create([
|
|
'raw_material_id' => $item['material_id'], // ID bahan baku yang dibeli.
|
|
'user_id' => auth()->id(), // ID pengguna yang sedang login yang melakukan pembelian.
|
|
'type' => 'in', // Tipe log adalah 'in' (masuk), menunjukkan penambahan stok.
|
|
'quantity' => $item['quantity'], // Kuantitas yang dibeli.
|
|
'price' => $newPrice, // Harga per unit yang baru dihitung.
|
|
'subtotal' => $item['subtotal'], // Subtotal total untuk item ini.
|
|
// Catatan log: jika ada input 'notes', gunakan itu; jika tidak, gunakan 'Pembelian bahan baku'.
|
|
'notes' => $validated['notes'] ? $validated['notes'] : 'Pembelian bahan baku'
|
|
]);
|
|
}
|
|
});
|
|
|
|
// Mengarahkan kembali ke halaman index bahan baku dengan pesan sukses setelah semua item berhasil disimpan.
|
|
return redirect()->route('raw-materials.index')
|
|
->with('success', 'Pembelian bahan baku berhasil disimpan.');
|
|
}
|
|
|
|
/**
|
|
* Menampilkan form pemakaian bahan baku
|
|
*/
|
|
public function usage()
|
|
{
|
|
$materials = \App\Models\RawMaterial::orderBy('name')->get();
|
|
return view('raw-materials.usage', compact('materials'));
|
|
}
|
|
|
|
/**
|
|
* Proses pemakaian bahan baku (multi-item)
|
|
*/
|
|
public function storeUsage(\Illuminate\Http\Request $request)
|
|
{
|
|
$request->validate([
|
|
'items' => 'required|array',
|
|
'items.*.material_id' => 'required|exists:raw_materials,id',
|
|
'items.*.quantity' => 'required|numeric|min:0.01',
|
|
'notes' => 'nullable|string',
|
|
]);
|
|
$items = $request->items;
|
|
$notes = $request->notes;
|
|
DB::transaction(function () use ($items, $notes) {
|
|
foreach ($items as $item) {
|
|
$material = \App\Models\RawMaterial::findOrFail($item['material_id']);
|
|
if ($material->stock < $item['quantity']) {
|
|
throw new \Exception('Stok bahan baku ' . $material->name . ' tidak mencukupi.');
|
|
}
|
|
$material->decrement('stock', $item['quantity']);
|
|
\App\Models\RawMaterialLog::create([
|
|
'raw_material_id' => $material->id,
|
|
'user_id' => auth()->id(),
|
|
'type' => 'pemakaian',
|
|
'quantity' => $item['quantity'],
|
|
'price' => 0,
|
|
'subtotal' => 0,
|
|
'notes' => $notes ?? 'Pemakaian bahan baku',
|
|
]);
|
|
}
|
|
});
|
|
return redirect()->route('raw-materials.usage')->with('success', 'Pemakaian bahan baku berhasil diproses.');
|
|
}
|
|
}
|