将文件夹命名从拼音改为英文,整理了一些代码,将导入语句迁移到了头部

This commit is contained in:
2026-06-14 16:39:09 +08:00
parent 1fd0301e0e
commit 21bb129c5d
178 changed files with 29249 additions and 35862 deletions

113
products/utils.py Normal file
View File

@@ -0,0 +1,113 @@
# tongji/utils.py 或 shangpin/utils.py
import logging
from datetime import date
from decimal import Decimal
from django.db import transaction
from django.db.models import F
from .models import ShangpinMeiriTongji
from products.models import Shangpin
logger = logging.getLogger(__name__)
def update_shangpin_daily_stat(
shangpin_id,
caozuo_leixing,
dingdan_jiage=Decimal('0.00'),
pingtai_shouyi=Decimal('0.00'),
dianpu_zongshouyi=Decimal('0.00')
):
"""
原子更新商品每日统计数据(高并发安全,无店铺关联)
参数:
shangpin_id: 商品ID (int)
caozuo_leixing: 操作类型
1 = 下单(点单)
2 = 结算(成交)
3 = 退款
dingdan_jiage: 订单金额商品价格默认0.00
pingtai_shouyi: 平台收益金额默认0.00
dianpu_zongshouyi: 店铺总收益金额默认0.00
注意:
- 金额若小于0则自动设为0
- 日期自动取当天
- 使用 select_for_update 配合事务,保证并发时数据绝对准确
- 若商品不存在,仅记录日志不中断主流程
"""
# 参数归一化与合法性处理
dingdan_jiage = Decimal(str(dingdan_jiage)) if dingdan_jiage else Decimal('0.00')
pingtai_shouyi = Decimal(str(pingtai_shouyi)) if pingtai_shouyi else Decimal('0.00')
dianpu_zongshouyi = Decimal(str(dianpu_zongshouyi)) if dianpu_zongshouyi else Decimal('0.00')
if dingdan_jiage < 0:
dingdan_jiage = Decimal('0.00')
if pingtai_shouyi < 0:
pingtai_shouyi = Decimal('0.00')
if dianpu_zongshouyi < 0:
dianpu_zongshouyi = Decimal('0.00')
today = date.today()
# 校验商品是否存在(不加锁,仅校验)
if not Shangpin.objects.filter(id=shangpin_id).exists():
logger.error(f"商品ID {shangpin_id} 不存在,统计更新失败")
return
# 开启事务,使用行锁确保并发安全
with transaction.atomic():
# 获取或创建统计记录,并锁定该行
tongji, created = ShangpinMeiriTongji.objects.select_for_update().get_or_create(
shangpin_id=shangpin_id,
riqi=today,
defaults={
'nian': today.year,
'yue': today.month,
'ri': today.day,
'diandan_zongliang': 0,
'diandan_zonge': Decimal('0.00'),
'chengjiao_zongliang': 0,
'chengjiao_zonge': Decimal('0.00'),
'tuikuan_zongliang': 0,
'tuikuan_zonge': Decimal('0.00'),
'pingtai_shouyi': Decimal('0.00'),
'dianpu_zongshouyi': Decimal('0.00'),
}
)
# 根据操作类型构建更新字段(使用 F 表达式累加)
update_fields = {}
if caozuo_leixing == 1: # 下单
update_fields['diandan_zongliang'] = F('diandan_zongliang') + 1
update_fields['diandan_zonge'] = F('diandan_zonge') + dingdan_jiage
elif caozuo_leixing == 2: # 结算(成交)
update_fields['chengjiao_zongliang'] = F('chengjiao_zongliang') + 1
update_fields['chengjiao_zonge'] = F('chengjiao_zonge') + dingdan_jiage
# 收益直接累加传入值
update_fields['pingtai_shouyi'] = F('pingtai_shouyi') + pingtai_shouyi
update_fields['dianpu_zongshouyi'] = F('dianpu_zongshouyi') + dianpu_zongshouyi
elif caozuo_leixing == 3: # 退款
update_fields['tuikuan_zongliang'] = F('tuikuan_zongliang') + 1
update_fields['tuikuan_zonge'] = F('tuikuan_zonge') + dingdan_jiage
# 退款是否应扣减收益?根据业务需求决定,此处暂不处理收益字段
else:
logger.warning(f"未知的操作类型: {caozuo_leixing}")
return
# 原子更新字段
if update_fields:
for field, value in update_fields.items():
setattr(tongji, field, value)
tongji.save(update_fields=list(update_fields.keys()))
logger.info(
f"商品统计更新: 商品ID={shangpin_id}, 操作类型={caozuo_leixing}, "
f"订单金额={dingdan_jiage}, 平台收益={pingtai_shouyi}, "
f"店铺收益={dianpu_zongshouyi}, 日期={today}"
)