Files
Django/shop/services/shop_binding.py
XingQue ed627fa6f7 fix: 修复点单商品在多店铺间跳动
扫码绑店参数只消费一次,避免 Tab 返回反复换绑;一人多条脏绑定取最新并在换绑时清理,hqsp 稳定取当前店。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-21 02:53:34 +08:00

96 lines
3.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 django.db import transaction
from django.db.models import F
from shop.models import Dianpu, YonghuDianpuBangding
import logging
logger = logging.getLogger(__name__)
def get_latest_binding_qs(yonghu):
"""同一用户可能历史残留多条绑定,一律取最近更新的一条。"""
return (
YonghuDianpuBangding.objects
.filter(yonghu=yonghu)
.select_related('dianpu')
.order_by('-UpdateTime', '-id')
)
def get_user_shop_binding(yonghu):
"""读取当前生效绑定(最新一条)。"""
return get_latest_binding_qs(yonghu).first()
def _delete_extra_bindings(yonghu, keep_id=None):
"""
删除同一用户多余绑定行,并扣减对应店铺绑定数。
keep_id: 保留的绑定主键None 表示全部删除。
"""
qs = YonghuDianpuBangding.objects.select_for_update().filter(yonghu=yonghu)
if keep_id is not None:
qs = qs.exclude(pk=keep_id)
extras = list(qs.select_related('dianpu'))
for row in extras:
try:
dianpu = row.dianpu
dianpu.bangding_yonghushu = F('bangding_yonghushu') - 1
dianpu.save(update_fields=['bangding_yonghushu'])
except Exception:
logger.warning('扣减多余绑定店铺人数失败 binding=%s', row.pk, exc_info=True)
row.delete()
return len(extras)
@transaction.atomic
def set_user_shop_binding(yonghu, dianpu):
"""
将用户唯一绑定到 dianpu清理多余行。
返回 (changed: bool, msg: str)
"""
yonghu_locked = type(yonghu).objects.select_for_update().get(pk=yonghu.pk)
dianpu_locked = Dianpu.objects.select_for_update().get(pk=dianpu.pk)
if dianpu_locked.zhuangtai != 1:
return False, '店铺已被封禁,无法绑定'
rows = list(
YonghuDianpuBangding.objects.select_for_update()
.filter(yonghu=yonghu_locked)
.select_related('dianpu')
.order_by('-UpdateTime', '-id')
)
if rows:
primary = rows[0]
if primary.dianpu_id == dianpu_locked.id:
# 已是目标店:清掉多余行即可
_delete_extra_bindings(yonghu_locked, keep_id=primary.pk)
return False, '已绑定该店铺'
old = primary.dianpu
old.bangding_yonghushu = F('bangding_yonghushu') - 1
old.save(update_fields=['bangding_yonghushu'])
primary.dianpu = dianpu_locked
primary.save(update_fields=['dianpu', 'UpdateTime'])
_delete_extra_bindings(yonghu_locked, keep_id=primary.pk)
else:
primary = YonghuDianpuBangding.query.create(yonghu=yonghu_locked, dianpu=dianpu_locked)
dianpu_locked.bangding_yonghushu = F('bangding_yonghushu') + 1
dianpu_locked.save(update_fields=['bangding_yonghushu'])
return True, '绑定成功'
@transaction.atomic
def clear_user_shop_binding(yonghu):
"""解除用户全部店铺绑定。返回被解除的主店铺 id 或 None。"""
yonghu_locked = type(yonghu).objects.select_for_update().get(pk=yonghu.pk)
primary = get_latest_binding_qs(yonghu_locked).first()
old_id = primary.dianpu_id if primary else None
_delete_extra_bindings(yonghu_locked, keep_id=None)
return old_id