fix: 修复点单商品在多店铺间跳动

扫码绑店参数只消费一次,避免 Tab 返回反复换绑;一人多条脏绑定取最新并在换绑时清理,hqsp 稳定取当前店。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-07-21 02:53:34 +08:00
parent 435422e716
commit ed627fa6f7
4 changed files with 115 additions and 95 deletions

View File

@@ -0,0 +1 @@
# shop.services

View File

@@ -0,0 +1,95 @@
"""用户店铺绑定:一人只能绑定一家店(业务约定)。"""
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