121 lines
4.4 KiB
PHP
121 lines
4.4 KiB
PHP
<?php
|
|
|
|
namespace Modules\SupplyChain\Http\Controllers;
|
|
|
|
use Carbon\Carbon;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Routing\Controller;
|
|
use Modules\SupplyChain\Http\Controllers\Concerns\AuthorizesSupplyChain;
|
|
use Modules\SupplyChain\Models\DemandForecast;
|
|
use Modules\SupplyChain\Services\DemandForecastService;
|
|
use Modules\SupplyChain\Utils\SupplyChainUtil;
|
|
use Yajra\DataTables\Facades\DataTables;
|
|
|
|
class DemandForecastController extends Controller
|
|
{
|
|
use AuthorizesSupplyChain;
|
|
|
|
public function __construct(
|
|
protected SupplyChainUtil $supplyChainUtil,
|
|
protected DemandForecastService $forecastService
|
|
) {
|
|
}
|
|
|
|
public function index(Request $request)
|
|
{
|
|
$this->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 '<a class="btn btn-xs btn-info" href="'.action([self::class, 'show'], $row->id).'"><i class="fa fa-eye"></i></a>';
|
|
})
|
|
->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'])
|
|
);
|
|
}
|
|
}
|