From d6591acdff0c9bf2a52369349a0da9786e36789d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EC=98=81=EB=B3=B4?= Date: Sat, 21 Mar 2026 15:06:55 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20[=EC=A0=88=EA=B3=A1]=20code/lot=5Fn?= =?UTF-8?q?o=20=EB=B6=84=EB=A6=AC=20=E2=80=94=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=B2=B4=EA=B3=84=EC=99=80=20LOT=20=EB=B2=88=ED=98=B8=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - bending_items.code: LOT번호(CP260319) → 코드체계(CP)만 저장 - bending_items.lot_no: 기존 code 값 이관 (LOT 번호) - bending_models.code: 전체코드(GR-KSS01-벽면형-SUS) → 접두사(GR)만 저장 - bending_models.lot_no: 기존 code 값 이관 - unique 제약: code → lot_no로 이동 - BendingCodeService.resolveItem: LIKE → 정확 매칭 - 검색: lot_no 필드 추가 - Swagger 문서 업데이트 --- .../Api/V1/BendingItemStoreRequest.php | 7 +- .../Api/V1/BendingItemUpdateRequest.php | 3 +- .../Resources/Api/V1/BendingItemResource.php | 1 + app/Models/BendingItem.php | 4 +- app/Services/BendingCodeService.php | 6 +- app/Services/BendingItemService.php | 4 +- app/Swagger/v1/BendingItemApi.php | 6 +- ...rate_code_and_lot_no_in_bending_tables.php | 70 +++++++++++++++++++ 8 files changed, 90 insertions(+), 11 deletions(-) create mode 100644 database/migrations/2026_03_21_100000_separate_code_and_lot_no_in_bending_tables.php diff --git a/app/Http/Requests/Api/V1/BendingItemStoreRequest.php b/app/Http/Requests/Api/V1/BendingItemStoreRequest.php index 302a13e2..b65e20bb 100644 --- a/app/Http/Requests/Api/V1/BendingItemStoreRequest.php +++ b/app/Http/Requests/Api/V1/BendingItemStoreRequest.php @@ -14,9 +14,10 @@ public function authorize(): bool public function rules(): array { return [ - 'code' => [ - 'required', 'string', 'max:50', - \Illuminate\Validation\Rule::unique('bending_items', 'code')->where('tenant_id', request()->header('X-TENANT-ID', app()->bound('tenant_id') ? app('tenant_id') : 1)), + 'code' => 'required|string|max:10', + 'lot_no' => [ + 'nullable', 'string', 'max:50', + \Illuminate\Validation\Rule::unique('bending_items', 'lot_no')->where('tenant_id', request()->header('X-TENANT-ID', app()->bound('tenant_id') ? app('tenant_id') : 1)), ], 'item_name' => 'required|string|max:50', 'item_sep' => 'required|in:스크린,철재', diff --git a/app/Http/Requests/Api/V1/BendingItemUpdateRequest.php b/app/Http/Requests/Api/V1/BendingItemUpdateRequest.php index 9cd0975b..296c3183 100644 --- a/app/Http/Requests/Api/V1/BendingItemUpdateRequest.php +++ b/app/Http/Requests/Api/V1/BendingItemUpdateRequest.php @@ -14,7 +14,8 @@ public function authorize(): bool public function rules(): array { return [ - 'code' => 'sometimes|string|max:100', + 'code' => 'sometimes|string|max:10', + 'lot_no' => 'nullable|string|max:50', 'name' => 'sometimes|string|max:200', 'item_name' => 'sometimes|string|max:50', 'item_sep' => 'sometimes|in:스크린,철재', diff --git a/app/Http/Resources/Api/V1/BendingItemResource.php b/app/Http/Resources/Api/V1/BendingItemResource.php index ef5ee98a..01552477 100644 --- a/app/Http/Resources/Api/V1/BendingItemResource.php +++ b/app/Http/Resources/Api/V1/BendingItemResource.php @@ -12,6 +12,7 @@ public function toArray(Request $request): array return [ 'id' => $this->id, 'code' => $this->code, + 'lot_no' => $this->lot_no, 'legacy_code' => $this->legacy_code, // 정규 컬럼 직접 참조 'item_name' => $this->item_name, diff --git a/app/Models/BendingItem.php b/app/Models/BendingItem.php index 06aab5d1..e0894de2 100644 --- a/app/Models/BendingItem.php +++ b/app/Models/BendingItem.php @@ -12,7 +12,8 @@ /** * 절곡 기초관리 마스터 * - * code: {제품Code}{종류Code}{YYMMDD} (예: CP260319 = 케이스 점검구) + * code: 코드 체계 (제품Code+종류Code, 예: CP = 케이스 점검구) + * lot_no: LOT 번호 (code+날짜+일련, 예: CP260319-02) * bending_data: 전개도 JSON 배열 [{no, input, rate, sum, color, aAngle}] */ class BendingItem extends Model @@ -24,6 +25,7 @@ class BendingItem extends Model protected $fillable = [ 'tenant_id', 'code', + 'lot_no', 'legacy_code', 'legacy_bending_id', 'item_name', diff --git a/app/Services/BendingCodeService.php b/app/Services/BendingCodeService.php index 4ae7e406..387f3b25 100644 --- a/app/Services/BendingCodeService.php +++ b/app/Services/BendingCodeService.php @@ -134,9 +134,9 @@ public function getCodeMap(): array */ public function resolveItem(string $prodCode, string $specCode, string $lengthCode): ?array { - // 1차: code + length_code로 조회 (신규 LOT 체계) + // 1차: code(코드 체계) + length_code로 조회 $item = BendingItem::where('tenant_id', $this->tenantId()) - ->where('code', 'like', "{$prodCode}{$specCode}%") + ->where('code', "{$prodCode}{$specCode}") ->where('length_code', $lengthCode) ->where('is_active', true) ->first(); @@ -156,7 +156,7 @@ public function resolveItem(string $prodCode, string $specCode, string $lengthCo return [ 'item_id' => $item->id, - 'item_code' => $item->code, + 'item_code' => $item->lot_no ?? $item->code, 'item_name' => $item->item_name, 'specification' => $item->item_spec, 'unit' => 'EA', diff --git a/app/Services/BendingItemService.php b/app/Services/BendingItemService.php index 92bf00ce..5d9e8228 100644 --- a/app/Services/BendingItemService.php +++ b/app/Services/BendingItemService.php @@ -20,6 +20,7 @@ public function list(array $params): LengthAwarePaginator fn ($q2) => $q2 ->where('item_name', 'like', "%{$v}%") ->orWhere('code', 'like', "%{$v}%") + ->orWhere('lot_no', 'like', "%{$v}%") ->orWhere('item_spec', 'like', "%{$v}%") ->orWhere('legacy_code', 'like', "%{$v}%") )) @@ -48,6 +49,7 @@ public function create(array $data): BendingItem return BendingItem::create([ 'tenant_id' => $this->tenantId(), 'code' => $data['code'], + 'lot_no' => $data['lot_no'] ?? null, 'legacy_code' => $data['legacy_code'] ?? null, 'legacy_bending_id' => $data['legacy_bending_id'] ?? null, 'item_name' => $data['item_name'] ?? $data['name'] ?? '', @@ -77,7 +79,7 @@ public function update(int $id, array $data): BendingItem $item = BendingItem::findOrFail($id); $columns = [ - 'code', 'item_name', 'item_sep', 'item_bending', + 'code', 'lot_no', 'item_name', 'item_sep', 'item_bending', 'material', 'item_spec', 'model_name', 'model_UA', 'rail_width', 'exit_direction', 'box_width', 'box_height', 'front_bottom', 'inspection_door', 'length_code', 'length_mm', diff --git a/app/Swagger/v1/BendingItemApi.php b/app/Swagger/v1/BendingItemApi.php index b3bd3ab7..620cfaac 100644 --- a/app/Swagger/v1/BendingItemApi.php +++ b/app/Swagger/v1/BendingItemApi.php @@ -8,7 +8,8 @@ * @OA\Schema( * schema="BendingItem", * @OA\Property(property="id", type="integer", example=431), - * @OA\Property(property="code", type="string", example="RS260319", description="LOT 코드: {제품Code}{종류Code}{YYMMDD}"), + * @OA\Property(property="code", type="string", example="RS", description="코드 체계 (제품Code+종류Code)"), + * @OA\Property(property="lot_no", type="string", nullable=true, example="RS260319", description="LOT 번호 (code+날짜+일련번호)"), * @OA\Property(property="legacy_code", type="string", nullable=true, example="BD-RS-30", description="이전 코드 (items 기반)"), * @OA\Property(property="item_name", type="string", example="SUS마감재"), * @OA\Property(property="item_sep", type="string", enum={"스크린","철재"}), @@ -120,7 +121,8 @@ public function show() {} * summary="절곡품 등록", * @OA\RequestBody(@OA\JsonContent( * required={"code","item_name","item_sep","item_bending","material"}, - * @OA\Property(property="code", type="string", example="RM260319", description="LOT 코드"), + * @OA\Property(property="code", type="string", example="RM", description="코드 체계 (prod+spec)"), + * @OA\Property(property="lot_no", type="string", nullable=true, example="RM260319", description="LOT 번호"), * @OA\Property(property="item_name", type="string", example="본체"), * @OA\Property(property="item_sep", type="string", enum={"스크린","철재"}), * @OA\Property(property="item_bending", type="string", example="가이드레일"), diff --git a/database/migrations/2026_03_21_100000_separate_code_and_lot_no_in_bending_tables.php b/database/migrations/2026_03_21_100000_separate_code_and_lot_no_in_bending_tables.php new file mode 100644 index 00000000..97a18a0d --- /dev/null +++ b/database/migrations/2026_03_21_100000_separate_code_and_lot_no_in_bending_tables.php @@ -0,0 +1,70 @@ +string('lot_no', 50)->nullable()->after('code')->comment('LOT 번호 (기존 code 값 이관)'); + }); + + // 기존 code → lot_no 이관, code에는 앞 2자리(prod+spec)만 남기기 + DB::statement("UPDATE bending_items SET lot_no = code, code = LEFT(code, 2) WHERE lot_no IS NULL"); + + // unique 제약 변경: code → lot_no + Schema::table('bending_items', function (Blueprint $table) { + // 기존 unique 제거 + $indexes = collect(DB::select("SHOW INDEX FROM bending_items WHERE Key_name = 'uk_tenant_code'")); + if ($indexes->isNotEmpty()) { + $table->dropUnique('uk_tenant_code'); + } + // lot_no에 unique 추가 + $table->unique(['tenant_id', 'lot_no', 'deleted_at'], 'uk_tenant_lot_no'); + // code 인덱스 유지 (필터용) + $table->index('code', 'idx_bending_code_type'); + }); + + // ── bending_models ── + Schema::table('bending_models', function (Blueprint $table) { + $table->string('lot_no', 100)->nullable()->after('code')->comment('전체 코드 (기존 code 값 이관)'); + }); + + // 기존 code → lot_no 이관, code에는 접두사만 남기기 (GR-, SB-, BB-) + DB::statement("UPDATE bending_models SET lot_no = code, code = CASE + WHEN code LIKE 'GR-%' THEN 'GR' + WHEN code LIKE 'SB-%' THEN 'SB' + WHEN code LIKE 'BB-%' THEN 'BB' + ELSE LEFT(code, 2) + END WHERE lot_no IS NULL"); + } + + public function down(): void + { + // bending_items: lot_no → code 복원 + DB::statement("UPDATE bending_items SET code = lot_no WHERE lot_no IS NOT NULL"); + Schema::table('bending_items', function (Blueprint $table) { + $indexes = collect(DB::select("SHOW INDEX FROM bending_items WHERE Key_name = 'uk_tenant_lot_no'")); + if ($indexes->isNotEmpty()) { + $table->dropUnique('uk_tenant_lot_no'); + } + $indexes2 = collect(DB::select("SHOW INDEX FROM bending_items WHERE Key_name = 'idx_bending_code_type'")); + if ($indexes2->isNotEmpty()) { + $table->dropIndex('idx_bending_code_type'); + } + $table->unique(['tenant_id', 'code', 'deleted_at'], 'uk_tenant_code'); + $table->dropColumn('lot_no'); + }); + + // bending_models: lot_no → code 복원 + DB::statement("UPDATE bending_models SET code = lot_no WHERE lot_no IS NOT NULL"); + Schema::table('bending_models', function (Blueprint $table) { + $table->dropColumn('lot_no'); + }); + } +};