where('is_active', true) ->whereHas('variants', fn (Builder $query) => $query->where('stock', '<=', 0)) ->with([ 'variants' => fn ($query) => $query ->where('stock', '<=', 0) ->with('media') ->orderBy('name'), ]) ->orderBy('name') ->limit($limit) ->get() ->map(fn (Product $product) => [ 'id' => $product->id, 'name' => $product->name, 'edit_url' => route('admin.master.products.edit', $product), 'variants' => $product->variants->map(fn (ProductVariant $variant) => [ 'id' => $variant->id, 'name' => $variant->name, 'stock_formatted' => $variant->stock_formatted, 'images' => MediaPresenter::collection($variant, 'images'), ])->values()->all(), ]) ->filter(fn (array $group) => $group['variants'] !== []) ->values() ->all(); } public function outOfStockRawMaterialGroups(int $limit = 50): array { return $this->rawMaterialGroupsWithStockFilter( fn (Builder $query) => $query->where('stock', '<=', 0), $limit, ); } public function lowStockRawMaterialGroups(int $limit = 50): array { $minStock = [ RawMaterialUnit::YARD->value => 20, RawMaterialUnit::METER->value => 10, RawMaterialUnit::KILOGRAM->value => 5, ]; return $this->rawMaterialGroupsWithStockFilter( function (Builder $query) use ($minStock): void { $query->where('stock', '>', 0)->where(function (Builder $query) use ($minStock): void { foreach (RawMaterialUnit::cases() as $unit) { $query->orWhere(function (Builder $query) use ($unit, $minStock): void { $query->whereHas( 'rawMaterial', fn (Builder $rawMaterialQuery) => $rawMaterialQuery->where('unit', $unit), )->where('stock', '<', $minStock[$unit->value]); }); } }); }, $limit, ); } private function rawMaterialGroupsWithStockFilter(callable $priceConstraint, int $limit): array { return RawMaterial::query() ->where('is_active', true) ->whereHas('prices', $priceConstraint) ->with([ 'prices' => function ($query) use ($priceConstraint): void { $priceConstraint($query); $query->with('media')->orderBy('variant'); }, ]) ->orderBy('name') ->limit($limit) ->get() ->map(fn (RawMaterial $rawMaterial) => [ 'id' => $rawMaterial->id, 'name' => $rawMaterial->name, 'edit_url' => route('admin.master.raw_materials.edit', $rawMaterial), 'unit_label' => $rawMaterial->unit_label, 'variants' => $rawMaterial->prices->map(fn (RawMaterialPrice $price) => [ 'id' => $price->id, 'name' => $price->variant, 'stock_formatted' => $price->stock_formatted, 'images' => MediaPresenter::collection($price, 'images'), ])->values()->all(), ]) ->filter(fn (array $group) => $group['variants'] !== []) ->values() ->all(); } }