store/app/Services/Master/MasterInventoryService.php

109 lines
4.0 KiB
PHP

<?php
namespace App\Services\Master;
use App\Enums\RawMaterialUnit;
use App\Models\Product;
use App\Models\ProductVariant;
use App\Models\RawMaterial;
use App\Models\RawMaterialPrice;
use App\Support\Media\MediaPresenter;
use Illuminate\Database\Eloquent\Builder;
class MasterInventoryService
{
public function outOfStockProductGroups(int $limit = 50): array
{
return Product::query()
->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();
}
}