feat: [작업지시/작업자화면] items.item 관계 로드, 부서 필터 개선, BD 재질 자동 매칭, 전개도 폭 매칭

This commit is contained in:
김보곤
2026-03-21 07:59:53 +09:00
parent 41177f8f6c
commit da1ea6d3b4
3 changed files with 189 additions and 31 deletions

View File

@@ -2,8 +2,7 @@
namespace App\Services;
use App\Models\BendingItem;
use App\Models\Orders\Order;
use App\Models\Items\Item;
class BendingCodeService extends Service
{
@@ -128,28 +127,19 @@ public function getCodeMap(): array
}
/**
* 드롭다운 선택 조합 → bending_items 품목 매핑 조회
* 드롭다운 선택 조합 → 품목(items) 매핑 조회
*
* legacy_code 패턴: BD-{prod}{spec}-{length} (예: BD-CP-30)
* 품목코드 패턴: BD-{prod}{spec}-{length} (예: BD-RC-24)
*/
public function resolveItem(string $prodCode, string $specCode, string $lengthCode): ?array
{
// 1차: code + length_code로 조회 (신규 LOT 체계)
$item = BendingItem::where('tenant_id', $this->tenantId())
->where('code', 'like', "{$prodCode}{$specCode}%")
->where('length_code', $lengthCode)
$itemCode = "BD-{$prodCode}{$specCode}-{$lengthCode}";
$item = Item::where('tenant_id', $this->tenantId())
->where('code', $itemCode)
->where('is_active', true)
->first();
// 2차: legacy_code 폴백
if (! $item) {
$legacyCode = "BD-{$prodCode}{$specCode}-{$lengthCode}";
$item = BendingItem::where('tenant_id', $this->tenantId())
->where('legacy_code', $legacyCode)
->where('is_active', true)
->first();
}
if (! $item) {
return null;
}
@@ -157,9 +147,9 @@ public function resolveItem(string $prodCode, string $specCode, string $lengthCo
return [
'item_id' => $item->id,
'item_code' => $item->code,
'item_name' => $item->item_name,
'specification' => $item->item_spec,
'unit' => 'EA',
'item_name' => $item->name,
'specification' => $item->getOption('item_spec'),
'unit' => $item->unit ?? 'EA',
];
}
@@ -202,4 +192,87 @@ public static function getMaterial(string $prodCode, string $specCode): ?string
{
return self::MATERIAL_MAP["{$prodCode}:{$specCode}"] ?? null;
}
/**
* 품목 코드(BD-XX-YY) → 매칭되는 bending_item의 전개 폭(width_sum) 반환
*
* 매칭 로직:
* BD-{prod}{spec}-{length} 파싱
* → PRODUCTS/SPECS에서 item_bending, item_sep, 키워드 추출
* → bending_items 검색 → bending_data 마지막 sum = 전개 폭
*/
public function getBendingWidthByItemCode(string $itemCode): ?float
{
if (! preg_match('/^BD-([A-Z])([A-Z])-(\d+)$/', $itemCode, $m)) {
return null;
}
$prodCode = $m[1];
$specCode = $m[2];
// 제품명 → item_bending 추출 (가이드레일(벽면형) → 가이드레일)
$productName = null;
foreach (self::PRODUCTS as $p) {
if ($p['code'] === $prodCode) {
$productName = $p['name'];
break;
}
}
if (! $productName) {
return null;
}
// 종류명 추출
$specName = null;
foreach (self::SPECS as $s) {
if ($s['code'] === $specCode && in_array($prodCode, $s['products'])) {
$specName = $s['name'];
break;
}
}
if (! $specName) {
return null;
}
// item_bending: 괄호 제거 (가이드레일(벽면형) → 가이드레일)
$itemBending = preg_replace('/\(.*\)/', '', $productName);
// item_sep 판단: 종류명 또는 제품명에 '철재' → 철재, 아니면 스크린
$itemSep = (str_contains($specName, '철재') || str_contains($productName, '철재'))
? '철재' : '스크린';
// bending_items 검색
$query = \App\Models\BendingItem::query()
->where('tenant_id', $this->tenantId())
->where('item_bending', $itemBending)
->where('item_sep', $itemSep)
->whereNotNull('bending_data');
// 가이드레일: 벽면형/측면형 구분 (item_name 키워드 매칭)
if (str_contains($productName, '벽면형')) {
$query->where('item_name', 'LIKE', '%벽면형%');
} elseif (str_contains($productName, '측면형')) {
$query->where('item_name', 'LIKE', '%측면형%');
}
// 종류 키워드 매칭 (본체, C형, D형, 전면, 점검구, 린텔 등)
$specKeyword = preg_replace('/\(.*\)/', '', $specName); // 본체(철재) → 본체
$query->where('item_name', 'LIKE', "%{$specKeyword}%");
// 최신 코드 우선
$bendingItem = $query->orderByDesc('code')->first();
if (! $bendingItem) {
return null;
}
// bending_data 마지막 항목의 sum = 전개 폭
$data = $bendingItem->bending_data;
if (empty($data)) {
return null;
}
$last = end($data);
return isset($last['sum']) ? (float) $last['sum'] : null;
}
}