扫码绑店参数只消费一次,避免 Tab 返回反复换绑;一人多条脏绑定取最新并在换绑时清理,hqsp 稳定取当前店。 Co-authored-by: Cursor <cursoragent@cursor.com>
96 lines
3.2 KiB
Python
96 lines
3.2 KiB
Python
"""用户店铺绑定:一人只能绑定一家店(业务约定)。"""
|
||
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
|