diff --git a/backend/app.py b/backend/app.py index bb99d5e..9bed1ca 100644 --- a/backend/app.py +++ b/backend/app.py @@ -3010,6 +3010,8 @@ def api_member_history(phone): 회원 구매 이력 통합 조회 API - 마일리지 적립/사용 내역 (SQLite) - transaction_id로 POS 품목 조회 (MSSQL) + - 전체 구매 이력 (SALE_MAIN) + - 조제 이력 (PS_main) """ try: # 전화번호 정규화 @@ -3019,7 +3021,9 @@ def api_member_history(phone): 'success': True, 'phone': phone, 'mileage': None, - 'purchases': [] + 'purchases': [], # 전체 구매 이력 + 'prescriptions': [], # 조제 이력 + 'pos_customer': None } transaction_ids = [] # 적립된 거래번호 수집 @@ -3082,7 +3086,29 @@ def api_member_history(phone): except Exception as e: logging.warning(f"마일리지 조회 실패: {e}") - # 2. transaction_id로 POS 품목 조회 (MSSQL) + # 2. 전화번호로 POS 고객코드 조회 (MSSQL) + cuscode = None + try: + base_session = db_manager.get_session('PM_BASE') + cuscode_query = text(""" + SELECT TOP 1 CUSCODE, PANAME + FROM CD_PERSON + WHERE REPLACE(REPLACE(PHONE, '-', ''), ' ', '') = :phone + OR REPLACE(REPLACE(TEL_NO, '-', ''), ' ', '') = :phone + OR REPLACE(REPLACE(PHONE2, '-', ''), ' ', '') = :phone + """) + cus_row = base_session.execute(cuscode_query, {'phone': phone}).fetchone() + + if cus_row: + cuscode = cus_row.CUSCODE + result['pos_customer'] = { + 'cuscode': cuscode, + 'name': cus_row.PANAME + } + except Exception as e: + logging.warning(f"POS 고객 조회 실패: {e}") + + # 3. transaction_id로 POS 품목 조회 (마일리지 적립 내역) if transaction_ids and result['mileage']: try: pres_session = db_manager.get_session('PM_PRES') @@ -3118,6 +3144,112 @@ def api_member_history(phone): except Exception as e: logging.warning(f"POS 품목 조회 실패: {e}") + # 4. 전체 구매 이력 조회 (고객코드 기준) + if cuscode: + try: + pres_session = db_manager.get_session('PM_PRES') + + # 최근 60일 구매 이력 + purchase_query = text(""" + SELECT TOP 30 + M.SL_NO_order as order_no, + M.SL_DT_appl as order_date, + M.SL_MY_total as total_amount + FROM SALE_MAIN M + WHERE M.SL_CD_custom = :cuscode + ORDER BY M.SL_DT_appl DESC, M.SL_NO_order DESC + """) + orders = pres_session.execute(purchase_query, {'cuscode': cuscode}).fetchall() + + purchases = [] + for order in orders: + # 품목 조회 + items_query = text(""" + SELECT + S.DrugCode, + G.GoodsName, + S.QUAN as quantity, + S.SL_TOTAL_PRICE as price + FROM SALE_SUB S + LEFT JOIN PM_DRUG.dbo.CD_GOODS G ON S.DrugCode = G.DrugCode + WHERE S.SL_NO_order = :order_no + """) + items = pres_session.execute(items_query, {'order_no': order.order_no}).fetchall() + + purchases.append({ + 'order_no': order.order_no, + 'date': order.order_date, + 'total': float(order.total_amount) if order.total_amount else 0, + 'items': [{ + 'drug_code': item.DrugCode, + 'name': item.GoodsName or '알 수 없음', + 'quantity': float(item.quantity) if item.quantity else 1, + 'price': float(item.price) if item.price else 0 + } for item in items] + }) + + result['purchases'] = purchases + + except Exception as e: + logging.warning(f"전체 구매 이력 조회 실패: {e}") + + # 5. 조제 이력 조회 (고객코드 기준) + if cuscode: + try: + pres_session = db_manager.get_session('PM_PRES') + + # 최근 조제 이력 (최대 30건) + rx_query = text(""" + SELECT TOP 30 + P.PreSerial, + P.Indate, + P.Paname, + P.Drname, + P.OrderName, + P.TDAYS + FROM PS_main P + WHERE P.CusCode = :cuscode + ORDER BY P.Indate DESC, P.PreSerial DESC + """) + rxs = pres_session.execute(rx_query, {'cuscode': cuscode}).fetchall() + + prescriptions = [] + for rx in rxs: + # 처방 품목 조회 + items_query = text(""" + SELECT + S.DrugCode, + G.GoodsName, + S.Days, + S.QUAN, + S.QUAN_TIME + FROM PS_sub_pharm S + LEFT JOIN PM_DRUG.dbo.CD_GOODS G ON S.DrugCode = G.DrugCode + WHERE S.PreSerial = :pre_serial + """) + items = pres_session.execute(items_query, {'pre_serial': rx.PreSerial}).fetchall() + + prescriptions.append({ + 'pre_serial': rx.PreSerial, + 'date': rx.Indate, + 'patient_name': rx.Paname, + 'doctor': rx.Drname, + 'hospital': rx.OrderName, + 'total_days': rx.TDAYS, + 'items': [{ + 'drug_code': item.DrugCode, + 'name': item.GoodsName or '알 수 없음', + 'days': float(item.Days) if item.Days else 0, + 'quantity': float(item.QUAN) if item.QUAN else 0, + 'times_per_day': float(item.QUAN_TIME) if item.QUAN_TIME else 0 + } for item in items] + }) + + result['prescriptions'] = prescriptions + + except Exception as e: + logging.warning(f"조제 이력 조회 실패: {e}") + return jsonify(result) except Exception as e: diff --git a/backend/templates/admin_members.html b/backend/templates/admin_members.html index ff35749..bf3914e 100644 --- a/backend/templates/admin_members.html +++ b/backend/templates/admin_members.html @@ -610,8 +610,9 @@
-
📊 적립 내역
-
🛒 구매 이력
+
📊 적립
+
🛒 구매
+
💊 조제
데이터를 불러오는 중...
@@ -888,8 +889,10 @@ if (currentDetailTab === 'mileage') { renderMileageTab(content); - } else { + } else if (currentDetailTab === 'purchase') { renderPurchaseTab(content); + } else if (currentDetailTab === 'prescription') { + renderPrescriptionTab(content); } } @@ -941,26 +944,23 @@ } function renderPurchaseTab(container) { - // 적립 내역 중 품목이 있는 것들만 추출 - if (!detailData.mileage || !detailData.mileage.transactions) { - container.innerHTML = '
📭 구매 이력이 없습니다
'; - return; - } - - const purchases = detailData.mileage.transactions.filter(tx => - tx.items && tx.items.length > 0 && tx.points > 0 - ); - - if (purchases.length === 0) { - container.innerHTML = '
📭 QR 적립된 구매 이력이 없습니다
'; + // POS 전체 구매 이력 (고객코드 기준) + if (!detailData.purchases || detailData.purchases.length === 0) { + if (!detailData.pos_customer) { + container.innerHTML = '
📭 POS 회원으로 등록되지 않았습니다
전화번호가 POS에 등록되면 구매 이력이 표시됩니다
'; + } else { + container.innerHTML = '
📭 구매 이력이 없습니다
'; + } return; } - container.innerHTML = purchases.map(p => { + container.innerHTML = detailData.purchases.map(p => { // 날짜 포맷 - const date = p.created_at ? new Date(p.created_at).toLocaleString('ko-KR', { - year: 'numeric', month: 'short', day: 'numeric' - }) : ''; + const dateStr = p.date || ''; + let formattedDate = dateStr; + if (dateStr.length === 8) { + formattedDate = `${dateStr.slice(0,4)}.${dateStr.slice(4,6)}.${dateStr.slice(6,8)}`; + } // 품목 렌더링 const itemsHtml = (p.items || []).map(item => ` @@ -974,10 +974,9 @@ return `
- 📅 ${date} - ${(p.total_amount || 0).toLocaleString()}원 + 📅 ${formattedDate} + ${(p.total || 0).toLocaleString()}원
-
+${p.points.toLocaleString()}P 적립
${p.items && p.items.length > 0 ? `
${itemsHtml}
` : ''} @@ -985,6 +984,50 @@ `; }).join(''); } + + function renderPrescriptionTab(container) { + // 조제 이력 (고객코드 기준) + if (!detailData.prescriptions || detailData.prescriptions.length === 0) { + if (!detailData.pos_customer) { + container.innerHTML = '
📭 POS 회원으로 등록되지 않았습니다
전화번호가 POS에 등록되면 조제 이력이 표시됩니다
'; + } else { + container.innerHTML = '
📭 조제 이력이 없습니다
'; + } + return; + } + + container.innerHTML = detailData.prescriptions.map(rx => { + // 날짜 포맷 + const dateStr = rx.date || ''; + let formattedDate = dateStr; + if (dateStr.length === 8) { + formattedDate = `${dateStr.slice(0,4)}.${dateStr.slice(4,6)}.${dateStr.slice(6,8)}`; + } + + // 처방 품목 렌더링 + const itemsHtml = (rx.items || []).map(item => ` +
+ ${escapeHtml(item.name)} + ${item.days}일 x${item.times_per_day}회 +
+ `).join(''); + + return ` +
+
+ 📅 ${formattedDate} + ${rx.total_days || ''}일분 +
+
+ 🏥 ${escapeHtml(rx.hospital || '')} · ${escapeHtml(rx.doctor || '')} +
+ ${rx.items && rx.items.length > 0 ? ` +
${itemsHtml}
+ ` : ''} +
+ `; + }).join(''); + } function openSendFromDetail() { if (!currentDetailMember) return;