319 lines
11 KiB
Python
319 lines
11 KiB
Python
from fastapi import HTTPException
|
||
from datetime import datetime, timedelta
|
||
from decimal import Decimal
|
||
from ..db import get_connection
|
||
from ..utils.jwt_handler import verify_token
|
||
import configparser
|
||
from ..utils import calculate_price
|
||
|
||
config = configparser.ConfigParser()
|
||
config.read('backend/config.conf')
|
||
unit_price = Decimal(config.get('price', 'unit_price'))
|
||
points_rate = Decimal(config.get('price', 'points_rate'))
|
||
get_points_rate = Decimal(config.get('price', 'get_points_rate'))
|
||
strategy_id = int(config.get('now_price', 'strategy_id'))
|
||
|
||
def get_user_active_order(token: str):
|
||
try:
|
||
payload = verify_token(token)
|
||
phone_number = payload["sub"]
|
||
print(f"Verified phone_number: {phone_number}")
|
||
except ValueError as e:
|
||
raise HTTPException(401, str(e))
|
||
"""获取用户进行中订单"""
|
||
connection = get_connection()
|
||
try:
|
||
cursor = connection.cursor(dictionary=True)
|
||
cursor.execute("""
|
||
SELECT
|
||
o.order_id,
|
||
o.start_datetime,
|
||
gt.game_table_number,
|
||
o.num_players
|
||
FROM users u
|
||
INNER JOIN orders o ON u.user_id = o.user_id
|
||
INNER JOIN game_tables gt ON o.game_table_id = gt.table_id
|
||
WHERE
|
||
u.phone_number = %s
|
||
AND o.order_status = 'in_progress'
|
||
ORDER BY o.start_datetime DESC
|
||
LIMIT 1;
|
||
""", (phone_number,))
|
||
return cursor.fetchone() or {}
|
||
except Exception as e:
|
||
raise HTTPException(status_code=500, detail=str(e))
|
||
finally:
|
||
cursor.close()
|
||
connection.close()
|
||
|
||
def create_user_order(token: str, table_id: int, num_players: int):
|
||
"""创建用户订单"""
|
||
try:
|
||
payload = verify_token(token)
|
||
phone_number = payload["sub"]
|
||
except ValueError as e:
|
||
raise HTTPException(status_code=401, detail=str(e))
|
||
|
||
connection = get_connection()
|
||
try:
|
||
cursor = connection.cursor()
|
||
|
||
cursor = connection.cursor()
|
||
# 新增用户订单状态检查
|
||
cursor.execute("""
|
||
SELECT order_status
|
||
FROM orders
|
||
WHERE user_id = (SELECT user_id FROM users WHERE phone_number = %s)
|
||
AND order_status IN ('in_progress', 'pending')
|
||
LIMIT 1
|
||
""", (phone_number,))
|
||
existing_order = cursor.fetchone()
|
||
if existing_order:
|
||
status = existing_order[0]
|
||
if status == 'in_progress':
|
||
raise HTTPException(status_code=400, detail="存在进行中的订单")
|
||
raise HTTPException(status_code=400, detail="存在未付款的订单")
|
||
|
||
# 获取当前最大订单号
|
||
cursor.execute("SELECT MAX(order_id) FROM orders")
|
||
max_order_id = cursor.fetchone()[0]
|
||
|
||
# 生成订单号(从100开始)
|
||
order_id = 100 if max_order_id is None else int(max_order_id) + 1
|
||
print("order_id:", order_id)
|
||
# 验证用户存在
|
||
cursor.execute("SELECT user_id FROM users WHERE phone_number = %s", (phone_number,))
|
||
user = cursor.fetchone()
|
||
if not user:
|
||
raise HTTPException(status_code=404, detail="用户不存在")
|
||
|
||
# 检查桌子占用
|
||
# cursor.execute("""
|
||
# SELECT EXISTS(
|
||
# SELECT 1 FROM orders
|
||
# WHERE game_table_id = %s
|
||
# AND order_status = 'in_progress'
|
||
# )""", (table_id,))
|
||
# if cursor.fetchone()[0]:
|
||
# raise HTTPException(status_code=400, detail="桌子已被占用")
|
||
|
||
# 创建订单
|
||
order_date = datetime.now().date()
|
||
start_datetime = datetime.now()
|
||
|
||
cursor.execute("""
|
||
INSERT INTO orders (
|
||
order_id, user_id, game_table_id,
|
||
order_date, start_datetime, num_players,
|
||
order_status, pricing_strategy_id
|
||
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
||
""", (order_id, user[0], table_id, order_date, start_datetime, num_players, 'in_progress', strategy_id))
|
||
|
||
connection.commit()
|
||
return {"order_id": order_id, "message": "订单创建成功"}
|
||
except Exception as e:
|
||
connection.rollback()
|
||
raise HTTPException(status_code=500, detail=str(e))
|
||
finally:
|
||
cursor.close()
|
||
connection.close()
|
||
|
||
|
||
def complete_user_order(token: str, order_id: int):
|
||
"""完成用户订单(计算最终价格)"""
|
||
try:
|
||
# 验证用户身份
|
||
payload = verify_token(token)
|
||
phone_number = payload["sub"]
|
||
except ValueError as e:
|
||
raise HTTPException(status_code=401, detail=str(e))
|
||
|
||
connection = get_connection()
|
||
try:
|
||
with connection.cursor(dictionary=True) as cursor:
|
||
# 获取订单信息
|
||
cursor.execute("""
|
||
SELECT o.user_id, o.start_datetime
|
||
FROM orders o
|
||
WHERE o.order_id = %s
|
||
FOR UPDATE
|
||
""", (order_id,))
|
||
order = cursor.fetchone()
|
||
|
||
if not order:
|
||
raise HTTPException(status_code=404, detail="订单不存在")
|
||
|
||
# 验证用户权限
|
||
cursor.execute("SELECT user_id FROM users WHERE phone_number = %s", (phone_number,))
|
||
user = cursor.fetchone()
|
||
if not user or order['user_id'] != user['user_id']:
|
||
raise HTTPException(status_code=403, detail="无权操作此订单")
|
||
|
||
# 计算订单时长
|
||
end_datetime = datetime.now()
|
||
duration_minutes = (end_datetime - order['start_datetime']).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 get_earliest_pending_order(token: str):
|
||
"""获取用户最早的pending订单"""
|
||
try:
|
||
payload = verify_token(token)
|
||
phone_number = payload["sub"]
|
||
except ValueError as e:
|
||
raise HTTPException(401, detail=str(e))
|
||
|
||
connection = get_connection()
|
||
try:
|
||
with connection.cursor(dictionary=True) as cursor:
|
||
# 查询最早pending订单
|
||
cursor.execute("""
|
||
SELECT o.order_id
|
||
FROM users u
|
||
JOIN orders o ON u.user_id = o.user_id
|
||
WHERE u.phone_number = %s
|
||
AND o.order_status = 'pending'
|
||
ORDER BY o.start_datetime ASC
|
||
LIMIT 1
|
||
""", (phone_number,))
|
||
result = cursor.fetchone()
|
||
return {"order_id": result["order_id"]} if result else {}
|
||
except Exception as e:
|
||
raise HTTPException(500, detail=str(e))
|
||
finally:
|
||
connection.close()
|
||
|
||
def get_order_detail_with_points(token: str, order_id: int):
|
||
"""获取订单详情及用户积分"""
|
||
try:
|
||
payload = verify_token(token)
|
||
phone_number = payload["sub"]
|
||
except ValueError as e:
|
||
raise HTTPException(401, detail=str(e))
|
||
|
||
connection = get_connection()
|
||
try:
|
||
with connection.cursor(dictionary=True) as cursor:
|
||
# 验证订单归属
|
||
cursor.execute("""
|
||
SELECT
|
||
o.order_id,
|
||
gt.game_table_number,
|
||
o.order_date,
|
||
o.start_datetime AS start_time,
|
||
o.end_datetime AS end_time,
|
||
o.game_process_time,
|
||
o.num_players,
|
||
o.payable_price,
|
||
u.points
|
||
FROM orders o
|
||
JOIN game_tables gt ON o.game_table_id = gt.table_id
|
||
JOIN users u ON o.user_id = u.user_id
|
||
WHERE o.order_id = %s
|
||
AND u.phone_number = %s
|
||
""", (order_id, phone_number))
|
||
|
||
result = cursor.fetchone()
|
||
if not result:
|
||
raise HTTPException(404, detail="订单不存在或无权访问")
|
||
|
||
# 格式化日期字段
|
||
result['order_date'] = result['order_date'].isoformat()
|
||
result['start_time'] = result['start_time'].isoformat()
|
||
result['end_time'] = result['end_time'].isoformat() if result['end_time'] else None
|
||
|
||
return {
|
||
"order_id": result["order_id"],
|
||
"game_table_number": result["game_table_number"],
|
||
"order_date": result["order_date"],
|
||
"start_time": result["start_time"],
|
||
"end_time": result["end_time"],
|
||
"num_players": result["num_players"],
|
||
"payable_price": float(result["payable_price"]),
|
||
"game_process_time": result["game_process_time"],
|
||
"points": result["points"]
|
||
}
|
||
except Exception as e:
|
||
raise HTTPException(500, detail=str(e))
|
||
finally:
|
||
connection.close()
|
||
|
||
|
||
def preview_price_adjustment(token: str, order_id: int, used_points: int):
|
||
"""预览价格调整(不修改数据库)"""
|
||
try:
|
||
payload = verify_token(token)
|
||
phone_number = payload["sub"]
|
||
except ValueError as e:
|
||
raise HTTPException(401, detail=str(e))
|
||
|
||
connection = get_connection()
|
||
try:
|
||
with connection.cursor(dictionary=True) as cursor:
|
||
# 获取用户当前积分
|
||
cursor.execute("""
|
||
SELECT u.user_id, u.points
|
||
FROM users u
|
||
WHERE u.phone_number = %s
|
||
""", (phone_number,))
|
||
user = cursor.fetchone()
|
||
if not user:
|
||
raise HTTPException(404, "用户不存在")
|
||
|
||
if user['points'] < used_points:
|
||
raise HTTPException(400, "积分不足")
|
||
|
||
# 获取原始价格
|
||
cursor.execute("""
|
||
SELECT payable_price
|
||
FROM orders
|
||
WHERE order_id = %s
|
||
AND user_id = %s
|
||
AND order_status = 'pending'
|
||
""", (order_id, user['user_id']))
|
||
order = cursor.fetchone()
|
||
if not order:
|
||
raise HTTPException(404, "订单不存在或不可修改")
|
||
|
||
# 计算新价格(仅预览)
|
||
points_value = used_points * points_rate
|
||
new_price = max(order['payable_price'] - points_value, Decimal('0'))
|
||
|
||
return {
|
||
"new_price": float(new_price),
|
||
}
|
||
|
||
except HTTPException as e:
|
||
raise
|
||
except Exception as e:
|
||
raise HTTPException(500, f"计算失败: {str(e)}")
|
||
finally:
|
||
connection.close()
|