feat: POS 실시간 판매 조회 웹 페이지 (Qt GUI 웹 버전)
This commit is contained in:
263
backend/app.py
263
backend/app.py
@@ -4851,6 +4851,269 @@ def get_breeds(species):
|
||||
return jsonify({'success': True, 'breeds': ['기타']})
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# POS 실시간 판매 조회 (Qt GUI 웹 버전)
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
@app.route('/admin/pos-live')
|
||||
def admin_pos_live():
|
||||
"""POS 실시간 판매 조회 페이지 (Qt GUI 웹 버전)"""
|
||||
return render_template('admin_pos_live.html')
|
||||
|
||||
|
||||
@app.route('/api/admin/pos-live')
|
||||
def api_admin_pos_live():
|
||||
"""
|
||||
실시간 판매 내역 API (Qt GUI와 동일한 쿼리)
|
||||
- MSSQL: SALE_MAIN, CD_SUNAB, SALE_SUB
|
||||
- SQLite: claim_tokens, users, mileage_ledger
|
||||
"""
|
||||
date_str = request.args.get('date')
|
||||
if not date_str:
|
||||
date_str = datetime.now().strftime('%Y%m%d')
|
||||
|
||||
mssql_conn = None
|
||||
try:
|
||||
# MSSQL 연결
|
||||
mssql_engine = db_manager.get_engine('PM_PRES')
|
||||
mssql_conn = mssql_engine.raw_connection()
|
||||
mssql_cursor = mssql_conn.cursor()
|
||||
|
||||
# SQLite 연결
|
||||
sqlite_conn = db_manager.get_sqlite_connection()
|
||||
sqlite_cursor = sqlite_conn.cursor()
|
||||
|
||||
# 메인 쿼리: SALE_MAIN + CD_SUNAB 조인
|
||||
query = """
|
||||
SELECT
|
||||
M.SL_NO_order,
|
||||
M.InsertTime,
|
||||
M.SL_MY_sale,
|
||||
ISNULL(M.SL_NM_custom, '[비고객]') AS customer_name,
|
||||
ISNULL(S.card_total, 0) AS card_total,
|
||||
ISNULL(S.cash_total, 0) AS cash_total,
|
||||
ISNULL(M.SL_MY_total, 0) AS total_amount,
|
||||
ISNULL(M.SL_MY_discount, 0) AS discount,
|
||||
S.cash_receipt_mode,
|
||||
S.cash_receipt_num
|
||||
FROM SALE_MAIN M
|
||||
OUTER APPLY (
|
||||
SELECT TOP 1
|
||||
ISNULL(ETC_CARD, 0) + ISNULL(OTC_CARD, 0) AS card_total,
|
||||
ISNULL(ETC_CASH, 0) + ISNULL(OTC_CASH, 0) AS cash_total,
|
||||
nCASHINMODE AS cash_receipt_mode,
|
||||
nAPPROVAL_NUM AS cash_receipt_num
|
||||
FROM CD_SUNAB
|
||||
WHERE PRESERIAL = M.SL_NO_order
|
||||
) S
|
||||
WHERE M.SL_DT_appl = ?
|
||||
ORDER BY M.InsertTime DESC
|
||||
"""
|
||||
|
||||
mssql_cursor.execute(query, date_str)
|
||||
rows = mssql_cursor.fetchall()
|
||||
|
||||
sales_list = []
|
||||
total_sales = 0
|
||||
|
||||
for row in rows:
|
||||
order_no, insert_time, sale_amount, customer, card_total, cash_total, total_amount, discount, cash_receipt_mode, cash_receipt_num = row
|
||||
|
||||
# 품목 수 조회 (SALE_SUB)
|
||||
mssql_cursor.execute("""
|
||||
SELECT COUNT(*) FROM SALE_SUB WHERE SL_NO_order = ?
|
||||
""", order_no)
|
||||
item_count_row = mssql_cursor.fetchone()
|
||||
item_count = item_count_row[0] if item_count_row else 0
|
||||
|
||||
# SQLite에서 QR 발행 여부 확인
|
||||
sqlite_cursor.execute("""
|
||||
SELECT id FROM claim_tokens WHERE transaction_id = ?
|
||||
""", (order_no,))
|
||||
qr_record = sqlite_cursor.fetchone()
|
||||
qr_issued = bool(qr_record)
|
||||
|
||||
# SQLite에서 적립 사용자 조회
|
||||
sqlite_cursor.execute("""
|
||||
SELECT u.nickname, u.phone, ct.claimable_points
|
||||
FROM claim_tokens ct
|
||||
LEFT JOIN users u ON ct.claimed_by_user_id = u.id
|
||||
WHERE ct.transaction_id = ? AND ct.claimed_at IS NOT NULL
|
||||
""", (order_no,))
|
||||
claimed_user = sqlite_cursor.fetchone()
|
||||
|
||||
# 적립 사용자 정보 분리
|
||||
if claimed_user and claimed_user['nickname'] and claimed_user['phone']:
|
||||
claimed_name = claimed_user['nickname']
|
||||
claimed_phone = claimed_user['phone']
|
||||
claimed_points = claimed_user['claimable_points']
|
||||
else:
|
||||
claimed_name = ""
|
||||
claimed_phone = ""
|
||||
claimed_points = 0
|
||||
|
||||
# 결제수단 판별
|
||||
card_amt = float(card_total) if card_total else 0.0
|
||||
cash_amt = float(cash_total) if cash_total else 0.0
|
||||
has_cash_receipt = (
|
||||
str(cash_receipt_mode or '').strip() == '1'
|
||||
and str(cash_receipt_num or '').strip() != ''
|
||||
)
|
||||
|
||||
if card_amt > 0 and cash_amt > 0:
|
||||
pay_method = '카드+현금'
|
||||
elif card_amt > 0:
|
||||
pay_method = '카드'
|
||||
elif cash_amt > 0:
|
||||
pay_method = '현영' if has_cash_receipt else '현금'
|
||||
else:
|
||||
pay_method = ''
|
||||
|
||||
paid = (card_amt + cash_amt) > 0
|
||||
disc_amt = float(discount) if discount else 0.0
|
||||
total_amt = float(total_amount) if total_amount else 0.0
|
||||
sale_amt = float(sale_amount) if sale_amount else 0.0
|
||||
|
||||
total_sales += sale_amt
|
||||
|
||||
sales_list.append({
|
||||
'order_no': order_no,
|
||||
'time': insert_time.strftime('%H:%M') if insert_time else '--:--',
|
||||
'amount': sale_amt,
|
||||
'discount': disc_amt,
|
||||
'total_before_dc': total_amt,
|
||||
'customer': customer,
|
||||
'pay_method': pay_method,
|
||||
'paid': paid,
|
||||
'item_count': item_count,
|
||||
'claimed_name': claimed_name,
|
||||
'claimed_phone': claimed_phone,
|
||||
'claimed_points': claimed_points,
|
||||
'qr_issued': qr_issued
|
||||
})
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'date': date_str,
|
||||
'count': len(sales_list),
|
||||
'total_sales': total_sales,
|
||||
'sales': sales_list
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"POS 실시간 조회 오류: {e}")
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
finally:
|
||||
if mssql_conn:
|
||||
mssql_conn.close()
|
||||
|
||||
|
||||
@app.route('/api/admin/pos-live/detail/<order_no>')
|
||||
def api_admin_pos_live_detail(order_no):
|
||||
"""
|
||||
판매 상세 조회 API (SALE_SUB 품목 목록)
|
||||
"""
|
||||
mssql_conn = None
|
||||
try:
|
||||
mssql_engine = db_manager.get_engine('PM_PRES')
|
||||
mssql_conn = mssql_engine.raw_connection()
|
||||
cursor = mssql_conn.cursor()
|
||||
|
||||
# 품목 상세 조회
|
||||
cursor.execute("""
|
||||
SELECT
|
||||
S.DrugCode AS drug_code,
|
||||
ISNULL(G.GoodsName, '(약품명 없음)') AS product_name,
|
||||
S.SL_NM_item AS quantity,
|
||||
S.SL_NM_cost_a AS unit_price,
|
||||
S.SL_TOTAL_PRICE AS total_price
|
||||
FROM SALE_SUB S
|
||||
LEFT JOIN PM_DRUG.dbo.CD_GOODS G ON S.DrugCode = G.DrugCode
|
||||
WHERE S.SL_NO_order = ?
|
||||
ORDER BY S.DrugCode
|
||||
""", order_no)
|
||||
|
||||
rows = cursor.fetchall()
|
||||
items = []
|
||||
for row in rows:
|
||||
items.append({
|
||||
'drug_code': row[0],
|
||||
'product_name': row[1],
|
||||
'quantity': int(row[2]) if row[2] else 0,
|
||||
'unit_price': float(row[3]) if row[3] else 0,
|
||||
'total_price': float(row[4]) if row[4] else 0
|
||||
})
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'order_no': order_no,
|
||||
'items': items
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"판매 상세 조회 오류: {e}")
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
finally:
|
||||
if mssql_conn:
|
||||
mssql_conn.close()
|
||||
|
||||
|
||||
@app.route('/api/admin/user-mileage/<phone>')
|
||||
def api_admin_user_mileage(phone):
|
||||
"""
|
||||
회원 마일리지 내역 API
|
||||
"""
|
||||
try:
|
||||
sqlite_conn = db_manager.get_sqlite_connection()
|
||||
cursor = sqlite_conn.cursor()
|
||||
|
||||
# 전화번호로 사용자 조회
|
||||
cursor.execute("""
|
||||
SELECT id, nickname, phone, mileage_balance, created_at
|
||||
FROM users WHERE phone = ?
|
||||
""", (phone,))
|
||||
user = cursor.fetchone()
|
||||
|
||||
if not user:
|
||||
return jsonify({'success': False, 'error': '등록되지 않은 회원입니다.'}), 404
|
||||
|
||||
# 적립 내역 조회
|
||||
cursor.execute("""
|
||||
SELECT points, balance_after, reason, description, created_at
|
||||
FROM mileage_ledger
|
||||
WHERE user_id = ?
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 50
|
||||
""", (user['id'],))
|
||||
transactions = cursor.fetchall()
|
||||
|
||||
history = []
|
||||
for tx in transactions:
|
||||
history.append({
|
||||
'points': tx['points'],
|
||||
'balance_after': tx['balance_after'],
|
||||
'reason': tx['reason'],
|
||||
'description': tx['description'],
|
||||
'created_at': tx['created_at']
|
||||
})
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'user': {
|
||||
'id': user['id'],
|
||||
'nickname': user['nickname'],
|
||||
'phone': user['phone'],
|
||||
'mileage_balance': user['mileage_balance'],
|
||||
'created_at': user['created_at']
|
||||
},
|
||||
'history': history
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"회원 마일리지 조회 오류: {e}")
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import os
|
||||
|
||||
|
||||
Reference in New Issue
Block a user