From 7d2b458e31f95dce77b7fac13f4b208fbfa12ae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=9C=EA=B3=A8=EC=95=BD=EC=82=AC?= Date: Tue, 17 Feb 2026 02:18:34 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20=EC=88=98=EB=8F=99=20=EB=A1=9C=ED=8A=B8?= =?UTF-8?q?=20=EB=B0=B0=EB=B6=84=20=EC=8B=9C=20remaining=5Fqty=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 문제: - 수동 로트 배분 후 remaining_qty를 감소시키지 않아 재고 부족 오류 발생 - 재고 부족 체크를 수동 배분에서 제외했던 임시 처리 해결: - 수동 로트 배분 시에도 remaining_qty 감소 처리 추가 - 재고 부족 체크를 수동/자동 모두에 적용하도록 복원 - 이제 수동 배분도 정확한 재고 검증 수행 검증 테스트 추가: - 배분 합계 불일치 시 오류 - 로트 재고 부족 시 오류 - 존재하지 않는 로트 사용 시 오류 이제 수동 로트 배분도 자동 선택과 동일한 수준의 재고 검증을 수행합니다. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app.py | 7 ++- test_lot_validation.py | 108 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 test_lot_validation.py 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