fix(代理分销注册): 校验手机号/用户名/店铺编号唯一性并支持驳回后重注册
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m57s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m57s
- 提交写事务内先取事务级 advisory lock,再校验既有未删除账号/店铺与其它待审批申请: 手机号 1014、用户名 1013、店铺编号 1031、待审批占用 1007,冲突不落库且不消费短信验证码 - 已驳回(含通过后撤销)与已通过的终态记录不阻塞重新注册,形成新记录与新审批实例 - 并发同关键字段提交串行裁决,同一关键字段至多一条待审批记录 - 审批通过建店建号前复检关键字段,冲突返回可定位错误并整体回滚,不再以裸数据库错误收场 - 归档 Change fix-agent-distribution-registration-duplicate-guard 并同步主 Spec 验证:junhong_cmp_test + Redis DB 6 受控脚手架 37 项通过 / 0 项失败(含 6 路并发仅 1 条落库、 审批冲突回滚与无冲突建店回归),清理后 fixture 残留 0;gofmt/go build/go vet 全绿; openspec validate --all 35 项通过、doctor healthy、context-health 通过
This commit is contained in:
@@ -89,7 +89,10 @@ func (h *DistributionApprovalHandler) Handle(ctx context.Context, event approval
|
||||
}
|
||||
|
||||
// applyApproved 在同一事务内建立店铺、账号、钱包、层级与业务员快照。
|
||||
// 上级店铺必须仍然存在且启用;手机号或用户名已被并发注册占用时整体回滚,不留半套实体。
|
||||
// 上级店铺必须仍然存在且启用;手机号、用户名或店铺编号已被既有账号/店铺占用时整体回滚,不留半套实体。
|
||||
// 审批路径不取提交侧的关键字段 advisory lock:提交侧的校验与插入同处一个串行化区间,
|
||||
// 且账号/店铺写入与注册记录状态推进同事务提交,因此提交侧只会看到「已提交的账号/店铺」或「仍待审批的冲突记录」,
|
||||
// 两种情况都会拒绝。
|
||||
func (h *DistributionApprovalHandler) applyApproved(
|
||||
ctx context.Context,
|
||||
tx *gorm.DB,
|
||||
@@ -104,6 +107,11 @@ func (h *DistributionApprovalHandler) applyApproved(
|
||||
if level > constants.ShopMaxLevel {
|
||||
return errors.New(errors.CodeShopLevelExceeded, "店铺层级不能超过 7 级")
|
||||
}
|
||||
// 提交时的关键字段门禁可能已被此后的并发事实占用(平台手工建店、历史待审批记录):
|
||||
// 此处复检把裸唯一索引错误换成可定位错误码,仍整体回滚,注册记录保持待审批。
|
||||
if err := ensureRegistrationKeysAvailable(ctx, tx, registration.Phone, registration.Username, registration.ShopCode); err != nil {
|
||||
return err
|
||||
}
|
||||
role, err := loadEnabledCustomerRole(ctx, tx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user