refactor: [절곡] code/lot_no 분리 — 코드 체계와 LOT 번호 분리

- 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 문서 업데이트
This commit is contained in:
2026-03-21 15:06:55 +09:00
parent 78ff01d6b1
commit d6591acdff
8 changed files with 90 additions and 11 deletions

View File

@@ -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:스크린,철재',

View File

@@ -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:스크린,철재',

View File

@@ -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,

View File

@@ -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',

View File

@@ -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',

View File

@@ -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',

View File

@@ -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="가이드레일"),

View File

@@ -0,0 +1,70 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
public function up(): void
{
// ── bending_items ──
Schema::table('bending_items', function (Blueprint $table) {
$table->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');
});
}
};