table_game/backend/app/services/admin_order_service.py

220 lines
7.8 KiB
Python

from fastapi import HTTPException
from decimal import Decimal
from ..db import get_connection
from ..utils.jwt_handler import verify_token
import configparser
from datetime import datetime
import pytz
from ..utils import calculate_price
# 读取配置文件
config = configparser.ConfigParser()
config.read('backend/config.conf')
points_rate = Decimal(config.get('price', 'points_rate'))
get_points_rate = Decimal(config.get('price', 'get_points_rate'))
def verify_admin_permission(token: str):
"""公共权限验证方法"""
try:
payload = verify_token(token)
username = payload["sub"]
except ValueError as e:
raise HTTPException(status_code=401, detail=str(e))
connection = get_connection()
try:
cursor = connection.cursor(dictionary=True)
cursor.execute("SELECT user_type FROM users WHERE username = %s;", (username,))
admin_user = cursor.fetchone()
if not admin_user or admin_user["user_type"] != "admin":
raise HTTPException(status_code=403, detail="Permission denied")
return username
finally:
cursor.close()
connection.close()
def query_orders_by_status_and_range(token: str, start: int, end: int, order_status: str):
verify_admin_permission(token)
connection = get_connection()
try:
cursor = connection.cursor(dictionary=True)
cursor.execute("""
SELECT
o.order_id,
o.user_id,
u.username AS user_name, -- 添加用户名
g.game_table_number AS game_table_number, -- 添加游戏桌编号
o.order_date,
o.num_players,
o.order_status,
o.payable_price,
o.paid_price,
o.payment_method,
o.start_datetime,
o.end_datetime,
o.used_points, -- 使用的积分
o.coupon_id, -- 使用的优惠券
o.game_process_time, -- 总游戏时间
o.settlement_time
FROM orders o
LEFT JOIN users u ON o.user_id = u.user_id
LEFT JOIN game_tables g ON o.game_table_id = g.table_id
WHERE order_status = %s
ORDER BY o.order_id ASC
LIMIT %s OFFSET %s
""", (order_status, end - start + 1, start - 1))
result = cursor.fetchall()
cursor.execute("SELECT COUNT(*) FROM orders WHERE order_status = %s", (order_status,))
total = cursor.fetchone()["COUNT(*)"]
return {"orders": result, "total": total}
except Exception as e:
raise HTTPException(status_code=500, detail=f"Error during query: {str(e)}")
finally:
cursor.close()
connection.close()
def complete_order(token: str, order_id: int, end_datetime: datetime):
"""结束订单并计算最终价格"""
verify_admin_permission(token)
connection = get_connection()
try:
with connection.cursor(dictionary=True) as cursor:
# 查询订单基础信息(确保订单存在并锁定)
cursor.execute("""
SELECT start_datetime
FROM orders
WHERE order_id = %s
FOR UPDATE
""", (order_id,))
order = cursor.fetchone()
if not order:
raise HTTPException(status_code=404, detail="订单不存在")
# 处理时间
db_start = order['start_datetime'].replace(tzinfo=None)
input_end = end_datetime.replace(tzinfo=None)
# 计算游戏时长(分钟)
duration_minutes = (input_end - db_start).total_seconds() / 60
duration_minutes_dec = Decimal(str(duration_minutes))
# 更新订单状态并设置结束时间
cursor.execute("""
UPDATE orders
SET end_datetime = %s,
game_process_time = %s,
order_status = 'pending'
WHERE order_id = %s
""", (end_datetime, duration_minutes_dec, order_id))
# 提交事务,确保订单已结束
connection.commit()
# 调用价格计算逻辑(会自动写入数据库)
success = calculate_price.calculate_order_price(order_id)
if not success:
raise HTTPException(status_code=500, detail="订单价格计算失败")
return {"message": "订单已结束待结算"}
except Exception as e:
connection.rollback()
raise HTTPException(status_code=500, detail=str(e))
finally:
connection.close()
def settle_order(token: str, order_id: int, used_points: int = 0, coupon_id: int = None):
"""结算最终订单"""
verify_admin_permission(token)
connection = get_connection()
try:
with connection.cursor(dictionary=True) as cursor:
cursor.execute("""
SELECT payable_price, user_id
FROM orders
WHERE order_id = %s
AND order_status = 'pending'
FOR UPDATE
""", (order_id,))
order = cursor.fetchone()
points_value = used_points * points_rate
final_price = max(order['payable_price'] - points_value, Decimal('0'))
settlement_time = datetime.now(pytz.timezone('Asia/Shanghai'))
# 更新订单状态
cursor.execute("""
UPDATE orders
SET paid_price = %s,
used_points = %s,
coupon_id = %s,
order_status = 'completed',
payment_method = 'offline',
settlement_time = %s
WHERE order_id = %s
""", (final_price, used_points, coupon_id, settlement_time.strftime("%Y-%m-%d %H:%M:%S"), order_id))
if used_points > 0:
earned_points = 0
else:
earned_points = int(final_price * get_points_rate)
# 更新用户积分
cursor.execute("""
UPDATE users
SET points = points - %s + %s
WHERE user_id = %s
""", (used_points, earned_points, order['user_id']))
# 插入积分变动记录
change_amount = earned_points - used_points
reason = f"订单结算,订单号:{order_id}"
cursor.execute("""
INSERT INTO points_history (user_id, change_amount, reason)
VALUES (%s, %s, %s)
""", (order['user_id'], change_amount, reason))
connection.commit()
return {"message": "订单结算成功", "final_price": final_price}
except Exception as e:
connection.rollback()
raise HTTPException(status_code=500, detail=str(e))
finally:
connection.close()
# 在适当位置新增服务层方法
def get_order_details_service(token: str, order_id: int):
"""服务层:获取订单详情"""
verify_admin_permission(token) # 复用已有的权限验证方法
connection = get_connection()
if not connection:
raise HTTPException(status_code=500, detail="Database connection failed!")
try:
with connection.cursor(dictionary=True) as cursor:
cursor.execute("""
SELECT o.*, t.price AS table_price, g.price AS game_price
FROM orders o
JOIN game_tables t ON o.game_table_id = t.table_id
LEFT JOIN games g ON o.game_id = g.game_id
WHERE o.order_id = %s
""", (order_id,))
result = cursor.fetchone()
if not result:
raise HTTPException(status_code=404, detail="Order not found")
return result
finally:
connection.close()