Files
sam-docs/projects/quotation/phase-1-5130-analysis/js-formulas.md
hskwon 1066ea25b2 docs: Phase 5 API 문서 추가 (사용자 초대, 알림설정, 계정관리)
- erp-api-list.md: Phase 5 섹션 추가 (12개 API)
- erp-api-detail.md: Phase 5 상세 스펙 추가
  - 13. 사용자 초대 (5개): 목록, 발송, 수락, 취소, 재발송
  - 14. 알림 설정 (3개): 조회, 수정, 일괄수정
  - 15. 계정 관리 (4개): 탈퇴, 사용중지, 약관조회, 약관수정
2025-12-19 15:35:41 +09:00

471 lines
13 KiB
Markdown
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.

# 5130 견적 수식 분석
> **핵심 문서** - 모든 견적 계산 수식 상세 분석
> **분석 일자:** 2025-12-19
---
## 📋 수식 개요
### 수식 파일 위치
| 파일 | 용도 | 핵심 함수 |
|------|------|----------|
| `common/calculation.js` | 프론트엔드 행 계산 | `calculateRowTotal()` |
| `fetch_unitprice.php` | 단가 조회/계산 헬퍼 | 30+ 함수 |
| `get_screen_amount.php` | 스크린 견적 계산 | `calculateScreenAmount()` |
| `get_slat_amount.php` | 슬랫 견적 계산 | `calculateSlatAmount()` |
---
## 🔢 기본 계산 수식
### 1. 행별 합계 계산 (calculation.js)
```javascript
// 기본 수식
totalPrice = 수량(su) × 단가(unitPrice)
// 면적 기반 수식
if (면적단가 > 0) {
단가 = 면적(areaLength) × 면적단가(areaPrice)
totalPrice = 수량 × 단가
}
```
### 2. 면적 계산
```php
// 스크린 면적 (m²)
// 기본 높이 350에 +550 추가 = 900 기준
$calculateHeight = $height + 550;
$area = $width * $calculateHeight / 1000000;
// 슬랫 면적 (m²)
// 기본 높이 350에 +50 추가 = 400 기준
$calculateHeight = $height + 50;
$area = $width * $calculateHeight / 1000000;
```
---
## 💰 항목별 수식 상세
### 1. 검사비 (인정검사비)
```php
$inspectionFee = 기본값(50000);
$검사비 = $inspectionFee × $수량;
```
| 입력 | 출력 | 단위 |
|------|------|------|
| 검사비 단가 | 검사비 총액 | 원 |
---
### 2. 주자재 (스크린/슬랫)
```php
// 스크린 (실리카/와이어)
$screen_price = $price_raw_materials × round($area, 2);
$주자재_스크린 = $screen_price × $수량;
// 슬랫 (방화)
$slat_price = $price_raw_materials × round($area, 2);
$주자재_슬랫 = $slat_price × $수량;
```
| 입력 | 계산 | 출력 |
|------|------|------|
| 폭(W), 높이(H), 단가 | 면적 × 단가 × 수량 | 주자재 금액 |
**조건:** `slatcheck == '1'` 일 때만 슬랫 주자재 계산
---
### 3. 조인트바 (슬랫 전용)
```php
$jointbar_price = $price_jointbar × $item['col76'];
```
| 입력 | 출력 |
|------|------|
| 조인트바 개수(col76) × 단가 | 조인트바 금액 |
**조건:** `slatcheck == '1'` 일 때만 계산
---
### 4. 모터
```php
// 모터 용량 추출 (숫자만)
$motorSpec = preg_replace('/[a-zA-Z]/', '', $item['col19']);
$motorUnit_price = getPriceForMotor($motorSpec, $itemList);
$모터 = $motorUnit_price × $수량;
```
| 입력 | 조건 | 출력 |
|------|------|------|
| 모터 용량, 수량 | 모터공급처='경동(견적가포함)' AND motor='1' | 모터 금액 |
**모터 용량 판별 로직:**
```php
function calculateMotorSpec($item, $weight, $BracketInch) {
// 스크린/철재 구분
$ItemSel = (substr($item['col4'], 0, 2) === 'KS') ? '스크린' : '철재';
// 중량 + 인치 조합으로 용량 결정
// 스크린: 150K, 300K, 400K, 500K, 600K
// 철재: 300K, 400K, 500K, 600K, 800K, 1000K
// 예시 조건 (스크린 150K)
if ($ItemSel === '스크린' && $BracketInch == 4 && $weight <= 150) {
return 150;
}
// ... 기타 조건들
}
```
**모터 용량 매핑표:**
| 인치 | 중량 범위 | 스크린 용량 | 철재 용량 |
|------|----------|------------|----------|
| 4" | ≤150kg | 150K | - |
| 4" | ≤300kg | 300K | 300K |
| 4" | ≤400kg | 400K | 400K |
| 5" | ≤500kg | 500K | 500K |
| 5" | ≤600kg | 600K | 600K |
| 6" | ≤800kg | - | 800K |
| 8" | ≤1000kg | - | 1000K |
---
### 5. 연동제어기
```php
$price1 = calculateControllerSpec($item['col15'], $itemList, '매립형');
$price2 = calculateControllerSpec($item['col16'], $itemList, '노출형');
$price3 = calculateControllerSpec($item['col17'], $itemList, '뒷박스');
$controller_price =
$price1 × $매립형_수량 +
$price2 × $노출형_수량 +
$price3 × $뒷박스_수량;
```
| 유형 | 입력 컬럼 | 설명 |
|------|----------|------|
| 매립형 | col15 (스크린) / col16 (슬랫) | 벽 매립 타입 |
| 노출형 | col16 (스크린) / col17 (슬랫) | 외부 노출 타입 |
| 뒷박스 | col17 (스크린) / col18 (슬랫) | 뒷면 박스 타입 |
---
### 6. 케이스
```php
// 규격별 단가 조회 (BDmodels 테이블)
if ($item['col36'] === 'custom') {
$dimension = $item['col36_custom']; // 커스텀 규격
} else {
$dimension = $item['col36']; // 표준 규격
}
// 표준 규격이면 단가표에서 조회
if (array_key_exists($dimension, $shutterBoxprices)) {
$shutter_price = $shutterBoxprices[$dimension] / 1000;
} else {
// 비표준 규격은 기본 단가 기준 면적비로 계산
$basicbox_price = $shutterBoxprices['500*380']; // 스크린 기본
// 또는 '650*550' (슬랫 기본)
$basicbox_pricePermeter = $basicbox_price / (500 * 380 / 1000);
$shutter_price = $basicbox_pricePermeter × $boxwidth × $boxheight / 1000;
}
$케이스 = round($shutter_price × $total_length × 1000) × $수량;
```
| 조건 | 계산 |
|------|------|
| steel='1' (절곡 체크) | 단가 × 길이(m) × 수량 |
---
### 7. 케이스용 연기차단재
```php
$boxSmokeBanPrices = BDmodels에서 '케이스용 연기차단재' 단가 조회;
$total_length = $item['col37'] / 1000; // mm → m 변환
$케이스용_연기차단재 = round($boxSmokeBanPrices × $total_length) × $수량;
```
| 조건 | 계산 |
|------|------|
| steel='1' AND 케이스규격 있음 | 단가 × 길이(m) × 수량 |
---
### 8. 케이스 마구리
```php
$maguriCol = $item['col45']; // 마구리 규격
$maguriPrices = BDmodels에서 seconditem='마구리' AND spec=$maguriCol 조회;
$케이스_마구리 = round($maguriPrices × $수량);
```
| 조건 | 계산 |
|------|------|
| steel='1' | 단가 × 수량 |
---
### 9. 모터 받침용 앵글
```php
// 스크린
$price_angle = calculateAngle($item['col14'], $itemList, '스크린용');
// 슬랫 (브라켓 크기 기반)
if (empty($item['col21'])) {
$bracket_size = searchBracketSize($item['col13'], $item['col22']);
} else {
$bracket_size = $item['col21'];
}
$price_angle = calculateAngleBracket_slat($item['col15'], $itemList, $bracket_size);
$모터받침용_앵글 = round($price_angle × $수량 × 4); // 4개 세트
```
**브라켓 사이즈 결정 로직:**
```php
function searchBracketSize($motorWeight, $bracketInch) {
// 모터 용량 판별
$motorCapacity = calculateMotorKG($weight, $inch);
// 용량별 브라켓 사이즈 매핑
if (in_array($motorCapacity, [300, 400])) return '530*320';
if (in_array($motorCapacity, [500, 600])) return '600*350';
if (in_array($motorCapacity, [800, 1000])) return '690*390';
return '530*320'; // 기본값
}
```
---
### 10. 가이드레일
```php
// 레일 유형에 따른 가격 계산
if (strpos($guideType, '혼합') !== false) {
// 혼합형: 벽면 + 측면 각각 다른 규격
$wallPrice = $guidrailPrices[$wallKey];
$sidePrice = $guidrailPrices[$sideKey];
$guidrail_price = $wallPrice + $sidePrice; // 1개 세트
} else {
// 단일형: 벽면 또는 측면
$guidrail_price = $guidrailPrices[$guideKey] × 2; // 2개 세트
}
$total_length = $item['col23'] / 1000; // mm → m
$가이드레일 = round($guidrail_price × $total_length) × $수량;
```
**가이드레일 키 구성:**
```
$key = $modelCode|$finishingType|$spec
예: KS-100|도장|65*80
```
---
### 11. 레일용 연기차단재
```php
$guiderailSmokeBanPrices = BDmodels에서 '가이드레일용 연기차단재' 조회;
$total_length = $item['col23'] / 1000;
$레일용_연기차단재 = round($guiderailSmokeBanPrices × $total_length) × 2 × $수량;
```
| 조건 | 계산 |
|------|------|
| steel='1' AND 연기차단재 옵션 있음 | 단가 × 길이 × 2(양쪽) × 수량 |
---
### 12. 하장바
```php
$bottomBarPrices = BDmodels에서
model_name=$modelCode AND
seconditem='하단마감재' AND
finishing_type=$finishingType 조회;
$total_length = $item['col48'] / 1000 × $수량; // 스크린
// 또는 $item['col49'] (슬랫)
$하장바 = round($bottomBarPrices × $total_length);
```
| 조건 | 계산 |
|------|------|
| steel='1' AND 하장바 옵션 있음 | 단가 × 길이 × 수량 |
---
### 13. L바 (스크린 전용)
```php
$LBarPrices = BDmodels에서 seconditem='L-BAR' 조회;
$total_length = $item['col51'] / 1000 × $수량;
$L바 = round($LBarPrices × $total_length);
```
| 조건 | 계산 |
|------|------|
| steel='1' AND L바 옵션 있음 | 단가 × 길이 × 수량 |
---
### 14. 보강평철 (스크린 전용)
```php
$bottomPlatePrices = BDmodels에서 seconditem='보강평철' 조회;
$total_length = $item['col54'] / 1000 × $수량;
$보강평철 = round($bottomPlatePrices × $total_length);
```
| 조건 | 계산 |
|------|------|
| steel='1' AND 보강평철 옵션 있음 | 단가 × 길이 × 수량 |
---
### 15. 감기샤프트
```php
function calculateShaftPrice($item, $pdo) {
// 샤프트 규격별 가격 합산
// 컬럼: col59~col65 (스크린), col61~col71 (슬랫)
addShaftPrice($item['col59'], $itemList, '3', '300', $sum); // 3인치 300mm
addShaftPrice($item['col60'], $itemList, '4', '3000', $sum); // 4인치 3000mm
addShaftPrice($item['col61'], $itemList, '4', '4500', $sum); // 4인치 4500mm
// ... 기타 규격
return $sum_shaft_price;
}
function addShaftPrice($column, $itemList, $size, $length, &$sum) {
$shaft_price = calculateShaft($column, $itemList, $size, $length);
if ($shaft_price > 0) {
$sum += $shaft_price;
}
}
```
**샤프트 규격표:**
| 인치 | 길이 | 스크린 컬럼 | 슬랫 컬럼 |
|------|------|------------|----------|
| 3" | 300mm | col59 | - |
| 4" | 3000mm | col60 | col61 |
| 4" | 4500mm | col61 | col62 |
| 4" | 6000mm | col62 | col63 |
| 5" | 6000mm | col63 | col64 |
| 5" | 7000mm | col64 | col65 |
| 5" | 8200mm | col65 | col66 |
| 6" | 3000mm | - | col67 |
| 6" | 6000mm | - | col68 |
| 6" | 7000mm | - | col69 |
| 6" | 8000mm | - | col70 |
| 8" | 8200mm | - | col71 |
---
### 16. 무게평철 12T (스크린 전용)
```php
$baseWeightPlatePrice = 12000; // 고정 단가
$무게평철 = $baseWeightPlatePrice × $item['col57'];
```
| 조건 | 계산 |
|------|------|
| steel='1' | 12,000원 × 개수 |
---
### 17. 환봉 (스크린 전용)
```php
$round_bar_price = 2000; // 고정 단가
$round_bar_surang = $item['col70'];
$환봉 = round($round_bar_price × $round_bar_surang);
```
| 조건 | 계산 |
|------|------|
| steel='1' | 2,000원 × 개수 |
---
### 18. 각파이프
```php
$pipe_price_3000 = calculatePipe($itemList, '1.4', '3000'); // 1.4T 3000mm
$pipe_price_6000 = calculatePipe($itemList, '1.4', '6000'); // 1.4T 6000mm
$pipe_surang_3000 = $item['col68']; // 스크린
$pipe_surang_6000 = $item['col69'];
// 또는 col74, col75 (슬랫)
$각파이프_총액 =
($pipe_price_3000 × $pipe_surang_3000) +
($pipe_price_6000 × $pipe_surang_6000);
```
| 조건 | 계산 |
|------|------|
| partscheck='1' | (3000mm 단가 × 수량) + (6000mm 단가 × 수량) |
---
### 19. 앵글
```php
$mainangle_price = calculateMainAngle(1, $itemList, '앵글3T', '2.5'); // 스크린
// 또는 '앵글4T' (슬랫)
$mainangle_surang = $item['col71']; // 스크린
// 또는 col77 (슬랫)
$앵글 = round($mainangle_price × $mainangle_surang);
```
| 조건 | 계산 |
|------|------|
| partscheck='1' | 단가 × 수량 |
---
## 📊 전체 금액 계산
```php
$totalRowAmount = 0;
foreach ($rowItemDetails as $key => $value) {
if (!in_array($key, ['TotalAmount', 'slatcheck', 'partscheck', 'steel', 'motor', 'warranty'])) {
$totalRowAmount += $value;
}
}
$rowItemDetails['TotalAmount'] = round($totalRowAmount);
```
**반환 데이터 구조:**
```php
return [
'total_amount' => $total_amount, // 전체 합계
'details' => $sums, // 행별 소계 배열
'itemDetails' => $itemDetails, // 항목별 상세 금액
'surangSum' => $surangSum // 총 수량
];
```
---
## 🏷️ 테스트 케이스
### 스크린 견적 예시
| 입력 | 값 |
|------|-----|
| 폭(W) | 3,000mm |
| 높이(H) | 2,500mm |
| 수량 | 2 |
| 모터공급 | 경동(견적가포함) |
| 모터용량 | 300K |
| 케이스 | 500*380 |
| 검사비 | 50,000원 |
| 항목 | 계산식 | 금액 |
|------|--------|------|
| 검사비 | 50,000 × 2 | 100,000 |
| 주자재 | 면적 × 단가 × 2 | (계산 필요) |
| 모터 | 300K 단가 × 2 | (단가표 참조) |
| ... | ... | ... |
---
## ⚠️ 주의사항
1. **컬럼 번호 차이**: 스크린과 슬랫에서 같은 항목이 다른 컬럼 사용
2. **단위 변환**: mm → m 변환 필수 (/ 1000)
3. **반올림 처리**: 대부분 `round()` 사용
4. **조건부 계산**: 체크박스 옵션에 따라 계산 여부 결정
5. **JSON 데이터**: 단가 테이블의 `itemList` 컬럼은 JSON 형식
---
## 📚 참조
- [fetch_unitprice.php](../../../../5130/estimate/fetch_unitprice.php) - 헬퍼 함수
- [get_screen_amount.php](../../../../5130/estimate/get_screen_amount.php) - 스크린 계산
- [get_slat_amount.php](../../../../5130/estimate/get_slat_amount.php) - 슬랫 계산