- erp-api-list.md: Phase 5 섹션 추가 (12개 API) - erp-api-detail.md: Phase 5 상세 스펙 추가 - 13. 사용자 초대 (5개): 목록, 발송, 수락, 취소, 재발송 - 14. 알림 설정 (3개): 조회, 수정, 일괄수정 - 15. 계정 관리 (4개): 탈퇴, 사용중지, 약관조회, 약관수정
19 KiB
19 KiB
비즈니스 로직 분석
분석 대상: 5130 레거시 견적 시스템 비즈니스 로직 분석 일자: 2025-12-19
비즈니스 프로세스 개요
견적 생성 플로우
┌─────────────────────────────────────────────────────────────┐
│ 1. 견적 시작 │
│ └─ 신규 / 복사 / 수주연계 │
├─────────────────────────────────────────────────────────────┤
│ 2. 기본 정보 입력 │
│ └─ 현장명, 발주처, 담당자 │
├─────────────────────────────────────────────────────────────┤
│ 3. 제품 선택 │
│ ├─ 대분류: 스크린 / 철재 │
│ ├─ 모델: KSS01, KFS01 등 │
│ └─ 규격: 폭, 높이, 마구리윙 │
├─────────────────────────────────────────────────────────────┤
│ 4. 옵션 선택 │
│ └─ 절곡, 모터, 보증, 슬랫, 부자재 │
├─────────────────────────────────────────────────────────────┤
│ 5. 상세 항목 입력 │
│ ├─ 각 행별 위치, 폭, 높이, 수량 입력 │
│ └─ 자동 계산 트리거 │
├─────────────────────────────────────────────────────────────┤
│ 6. 금액 계산 (자동) │
│ ├─ AJAX → get_screen_amount / get_slat_amount │
│ ├─ 18개 항목별 단가 조회 및 계산 │
│ └─ 합계 산출 │
├─────────────────────────────────────────────────────────────┤
│ 7. 할인 적용 │
│ └─ 할인율 / 할인액 입력 → 최종금액 계산 │
├─────────────────────────────────────────────────────────────┤
│ 8. 저장 │
│ ├─ 견적번호 생성 (KD-PR-YYMMDD-NN) │
│ └─ DB 저장 (estimate 테이블) │
└─────────────────────────────────────────────────────────────┘
1. 견적 유형별 처리
스크린 견적 (Screen)
| 특성 | 값 |
|---|---|
| 대분류 | 스크린 |
| 주자재 소재 | 실리카, 와이어 |
| 면적 계산 | (높이 + 550) × 폭 / 1,000,000 m² |
| 기본 제작폭 | 160mm |
| 전용 항목 | L바, 보강평철, 무게평철, 환봉 |
슬랫 견적 (Slat/철재)
| 특성 | 값 |
|---|---|
| 대분류 | 철재 |
| 주자재 소재 | 방화슬랫 |
| 면적 계산 | (높이 + 50) × 폭 / 1,000,000 m² |
| 기본 제작폭 | 110mm |
| 전용 항목 | 조인트바 |
2. 옵션 체크박스 로직
옵션별 영향 항목
| 옵션 | 변수 | 영향받는 항목 |
|---|---|---|
| 절곡 | steel |
케이스, 케이스용 연기차단재, 마구리, 가이드레일, 레일용 연기차단재, 하장바, L바(스크린), 보강평철(스크린) |
| 모터 | motor |
모터 가격 포함/미포함 |
| 보증 | warranty |
보증기간 표시 (인정) |
| 슬랫 | slatcheck |
주자재(슬랫), 조인트바 |
| 부자재 | partscheck |
감기샤프트, 각파이프, 앵글 |
조건부 계산 로직
// 절곡 옵션 체크 시
if ($steel == '1') {
// 케이스, 연기차단재, 레일, 하장바 등 계산
$caseAmount = calculateCase($width, $caseType, $itemList);
$smokebanAmount = calculateSmokeban($width, $itemList);
// ...
} else {
// 해당 항목 0원 처리
$caseAmount = 0;
$smokebanAmount = 0;
}
// 모터 옵션 체크 시
if ($motor == '1') {
$motorAmount = getMotorPrice($motorCapacity);
} else {
$motorAmount = 0;
}
3. 단가 조회 로직
조회 우선순위
- BDmodels 테이블: 모델별 품목 단가
- price_ 테이블*: 품목별 세부 단가
- 기본값: 조회 실패 시 기본 단가 적용
단가 조회 함수
// fetch_unitprice.php
// 1. 모터 단가 조회
function getMotorPrice($capacity) {
// price_motor 테이블에서 용량별 단가 조회
$sql = "SELECT unit_price FROM price_motor WHERE capacity = ?";
// ...
}
// 2. 샤프트 단가 조회
function getShaftPrice($length) {
// price_shaft 테이블에서 길이별 단가 조회
$sql = "SELECT unit_price FROM price_shaft WHERE ? BETWEEN min_length AND max_length";
// ...
}
// 3. BDmodels에서 품목 단가 조회
function getBDModelPrice($modelname, $itemname, $size) {
$sql = "SELECT itemList FROM BDmodels WHERE modelname = ? AND itemname = ?";
// JSON 파싱 후 사이즈에 맞는 가격 반환
}
4. 금액 계산 플로우
스크린 금액 계산 (get_screen_amount.php)
┌─────────────────────────────────────────────────────────────┐
│ 입력값 │
│ - 폭(col2), 높이(col3), 수량(col4), 소재(col5) │
│ - 케이스타입(col6), 레일타입(col7), 설치방식(col8) │
│ - 체크박스옵션 (steel, motor, warranty, slatcheck, partscheck)│
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 1. 면적 계산 │
│ area = (height + 550) × width / 1,000,000 │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 2. 중량 계산 (모터 용량 결정용) │
│ weight = area × 소재별_단위중량 │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 3. 모터 용량 결정 │
│ motorCapacity = searchBracketSize(weight, inch) │
│ → 150K / 300K / 500K / 800K / 1000K │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 4. 18개 항목별 금액 계산 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 1. 검사비: inspectionFee (고정) │ │
│ │ 2. 주자재: area × 소재단가 │ │
│ │ 3. 모터: getMotorPrice(capacity) × motor체크 │ │
│ │ 4. 제어기: getControllerPrice(type) × motor체크 │ │
│ │ 5. 케이스: (width+제작폭) × m당단가 × steel체크 │ │
│ │ 6. 케이스연기차단재: width × m당단가 × steel체크 │ │
│ │ 7. 마구리: 2개 × 개당단가 × steel체크 │ │
│ │ 8. 앵글: 규격별단가 × steel체크 │ │
│ │ 9. 가이드레일: (height+레일여유) × m당단가 × steel │ │
│ │ 10. 레일연기차단재: height × m당단가 × steel │ │
│ │ 11. 하장바: width × m당단가 × steel체크 │ │
│ │ 12. L바: width × m당단가 × steel체크 │ │
│ │ 13. 보강평철: width × m당단가 × steel체크 │ │
│ │ 14. 샤프트: getShaftPrice(width) × partscheck │ │
│ │ 15. 무게평철: weight계산 × 단가 │ │
│ │ 16. 환봉: 길이계산 × m당단가 │ │
│ │ 17. 각파이프: 길이계산 × m당단가 × partscheck │ │
│ │ 18. 앵글: 길이계산 × m당단가 × partscheck │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 5. 행 합계 │
│ rowTotal = Σ(항목별금액) × 수량 │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 6. 전체 합계 │
│ estimateTotal = Σ(모든행 rowTotal) │
│ EstimateFinalSum = estimateTotal - 할인액 │
└─────────────────────────────────────────────────────────────┘
5. 모터 용량 결정 로직
중량 + 인치 기반 판단
function searchBracketSize($motorWeight, $bracketInch = null) {
$weight = floatval($motorWeight);
$inch = intval($bracketInch);
// 인치별 중량 기준
if ($inch > 0) {
// 4인치 기준
if ($inch == 4 && $weight <= 300) → 300K
if ($inch == 4 && $weight <= 400) → 400K
// 5인치 기준
if ($inch == 5 && $weight <= 246) → 300K
if ($inch == 5 && $weight <= 327) → 400K
if ($inch == 5 && $weight <= 500) → 500K
if ($inch == 5 && $weight <= 600) → 600K
// 6인치 기준
if ($inch == 6 && $weight <= 208) → 300K
if ($inch == 6 && $weight <= 277) → 400K
if ($inch == 6 && $weight <= 424) → 500K
if ($inch == 6 && $weight <= 508) → 600K
if ($inch == 6 && $weight <= 800) → 800K
if ($inch == 6 && $weight <= 1000) → 1000K
// 8인치 기준
if ($inch == 8 && $weight <= 324) → 500K
if ($inch == 8 && $weight <= 388) → 600K
if ($inch == 8 && $weight <= 611) → 800K
if ($inch == 8 && $weight <= 1000) → 1000K
} else {
// 인치 없이 중량만으로 판단
if ($weight <= 300) → 300K
if ($weight <= 400) → 400K
if ($weight <= 500) → 500K
if ($weight <= 600) → 600K
if ($weight <= 800) → 800K
if ($weight <= 1000) → 1000K
}
}
브라켓 사이즈 매핑
| 모터 용량 | 브라켓 사이즈 |
|---|---|
| 300K, 400K | 530×320 |
| 500K, 600K | 600×350 |
| 800K, 1000K | 690×390 |
6. 견적번호 생성
형식
KD-PR-YYMMDD-NN
KD: 경동 (회사코드)
PR: 프로젝트
YYMMDD: 날짜 (년월일 6자리)
NN: 일련번호 (01~99, 당일 기준)
생성 로직
// generate_serial_pjnum.php
function generatePjnum($pdo) {
$today = date('ymd');
$prefix = "KD-PR-{$today}-";
// 오늘 날짜의 마지막 번호 조회
$sql = "SELECT pjnum FROM estimate
WHERE pjnum LIKE ?
ORDER BY pjnum DESC LIMIT 1";
$stmh = $pdo->prepare($sql);
$stmh->execute([$prefix . '%']);
$row = $stmh->fetch();
if ($row) {
// 마지막 번호 추출 후 +1
$lastNum = intval(substr($row['pjnum'], -2));
$nextNum = str_pad($lastNum + 1, 2, '0', STR_PAD_LEFT);
} else {
$nextNum = '01';
}
return $prefix . $nextNum;
}
7. 금액 처리 규칙
단위 변환
| 항목 | 입력 단위 | 계산 단위 | 비고 |
|---|---|---|---|
| 폭/높이 | mm | m | /1000 변환 |
| 면적 | - | m² | 폭×높이/1,000,000 |
| 중량 | - | kg | 면적×단위중량 |
| 금액 | - | 원 | 천원 단위 반올림 |
반올림 규칙
// calculation.js
// 금액은 천원 단위에서 반올림
roundedAreaPrice = Math.round(areaPrice / 1000) * 1000;
// 면적은 소수점 2자리
area = Math.round(area * 100) / 100;
수동 편집 처리
// 수동 편집된 셀은 배경색 변경
$('.manually-edited').css('background-color', '#f8d7da');
// 자동 계산 시 수동 편집 값 유지 옵션
if (!isManuallyEdited) {
cell.val(calculatedValue);
}
8. 데이터 저장 규칙
저장 전 검증
- 필수값 확인: 현장명, 발주처, 담당자
- 수치 변환: 콤마 제거, 정수 변환
- 권한 확인: 레벨 5 이하
저장 데이터
// insert.php
$data = [
'pjnum' => generatePjnum(),
'indate' => date('Y-m-d'),
'orderman' => $_SESSION['name'],
'outworkplace' => $outworkplace,
'major_category' => $major_category,
'model_name' => $model_name,
'makeWidth' => intval(str_replace(',', '', $makeWidth)),
'makeHeight' => intval(str_replace(',', '', $makeHeight)),
'maguriWing' => $maguriWing,
'inspectionFee' => intval(str_replace(',', '', $inspectionFee)),
'estimateList' => json_encode($estimateList),
'estimateList_auto' => json_encode($estimateList_auto),
'estimateSlatList' => json_encode($estimateSlatList),
'estimateSlatList_auto' => json_encode($estimateSlatList_auto),
'estimateTotal' => intval(str_replace(',', '', $estimateTotal)),
'steel' => $steel,
'motor' => $motor,
'warranty' => $warranty,
'slatcheck' => $slatcheck,
'partscheck' => $partscheck
];
9. SAM 이관 시 로직 변경
Service 클래스 분리
// app/Services/QuotationService.php
class QuotationService
{
// 1. 견적 생성
public function createQuote(array $data): Quote { }
// 2. 금액 계산
public function calculateAmount(Quote $quote): array { }
// 3. 스크린 계산
protected function calculateScreenAmount(array $details): array { }
// 4. 슬랫 계산
protected function calculateSlatAmount(array $details): array { }
// 5. 모터 용량 결정
protected function determineMotorCapacity(float $weight, ?int $inch): int { }
// 6. 단가 조회
protected function getUnitPrice(string $itemCode, array $params): float { }
}
계산 로직 캡슐화
// app/ValueObjects/QuoteDimension.php
class QuoteDimension
{
public function __construct(
public readonly int $width,
public readonly int $height,
public readonly int $wing = 50
) {}
public function getAreaForScreen(): float
{
return ($this->height + 550) * $this->width / 1000000;
}
public function getAreaForSlat(): float
{
return ($this->height + 50) * $this->width / 1000000;
}
}
옵션 처리
// app/ValueObjects/QuoteOptions.php
class QuoteOptions
{
public function __construct(
public readonly bool $steel = false,
public readonly bool $motor = false,
public readonly bool $warranty = false,
public readonly bool $slat = false,
public readonly bool $parts = false
) {}
public static function fromArray(array $data): self
{
return new self(
steel: $data['steel'] ?? false,
motor: $data['motor'] ?? false,
warranty: $data['warranty'] ?? false,
slat: $data['slat'] ?? false,
parts: $data['parts'] ?? false
);
}
public function toJson(): string
{
return json_encode([
'steel' => $this->steel,
'motor' => $this->motor,
'warranty' => $this->warranty,
'slat' => $this->slat,
'parts' => $this->parts
]);
}
}
참조 파일
5130/estimate/get_screen_amount.php- 스크린 계산 로직5130/estimate/get_slat_amount.php- 슬랫 계산 로직5130/estimate/fetch_unitprice.php- 단가 조회 함수5130/estimate/insert.php- 저장 로직5130/estimate/generate_serial_pjnum.php- 번호 생성