refactor: prices.item_type_code 통합 및 하드코딩 제거

- 레거시 PRODUCT/MATERIAL 값을 실제 item_type(FG, PT 등)으로 마이그레이션
- Price 모델에서 하드코딩된 ITEM_TYPE_* 상수 제거
- PricingService.getCost()에서 하드코딩된 자재 유형 배열을
  common_codes.attributes.is_material 플래그 조회로 변경
- common_codes item_type 그룹에 is_material 플래그 추가
  - FG, PT: is_material = false (제품)
  - SM, RM, CS: is_material = true (자재)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-21 17:22:51 +09:00
parent b74297a75b
commit 8ab65e18d0
4 changed files with 169 additions and 12 deletions

View File

@@ -29,16 +29,8 @@ class Price extends Model
public const STATUS_FINALIZED = 'finalized';
// 품목 유형 (items.item_type)
public const ITEM_TYPE_FG = 'FG'; // Finished Goods (완제품)
public const ITEM_TYPE_PT = 'PT'; // Part (부품)
public const ITEM_TYPE_RM = 'RM'; // Raw Material (원자재)
public const ITEM_TYPE_SM = 'SM'; // Semi-finished (반제품)
public const ITEM_TYPE_CS = 'CS'; // Consumables/Supplies (소모품)
// 품목 유형은 common_codes 테이블의 code_group='item_type'에서 관리
// FG(완제품), PT(부품), RM(원자재), SM(반제품), CS(소모품)
protected $fillable = [
'tenant_id',

View File

@@ -385,8 +385,15 @@ public function getCost(array $params): array
'price_id' => null,
];
// 1순위: 자재인 경우 수입검사 입고단가 조회
if ($itemType === 'MATERIAL') {
// 1순위: 자재(is_material = true)인 경우 수입검사 입고단가 조회
// common_codes의 attributes.is_material 플래그로 자재 여부 판단
$isMaterial = DB::table('common_codes')
->where('code_group', 'item_type')
->where('code', $itemType)
->whereJsonContains('attributes->is_material', true)
->exists();
if ($isMaterial) {
$receipt = MaterialReceipt::query()
->where('material_id', $itemId)
->where('receipt_date', '<=', $date)

View File

@@ -0,0 +1,76 @@
<?php
/**
* prices 테이블의 item_type_code를 items 테이블의 실제 item_type으로 업데이트
*
* 배경:
* - 기존 products/materials 테이블이 items로 통합됨
* - prices 테이블의 item_type_code가 PRODUCT/MATERIAL (레거시)와 FG/PT/SM/RM/CS (신규) 혼재
* - 모든 값을 items.item_type 기준으로 통일
*/
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
// PRODUCT/MATERIAL 레거시 데이터를 실제 item_type으로 업데이트
$legacyPrices = DB::table('prices')
->whereIn('item_type_code', ['PRODUCT', 'MATERIAL'])
->get();
$updated = 0;
$failed = 0;
foreach ($legacyPrices as $price) {
// items 테이블에서 실제 item_type 조회
$item = DB::table('items')
->where('id', $price->item_id)
->whereNull('deleted_at')
->first();
if ($item && $item->item_type) {
DB::table('prices')
->where('id', $price->id)
->update(['item_type_code' => $item->item_type]);
$updated++;
Log::info('Price item_type_code updated', [
'price_id' => $price->id,
'old_value' => $price->item_type_code,
'new_value' => $item->item_type,
'item_id' => $price->item_id,
]);
} else {
$failed++;
Log::warning('Price item_type_code update failed - item not found', [
'price_id' => $price->id,
'item_type_code' => $price->item_type_code,
'item_id' => $price->item_id,
]);
}
}
Log::info('Migration completed: update_prices_item_type_code_to_actual_item_type', [
'total_legacy' => $legacyPrices->count(),
'updated' => $updated,
'failed' => $failed,
]);
}
/**
* Reverse the migrations.
* 주의: 원본 값 복원이 불가능하므로 롤백하지 않음
*/
public function down(): void
{
// 롤백 불가 (원본 PRODUCT/MATERIAL 정보 손실)
Log::warning('Rollback not supported for update_prices_item_type_code_to_actual_item_type');
}
};

View File

@@ -0,0 +1,82 @@
<?php
/**
* common_codes의 item_type 그룹에 is_material 플래그 추가
*
* - FG(완제품), PT(부품): is_material = false
* - SM(부자재), RM(원자재), CS(소모품): is_material = true
*
* 이 플래그는 수입검사 대상 여부 판단에 사용됨
* 추후 items 테이블의 개별 필드로 대체 예정
*/
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
// 제품 타입 (is_material = false)
$productTypes = ['FG', 'PT'];
// 자재 타입 (is_material = true)
$materialTypes = ['SM', 'RM', 'CS'];
foreach ($productTypes as $code) {
$this->updateAttributes($code, false);
}
foreach ($materialTypes as $code) {
$this->updateAttributes($code, true);
}
}
/**
* attributes JSON에 is_material 플래그 추가
*/
private function updateAttributes(string $code, bool $isMaterial): void
{
$record = DB::table('common_codes')
->where('code_group', 'item_type')
->where('code', $code)
->first();
if ($record) {
$attributes = json_decode($record->attributes ?? '{}', true);
$attributes['is_material'] = $isMaterial;
DB::table('common_codes')
->where('id', $record->id)
->update(['attributes' => json_encode($attributes)]);
}
}
/**
* Reverse the migrations.
*/
public function down(): void
{
// is_material 플래그 제거
$codes = ['FG', 'PT', 'SM', 'RM', 'CS'];
foreach ($codes as $code) {
$record = DB::table('common_codes')
->where('code_group', 'item_type')
->where('code', $code)
->first();
if ($record) {
$attributes = json_decode($record->attributes ?? '{}', true);
unset($attributes['is_material']);
DB::table('common_codes')
->where('id', $record->id)
->update(['attributes' => json_encode($attributes)]);
}
}
}
};