feat:优化云版消费机

This commit is contained in:
dzc committed 2026-05-22 16:46:35 +08:00
1 parent 38c24e2ce6
commit e00e69ccbb
29 files changed
+464 -66

No files matched your search

@@ -141,6 +141,9 @@ public interface CacheConstants {
String WALLET_RULE_PRICE_CONFIG_DETAIL = "wallet:detail:rule_price_config";
// 用户的食堂商户(从视图里查询)
String WALLET_VIEWS_CANTEEN_MCH = "wallet:detail:view_canteen_mch";
/* ************************************* end 钱包相关 end ************************************* */
/* ************************************* start 第三方对接相关 start ************************************* */
@@ -157,6 +160,8 @@ public interface CacheConstants {
String HARDER_ORDER_NON_PAY = "hard:order:non_pay";
String HARD_XFJ_WHITE_LIST_LOCK = "hard:xfj:whitelist:lock";
/* ************************************* end 订单相关 end ************************************* */
@@ -9,6 +9,7 @@ import com.bsd.pjcloud.hard.service.HardXfjService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.websocket.server.PathParam;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpEntity;
@@ -1,17 +1,10 @@
package com.bsd.pjcloud.hard.controller.xfj;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.log.annotation.SysLog;
import com.bsd.pjcloud.hard.api.dto.xfj.HardXfjLogDto;
import com.bsd.pjcloud.hard.api.entity.xfj.HardXfjLogEntity;
import com.bsd.pjcloud.hard.service.HardXfjLogService;
import org.springframework.security.access.prepost.PreAuthorize;
import com.bsd.pjcloud.common.excel.annotation.ResponseExcel;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.http.HttpHeaders;
@@ -20,9 +13,6 @@ import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Objects;
/**
* 消费机日志
*/
@@ -51,7 +51,7 @@ public class HardApiServiceImpl implements HardApiService {
result.setWalletBalance(wallet.getBalance());
result.setWalletIsFreeze(wallet.getIsFreeze());
// 查询用户食堂信息
MchManageVo mchDetail = remoteMchService.getFirstMchByDeptId(user.getSysUser().getDeptId(), MerchantTypeEnum.CANTEEN).getData();
MchManageVo mchDetail = remoteMchService.getViewsCanteenMchByDeptId(user.getSysUser().getDeptId()).getData();
if (ObjectUtil.isNotEmpty(mchDetail)) {
result.setCanteenId(mchDetail.getId());
}
@@ -84,7 +84,7 @@ public class HardApiServiceImpl implements HardApiService {
result.setWalletBalance(wallet.getBalance());
result.setWalletIsFreeze(wallet.getIsFreeze());
// 查询用户食堂信息
MchManageVo mchDetail = remoteMchService.getFirstMchByDeptId(user.getSysUser().getDeptId(), MerchantTypeEnum.CANTEEN).getData();
MchManageVo mchDetail = remoteMchService.getViewsCanteenMchByDeptId(user.getSysUser().getDeptId()).getData();
if (ObjectUtil.isNotEmpty(mchDetail)) {
result.setCanteenId(mchDetail.getId());
}
@@ -1380,7 +1380,7 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
List<MchRuleJoinDtoVo> list = mchRuleJoinService.innerMchRoleList(mch.getId()).getData();
if (ObjectUtil.isEmpty(list)) return extraPrice;
// 查询用户食堂
MchManageVo userMch = remoteMchService.getFirstMchByDeptId(sysUser.getDeptId(), MerchantTypeEnum.CANTEEN).getData();
MchManageVo userMch = remoteMchService.getViewsCanteenMchByDeptId(sysUser.getDeptId()).getData();
for (MchRuleJoinDtoVo v : list) {
Long basePrice = v.getBasePrice();
Long multiple = v.getMultiple();
@@ -8,6 +8,7 @@ import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsd.pjcloud.admin.api.dto.UserInfo;
import com.bsd.pjcloud.admin.api.feign.RemoteUserService;
import com.bsd.pjcloud.common.core.constant.CacheConstants;
import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum;
import com.bsd.pjcloud.hard.api.constant.HardTypeEnum;
import com.bsd.pjcloud.hard.api.constant.xfj.HardXfjTypeEnum;
@@ -24,6 +25,7 @@ import com.bsd.pjcloud.hard.api.vo.xfj.*;
import com.bsd.pjcloud.hard.mapper.order.HardOrderMapper;
import com.bsd.pjcloud.hard.service.*;
import com.bsd.pjcloud.wallet.api.constant.WalletTypeEnum;
import com.bsd.pjcloud.wallet.api.dto.WalletRemoteOpenCardListDto;
import com.bsd.pjcloud.wallet.api.entity.WalletActiveEntity;
import com.bsd.pjcloud.wallet.api.entity.WalletCodeUseEntity;
import com.bsd.pjcloud.wallet.api.entity.WalletManageEntity;
@@ -32,6 +34,7 @@ import com.bsd.pjcloud.wallet.api.feign.RemoteWalletService;
import com.bsd.pjcloud.wallet.api.vo.WalletManageVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@@ -63,6 +66,8 @@ public class HardXfjServiceImpl implements HardXfjService {
private final RemoteUserService remoteUserService;
private final RemoteWalletService walletService;
private final StringRedisTemplate redisTemplate;
/**
* 检查设备并返回配置
*/
@@ -154,7 +159,7 @@ public class HardXfjServiceImpl implements HardXfjService {
result.setMsg(e.getMessage());
return result;
} finally {
saveLogger(logger);
// saveLogger(logger);
}
}
@@ -689,8 +694,30 @@ public class HardXfjServiceImpl implements HardXfjService {
public XfjWhiteListVo whiteList(String body, Map<String, String> headers) {
HardXfjLogEntity logger = initLogger(body, headers, "获取卡号白名单接口");
XfjWhiteListVo result = new XfjWhiteListVo();
Boolean hasLock = false;
Map<String, String> transitionHeader = new LinkedHashMap<>();
for (Map.Entry<String, String> entry : headers.entrySet()) {
transitionHeader.put(entry.getKey().toUpperCase(), entry.getValue());
}
String uniqueCode = transitionHeader.get("DEVICE-ID");
if (ObjectUtil.isEmpty(uniqueCode)) {
return null;
}
String lockKey = CacheConstants.HARD_XFJ_WHITE_LIST_LOCK + ":" + uniqueCode;
// 检查是否存在锁
hasLock = redisTemplate.hasKey(lockKey);
if (ObjectUtil.isNotEmpty(hasLock) && hasLock) {
log.warn("|获取卡号白名单接口|设备uniqueCode:{}在30分钟内已查询过,拒绝重复查询", uniqueCode);
return null;
}
try {
HardManagerEntity entity = checkSignAndReturnConfig(body, headers);
if (ObjectUtil.isEmpty(entity)) {
return null;
}
logger.setUniqueCode(entity.getUniqueCode());
// 获取参数
XfjWhiteListDto dto = JSONUtil.toBean(body, XfjWhiteListDto.class);
@@ -700,10 +727,25 @@ public class HardXfjServiceImpl implements HardXfjService {
if (!ObjectUtil.isAllNotEmpty(dto.getPage(), dto.getPageNumber(), dto.getCommID())) {
throw new RuntimeException("解析参数错误");
}
// 查询开卡数据
Page<WalletActiveEntity> walletActivePage = walletService.remoteOpenCardList(dto.getPage(), dto.getPageNumber()).getData();
// 查询开卡数据(只查询本部门及以下的)
WalletRemoteOpenCardListDto openCardListDto = new WalletRemoteOpenCardListDto();
openCardListDto.setCurrent(dto.getPage());
openCardListDto.setPageSize(dto.getPageNumber());
openCardListDto.setMchId(entity.getMerchantId());
openCardListDto.setCarNumberLength(10);
Page<WalletActiveEntity> walletActivePage = walletService.remoteOpenCardList(openCardListDto).getData();
if (ObjectUtil.isEmpty(walletActivePage) || ObjectUtil.isEmpty(walletActivePage.getRecords())) {
throw new RuntimeException("查询开卡数据为空");
// 查询完成,设置30分钟的锁
redisTemplate.opsForValue().set(lockKey, "1", Duration.ofMinutes(30));
log.info("|获取卡号白名单接口|设备 {} 查询完成,设置30分钟锁", entity.getUniqueCode());
result.setCommID(dto.getCommID());
result.setPage(dto.getPage());
result.setPageLen(0L);
result.setUptate("0");
result.setWLData("");
return result;
}
List<WalletActiveEntity> walletActiveRecords = walletActivePage.getRecords();
List<String> whiteCarList = new ArrayList<>();
@@ -711,6 +753,9 @@ public class HardXfjServiceImpl implements HardXfjService {
boolean isSelectEnd = false;
if (walletActiveRecords.size() < dto.getPageNumber()) {
isSelectEnd = true;
// 查询完成,设置30分钟的锁
redisTemplate.opsForValue().set(lockKey, "1", Duration.ofMinutes(30));
log.info("|获取卡号白名单接口|设备 {} 查询完成,设置30分钟锁", entity.getUniqueCode());
}
for (WalletActiveEntity item : walletActiveRecords) {
String whiteCarNumber = generateWhiteCarNumber(String.valueOf(item.getCardSort()), item.getCardNumber(), ObjectUtil.equals(item.getDelFlag(), YesNoEnum.YES.getCode()) ? "0" : "1");
@@ -718,7 +763,7 @@ public class HardXfjServiceImpl implements HardXfjService {
}
result.setCommID(dto.getCommID());
result.setPage(dto.getPage());
result.setPageLen(dto.getPageNumber());
result.setPageLen((long) walletActiveRecords.size());
result.setUptate(isSelectEnd ? "0" : "1");
result.setWLData(whiteCarList.stream().collect(Collectors.joining(",")));
return result;
@@ -730,7 +775,9 @@ public class HardXfjServiceImpl implements HardXfjService {
result.setMsg(e.getMessage());
return result;
} finally {
saveLogger(logger);
if (ObjectUtil.isNotEmpty(hasLock) && !hasLock) {
saveLogger(logger);
}
}
}
@@ -15,6 +15,7 @@ import com.wechat.pay.java.service.partnerpayments.app.AppService;
import com.wechat.pay.java.service.partnerpayments.app.AppServiceExtension;
import com.wechat.pay.java.service.partnerpayments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.partnerpayments.nativepay.NativePayService;
import com.wechat.pay.java.service.profitsharing.ProfitsharingService;
import com.wechat.pay.java.service.refund.RefundService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -83,4 +84,17 @@ public class WechatConfiguration {
return new RefundService.Builder().config(config).build();
}
// 分账服务
@Bean
public ProfitsharingService profitsharingService() {
AppPlusPayConfig.WechatConfig wechatConfig = properties.getWechatConfig();
Config config = new RSAAutoCertificateConfig.Builder()
.merchantId(wechatConfig.getMerchantId())
.privateKeyFromPath(wechatConfig.getMchPrivatePath())
.merchantSerialNumber(wechatConfig.getMerchantSerialNumber())
.apiV3Key(wechatConfig.getApiV3Key())
.build();
return new ProfitsharingService.Builder().config(config).build();
}
}
@@ -0,0 +1,13 @@
package com.bsd.pjcloud.thirdparty.service;
import com.bsd.pjcloud.thirdparty.entity.pay.ThirdPayOrderEntity;
public interface ThirdAppPlusWechatFzService {
/**
* 发起分账
*/
void create(ThirdPayOrderEntity orderEntity);
}
@@ -240,7 +240,7 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
if (ObjectUtil.isEmpty(userInfo)) {
throw new RuntimeException("用户不存在");
}
MchManageVo mchManage = remoteMchService.getFirstMchByDeptId(userInfo.getSysUser().getDeptId(), MerchantTypeEnum.CANTEEN).getData();
MchManageVo mchManage = remoteMchService.getViewsCanteenMchByDeptId(userInfo.getSysUser().getDeptId()).getData();
if (ObjectUtil.isEmpty(mchManage)) {
throw new RuntimeException("用户不属于任何食堂");
}
@@ -25,6 +25,7 @@ import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.partnerpayments.app.AppServiceExtension;
import com.wechat.pay.java.service.partnerpayments.app.model.*;
import com.wechat.pay.java.service.partnerpayments.app.model.Amount;
import com.wechat.pay.java.service.profitsharing.ProfitsharingService;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.*;
import lombok.RequiredArgsConstructor;
@@ -61,7 +62,7 @@ public class ThirdAppPlusWechatServiceImpl implements ThirdAppPlusWechatService
private final AppServiceExtension appServiceExtension;
private final RefundService refundService;
private final NotificationParser notificationParser;
private final ProfitsharingService profitsharingService;
/**
* APP支付
@@ -0,0 +1,37 @@
package com.bsd.pjcloud.thirdparty.service.impl.appplus.fz;
import com.bsd.pjcloud.thirdparty.entity.pay.ThirdPayOrderEntity;
import com.bsd.pjcloud.thirdparty.service.ThirdAppPlusWechatFzService;
import com.wechat.pay.java.service.profitsharing.ProfitsharingService;
import com.wechat.pay.java.service.profitsharing.model.CreateOrderRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
/**
* 微信分账
*/
@Service
@Validated
@Slf4j
@RequiredArgsConstructor
public class ThirdAppPlusWechatFzServiceImpl implements ThirdAppPlusWechatFzService {
private final ProfitsharingService profitsharingService;
/**
* 发起分账
*/
@Override
public void create(ThirdPayOrderEntity orderEntity) {
String outOrderNo = "fz" + orderEntity.getPayNo();
// 请求参数
CreateOrderRequest createDto = new CreateOrderRequest();
createDto.setOutOrderNo(outOrderNo);
profitsharingService.createOrder(createDto);
}
}
@@ -52,7 +52,7 @@ public interface SysDeptService extends IService<SysDept> {
*/
List<Tree<Long>> selectTree(String deptName, Long parentId, PjcloudUser user);
List<Tree<Long>> selectTreeV2(String deptName, Long parentId, PjcloudUser user);
List<Tree<Long>> selectTreeV2(String deptName, Long parentId, PjcloudUser user);
List<Tree<Long>> selectSimpleTree(String deptName, Long parentId);
@@ -38,6 +38,7 @@ import com.bsd.pjcloud.admin.api.vo.DeptExcelVO;
import com.bsd.pjcloud.admin.api.vo.OrgTreeVO;
import com.bsd.pjcloud.admin.mapper.*;
import com.bsd.pjcloud.admin.service.SysDeptService;
import com.bsd.pjcloud.common.core.constant.CacheConstants;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.data.datascope.DataScope;
import com.bsd.pjcloud.common.excel.vo.ErrorMessage;
@@ -46,6 +47,7 @@ import com.bsd.pjcloud.common.security.util.SecurityUtils;
import com.bsd.pjcloud.wallet.api.feign.RemoteWalletService;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;
@@ -112,6 +114,12 @@ public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> impl
* 修改部门
*/
@Override
@CacheEvict(
value = CacheConstants.WALLET_VIEWS_CANTEEN_MCH,
key = "#dto.getDeptId()",
condition = "#dto.getDeptId() != null",
beforeInvocation = true
)
public Boolean edit(SysDept sysDept) {
boolean isEdit = updateById(sysDept);
remoteWalletService.deptChange(sysDept.getDeptId(), Boolean.FALSE);
@@ -218,8 +226,8 @@ public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> impl
break;
}
}
List<Tree<Long>> currentDeptAllNodes = getSubTreeNodes(currentDeptTree);
return currentDeptAllNodes;
// List<Tree<Long>> currentDeptAllNodes = getSubTreeNodes(currentDeptTree);
return List.of(currentDeptTree);
}
public List<Tree<Long>> getSubTreeNodes(Tree<Long> node) {
@@ -34,4 +34,9 @@ public class WalletActiveDto extends WalletActiveEntity {
* 是否硬件激活
*/
private Boolean isMchActive;
/**
* 卡号长度
*/
private Integer carNumberLength;
}
@@ -0,0 +1,43 @@
package com.bsd.pjcloud.wallet.api.dto;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.bsd.pjcloud.common.excel.annotation.ExcelLine;
import lombok.Data;
@Data
public class WalletImportActiveDto {
/**
* 导入时候回显行号
*/
@ExcelLine
@ExcelIgnore
private Long lineNum;
@ColumnWidth(100)
@ExcelProperty("用户姓名")
private String username;
@ColumnWidth(100)
@ExcelProperty("用户手机号")
private String userMobile;
@ColumnWidth(100)
@ExcelProperty("卡号")
private String cardNumber;
// 开卡的id
private Long id;
// 钱包id
private Long walletId;
// 用户id
private Long userId;
// 用户部门id
private Long userDeptId;
}
@@ -0,0 +1,33 @@
package com.bsd.pjcloud.wallet.api.dto;
import lombok.Data;
@Data
public class WalletRemoteOpenCardListDto {
/**
* 当前页
*/
private Long current;
/**
* 分页
*/
private Long pageSize;
/**
* 父部门id
*/
private Long parentDeptId;
/**
* 商户id
*/
private Long mchId;
/**
* 卡号长度
*/
private Integer carNumberLength;
}
@@ -52,4 +52,8 @@ public interface RemoteMchService {
@NoToken
@GetMapping("/mch-manage/get-first-mch-by-dept-id")
R<MchManageVo> getFirstMchByDeptId(@RequestParam Long deptId, @RequestParam MerchantTypeEnum mchType);
@NoToken
@GetMapping("/mch-manage/get-views-canteen-mch-by-dept-id")
R<MchManageVo> getViewsCanteenMchByDeptId(@RequestParam Long deptId);
}
@@ -5,12 +5,14 @@ import com.bsd.pjcloud.common.core.constant.ServiceNameConstants;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.feign.annotation.NoToken;
import com.bsd.pjcloud.wallet.api.constant.WalletTypeEnum;
import com.bsd.pjcloud.wallet.api.dto.WalletRemoteOpenCardListDto;
import com.bsd.pjcloud.wallet.api.entity.WalletActiveEntity;
import com.bsd.pjcloud.wallet.api.entity.WalletManageEntity;
import com.bsd.pjcloud.wallet.api.vo.WalletActiveVo;
import com.bsd.pjcloud.wallet.api.vo.WalletManageVo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
@@ -68,6 +70,6 @@ public interface RemoteWalletService {
R<String> innserIsUseDoor(@RequestParam Long userId);
@NoToken
@GetMapping("/wallet-active/remote/open-card-list")
R<Page<WalletActiveEntity>> remoteOpenCardList(@RequestParam Long current, @RequestParam Long pageSize);
@PostMapping("/wallet-active/remote/open-card-list")
R<Page<WalletActiveEntity>> remoteOpenCardList(@RequestBody WalletRemoteOpenCardListDto body);
}
@@ -2,16 +2,20 @@ package com.bsd.pjcloud.wallet.controller;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.core.validation.Group;
import com.bsd.pjcloud.common.excel.annotation.RequestExcel;
import com.bsd.pjcloud.common.idempotent.annotation.Idempotent;
import com.bsd.pjcloud.common.log.annotation.SysLog;
import com.bsd.pjcloud.common.security.annotation.Inner;
import com.bsd.pjcloud.common.security.service.PjcloudUser;
import com.bsd.pjcloud.common.security.util.SecurityUtils;
import com.bsd.pjcloud.wallet.api.dto.WalletImportActiveDto;
import com.bsd.pjcloud.wallet.api.dto.WalletRemoteOpenCardListDto;
import com.bsd.pjcloud.wallet.api.dto.WalletActiveBindCardDto;
import com.bsd.pjcloud.wallet.api.dto.WalletActiveDto;
import com.bsd.pjcloud.wallet.api.entity.WalletActiveEntity;
@@ -26,6 +30,7 @@ import org.springframework.http.HttpHeaders;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -51,13 +56,18 @@ public class WalletActiveController {
/* ************************************* start 远程调用 start ************************************* */
@Inner()
@GetMapping("/remote/open-card-list")
@PostMapping("/remote/open-card-list")
@Operation(summary = "远程调用开卡并且绑定用户的列表")
public R<Page<WalletActiveEntity>> remoteOpenCardList(@RequestParam Long current, @RequestParam Long pageSize) {
public R<Page<WalletActiveEntity>> remoteOpenCardList(@RequestBody WalletRemoteOpenCardListDto body) {
if (ObjectUtil.isEmpty(body.getCurrent()) || ObjectUtil.isEmpty(body.getPageSize())) {
return null;
}
Page page = new Page();
page.setCurrent(current);
page.setSize(pageSize);
page.setCurrent(body.getCurrent());
page.setSize(body.getPageSize());
WalletActiveDto dto = new WalletActiveDto();
dto.setMerchantId(body.getMchId());
dto.setCarNumberLength(body.getCarNumberLength());
return R.ok(walletActiveService.openCardList(page, dto));
}
@@ -185,4 +195,14 @@ public class WalletActiveController {
public List<WalletActiveEntity> export(WalletActiveEntity walletActive, Long[] ids) {
return walletActiveService.list(Wrappers.lambdaQuery(walletActive).in(ArrayUtil.isNotEmpty(ids), WalletActiveEntity::getId, ids));
}
/**
* 导入开卡信息,会直接覆盖
*/
@PostMapping("/import")
@PreAuthorize("@pms.hasPermission('wallet_walletActive_import')")
public R importWalletActive(@RequestExcel List<WalletImportActiveDto> excelVOList, BindingResult bindingResult) {
return walletActiveService.importWalletActive(excelVOList, bindingResult);
}
}
@@ -126,6 +126,14 @@ public class MchManageController {
if (ObjectUtil.isEmpty(mchManage)) return R.failed("商户不存在");
return R.ok(mchManage);
}
@Inner
@GetMapping("/get-views-canteen-mch-by-dept-id")
public R<MchManageVo> getViewsCanteenMchByDeptId(@RequestParam Long deptId) {
MchManageVo mchManage = mchManageService.getViewsCanteenMchByDeptId(deptId);
if (ObjectUtil.isEmpty(mchManage)) return R.failed("商户不存在");
return R.ok(mchManage);
}
/* ************************************* end 远程调用 end ************************************* */
/* ************************************* start app start ************************************* */
@@ -161,7 +161,6 @@ public class WalletRechargeApplyController {
}
@PostMapping("/read-excel")
@Idempotent(expireTime = 3, info = "正在上传中,请勿重复操作")
public R readExcel(@RequestExcel List<WalletRechargeExcelDto> excelVOList, BindingResult bindingResult, @RequestParam(required = false) String bizType) {
return walletRechargeApplyService.readExcel(excelVOList, bindingResult, bizType);
}
@@ -14,4 +14,6 @@ public interface MchDeptViewMapper {
List<WalletMchDeptViewVo> selectList(@Param("dto") WalletMchDeptViewDto dto);
WalletMchDeptViewVo selectByDeptId(@Param("deptId") Long deptId);
}
@@ -41,6 +41,11 @@ public interface MchManageService extends IService<MchManageEntity> {
MchManageVo getFirstMchByDeptId(Long deptId, List<MerchantTypeEnum> mchTypeList);
/**
* 从视图里获取食堂商户信息
*/
MchManageVo getViewsCanteenMchByDeptId(Long deptId);
/**
* 刷新商户二维码
*/
@@ -2,12 +2,18 @@ package com.bsd.pjcloud.wallet.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.wallet.api.dto.WalletActiveBindCardDto;
import com.bsd.pjcloud.wallet.api.dto.WalletActiveDto;
import com.bsd.pjcloud.wallet.api.dto.WalletImportActiveDto;
import com.bsd.pjcloud.wallet.api.dto.recharge.excel.WalletRechargeExcelDto;
import com.bsd.pjcloud.wallet.api.entity.WalletActiveEntity;
import com.bsd.pjcloud.wallet.api.entity.WalletManageEntity;
import com.bsd.pjcloud.wallet.api.vo.WalletActiveVo;
import jakarta.validation.constraints.NotEmpty;
import org.springframework.validation.BindingResult;
import java.util.List;
public interface WalletActiveService extends IService<WalletActiveEntity> {
/**
@@ -77,4 +83,9 @@ public interface WalletActiveService extends IService<WalletActiveEntity> {
* 更新
*/
Long edit(WalletActiveEntity walletActive);
/**
* 导入开卡信息,会直接覆盖
*/
R importWalletActive(List<WalletImportActiveDto> excelVOList, BindingResult bindingResult);
}
@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bsd.pjcloud.admin.api.dto.UserInfo;
import com.bsd.pjcloud.admin.api.entity.SysDept;
import com.bsd.pjcloud.admin.api.entity.SysUser;
import com.bsd.pjcloud.admin.api.feign.RemoteDeptService;
@@ -16,17 +17,14 @@ import com.bsd.pjcloud.common.core.constant.enums.MerchantTypeEnum;
import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum;
import com.bsd.pjcloud.common.core.util.CollectionUtils;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.excel.vo.ErrorMessage;
import com.bsd.pjcloud.wallet.api.constant.WalleCardStatusEnum;
import com.bsd.pjcloud.wallet.api.constant.WalletTypeEnum;
import com.bsd.pjcloud.wallet.api.dto.MchManageDto;
import com.bsd.pjcloud.wallet.api.dto.WalletActiveBindCardDto;
import com.bsd.pjcloud.wallet.api.dto.WalletActiveDto;
import com.bsd.pjcloud.wallet.api.dto.WalletTypeDto;
import com.bsd.pjcloud.wallet.api.dto.*;
import com.bsd.pjcloud.wallet.api.entity.mch.MchManageEntity;
import com.bsd.pjcloud.wallet.api.entity.WalletActiveEntity;
import com.bsd.pjcloud.wallet.api.entity.WalletManageEntity;
import com.bsd.pjcloud.wallet.api.entity.WalletTypeEntity;
import com.bsd.pjcloud.wallet.api.entity.mch.MchRulePriceConfigEntity;
import com.bsd.pjcloud.wallet.api.utils.WalletDataUtil;
import com.bsd.pjcloud.wallet.api.vo.MchManageVo;
import com.bsd.pjcloud.wallet.api.vo.WalletActiveVo;
@@ -38,20 +36,17 @@ import com.bsd.pjcloud.wallet.service.WalletManageService;
import com.bsd.pjcloud.wallet.service.WalletTypeService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
* 钱包开卡
*
* @author dzc
* @date 2024-12-31 18:53:31
*/
@Validated
@Slf4j
@@ -336,6 +331,117 @@ public class WalletActiveServiceImpl extends ServiceImpl<WalletActiveMapper, Wal
return walletActive.getId();
}
/**
* 导入开卡信息,会直接覆盖
*/
@Override
@Transactional
public R importWalletActive(List<WalletImportActiveDto> excelVOList, BindingResult bindingResult) {
ImmutablePair<List<ErrorMessage>, List<WalletImportActiveDto>> pair = validateExcelData(excelVOList, bindingResult, false);
List<ErrorMessage> errorMessages = pair.getLeft();
List<WalletImportActiveDto> list = pair.getRight();
if (ObjectUtil.isNotEmpty(errorMessages)) return R.failed(errorMessages);
// 更改卡号
List<WalletActiveEntity> updateActiveList = new ArrayList<>();
List<WalletManageEntity> updateWalletManageList = new ArrayList<>();
for (WalletImportActiveDto v : list) {
if (ObjectUtil.isNotEmpty(v.getId())) {
WalletActiveEntity entity = new WalletActiveEntity();
entity.setId(v.getId());
entity.setCardNumber(v.getCardNumber());
updateActiveList.add(entity);
}
if (ObjectUtil.isNotEmpty(v.getWalletId())) {
WalletManageEntity entity = new WalletManageEntity();
entity.setId(v.getWalletId());
entity.setCardNumber(v.getCardNumber());
updateWalletManageList.add(entity);
}
}
// 更改钱包绑定的饭卡卡号
baseMapper.updateById(updateActiveList);
// 更改钱包管理绑定的饭卡卡号
walletManageService.updateBatchById(updateWalletManageList);
return R.ok(null, "导入成功");
}
public ImmutablePair<List<ErrorMessage>, List<WalletImportActiveDto>> validateExcelData(List<WalletImportActiveDto> list, BindingResult bindingResult, boolean validatePrice) {
if (ObjectUtil.isEmpty(list)) {
throw new RuntimeException("读取excel数据错误");
}
list = list.stream().filter(v -> !ObjectUtil.isAllEmpty(v.getUsername(), v.getUserMobile(), v.getCardNumber())).toList();
if (ObjectUtil.isEmpty(list)) {
throw new RuntimeException("读取excel数据错误");
}
List<ErrorMessage> errorMessageList = (List<ErrorMessage>) bindingResult.getTarget();
List<String> usernameList = list.stream().map(WalletImportActiveDto::getUsername).toList();
List<String> userPoneList = list.stream().map(WalletImportActiveDto::getUserMobile).toList();
for (WalletImportActiveDto v : list) {
Set<String> errors = new LinkedHashSet<>();
if (ObjectUtil.isEmpty(v.getUsername())) {
errors.add("请输入用户姓名");
}
if (ObjectUtil.isEmpty(v.getUserMobile())) {
errors.add("请输入用户手机号");
}
if (ObjectUtil.isEmpty(v.getCardNumber())) {
errors.add("请输入卡号");
} else {
if (!List.of(10, 12).contains(v.getCardNumber().length())) {
errors.add("卡号长度错误,卡号长度必须为10、12");
}
}
if (ObjectUtil.isNotEmpty(v.getUsername()) && ObjectUtil.isNotEmpty(v.getUserMobile())) {
R<UserInfo> user = userService.getUserByNameAndMobile(v.getUsername(), v.getUserMobile());
Optional<SysUser> sysUser = Optional.of(user).map(R::getData).map(UserInfo::getSysUser);
if (sysUser.isEmpty()) {
errors.add("用户不存在");
} else {
if (!ObjectUtil.equals(sysUser.get().getName(), v.getUsername())) {
errors.add("用户不存在");
} else {
v.setUserId(sysUser.get().getUserId());
v.setUserDeptId(sysUser.get().getDeptId());
}
}
}
long userPhone = userPoneList.stream().filter(i -> ObjectUtil.equals(i, v.getUserMobile())).count();
if (userPhone > 1) {
errors.add("用手机号 <" + v.getUserMobile() + "> 重复");
}
if (ObjectUtil.isNotEmpty(errors)) {
errorMessageList.add(new ErrorMessage(v.getLineNum(), errors));
}
}
// 查询用户有没有绑定过饭卡
List<Long> userIdList = list.stream().map(WalletImportActiveDto::getUserId).distinct().filter(ObjectUtil::isNotEmpty).toList();
if (ObjectUtil.isNotEmpty(userIdList)) {
List<WalletActiveEntity> walletActiveList = baseMapper.selectList(new LambdaQueryWrapper<WalletActiveEntity>().in(WalletActiveEntity::getUserId, userIdList));
for (WalletImportActiveDto v : list) {
WalletActiveEntity targetWalletActive = walletActiveList.stream().filter(i -> ObjectUtil.equals(i.getUserId(), v.getUserId())).findFirst().orElse(null);
if (ObjectUtil.isEmpty(targetWalletActive)) {
Set<String> errors = new LinkedHashSet<>();
// 找到错误信息
ErrorMessage errorMessage = errorMessageList.stream().filter(i -> ObjectUtil.equals(i.getLineNum(), v.getLineNum())).findFirst().orElse(null);
if (ObjectUtil.isNotEmpty(errorMessage)) {
errors = errorMessage.getErrors();
}
errors.add("用户 <" + v.getUsername() + "> 没有绑定饭卡");
if (ObjectUtil.isEmpty(errorMessage)) {
errorMessageList.add(new ErrorMessage(v.getLineNum(), errors));
}
} else {
v.setId(targetWalletActive.getId());
v.setWalletId(targetWalletActive.getWalletId());
}
}
}
if (ObjectUtil.isNotEmpty(errorMessageList)) {
return ImmutablePair.of(errorMessageList, null);
}
return ImmutablePair.of(null, list);
}
private boolean existWalletCarNumber(String cardNumber, Long id) {
Long count = baseMapper.selectCount(new LambdaQueryWrapper<WalletActiveEntity>()
.eq(ObjectUtil.isNotEmpty(cardNumber), WalletActiveEntity::getCardNumber, cardNumber)
@@ -39,13 +39,17 @@ import com.bsd.pjcloud.wallet.api.utils.WalletDataUtil;
import com.bsd.pjcloud.wallet.api.vo.MchManageVo;
import com.bsd.pjcloud.wallet.api.vo.code.MchCollectionCodeVo;
import com.bsd.pjcloud.wallet.api.vo.mch.MchPaySettingVo;
import com.bsd.pjcloud.wallet.api.vo.mch.WalletMchDeptViewVo;
import com.bsd.pjcloud.wallet.mapper.MchManageMapper;
import com.bsd.pjcloud.wallet.mapper.WalletTypeMapper;
import com.bsd.pjcloud.wallet.mapper.mch.view.MchDeptViewMapper;
import com.bsd.pjcloud.wallet.service.MchManageService;
import com.bsd.pjcloud.wallet.service.MchPaySettingService;
import com.bsd.pjcloud.wallet.service.WalletThirdZyService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mock.web.MockMultipartFile;
@@ -65,9 +69,6 @@ import java.util.concurrent.CompletableFuture;
/**
* 商户管理
*
* @author dzc
* @date 2025-01-02 11:09:26
*/
@Validated
@Slf4j
@@ -88,6 +89,7 @@ public class MchManageServiceImpl extends ServiceImpl<MchManageMapper, MchManage
@Lazy
private final WalletThirdZyService walletThirdZyService;
private final WalletTypeMapper walletTypeMapper;
private final MchDeptViewMapper mchDeptViewMapper;
private final StringRedisTemplate redisTemplate;
@@ -127,6 +129,12 @@ public class MchManageServiceImpl extends ServiceImpl<MchManageMapper, MchManage
@Override
// @CacheEvict(value = CacheConstants.WALLET_MCH, key = "#dto.getId()", condition = "#dto.getId() != null")
@CacheEvict(
value = CacheConstants.WALLET_VIEWS_CANTEEN_MCH,
key = "#dto.getDeptId()",
condition = "#dto.getDeptId() != null",
beforeInvocation = true
)
public void edit(MchManageEntity dto) {
if (existName(dto.getName(), dto.getTypes(), dto.getId())) {
throw new RuntimeException("商户名不能重复");
@@ -310,13 +318,11 @@ public class MchManageServiceImpl extends ServiceImpl<MchManageMapper, MchManage
@Override
public MchManageVo getFirstMchByDeptId(Long deptId, List<MerchantTypeEnum> mchTypeList) {
List<SysDept> parentDeptIdList = remoteDeptService.getParentDeptList(deptId).getData();
log.error("getFirstMchByDeptId.parentDeptIdList:{}", JSONUtil.toJsonStr(parentDeptIdList));
if (ObjectUtil.isEmpty(parentDeptIdList)) {
return null;
}
List<Long> deptIds = parentDeptIdList.stream().map(SysDept::getDeptId).toList();
MchManageVo targetMchVo = getFirstMch(deptIds, mchTypeList);
log.error("getFirstMchByDeptId.targetMchVo:{}", JSONUtil.toJsonStr(targetMchVo));
if (ObjectUtil.isNotEmpty(targetMchVo)) {
MchPaySettingDto paySettingDto = new MchPaySettingDto();
paySettingDto.setMchId(targetMchVo.getId());
@@ -329,6 +335,24 @@ public class MchManageServiceImpl extends ServiceImpl<MchManageMapper, MchManage
return targetMchVo;
}
/**
* 从视图里获取食堂商户信息
*/
@Override
@Cacheable(
value = CacheConstants.WALLET_VIEWS_CANTEEN_MCH + "#3600",
key = "#deptId",
condition = "#deptId != null",
unless = "#result == null"
)
public MchManageVo getViewsCanteenMchByDeptId(Long deptId) {
WalletMchDeptViewVo walletMchDeptView = mchDeptViewMapper.selectByDeptId(deptId);
if (ObjectUtil.isEmpty(walletMchDeptView) || ObjectUtil.isEmpty(walletMchDeptView.getDeptId())) {
return null;
}
return baseMapper.join(walletMchDeptView.getMchId());
}
/**
* 刷新商户二维码
*/
@@ -3,21 +3,22 @@
<mapper namespace="com.bsd.pjcloud.wallet.mapper.WalletActiveMapper">
<sql id="selectA">
select a.id,
a.user_id,
a.wallet_id,
a.wallet_type_id,
a.dept_id,
a.merchant_id,
a.card_number,
a.card_sort,
a.is_active_hardware,
a.create_by,
a.create_time,
a.update_by,
a.update_time,
a.del_flag,
a.tenant_id
select
a.id,
a.user_id,
a.wallet_id,
a.wallet_type_id,
a.dept_id,
a.merchant_id,
a.card_number,
a.card_sort,
a.is_active_hardware,
a.create_by,
a.create_time,
a.update_by,
a.update_time,
a.del_flag,
a.tenant_id
</sql>
<sql id="whereA">
@@ -33,7 +34,8 @@
<include refid="selectA"/>
from wallet_active a
<where>
a.user_id is not null
a.del_flag = '0'
and a.user_id is not null
and a.wallet_id is not null
<if test="dto.cardNumber != null and dto.cardNumber != '' ">
and a.act_id = #{dto.cardNumber}
@@ -41,8 +43,16 @@
<if test="dto.isActiveHardware != null and dto.isActiveHardware != '' ">
and a.is_active_hardware = #{dto.isActiveHardware}
</if>
<if test="dto.deptId != null">
and a.dept_id = #{dto.deptId}
</if>
<if test="dto.merchantId != null">
and a.merchant_id = #{dto.merchantId}
</if>
<if test="dto.carNumberLength != null">
and length(a.card_number) = #{dto.carNumberLength}
</if>
</where>
order by a.card_sort asc, a.id asc
</select>
</mapper>
@@ -52,4 +52,14 @@
order by a.mchDeptId, a.level
</select>
</mapper>
<select id="selectByDeptId" resultType="com.bsd.pjcloud.wallet.api.vo.mch.WalletMchDeptViewVo">
<include refid="selectA"/>
from v_mch_dept_tree a
<where>
and a.deptId = #{deptId}
</where>
order by a.level asc
limit 1
</select>
</mapper>