Files
sam-api/app/Services/BendingCodeService.php
유병철 8f8eae92f2 fix: [bending] 품목 resolveItem eager loading 컬럼 수정
- item 관계 로드 시 specification → attributes로 변경

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 21:13:24 +09:00

195 lines
7.2 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Services;
use App\Models\Production\BendingItemMapping;
class BendingCodeService extends Service
{
// =========================================================================
// 제품 코드 (7종)
// =========================================================================
public const PRODUCTS = [
['code' => 'R', 'name' => '가이드레일(벽면형)'],
['code' => 'S', 'name' => '가이드레일(측면형)'],
['code' => 'G', 'name' => '연기차단재'],
['code' => 'B', 'name' => '하단마감재(스크린)'],
['code' => 'T', 'name' => '하단마감재(철재)'],
['code' => 'L', 'name' => 'L-Bar'],
['code' => 'C', 'name' => '케이스'],
];
// =========================================================================
// 종류 코드 + 사용 가능 제품
// 경동기업 재공품 LOT 채번 규칙 기준 (2026-03 최신)
// =========================================================================
public const SPECS = [
['code' => 'M', 'name' => '본체', 'products' => ['R']],
['code' => 'M', 'name' => '본체디딤', 'products' => ['S']],
['code' => 'T', 'name' => '본체(철재)', 'products' => ['R', 'S']],
['code' => 'C', 'name' => 'C형', 'products' => ['R', 'S']],
['code' => 'D', 'name' => 'D형', 'products' => ['R', 'S']],
['code' => 'S', 'name' => 'SUS마감재', 'products' => ['R', 'B', 'T']],
['code' => 'S', 'name' => 'SUS마감재(3)', 'products' => ['S']],
['code' => 'U', 'name' => 'SUS마감재(3)', 'products' => ['S']],
['code' => 'W', 'name' => '본체(L120)', 'products' => ['R', 'S']],
['code' => 'F', 'name' => 'SUS마감재(L120)', 'products' => ['R', 'S']],
['code' => 'E', 'name' => 'EGI', 'products' => ['B', 'T']],
['code' => 'I', 'name' => '화이바원단(W50)', 'products' => ['G']],
['code' => 'H', 'name' => '화이바원단(W80)', 'products' => ['G']],
['code' => 'A', 'name' => '스크린용', 'products' => ['L']],
['code' => 'F', 'name' => '전면부', 'products' => ['C']],
['code' => 'P', 'name' => '점검구', 'products' => ['C']],
['code' => 'L', 'name' => '린텔부', 'products' => ['C']],
['code' => 'B', 'name' => '후면코너부', 'products' => ['C']],
];
// =========================================================================
// 모양&길이 코드
// 연기차단재(G)는 SMOKE_BARRIER, 그 외는 GENERAL 사용
// 신규 길이 발생 시 코드 추가 가능 (확장형)
// =========================================================================
public const LENGTHS_SMOKE_BARRIER = [
['code' => '53', 'name' => 'W50 × 3000'],
['code' => '54', 'name' => 'W50 × 4000'],
['code' => '83', 'name' => 'W80 × 3000'],
['code' => '84', 'name' => 'W80 × 4000'],
];
public const LENGTHS_GENERAL = [
['code' => '06', 'name' => '610'],
['code' => '12', 'name' => '1219'],
['code' => '17', 'name' => '1750'],
['code' => '20', 'name' => '2000'],
['code' => '24', 'name' => '2438'],
['code' => '30', 'name' => '3000'],
['code' => '35', 'name' => '3500'],
['code' => '40', 'name' => '4000'],
['code' => '41', 'name' => '4150'],
['code' => '42', 'name' => '4200'],
['code' => '43', 'name' => '4300'],
['code' => '45', 'name' => '4500'],
];
// =========================================================================
// 제품+종류 → 원자재(재질) 매핑
// =========================================================================
public const MATERIAL_MAP = [
// 연기차단재
'G:I' => '화이바원단',
'G:H' => '화이바원단',
// 하단마감재(스크린)
'B:S' => 'SUS 1.2T',
'B:E' => 'EGI 1.55T',
// 하단마감재(철재)
'T:S' => 'SUS 1.2T',
'T:E' => 'EGI 1.55T',
// L-Bar
'L:A' => 'EGI 1.55T',
// 가이드레일(벽면형)
'R:M' => 'EGI 1.55T',
'R:T' => 'EGI 1.55T',
'R:C' => 'EGI 1.55T',
'R:D' => 'EGI 1.55T',
'R:S' => 'SUS 1.2T',
'R:W' => 'EGI 1.55T',
'R:F' => 'SUS 1.2T',
// 가이드레일(측면형)
'S:M' => 'EGI 1.55T',
'S:T' => 'EGI 1.55T',
'S:C' => 'EGI 1.55T',
'S:D' => 'EGI 1.55T',
'S:S' => 'SUS 1.2T',
'S:U' => 'SUS 1.2T',
'S:W' => 'EGI 1.55T',
'S:F' => 'SUS 1.2T',
// 케이스
'C:F' => 'EGI 1.55T',
'C:P' => 'EGI 1.55T',
'C:L' => 'EGI 1.55T',
'C:B' => 'EGI 1.55T',
];
/**
* 코드맵 전체 반환 (프론트엔드 드롭다운 구성용)
*/
public function getCodeMap(): array
{
return [
'products' => self::PRODUCTS,
'specs' => self::SPECS,
'lengths' => [
'smoke_barrier' => self::LENGTHS_SMOKE_BARRIER,
'general' => self::LENGTHS_GENERAL,
],
'material_map' => self::MATERIAL_MAP,
];
}
/**
* 드롭다운 선택 조합 → items 테이블 품목 매핑 조회
*/
public function resolveItem(string $prodCode, string $specCode, string $lengthCode): ?array
{
$mapping = BendingItemMapping::where('tenant_id', $this->tenantId())
->where('prod_code', $prodCode)
->where('spec_code', $specCode)
->where('length_code', $lengthCode)
->where('is_active', true)
->with('item:id,code,name,attributes,unit')
->first();
if (! $mapping || ! $mapping->item) {
return null;
}
return [
'item_id' => $mapping->item->id,
'item_code' => $mapping->item->code,
'item_name' => $mapping->item->name,
'specification' => $mapping->item->specification,
'unit' => $mapping->item->unit ?? 'EA',
];
}
/**
* LOT 번호 생성 (일련번호 없음 — 같은 날 같은 조합은 동일 LOT)
*
* 예: prod='C', spec='L', length='30', date='2026-03-18' → 'CL6318-30'
*/
public function generateLotNumber(string $prodCode, string $specCode, string $lengthCode, string $date): string
{
$dateCode = self::generateDateCode($date);
return "{$prodCode}{$specCode}{$dateCode}-{$lengthCode}";
}
/**
* 날짜 → 4자리 날짜코드
*
* 2026-03-17 → '6317'
* 2026-10-05 → '6A05'
*/
public static function generateDateCode(string $date): string
{
$dt = \Carbon\Carbon::parse($date);
$year = $dt->year % 10;
$month = $dt->month;
$day = $dt->day;
$monthCode = $month >= 10
? chr(55 + $month) // 10=A, 11=B, 12=C
: (string) $month;
return $year.$monthCode.str_pad($day, 2, '0', STR_PAD_LEFT);
}
/**
* 제품+종류 → 원자재(재질) 반환
*/
public static function getMaterial(string $prodCode, string $specCode): ?string
{
return self::MATERIAL_MAP["{$prodCode}:{$specCode}"] ?? null;
}
}