feat(订单): 添加汇邦云用户ID支持并重构余额处理逻辑
- 在订单相关表中添加ab98_user_id字段 - 新增MoneyUtil工具类处理金额转换 - 重构订单和退款逻辑使用user_balance表存储余额 - 添加根据汇邦云用户ID查询余额的接口
This commit is contained in:
parent
bf381fcd35
commit
ca62ab0ae9
|
|
@ -167,19 +167,23 @@ public class CaffeineController {
|
|||
result.put("data", caffeineCacheService.dynamicCodeCache.getAll());
|
||||
break;
|
||||
default:
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("error", "未知的缓存类型: " + cacheName);
|
||||
map.put("supportedTypes", new String[]{
|
||||
"captchaCache", "loginUserCache", "userCache",
|
||||
"roleCache", "postCache", "qyUseridCache", "dynamicCodeCache"
|
||||
});
|
||||
return ResponseEntity.badRequest()
|
||||
.body(Map.of("error", "未知的缓存类型: " + cacheName,
|
||||
"supportedTypes", new String[]{
|
||||
"captchaCache", "loginUserCache", "userCache",
|
||||
"roleCache", "postCache", "qyUseridCache", "dynamicCodeCache"
|
||||
}));
|
||||
.body(map);
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(result);
|
||||
} catch (Exception e) {
|
||||
log.error("获取缓存数据失败: {}", cacheName, e);
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("error", "获取缓存数据失败: " + e.getMessage());
|
||||
return ResponseEntity.internalServerError()
|
||||
.body(Map.of("error", "获取缓存数据失败: " + e.getMessage()));
|
||||
.body(map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,9 +10,12 @@ import com.agileboot.common.core.dto.ResponseDTO;
|
|||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.common.exception.error.ErrorCode.Client;
|
||||
import com.agileboot.common.utils.MoneyUtil;
|
||||
import com.agileboot.common.utils.OpenSignUtil;
|
||||
import com.agileboot.domain.ab98.user.Ab98UserApplicationService;
|
||||
import com.agileboot.domain.ab98.user.db.Ab98UserEntity;
|
||||
import com.agileboot.domain.ab98.user_balance.UserBalanceApplicationService;
|
||||
import com.agileboot.domain.ab98.user_balance.dto.UserBalanceDTO;
|
||||
import com.agileboot.domain.common.dto.QyLoginDTO;
|
||||
import com.agileboot.domain.qywx.accessToken.AccessTokenApplicationService;
|
||||
import com.agileboot.domain.qywx.accessToken.db.QyAccessTokenEntity;
|
||||
|
|
@ -72,6 +75,7 @@ public class PaymentController {
|
|||
private final PaymentApplicationService paymentApplicationService;
|
||||
private final PaymentOperationLogApplicationService paymentOperationLogApplicationService;
|
||||
private final Ab98UserApplicationService ab98UserApplicationService;
|
||||
private final UserBalanceApplicationService userBalanceApplicationService;
|
||||
private final WxshopConfig wxshopConfig;
|
||||
|
||||
// 新增回调接口
|
||||
|
|
@ -308,7 +312,7 @@ public class PaymentController {
|
|||
|
||||
Ab98UserEntity ab98User = ab98UserApplicationService.getByAb98UserId(qyUser.getAb98UserId());
|
||||
try {
|
||||
if (qyUser.getAb98UserId()!= null) {
|
||||
if (qyUser.getAb98UserId() != null) {
|
||||
ab98User.setOpenid(openid);
|
||||
ab98User.updateById();
|
||||
}
|
||||
|
|
@ -316,13 +320,15 @@ public class PaymentController {
|
|||
log.error("更新汇邦云绑定的微信openid失败", e);
|
||||
}
|
||||
|
||||
UserBalanceDTO userBalance = userBalanceApplicationService.getByCorpidAndAb98UserId(corpid, ab98User.getAb98UserId());
|
||||
|
||||
// 创建响应对象(假设GetBalanceResponse包含balance字段)
|
||||
GetBalanceResponse response = new GetBalanceResponse(
|
||||
qyUser.getUserid(),
|
||||
qyUser.getCorpid(),
|
||||
qyUser.getBalance(),
|
||||
qyUser.getUseBalance(),
|
||||
qyUser.getBalanceLimit(),
|
||||
userBalance != null ? MoneyUtil.fenToYuan(userBalance.getBalance()) : BigDecimal.ZERO,
|
||||
userBalance != null ? MoneyUtil.fenToYuan(userBalance.getUseBalance()) : BigDecimal.ZERO,
|
||||
userBalance != null ? MoneyUtil.fenToYuan(userBalance.getBalanceLimit()) : BigDecimal.ZERO,
|
||||
ab98User);
|
||||
return ResponseDTO.ok(response);
|
||||
}
|
||||
|
|
@ -342,13 +348,53 @@ public class PaymentController {
|
|||
ab98User = ab98UserApplicationService.getByAb98UserId(qyUser.getAb98UserId());
|
||||
}
|
||||
|
||||
if (ab98User == null) {
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Client.COMMON_REQUEST_PARAMETERS_INVALID, "未找到对应的汇邦云用户记录"));
|
||||
}
|
||||
|
||||
UserBalanceDTO userBalance = userBalanceApplicationService.getByCorpidAndAb98UserId(corpid, ab98User.getAb98UserId());
|
||||
|
||||
// 创建响应对象(假设GetBalanceResponse包含balance字段)
|
||||
GetBalanceResponse response = new GetBalanceResponse(
|
||||
qyUser.getUserid(),
|
||||
qyUser.getCorpid(),
|
||||
qyUser.getBalance(),
|
||||
qyUser.getUseBalance(),
|
||||
qyUser.getBalanceLimit(),
|
||||
userBalance != null ? MoneyUtil.fenToYuan(userBalance.getBalance()) : BigDecimal.ZERO,
|
||||
userBalance != null ? MoneyUtil.fenToYuan(userBalance.getUseBalance()) : BigDecimal.ZERO,
|
||||
userBalance != null ? MoneyUtil.fenToYuan(userBalance.getBalanceLimit()) : BigDecimal.ZERO,
|
||||
ab98User);
|
||||
return ResponseDTO.ok(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据企业微信ID和汇邦云用户ID查询用户余额
|
||||
* @param corpid 企业微信ID
|
||||
* @param ab98UserId 汇邦云用户ID
|
||||
* @return 包含用户余额信息的响应结果
|
||||
* @apiNote 该接口直接查询user_balance表,返回原始余额数据(单位:分)
|
||||
*/
|
||||
@GetMapping("/getUserBalance")
|
||||
public ResponseDTO<GetBalanceResponse> getUserBalance(@RequestParam String corpid, @RequestParam Long ab98UserId) {
|
||||
if (corpid == null || ab98UserId == null) {
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Client.COMMON_REQUEST_PARAMETERS_INVALID, "corpid和ab98UserId不能为空"));
|
||||
}
|
||||
|
||||
Ab98UserEntity ab98User = ab98UserApplicationService.getByAb98UserId(ab98UserId);
|
||||
if (ab98User == null) {
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Client.COMMON_REQUEST_PARAMETERS_INVALID, "未找到对应的汇邦云用户记录"));
|
||||
}
|
||||
|
||||
UserBalanceDTO userBalance = userBalanceApplicationService.getByCorpidAndAb98UserId(corpid, ab98UserId);
|
||||
|
||||
if (userBalance == null) {
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Client.COMMON_REQUEST_PARAMETERS_INVALID, "未找到对应的用户余额记录"));
|
||||
}
|
||||
|
||||
GetBalanceResponse response = new GetBalanceResponse(
|
||||
null,
|
||||
corpid,
|
||||
MoneyUtil.fenToYuan(userBalance.getBalance()),
|
||||
MoneyUtil.fenToYuan(userBalance.getUseBalance()),
|
||||
MoneyUtil.fenToYuan(userBalance.getBalanceLimit()),
|
||||
ab98User);
|
||||
return ResponseDTO.ok(response);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
package com.agileboot.common.utils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
/**
|
||||
* 金额工具类
|
||||
* 提供分(Long)和元(BigDecimal)之间的转换
|
||||
*
|
||||
* @author agileboot
|
||||
*/
|
||||
public class MoneyUtil {
|
||||
|
||||
/**
|
||||
* 分转换为元(BigDecimal,保留两位小数)
|
||||
*
|
||||
* @param fen 金额(单位:分)
|
||||
* @return 金额(单位:元),保留两位小数
|
||||
*/
|
||||
public static BigDecimal fenToYuan(Long fen) {
|
||||
if (fen == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return new BigDecimal(fen).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
/**
|
||||
* 元转换为分(Long)
|
||||
*
|
||||
* @param yuan 金额(单位:元)
|
||||
* @return 金额(单位:分)
|
||||
*/
|
||||
public static Long yuanToFen(BigDecimal yuan) {
|
||||
if (yuan == null) {
|
||||
return 0L;
|
||||
}
|
||||
return yuan.multiply(new BigDecimal(100)).setScale(0, RoundingMode.HALF_UP).longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 分转换为元格式的字符串(保留两位小数)
|
||||
*
|
||||
* @param fen 金额(单位:分)
|
||||
* @return 金额字符串(单位:元),格式如:"100.00"
|
||||
*/
|
||||
public static String fenToYuanString(Long fen) {
|
||||
if (fen == null) {
|
||||
return "0.00";
|
||||
}
|
||||
return fenToYuan(fen).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 元格式的字符串转换为分
|
||||
*
|
||||
* @param yuanStr 金额字符串(单位:元),格式如:"100.00"
|
||||
* @return 金额(单位:分)
|
||||
*/
|
||||
public static Long yuanStringToFen(String yuanStr) {
|
||||
if (yuanStr == null || yuanStr.trim().isEmpty()) {
|
||||
return 0L;
|
||||
}
|
||||
try {
|
||||
BigDecimal yuan = new BigDecimal(yuanStr.trim());
|
||||
return yuanToFen(yuan);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException("无效的金额格式: " + yuanStr, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,10 @@ package com.agileboot.domain.shop.approval;
|
|||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.agileboot.common.config.WxshopConfig;
|
||||
import com.agileboot.common.utils.MoneyUtil;
|
||||
import com.agileboot.domain.ab98.user_balance.db.UserBalanceEntity;
|
||||
import com.agileboot.domain.ab98.user_balance.db.UserBalanceService;
|
||||
import com.agileboot.domain.ab98.user_balance.dto.UserBalanceDTO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import com.agileboot.common.constant.UrlConstants;
|
||||
import com.agileboot.common.constant.WeixinConstants;
|
||||
|
|
@ -112,6 +116,7 @@ public class ReturnApprovalApplicationService {
|
|||
private final CabinetMainboardService cabinetMainboardService;
|
||||
private final CabinetCellOperationModelFactory cabinetCellOperationModelFactory;
|
||||
private final MqttService mqttService;
|
||||
private final UserBalanceService userBalanceService;
|
||||
@Autowired
|
||||
private WxshopConfig wxshopConfig;
|
||||
|
||||
|
|
@ -259,15 +264,31 @@ public class ReturnApprovalApplicationService {
|
|||
} else if (Objects.equals(orderModel.getPaymentMethod(), "balance")) {
|
||||
// 余额退款
|
||||
try {
|
||||
QyAuthCorpInfoEntity authCorpInfo = authCorpInfoApplicationService.selectByCorpid(model.getCorpid());
|
||||
QyAccessTokenEntity accessToken = accessTokenApplicationService.getByAppid(authCorpInfo.getAppid(), model.getCorpid());
|
||||
String userid = QywxApiUtil.convertToUserid(accessToken.getAccessToken(), orderModel.getOpenid()).getUserid();
|
||||
QyUserEntity qyUser = userService.getUserByUserIdAndCorpid(userid, model.getCorpid());
|
||||
if (null != qyUser) {
|
||||
Long ab98UserId = orderModel.getAb98UserId();
|
||||
if (null == ab98UserId) {
|
||||
QyAuthCorpInfoEntity authCorpInfo = authCorpInfoApplicationService.selectByCorpid(model.getCorpid());
|
||||
QyAccessTokenEntity accessToken = accessTokenApplicationService.getByAppid(authCorpInfo.getAppid(), model.getCorpid());
|
||||
String userid = QywxApiUtil.convertToUserid(accessToken.getAccessToken(), orderModel.getOpenid()).getUserid();
|
||||
QyUserEntity qyUser = userService.getUserByUserIdAndCorpid(userid, model.getCorpid());
|
||||
ab98UserId = qyUser.getAb98UserId();
|
||||
}
|
||||
|
||||
if (null == ab98UserId) {
|
||||
throw new IllegalArgumentException("ab98用户不存在");
|
||||
}
|
||||
|
||||
UserBalanceEntity userBalance = userBalanceService.getByCorpidAndAb98UserId(model.getCorpid(), ab98UserId);
|
||||
if (null == userBalance) {
|
||||
throw new IllegalArgumentException("用户余额不存在");
|
||||
}
|
||||
userBalance.setBalance(userBalance.getBalance() + MoneyUtil.yuanToFen(command.getReturnAmount()));
|
||||
userBalance.setUseBalance(userBalance.getUseBalance() - MoneyUtil.yuanToFen(command.getReturnAmount()));
|
||||
userBalance.updateById();
|
||||
/*if (null != qyUser) {
|
||||
qyUser.setBalance(qyUser.getBalance().add(command.getReturnAmount()));
|
||||
qyUser.setUseBalance(qyUser.getUseBalance().subtract(command.getReturnAmount()));
|
||||
}
|
||||
userService.updateById(qyUser);
|
||||
userService.updateById(qyUser);*/
|
||||
} catch (Exception e) {
|
||||
log.error("余额退款失败", e);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@ package com.agileboot.domain.shop.order;
|
|||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.agileboot.common.config.WxshopConfig;
|
||||
import com.agileboot.common.utils.MoneyUtil;
|
||||
import com.agileboot.domain.ab98.user_balance.db.UserBalanceEntity;
|
||||
import com.agileboot.domain.ab98.user_balance.db.UserBalanceService;
|
||||
import com.agileboot.domain.ab98.user_balance.dto.UserBalanceDTO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
|
|
@ -96,6 +100,7 @@ public class OrderApplicationService {
|
|||
private final QyUserService qyUserService;
|
||||
private final Ab98UserService ab98UserService;
|
||||
private final WxUserService wxUserService;
|
||||
private final UserBalanceService userBalanceService;
|
||||
@Autowired
|
||||
private WxshopConfig wxshopConfig;
|
||||
|
||||
|
|
@ -187,6 +192,7 @@ public class OrderApplicationService {
|
|||
orderModel.setIsInternal(command.getIsInternal());
|
||||
orderModel.setUserid(command.getQyUserid());
|
||||
orderModel.setName(command.getName());
|
||||
orderModel.setAb98UserId(command.getAb98UserId());
|
||||
orderModel.setIsDeductStock(0);
|
||||
orderModel.setMode(command.getMode());
|
||||
orderModel.insert();
|
||||
|
|
@ -217,7 +223,7 @@ public class OrderApplicationService {
|
|||
|
||||
return new CreateOrderResult(orderModel.getOrderId(), orderModel.getTotalAmount(), paymentResponse, BigDecimal.valueOf(0));
|
||||
} else if (Objects.equals(command.getPaymentType(), "balance")) {
|
||||
QyUserEntity qyUser = userService.getUserByUserIdAndCorpid(command.getUserid(), command.getCorpid());
|
||||
/*QyUserEntity qyUser = userService.getUserByUserIdAndCorpid(command.getUserid(), command.getCorpid());
|
||||
// 余额不足
|
||||
if (qyUser.getBalance().compareTo(orderModel.getTotalAmount()) < 0) {
|
||||
throw new ApiException(ErrorCode.Client.COMMON_REQUEST_PARAMETERS_INVALID, "余额不足");
|
||||
|
|
@ -225,14 +231,25 @@ public class OrderApplicationService {
|
|||
qyUser.setBalance(qyUser.getBalance().subtract(orderModel.getTotalAmount()));
|
||||
qyUser.setUseBalance(qyUser.getUseBalance().add(orderModel.getTotalAmount()));
|
||||
userService.updateById(qyUser);
|
||||
}*/
|
||||
|
||||
UserBalanceEntity userBalance = userBalanceService.getByCorpidAndAb98UserId(command.getCorpid(), command.getAb98UserId());
|
||||
// 余额不足
|
||||
if (userBalance.getBalance().compareTo(MoneyUtil.yuanToFen(orderModel.getTotalAmount())) < 0) {
|
||||
throw new ApiException(ErrorCode.Client.COMMON_REQUEST_PARAMETERS_INVALID, "余额不足");
|
||||
} else {
|
||||
userBalance.setBalance(userBalance.getBalance() - MoneyUtil.yuanToFen(orderModel.getTotalAmount()));
|
||||
userBalance.setUseBalance(userBalance.getUseBalance() + MoneyUtil.yuanToFen(orderModel.getTotalAmount()));
|
||||
userBalanceService.updateById(userBalance);
|
||||
}
|
||||
|
||||
// 金额转换(元转分)并四舍五入
|
||||
BigDecimal amountInFen = orderModel.getTotalAmount()
|
||||
.multiply(new BigDecimal("100"))
|
||||
.setScale(0, RoundingMode.HALF_UP);
|
||||
handlePaymentSuccess(orderModel.getOrderId(), Integer.valueOf(amountInFen.toPlainString()),
|
||||
"balance-" + orderModel.getOrderId(), DateUtil.formatDateTime(new Date()));
|
||||
return new CreateOrderResult(orderModel.getOrderId(), orderModel.getTotalAmount(), null, qyUser.getBalance());
|
||||
return new CreateOrderResult(orderModel.getOrderId(), orderModel.getTotalAmount(), null, MoneyUtil.fenToYuan(userBalance.getBalance()));
|
||||
} else if (Objects.equals(command.getPaymentType(), "approval")) {
|
||||
submitAssetApproval(orderModel, goodsList, command);
|
||||
return new CreateOrderResult(orderModel.getOrderId(), orderModel.getTotalAmount(), null, BigDecimal.valueOf(0));
|
||||
|
|
|
|||
|
|
@ -45,4 +45,7 @@ public class SubmitOrderCommand {
|
|||
|
||||
@ApiModelProperty("是否为微信小程序支付,0否 1是")
|
||||
private Integer isWxMp;
|
||||
|
||||
@ApiModelProperty("汇邦云用户ID")
|
||||
private Long ab98UserId;
|
||||
}
|
||||
|
|
@ -57,6 +57,10 @@ public class ShopOrderEntity extends BaseEntity<ShopOrderEntity> {
|
|||
@TableField("name")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty("汇邦云用户ID")
|
||||
@TableField(value = "ab98_user_id")
|
||||
private Long ab98UserId;
|
||||
|
||||
@ApiModelProperty("是否内部用户(0否 1汇邦云用户 2企业微信用户)")
|
||||
@TableField("is_internal")
|
||||
private Integer isInternal;
|
||||
|
|
|
|||
|
|
@ -21,3 +21,5 @@ CREATE TABLE `user_balance` (
|
|||
|
||||
-- 添加 deleted 字段的 ALTER 语句
|
||||
ALTER TABLE `user_balance` ADD COLUMN `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除标志(0存在 1删除)';
|
||||
|
||||
ALTER TABLE `shop_order` ADD COLUMN `ab98_user_id` bigint DEFAULT NULL COMMENT '汇邦云用户ID' AFTER `name`;
|
||||
|
|
|
|||
Loading…
Reference in New Issue