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