- products 테이블: 6개 고정 필드 + attributes JSON - product_components 테이블: 수식/조건 + attributes JSON - tenant_stat_fields 테이블: 테넌트별 통계 필드 설정 - stat_snapshots 테이블: 통계 캐싱 - BP-MES CategoryFields Seeder: 제품/부품/절곡품 카테고리 필드 - BP-MES TenantStatFields Seeder: 통계 필드 설정 [변경 사항] 삭제: - 2025_11_13_120000_extend_products_table_for_bp_mes.php - 2025_11_13_120001_extend_product_components_table_for_bp_mes.php 추가: - 2025_11_14_000001_add_hybrid_fields_to_products_table.php - 2025_11_14_000002_add_attributes_to_product_components_table.php - 2025_11_14_000003_create_tenant_stat_fields_table.php - 2025_11_14_000004_create_stat_snapshots_table.php - BpMesCategoryFieldsSeeder.php - BpMesTenantStatFieldsSeeder.php [배경] 멀티테넌트 시스템의 유연성 확보를 위해 고정 필드를 최소화하고 동적 필드 시스템(category_fields + attributes JSON)으로 전환. 통계 성능을 위해 자주 조회하는 분류 필드(product_category, part_type)는 고정 컬럼으로 유지하고 인덱싱.
175 lines
6.3 KiB
PHP
175 lines
6.3 KiB
PHP
<?php
|
|
|
|
namespace Database\Seeders;
|
|
|
|
use Illuminate\Database\Seeder;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
/**
|
|
* BP-MES 테넌트 통계 필드 설정 시더
|
|
*
|
|
* 목적: BP-MES 테넌트가 통계를 내고 싶은 필드를 tenant_stat_fields 테이블에 선언
|
|
*
|
|
* 효과:
|
|
* - 일일 스케줄러가 이 필드들의 통계를 계산하여 stat_snapshots에 저장
|
|
* - 대시보드 및 통계 화면에서 빠른 조회 가능
|
|
* - 잠재적으로 MySQL Virtual Column 최적화 대상 식별
|
|
*
|
|
* 실행: php artisan db:seed --class=BpMesTenantStatFieldsSeeder
|
|
*
|
|
* @see /claudedocs/mes/ITEM_MANAGEMENT_MIGRATION_GUIDE.md
|
|
*/
|
|
class BpMesTenantStatFieldsSeeder extends Seeder
|
|
{
|
|
/**
|
|
* BP-MES 테넌트 ID (실제 환경에 맞게 수정 필요)
|
|
*/
|
|
private const TENANT_ID = 1;
|
|
|
|
public function run(): void
|
|
{
|
|
// 1. products 테이블의 통계 필드 정의
|
|
$productStatFields = [
|
|
// 마진율 통계 (중요 지표)
|
|
[
|
|
'target_table' => 'products',
|
|
'field_key' => 'margin_rate',
|
|
'field_name' => '마진율(%)',
|
|
'field_type' => 'decimal',
|
|
'aggregation_types' => ['avg', 'min', 'max'],
|
|
'is_critical' => true,
|
|
'display_order' => 1,
|
|
'description' => '제품별 마진율 통계 (평균, 최소, 최대)',
|
|
],
|
|
|
|
// 가공비 통계
|
|
[
|
|
'target_table' => 'products',
|
|
'field_key' => 'processing_cost',
|
|
'field_name' => '가공비(원)',
|
|
'field_type' => 'decimal',
|
|
'aggregation_types' => ['avg', 'sum', 'min', 'max'],
|
|
'is_critical' => true,
|
|
'display_order' => 2,
|
|
'description' => '가공비 통계 (평균, 합계, 최소, 최대)',
|
|
],
|
|
|
|
// 인건비 통계
|
|
[
|
|
'target_table' => 'products',
|
|
'field_key' => 'labor_cost',
|
|
'field_name' => '인건비(원)',
|
|
'field_type' => 'decimal',
|
|
'aggregation_types' => ['avg', 'sum', 'min', 'max'],
|
|
'is_critical' => true,
|
|
'display_order' => 3,
|
|
'description' => '인건비 통계 (평균, 합계, 최소, 최대)',
|
|
],
|
|
|
|
// 설치비 통계
|
|
[
|
|
'target_table' => 'products',
|
|
'field_key' => 'install_cost',
|
|
'field_name' => '설치비(원)',
|
|
'field_type' => 'decimal',
|
|
'aggregation_types' => ['avg', 'sum', 'min', 'max'],
|
|
'is_critical' => true,
|
|
'display_order' => 4,
|
|
'description' => '설치비 통계 (평균, 합계, 최소, 최대)',
|
|
],
|
|
|
|
// 절곡 길이 통계 (선택적)
|
|
[
|
|
'target_table' => 'products',
|
|
'field_key' => 'bending_length',
|
|
'field_name' => '절곡길이(mm)',
|
|
'field_type' => 'decimal',
|
|
'aggregation_types' => ['avg', 'min', 'max'],
|
|
'is_critical' => false,
|
|
'display_order' => 10,
|
|
'description' => '절곡품 길이 통계 (선택적 집계)',
|
|
],
|
|
|
|
// 조립 길이 통계 (선택적)
|
|
[
|
|
'target_table' => 'products',
|
|
'field_key' => 'assembly_length',
|
|
'field_name' => '조립길이(mm)',
|
|
'field_type' => 'decimal',
|
|
'aggregation_types' => ['avg', 'min', 'max'],
|
|
'is_critical' => false,
|
|
'display_order' => 11,
|
|
'description' => '부품 조립 길이 통계 (선택적 집계)',
|
|
],
|
|
|
|
// 측면 규격 통계 (선택적)
|
|
[
|
|
'target_table' => 'products',
|
|
'field_key' => 'side_spec_width',
|
|
'field_name' => '측면규격_폭(mm)',
|
|
'field_type' => 'decimal',
|
|
'aggregation_types' => ['avg', 'min', 'max'],
|
|
'is_critical' => false,
|
|
'display_order' => 12,
|
|
'description' => '측면 규격 폭 통계 (선택적 집계)',
|
|
],
|
|
|
|
[
|
|
'target_table' => 'products',
|
|
'field_key' => 'side_spec_height',
|
|
'field_name' => '측면규격_높이(mm)',
|
|
'field_type' => 'decimal',
|
|
'aggregation_types' => ['avg', 'min', 'max'],
|
|
'is_critical' => false,
|
|
'display_order' => 13,
|
|
'description' => '측면 규격 높이 통계 (선택적 집계)',
|
|
],
|
|
];
|
|
|
|
// 2. materials 테이블의 통계 필드 정의 (향후 확장용 예시)
|
|
$materialStatFields = [
|
|
// 예시: 자재 단가 통계
|
|
[
|
|
'target_table' => 'materials',
|
|
'field_key' => 'unit_price',
|
|
'field_name' => '단가(원)',
|
|
'field_type' => 'decimal',
|
|
'aggregation_types' => ['avg', 'min', 'max'],
|
|
'is_critical' => false,
|
|
'display_order' => 1,
|
|
'description' => '자재 단가 통계 (향후 활용)',
|
|
],
|
|
];
|
|
|
|
// 3. products 통계 필드 생성
|
|
foreach ($productStatFields as $field) {
|
|
$this->insertTenantStatField($field);
|
|
}
|
|
|
|
// 4. materials 통계 필드 생성 (향후 확장)
|
|
foreach ($materialStatFields as $field) {
|
|
$this->insertTenantStatField($field);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* tenant_stat_fields 테이블에 필드 삽입
|
|
*/
|
|
private function insertTenantStatField(array $field): void
|
|
{
|
|
DB::table('tenant_stat_fields')->insert([
|
|
'tenant_id' => self::TENANT_ID,
|
|
'target_table' => $field['target_table'],
|
|
'field_key' => $field['field_key'],
|
|
'field_name' => $field['field_name'],
|
|
'field_type' => $field['field_type'],
|
|
'aggregation_types' => json_encode($field['aggregation_types']),
|
|
'is_critical' => $field['is_critical'],
|
|
'display_order' => $field['display_order'],
|
|
'description' => $field['description'],
|
|
'created_at' => now(),
|
|
'updated_at' => now(),
|
|
]);
|
|
}
|
|
}
|