diff --git a/app/Enums/RawMaterialUnit.php b/app/Enums/RawMaterialUnit.php index 2d3596a..62b049e 100644 --- a/app/Enums/RawMaterialUnit.php +++ b/app/Enums/RawMaterialUnit.php @@ -12,6 +12,12 @@ enum RawMaterialUnit: string case METER = 'meter'; case KILOGRAM = 'kilogram'; + private const MIN_STOCK_YARD = 5.0; + + private const MIN_STOCK_METER = 5.0; + + private const MIN_STOCK_KILOGRAM = 2.0; + public function label(): string { return match ($this) { @@ -37,4 +43,13 @@ public static function values(): array { return array_column(self::cases(), 'value'); } + + public function minStock(): float + { + return match ($this) { + self::YARD => self::MIN_STOCK_YARD, + self::METER => self::MIN_STOCK_METER, + self::KILOGRAM => self::MIN_STOCK_KILOGRAM, + }; + } } diff --git a/app/Http/Controllers/Admin/Master/ProductController.php b/app/Http/Controllers/Admin/Master/ProductController.php index b573681..5870bd3 100644 --- a/app/Http/Controllers/Admin/Master/ProductController.php +++ b/app/Http/Controllers/Admin/Master/ProductController.php @@ -33,6 +33,7 @@ public function index(Request $request): Response return Inertia::render('admin/master/products/Index', [ 'products' => $this->productService->paginateForIndex($tableQuery, $isActive), 'outOfStockGroups' => $this->productService->outOfStockGroups(), + 'stockWarningGroups' => $this->productService->stockWarningGroups(), 'filters' => $this->dataTableFilters($tableQuery, [ 'is_active' => $isActive, ]), diff --git a/app/Http/Controllers/Admin/Master/RawMaterialController.php b/app/Http/Controllers/Admin/Master/RawMaterialController.php index ab7772f..06e2dc5 100644 --- a/app/Http/Controllers/Admin/Master/RawMaterialController.php +++ b/app/Http/Controllers/Admin/Master/RawMaterialController.php @@ -33,6 +33,7 @@ public function index(Request $request): Response return Inertia::render('admin/master/raw-materials/Index', [ 'rawMaterials' => $this->rawMaterialService->paginateForIndex($tableQuery, $isActive), 'outOfStockGroups' => $this->rawMaterialService->outOfStockGroups(), + 'stockWarningGroups' => $this->rawMaterialService->stockWarningGroups(), 'filters' => $this->dataTableFilters($tableQuery, [ 'is_active' => $isActive, ]), diff --git a/app/Models/ProductVariant.php b/app/Models/ProductVariant.php index 52173ad..1e7fe9b 100644 --- a/app/Models/ProductVariant.php +++ b/app/Models/ProductVariant.php @@ -20,6 +20,8 @@ class ProductVariant extends Model implements HasMedia use InteractsWithActivityLog; use SoftDeletes; + private const MIN_STOCK = 5; + protected function casts(): array { return [ @@ -47,6 +49,11 @@ public function product(): BelongsTo return $this->belongsTo(Product::class); } + public static function minStock(): int + { + return self::MIN_STOCK; + } + public static function mediaModuleName(): string { return 'product'; diff --git a/app/Services/Master/ProductService.php b/app/Services/Master/ProductService.php index eef5af6..13b42b7 100644 --- a/app/Services/Master/ProductService.php +++ b/app/Services/Master/ProductService.php @@ -34,12 +34,56 @@ public function __construct( * }> */ public function outOfStockGroups(): array + { + return $this->inventoryAlertGroups( + fn (ProductVariant $variant): bool => $variant->stock <= 0, + ); + } + + /** + * @return list>, + * }>, + * }> + */ + public function stockWarningGroups(): array + { + return $this->inventoryAlertGroups(function (ProductVariant $variant): bool { + if ($variant->stock <= 0) { + return false; + } + + return $variant->stock < ProductVariant::minStock(); + }); + } + + /** + * @return list>, + * }>, + * }> + */ + private function inventoryAlertGroups(callable $filter): array { return ProductVariant::query() ->with(['product', 'media']) - ->where('stock', '<=', 0) ->whereHas('product', fn (Builder $query) => $query->where('is_active', true)) ->get() + ->filter($filter) ->sortBy([ fn (ProductVariant $variant) => $variant->product->name, fn (ProductVariant $variant) => $variant->name, diff --git a/app/Services/Master/RawMaterialService.php b/app/Services/Master/RawMaterialService.php index f6b32b4..ca219dd 100644 --- a/app/Services/Master/RawMaterialService.php +++ b/app/Services/Master/RawMaterialService.php @@ -33,11 +33,61 @@ public function __construct( * }> */ public function outOfStockGroups(): array + { + return $this->inventoryAlertGroups( + fn (RawMaterialPrice $price): bool => (float) $price->stock <= 0, + ); + } + + /** + * @return list>, + * }>, + * }> + */ + public function stockWarningGroups(): array + { + return $this->inventoryAlertGroups(function (RawMaterialPrice $price): bool { + $stock = (float) $price->stock; + + if ($stock <= 0) { + return false; + } + + $minStock = $price->rawMaterial->unit->minStock(); + + return $stock < $minStock; + }); + } + + /** + * @return list>, + * }>, + * }> + */ + private function inventoryAlertGroups(callable $filter): array { return RawMaterialPrice::query() ->with(['rawMaterial', 'media']) - ->where('stock', '<=', 0) ->get() + ->filter($filter) ->sortBy([ fn (RawMaterialPrice $price) => $price->rawMaterial->name, fn (RawMaterialPrice $price) => $price->variant, diff --git a/resources/js/components/admin/master/MasterOutOfStockCatalogSection.vue b/resources/js/components/admin/master/MasterOutOfStockCatalogSection.vue index 931644f..e957338 100644 --- a/resources/js/components/admin/master/MasterOutOfStockCatalogSection.vue +++ b/resources/js/components/admin/master/MasterOutOfStockCatalogSection.vue @@ -1,6 +1,6 @@