- 데이터베이스 스키마 확장: BOM 테이블에 계산 관련 필드 추가 - 계산 엔진 구현: CalculationEngine, FormulaParser, ParameterValidator - API 구현: 견적 파라미터 추출, 실시간 BOM 계산, 업체별 산출식 관리 - FormRequest 검증: 모든 입력 데이터 검증 및 한국어 에러 메시지 - 라우트 등록: 5개 BOM 계산 API 엔드포인트 추가 주요 기능: • BOM에서 필요한 조건만 동적 추출하여 견적 화면에 표시 • 경동기업 하드코딩 산출식을 동적 시스템으로 전환 • 업체별 산출식 버전 관리 및 실시간 테스트 지원 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
265 lines
9.2 KiB
PHP
265 lines
9.2 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Design;
|
|
|
|
use App\Services\Service;
|
|
use App\Services\Calculation\CalculationEngine;
|
|
use App\Models\Design\BomTemplate;
|
|
use App\Models\Calculation\CalculationConfig;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class BomCalculationService extends Service
|
|
{
|
|
protected CalculationEngine $calculationEngine;
|
|
|
|
public function __construct(CalculationEngine $calculationEngine)
|
|
{
|
|
$this->calculationEngine = $calculationEngine;
|
|
}
|
|
|
|
/**
|
|
* 견적 파라미터 조회
|
|
* @param int $modelId 모델 ID
|
|
* @param string|null $companyName 업체명
|
|
* @return array
|
|
*/
|
|
public function getEstimateParameters(int $modelId, ?string $companyName = null): array
|
|
{
|
|
try {
|
|
// 모델의 기본 BOM 템플릿 조회
|
|
$bomTemplate = BomTemplate::with(['modelVersion.model'])
|
|
->where('tenant_id', $this->tenantId())
|
|
->whereHas('modelVersion', function ($query) use ($modelId) {
|
|
$query->whereHas('model', function ($q) use ($modelId) {
|
|
$q->where('id', $modelId);
|
|
});
|
|
})
|
|
->where('is_primary', true)
|
|
->first();
|
|
|
|
if (!$bomTemplate) {
|
|
throw new \Exception("모델 ID {$modelId}에 대한 BOM 템플릿을 찾을 수 없습니다.");
|
|
}
|
|
|
|
// 파라미터 스키마 추출
|
|
$parameters = $this->calculationEngine->getRequiredParameters($bomTemplate->id);
|
|
|
|
// 업체별 추가 파라미터가 있는지 확인
|
|
if ($companyName) {
|
|
$companyParameters = $this->getCompanySpecificParameters($companyName);
|
|
if ($companyParameters) {
|
|
$parameters = array_merge_recursive($parameters, $companyParameters);
|
|
}
|
|
}
|
|
|
|
return [
|
|
'model_info' => [
|
|
'id' => $bomTemplate->modelVersion->model->id,
|
|
'name' => $bomTemplate->modelVersion->model->name ?? '모델명 없음',
|
|
'version' => $bomTemplate->modelVersion->version_no ?? 'v1.0',
|
|
'bom_template_id' => $bomTemplate->id
|
|
],
|
|
'company_info' => [
|
|
'company_type' => $bomTemplate->company_type,
|
|
'formula_version' => $bomTemplate->formula_version,
|
|
'requested_company' => $companyName
|
|
],
|
|
'parameters' => $parameters,
|
|
'calculation_preview' => true
|
|
];
|
|
|
|
} catch (\Exception $e) {
|
|
Log::error('견적 파라미터 조회 실패', [
|
|
'model_id' => $modelId,
|
|
'company_name' => $companyName,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* BOM 계산 실행
|
|
* @param int $bomTemplateId BOM 템플릿 ID
|
|
* @param array $parameters 입력 파라미터
|
|
* @param string|null $companyName 업체명
|
|
* @return array
|
|
*/
|
|
public function calculateBomEstimate(int $bomTemplateId, array $parameters, ?string $companyName = null): array
|
|
{
|
|
try {
|
|
DB::beginTransaction();
|
|
|
|
// BOM 템플릿 조회 및 권한 확인
|
|
$bomTemplate = BomTemplate::where('tenant_id', $this->tenantId())
|
|
->findOrFail($bomTemplateId);
|
|
|
|
// 업체명이 지정된 경우 BOM 템플릿 업데이트
|
|
if ($companyName && $bomTemplate->company_type !== $companyName) {
|
|
$bomTemplate->update(['company_type' => $companyName]);
|
|
}
|
|
|
|
// 계산 엔진 실행
|
|
$result = $this->calculationEngine->calculateBOM($bomTemplateId, $parameters, $companyName);
|
|
|
|
// 계산 이력 로그 저장 (선택사항)
|
|
$this->logCalculationHistory($bomTemplateId, $parameters, $result, $companyName);
|
|
|
|
DB::commit();
|
|
|
|
return [
|
|
'success' => $result['success'],
|
|
'data' => $result['success'] ? $result : null,
|
|
'error' => $result['success'] ? null : $result['error']
|
|
];
|
|
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
Log::error('BOM 계산 실행 실패', [
|
|
'bom_template_id' => $bomTemplateId,
|
|
'parameters' => $parameters,
|
|
'company_name' => $companyName,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
|
|
return [
|
|
'success' => false,
|
|
'data' => null,
|
|
'error' => $e->getMessage()
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 업체별 산출식 목록 조회
|
|
* @param string $companyName 업체명
|
|
* @return array
|
|
*/
|
|
public function getCompanyFormulas(string $companyName): array
|
|
{
|
|
$formulas = CalculationConfig::getActiveFormulasForCompany($this->tenantId(), $companyName);
|
|
|
|
return [
|
|
'company_name' => $companyName,
|
|
'total_formulas' => count($formulas),
|
|
'formulas' => array_map(function ($formula) {
|
|
return [
|
|
'type' => $formula['formula_type'],
|
|
'version' => $formula['version'],
|
|
'description' => $formula['description'],
|
|
'parameters' => $formula['parameters'],
|
|
'updated_at' => $formula['updated_at']
|
|
];
|
|
}, $formulas)
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 업체별 산출식 등록/수정
|
|
* @param string $companyName 업체명
|
|
* @param string $formulaType 산출식 타입
|
|
* @param array $formulaData 산출식 데이터
|
|
* @return array
|
|
*/
|
|
public function saveCompanyFormula(string $companyName, string $formulaType, array $formulaData): array
|
|
{
|
|
try {
|
|
DB::beginTransaction();
|
|
|
|
// 기존 산출식이 있는지 확인
|
|
$existingFormula = CalculationConfig::getLatestFormula($this->tenantId(), $companyName, $formulaType);
|
|
|
|
if ($existingFormula) {
|
|
// 버전 업그레이드
|
|
$newVersion = $this->incrementVersion($existingFormula->version);
|
|
$existingFormula->update(['is_active' => false]); // 기존 비활성화
|
|
} else {
|
|
$newVersion = 'v1.0';
|
|
}
|
|
|
|
// 새 산출식 생성
|
|
$formula = CalculationConfig::create([
|
|
'tenant_id' => $this->tenantId(),
|
|
'company_name' => $companyName,
|
|
'formula_type' => $formulaType,
|
|
'version' => $newVersion,
|
|
'formula_expression' => $formulaData['formula_expression'],
|
|
'parameters' => $formulaData['parameters'],
|
|
'conditions' => $formulaData['conditions'] ?? null,
|
|
'validation_rules' => $formulaData['validation_rules'] ?? null,
|
|
'description' => $formulaData['description'] ?? null,
|
|
'is_active' => true,
|
|
'created_by' => $this->apiUserId()
|
|
]);
|
|
|
|
DB::commit();
|
|
|
|
return [
|
|
'id' => $formula->id,
|
|
'company_name' => $formula->company_name,
|
|
'formula_type' => $formula->formula_type,
|
|
'version' => $formula->version,
|
|
'is_active' => $formula->is_active,
|
|
'created_at' => $formula->created_at
|
|
];
|
|
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
Log::error('업체별 산출식 저장 실패', [
|
|
'company_name' => $companyName,
|
|
'formula_type' => $formulaType,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 업체별 추가 파라미터 조회
|
|
*/
|
|
protected function getCompanySpecificParameters(string $companyName): ?array
|
|
{
|
|
// 업체별 특수 파라미터가 있는지 확인
|
|
$companyConfig = CalculationConfig::forTenant($this->tenantId())
|
|
->forCompany($companyName)
|
|
->forType('additional_parameters')
|
|
->active()
|
|
->latest()
|
|
->first();
|
|
|
|
return $companyConfig ? $companyConfig->parameters : null;
|
|
}
|
|
|
|
/**
|
|
* 계산 이력 로그 저장
|
|
*/
|
|
protected function logCalculationHistory(int $bomTemplateId, array $parameters, array $result, ?string $companyName): void
|
|
{
|
|
// 필요에 따라 계산 이력을 별도 테이블에 저장
|
|
Log::info('BOM 계산 완료', [
|
|
'bom_template_id' => $bomTemplateId,
|
|
'company_name' => $companyName,
|
|
'parameters' => $parameters,
|
|
'success' => $result['success'],
|
|
'calculated_items_count' => $result['success'] ? count($result['bom_items']) : 0,
|
|
'calculated_by' => $this->apiUserId()
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 버전 번호 증가
|
|
*/
|
|
protected function incrementVersion(string $currentVersion): string
|
|
{
|
|
if (preg_match('/^v(\d+)\.(\d+)$/', $currentVersion, $matches)) {
|
|
$major = (int)$matches[1];
|
|
$minor = (int)$matches[2];
|
|
return "v{$major}." . ($minor + 1);
|
|
}
|
|
|
|
return 'v1.0';
|
|
}
|
|
} |