|
|
@@ -15,7 +15,9 @@ import com.ruoyi.system.domain.InfoBankCard;
|
|
|
import com.ruoyi.system.domain.InfoUser;
|
|
|
import com.ruoyi.system.mapper.InfoBankCardMapper;
|
|
|
import com.ruoyi.system.mapper.InfoUserMapper;
|
|
|
+import com.ruoyi.system.mapper.PosStoreMapper;
|
|
|
import com.ruoyi.system.service.MerchantStoreAccessService;
|
|
|
+import com.ruoyi.system.service.StallPaymentAccessService;
|
|
|
import com.ruoyi.system.utils.Auth;
|
|
|
import com.ruoyi.system.utils.JwtUtil;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
@@ -31,10 +33,11 @@ import org.springframework.web.bind.annotation.RestController;
|
|
|
|
|
|
import java.util.Date;
|
|
|
import java.util.List;
|
|
|
+import java.util.Objects;
|
|
|
|
|
|
/**
|
|
|
* 收款银行卡管理接口(031,商家/骑手通用;foodie-store 支付设置页与骑手 App 共用)。
|
|
|
- * 卡归属:骑手=本人;商家(含子账号)=主账号(连锁共享,与支付方式选择同语义)。
|
|
|
+ * 卡归属:骑手=本人;普通商家(含子账号)=主账号;夜市摊位=store_id。
|
|
|
* 同一归属同时最多一张启用卡;付款方仅能看到启用卡(bankInfo 已改读启用卡)。
|
|
|
*/
|
|
|
@RestController
|
|
|
@@ -42,29 +45,34 @@ import java.util.List;
|
|
|
@Anonymous
|
|
|
public class BankCardController extends BaseController {
|
|
|
|
|
|
- /** 单人卡数上限,防止无限囤卡。 */
|
|
|
+ /** 每个归属(主账号、骑手或摊位)的卡数上限,防止无限囤卡。 */
|
|
|
private static final int MAX_CARDS = 10;
|
|
|
|
|
|
private final InfoBankCardMapper bankCardMapper;
|
|
|
private final InfoUserMapper userMapper;
|
|
|
private final MerchantStoreAccessService merchantStoreAccessService;
|
|
|
+ private final StallPaymentAccessService stallPaymentAccessService;
|
|
|
+ private final PosStoreMapper storeMapper;
|
|
|
|
|
|
public BankCardController(InfoBankCardMapper bankCardMapper,
|
|
|
InfoUserMapper userMapper,
|
|
|
- MerchantStoreAccessService merchantStoreAccessService) {
|
|
|
+ MerchantStoreAccessService merchantStoreAccessService,
|
|
|
+ StallPaymentAccessService stallPaymentAccessService,
|
|
|
+ PosStoreMapper storeMapper) {
|
|
|
this.bankCardMapper = bankCardMapper;
|
|
|
this.userMapper = userMapper;
|
|
|
this.merchantStoreAccessService = merchantStoreAccessService;
|
|
|
+ this.stallPaymentAccessService = stallPaymentAccessService;
|
|
|
+ this.storeMapper = storeMapper;
|
|
|
}
|
|
|
|
|
|
- /** 本人(商家为主账号)卡列表,含启用标记。 */
|
|
|
+ /** 本归属(普通商家主账号、骑手本人或摊位)卡列表,含启用标记。 */
|
|
|
@Auth
|
|
|
@GetMapping
|
|
|
public AjaxResult list(@RequestHeader String token) {
|
|
|
- Long ownerId = resolveOwner(token);
|
|
|
+ CardOwner owner = resolveOwner(token);
|
|
|
List<InfoBankCard> cards = bankCardMapper.selectList(
|
|
|
- new LambdaQueryWrapper<InfoBankCard>()
|
|
|
- .eq(InfoBankCard::getUserId, ownerId)
|
|
|
+ ownerQuery(owner)
|
|
|
.orderByDesc(InfoBankCard::getIsActive)
|
|
|
.orderByDesc(InfoBankCard::getId));
|
|
|
return success(cards);
|
|
|
@@ -75,14 +83,16 @@ public class BankCardController extends BaseController {
|
|
|
@PostMapping
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
public AjaxResult add(@RequestHeader String token, @RequestBody BankCardSaveDto dto) {
|
|
|
- Long ownerId = resolveOwner(token);
|
|
|
- InfoBankCard card = validated(dto, ownerId);
|
|
|
+ CardOwner owner = resolveOwner(token);
|
|
|
+ InfoBankCard card = validated(dto);
|
|
|
+ lockStall(owner);
|
|
|
long count = bankCardMapper.selectCount(
|
|
|
- new LambdaQueryWrapper<InfoBankCard>().eq(InfoBankCard::getUserId, ownerId));
|
|
|
+ ownerQuery(owner));
|
|
|
if (count >= MAX_CARDS) {
|
|
|
throw new ServiceException(MessageUtils.message("pay.bankcard.limit"));
|
|
|
}
|
|
|
- card.setUserId(ownerId);
|
|
|
+ card.setUserId(owner.userId());
|
|
|
+ card.setStoreId(owner.storeId());
|
|
|
// 首张卡自动启用,避免迁移遗漏或新收款方忘记启用导致线下转账长期不就绪
|
|
|
card.setIsActive(count == 0 ? 1 : 0);
|
|
|
Date now = new Date();
|
|
|
@@ -96,12 +106,12 @@ public class BankCardController extends BaseController {
|
|
|
@Auth
|
|
|
@PutMapping
|
|
|
public AjaxResult update(@RequestHeader String token, @RequestBody BankCardSaveDto dto) {
|
|
|
- Long ownerId = resolveOwner(token);
|
|
|
+ CardOwner owner = resolveOwner(token);
|
|
|
if (dto == null || dto.getId() == null) {
|
|
|
throw new ServiceException(MessageUtils.message("pay.bankcard.invalid"));
|
|
|
}
|
|
|
- InfoBankCard existing = requireOwnCard(dto.getId(), ownerId);
|
|
|
- InfoBankCard validated = validated(dto, ownerId);
|
|
|
+ InfoBankCard existing = requireOwnCard(dto.getId(), owner);
|
|
|
+ InfoBankCard validated = validated(dto);
|
|
|
existing.setBankName(validated.getBankName());
|
|
|
existing.setAccountNo(validated.getAccountNo());
|
|
|
existing.setAccountName(validated.getAccountName());
|
|
|
@@ -110,12 +120,12 @@ public class BankCardController extends BaseController {
|
|
|
return success();
|
|
|
}
|
|
|
|
|
|
- /** 删除本人卡;删的是启用卡则该归属回到"无启用卡"(线下转账不就绪)。 */
|
|
|
+ /** 删除本归属卡;删的是启用卡则该归属回到"无启用卡"(线下转账不就绪)。 */
|
|
|
@Auth
|
|
|
@DeleteMapping("/{id}")
|
|
|
public AjaxResult delete(@RequestHeader String token, @PathVariable Long id) {
|
|
|
- Long ownerId = resolveOwner(token);
|
|
|
- requireOwnCard(id, ownerId);
|
|
|
+ CardOwner owner = resolveOwner(token);
|
|
|
+ requireOwnCard(id, owner);
|
|
|
bankCardMapper.deleteById(id);
|
|
|
return success();
|
|
|
}
|
|
|
@@ -128,14 +138,14 @@ public class BankCardController extends BaseController {
|
|
|
@PutMapping("/activate/{id}")
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
public AjaxResult activate(@RequestHeader String token, @PathVariable Long id) {
|
|
|
- Long ownerId = resolveOwner(token);
|
|
|
- requireOwnCard(id, ownerId);
|
|
|
+ CardOwner owner = resolveOwner(token);
|
|
|
+ lockStall(owner);
|
|
|
+ requireOwnCard(id, owner);
|
|
|
Date now = new Date();
|
|
|
- bankCardMapper.update(null, new LambdaUpdateWrapper<InfoBankCard>()
|
|
|
- .eq(InfoBankCard::getUserId, ownerId)
|
|
|
+ bankCardMapper.update(null, ownerUpdate(owner)
|
|
|
.set(InfoBankCard::getIsActive, 0)
|
|
|
.set(InfoBankCard::getUpdateTime, now));
|
|
|
- bankCardMapper.update(null, new LambdaUpdateWrapper<InfoBankCard>()
|
|
|
+ bankCardMapper.update(null, ownerUpdate(owner)
|
|
|
.eq(InfoBankCard::getId, id)
|
|
|
.set(InfoBankCard::getIsActive, 1)
|
|
|
.set(InfoBankCard::getUpdateTime, now));
|
|
|
@@ -143,7 +153,7 @@ public class BankCardController extends BaseController {
|
|
|
}
|
|
|
|
|
|
/** 字段校验:必填、长度、银行名必须属于字典 taiwan_bank_list(与商家审核资料同源)。 */
|
|
|
- private InfoBankCard validated(BankCardSaveDto dto, Long ownerId) {
|
|
|
+ private InfoBankCard validated(BankCardSaveDto dto) {
|
|
|
if (dto == null || StringUtils.isBlank(dto.getBankName())
|
|
|
|| StringUtils.isBlank(dto.getAccountNo()) || StringUtils.isBlank(dto.getAccountName())
|
|
|
|| dto.getBankName().trim().length() > 64
|
|
|
@@ -171,28 +181,53 @@ public class BankCardController extends BaseController {
|
|
|
return card;
|
|
|
}
|
|
|
|
|
|
- /** 只能操作归属自己的卡,统一按无权限处理避免枚举他人卡 ID。 */
|
|
|
- private InfoBankCard requireOwnCard(Long id, Long ownerId) {
|
|
|
+ /** 只能操作同一用户或同一摊位的卡,两类归属都比较,避免枚举其他归属卡 ID。 */
|
|
|
+ private InfoBankCard requireOwnCard(Long id, CardOwner owner) {
|
|
|
InfoBankCard card = id == null ? null : bankCardMapper.selectById(id);
|
|
|
- if (card == null || !ownerId.equals(card.getUserId())) {
|
|
|
+ if (card == null || !Objects.equals(owner.userId(), card.getUserId())
|
|
|
+ || !Objects.equals(owner.storeId(), card.getStoreId())) {
|
|
|
throw new ServiceException(MessageUtils.message("no.user.stop"));
|
|
|
}
|
|
|
return card;
|
|
|
}
|
|
|
|
|
|
- /** token → 卡归属:骑手(2)=本人;商家系(1/3/4/5)=主账号;普通用户不可维护收款卡。 */
|
|
|
- private Long resolveOwner(String token) {
|
|
|
+ /** 用户卡和摊位卡互斥;全部读写都由服务端解析归属,不能靠请求参数指定。 */
|
|
|
+ private record CardOwner(Long userId, Long storeId) { }
|
|
|
+
|
|
|
+ private LambdaQueryWrapper<InfoBankCard> ownerQuery(CardOwner owner) {
|
|
|
+ LambdaQueryWrapper<InfoBankCard> query = new LambdaQueryWrapper<>();
|
|
|
+ return owner.storeId() != null ? query.eq(InfoBankCard::getStoreId, owner.storeId())
|
|
|
+ : query.eq(InfoBankCard::getUserId, owner.userId());
|
|
|
+ }
|
|
|
+
|
|
|
+ private LambdaUpdateWrapper<InfoBankCard> ownerUpdate(CardOwner owner) {
|
|
|
+ LambdaUpdateWrapper<InfoBankCard> update = new LambdaUpdateWrapper<>();
|
|
|
+ return owner.storeId() != null ? update.eq(InfoBankCard::getStoreId, owner.storeId())
|
|
|
+ : update.eq(InfoBankCard::getUserId, owner.userId());
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 多摊位主可能同时新增首卡或切换启用卡;锁摊位行直至事务结束,保证同一摊位串行处理。 */
|
|
|
+ private void lockStall(CardOwner owner) {
|
|
|
+ if (owner.storeId() != null && storeMapper.lockStallForPayment(owner.storeId()) == null) {
|
|
|
+ throw new ServiceException(MessageUtils.message("merchant.store.access.denied"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /** token → 卡归属:骑手本人、普通商家主账号或有效摊位;夜市主不可维护摊位卡。 */
|
|
|
+ private CardOwner resolveOwner(String token) {
|
|
|
Long userId = Long.valueOf(new JwtUtil().getusid(token));
|
|
|
InfoUser user = userMapper.selectById(userId);
|
|
|
if (user == null) {
|
|
|
throw new ServiceException(MessageUtils.message("no.user.stop"));
|
|
|
}
|
|
|
if ("2".equals(user.getUserType())) {
|
|
|
- return userId;
|
|
|
+ return new CardOwner(userId, null);
|
|
|
+ }
|
|
|
+ if ("4".equals(user.getUserType())) {
|
|
|
+ return new CardOwner(null, stallPaymentAccessService.resolveStoreId(userId));
|
|
|
}
|
|
|
- if ("1".equals(user.getUserType()) || "3".equals(user.getUserType())
|
|
|
- || "4".equals(user.getUserType()) || "5".equals(user.getUserType())) {
|
|
|
- return merchantStoreAccessService.resolve(userId).ownerUserId();
|
|
|
+ if ("1".equals(user.getUserType()) || "5".equals(user.getUserType())) {
|
|
|
+ return new CardOwner(merchantStoreAccessService.resolve(userId).ownerUserId(), null);
|
|
|
}
|
|
|
throw new ServiceException(MessageUtils.message("no.user.stop"));
|
|
|
}
|