Files
pharmacy-stats-api/app.py
청춘약국 8abc67a0af fix(api): 보훈 세분화 라벨 매핑 추가 (4_1~4_4)
웹 stats UI 에서 '보훈100%', '보훈60%' 대신 raw 코드 '4_1', '4_2'
가 그대로 노출되던 문제 수정.

v1_pharmit3000.py 가 QT-POS 와 동기화되면서 보훈 세분화 키
(4_1~4_4) 를 반환하기 시작했으나, app.py 의 GUBUN_LABEL dict 에
해당 키가 없어 dict.get(code, code) fallback 으로 날 코드가 그대로
노출됐음.

pharmon-web/sales_stats_dialog.py 의 _GUBUN_LABEL 과 완전 동기화:
- 4_1: 보훈100%  (GITA_GUBUN=1)
- 4_2: 보훈60%   (GITA_GUBUN=2)
- 4_3: 보훈50%   (GITA_GUBUN=3)
- 4_4: 보훈30%   (GITA_GUBUN=4)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 20:56:19 +09:00

322 lines
8.8 KiB
Python

# -*- coding: utf-8 -*-
"""
Pharmacy Stats API - Flask 서버
QT-POS 통계 다이얼로그 API 버전
v1: PharmIT3000
v2: PMPLUS20
"""
from flask import Flask, jsonify, request, render_template
from datetime import date, timedelta
from queries import v1_pharmit3000 as v1
from queries import v2_pmplus20 as v2
app = Flask(__name__)
# 보험구분 라벨 (pharmon-web/sales_stats_dialog.py _GUBUN_LABEL 와 동기화)
GUBUN_LABEL = {
'0': '건강보험',
'1': '의료급여',
'2': '산재',
'3': '자동차',
'4': '보훈', # 기타 보훈 (GITA_GUBUN 없을 때)
'4_1': '보훈100%', # GITA_GUBUN=1
'4_2': '보훈60%', # GITA_GUBUN=2
'4_3': '보훈50%', # GITA_GUBUN=3
'4_4': '보훈30%', # GITA_GUBUN=4
'5': '공상',
'6': '본인',
'7': '차상위1',
'8': '희귀',
'9': '비급여',
'E': '차상위2',
'F': '차상위2',
}
@app.route('/')
def index():
return render_template('stats.html')
# ============== v1 API (PharmIT3000) ==============
@app.route('/v1/api/stats')
def v1_stats():
"""v1 전체 통계"""
date_from = request.args.get('from', _default_from())
date_to = request.args.get('to', _default_to())
try:
result = v1.get_sales_stats(date_from, date_to)
result['version'] = 'v1'
result['source'] = 'PharmIT3000'
result['date_from'] = date_from
result['date_to'] = date_to
return jsonify(result)
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/v1/api/stats/insurance')
def v1_stats_insurance():
"""v1 보험별 통계"""
date_from = request.args.get('from', _default_from())
date_to = request.args.get('to', _default_to())
result = v1.get_sales_stats(date_from, date_to)
by_gubun = []
for code, data in result.get('by_gubun', {}).items():
by_gubun.append({
'code': code,
'label': GUBUN_LABEL.get(code, code),
**data
})
return jsonify({
'version': 'v1',
'source': 'PharmIT3000',
'date_from': date_from,
'date_to': date_to,
'total': result['total'],
'by_gubun': sorted(by_gubun, key=lambda x: x['code'])
})
@app.route('/v1/api/stats/time')
def v1_stats_time():
"""v1 시간가산별 통계"""
date_from = request.args.get('from', _default_from())
date_to = request.args.get('to', _default_to())
result = v1.get_sales_stats(date_from, date_to)
return jsonify({
'version': 'v1',
'source': 'PharmIT3000',
'date_from': date_from,
'date_to': date_to,
'total': result['total'],
'by_time': result['by_time']
})
@app.route('/v1/api/stats/payment')
def v1_stats_payment():
"""v1 결제수단별 통계"""
date_from = request.args.get('from', _default_from())
date_to = request.args.get('to', _default_to())
result = v1.get_sales_stats(date_from, date_to)
return jsonify({
'version': 'v1',
'source': 'PharmIT3000',
'date_from': date_from,
'date_to': date_to,
'total': result['total'],
'by_pay': result['by_pay']
})
@app.route('/v1/api/stats/hospital')
def v1_stats_hospital():
"""v1 병원별 통계"""
date_from = request.args.get('from', _default_from())
date_to = request.args.get('to', _default_to())
result = v1.get_sales_stats(date_from, date_to)
by_hosp = []
for name, data in result.get('by_hosp', {}).items():
by_hosp.append({'name': name, **data})
return jsonify({
'version': 'v1',
'source': 'PharmIT3000',
'date_from': date_from,
'date_to': date_to,
'total': result['total'],
'by_hosp': sorted(by_hosp, key=lambda x: -x['cnt'])[:50] # 상위 50개
})
# ============== v2 API (PMPLUS20) ==============
@app.route('/v2/api/stats')
def v2_stats():
"""v2 전체 통계"""
date_from = request.args.get('from', _default_from())
date_to = request.args.get('to', _default_to())
try:
result = v2.get_sales_stats(date_from, date_to)
result['version'] = 'v2'
result['source'] = 'PMPLUS20'
result['date_from'] = date_from
result['date_to'] = date_to
return jsonify(result)
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/v2/api/stats/insurance')
def v2_stats_insurance():
"""v2 보험별 통계"""
date_from = request.args.get('from', _default_from())
date_to = request.args.get('to', _default_to())
result = v2.get_sales_stats(date_from, date_to)
if 'error' in result:
return jsonify(result), 500
by_gubun = []
for code, data in result.get('by_gubun', {}).items():
by_gubun.append({
'code': code,
'label': GUBUN_LABEL.get(code, code),
**data
})
return jsonify({
'version': 'v2',
'source': 'PMPLUS20',
'date_from': date_from,
'date_to': date_to,
'total': result['total'],
'by_gubun': sorted(by_gubun, key=lambda x: x['code'])
})
@app.route('/v2/api/stats/time')
def v2_stats_time():
"""v2 시간가산별 통계"""
date_from = request.args.get('from', _default_from())
date_to = request.args.get('to', _default_to())
result = v2.get_sales_stats(date_from, date_to)
if 'error' in result:
return jsonify(result), 500
return jsonify({
'version': 'v2',
'source': 'PMPLUS20',
'date_from': date_from,
'date_to': date_to,
'total': result['total'],
'by_time': result['by_time']
})
@app.route('/v2/api/stats/payment')
def v2_stats_payment():
"""v2 결제수단별 통계"""
date_from = request.args.get('from', _default_from())
date_to = request.args.get('to', _default_to())
result = v2.get_sales_stats(date_from, date_to)
if 'error' in result:
return jsonify(result), 500
return jsonify({
'version': 'v2',
'source': 'PMPLUS20',
'date_from': date_from,
'date_to': date_to,
'total': result['total'],
'by_pay': result['by_pay']
})
@app.route('/v2/api/stats/hospital')
def v2_stats_hospital():
"""v2 병원별 통계"""
date_from = request.args.get('from', _default_from())
date_to = request.args.get('to', _default_to())
result = v2.get_sales_stats(date_from, date_to)
if 'error' in result:
return jsonify(result), 500
by_hosp = []
for name, data in result.get('by_hosp', {}).items():
by_hosp.append({'name': name, **data})
return jsonify({
'version': 'v2',
'source': 'PMPLUS20',
'date_from': date_from,
'date_to': date_to,
'total': result['total'],
'by_hosp': sorted(by_hosp, key=lambda x: -x['cnt'])[:50]
})
# ============== 비교 API ==============
@app.route('/api/compare')
def compare():
"""v1 vs v2 비교"""
date_from = request.args.get('from', _default_from())
date_to = request.args.get('to', _default_to())
v1_result = v1.get_sales_stats(date_from, date_to)
v2_result = v2.get_sales_stats(date_from, date_to)
# 차이 계산
diff = {}
if 'total' in v1_result and 'total' in v2_result:
v1_total = v1_result['total']
v2_total = v2_result['total']
for key in v1_total:
v1_val = v1_total.get(key, 0)
v2_val = v2_total.get(key, 0)
diff[key] = v2_val - v1_val
return jsonify({
'date_from': date_from,
'date_to': date_to,
'v1': {
'source': 'PharmIT3000',
'total': v1_result.get('total', {}),
'error': v1_result.get('error')
},
'v2': {
'source': 'PMPLUS20',
'total': v2_result.get('total', {}),
'error': v2_result.get('error')
},
'diff': diff
})
def _default_from():
"""기본 시작일: 이번 달 1일"""
today = date.today()
return today.replace(day=1).strftime('%Y%m%d')
def _default_to():
"""기본 종료일: 오늘"""
return date.today().strftime('%Y%m%d')
if __name__ == '__main__':
print("🏥 Pharmacy Stats API")
print("http://0.0.0.0:5060")
print("")
print("Endpoints:")
print(" /v1/api/stats - PharmIT3000 전체 통계")
print(" /v1/api/stats/insurance - PharmIT3000 보험별")
print(" /v1/api/stats/time - PharmIT3000 시간가산별")
print(" /v1/api/stats/payment - PharmIT3000 결제수단별")
print(" /v1/api/stats/hospital - PharmIT3000 병원별")
print("")
print(" /v2/api/stats/... - PMPLUS20 (동일 구조)")
print("")
print(" /api/compare - v1 vs v2 비교")
app.run(host='0.0.0.0', port=5050, debug=True)