🧮 구매 수량 계산 로직: - 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 라우팅 추가 - 구매확정 버튼 → 구매 페이지 이동
110 lines
5.1 KiB
Python
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() |