first(); if($request->ajax()){ $data = Product::with(['category','dealers']); return DataTables::of($data) ->addIndexColumn() ->addColumn('category_name', function ($row) { return $row->category ? $row->category->name : '-'; }) ->addColumn('total_stock', function ($row){ return $row->dealers->sum(function($dealer){ return $dealer->pivot->quantity ?? 0; }); }) ->addColumn('action', function ($row) use ($menu) { $btn = '
'; // if (Auth::user()->can('delete', $menu)) { // $btn .= ''; // } if (Auth::user()->can('update', $menu)) { $btn .= 'Edit'; } $btn .= ''; $btn .= '
'; return $btn; }) ->rawColumns(['action']) ->make(true); } return view('warehouse_management.products.index'); } /** * Show the form for creating a new resource. * * @return \Illuminate\Http\Response */ public function create() { $categories = ProductCategory::with('children')->whereNull('parent_id')->get(); $dealers = Dealer::all(); return view('warehouse_management.products.create', compact('categories', 'dealers')); } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { $request->validate([ 'code' => [ 'required', 'string', Rule::unique('products')->whereNull('deleted_at'), ], 'name' => 'required|string', 'description' => 'nullable|string', 'unit' => 'nullable|string', 'active' => 'required|boolean', 'product_category_id' => 'required|exists:product_categories,id', 'dealer_stock' => 'nullable|array', 'dealer_stock.*.dealer_id' => 'required|exists:dealers,id', 'dealer_stock.*.quantity' => 'required|integer|min:0', ]); // Create product $product = Product::create([ 'code' => $request->code, 'name' => $request->name, 'unit' => $request->unit, 'description' => $request->description, 'product_category_id' => $request->product_category_id, ]); // Prepare dealer stock for pivot and create mutation records $pivotData = []; if ($request->has('dealer_stock')) { foreach ($request->dealer_stock as $stockData) { if (empty($stockData['dealer_id']) || !isset($stockData['quantity'])) continue; $dealerId = $stockData['dealer_id']; $quantity = $stockData['quantity']; $pivotData[$dealerId] = ['quantity' => $quantity]; // Create stock mutation for initial stock "in" StockMutation::create([ 'product_id' => $product->id, 'dealer_id' => $dealerId, 'mutation_type' => 'in', // karena ini penambahan stok awal 'quantity' => $quantity, 'description' => 'Initial stock added when product created', 'user_id' => Auth::id(), ]); } // Attach dealer stock using pivot table $product->dealers()->attach($pivotData); } return redirect()->route('products.index')->with('success', 'Produk berhasil ditambahkan.'); } /** * Display the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function show($id) { // } /** * Show the form for editing the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function edit($id) { $product = Product::findOrFail($id); return view('warehouse_management.products.edit', [ 'product' => $product->load('dealers'), 'dealers' => Dealer::all(), 'categories' => ProductCategory::with('children')->get(), ]); } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * @return \Illuminate\Http\Response */ public function update(Request $request, Product $product) { $request->validate([ 'code' => [ 'required', 'string', Rule::unique('products')->ignore($product->id)->whereNull('deleted_at'), ], 'name' => 'required|string', 'description' => 'nullable|string', 'unit' => 'nullable|string', 'active' => 'required|boolean', 'product_category_id' => 'required|exists:product_categories,id', 'dealer_stock' => 'nullable|array', 'dealer_stock.*.dealer_id' => 'required|exists:dealers,id', 'dealer_stock.*.quantity' => 'required|integer|min:0', ]); $product->update($request->only(['code', 'name', 'description', 'unit', 'product_category_id'])); // Ambil stok lama dari pivot $oldStocks = $product->dealers()->pluck('quantity', 'dealer_id')->toArray(); // Data baru untuk sync pivot $syncData = []; $newStocks = []; if ($request->has('dealer_stock')) { foreach ($request->dealer_stock as $item) { $dealerId = $item['dealer_id']; $newQty = $item['quantity']; $syncData[$dealerId] = ['quantity' => $newQty]; $newStocks[$dealerId] = $newQty; } } // Sync pivot table $product->dealers()->sync($syncData); // Hitung mutasi stok (selisih) // Mutasi stok untuk stok baru atau perubahan stok foreach ($newStocks as $dealerId => $newQty) { $oldQty = $oldStocks[$dealerId] ?? 0; $diff = $newQty - $oldQty; if ($diff != 0) { StockMutation::create([ 'product_id' => $product->id, 'dealer_id' => $dealerId, 'mutation_type' => $diff > 0 ? 'in' : 'out', 'quantity' => abs($diff), 'description' => 'Stock updated via product update', 'user_id' => auth()->id(), ]); } } // Mutasi stok untuk dealer yang dihapus (stok jadi 0) $deletedDealers = array_diff_key($oldStocks, $newStocks); foreach ($deletedDealers as $dealerId => $oldQty) { if ($oldQty > 0) { StockMutation::create([ 'product_id' => $product->id, 'dealer_id' => $dealerId, 'mutation_type' => 'out', 'quantity' => $oldQty, 'description' => 'Stock removed via product update (dealer removed)', 'user_id' => auth()->id(), ]); } } return redirect()->route('products.index')->with('success', 'Produk berhasil diperbarui.'); } /** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response */ public function destroy(Product $product) { // Ambil stok pivot sebelum hapus $dealerStocks = $product->dealers()->pluck('quantity', 'dealer_id')->toArray(); // Buat mutasi stok keluar (out) untuk semua stok yang dihapus foreach ($dealerStocks as $dealerId => $qty) { if ($qty > 0) { StockMutation::create([ 'product_id' => $product->id, 'dealer_id' => $dealerId, 'mutation_type' => 'out', 'quantity' => $qty, 'description' => 'Stock removed due to product deletion', 'user_id' => auth()->id(), ]); } } // Hapus pivot stok dealer $product->dealers()->detach(); // Hapus produk $product->delete(); return redirect()->route('products.index')->with('success', 'Produk berhasil dihapus.'); } public function toggleActive(Request $request, Product $product) { // You can add authorization here $product->active = !$product->active; $product->save(); return response()->json([ 'success' => true, 'active' => $product->active, 'message' => 'Status produk berhasil diperbarui.' ]); } }