feat: PMR 조제관리 - MSSQL(PharmaIT3000) 연동
- pmr_api.py: 192.168.0.4 MSSQL 연결 - /pmr/api/prescriptions: 일별 처방전 목록 - /pmr/api/prescription/<id>: 처방전 상세 - /pmr/api/stats: 당일 통계 - /pmr/api/test: DB 연결 테스트 - pmr.html: API 엔드포인트 수정
This commit is contained in:
322
backend/pmr_api.py
Normal file
322
backend/pmr_api.py
Normal file
@@ -0,0 +1,322 @@
|
||||
# pmr_api.py - 조제관리(PMR) Blueprint API
|
||||
# PharmaIT3000 MSSQL 연동 (192.168.0.4)
|
||||
|
||||
from flask import Blueprint, jsonify, request, render_template
|
||||
import pyodbc
|
||||
from datetime import datetime, date
|
||||
import logging
|
||||
|
||||
pmr_bp = Blueprint('pmr', __name__, url_prefix='/pmr')
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# MSSQL 연결 설정 (PharmaIT3000 - 192.168.0.4)
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
MSSQL_CONFIG = {
|
||||
'server': '192.168.0.4\\PM2014',
|
||||
'username': 'sa',
|
||||
'password': 'tmddls214!%(',
|
||||
'driver': 'ODBC Driver 17 for SQL Server'
|
||||
}
|
||||
|
||||
def get_mssql_connection(database='PM_PRES'):
|
||||
"""MSSQL 연결 획득"""
|
||||
conn_str = (
|
||||
f"DRIVER={{{MSSQL_CONFIG['driver']}}};"
|
||||
f"SERVER={MSSQL_CONFIG['server']};"
|
||||
f"DATABASE={database};"
|
||||
f"UID={MSSQL_CONFIG['username']};"
|
||||
f"PWD={MSSQL_CONFIG['password']};"
|
||||
"TrustServerCertificate=yes;"
|
||||
"Connection Timeout=10"
|
||||
)
|
||||
return pyodbc.connect(conn_str, timeout=10)
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# 조제관리 페이지
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
@pmr_bp.route('/')
|
||||
def pmr_index():
|
||||
"""조제관리 메인 페이지"""
|
||||
return render_template('pmr.html')
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# API: 날짜별 처방전 목록
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
@pmr_bp.route('/api/prescriptions', methods=['GET'])
|
||||
def get_prescriptions_by_date():
|
||||
"""
|
||||
날짜별 처방전 목록 조회
|
||||
Query Params:
|
||||
- date: YYYY-MM-DD (기본값: 오늘)
|
||||
"""
|
||||
try:
|
||||
date_str = request.args.get('date', date.today().strftime('%Y-%m-%d'))
|
||||
# YYYYMMDD 형식으로 변환
|
||||
date_yyyymmdd = date_str.replace('-', '')
|
||||
|
||||
conn = get_mssql_connection('PM_PRES')
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("""
|
||||
SELECT
|
||||
PreSerial,
|
||||
Day_Serial,
|
||||
PassDay,
|
||||
Paname,
|
||||
PaNum,
|
||||
CusCode,
|
||||
InsName,
|
||||
Drname,
|
||||
PresTime,
|
||||
PreGubun,
|
||||
PRICE_T,
|
||||
PRICE_P,
|
||||
PRICE_C
|
||||
FROM PS_MAIN
|
||||
WHERE PassDay = ?
|
||||
ORDER BY Day_Serial ASC
|
||||
""", (date_yyyymmdd,))
|
||||
|
||||
prescriptions = []
|
||||
for row in cursor.fetchall():
|
||||
# 주민번호에서 나이/성별 추출
|
||||
panum = row.PaNum or ''
|
||||
age = None
|
||||
gender = None
|
||||
if len(panum) >= 7:
|
||||
try:
|
||||
birth_year = int(panum[:2])
|
||||
gender_code = panum[6] if len(panum) > 6 else ''
|
||||
|
||||
# 성별 및 세기 판단
|
||||
if gender_code in ['1', '2', '5', '6']:
|
||||
birth_year += 1900
|
||||
elif gender_code in ['3', '4', '7', '8']:
|
||||
birth_year += 2000
|
||||
else:
|
||||
birth_year += 1900
|
||||
|
||||
gender = '남' if gender_code in ['1', '3', '5', '7'] else '여'
|
||||
age = datetime.now().year - birth_year
|
||||
except:
|
||||
pass
|
||||
|
||||
prescriptions.append({
|
||||
'prescription_id': row.PreSerial,
|
||||
'order_number': row.Day_Serial,
|
||||
'date': row.PassDay,
|
||||
'patient_name': row.Paname,
|
||||
'patient_id': row.PaNum[:6] + '******' if row.PaNum and len(row.PaNum) > 6 else row.PaNum,
|
||||
'patient_code': row.CusCode,
|
||||
'hospital': row.InsName,
|
||||
'doctor': row.Drname,
|
||||
'time': row.PresTime,
|
||||
'type': '급여' if row.PreGubun == '0' else '비급여' if row.PreGubun == '9' else row.PreGubun,
|
||||
'age': age,
|
||||
'gender': gender,
|
||||
'price_total': row.PRICE_T,
|
||||
'price_patient': row.PRICE_P,
|
||||
'price_claim': row.PRICE_C
|
||||
})
|
||||
|
||||
conn.close()
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'date': date_str,
|
||||
'count': len(prescriptions),
|
||||
'prescriptions': prescriptions
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"PMR 처방전 목록 조회 오류: {e}")
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# API: 처방전 상세 (약품 목록)
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
@pmr_bp.route('/api/prescription/<prescription_id>', methods=['GET'])
|
||||
def get_prescription_detail(prescription_id):
|
||||
"""
|
||||
처방전 상세 정보 (약품 목록 포함)
|
||||
"""
|
||||
try:
|
||||
conn = get_mssql_connection('PM_PRES')
|
||||
cursor = conn.cursor()
|
||||
|
||||
# 처방전 기본 정보
|
||||
cursor.execute("""
|
||||
SELECT
|
||||
PreSerial,
|
||||
Day_Serial,
|
||||
PassDay,
|
||||
Paname,
|
||||
PaNum,
|
||||
CusCode,
|
||||
InsName,
|
||||
Drname,
|
||||
PresTime,
|
||||
PreGubun,
|
||||
PRICE_T,
|
||||
PRICE_P,
|
||||
PRICE_C
|
||||
FROM PS_MAIN
|
||||
WHERE PreSerial = ?
|
||||
""", (prescription_id,))
|
||||
|
||||
rx_row = cursor.fetchone()
|
||||
if not rx_row:
|
||||
conn.close()
|
||||
return jsonify({'success': False, 'error': '처방전을 찾을 수 없습니다'}), 404
|
||||
|
||||
# 처방 약품 목록 (PS_sub_pharm 테이블 확인 필요)
|
||||
cursor.execute("""
|
||||
SELECT COLUMN_NAME
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_NAME = 'PS_sub_pharm'
|
||||
""")
|
||||
sub_columns = [row[0] for row in cursor.fetchall()]
|
||||
|
||||
# 약품 목록 조회
|
||||
medications = []
|
||||
if 'PreSerial' in sub_columns:
|
||||
cursor.execute("""
|
||||
SELECT *
|
||||
FROM PS_sub_pharm
|
||||
WHERE PreSerial = ?
|
||||
ORDER BY 1
|
||||
""", (prescription_id,))
|
||||
|
||||
med_columns = [col[0] for col in cursor.description]
|
||||
for row in cursor.fetchall():
|
||||
med_dict = dict(zip(med_columns, row))
|
||||
medications.append({
|
||||
'medication_code': med_dict.get('GoodsCode') or med_dict.get('PCODE') or '',
|
||||
'med_name': med_dict.get('GoodsName') or med_dict.get('PNAME') or '',
|
||||
'dosage': med_dict.get('Once_Qty') or med_dict.get('POESSION') or 0,
|
||||
'frequency': med_dict.get('Times') or med_dict.get('PTIMES') or 0,
|
||||
'duration': med_dict.get('Days') or med_dict.get('PDAY') or 0,
|
||||
'total_qty': med_dict.get('Total_Qty') or 0,
|
||||
'type': med_dict.get('PS_Type', '0')
|
||||
})
|
||||
|
||||
conn.close()
|
||||
|
||||
# 나이/성별 계산
|
||||
panum = rx_row.PaNum or ''
|
||||
age = None
|
||||
gender = None
|
||||
if len(panum) >= 7:
|
||||
try:
|
||||
birth_year = int(panum[:2])
|
||||
gender_code = panum[6]
|
||||
if gender_code in ['1', '2', '5', '6']:
|
||||
birth_year += 1900
|
||||
elif gender_code in ['3', '4', '7', '8']:
|
||||
birth_year += 2000
|
||||
gender = '남' if gender_code in ['1', '3', '5', '7'] else '여'
|
||||
age = datetime.now().year - birth_year
|
||||
except:
|
||||
pass
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'prescription': {
|
||||
'prescription_id': rx_row.PreSerial,
|
||||
'order_number': rx_row.Day_Serial,
|
||||
'date': rx_row.PassDay,
|
||||
'time': rx_row.PresTime,
|
||||
'hospital': rx_row.InsName,
|
||||
'doctor': rx_row.Drname,
|
||||
'type': '급여' if rx_row.PreGubun == '0' else '비급여',
|
||||
'price_total': rx_row.PRICE_T,
|
||||
'price_patient': rx_row.PRICE_P
|
||||
},
|
||||
'patient': {
|
||||
'name': rx_row.Paname,
|
||||
'code': rx_row.CusCode,
|
||||
'age': age,
|
||||
'gender': gender
|
||||
},
|
||||
'medications': medications,
|
||||
'medication_count': len(medications)
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"PMR 처방전 상세 조회 오류: {e}")
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# API: 통계 (당일 요약)
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
@pmr_bp.route('/api/stats', methods=['GET'])
|
||||
def get_daily_stats():
|
||||
"""당일 조제 통계"""
|
||||
try:
|
||||
date_str = request.args.get('date', date.today().strftime('%Y-%m-%d'))
|
||||
date_yyyymmdd = date_str.replace('-', '')
|
||||
|
||||
conn = get_mssql_connection('PM_PRES')
|
||||
cursor = conn.cursor()
|
||||
|
||||
# 처방전 수
|
||||
cursor.execute("""
|
||||
SELECT COUNT(*) as cnt
|
||||
FROM PS_MAIN
|
||||
WHERE PassDay = ?
|
||||
""", (date_yyyymmdd,))
|
||||
total_prescriptions = cursor.fetchone()[0]
|
||||
|
||||
# 총 금액
|
||||
cursor.execute("""
|
||||
SELECT
|
||||
ISNULL(SUM(PRICE_T), 0) as total,
|
||||
ISNULL(SUM(PRICE_P), 0) as patient,
|
||||
ISNULL(SUM(PRICE_C), 0) as claim
|
||||
FROM PS_MAIN
|
||||
WHERE PassDay = ?
|
||||
""", (date_yyyymmdd,))
|
||||
price_row = cursor.fetchone()
|
||||
|
||||
conn.close()
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'date': date_str,
|
||||
'stats': {
|
||||
'total_prescriptions': total_prescriptions,
|
||||
'total_amount': price_row[0] if price_row else 0,
|
||||
'patient_amount': price_row[1] if price_row else 0,
|
||||
'claim_amount': price_row[2] if price_row else 0
|
||||
}
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"PMR 통계 조회 오류: {e}")
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# API: DB 연결 테스트
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
@pmr_bp.route('/api/test', methods=['GET'])
|
||||
def test_connection():
|
||||
"""DB 연결 테스트"""
|
||||
try:
|
||||
conn = get_mssql_connection('PM_PRES')
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT @@VERSION")
|
||||
version = cursor.fetchone()[0]
|
||||
conn.close()
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'server': MSSQL_CONFIG['server'],
|
||||
'version': version[:100] + '...'
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
Reference in New Issue
Block a user