# -*- coding: utf-8 -*- """ 수인약품 도매상 API - Flask Blueprint 핵심 로직은 wholesale 패키지에서 가져옴 이 파일은 Flask 웹 API 연동만 담당 """ import time import logging from flask import Blueprint, jsonify, request as flask_request # wholesale 패키지 경로 설정 import wholesale_path # wholesale 패키지에서 핵심 클래스 가져오기 from wholesale import SooinSession logger = logging.getLogger(__name__) # Blueprint 생성 sooin_bp = Blueprint('sooin', __name__, url_prefix='/api/sooin') # ========== 세션 관리 ========== _sooin_session = None def get_sooin_session(): global _sooin_session if _sooin_session is None: _sooin_session = SooinSession() return _sooin_session def search_sooin_stock(keyword: str, search_type: str = 'kd_code'): """수인약품 재고 검색 (동기, 빠름)""" try: session = get_sooin_session() result = session.search_products(keyword) if result.get('success'): return { 'success': True, 'keyword': keyword, 'search_type': search_type, 'count': result['total'], 'items': result['items'] } else: return result except Exception as e: logger.error(f"수인약품 검색 오류: {e}") return {'success': False, 'error': 'SEARCH_ERROR', 'message': str(e)} # ========== Flask API Routes ========== @sooin_bp.route('/stock', methods=['GET']) def api_sooin_stock(): """ 수인약품 재고 조회 API GET /api/sooin/stock?kd_code=073100220 GET /api/sooin/stock?keyword=코자정&type=name """ kd_code = flask_request.args.get('kd_code', '').strip() keyword = flask_request.args.get('keyword', '').strip() search_type = flask_request.args.get('type', 'kd_code').strip() search_term = kd_code or keyword if kd_code: search_type = 'kd_code' if not search_term: return jsonify({ 'success': False, 'error': 'MISSING_PARAM', 'message': 'kd_code 또는 keyword 파라미터가 필요합니다' }), 400 try: result = search_sooin_stock(search_term, search_type) return jsonify(result) except Exception as e: logger.error(f"수인약품 API 오류: {e}") return jsonify({ 'success': False, 'error': 'API_ERROR', 'message': str(e) }), 500 @sooin_bp.route('/session-status', methods=['GET']) def api_session_status(): """세션 상태 확인""" session = get_sooin_session() return jsonify({ 'logged_in': session._logged_in, 'last_login': session._last_login, 'session_age_sec': int(time.time() - session._last_login) if session._last_login else None }) @sooin_bp.route('/balance', methods=['GET']) def api_sooin_balance(): """ 수인약품 잔고(미수금) 조회 API GET /api/sooin/balance Returns: { "success": true, "balance": 14293001, // 현재 잔고 (누계합) "prev_balance": 10592762, // 전일잔액 "monthly_sales": 3700239, // 월 매출 "yearly_sales": 34380314 // 연 누계 매출 } """ try: session = get_sooin_session() result = session.get_balance() return jsonify(result) except Exception as e: logger.error(f"수인약품 잔고 조회 오류: {e}") return jsonify({ 'success': False, 'error': 'BALANCE_ERROR', 'message': str(e), 'balance': 0 }), 500 @sooin_bp.route('/monthly-sales', methods=['GET']) def api_sooin_monthly_sales(): """ 수인약품 월간 매출 조회 API GET /api/sooin/monthly-sales?year=2026&month=3 Returns: { "success": true, "total_amount": 3700239, // 월간 매출 합계 "total_paid": 0, // 월간 입금 합계 "ending_balance": 14293001, // 월말 잔액 "opening_balance": 10592762, // 전일(기초) 잔액 "from_date": "2026-03-01", "to_date": "2026-03-31" } """ from datetime import datetime year = flask_request.args.get('year', type=int) month = flask_request.args.get('month', type=int) # 기본값: 현재 월 if not year or not month: now = datetime.now() year = year or now.year month = month or now.month try: session = get_sooin_session() if hasattr(session, 'get_monthly_sales'): result = session.get_monthly_sales(year, month) return jsonify(result) else: return jsonify({ 'success': False, 'error': 'NOT_IMPLEMENTED', 'message': '수인약품 월간 매출 조회 미구현' }), 501 except Exception as e: logger.error(f"수인약품 월간 매출 조회 오류: {e}") return jsonify({ 'success': False, 'error': 'MONTHLY_SALES_ERROR', 'message': str(e) }), 500 @sooin_bp.route('/cart', methods=['GET']) def api_sooin_cart(): """장바구니 조회 API""" try: session = get_sooin_session() result = session.get_cart() return jsonify(result) except Exception as e: return jsonify({'success': False, 'error': str(e), 'items': []}), 500 @sooin_bp.route('/cart/clear', methods=['POST']) def api_sooin_cart_clear(): """장바구니 비우기 API""" try: session = get_sooin_session() result = session.clear_cart() return jsonify(result) except Exception as e: return jsonify({'success': False, 'error': str(e)}), 500 @sooin_bp.route('/cart/cancel', methods=['POST']) def api_sooin_cart_cancel(): """ 장바구니 항목 취소 API POST /api/sooin/cart/cancel { "row_index": 0 } 또는 { "internal_code": "32495" } """ data = flask_request.get_json() or {} row_index = data.get('row_index') internal_code = data.get('internal_code') if row_index is None and not internal_code: return jsonify({ 'success': False, 'error': 'MISSING_PARAM', 'message': 'row_index 또는 internal_code가 필요합니다' }), 400 try: session = get_sooin_session() result = session.cancel_item(row_index=row_index, product_code=internal_code) return jsonify(result) except Exception as e: return jsonify({'success': False, 'error': str(e)}), 500 @sooin_bp.route('/cart/restore', methods=['POST']) def api_sooin_cart_restore(): """ 취소된 항목 복원 API POST /api/sooin/cart/restore { "row_index": 0 } """ data = flask_request.get_json() or {} row_index = data.get('row_index') internal_code = data.get('internal_code') try: session = get_sooin_session() result = session.restore_item(row_index=row_index, product_code=internal_code) return jsonify(result) except Exception as e: return jsonify({'success': False, 'error': str(e)}), 500 @sooin_bp.route('/order', methods=['POST']) def api_sooin_order(): """ 수인약품 주문 API (장바구니 추가) POST /api/sooin/order { "kd_code": "073100220", "quantity": 1, "specification": "30T", "check_stock": true } """ data = flask_request.get_json() if not data: return jsonify({'success': False, 'error': 'NO_DATA'}), 400 kd_code = data.get('kd_code', '').strip() quantity = data.get('quantity', 1) specification = data.get('specification') check_stock = data.get('check_stock', True) if not kd_code: return jsonify({ 'success': False, 'error': 'MISSING_PARAM', 'message': 'kd_code가 필요합니다' }), 400 try: session = get_sooin_session() result = session.quick_order( kd_code=kd_code, quantity=quantity, spec=specification, check_stock=check_stock ) return jsonify(result) except Exception as e: logger.error(f"수인약품 주문 오류: {e}") return jsonify({ 'success': False, 'error': 'ORDER_ERROR', 'message': str(e) }), 500 @sooin_bp.route('/confirm', methods=['POST']) def api_sooin_confirm(): """주문 확정 API""" data = flask_request.get_json() or {} memo = data.get('memo', '') try: session = get_sooin_session() result = session.submit_order(memo) return jsonify(result) except Exception as e: return jsonify({'success': False, 'error': str(e)}), 500 @sooin_bp.route('/full-order', methods=['POST']) def api_sooin_full_order(): """ 전체 주문 API (검색 → 장바구니 → 확정) POST /api/sooin/full-order { "kd_code": "073100220", "quantity": 1, "specification": "30T", "auto_confirm": true, "memo": "자동주문" } """ data = flask_request.get_json() if not data or not data.get('kd_code'): return jsonify({'success': False, 'error': 'kd_code required'}), 400 try: session = get_sooin_session() # 장바구니에 담기 cart_result = session.quick_order( kd_code=data['kd_code'], quantity=data.get('quantity', 1), spec=data.get('specification'), check_stock=data.get('check_stock', True) ) if not cart_result.get('success'): return jsonify(cart_result) if not data.get('auto_confirm', True): return jsonify(cart_result) # 주문 확정 confirm_result = session.submit_order(data.get('memo', '')) if confirm_result.get('success'): return jsonify({ 'success': True, 'message': f"{cart_result['product']['name']} {cart_result['quantity']}개 주문 완료", 'product': cart_result['product'], 'quantity': cart_result['quantity'], 'confirmed': True }) else: return jsonify({ 'success': False, 'error': confirm_result.get('error', 'CONFIRM_FAILED'), 'message': f"장바구니 담기 성공, 주문 확정 실패", 'product': cart_result['product'], 'cart_added': True }) except Exception as e: return jsonify({'success': False, 'error': str(e)}), 500 @sooin_bp.route('/order-batch', methods=['POST']) def api_sooin_order_batch(): """수인약품 일괄 주문 API""" data = flask_request.get_json() if not data or not data.get('items'): return jsonify({'success': False, 'error': 'NO_ITEMS'}), 400 items = data.get('items', []) check_stock = data.get('check_stock', True) session = get_sooin_session() results = [] success_count = 0 failed_count = 0 for item in items: kd_code = item.get('kd_code', '').strip() quantity = item.get('quantity', 1) specification = item.get('specification') if not kd_code: results.append({ 'kd_code': kd_code, 'success': False, 'error': 'MISSING_KD_CODE' }) failed_count += 1 continue try: result = session.quick_order( kd_code=kd_code, quantity=quantity, spec=specification, check_stock=check_stock ) result['kd_code'] = kd_code result['requested_qty'] = quantity results.append(result) if result.get('success'): success_count += 1 else: failed_count += 1 except Exception as e: results.append({ 'kd_code': kd_code, 'success': False, 'error': 'EXCEPTION', 'message': str(e) }) failed_count += 1 return jsonify({ 'success': True, 'total': len(items), 'success_count': success_count, 'failed_count': failed_count, 'results': results })