feat: add support for individual consumable items in service items
- Introduced `consumables` field in `ServiceItem` to allow multiple individual items alongside inventory packages. - Created `ServiceItemConsumable` entity to manage individual consumable items linked to a service. - Updated `ServiceItemController` to handle CRUD operations for consumables. - Enhanced `ServiceDetailPage` and `ServiceItemFormModal` to display and manage consumables. - Added tests to ensure functionality for adding, updating, and validating consumables. - Updated API documentation to reflect changes in service item structure and consumables.
This commit is contained in:
@@ -17,6 +17,7 @@ use App\ClinicService\Service\ServiceItemAuditService;
|
||||
use App\ClinicService\Service\TariffService;
|
||||
use App\Clinic\Repository\ClinicRepository;
|
||||
use App\Doctor\Repository\DoctorRepository;
|
||||
use App\Inventory\Repository\InventoryItemRepository;
|
||||
use App\Inventory\Repository\InventoryPackageRepository;
|
||||
use App\Shared\Constant\ErrorCodes;
|
||||
use App\Shared\Controller\BaseController;
|
||||
@@ -44,6 +45,7 @@ class ClinicServiceController extends BaseController
|
||||
private readonly TariffRepository $tariffRepo,
|
||||
private readonly TariffService $tariffService,
|
||||
private readonly InventoryPackageRepository $packageRepo,
|
||||
private readonly InventoryItemRepository $inventoryItemRepo,
|
||||
private readonly ServiceItemAuditService $auditService,
|
||||
private readonly ServiceItemAuditLogRepository $auditLogRepo,
|
||||
private readonly EntityManagerInterface $em,
|
||||
@@ -98,6 +100,39 @@ class ClinicServiceController extends BaseController
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* `consumables: [{item_uuid, amount}]` را روی خدمت مینشاند. آرایهی خالی یعنی حذف
|
||||
* همهی اقلام. هر قلم باید متعلق به همان مطب/کلینیک باشد.
|
||||
*/
|
||||
private function applyConsumables(ServiceItem $item, array $data, string $entityType, ?int $entityId): ?JsonResponse
|
||||
{
|
||||
if (!array_key_exists('consumables', $data)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$lines = [];
|
||||
foreach ((array) ($data['consumables'] ?? []) as $raw) {
|
||||
$uuid = is_array($raw) ? ($raw['item_uuid'] ?? null) : null;
|
||||
if ($uuid === null || $uuid === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$inventoryItem = $this->inventoryItemRepo->findByUuid((string) $uuid);
|
||||
if ($inventoryItem === null
|
||||
|| $inventoryItem->getEntityType() !== $entityType
|
||||
|| $inventoryItem->getEntityId() !== $entityId
|
||||
) {
|
||||
return $this->error(ErrorCodes::ERR_VALIDATION_001, 'کالای انتخابشده یافت نشد', 422, 'consumables');
|
||||
}
|
||||
|
||||
$lines[] = ['item' => $inventoryItem, 'amount' => max(1, (int) ($raw['amount'] ?? 1))];
|
||||
}
|
||||
|
||||
$item->replaceConsumables($lines);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// ── Service Sections ─────────────────────────────────────────────────────
|
||||
|
||||
#[Route('/api/v1/service-sections', methods: ['GET'])]
|
||||
@@ -275,6 +310,10 @@ class ClinicServiceController extends BaseController
|
||||
if ($packageError !== null) {
|
||||
return $packageError;
|
||||
}
|
||||
$consumableError = $this->applyConsumables($item, $data, $entityType, $entityId);
|
||||
if ($consumableError !== null) {
|
||||
return $consumableError;
|
||||
}
|
||||
|
||||
$this->itemRepo->save($item);
|
||||
|
||||
@@ -325,6 +364,10 @@ class ClinicServiceController extends BaseController
|
||||
if ($packageError !== null) {
|
||||
return $packageError;
|
||||
}
|
||||
$consumableError = $this->applyConsumables($item, $data, $entityType, $entityId);
|
||||
if ($consumableError !== null) {
|
||||
return $consumableError;
|
||||
}
|
||||
|
||||
$this->itemRepo->save($item);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user