Files
sam-api/app/Models/Items/Item.php
kent 02e268e49a docs(API): 견적 BOM 산출 작업 현황 및 Item 모델 주석 추가
- Item 모델 item_category 필드 주석 추가
- CURRENT_WORKS.md 견적 자동산출 작업 현황 업데이트
- LOGICAL_RELATIONSHIPS.md 관계 문서 업데이트

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

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-02 21:06:06 +09:00

209 lines
5.6 KiB
PHP

<?php
namespace App\Models\Items;
use App\Models\Commons\Category;
use App\Models\Commons\File;
use App\Models\Commons\Tag;
use App\Traits\BelongsToTenant;
use App\Traits\ModelTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* 통합 품목 모델
*
* products + materials를 통합한 단일 품목 테이블
* item_type: FG(완제품), PT(부품), SM(부자재), RM(원자재), CS(소모품)
*/
class Item extends Model
{
use BelongsToTenant, ModelTrait, SoftDeletes;
protected $fillable = [
'tenant_id',
'item_type',
'item_category', // 품목 카테고리 (SCREEN, STEEL, BENDING, ALUMINUM 등)
'code',
'name',
'unit',
'category_id',
'bom',
'attributes',
'attributes_archive',
'options',
'description',
'is_active',
'created_by',
'updated_by',
];
protected $casts = [
'bom' => 'array',
'attributes' => 'array',
'attributes_archive' => 'array',
'options' => 'array',
'is_active' => 'boolean',
];
protected $hidden = [
'deleted_at',
];
/**
* item_type 상수
*/
public const TYPE_FINISHED_GOODS = 'FG'; // 완제품
public const TYPE_PARTS = 'PT'; // 부품
public const TYPE_SUB_MATERIALS = 'SM'; // 부자재
public const TYPE_RAW_MATERIALS = 'RM'; // 원자재
public const TYPE_CONSUMABLES = 'CS'; // 소모품
/**
* Products 타입 (FG, PT)
*/
public const PRODUCT_TYPES = ['FG', 'PT'];
/**
* Materials 타입 (SM, RM, CS)
*/
public const MATERIAL_TYPES = ['SM', 'RM', 'CS'];
// ──────────────────────────────────────────────────────────────
// 관계
// ──────────────────────────────────────────────────────────────
/**
* 상세 정보 (1:1)
*/
public function details()
{
return $this->hasOne(ItemDetail::class);
}
/**
* 카테고리
*/
public function category()
{
return $this->belongsTo(Category::class, 'category_id');
}
/**
* BOM 자식 품목들 (JSON bom 필드 기반)
* 주의: 이 관계는 bom JSON에서 child_item_id를 추출하여 조회
*/
public function bomChildren()
{
$childIds = collect($this->bom ?? [])->pluck('child_item_id')->filter()->toArray();
return self::whereIn('id', $childIds);
}
/**
* 파일 (document_id/document_type 기반)
*
* ItemsFileController가 document_id=item_id, document_type='1'(group_id)로 저장
* morphMany(fileable) 대신 hasMany + where 조건 사용
*/
public function files()
{
return $this->hasMany(File::class, 'document_id')
->where('document_type', '1'); // ITEM_GROUP_ID
}
/**
* 태그 (폴리모픽)
*/
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable');
}
// ──────────────────────────────────────────────────────────────
// 스코프
// ──────────────────────────────────────────────────────────────
/**
* 특정 타입 필터
*/
public function scopeType($query, string $type)
{
return $query->where('item_type', strtoupper($type));
}
/**
* Products 타입만 (FG, PT)
*/
public function scopeProducts($query)
{
return $query->whereIn('item_type', self::PRODUCT_TYPES);
}
/**
* Materials 타입만 (SM, RM, CS)
*/
public function scopeMaterials($query)
{
return $query->whereIn('item_type', self::MATERIAL_TYPES);
}
/**
* 활성 품목만
*/
public function scopeActive($query)
{
return $query->where('is_active', true);
}
// ──────────────────────────────────────────────────────────────
// 헬퍼 메서드
// ──────────────────────────────────────────────────────────────
/**
* Product 타입인지 확인
*/
public function isProduct(): bool
{
return in_array($this->item_type, self::PRODUCT_TYPES);
}
/**
* Material 타입인지 확인
*/
public function isMaterial(): bool
{
return in_array($this->item_type, self::MATERIAL_TYPES);
}
/**
* BOM 자식 품목 ID 목록 추출
*/
public function getBomChildIds(): array
{
return collect($this->bom ?? [])->pluck('child_item_id')->filter()->toArray();
}
/**
* BOM 자식 품목들 조회 및 모델에 설정
*/
public function loadBomChildren(): self
{
$childIds = $this->getBomChildIds();
if (empty($childIds)) {
$this->setRelation('bom_children', collect());
return $this;
}
$children = self::whereIn('id', $childIds)->get()->keyBy('id');
$this->setRelation('bom_children', $children);
return $this;
}
}