Files
TK-BOM-Project/test_purchase_calculator.py
Hyungi Ahn 28431ee490 feat: 구매 수량 계산 시스템 구현
🧮 구매 수량 계산 로직:
- PIPE: 절단 손실(3mm/절단) + 6M 단위 올림 계산
- 일반 자재: 여유율 + 최소 주문 수량 적용
- 자재별 차별화된 여유율 (VALVE 50%, BOLT 20% 등)

🛒 구매 관리 API:
- /purchase/items/calculate: 실시간 구매 수량 계산
- /purchase/items/save: 구매 품목 DB 저장
- /purchase/revision-diff: 리비전간 차이 계산
- /purchase/orders/create: 구매 주문 생성

🧪 테스트 검증:
- PIPE 절단 손실 계산: 25,000mm → 5본 (정확)
- 여유율 적용: VALVE 2개 → 3개 (50% 예비)
- 최소 주문: BOLT 24개 → 50개 (박스 단위)

📱 프론트엔드:
- PurchaseConfirmationPage 라우팅 추가
- 구매확정 버튼 → 구매 페이지 이동
2025-07-18 13:18:13 +09:00

110 lines
5.1 KiB
Python

#!/usr/bin/env python3
"""
구매 수량 계산기 테스트
특히 파이프 절단 손실 + 6M 단위 계산 테스트
"""
import sys
import os
sys.path.append('backend')
def test_pipe_calculation():
"""파이프 절단 손실 + 6M 단위 계산 테스트"""
from app.services.purchase_calculator import calculate_pipe_purchase_quantity
print("🔧 PIPE 구매 수량 계산 테스트\n")
# 테스트 케이스들
test_cases = [
{
"name": "25,000mm 필요 (10회 절단)",
"materials": [
{"length_mm": 3000, "original_description": "PIPE 4\" SCH40 - 3M", "quantity": 1},
{"length_mm": 2500, "original_description": "PIPE 4\" SCH40 - 2.5M", "quantity": 1},
{"length_mm": 1800, "original_description": "PIPE 4\" SCH40 - 1.8M", "quantity": 1},
{"length_mm": 4200, "original_description": "PIPE 4\" SCH40 - 4.2M", "quantity": 1},
{"length_mm": 2100, "original_description": "PIPE 4\" SCH40 - 2.1M", "quantity": 1},
{"length_mm": 1500, "original_description": "PIPE 4\" SCH40 - 1.5M", "quantity": 1},
{"length_mm": 3800, "original_description": "PIPE 4\" SCH40 - 3.8M", "quantity": 1},
{"length_mm": 2200, "original_description": "PIPE 4\" SCH40 - 2.2M", "quantity": 1},
{"length_mm": 1900, "original_description": "PIPE 4\" SCH40 - 1.9M", "quantity": 1},
{"length_mm": 2000, "original_description": "PIPE 4\" SCH40 - 2M", "quantity": 1}
],
"expected_pipes": 5
},
{
"name": "5,900mm 필요 (3회 절단)",
"materials": [
{"length_mm": 2000, "original_description": "PIPE 6\" SCH40 - 2M", "quantity": 1},
{"length_mm": 1900, "original_description": "PIPE 6\" SCH40 - 1.9M", "quantity": 1},
{"length_mm": 2000, "original_description": "PIPE 6\" SCH40 - 2M", "quantity": 1}
],
"expected_pipes": 1
},
{
"name": "12,000mm 정확히 (4회 절단)",
"materials": [
{"length_mm": 3000, "original_description": "PIPE 8\" SCH40 - 3M", "quantity": 4}
],
"expected_pipes": 2
}
]
for i, test_case in enumerate(test_cases, 1):
print(f"📋 테스트 {i}: {test_case['name']}")
result = calculate_pipe_purchase_quantity(test_case["materials"])
print(f" 🎯 BOM 총 길이: {result['bom_quantity']:,}mm")
print(f" ✂️ 절단 횟수: {result['cutting_count']}")
print(f" 📏 절단 손실: {result['cutting_loss']}mm (각 절단마다 3mm)")
print(f" 🔢 총 필요량: {result['required_length']:,}mm")
print(f" 📦 구매 파이프: {result['pipes_count']}본 (각 6M)")
print(f" 💰 구매 총량: {result['calculated_qty']:,}mm")
print(f" ♻️ 여유분: {result['waste_length']:,}mm")
print(f" 📊 활용률: {result['utilization_rate']:.1f}%")
# 결과 확인
if result['pipes_count'] == test_case['expected_pipes']:
print(f" ✅ 성공: 예상 {test_case['expected_pipes']}본 = 결과 {result['pipes_count']}")
else:
print(f" ❌ 실패: 예상 {test_case['expected_pipes']}본 ≠ 결과 {result['pipes_count']}")
print()
def test_standard_calculation():
"""일반 자재 구매 수량 계산 테스트"""
from app.services.purchase_calculator import calculate_standard_purchase_quantity
print("🔧 일반 자재 구매 수량 계산 테스트\n")
test_cases = [
{"category": "VALVE", "bom_qty": 2, "expected_factor": 1.5, "desc": "밸브 2개 (50% 예비품)"},
{"category": "BOLT", "bom_qty": 24, "expected_min": 50, "desc": "볼트 24개 (박스 단위 50개)"},
{"category": "FITTING", "bom_qty": 5, "expected_factor": 1.1, "desc": "피팅 5개 (10% 여유)"},
{"category": "GASKET", "bom_qty": 3, "expected_factor": 1.25, "desc": "가스켓 3개 (25% 교체 주기)"},
{"category": "INSTRUMENT", "bom_qty": 1, "expected_factor": 1.0, "desc": "계기 1개 (정확한 수량)"}
]
for i, test_case in enumerate(test_cases, 1):
print(f"📋 테스트 {i}: {test_case['desc']}")
result = calculate_standard_purchase_quantity(
test_case["category"],
test_case["bom_qty"]
)
print(f" 🎯 BOM 수량: {result['bom_quantity']}")
print(f" 📈 여유율: {result['safety_factor']:.2f} ({(result['safety_factor']-1)*100:.0f}%)")
print(f" 🔢 여유 적용: {result['safety_qty']:.1f}")
print(f" 📦 최소 주문: {result['min_order_qty']}")
print(f" 💰 최종 구매: {result['calculated_qty']}")
print(f" ♻️ 여유분: {result['waste_quantity']}")
print(f" 📊 활용률: {result['utilization_rate']:.1f}%")
print()
if __name__ == "__main__":
test_pipe_calculation()
test_standard_calculation()