Files
sam-api/app/Services/BendingCodeService.php
김보곤 daf292f687 feat: [bending] LOT 채번 코드맵 최신화 (경동기업 2026-03 기준)
- 종류 코드 신규: W(본체L120), F(SUS마감재L120), H(화이바원단W80)
- 길이 코드 신규: 06(610), 17(1750), 20(2000), 45(4500)
- 명칭 변경: 본체디딤(S:M), SUS마감재(3)(S:S/U), 화이바원단(W50)(G:I)
- 가이드레일(R/S)에서 EGI 종류 코드 제거
- MATERIAL_MAP 신규 조합 추가
2026-03-18 19:31:30 +09:00

204 lines
7.4 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\Orders\Order;
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' => '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,specification,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 번호 생성 (일련번호 suffix 포함)
*
* base: 'GI6317-53' → 결과: 'GI6317-53-001'
*/
public function generateLotNumber(string $lotBase): string
{
$tenantId = $this->tenantId();
// 같은 base로 시작하는 기존 LOT 수 조회
$count = Order::withoutGlobalScopes()
->where('tenant_id', $tenantId)
->where('order_type_code', Order::TYPE_STOCK)
->where('options->bending_lot->lot_number', 'LIKE', $lotBase.'-%')
->count();
$seq = str_pad($count + 1, 3, '0', STR_PAD_LEFT);
return "{$lotBase}-{$seq}";
}
/**
* 날짜 → 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;
}
}