213 lines
8.3 KiB
PHP
213 lines
8.3 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\BendingItem;
|
|
use Illuminate\Pagination\LengthAwarePaginator;
|
|
|
|
class BendingItemService extends Service
|
|
{
|
|
public function list(array $params): LengthAwarePaginator
|
|
{
|
|
return BendingItem::query()
|
|
->when($params['item_sep'] ?? null, fn ($q, $v) => $q->where('item_sep', $v))
|
|
->when($params['item_bending'] ?? null, fn ($q, $v) => $q->where('item_bending', $v))
|
|
->when($params['material'] ?? null, fn ($q, $v) => $q->where('material', 'like', "%{$v}%"))
|
|
->when($params['model_UA'] ?? null, fn ($q, $v) => $q->where('model_UA', $v))
|
|
->when($params['model_name'] ?? null, fn ($q, $v) => $q->where('model_name', $v))
|
|
->when($params['legacy_bending_num'] ?? $params['legacy_bending_id'] ?? null, fn ($q, $v) => $q->where('legacy_bending_id', (int) $v))
|
|
->when($params['search'] ?? null, fn ($q, $v) => $q->where(
|
|
fn ($q2) => $q2
|
|
->where('item_name', 'like', "%{$v}%")
|
|
->orWhere('code', 'like', "%{$v}%")
|
|
->orWhere('item_spec', 'like', "%{$v}%")
|
|
->orWhere('legacy_code', 'like', "%{$v}%")
|
|
))
|
|
->orderByDesc('id')
|
|
->paginate($params['size'] ?? 50);
|
|
}
|
|
|
|
public function filters(): array
|
|
{
|
|
return [
|
|
'item_sep' => BendingItem::whereNotNull('item_sep')->distinct()->pluck('item_sep')->sort()->values(),
|
|
'item_bending' => BendingItem::whereNotNull('item_bending')->distinct()->pluck('item_bending')->sort()->values(),
|
|
'material' => BendingItem::whereNotNull('material')->distinct()->pluck('material')->sort()->values(),
|
|
'model_UA' => BendingItem::whereNotNull('model_UA')->distinct()->pluck('model_UA')->sort()->values(),
|
|
'model_name' => BendingItem::whereNotNull('model_name')->distinct()->pluck('model_name')->sort()->values(),
|
|
];
|
|
}
|
|
|
|
public function find(int $id): BendingItem
|
|
{
|
|
return BendingItem::findOrFail($id);
|
|
}
|
|
|
|
public function create(array $data): BendingItem
|
|
{
|
|
$code = $data['code'] ?? '';
|
|
|
|
// BD-XX 접두사 → 자동 채번 (BD-XX 또는 BD-XX.nn)
|
|
if (preg_match('/^BD-([A-Z]{2})$/i', $code, $m)) {
|
|
$code = $this->generateCode($m[1]);
|
|
}
|
|
|
|
return BendingItem::create([
|
|
'tenant_id' => $this->tenantId(),
|
|
'code' => $code,
|
|
'legacy_code' => $data['legacy_code'] ?? null,
|
|
'legacy_bending_id' => $data['legacy_bending_id'] ?? null,
|
|
'item_name' => $data['item_name'] ?? $data['name'] ?? '',
|
|
'item_sep' => $data['item_sep'] ?? null,
|
|
'item_bending' => $data['item_bending'] ?? null,
|
|
'material' => $data['material'] ?? null,
|
|
'item_spec' => $data['item_spec'] ?? null,
|
|
'model_name' => $data['model_name'] ?? null,
|
|
'model_UA' => $data['model_UA'] ?? null,
|
|
'rail_width' => $data['rail_width'] ?? null,
|
|
'exit_direction' => $data['exit_direction'] ?? null,
|
|
'box_width' => $data['box_width'] ?? null,
|
|
'box_height' => $data['box_height'] ?? null,
|
|
'front_bottom' => $data['front_bottom'] ?? $data['front_bottom_width'] ?? null,
|
|
'inspection_door' => $data['inspection_door'] ?? null,
|
|
'length_code' => $data['length_code'] ?? null,
|
|
'length_mm' => $data['length_mm'] ?? null,
|
|
'bending_data' => $data['bendingData'] ?? null,
|
|
'options' => $this->buildOptions($data),
|
|
'is_active' => true,
|
|
'created_by' => $this->apiUserId(),
|
|
]);
|
|
}
|
|
|
|
public function update(int $id, array $data): BendingItem
|
|
{
|
|
$item = BendingItem::findOrFail($id);
|
|
|
|
// code는 수정 불가 (고유 품목코드)
|
|
$columns = [
|
|
'item_name', 'item_sep', 'item_bending',
|
|
'material', 'item_spec', 'model_name', 'model_UA',
|
|
'rail_width', 'exit_direction', 'box_width', 'box_height',
|
|
'front_bottom', 'inspection_door', 'length_code', 'length_mm',
|
|
];
|
|
foreach ($columns as $col) {
|
|
if (array_key_exists($col, $data)) {
|
|
$item->{$col} = $data[$col];
|
|
}
|
|
}
|
|
if (array_key_exists('front_bottom_width', $data) && ! array_key_exists('front_bottom', $data)) {
|
|
$item->front_bottom = $data['front_bottom_width'];
|
|
}
|
|
|
|
// 전개도 (JSON 직접 저장)
|
|
if (array_key_exists('bendingData', $data)) {
|
|
$item->bending_data = $data['bendingData'];
|
|
}
|
|
|
|
// 비정형 속성
|
|
foreach (self::OPTION_KEYS as $key) {
|
|
if (array_key_exists($key, $data)) {
|
|
$item->setOption($key, $data[$key]);
|
|
}
|
|
}
|
|
|
|
$item->updated_by = $this->apiUserId();
|
|
$item->save();
|
|
|
|
return $item;
|
|
}
|
|
|
|
public function delete(int $id): bool
|
|
{
|
|
$item = BendingItem::findOrFail($id);
|
|
$item->deleted_by = $this->apiUserId();
|
|
$item->save();
|
|
|
|
return $item->delete();
|
|
}
|
|
|
|
private function buildOptions(array $data): ?array
|
|
{
|
|
$options = [];
|
|
foreach (self::OPTION_KEYS as $key) {
|
|
if (isset($data[$key])) {
|
|
$options[$key] = $data[$key];
|
|
}
|
|
}
|
|
|
|
return empty($options) ? null : $options;
|
|
}
|
|
|
|
private const OPTION_KEYS = [
|
|
'search_keyword', 'registration_date', 'author', 'memo',
|
|
'parent_num', 'modified_by',
|
|
];
|
|
|
|
/**
|
|
* 기초자료 코드 자동 채번
|
|
*
|
|
* BD-XX : 표준 형상 (재공품 코드 앞 5자리와 동일)
|
|
* BD-XX.nnn : 표준 대비 변형 (주문 수정 형상, 최대 999종)
|
|
*
|
|
* 첫 등록 → BD-XX (표준), 이후 → BD-XX.001~ (변형)
|
|
*/
|
|
private function generateCode(string $prefix): string
|
|
{
|
|
$prefix = strtoupper($prefix);
|
|
|
|
// BD-XX.nnn 형태 중 가장 큰 순번 조회
|
|
$lastDotCode = BendingItem::withoutGlobalScopes()
|
|
->where('code', 'like', "BD-{$prefix}.%")
|
|
->orderByRaw('CAST(SUBSTRING(code, ?) AS UNSIGNED) DESC', [strlen("BD-{$prefix}.") + 1])
|
|
->value('code');
|
|
|
|
// BD-XX (표준 형상) 존재 여부
|
|
$plainExists = BendingItem::withoutGlobalScopes()
|
|
->where('code', "BD-{$prefix}")
|
|
->exists();
|
|
|
|
if (! $lastDotCode && ! $plainExists) {
|
|
// 해당 분류 첫 등록 → BD-XX (표준 형상)
|
|
return "BD-{$prefix}";
|
|
}
|
|
|
|
if ($plainExists && ! $lastDotCode) {
|
|
// 표준만 있고 변형 없음 → 변형 001번 부여
|
|
return "BD-{$prefix}.001";
|
|
}
|
|
|
|
// 변형이 이미 있음 → 마지막 +1
|
|
preg_match('/\.(\d+)$/', $lastDotCode, $m);
|
|
$nextSeq = (int) ($m[1] ?? 0) + 1;
|
|
|
|
return "BD-{$prefix}.".str_pad($nextSeq, 3, '0', STR_PAD_LEFT);
|
|
}
|
|
|
|
/**
|
|
* 사용 가능한 분류코드 접두사 목록
|
|
*/
|
|
public function prefixes(): array
|
|
{
|
|
return BendingItem::withoutGlobalScopes()
|
|
->where('code', 'like', 'BD-%')
|
|
->selectRaw("CASE WHEN code LIKE 'BD-__.%' THEN SUBSTRING(code, 4, 2) ELSE SUBSTRING(code, 4, 2) END as prefix, COUNT(*) as cnt")
|
|
->groupBy('prefix')
|
|
->orderBy('prefix')
|
|
->pluck('cnt', 'prefix')
|
|
->toArray();
|
|
}
|
|
|
|
/** 분류코드 접두사 정의 */
|
|
public const PREFIX_LABELS = [
|
|
'RS' => '가이드레일 SUS마감재', 'RM' => '가이드레일 본체/보강', 'RC' => '가이드레일 C형',
|
|
'RD' => '가이드레일 D형', 'RE' => '가이드레일 측면마감', 'RT' => '가이드레일 절단판',
|
|
'RH' => '가이드레일 뒷보강', 'RN' => '가이드레일 비인정',
|
|
'CP' => '케이스 밑면판/점검구', 'CF' => '케이스 전면판', 'CB' => '케이스 후면코너/후면부',
|
|
'CL' => '케이스 린텔', 'CX' => '케이스 상부덮개',
|
|
'BS' => '하단마감재 SUS', 'BE' => '하단마감재 EGI', 'BH' => '하단마감재 보강평철',
|
|
'TS' => '철재 하단마감재 SUS', 'TE' => '철재 하단마감재 EGI',
|
|
'XE' => '마구리', 'LE' => 'L-BAR',
|
|
'ZP' => '특수 밑면/점검구', 'ZF' => '특수 전면판', 'ZB' => '특수 후면',
|
|
];
|
|
}
|