feat(admin): 기간별 사용약품 조회 페이지 완성

- /admin/drug-usage 페이지 + API 3개 구현
- GET /api/drug-usage: 기간별 약품 통계 (조제건수, 입고건수)
- GET /api/drug-usage/<code>/imports: 약품별 입고 상세
- GET /api/drug-usage/<code>/prescriptions: 약품별 조제 상세

UX 개선:
- 약품 클릭 시 입고/조제 상세 펼침 패널
- table-layout:fixed + colgroup으로 컬럼 너비 고정
- white-space:nowrap으로 날짜/숫자 줄바꿈 방지
- 금액/거래처 사이 border로 구분선 추가
- 발행기관 OrderName으로 수정 (InsName 오류 수정)

QT_GUI 데이터와 100% 일치 검증 (살라겐정)
This commit is contained in:
thug0bin
2026-03-11 19:38:06 +09:00
parent 04bf7a8535
commit 6db31785fa
9 changed files with 1274 additions and 0 deletions

View File

@@ -3498,6 +3498,12 @@ def admin_products():
return render_template('admin_products.html')
@app.route('/admin/drug-usage')
def admin_drug_usage():
"""기간별 사용약품 조회 페이지"""
return render_template('admin_drug_usage.html')
@app.route('/admin/members')
def admin_members():
"""회원 검색 페이지 (팜IT3000 CD_PERSON, 알림톡/SMS 발송)"""
@@ -8828,6 +8834,113 @@ def api_drug_usage():
}), 500
@app.route('/api/drug-usage/<drug_code>/imports')
def api_drug_usage_imports(drug_code):
"""약품별 입고 상세 API"""
start_date = request.args.get('start_date', '')
end_date = request.args.get('end_date', '')
if not start_date or not end_date:
return jsonify({'success': False, 'error': 'start_date, end_date 필수'}), 400
try:
drug_session = db_manager.get_session('PM_DRUG')
result = drug_session.execute(text("""
SELECT
wm.WH_DT_appl as import_date,
ws.WH_NM_item_a as quantity,
ws.WH_MY_unit_a as unit_price,
c.CD_NM_custom as supplier_name,
c.CD_NM_charge1 as contact_person
FROM WH_sub ws
INNER JOIN WH_main wm ON ws.WH_SR_stock = wm.WH_NO_stock
LEFT JOIN PM_BASE.dbo.CD_custom c ON wm.WH_CD_cust_sale = c.CD_CD_custom
WHERE ws.DrugCode = :drug_code
AND wm.WH_DT_appl BETWEEN :start_date AND :end_date
ORDER BY wm.WH_DT_appl DESC
"""), {'drug_code': drug_code, 'start_date': start_date, 'end_date': end_date})
items = []
for row in result:
qty = float(row.quantity) if row.quantity else 0
price = float(row.unit_price) if row.unit_price else 0
items.append({
'import_date': row.import_date or '',
'quantity': qty,
'unit_price': price,
'amount': qty * price,
'supplier_name': row.supplier_name or '',
'person_name': row.contact_person or ''
})
return jsonify({
'success': True,
'drug_code': drug_code,
'total_count': len(items),
'items': items
})
except Exception as e:
logging.error(f"drug-usage imports API 오류: {e}")
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/drug-usage/<drug_code>/prescriptions')
def api_drug_usage_prescriptions(drug_code):
"""약품별 조제(매출) 상세 API"""
start_date = request.args.get('start_date', '')
end_date = request.args.get('end_date', '')
if not start_date or not end_date:
return jsonify({'success': False, 'error': 'start_date, end_date 필수'}), 400
try:
pres_session = db_manager.get_session('PM_PRES')
result = pres_session.execute(text("""
SELECT
pm.Indate as rx_date,
CONVERT(varchar, DATEADD(day, sp.Days, CONVERT(date, pm.Indate, 112)), 112) as expiry_date,
pm.Paname as patient_name,
pm.OrderName as institution_name,
sp.QUAN as dosage,
sp.QUAN_TIME as frequency,
sp.Days as days
FROM PS_sub_pharm sp
INNER JOIN PS_main pm ON pm.PreSerial = sp.PreSerial
WHERE sp.DrugCode = :drug_code
AND pm.Indate BETWEEN :start_date AND :end_date
AND (sp.PS_Type IS NULL OR sp.PS_Type != '9')
ORDER BY pm.Indate DESC
"""), {'drug_code': drug_code, 'start_date': start_date, 'end_date': end_date})
items = []
for row in result:
dosage = float(row.dosage) if row.dosage else 0
freq = float(row.frequency) if row.frequency else 0
days = int(row.days) if row.days else 0
items.append({
'rx_date': row.rx_date or '',
'expiry_date': row.expiry_date or '',
'patient_name': row.patient_name or '',
'institution_name': row.institution_name or '',
'dosage': dosage,
'frequency': freq,
'days': days,
'total_qty': dosage * freq * days
})
return jsonify({
'success': True,
'drug_code': drug_code,
'total_count': len(items),
'items': items
})
except Exception as e:
logging.error(f"drug-usage prescriptions API 오류: {e}")
return jsonify({'success': False, 'error': str(e)}), 500
if __name__ == '__main__':
import os