stockService = $stockService; } /** * Display work products for a specific work */ public function index(Request $request, $workId) { $menu = Menu::where('link', 'work.index')->first(); abort_if(Gate::denies('view', $menu), 403, 'Unauthorized User'); $work = Work::with('category')->findOrFail($workId); if ($request->ajax()) { Log::info('Work products index AJAX request for work ID: ' . $workId); $workProducts = WorkProduct::with(['product', 'product.category']) ->where('work_id', $workId) ->get(); Log::info('Found ' . $workProducts->count() . ' work products'); return DataTables::of($workProducts) ->addIndexColumn() ->addColumn('product_name', function($row) { return $row->product->name; }) ->addColumn('product_code', function($row) { return $row->product->code; }) ->addColumn('product_category', function($row) { return $row->product->category ? $row->product->category->name : '-'; }) ->addColumn('unit', function($row) { return $row->product->unit; }) ->addColumn('quantity_required', function($row) { return number_format($row->quantity_required, 2); }) ->addColumn('action', function($row) use ($menu) { $btn = '
'; if(Gate::allows('update', $menu)) { $btn .= ''; } if(Gate::allows('delete', $menu)) { $btn .= ''; } $btn .= '
'; return $btn; }) ->rawColumns(['action']) ->make(true); } $products = Product::where('active', true)->with('category')->get(); return view('back.master.work-products', compact('work', 'products')); } /** * Store work product relationship */ public function store(Request $request) { $menu = Menu::where('link', 'work.index')->first(); abort_if(Gate::denies('create', $menu), 403, 'Unauthorized User'); $request->validate([ 'work_id' => 'required|exists:works,id', 'product_id' => 'required|exists:products,id', 'quantity_required' => 'required|numeric|min:0.01', 'notes' => 'nullable|string' ]); // Check if combination already exists $exists = WorkProduct::where('work_id', $request->work_id) ->where('product_id', $request->product_id) ->exists(); if ($exists) { return response()->json([ 'status' => 422, 'message' => 'Produk sudah ditambahkan ke pekerjaan ini' ], 422); } WorkProduct::create($request->all()); return response()->json([ 'status' => 200, 'message' => 'Produk berhasil ditambahkan ke pekerjaan' ]); } /** * Show work product for editing */ public function show($workId, $workProductId) { $menu = Menu::where('link', 'work.index')->first(); abort_if(Gate::denies('view', $menu), 403, 'Unauthorized User'); try { $workProduct = WorkProduct::with(['work', 'product', 'product.category']) ->where('work_id', $workId) ->where('id', $workProductId) ->firstOrFail(); return response()->json([ 'status' => 200, 'data' => $workProduct ]); } catch (\Exception $e) { Log::error('Error fetching work product: ' . $e->getMessage()); return response()->json([ 'status' => 404, 'message' => 'Work product tidak ditemukan' ], 404); } } /** * Update work product relationship */ public function update(Request $request, $workId, $workProductId) { $menu = Menu::where('link', 'work.index')->first(); abort_if(Gate::denies('update', $menu), 403, 'Unauthorized User'); $request->validate([ 'quantity_required' => 'required|numeric|min:0.01', 'notes' => 'nullable|string' ]); try { $workProduct = WorkProduct::where('work_id', $workId) ->where('id', $workProductId) ->firstOrFail(); $workProduct->update($request->only(['quantity_required', 'notes'])); return response()->json([ 'status' => 200, 'message' => 'Data produk pekerjaan berhasil diupdate' ]); } catch (\Exception $e) { Log::error('Error updating work product: ' . $e->getMessage()); return response()->json([ 'status' => 404, 'message' => 'Work product tidak ditemukan' ], 404); } } /** * Remove work product relationship */ public function destroy($workId, $workProductId) { $menu = Menu::where('link', 'work.index')->first(); abort_if(Gate::denies('delete', $menu), 403, 'Unauthorized User'); try { $workProduct = WorkProduct::where('work_id', $workId) ->where('id', $workProductId) ->firstOrFail(); $workProduct->delete(); return response()->json([ 'status' => 200, 'message' => 'Produk berhasil dihapus dari pekerjaan' ]); } catch (\Exception $e) { Log::error('Error deleting work product: ' . $e->getMessage()); return response()->json([ 'status' => 404, 'message' => 'Work product tidak ditemukan' ], 404); } } /** * Get stock prediction for work */ public function stockPrediction(Request $request, $workId) { $quantity = $request->get('quantity', 1); $prediction = $this->stockService->getStockUsagePrediction($workId, $quantity); return response()->json([ 'status' => 200, 'data' => $prediction ]); } /** * Check stock availability for work at specific dealer */ public function checkStock(Request $request) { $request->validate([ 'work_id' => 'required|exists:works,id', 'dealer_id' => 'required|exists:dealers,id', 'quantity' => 'required|integer|min:1' ]); $availability = $this->stockService->checkStockAvailability( $request->work_id, $request->dealer_id, $request->quantity ); return response()->json([ 'status' => 200, 'data' => $availability ]); } }