将文件夹命名从拼音改为英文,整理了一些代码,将导入语句迁移到了头部
This commit is contained in:
113
products/utils.py
Normal file
113
products/utils.py
Normal 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}"
|
||||
)
|
||||
Reference in New Issue
Block a user