- Migrate5130BendingStock: BD-* 품목 초기 재고 셋팅으로 목적 변경, --min-stock 옵션 추가 - ValidateBendingItems: BD-* 품목 존재 여부 검증 커맨드 신규 - BendingItemSeeder: 경동 절곡 품목 시딩 신규 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
138 lines
5.1 KiB
PHP
138 lines
5.1 KiB
PHP
<?php
|
||
|
||
namespace App\Console\Commands;
|
||
|
||
use Illuminate\Console\Attributes\AsCommand;
|
||
use Illuminate\Console\Command;
|
||
use Illuminate\Support\Facades\DB;
|
||
|
||
#[AsCommand(name: 'bending:validate-items', description: 'BD-* 절곡 세부품목 마스터 데이터 검증 (prefix × lengthCode 전 조합)')]
|
||
class ValidateBendingItems extends Command
|
||
{
|
||
protected $signature = 'bending:validate-items
|
||
{--tenant_id=287 : Target tenant ID (default: 287 경동기업)}';
|
||
|
||
/**
|
||
* prefix별 유효 길이코드 정의
|
||
*
|
||
* 가이드레일: 30, 35, 40, 43 (벽면/측면 공통)
|
||
* 하단마감재: 30, 40
|
||
* 셔터박스: 12, 24, 30, 35, 40, 41
|
||
* 연기차단재: 53, 54, 83, 84 (W50/W80 전용 코드)
|
||
* XX: 12, 24, 30, 35, 40, 41, 43 (하부BASE + 셔터 상부/마구리)
|
||
* YY: 30, 35, 40, 43 (별도 SUS 마감)
|
||
* HH: 30, 40 (보강평철)
|
||
*/
|
||
private function getPrefixLengthCodes(): array
|
||
{
|
||
$guideRailCodes = ['30', '35', '40', '43'];
|
||
$guideRailCodesWithExtra = ['24', '30', '35', '40', '43']; // RT/ST는 적은 종류
|
||
$bottomBarCodes = ['30', '40'];
|
||
$shutterBoxCodes = ['12', '24', '30', '35', '40', '41'];
|
||
|
||
return [
|
||
// 가이드레일 벽면형
|
||
'RS' => $guideRailCodes, // 벽면 SUS 마감재
|
||
'RM' => ['24', '30', '35', '40', '42', '43'], // 벽면 본체 (EGI)
|
||
'RC' => ['24', '30', '35', '40', '42', '43'], // 벽면 C형
|
||
'RD' => ['24', '30', '35', '40', '42', '43'], // 벽면 D형
|
||
'RT' => ['30', '43'], // 벽면 본체 (철재)
|
||
|
||
// 가이드레일 측면형
|
||
'SS' => ['30', '35', '40'], // 측면 SUS 마감재
|
||
'SM' => ['24', '30', '35', '40', '43'], // 측면 본체 (EGI)
|
||
'SC' => ['24', '30', '35', '40', '43'], // 측면 C형
|
||
'SD' => ['24', '30', '35', '40', '43'], // 측면 D형
|
||
'ST' => ['43'], // 측면 본체 (철재)
|
||
'SU' => ['30', '35', '40', '43'], // 측면 SUS (SUS2)
|
||
|
||
// 하단마감재
|
||
'BE' => $bottomBarCodes, // EGI 마감
|
||
'BS' => ['24', '30', '35', '40', '43'], // SUS 마감
|
||
'TS' => ['43'], // 철재 SUS
|
||
'LA' => $bottomBarCodes, // L-Bar
|
||
|
||
// 셔터박스
|
||
'CF' => $shutterBoxCodes, // 전면부
|
||
'CL' => $shutterBoxCodes, // 린텔부
|
||
'CP' => $shutterBoxCodes, // 점검구
|
||
'CB' => $shutterBoxCodes, // 후면코너부
|
||
|
||
// 연기차단재
|
||
'GI' => ['53', '54', '83', '84', '30', '35', '40'], // W50/W80 + 일반
|
||
|
||
// 공용/기타
|
||
'XX' => ['12', '24', '30', '35', '40', '41', '43'], // 하부BASE/셔터 상부/마구리
|
||
'YY' => ['30', '35', '40', '43'], // 별도 SUS 마감
|
||
'HH' => ['30', '40'], // 보강평철
|
||
];
|
||
}
|
||
|
||
public function handle(): int
|
||
{
|
||
$tenantId = (int) $this->option('tenant_id');
|
||
|
||
$this->info("=== BD-* 절곡 세부품목 마스터 검증 (tenant: {$tenantId}) ===");
|
||
$this->newLine();
|
||
|
||
// DB에서 전체 BD-* 품목 조회
|
||
$existingItems = DB::table('items')
|
||
->where('tenant_id', $tenantId)
|
||
->where('code', 'like', 'BD-%')
|
||
->whereNull('deleted_at')
|
||
->pluck('code')
|
||
->toArray();
|
||
|
||
$existingSet = array_flip($existingItems);
|
||
|
||
$this->info('현재 등록된 BD-* 품목: '.count($existingItems).'개');
|
||
$this->newLine();
|
||
|
||
$prefixMap = $this->getPrefixLengthCodes();
|
||
$totalExpected = 0;
|
||
$missing = [];
|
||
$found = 0;
|
||
|
||
foreach ($prefixMap as $prefix => $codes) {
|
||
$prefixMissing = [];
|
||
foreach ($codes as $code) {
|
||
$itemCode = "BD-{$prefix}-{$code}";
|
||
$totalExpected++;
|
||
|
||
if (isset($existingSet[$itemCode])) {
|
||
$found++;
|
||
} else {
|
||
$prefixMissing[] = $itemCode;
|
||
$missing[] = $itemCode;
|
||
}
|
||
}
|
||
|
||
$status = empty($prefixMissing) ? '✅' : '❌';
|
||
$countStr = count($codes) - count($prefixMissing).'/'.count($codes);
|
||
$this->line(" {$status} BD-{$prefix}: {$countStr}");
|
||
|
||
if (! empty($prefixMissing)) {
|
||
foreach ($prefixMissing as $m) {
|
||
$this->line(" ⚠️ 누락: {$m}");
|
||
}
|
||
}
|
||
}
|
||
|
||
$this->newLine();
|
||
$this->info('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||
$this->info("검증 결과: {$found}/{$totalExpected} 등록 완료");
|
||
|
||
if (empty($missing)) {
|
||
$this->info('✅ All items registered — 누락 0건');
|
||
|
||
return self::SUCCESS;
|
||
}
|
||
|
||
$this->warn('❌ 누락 항목: '.count($missing).'건');
|
||
$this->newLine();
|
||
$this->table(['누락 품목코드'], array_map(fn ($m) => [$m], $missing));
|
||
|
||
return self::FAILURE;
|
||
}
|
||
}
|