feat: 품목 코드 중복 시 에러 반환 및 중복 ID 제공
- DuplicateCodeException 커스텀 예외 추가 - 등록/수정 시 자동 코드 증가 기능 제거 - 중복 발견 시 duplicate_id, duplicate_code 함께 반환 - resolveUniqueCode(), resolveUniqueMaterialCode() 메서드 제거
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
namespace App\Services;
|
||||
|
||||
use App\Constants\SystemFields;
|
||||
use App\Exceptions\DuplicateCodeException;
|
||||
use App\Helpers\ItemTypeHelper;
|
||||
use App\Models\ItemMaster\ItemField;
|
||||
use App\Models\Materials\Material;
|
||||
@@ -448,8 +449,16 @@ public function createItem(array $data): Product|Material
|
||||
*/
|
||||
private function createProduct(array $data, int $tenantId, int $userId): Product
|
||||
{
|
||||
// 품목 코드 중복 시 자동 증가
|
||||
$data['code'] = $this->resolveUniqueCode($data['code'], $tenantId);
|
||||
// 품목 코드 중복 체크
|
||||
$code = $data['code'] ?? '';
|
||||
$existingProduct = Product::withTrashed()
|
||||
->where('tenant_id', $tenantId)
|
||||
->where('code', $code)
|
||||
->first();
|
||||
|
||||
if ($existingProduct) {
|
||||
throw new DuplicateCodeException($code, $existingProduct->id);
|
||||
}
|
||||
|
||||
// 동적 필드를 options에 병합
|
||||
$this->processDynamicOptions($data, 'products');
|
||||
@@ -470,9 +479,16 @@ private function createProduct(array $data, int $tenantId, int $userId): Product
|
||||
*/
|
||||
private function createMaterial(array $data, int $tenantId, int $userId, string $materialType): Material
|
||||
{
|
||||
// 품목 코드 중복 시 자동 증가 (Materials용)
|
||||
// 품목 코드 중복 체크
|
||||
$code = $data['code'] ?? $data['material_code'] ?? '';
|
||||
$data['material_code'] = $this->resolveUniqueMaterialCode($code, $tenantId);
|
||||
$existingMaterial = Material::withTrashed()
|
||||
->where('tenant_id', $tenantId)
|
||||
->where('material_code', $code)
|
||||
->first();
|
||||
|
||||
if ($existingMaterial) {
|
||||
throw new DuplicateCodeException($code, $existingMaterial->id);
|
||||
}
|
||||
|
||||
// 동적 필드를 options에 병합
|
||||
$this->processDynamicOptions($data, 'materials');
|
||||
@@ -481,7 +497,7 @@ private function createMaterial(array $data, int $tenantId, int $userId, string
|
||||
'tenant_id' => $tenantId,
|
||||
'created_by' => $userId,
|
||||
'material_type' => $materialType,
|
||||
'material_code' => $data['material_code'],
|
||||
'material_code' => $code,
|
||||
'name' => $data['name'],
|
||||
'unit' => $data['unit'],
|
||||
'category_id' => $data['category_id'] ?? null,
|
||||
@@ -498,104 +514,6 @@ private function createMaterial(array $data, int $tenantId, int $userId, string
|
||||
return Material::create($payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Material 코드 중복 체크 및 고유 코드 생성
|
||||
*/
|
||||
private function resolveUniqueMaterialCode(string $code, int $tenantId): string
|
||||
{
|
||||
$exists = Material::withTrashed()
|
||||
->where('tenant_id', $tenantId)
|
||||
->where('material_code', $code)
|
||||
->exists();
|
||||
|
||||
if (! $exists) {
|
||||
return $code;
|
||||
}
|
||||
|
||||
// 마지막이 숫자인지 확인
|
||||
if (preg_match('/^(.+?)(\d+)$/', $code, $matches)) {
|
||||
$prefix = $matches[1];
|
||||
$number = (int) $matches[2];
|
||||
$digits = strlen($matches[2]);
|
||||
|
||||
do {
|
||||
$number++;
|
||||
$newCode = $prefix.str_pad($number, $digits, '0', STR_PAD_LEFT);
|
||||
$exists = Material::withTrashed()
|
||||
->where('tenant_id', $tenantId)
|
||||
->where('material_code', $newCode)
|
||||
->exists();
|
||||
} while ($exists);
|
||||
|
||||
return $newCode;
|
||||
}
|
||||
|
||||
// 마지막이 문자면 -001 추가
|
||||
$suffix = 1;
|
||||
do {
|
||||
$newCode = $code.'-'.str_pad($suffix, 3, '0', STR_PAD_LEFT);
|
||||
$exists = Material::withTrashed()
|
||||
->where('tenant_id', $tenantId)
|
||||
->where('material_code', $newCode)
|
||||
->exists();
|
||||
$suffix++;
|
||||
} while ($exists);
|
||||
|
||||
return $newCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 중복되지 않는 고유 코드 생성
|
||||
*
|
||||
* - 중복 없으면 원본 반환
|
||||
* - 마지막이 숫자면 숫자 증가 (P-001 → P-002)
|
||||
* - 마지막이 문자면 -001 추가 (ABC → ABC-001)
|
||||
*/
|
||||
private function resolveUniqueCode(string $code, int $tenantId): string
|
||||
{
|
||||
// 삭제된 항목 포함해서 중복 체크
|
||||
$exists = Product::withTrashed()
|
||||
->where('tenant_id', $tenantId)
|
||||
->where('code', $code)
|
||||
->exists();
|
||||
|
||||
if (! $exists) {
|
||||
return $code;
|
||||
}
|
||||
|
||||
// 마지막이 숫자인지 확인 (예: P-001, ITEM123)
|
||||
if (preg_match('/^(.+?)(\d+)$/', $code, $matches)) {
|
||||
$prefix = $matches[1];
|
||||
$number = (int) $matches[2];
|
||||
$digits = strlen($matches[2]);
|
||||
|
||||
// 숫자 증가하며 고유 코드 찾기
|
||||
do {
|
||||
$number++;
|
||||
$newCode = $prefix.str_pad($number, $digits, '0', STR_PAD_LEFT);
|
||||
$exists = Product::withTrashed()
|
||||
->where('tenant_id', $tenantId)
|
||||
->where('code', $newCode)
|
||||
->exists();
|
||||
} while ($exists);
|
||||
|
||||
return $newCode;
|
||||
}
|
||||
|
||||
// 마지막이 문자면 -001 추가
|
||||
$suffix = 1;
|
||||
do {
|
||||
$newCode = $code.'-'.str_pad($suffix, 3, '0', STR_PAD_LEFT);
|
||||
$exists = Product::withTrashed()
|
||||
->where('tenant_id', $tenantId)
|
||||
->where('code', $newCode)
|
||||
->exists();
|
||||
$suffix++;
|
||||
} while ($exists);
|
||||
|
||||
return $newCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 품목 수정 (Product/Material 통합)
|
||||
*
|
||||
@@ -632,14 +550,14 @@ private function updateProduct(int $id, array $data): Product
|
||||
|
||||
// 코드 변경 시 중복 체크
|
||||
if (isset($data['code']) && $data['code'] !== $product->code) {
|
||||
$exists = Product::query()
|
||||
$existingProduct = Product::query()
|
||||
->where('tenant_id', $tenantId)
|
||||
->where('code', $data['code'])
|
||||
->where('id', '!=', $product->id)
|
||||
->exists();
|
||||
->first();
|
||||
|
||||
if ($exists) {
|
||||
throw new BadRequestHttpException(__('error.duplicate_code'));
|
||||
if ($existingProduct) {
|
||||
throw new DuplicateCodeException($data['code'], $existingProduct->id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -673,14 +591,14 @@ private function updateMaterial(int $id, array $data): Material
|
||||
// 코드 변경 시 중복 체크
|
||||
$newCode = $data['material_code'] ?? $data['code'] ?? null;
|
||||
if ($newCode && $newCode !== $material->material_code) {
|
||||
$exists = Material::query()
|
||||
$existingMaterial = Material::query()
|
||||
->where('tenant_id', $tenantId)
|
||||
->where('material_code', $newCode)
|
||||
->where('id', '!=', $material->id)
|
||||
->exists();
|
||||
->first();
|
||||
|
||||
if ($exists) {
|
||||
throw new BadRequestHttpException(__('error.duplicate_code'));
|
||||
if ($existingMaterial) {
|
||||
throw new DuplicateCodeException($newCode, $existingMaterial->id);
|
||||
}
|
||||
$data['material_code'] = $newCode;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user