feat: 의약품 마스터 DB 연동 (ATTACH DATABASE)
- medicine_master.db (305,522행) CSV→SQLite 변환 완료 - get_db()에서 ATTACH DATABASE로 자동 연결 - GET /api/medicine-master/search: 상품명/업체명/표준코드 검색 - GET /api/medicine-master/categories: 전문일반구분별 통계 - config.py에 MEDICINE_MASTER_PATH 추가 - 취소된 제품 자동 필터링, 카테고리 필터 지원 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
725f14c59a
commit
c0d55f8e16
73
app.py
73
app.py
@ -15,7 +15,7 @@ from werkzeug.utils import secure_filename
|
|||||||
import json
|
import json
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from excel_processor import ExcelProcessor
|
from excel_processor import ExcelProcessor
|
||||||
from config import DATABASE_PATH, STATIC_PATH, TEMPLATES_PATH
|
from config import DATABASE_PATH, MEDICINE_MASTER_PATH, STATIC_PATH, TEMPLATES_PATH
|
||||||
|
|
||||||
# Flask 앱 초기화
|
# Flask 앱 초기화
|
||||||
app = Flask(__name__, static_folder='static', template_folder='templates')
|
app = Flask(__name__, static_folder='static', template_folder='templates')
|
||||||
@ -42,6 +42,10 @@ def get_db():
|
|||||||
conn = sqlite3.connect(app.config['DATABASE'])
|
conn = sqlite3.connect(app.config['DATABASE'])
|
||||||
conn.row_factory = sqlite3.Row # 딕셔너리 형태로 반환
|
conn.row_factory = sqlite3.Row # 딕셔너리 형태로 반환
|
||||||
conn.execute('PRAGMA foreign_keys = ON') # 외래키 제약 활성화
|
conn.execute('PRAGMA foreign_keys = ON') # 외래키 제약 활성화
|
||||||
|
# 의약품 마스터 DB 연결 (읽기 전용 참조)
|
||||||
|
medicine_db = str(MEDICINE_MASTER_PATH)
|
||||||
|
if os.path.exists(medicine_db):
|
||||||
|
conn.execute(f"ATTACH DATABASE '{medicine_db}' AS med_master")
|
||||||
try:
|
try:
|
||||||
yield conn
|
yield conn
|
||||||
conn.commit()
|
conn.commit()
|
||||||
@ -3768,6 +3772,73 @@ def convert_to_otc(compound_id):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return jsonify({'error': str(e)}), 500
|
return jsonify({'error': str(e)}), 500
|
||||||
|
|
||||||
|
# ==================== 의약품 마스터 검색 API ====================
|
||||||
|
|
||||||
|
@app.route('/api/medicine-master/search', methods=['GET'])
|
||||||
|
def search_medicine_master():
|
||||||
|
"""의약품 마스터 검색 (medicine_master.db ATTACH 활용)"""
|
||||||
|
try:
|
||||||
|
q = request.args.get('q', '').strip()
|
||||||
|
category = request.args.get('category', '') # 전문일반구분 필터
|
||||||
|
limit = min(int(request.args.get('limit', 50)), 200)
|
||||||
|
|
||||||
|
if not q or len(q) < 2:
|
||||||
|
return jsonify({'success': False, 'error': '검색어는 2자 이상 입력하세요'}), 400
|
||||||
|
|
||||||
|
with get_db() as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
where_clauses = ["(m.product_name LIKE ? OR m.company_name LIKE ? OR m.standard_code LIKE ? OR m.notes LIKE ?)"]
|
||||||
|
params = [f'%{q}%', f'%{q}%', f'%{q}%', f'%{q}%']
|
||||||
|
|
||||||
|
if category:
|
||||||
|
where_clauses.append("m.category = ?")
|
||||||
|
params.append(category)
|
||||||
|
|
||||||
|
# 취소된 제품 제외
|
||||||
|
where_clauses.append("(m.cancel_date IS NULL OR m.cancel_date = '')")
|
||||||
|
|
||||||
|
params.append(limit)
|
||||||
|
|
||||||
|
cursor.execute(f"""
|
||||||
|
SELECT m.id, m.product_name, m.company_name, m.spec,
|
||||||
|
m.total_quantity, m.form_type, m.package_type,
|
||||||
|
m.item_std_code, m.category, m.representative_code,
|
||||||
|
m.standard_code, m.ingredient_name_code, m.notes,
|
||||||
|
m.atc_code
|
||||||
|
FROM med_master.medicine_master m
|
||||||
|
WHERE {' AND '.join(where_clauses)}
|
||||||
|
ORDER BY m.product_name, m.spec
|
||||||
|
LIMIT ?
|
||||||
|
""", params)
|
||||||
|
|
||||||
|
results = [dict(row) for row in cursor.fetchall()]
|
||||||
|
|
||||||
|
return jsonify({'success': True, 'data': results, 'count': len(results)})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({'success': False, 'error': str(e)}), 500
|
||||||
|
|
||||||
|
@app.route('/api/medicine-master/categories', methods=['GET'])
|
||||||
|
def get_medicine_categories():
|
||||||
|
"""의약품 마스터 카테고리 목록 (전문일반구분)"""
|
||||||
|
try:
|
||||||
|
with get_db() as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT category, COUNT(*) as cnt
|
||||||
|
FROM med_master.medicine_master
|
||||||
|
WHERE category != '' AND (cancel_date IS NULL OR cancel_date = '')
|
||||||
|
GROUP BY category
|
||||||
|
ORDER BY cnt DESC
|
||||||
|
""")
|
||||||
|
categories = [{'name': row['category'], 'count': row['cnt']} for row in cursor.fetchall()]
|
||||||
|
|
||||||
|
return jsonify({'success': True, 'data': categories})
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({'success': False, 'error': str(e)}), 500
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# 데이터베이스 초기화
|
# 데이터베이스 초기화
|
||||||
if not os.path.exists(app.config['DATABASE']):
|
if not os.path.exists(app.config['DATABASE']):
|
||||||
|
|||||||
@ -12,6 +12,7 @@ PROJECT_ROOT = Path(__file__).parent
|
|||||||
|
|
||||||
# 데이터베이스 경로 - 항상 절대 경로 사용
|
# 데이터베이스 경로 - 항상 절대 경로 사용
|
||||||
DATABASE_PATH = PROJECT_ROOT / 'database' / 'kdrug.db'
|
DATABASE_PATH = PROJECT_ROOT / 'database' / 'kdrug.db'
|
||||||
|
MEDICINE_MASTER_PATH = PROJECT_ROOT / 'database' / 'medicine_master.db'
|
||||||
|
|
||||||
# 기타 자주 사용하는 경로들
|
# 기타 자주 사용하는 경로들
|
||||||
STATIC_PATH = PROJECT_ROOT / 'static'
|
STATIC_PATH = PROJECT_ROOT / 'static'
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user