feat: Implement category and unit selection for inventory items

- Added a new 'category' field to the InventoryItem entity and updated the database schema.
- Replaced free-text input for 'unit' and 'category' with select dropdowns in the AddItemModal.
- Introduced a new API endpoint to fetch metadata for units and categories.
- Updated inventory filtering logic to use the new 'category' field instead of 'consumable'.
- Enhanced validation for item creation and updates to ensure valid unit and category values.
- Updated tests to cover new functionality and ensure proper validation.
This commit is contained in:
hamed
2026-07-15 14:32:29 +03:30
parent defa0db023
commit 3e5dee0ad5
12 changed files with 513 additions and 36 deletions
+27 -5
View File
@@ -31,6 +31,7 @@ List the tenant's items plus the four derived stat counters.
"uuid": "…",
"name": "دستکش جراحی",
"consumable": "جراحی",
"category": "لوازم مصرفی و تزریقات",
"unit": "عدد",
"price": 250000,
"stock": 150,
@@ -45,11 +46,29 @@ List the tenant's items plus the four derived stat counters.
### GET `/api/v1/inventory-categories`
Distinct non-empty `consumable` values for the tenant — powers the filter dropdown.
Distinct non-empty `category` values **actually in use** by the tenant — powers the
filter dropdown. For the full list of allowed categories use `inventory-meta`.
#### Response `200`
```json
{ "success": true, "data": ["جراحی", "دندانپزشکی"] }
{ "success": true, "data": ["دارو", "لوازم آزمایشگاهی"] }
```
### GET `/api/v1/inventory-meta`
Backend-owned option lists for the item form. **Single source of truth** — the
admin never hardcodes units/categories. Values are plain Persian strings stored
as-is; the create/update endpoints validate against these lists.
#### Response `200`
```json
{
"success": true,
"data": {
"units": ["عدد", "بسته", "…", "سی‌سی", "میلی‌لیتر", "…"],
"categories": ["دارو", "لوازم مصرفی و تزریقات", "…", "سایر"]
}
}
```
### POST `/api/v1/inventory-item`
@@ -60,8 +79,9 @@ Create an item.
| Field | Type | Required | Notes |
|-------|------|----------|-------|
| `name` | string | ✅ | نام کالا |
| `consumable` | string | ❌ | «مصرفی» / گروه فیلتر |
| `unit` | string | ❌ | Default `عدد` |
| `consumable` | string | ❌ | «مصرفی» — یادداشت آزاد (سازگاری عقب‌رو) |
| `category` | string | ❌ | دسته‌بندی؛ باید یکی از `inventory-meta.categories` باشد. خالی → `null`. فرم ادمین آن را الزامی می‌کند |
| `unit` | string | ❌ | باید یکی از `inventory-meta.units` باشد. خالی → پیش‌فرض `عدد` |
| `price` | integer | ❌ | Rial, Default `0` |
| `stock` | integer | ❌ | Default `0` |
| `alertThreshold` | integer | ❌ | Default `0` |
@@ -74,7 +94,9 @@ Create an item.
#### Errors
| Status | Code | Cause |
|--------|------|-------|
| `422` | `ERR_VALIDATION_001` | `name` خالی است |
| `422` | `ERR_VALIDATION_001` | `name` خالی است (field `name`) |
| `422` | `ERR_VALIDATION_001` | `unit` خارج از لیست مجاز (field `unit`) |
| `422` | `ERR_VALIDATION_001` | `category` خارج از لیست مجاز (field `category`) |
| `403` | `ERR_FORBIDDEN_001` | پروفایل tenant یافت نشد |
### PATCH `/api/v1/inventory-item/{uuid}`