feat(order): 수인약품 선별 주문 및 rx-usage 주문 전송 개선

- order_api.py: 수인 주문 시 submit_order_selective() 사용 (기존 품목 보존)
- admin_rx_usage.html: cart_only=false로 변경 (장바구니+주문확정)
- 버튼 텍스트 변경: 장바구니 담기 → 주문 전송
This commit is contained in:
thug0bin
2026-03-06 21:52:40 +09:00
parent 5519f5ae62
commit be95f8b3d1
2 changed files with 595 additions and 68 deletions

View File

@@ -152,14 +152,21 @@ def api_submit_order():
return jsonify(result)
def submit_geoyoung_order(order: dict, dry_run: bool) -> dict:
"""지오영 주문 제출"""
def submit_geoyoung_order(order: dict, dry_run: bool, cart_only: bool = True) -> dict:
"""
지오영 주문 제출
Args:
order: 주문 정보
dry_run: True=시뮬레이션만, False=실제 주문
cart_only: True=장바구니만, False=주문 확정까지
"""
order_id = order['id']
items = order['items']
# 상태 업데이트
update_order_status(order_id, 'pending',
f'주문 제출 시작 (dry_run={dry_run})')
f'주문 제출 시작 (dry_run={dry_run}, cart_only={cart_only})')
results = []
success_count = 0
@@ -286,20 +293,22 @@ def submit_geoyoung_order(order: dict, dry_run: bool) -> dict:
spec = item.get('specification', '')
try:
# 지오영 주문 실행 (빠른 API - 장바구니+확정)
# 지오영 주문 실행
# cart_only=True: 장바구니만 (auto_confirm=False)
# cart_only=False: 주문 확정까지 (auto_confirm=True)
result = geo_session.full_order(
kd_code=kd_code,
quantity=order_qty,
specification=spec if spec else None,
check_stock=True,
auto_confirm=True,
auto_confirm=not cart_only, # cart_only면 확정 안함
memo=f"자동주문 - {item.get('product_name', '')}"
)
if result.get('success'):
status = 'success'
result_code = 'OK'
result_message = result.get('message', '주문 완료')
result_code = 'CART_ADDED' if cart_only else 'OK'
result_message = '장바구니 추가 완료' if cart_only else result.get('message', '주문 완료')
success_count += 1
else:
status = 'failed'
@@ -338,25 +347,41 @@ def submit_geoyoung_order(order: dict, dry_run: bool) -> dict:
})
# 주문 상태 업데이트
if failed_count == 0:
update_order_status(order_id, 'submitted',
f'주문 제출 완료: {success_count}개 품목')
elif success_count == 0:
update_order_status(order_id, 'failed',
f'주문 실패: {failed_count}개 품목')
if cart_only:
# 장바구니만 담은 경우
if failed_count == 0:
update_order_status(order_id, 'pending',
f'지오영 장바구니 추가 완료: {success_count}개 (사이트에서 확정 필요)')
elif success_count == 0:
update_order_status(order_id, 'failed',
f'장바구니 추가 실패: {failed_count}개 품목')
else:
update_order_status(order_id, 'partial',
f'부분 성공: {success_count}개 장바구니, {failed_count}개 실패')
else:
update_order_status(order_id, 'partial',
f'부분 주문: {success_count}개 성공, {failed_count}개 실패')
# 실제 주문까지 한 경우
if failed_count == 0:
update_order_status(order_id, 'submitted',
f'주문 제출 완료: {success_count}개 품목')
elif success_count == 0:
update_order_status(order_id, 'failed',
f'주문 실패: {failed_count}개 품목')
else:
update_order_status(order_id, 'partial',
f'부분 주문: {success_count}개 성공, {failed_count}개 실패')
return {
'success': True,
'dry_run': dry_run,
'cart_only': cart_only,
'order_id': order_id,
'order_no': order['order_no'],
'wholesaler': 'geoyoung',
'total_items': len(items),
'success_count': success_count,
'failed_count': failed_count,
'results': results
'results': results,
'note': '지오영 장바구니에 담김. 지오영 사이트에서 최종 확정 필요.' if cart_only else None
}
except Exception as e:
@@ -409,9 +434,10 @@ def api_quick_submit():
POST /api/order/quick-submit
{
"wholesaler_id": "geoyoung" | "sooin",
"wholesaler_id": "geoyoung" | "sooin" | "baekje",
"items": [...],
"dry_run": true
"dry_run": true,
"cart_only": true // true=장바구니만, false=실제 주문까지
}
"""
data = request.get_json()
@@ -438,13 +464,14 @@ def api_quick_submit():
# 3. 주문 제출
dry_run = data.get('dry_run', True)
cart_only = data.get('cart_only', True) # 기본값: 장바구니만
if order['wholesaler_id'] == 'geoyoung':
submit_result = submit_geoyoung_order(order, dry_run)
submit_result = submit_geoyoung_order(order, dry_run, cart_only=cart_only)
elif order['wholesaler_id'] == 'sooin':
submit_result = submit_sooin_order(order, dry_run)
submit_result = submit_sooin_order(order, dry_run, cart_only=cart_only)
elif order['wholesaler_id'] == 'baekje':
submit_result = submit_baekje_order(order, dry_run)
submit_result = submit_baekje_order(order, dry_run, cart_only=cart_only)
else:
submit_result = {'success': False, 'error': f"Wholesaler {order['wholesaler_id']} not supported"}
@@ -453,14 +480,21 @@ def api_quick_submit():
return jsonify(submit_result)
def submit_sooin_order(order: dict, dry_run: bool) -> dict:
"""수인약품 주문 제출"""
def submit_sooin_order(order: dict, dry_run: bool, cart_only: bool = True) -> dict:
"""
수인약품 주문 제출
Args:
order: 주문 정보
dry_run: True=시뮬레이션만, False=실제 주문
cart_only: True=장바구니만, False=주문 확정까지
"""
order_id = order['id']
items = order['items']
# 상태 업데이트
update_order_status(order_id, 'pending',
f'수인 주문 시작 (dry_run={dry_run})')
f'수인 주문 시작 (dry_run={dry_run}, cart_only={cart_only})')
results = []
success_count = 0
@@ -572,23 +606,15 @@ def submit_sooin_order(order: dict, dry_run: bool) -> dict:
kd_code = item.get('kd_code') or item.get('drug_code')
order_qty = item['order_qty']
spec = item.get('specification', '')
internal_code = item.get('internal_code')
try:
# internal_code가 없으면 검색해서 찾기
if not internal_code:
search_result = sooin_session.search_products(kd_code)
if search_result.get('success'):
for sooin_item in search_result.get('items', []):
if spec in sooin_item.get('spec', '') or sooin_item.get('spec', '') in spec:
internal_code = sooin_item.get('internal_code')
break
if not internal_code:
raise ValueError(f"내부 코드를 찾을 수 없음: {kd_code} {spec}")
# 장바구니 추가
cart_result = sooin_session.add_to_cart(internal_code, order_qty)
# quick_order 사용 (검색 → 가격/재고 정보 포함하여 장바구니 추가)
cart_result = sooin_session.quick_order(
kd_code=kd_code,
quantity=order_qty,
spec=spec if spec else None,
check_stock=False # 재고 체크는 이미 테스트에서 했으므로 스킵
)
if cart_result.get('success'):
status = 'success'
@@ -609,6 +635,9 @@ def submit_sooin_order(order: dict, dry_run: bool) -> dict:
update_item_result(item['id'], status, result_code, result_message)
# quick_order 결과에서 internal_code 가져오기
internal_code = cart_result.get('product', {}).get('internal_code') if cart_result.get('success') else None
save_order_context(item['id'], {
'drug_code': item['drug_code'],
'product_name': item['product_name'],
@@ -629,20 +658,57 @@ def submit_sooin_order(order: dict, dry_run: bool) -> dict:
'order_qty': order_qty,
'status': status,
'result_code': result_code,
'result_message': result_message
'result_message': result_message,
'internal_code': internal_code # 선별 주문용
})
# 주문 확정은 별도로 (장바구니에 담기만 한 상태)
if success_count > 0:
# cart_only=False면 주문 확정까지 진행 (선별 주문!)
if not cart_only and success_count > 0:
try:
# 이번에 담은 품목의 internal_code만 수집
ordered_codes = [r['internal_code'] for r in results
if r['status'] == 'success' and r.get('internal_code')]
if ordered_codes:
# 선별 주문: 기존 품목은 건드리지 않고, 이번에 담은 것만 주문
confirm_result = sooin_session.submit_order_selective(ordered_codes)
if confirm_result.get('success'):
restored_info = f", 기존 {confirm_result.get('restored_count', 0)}개 복원" if confirm_result.get('restored_count', 0) > 0 else ""
update_order_status(order_id, 'submitted',
f'수인 주문 확정 완료: {success_count}{restored_info}')
# 결과 메시지 업데이트
for r in results:
if r['status'] == 'success':
r['result_code'] = 'OK'
r['result_message'] = '주문 확정 완료'
else:
update_order_status(order_id, 'partial',
f'수인 장바구니 담김, 확정 실패: {confirm_result.get("error", "알 수 없는 오류")}')
else:
update_order_status(order_id, 'partial',
f'수인 장바구니 담김, internal_code 없음')
except Exception as e:
logger.error(f"수인 주문 확정 오류: {e}")
update_order_status(order_id, 'partial',
f'수인 장바구니 담김, 확정 중 오류: {str(e)}')
elif success_count > 0:
update_order_status(order_id, 'pending',
f'수인 장바구니 추가 완료: {success_count}개 (확정 필요)')
else:
update_order_status(order_id, 'failed',
f'수인 주문 실패: {failed_count}')
# 응답 생성
if cart_only:
note = '수인약품 장바구니에 담김. 사이트에서 최종 확정 필요.'
else:
note = None
return {
'success': True,
'dry_run': dry_run,
'cart_only': cart_only,
'order_id': order_id,
'order_no': order['order_no'],
'wholesaler': 'sooin',
@@ -650,7 +716,7 @@ def submit_sooin_order(order: dict, dry_run: bool) -> dict:
'success_count': success_count,
'failed_count': failed_count,
'results': results,
'note': '실제 주문 시 장바구니에 담김. 수인약품 사이트에서 최종 확정 필요.' if not dry_run else None
'note': note if not dry_run else None
}
except Exception as e:
@@ -663,14 +729,21 @@ def submit_sooin_order(order: dict, dry_run: bool) -> dict:
}
def submit_baekje_order(order: dict, dry_run: bool) -> dict:
"""백제약품 주문 제출"""
def submit_baekje_order(order: dict, dry_run: bool, cart_only: bool = True) -> dict:
"""
백제약품 주문 제출
Args:
order: 주문 정보
dry_run: True=시뮬레이션만, False=실제 주문
cart_only: True=장바구니만, False=주문 확정까지
"""
order_id = order['id']
items = order['items']
# 상태 업데이트
update_order_status(order_id, 'pending',
f'백제약품 주문 시작 (dry_run={dry_run})')
f'백제약품 주문 시작 (dry_run={dry_run}, cart_only={cart_only})')
results = []
success_count = 0
@@ -828,17 +901,42 @@ def submit_baekje_order(order: dict, dry_run: bool) -> dict:
'result_message': result_message
})
# 상태 업데이트
if success_count > 0:
# cart_only=False면 주문 확정까지 진행
if not cart_only and success_count > 0:
try:
confirm_result = baekje_session.submit_order()
if confirm_result.get('success'):
update_order_status(order_id, 'submitted',
f'백제 주문 확정 완료: {success_count}')
# 결과 메시지 업데이트
for r in results:
if r['status'] == 'success':
r['result_code'] = 'OK'
r['result_message'] = '주문 확정 완료'
else:
update_order_status(order_id, 'partial',
f'백제 장바구니 담김, 확정 실패: {confirm_result.get("error", "알 수 없는 오류")}')
except Exception as e:
logger.error(f"백제 주문 확정 오류: {e}")
update_order_status(order_id, 'partial',
f'백제 장바구니 담김, 확정 중 오류: {str(e)}')
elif success_count > 0:
update_order_status(order_id, 'pending',
f'백제 장바구니 추가 완료: {success_count}개 (확정 필요)')
else:
update_order_status(order_id, 'failed',
f'백제 주문 실패: {failed_count}')
# 응답 생성
if cart_only:
note = '백제약품 장바구니에 담김. 백제몰(ibjp.co.kr)에서 최종 확정 필요.'
else:
note = None
return {
'success': True,
'dry_run': dry_run,
'cart_only': cart_only,
'order_id': order_id,
'order_no': order['order_no'],
'wholesaler': 'baekje',
@@ -846,7 +944,7 @@ def submit_baekje_order(order: dict, dry_run: bool) -> dict:
'success_count': success_count,
'failed_count': failed_count,
'results': results,
'note': '실제 주문 시 장바구니에 담김. 백제몰(ibjp.co.kr)에서 최종 확정 필요.' if not dry_run else None
'note': note if not dry_run else None
}
except Exception as e: