authorizeSupplyChain('supplychain.forecast.view'); $businessId = $this->supplyChainUtil->getBusinessId(); if ($request->ajax()) { $forecasts = DemandForecast::forBusiness($businessId) ->with(['product', 'variation']) ->orderByDesc('forecast_month'); return DataTables::of($forecasts) ->addColumn('product_name', fn ($row) => $row->product?->name ?? '—') ->addColumn('variation_name', fn ($row) => $row->variation?->sub_sku ?? '—') ->editColumn('forecast_month', fn ($row) => $row->forecast_month->format('Y-m')) ->editColumn('forecast_qty', fn ($row) => number_format((float) $row->forecast_qty, 2)) ->editColumn('confidence', fn ($row) => number_format((float) $row->confidence, 1).'%') ->addColumn('action', function ($row) { return ''; }) ->rawColumns(['action']) ->make(true); } return view('supplychain::demand_forecasts.index'); } public function create() { $this->authorizeSupplyChain('supplychain.forecast.create'); return view('supplychain::demand_forecasts.create', [ 'products' => $this->supplyChainUtil->getProductsDropdown(), ]); } public function store(Request $request) { $this->authorizeSupplyChain('supplychain.forecast.create'); $businessId = $this->supplyChainUtil->getBusinessId(); $data = $request->validate([ 'product_id' => 'required|integer', 'variation_id' => 'nullable|integer', 'forecast_month' => 'required|date', 'forecast_qty' => 'required|numeric|min:0', 'method' => 'nullable|string|max:50', 'confidence' => 'nullable|numeric|min:0|max:100', 'source' => 'nullable|string|max:50', ]); DemandForecast::create([ 'business_id' => $businessId, 'product_id' => $data['product_id'], 'variation_id' => $data['variation_id'] ?? null, 'forecast_month' => Carbon::parse($data['forecast_month'])->startOfMonth()->toDateString(), 'forecast_qty' => $data['forecast_qty'], 'method' => $data['method'] ?? 'manual', 'confidence' => $data['confidence'] ?? 50, 'source' => $data['source'] ?? 'manual', ]); return $this->supplyChainUtil->jsonOrRedirect( $request, true, __('supplychain::lang.forecast_created'), action([self::class, 'index']) ); } public function show($id) { $this->authorizeSupplyChain('supplychain.forecast.view'); $businessId = $this->supplyChainUtil->getBusinessId(); $forecast = DemandForecast::forBusiness($businessId)->with(['product', 'variation'])->findOrFail($id); return view('supplychain::demand_forecasts.show', compact('forecast')); } public function generate(Request $request) { $this->authorizeSupplyChain('supplychain.forecast.create'); $businessId = $this->supplyChainUtil->getBusinessId(); $monthsAhead = (int) $request->input('months_ahead', 3); $results = $this->forecastService->generateForBusiness($businessId, $monthsAhead); return $this->supplyChainUtil->jsonOrRedirect( $request, true, __('supplychain::lang.forecasts_generated', ['count' => $results->count()]), action([self::class, 'index']) ); } }