From 4a529fc89161dd3af323da320f9fae9305e30469 Mon Sep 17 00:00:00 2001 From: thug0bin Date: Wed, 11 Mar 2026 23:26:22 +0900 Subject: [PATCH] =?UTF-8?q?feat(admin):=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EA=B5=AC=EB=A7=A4=20=EC=9D=B4=EB=A0=A5=EC=97=90=20MSSQL=20?= =?UTF-8?q?=EC=A7=81=EC=A0=91=20=EA=B5=AC=EB=A7=A4=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 배경 - 기존: QR 적립된 구매만 표시 (SQLite claim_tokens) - 문제: pos-live에서 고객 매핑한 구매가 안 보임 ## 변경 사항 - admin_user_detail API에 MSSQL SALE_MAIN 조회 추가 - 전화번호 → CD_PERSON.CUSCODE → SALE_MAIN.SL_CD_custom 매칭 - QR 적립 구매와 POS 직접 구매 통합 표시 - 중복 제거: 이미 QR 적립된 건은 스킵 - 최근 30일, 최대 20건 조회 ## 구매 소스 구분 - QR 적립: points > 0 - POS 직접 매핑: points = 0, source = 'pos' --- backend/app.py | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/backend/app.py b/backend/app.py index c0e04ca..d9f1163 100644 --- a/backend/app.py +++ b/backend/app.py @@ -1580,6 +1580,97 @@ def admin_user_detail(user_id): print(f"[WARNING] MSSQL 조회 실패 (user {user_id}): {mssql_error}") purchases = [] + # 5-1. MSSQL 직접 구매 이력 추가 (QR 적립 안 된 구매) + # 전화번호 → CUSCODE → SALE_MAIN 조회 + try: + if user['phone']: + phone_clean = user['phone'].replace('-', '').replace(' ', '') + base_session = db_manager.get_session('PM_BASE') + pres_session = db_manager.get_session('PM_PRES') + + # 전화번호로 CUSCODE 조회 + 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_clean}).fetchone() + + if cus_row: + cuscode = cus_row.CUSCODE + + # 이미 QR 적립된 transaction_id 목록 + existing_tx_ids = {p['transaction_id'] for p in purchases} + + # SALE_MAIN에서 이 고객의 구매 조회 (최근 30일, 최대 20건) + sale_query = text(""" + SELECT TOP 20 + M.SL_NO_order, + M.InsertTime, + M.SL_MY_sale + FROM SALE_MAIN M + WHERE M.SL_CD_custom = :cuscode + AND M.InsertTime >= DATEADD(day, -30, GETDATE()) + ORDER BY M.InsertTime DESC + """) + sales = pres_session.execute(sale_query, {'cuscode': cuscode}).fetchall() + + for sale in sales: + tx_id = sale.SL_NO_order + if tx_id in existing_tx_ids: + continue # 이미 QR 적립된 건 스킵 + + # 품목 조회 + items_query = text(""" + SELECT + S.DrugCode, + ISNULL(G.GoodsName, '(약품명 없음)') AS goods_name, + S.SL_NM_item AS quantity, + S.SL_NM_cost_a AS price, + S.SL_TOTAL_PRICE AS total + FROM SALE_SUB S + LEFT JOIN PM_DRUG.dbo.CD_GOODS G ON S.DrugCode = G.DrugCode + WHERE S.SL_NO_order = :tx_id + """) + items_raw = pres_session.execute(items_query, {'tx_id': tx_id}).fetchall() + + items = [{ + 'code': item.DrugCode, + 'barcode': '', + 'name': item.goods_name, + 'qty': int(item.quantity or 0), + 'price': int(item.price or 0), + 'total': int(item.total or 0), + 'categories': [] + } for item in items_raw] + + # 상품 요약 + if items: + first_item_name = items[0]['name'] + items_count = len(items) + items_summary = first_item_name if items_count == 1 else f"{first_item_name} 외 {items_count - 1}개" + else: + items_summary = "상품 정보 없음" + items_count = 0 + + purchases.append({ + 'transaction_id': tx_id, + 'date': str(sale.InsertTime)[:16].replace('T', ' ') if sale.InsertTime else '-', + 'amount': int(sale.SL_MY_sale or 0), + 'points': 0, # QR 적립 안 됨 + 'items_summary': items_summary, + 'items_count': items_count, + 'items': items, + 'source': 'pos' # POS 직접 매핑 구매 + }) + + # 날짜순 정렬 (최신 먼저) + purchases.sort(key=lambda x: x['date'], reverse=True) + except Exception as pos_purchase_error: + logging.warning(f"POS 구매 이력 조회 실패 (user {user_id}): {pos_purchase_error}") + # 6. 조제 이력 조회 (전화번호 → CUSCODE → PS_main) prescriptions = [] pos_customer = None