table_game/backend/app/utils/calculate_price.py
2025-03-20 04:41:04 +08:00

130 lines
5.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from datetime import datetime, timedelta
from decimal import Decimal
import configparser
from fastapi import HTTPException
from backend.app.db import get_connection
def get_pricing_strategy(strategy_id, cursor):
"""获取指定 ID 的价格策略"""
cursor.execute("""
SELECT segment1_threshold, segment1_price,
segment2_threshold, segment2_price,
segment3_price, segment3_threshold
FROM pricing_strategies
WHERE strategy_id = %s
""", (strategy_id,))
return cursor.fetchone()
def get_table_pricing_strategy(strategy_id, cursor):
"""获取指定 ID 的桌费策略"""
cursor.execute("""
SELECT segment1_threshold, segment1_price,
segment2_threshold, segment2_price,
segment3_price, segment3_threshold
FROM table_pricing_strategies
WHERE strategy_id = %s
""", (strategy_id,))
return cursor.fetchone()
def calculate_segmented_price(duration, strategy):
"""
计算按照分段收费策略的价格:
- duration: 总时长(分钟)
- strategy: 包含分段时间和价格的策略字典
"""
price = Decimal(0)
s1, p1, s2, p2, p3, s3 = strategy.values()
if duration <= s1:
price = duration * p1
elif duration <= s2:
price = (s1 * p1) + ((duration - s1) * p2)
else:
# 超过 s2 但小于 s3如果 s3 设定)
if s3 is not None and duration > s3:
duration = s3 # 限制最大计费时间
price = (s1 * p1) + ((s2 - s1) * p2) + ((duration - s2) * p3)
return price
def calculate_overtime_fee(start_datetime, end_datetime):
"""计算超时费用(深夜时段收费,按整小时计费)"""
# 读取配置文件
config = configparser.ConfigParser()
config.read('backend/config.conf')
stay_up_late = config['stay_up_late']
start_time = datetime.strptime(stay_up_late['start_time'], '%H:%M:%S').time()
end_time = datetime.strptime(stay_up_late['end_time'], '%H:%M:%S').time()
price_per_hour = Decimal(stay_up_late['price_minutes']) # 每小时收费
overtime_fee = Decimal(0)
current_time = start_datetime.replace(minute=0, second=0, microsecond=0) # 取整到整点
while current_time + timedelta(hours=1) <= end_datetime:
next_hour = current_time + timedelta(hours=1)
if start_time <= current_time.time() or current_time.time() < end_time:
overtime_fee += price_per_hour # 满一小时才计费
current_time = next_hour # 跳到下一个整点
return overtime_fee
def calculate_order_price(order_id):
"""计算订单价格并写入数据库"""
connection = get_connection()
try:
with connection.cursor(dictionary=True) as cursor:
# 获取订单信息
cursor.execute("""
SELECT o.start_datetime, o.end_datetime, o.num_players,
o.pricing_strategy_id, t.table_pricing_strategy_id,
o.game_table_id
FROM orders o
JOIN game_tables t ON o.game_table_id = t.table_id
WHERE o.order_id = %s
FOR UPDATE
""", (order_id,))
order = cursor.fetchone()
if not order or not order['end_datetime']:
raise HTTPException(status_code=404, detail="订单不存在或未完成")
# 计算游戏时长(分钟)
start_time = order['start_datetime'].replace(tzinfo=None)
end_time = order['end_datetime'].replace(tzinfo=None)
duration = (end_time - start_time).total_seconds() / 60
duration_dec = Decimal(str(duration))
# 获取价格策略
pricing_strategy = get_pricing_strategy(order['pricing_strategy_id'], cursor)
table_strategy = get_table_pricing_strategy(order['table_pricing_strategy_id'], cursor)
if not pricing_strategy or not table_strategy:
raise HTTPException(status_code=400, detail="价格策略未找到")
# 计算价格
# unit_price = calculate_segmented_price(duration_dec, pricing_strategy)
# 原本的基础价格废用,桌子价格为主要逻辑
table_price = calculate_segmented_price(duration_dec, table_strategy)
# 计算总价格
# base_price = (unit_price * order['num_players']) + table_price
base_price = table_price * order['num_players']
overtime_fee = calculate_overtime_fee(start_time, end_time)
total_price = base_price + overtime_fee
# print("总价: ", unit_price * order['num_players'], " 桌费: ", table_price, " 时长: ", duration_dec, " 超时费: ", overtime_fee)
# 更新订单价格
cursor.execute("""
UPDATE orders
SET payable_price = %s,
game_process_time = %s
WHERE order_id = %s
""", (total_price, duration_dec, order_id))
connection.commit()
return True
except Exception as e:
connection.rollback()
print(f"Error calculating order price: {e}")
return False
finally:
connection.close()