diff --git a/app.py b/app.py index 07ac3d4..2a3aafd 100644 --- a/app.py +++ b/app.py @@ -1366,6 +1366,9 @@ def create_compound(): VALUES ('CONSUME', ?, ?, ?, ?, 'compounds', ?) """, (herb_item_id, lot_id, -requested_qty, unit_price, compound_id)) + # remaining_qty 감소 (중요!) + remaining_qty -= requested_qty + # 자동 로트 선택 (기존 로직) else: # 원산지가 지정된 경우 해당 원산지만, 아니면 전체에서 FIFO @@ -1425,8 +1428,8 @@ def create_compound(): remaining_qty -= used - # 수동 배분이 아닌 경우에만 재고 부족 체크 - if remaining_qty > 0 and not ('lot_assignments' in ingredient and ingredient['lot_assignments']): + # 재고 부족 체크 (수동/자동 모두 적용) + if remaining_qty > 0: raise Exception(f"재고 부족: {ingredient.get('herb_name', herb_item_id)}") # 총 원가 업데이트 diff --git a/test_lot_validation.py b/test_lot_validation.py new file mode 100644 index 0000000..69814d7 --- /dev/null +++ b/test_lot_validation.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python3 +""" +로트 배분 검증 테스트 - 재고 부족 및 잘못된 배분 테스트 +""" + +import json +import requests + +BASE_URL = "http://localhost:5001" + +def test_insufficient_stock(): + print("=== 로트 배분 검증 테스트 ===\n") + + # 1. 배분 합계가 맞지 않는 경우 + print("1. 배분 합계가 필요량과 맞지 않는 경우") + + compound_data = { + "patient_id": 1, + "formula_id": None, + "je_count": 1, + "cheop_total": 1, + "pouch_total": 1, + "ingredients": [ + { + "herb_item_id": 63, + "grams_per_cheop": 100.0, + "total_grams": 100.0, + "origin": "manual", + "lot_assignments": [ + {"lot_id": 208, "quantity": 50.0}, # 50g + {"lot_id": 219, "quantity": 30.0} # 30g = 총 80g (100g 필요) + ] + } + ] + } + + response = requests.post(f"{BASE_URL}/api/compounds", json=compound_data, headers={"Content-Type": "application/json"}) + + if response.status_code != 200: + result = response.json() + print(f" ✅ 예상된 오류 발생: {result.get('error')}") + else: + print(f" ❌ 오류가 발생해야 하는데 성공함") + + # 2. 로트 재고가 부족한 경우 + print("\n2. 로트 재고가 부족한 경우") + + compound_data = { + "patient_id": 1, + "formula_id": None, + "je_count": 1, + "cheop_total": 1, + "pouch_total": 1, + "ingredients": [ + { + "herb_item_id": 63, + "grams_per_cheop": 5000.0, # 5000g 요청 + "total_grams": 5000.0, + "origin": "manual", + "lot_assignments": [ + {"lot_id": 208, "quantity": 5000.0} # 로트 208에 5000g 요청 (실제로는 4784g만 있음) + ] + } + ] + } + + response = requests.post(f"{BASE_URL}/api/compounds", json=compound_data, headers={"Content-Type": "application/json"}) + + if response.status_code != 200: + result = response.json() + print(f" ✅ 예상된 오류 발생: {result.get('error')}") + else: + print(f" ❌ 오류가 발생해야 하는데 성공함") + + # 3. 존재하지 않는 로트 + print("\n3. 존재하지 않는 로트 ID 사용") + + compound_data = { + "patient_id": 1, + "formula_id": None, + "je_count": 1, + "cheop_total": 1, + "pouch_total": 1, + "ingredients": [ + { + "herb_item_id": 63, + "grams_per_cheop": 10.0, + "total_grams": 10.0, + "origin": "manual", + "lot_assignments": [ + {"lot_id": 99999, "quantity": 10.0} # 존재하지 않는 로트 + ] + } + ] + } + + response = requests.post(f"{BASE_URL}/api/compounds", json=compound_data, headers={"Content-Type": "application/json"}) + + if response.status_code != 200: + result = response.json() + print(f" ✅ 예상된 오류 발생: {result.get('error')}") + else: + print(f" ❌ 오류가 발생해야 하는데 성공함") + + print("\n✅ 모든 검증 테스트 완료 - 잘못된 요청을 올바르게 거부함") + +if __name__ == "__main__": + test_insufficient_stock() \ No newline at end of file