Compare commits
12 Commits
be54601cdd
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| a99f05d029 | |||
| bd315fcbd9 | |||
| 716cde6ea0 | |||
| 04755188d6 | |||
| b12f232f56 | |||
| d75a3e0212 | |||
| 299bc5e28b | |||
| d7ed10f45d | |||
| ca6e3d20f6 | |||
| 6fad3b45fe | |||
| a8da54c130 | |||
| d105bd4fa6 |
@@ -141,9 +141,10 @@ public class TenantBalanceController {
|
||||
@Operation(summary = "获得租户积分记录分页")
|
||||
@Parameter(name = "tenantId", description = "租户 Id")
|
||||
@PreAuthorize("@ss.hasPermission('keyboard:tenant-balance:query')")
|
||||
public CommonResult<PageResult<TenantBalanceTransactionDO>> getTenantBalanceTransactionPage(PageParam pageReqVO,
|
||||
public CommonResult<PageResult<TenantBalanceTransactionRespVO>> getTenantBalanceTransactionPage(PageParam pageReqVO,
|
||||
@RequestParam("tenantId") Long tenantId) {
|
||||
return success(tenantBalanceService.getTenantBalanceTransactionPage(pageReqVO, tenantId));
|
||||
PageResult<TenantBalanceTransactionDO> pageResult = tenantBalanceService.getTenantBalanceTransactionPage(pageReqVO, tenantId);
|
||||
return success(BeanUtils.toBean(pageResult, TenantBalanceTransactionRespVO.class));
|
||||
}
|
||||
|
||||
@PostMapping("/tenant-balance-transaction/create")
|
||||
@@ -183,7 +184,8 @@ public class TenantBalanceController {
|
||||
@Operation(summary = "获得租户积分记录")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('keyboard:tenant-balance:query')")
|
||||
public CommonResult<TenantBalanceTransactionDO> getTenantBalanceTransaction(@RequestParam("id") Long id) {
|
||||
return success(tenantBalanceService.getTenantBalanceTransaction(id));
|
||||
public CommonResult<TenantBalanceTransactionRespVO> getTenantBalanceTransaction(@RequestParam("id") Long id) {
|
||||
TenantBalanceTransactionDO transaction = tenantBalanceService.getTenantBalanceTransaction(id);
|
||||
return success(BeanUtils.toBean(transaction, TenantBalanceTransactionRespVO.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.yolo.keyboard.controller.admin.tenantbalance.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 租户积分记录 Response VO")
|
||||
@Data
|
||||
public class TenantBalanceTransactionRespVO {
|
||||
|
||||
@Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "本次变动点数,正加负减", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
|
||||
private BigDecimal points;
|
||||
|
||||
@Schema(description = "变动后余额快照", example = "1000.00")
|
||||
private BigDecimal balance;
|
||||
|
||||
@Schema(description = "变动后冻结金额快照", example = "200.00")
|
||||
private BigDecimal frozenAmt;
|
||||
|
||||
@Schema(description = "变动后可提现余额快照", example = "800.00")
|
||||
private BigDecimal withdrawableBalance;
|
||||
|
||||
@Schema(description = "变动类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "RECHARGE")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "变动描述", example = "余额充值")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "订单Id/业务单号", example = "ORD123456")
|
||||
private String orderId;
|
||||
|
||||
@Schema(description = "业务流水号", example = "BIZ123456")
|
||||
private String bizNo;
|
||||
|
||||
@Schema(description = "操作人Id", example = "1")
|
||||
private Long operatorId;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@Schema(description = "备注", example = "管理员充值")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "租户Id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long tenantId;
|
||||
|
||||
}
|
||||
@@ -90,14 +90,6 @@ public class KeyboardTenantCommissionController {
|
||||
return success(BeanUtils.toBean(pageResult, KeyboardTenantCommissionRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/my-page")
|
||||
@Operation(summary = "获得当前登录租户的分成记录分页")
|
||||
@PreAuthorize("@ss.hasPermission('keyboard:tenant-commission:query:mypage')")
|
||||
public CommonResult<PageResult<KeyboardTenantCommissionRespVO>> getMyTenantCommissionPage(@Valid KeyboardTenantCommissionPageReqVO pageReqVO) {
|
||||
PageResult<KeyboardTenantCommissionDO> pageResult = tenantCommissionService.getMyTenantCommissionPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, KeyboardTenantCommissionRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/export-excel")
|
||||
@Operation(summary = "导出租户内购分成记录 Excel")
|
||||
@PreAuthorize("@ss.hasPermission('keyboard:tenant-commission:export')")
|
||||
|
||||
@@ -14,6 +14,9 @@ import static com.yolo.keyboard.framework.common.util.date.DateUtils.FORMAT_YEAR
|
||||
@Data
|
||||
public class KeyboardTenantCommissionPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "租户ID", example = "1", hidden = true)
|
||||
private Long tenantId;
|
||||
|
||||
@Schema(description = "内购记录ID", example = "20900")
|
||||
private Integer purchaseRecordId;
|
||||
|
||||
|
||||
@@ -84,8 +84,8 @@ public class KeyboardTenantWithdrawOrderController {
|
||||
@Operation(summary = "获得租户提现订单表(申请-审核-打款-完成/失败)分页")
|
||||
@PreAuthorize("@ss.hasPermission('keyboard:tenant-withdraw-order:query')")
|
||||
public CommonResult<PageResult<KeyboardTenantWithdrawOrderRespVO>> getTenantWithdrawOrderPage(@Valid KeyboardTenantWithdrawOrderPageReqVO pageReqVO) {
|
||||
PageResult<KeyboardTenantWithdrawOrderDO> pageResult = tenantWithdrawOrderService.getTenantWithdrawOrderPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, KeyboardTenantWithdrawOrderRespVO.class));
|
||||
PageResult<KeyboardTenantWithdrawOrderRespVO> pageResult = tenantWithdrawOrderService.getTenantWithdrawOrderPage(pageReqVO);
|
||||
return success(pageResult);
|
||||
}
|
||||
|
||||
@GetMapping("/export-excel")
|
||||
@@ -95,10 +95,9 @@ public class KeyboardTenantWithdrawOrderController {
|
||||
public void exportTenantWithdrawOrderExcel(@Valid KeyboardTenantWithdrawOrderPageReqVO pageReqVO,
|
||||
HttpServletResponse response) throws IOException {
|
||||
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
||||
List<KeyboardTenantWithdrawOrderDO> list = tenantWithdrawOrderService.getTenantWithdrawOrderPage(pageReqVO).getList();
|
||||
List<KeyboardTenantWithdrawOrderRespVO> list = tenantWithdrawOrderService.getTenantWithdrawOrderPage(pageReqVO).getList();
|
||||
// 导出 Excel
|
||||
ExcelUtils.write(response, "租户提现订单表(申请-审核-打款-完成/失败).xls", "数据", KeyboardTenantWithdrawOrderRespVO.class,
|
||||
BeanUtils.toBean(list, KeyboardTenantWithdrawOrderRespVO.class));
|
||||
ExcelUtils.write(response, "租户提现订单表(申请-审核-打款-完成/失败).xls", "数据", KeyboardTenantWithdrawOrderRespVO.class, list);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -111,4 +111,7 @@ public class KeyboardTenantWithdrawOrderPageReqVO extends PageParam {
|
||||
@Schema(description = "更新时间")
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
@Schema(description = "租户ID列表(用于下级租户过滤)", hidden = true)
|
||||
private List<Long> tenantIds;
|
||||
|
||||
}
|
||||
@@ -142,4 +142,12 @@ public class KeyboardTenantWithdrawOrderRespVO {
|
||||
@ExcelProperty("更新时间")
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
@Schema(description = "租户编号", example = "1")
|
||||
@ExcelProperty("租户编号")
|
||||
private Long tenantId;
|
||||
|
||||
@Schema(description = "租户名称", example = "芋道源码")
|
||||
@ExcelProperty("租户名称")
|
||||
private String tenantName;
|
||||
|
||||
}
|
||||
@@ -67,4 +67,8 @@ public class TenantBalanceTransactionDO {
|
||||
private String remark;
|
||||
|
||||
private Long tenantId;
|
||||
|
||||
private BigDecimal frozenAmt;
|
||||
|
||||
private BigDecimal withdrawableBalance;
|
||||
}
|
||||
@@ -41,6 +41,7 @@ public interface KeyboardTenantCommissionMapper extends BaseMapperX<KeyboardTena
|
||||
|
||||
default PageResult<KeyboardTenantCommissionDO> selectPage(KeyboardTenantCommissionPageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<KeyboardTenantCommissionDO>()
|
||||
.eqIfPresent(KeyboardTenantCommissionDO::getTenantId, reqVO.getTenantId())
|
||||
.eqIfPresent(KeyboardTenantCommissionDO::getPurchaseRecordId, reqVO.getPurchaseRecordId())
|
||||
.eqIfPresent(KeyboardTenantCommissionDO::getTransactionId, reqVO.getTransactionId())
|
||||
.eqIfPresent(KeyboardTenantCommissionDO::getInviteeUserId, reqVO.getInviteeUserId())
|
||||
@@ -57,28 +58,4 @@ public interface KeyboardTenantCommissionMapper extends BaseMapperX<KeyboardTena
|
||||
.eqIfPresent(KeyboardTenantCommissionDO::getRemark, reqVO.getRemark())
|
||||
.orderByDesc(KeyboardTenantCommissionDO::getId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据租户ID分页查询分成记录
|
||||
*/
|
||||
default PageResult<KeyboardTenantCommissionDO> selectPageByTenantId(KeyboardTenantCommissionPageReqVO reqVO, Long tenantId) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<KeyboardTenantCommissionDO>()
|
||||
.eq(KeyboardTenantCommissionDO::getTenantId, tenantId)
|
||||
.eqIfPresent(KeyboardTenantCommissionDO::getPurchaseRecordId, reqVO.getPurchaseRecordId())
|
||||
.eqIfPresent(KeyboardTenantCommissionDO::getTransactionId, reqVO.getTransactionId())
|
||||
.eqIfPresent(KeyboardTenantCommissionDO::getInviteeUserId, reqVO.getInviteeUserId())
|
||||
.eqIfPresent(KeyboardTenantCommissionDO::getInviterUserId, reqVO.getInviterUserId())
|
||||
.eqIfPresent(KeyboardTenantCommissionDO::getPurchaseAmount, reqVO.getPurchaseAmount())
|
||||
.eqIfPresent(KeyboardTenantCommissionDO::getCommissionRate, reqVO.getCommissionRate())
|
||||
.eqIfPresent(KeyboardTenantCommissionDO::getCommissionAmount, reqVO.getCommissionAmount())
|
||||
.eqIfPresent(KeyboardTenantCommissionDO::getStatus, reqVO.getStatus())
|
||||
.betweenIfPresent(KeyboardTenantCommissionDO::getPurchaseTime, reqVO.getPurchaseTime())
|
||||
.eqIfPresent(KeyboardTenantCommissionDO::getSettledAt, reqVO.getSettledAt())
|
||||
.eqIfPresent(KeyboardTenantCommissionDO::getBalanceTransactionId, reqVO.getBalanceTransactionId())
|
||||
.eqIfPresent(KeyboardTenantCommissionDO::getCreatedAt, reqVO.getCreatedAt())
|
||||
.eqIfPresent(KeyboardTenantCommissionDO::getUpdatedAt, reqVO.getUpdatedAt())
|
||||
.eqIfPresent(KeyboardTenantCommissionDO::getRemark, reqVO.getRemark())
|
||||
.orderByDesc(KeyboardTenantCommissionDO::getId));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ public interface KeyboardTenantWithdrawOrderMapper extends BaseMapperX<KeyboardT
|
||||
|
||||
default PageResult<KeyboardTenantWithdrawOrderDO> selectPage(KeyboardTenantWithdrawOrderPageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<KeyboardTenantWithdrawOrderDO>()
|
||||
.inIfPresent(KeyboardTenantWithdrawOrderDO::getTenantId, reqVO.getTenantIds())
|
||||
.eqIfPresent(KeyboardTenantWithdrawOrderDO::getWithdrawNo, reqVO.getWithdrawNo())
|
||||
.eqIfPresent(KeyboardTenantWithdrawOrderDO::getBizNo, reqVO.getBizNo())
|
||||
.eqIfPresent(KeyboardTenantWithdrawOrderDO::getCurrency, reqVO.getCurrency())
|
||||
|
||||
@@ -101,6 +101,8 @@ public class CommissionWithdrawableJob implements JobHandler {
|
||||
.bizNo(bizNo)
|
||||
.points(tenantTotalAmount)
|
||||
.balance(balance.getBalance())
|
||||
.frozenAmt(balance.getFrozenAmt() != null ? balance.getFrozenAmt() : BigDecimal.ZERO)
|
||||
.withdrawableBalance(newWithdrawable)
|
||||
.tenantId(tenantId)
|
||||
.type(WITHDRAWABLE_TYPE)
|
||||
.description("分成转可提现")
|
||||
|
||||
@@ -288,6 +288,8 @@ public class TenantCommissionCalculateJob implements JobHandler {
|
||||
.bizNo(bizNo)
|
||||
.points(commissionAmount)
|
||||
.balance(balance.getBalance())
|
||||
.frozenAmt(balance.getFrozenAmt() != null ? balance.getFrozenAmt() : BigDecimal.ZERO)
|
||||
.withdrawableBalance(balance.getWithdrawableBalance() != null ? balance.getWithdrawableBalance() : BigDecimal.ZERO)
|
||||
.tenantId(tenantId)
|
||||
.type(COMMISSION_TYPE)
|
||||
.description("邀请用户内购分成")
|
||||
|
||||
@@ -140,6 +140,8 @@ public class TenantBalanceServiceImpl implements TenantBalanceService {
|
||||
.bizNo(BizNoGenerator.generate("RECHARGE")) // 生成充值业务编号
|
||||
.points(new BigDecimal(String.valueOf(addReqVO.getAmount()))) // 充值金额
|
||||
.balance(newBalance) // 充值后余额
|
||||
.frozenAmt(balance.getFrozenAmt() != null ? balance.getFrozenAmt() : BigDecimal.ZERO) // 当前冻结金额
|
||||
.withdrawableBalance(balance.getWithdrawableBalance() != null ? balance.getWithdrawableBalance() : BigDecimal.ZERO) // 当前可提现金额
|
||||
.tenantId(addReqVO.getId())
|
||||
.type("RECHARGE") // 交易类型:充值
|
||||
.description("余额充值") // 交易描述
|
||||
@@ -243,18 +245,18 @@ public class TenantBalanceServiceImpl implements TenantBalanceService {
|
||||
throw exception(TENANT_BALANCE_NOT_EXISTS);
|
||||
}
|
||||
|
||||
// 3. 校验可用余额是否充足(可用余额 = 余额 - 冻结金额)
|
||||
// 3. 校验可提现金额是否充足
|
||||
BigDecimal withdrawAmount = withdrawReqVO.getAmount();
|
||||
BigDecimal frozenAmt = balance.getFrozenAmt() != null ? balance.getFrozenAmt() : BigDecimal.ZERO;
|
||||
BigDecimal availableBalance = balance.getBalance().subtract(frozenAmt);
|
||||
if (availableBalance.compareTo(withdrawAmount) < 0) {
|
||||
BigDecimal withdrawableBalance = balance.getWithdrawableBalance() != null ? balance.getWithdrawableBalance() : BigDecimal.ZERO;
|
||||
if (withdrawableBalance.compareTo(withdrawAmount) < 0) {
|
||||
throw exception(TENANT_BALANCE_WITHDRAW_INSUFFICIENT);
|
||||
}
|
||||
|
||||
// 4. 扣减余额并增加冻结金额
|
||||
BigDecimal newBalance = balance.getBalance().subtract(withdrawAmount);
|
||||
// 4. 从可提现金额中扣减并增加冻结金额
|
||||
BigDecimal frozenAmt = balance.getFrozenAmt() != null ? balance.getFrozenAmt() : BigDecimal.ZERO;
|
||||
BigDecimal newWithdrawableBalance = withdrawableBalance.subtract(withdrawAmount);
|
||||
BigDecimal newFrozenAmt = frozenAmt.add(withdrawAmount);
|
||||
balance.setBalance(newBalance);
|
||||
balance.setWithdrawableBalance(newWithdrawableBalance);
|
||||
balance.setFrozenAmt(newFrozenAmt);
|
||||
int updateCount = tenantBalanceMapper.updateById(balance);
|
||||
if (updateCount == 0) {
|
||||
@@ -268,8 +270,10 @@ public class TenantBalanceServiceImpl implements TenantBalanceService {
|
||||
// 6. 创建冻结交易记录
|
||||
TenantBalanceTransactionDO transaction = TenantBalanceTransactionDO.builder()
|
||||
.bizNo(bizNo)
|
||||
.points(withdrawAmount.negate()) // 冻结金额(负数表示冻结扣减)
|
||||
.balance(newBalance) // 扣减后的余额
|
||||
.points(withdrawAmount.negate()) // 冻结金额(负数表示冻结扣减)
|
||||
.balance(balance.getBalance()) // 当前总余额
|
||||
.frozenAmt(newFrozenAmt) // 冻结后的冻结金额
|
||||
.withdrawableBalance(newWithdrawableBalance) // 扣减后的可提现余额
|
||||
.tenantId(tenantId)
|
||||
.type("FREEZE")
|
||||
.description("提现冻结")
|
||||
|
||||
@@ -65,6 +65,5 @@ public interface KeyboardTenantCommissionService {
|
||||
* @param pageReqVO 分页查询
|
||||
* @return 租户内购分成记录分页
|
||||
*/
|
||||
PageResult<KeyboardTenantCommissionDO> getMyTenantCommissionPage(KeyboardTenantCommissionPageReqVO pageReqVO);
|
||||
|
||||
}
|
||||
@@ -15,6 +15,8 @@ import com.yolo.keyboard.framework.common.util.object.BeanUtils;
|
||||
|
||||
import com.yolo.keyboard.dal.mysql.tenantcommission.KeyboardTenantCommissionMapper;
|
||||
import com.yolo.keyboard.framework.tenant.core.context.TenantContextHolder;
|
||||
import com.yolo.keyboard.module.system.dal.dataobject.tenant.TenantDO;
|
||||
import com.yolo.keyboard.module.system.dal.mysql.tenant.TenantMapper;
|
||||
|
||||
import static com.yolo.keyboard.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static com.yolo.keyboard.framework.common.util.collection.CollectionUtils.convertList;
|
||||
@@ -32,6 +34,9 @@ public class KeyboardTenantCommissionServiceImpl implements KeyboardTenantCommis
|
||||
@Resource
|
||||
private KeyboardTenantCommissionMapper tenantCommissionMapper;
|
||||
|
||||
@Resource
|
||||
private TenantMapper tenantMapper;
|
||||
|
||||
@Override
|
||||
public Long createTenantCommission(KeyboardTenantCommissionSaveReqVO createReqVO) {
|
||||
// 插入
|
||||
@@ -79,13 +84,16 @@ public class KeyboardTenantCommissionServiceImpl implements KeyboardTenantCommis
|
||||
|
||||
@Override
|
||||
public PageResult<KeyboardTenantCommissionDO> getTenantCommissionPage(KeyboardTenantCommissionPageReqVO pageReqVO) {
|
||||
// 如果当前租户的 tenantLevel 不等于 0,只能查询属于自己的数据
|
||||
Long currentTenantId = TenantContextHolder.getTenantId();
|
||||
if (currentTenantId != null) {
|
||||
TenantDO currentTenant = tenantMapper.selectById(currentTenantId);
|
||||
if (currentTenant != null && currentTenant.getTenantLevel() != null
|
||||
&& currentTenant.getTenantLevel() != 0) {
|
||||
pageReqVO.setTenantId(currentTenantId);
|
||||
}
|
||||
}
|
||||
return tenantCommissionMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<KeyboardTenantCommissionDO> getMyTenantCommissionPage(KeyboardTenantCommissionPageReqVO pageReqVO) {
|
||||
Long tenantId = TenantContextHolder.getRequiredTenantId();
|
||||
return tenantCommissionMapper.selectPageByTenantId(pageReqVO, tenantId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -57,6 +57,6 @@ public interface KeyboardTenantWithdrawOrderService {
|
||||
* @param pageReqVO 分页查询
|
||||
* @return 租户提现订单表(申请-审核-打款-完成/失败)分页
|
||||
*/
|
||||
PageResult<KeyboardTenantWithdrawOrderDO> getTenantWithdrawOrderPage(KeyboardTenantWithdrawOrderPageReqVO pageReqVO);
|
||||
PageResult<KeyboardTenantWithdrawOrderRespVO> getTenantWithdrawOrderPage(KeyboardTenantWithdrawOrderPageReqVO pageReqVO);
|
||||
|
||||
}
|
||||
@@ -1,23 +1,34 @@
|
||||
package com.yolo.keyboard.service.tenantwithdraworder;
|
||||
|
||||
import com.yolo.keyboard.controller.admin.tenantwithdraworder.vo.KeyboardTenantWithdrawOrderPageReqVO;
|
||||
import com.yolo.keyboard.controller.admin.tenantwithdraworder.vo.KeyboardTenantWithdrawOrderRespVO;
|
||||
import com.yolo.keyboard.controller.admin.tenantwithdraworder.vo.KeyboardTenantWithdrawOrderSaveReqVO;
|
||||
import com.yolo.keyboard.dal.dataobject.tenantbalance.TenantBalanceDO;
|
||||
import com.yolo.keyboard.dal.dataobject.tenantbalancetransaction.TenantBalanceTransactionDO;
|
||||
import com.yolo.keyboard.dal.dataobject.tenantwithdraworder.KeyboardTenantWithdrawOrderDO;
|
||||
import com.yolo.keyboard.dal.mysql.tenantbalance.TenantBalanceMapper;
|
||||
import com.yolo.keyboard.dal.mysql.tenantbalancetransaction.TenantBalanceTransactionMapper;
|
||||
import com.yolo.keyboard.dal.mysql.tenantwithdraworder.KeyboardTenantWithdrawOrderMapper;
|
||||
import com.yolo.keyboard.framework.common.pojo.PageResult;
|
||||
import com.yolo.keyboard.framework.common.util.object.BeanUtils;
|
||||
import com.yolo.keyboard.framework.tenant.core.context.TenantContextHolder;
|
||||
import com.yolo.keyboard.module.system.dal.dataobject.tenant.TenantDO;
|
||||
import com.yolo.keyboard.module.system.dal.mysql.tenant.TenantMapper;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
import com.yolo.keyboard.controller.admin.tenantwithdraworder.vo.*;
|
||||
import com.yolo.keyboard.dal.dataobject.tenantwithdraworder.KeyboardTenantWithdrawOrderDO;
|
||||
import com.yolo.keyboard.framework.common.pojo.PageResult;
|
||||
import com.yolo.keyboard.framework.common.pojo.PageParam;
|
||||
import com.yolo.keyboard.framework.common.util.object.BeanUtils;
|
||||
|
||||
import com.yolo.keyboard.dal.mysql.tenantwithdraworder.KeyboardTenantWithdrawOrderMapper;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.yolo.keyboard.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static com.yolo.keyboard.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static com.yolo.keyboard.framework.common.util.collection.CollectionUtils.diffList;
|
||||
import static com.yolo.keyboard.module.infra.enums.ErrorCodeConstants.TENANT_WITHDRAW_ORDER_NOT_EXISTS;
|
||||
|
||||
/**
|
||||
@@ -32,6 +43,15 @@ public class KeyboardTenantWithdrawOrderServiceImpl implements KeyboardTenantWit
|
||||
@Resource
|
||||
private KeyboardTenantWithdrawOrderMapper tenantWithdrawOrderMapper;
|
||||
|
||||
@Resource
|
||||
private TenantMapper tenantMapper;
|
||||
|
||||
@Resource
|
||||
private TenantBalanceMapper tenantBalanceMapper;
|
||||
|
||||
@Resource
|
||||
private TenantBalanceTransactionMapper tenantBalanceTransactionMapper;
|
||||
|
||||
@Override
|
||||
public Long createTenantWithdrawOrder(KeyboardTenantWithdrawOrderSaveReqVO createReqVO) {
|
||||
// 插入
|
||||
@@ -43,12 +63,145 @@ public class KeyboardTenantWithdrawOrderServiceImpl implements KeyboardTenantWit
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void updateTenantWithdrawOrder(KeyboardTenantWithdrawOrderSaveReqVO updateReqVO) {
|
||||
// 校验存在
|
||||
validateTenantWithdrawOrderExists(updateReqVO.getId());
|
||||
// 更新
|
||||
KeyboardTenantWithdrawOrderDO existingOrder = tenantWithdrawOrderMapper.selectById(updateReqVO.getId());
|
||||
if (existingOrder == null) {
|
||||
throw exception(TENANT_WITHDRAW_ORDER_NOT_EXISTS);
|
||||
}
|
||||
|
||||
// 更新订单
|
||||
KeyboardTenantWithdrawOrderDO updateObj = BeanUtils.toBean(updateReqVO, KeyboardTenantWithdrawOrderDO.class);
|
||||
tenantWithdrawOrderMapper.updateById(updateObj);
|
||||
|
||||
String newStatus = updateReqVO.getStatus();
|
||||
String oldStatus = existingOrder.getStatus();
|
||||
|
||||
// 如果提现状态更新为成功(PAID),则扣除提现用户的冻结金额并创建流水记录
|
||||
if ("PAID".equals(newStatus) && !"PAID".equals(oldStatus)) {
|
||||
handleWithdrawSuccess(existingOrder);
|
||||
}
|
||||
// 如果提现状态更新为已拒绝、已取消、打款失败,则返还冻结金额到可提现余额并创建流水记录
|
||||
else if (isRefundStatus(newStatus) && !isRefundStatus(oldStatus)) {
|
||||
handleWithdrawRefund(existingOrder, newStatus, updateReqVO.getReason());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为需要退还冻结金额的状态
|
||||
*/
|
||||
private boolean isRefundStatus(String status) {
|
||||
return "REJECTED".equals(status) || "CANCELED".equals(status) || "FAILED".equals(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理提现成功:扣除冻结金额并记录流水
|
||||
*/
|
||||
private void handleWithdrawSuccess(KeyboardTenantWithdrawOrderDO order) {
|
||||
TenantBalanceDO balance = tenantBalanceMapper.selectById(order.getTenantId());
|
||||
if (balance == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 扣除冻结金额
|
||||
BigDecimal frozenAmt = balance.getFrozenAmt() != null ? balance.getFrozenAmt() : BigDecimal.ZERO;
|
||||
BigDecimal withdrawAmount = order.getAmount();
|
||||
BigDecimal newFrozenAmt = frozenAmt.subtract(withdrawAmount);
|
||||
if (newFrozenAmt.compareTo(BigDecimal.ZERO) < 0) {
|
||||
newFrozenAmt = BigDecimal.ZERO;
|
||||
}
|
||||
balance.setFrozenAmt(newFrozenAmt);
|
||||
tenantBalanceMapper.updateById(balance);
|
||||
|
||||
// 创建提现成功的流水记录
|
||||
BigDecimal currentWithdrawableBalance = balance.getWithdrawableBalance() != null ? balance.getWithdrawableBalance() : BigDecimal.ZERO;
|
||||
TenantBalanceTransactionDO transaction = TenantBalanceTransactionDO.builder()
|
||||
.bizNo(order.getBizNo())
|
||||
.points(withdrawAmount.negate()) // 提现金额(负数表示支出)
|
||||
.balance(balance.getBalance()) // 当前总余额
|
||||
.frozenAmt(newFrozenAmt) // 扣除后的冻结金额
|
||||
.withdrawableBalance(currentWithdrawableBalance) // 当前可提现余额
|
||||
.tenantId(order.getTenantId())
|
||||
.type("WITHDRAW_SUCCESS")
|
||||
.description("提现成功")
|
||||
.orderId(order.getWithdrawNo())
|
||||
.operatorId(TenantContextHolder.getTenantId())
|
||||
.createdAt(LocalDateTime.now())
|
||||
.build();
|
||||
tenantBalanceTransactionMapper.insert(transaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理提现退还:返还冻结金额到可提现余额并记录流水
|
||||
*
|
||||
* @param order 提现订单
|
||||
* @param newStatus 新状态
|
||||
* @param reason 拒绝/失败/取消原因
|
||||
*/
|
||||
private void handleWithdrawRefund(KeyboardTenantWithdrawOrderDO order, String newStatus, String reason) {
|
||||
TenantBalanceDO balance = tenantBalanceMapper.selectById(order.getTenantId());
|
||||
if (balance == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
BigDecimal withdrawAmount = order.getAmount();
|
||||
|
||||
// 扣除冻结金额
|
||||
BigDecimal frozenAmt = balance.getFrozenAmt() != null ? balance.getFrozenAmt() : BigDecimal.ZERO;
|
||||
BigDecimal newFrozenAmt = frozenAmt.subtract(withdrawAmount);
|
||||
if (newFrozenAmt.compareTo(BigDecimal.ZERO) < 0) {
|
||||
newFrozenAmt = BigDecimal.ZERO;
|
||||
}
|
||||
balance.setFrozenAmt(newFrozenAmt);
|
||||
|
||||
// 返还到可提现余额
|
||||
BigDecimal withdrawableBalance = balance.getWithdrawableBalance() != null ? balance.getWithdrawableBalance() : BigDecimal.ZERO;
|
||||
BigDecimal newWithdrawableBalance = withdrawableBalance.add(withdrawAmount);
|
||||
balance.setWithdrawableBalance(newWithdrawableBalance);
|
||||
|
||||
tenantBalanceMapper.updateById(balance);
|
||||
|
||||
// 根据状态确定流水类型和描述
|
||||
String type;
|
||||
String description;
|
||||
switch (newStatus) {
|
||||
case "REJECTED":
|
||||
type = "WITHDRAW_REJECTED";
|
||||
description = "提现被拒绝,金额已退还";
|
||||
break;
|
||||
case "CANCELED":
|
||||
type = "WITHDRAW_CANCELED";
|
||||
description = "提现已取消,金额已退还";
|
||||
break;
|
||||
case "FAILED":
|
||||
type = "WITHDRAW_FAILED";
|
||||
description = "提现打款失败,金额已退还";
|
||||
break;
|
||||
default:
|
||||
type = "WITHDRAW_REFUND";
|
||||
description = "提现退还";
|
||||
}
|
||||
|
||||
// 备注:优先使用传入的原因,如果没有则使用默认描述
|
||||
String remark = (reason != null && !reason.trim().isEmpty()) ? reason : description;
|
||||
|
||||
// 创建退还流水记录
|
||||
TenantBalanceTransactionDO transaction = TenantBalanceTransactionDO.builder()
|
||||
.bizNo(order.getBizNo())
|
||||
.points(withdrawAmount) // 退还金额(正数表示收入)
|
||||
.balance(balance.getBalance()) // 当前总余额
|
||||
.frozenAmt(newFrozenAmt) // 扣除后的冻结金额
|
||||
.withdrawableBalance(newWithdrawableBalance) // 退还后的可提现余额
|
||||
.tenantId(order.getTenantId())
|
||||
.type(type)
|
||||
.description(description)
|
||||
.remark(remark)
|
||||
.orderId(order.getWithdrawNo())
|
||||
.operatorId(TenantContextHolder.getTenantId())
|
||||
.createdAt(LocalDateTime.now())
|
||||
.build();
|
||||
tenantBalanceTransactionMapper.insert(transaction);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -78,8 +231,67 @@ public class KeyboardTenantWithdrawOrderServiceImpl implements KeyboardTenantWit
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<KeyboardTenantWithdrawOrderDO> getTenantWithdrawOrderPage(KeyboardTenantWithdrawOrderPageReqVO pageReqVO) {
|
||||
return tenantWithdrawOrderMapper.selectPage(pageReqVO);
|
||||
public PageResult<KeyboardTenantWithdrawOrderRespVO> getTenantWithdrawOrderPage(KeyboardTenantWithdrawOrderPageReqVO pageReqVO) {
|
||||
// 根据当前租户级别过滤下级租户的提现申请
|
||||
Long currentTenantId = TenantContextHolder.getTenantId();
|
||||
if (currentTenantId != null) {
|
||||
TenantDO currentTenant = tenantMapper.selectById(currentTenantId);
|
||||
if (currentTenant != null && currentTenant.getTenantLevel() != null) {
|
||||
if (currentTenant.getTenantLevel() == 0) {
|
||||
// 系统管理员:只能查看1级代理的提现申请
|
||||
List<TenantDO> firstLevelAgents = tenantMapper.selectList(
|
||||
new LambdaQueryWrapper<TenantDO>().eq(TenantDO::getTenantLevel, 1));
|
||||
List<Long> firstLevelAgentIds = firstLevelAgents.stream()
|
||||
.map(TenantDO::getId)
|
||||
.collect(Collectors.toList());
|
||||
if (CollUtil.isEmpty(firstLevelAgentIds)) {
|
||||
// 没有1级代理,返回空结果
|
||||
return PageResult.empty(0L);
|
||||
}
|
||||
pageReqVO.setTenantIds(firstLevelAgentIds);
|
||||
} else {
|
||||
// 非系统管理员:只能查看直属下级租户的提现申请
|
||||
List<TenantDO> subordinateTenants = tenantMapper.selectList(
|
||||
new LambdaQueryWrapper<TenantDO>().eq(TenantDO::getParentId, currentTenantId));
|
||||
List<Long> subordinateTenantIds = subordinateTenants.stream()
|
||||
.map(TenantDO::getId)
|
||||
.collect(Collectors.toList());
|
||||
if (CollUtil.isEmpty(subordinateTenantIds)) {
|
||||
// 没有下级租户,返回空结果
|
||||
return PageResult.empty(0L);
|
||||
}
|
||||
pageReqVO.setTenantIds(subordinateTenantIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分页查询租户提现订单数据
|
||||
PageResult<KeyboardTenantWithdrawOrderDO> pageResult = tenantWithdrawOrderMapper.selectPage(pageReqVO);
|
||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||
return PageResult.empty(pageResult.getTotal());
|
||||
}
|
||||
|
||||
// 批量获取租户名称 - 提升性能,避免N+1查询
|
||||
List<Long> tenantIds = pageResult.getList().stream()
|
||||
.map(KeyboardTenantWithdrawOrderDO::getTenantId)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
List<TenantDO> tenants = tenantMapper.selectBatchIds(tenantIds);
|
||||
Map<Long, String> tenantNameMap = CollUtil.isEmpty(tenants)
|
||||
? new HashMap<>() // 如果没有查询到租户数据,返回空map
|
||||
: tenants.stream().collect(Collectors.toMap(TenantDO::getId, TenantDO::getName, (a, b) -> a)); // 构建租户ID到名称的映射
|
||||
|
||||
// 转换为 VO 并填充租户名称
|
||||
List<KeyboardTenantWithdrawOrderRespVO> voList = pageResult.getList().stream().map(order -> {
|
||||
// 将DO转换为VO
|
||||
KeyboardTenantWithdrawOrderRespVO vo = BeanUtils.toBean(order, KeyboardTenantWithdrawOrderRespVO.class);
|
||||
// 根据租户ID获取并设置租户名称
|
||||
vo.setTenantName(tenantNameMap.get(order.getTenantId()));
|
||||
return vo;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
// 返回包含VO列表和总数的分页结果
|
||||
return new PageResult<>(voList, pageResult.getTotal());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import com.yolo.keyboard.framework.tenant.core.aop.TenantIgnore;
|
||||
import com.yolo.keyboard.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO;
|
||||
import com.yolo.keyboard.module.system.controller.admin.tenant.vo.tenant.TenantRespVO;
|
||||
import com.yolo.keyboard.module.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO;
|
||||
import com.yolo.keyboard.module.system.controller.admin.tenant.vo.tenant.TenantInfoRespVO;
|
||||
import com.yolo.keyboard.module.system.dal.dataobject.tenant.TenantDO;
|
||||
import com.yolo.keyboard.module.system.service.tenant.TenantService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@@ -113,6 +114,13 @@ public class TenantController {
|
||||
return success(BeanUtils.toBean(tenant, TenantRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/current")
|
||||
@Operation(summary = "获得当前登录租户信息")
|
||||
public CommonResult<TenantInfoRespVO> getCurrentTenant() {
|
||||
TenantDO tenant = tenantService.getCurrentTenant();
|
||||
return success(BeanUtils.toBean(tenant, TenantInfoRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得租户分页")
|
||||
@PreAuthorize("@ss.hasPermission('system:tenant:query')")
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.yolo.keyboard.module.system.controller.admin.tenant.vo.tenant;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Schema(description = "管理后台 - 当前租户信息 Response VO")
|
||||
@Data
|
||||
public class TenantInfoRespVO {
|
||||
|
||||
@Schema(description = "租户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "上级租户编号", example = "1")
|
||||
private Long parentId;
|
||||
|
||||
@Schema(description = "代理级别", example = "1")
|
||||
private Integer tenantLevel;
|
||||
|
||||
@Schema(description = "分润比例", example = "0.3")
|
||||
private BigDecimal profitShareRatio;
|
||||
|
||||
}
|
||||
@@ -19,6 +19,7 @@ public interface TenantMapper extends BaseMapperX<TenantDO> {
|
||||
.likeIfPresent(TenantDO::getContactName, reqVO.getContactName())
|
||||
.likeIfPresent(TenantDO::getContactMobile, reqVO.getContactMobile())
|
||||
.eqIfPresent(TenantDO::getStatus, reqVO.getStatus())
|
||||
.eqIfPresent(TenantDO::getParentId, reqVO.getParentId())
|
||||
.betweenIfPresent(TenantDO::getCreateTime, reqVO.getCreateTime())
|
||||
.orderByDesc(TenantDO::getId));
|
||||
}
|
||||
|
||||
@@ -142,4 +142,11 @@ public interface TenantService {
|
||||
*/
|
||||
void validTenant(Long id);
|
||||
|
||||
/**
|
||||
* 获取当前登录租户信息
|
||||
*
|
||||
* @return 当前租户
|
||||
*/
|
||||
TenantDO getCurrentTenant();
|
||||
|
||||
}
|
||||
|
||||
@@ -132,6 +132,11 @@ public class TenantServiceImpl implements TenantService {
|
||||
}
|
||||
tenant.setParentId(currentTenantId);
|
||||
tenant.setTenantLevel(parentTenant != null && parentTenant.getTenantLevel() != null ? parentTenant.getTenantLevel() + 1 : 1);
|
||||
|
||||
// 如果当前用户是1级代理,下级分成比例沿用自己的分成比例,不允许单独设置
|
||||
if (parentTenant != null && parentTenant.getTenantLevel() != null && parentTenant.getTenantLevel() == 1) {
|
||||
tenant.setProfitShareRatio(parentTenant.getProfitShareRatio());
|
||||
}
|
||||
}
|
||||
}
|
||||
tenantMapper.insert(tenant);
|
||||
@@ -285,6 +290,15 @@ public class TenantServiceImpl implements TenantService {
|
||||
|
||||
@Override
|
||||
public PageResult<TenantDO> getTenantPage(TenantPageReqVO pageReqVO) {
|
||||
// 如果当前租户是一级代理(tenantLevel=1),只能查询自己的下级租户
|
||||
Long currentTenantId = TenantContextHolder.getTenantId();
|
||||
if (currentTenantId != null) {
|
||||
TenantDO currentTenant = tenantMapper.selectById(currentTenantId);
|
||||
if (currentTenant != null && currentTenant.getTenantLevel() != null
|
||||
&& currentTenant.getTenantLevel() == 1) {
|
||||
pageReqVO.setParentId(currentTenantId);
|
||||
}
|
||||
}
|
||||
return tenantMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@@ -352,4 +366,10 @@ public class TenantServiceImpl implements TenantService {
|
||||
return tenantProperties == null || Boolean.FALSE.equals(tenantProperties.getEnable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TenantDO getCurrentTenant() {
|
||||
Long tenantId = TenantContextHolder.getRequiredTenantId();
|
||||
return getTenant(tenantId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user