!624 trade: 分销业务 - 佣金提现

Merge pull request !624 from 疯狂的世界/brokerate
This commit is contained in:
芋道源码
2023-09-19 14:25:43 +00:00
committed by Gitee
16 changed files with 717 additions and 8 deletions

View File

@@ -0,0 +1,82 @@
package cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawAuditReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawPageReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawRespVO;
import cn.iocoder.yudao.module.trade.convert.brokerage.withdraw.BrokerageWithdrawConvert;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.withdraw.BrokerageWithdrawDO;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum;
import cn.iocoder.yudao.module.trade.service.brokerage.withdraw.BrokerageWithdrawService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Map;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
@Tag(name = "管理后台 - 佣金提现")
@RestController
@RequestMapping("/trade/brokerage-withdraw")
@Validated
public class BrokerageWithdrawController {
@Resource
private BrokerageWithdrawService brokerageWithdrawService;
@Resource
private MemberUserApi memberUserApi;
@PutMapping("/approve")
@Operation(summary = "佣金提现 - 通过申请")
@PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:audit')")
public CommonResult<Boolean> approveBrokerageWithdraw(@RequestParam("id") Integer id) {
brokerageWithdrawService.auditBrokerageWithdraw(id, BrokerageWithdrawStatusEnum.AUDIT_SUCCESS, "");
return success(true);
}
@PutMapping("/reject")
@Operation(summary = "审核佣金提现 - 驳回申请")
@PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:audit')")
public CommonResult<Boolean> rejectBrokerageWithdraw(@Valid @RequestBody BrokerageWithdrawAuditReqVO reqVO) {
brokerageWithdrawService.auditBrokerageWithdraw(reqVO.getId(), BrokerageWithdrawStatusEnum.AUDIT_FAIL, reqVO.getAuditReason());
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得佣金提现")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:query')")
public CommonResult<BrokerageWithdrawRespVO> getBrokerageWithdraw(@RequestParam("id") Integer id) {
BrokerageWithdrawDO brokerageWithdraw = brokerageWithdrawService.getBrokerageWithdraw(id);
return success(BrokerageWithdrawConvert.INSTANCE.convert(brokerageWithdraw));
}
@GetMapping("/page")
@Operation(summary = "获得佣金提现分页")
@PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:query')")
public CommonResult<PageResult<BrokerageWithdrawRespVO>> getBrokerageWithdrawPage(@Valid BrokerageWithdrawPageReqVO pageVO) {
// 分页查询
PageResult<BrokerageWithdrawDO> pageResult = brokerageWithdrawService.getBrokerageWithdrawPage(pageVO);
// 涉及到的用户
Set<Long> userIds = convertSet(pageResult.getList(), BrokerageWithdrawDO::getUserId);
// 查询用户信息
Map<Long, MemberUserRespDTO> userMap = memberUserApi.getUserMap(userIds);
return success(BrokerageWithdrawConvert.INSTANCE.convertPage(pageResult, userMap));
}
}

View File

@@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.ToString;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@Schema(description = "管理后台 - 佣金提现审核 Request VO")
@Data
@ToString(callSuper = true)
public class BrokerageWithdrawAuditReqVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7161")
@NotNull(message = "编号不能为空")
private Integer id;
@Schema(description = "审核驳回原因", example = "不对")
@NotEmpty(message = "审核驳回原因不能为空")
private String auditReason;
}

View File

@@ -0,0 +1,68 @@
package cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
/**
* 佣金提现 Base VO提供给添加、修改、详细的子 VO 使用
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
*/
@Data
public class BrokerageWithdrawBaseVO {
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11436")
@NotNull(message = "用户编号不能为空")
private Long userId;
@Schema(description = "提现金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "18781")
@NotNull(message = "提现金额不能为空")
private Integer price;
@Schema(description = "提现手续费", requiredMode = Schema.RequiredMode.REQUIRED, example = "11417")
@NotNull(message = "提现手续费不能为空")
private Integer feePrice;
@Schema(description = "当前总佣金", requiredMode = Schema.RequiredMode.REQUIRED, example = "18576")
@NotNull(message = "当前总佣金不能为空")
private Integer totalPrice;
@Schema(description = "提现类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "提现类型不能为空")
private Integer type;
@Schema(description = "真实姓名", example = "赵六")
private String name;
@Schema(description = "账号")
private String accountNo;
@Schema(description = "银行名称", example = "1")
private String bankName;
@Schema(description = "开户地址", example = "海淀支行")
private String bankAddress;
@Schema(description = "收款码", example = "https://www.iocoder.cn")
private String accountQrCodeUrl;
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "状态不能为空")
private Integer status;
@Schema(description = "审核驳回原因", example = "不对")
private String auditReason;
@Schema(description = "审核时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime auditTime;
@Schema(description = "备注", example = "随便")
private String remark;
}

View File

@@ -0,0 +1,47 @@
package cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 佣金提现分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BrokerageWithdrawPageReqVO extends PageParam {
@Schema(description = "用户编号", example = "11436")
private Long userId;
@Schema(description = "提现类型", example = "1")
@InEnum(value = BrokerageWithdrawTypeEnum.class, message = "提现类型必须是 {value}")
private Integer type;
@Schema(description = "真实姓名", example = "赵六")
private String name;
@Schema(description = "账号")
private String accountNo;
@Schema(description = "银行名称", example = "1")
private String bankName;
@Schema(description = "状态", example = "1")
@InEnum(value = BrokerageWithdrawStatusEnum.class, message = "状态必须是 {value}")
private Integer status;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@@ -0,0 +1,25 @@
package cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 佣金提现 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BrokerageWithdrawRespVO extends BrokerageWithdrawBaseVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7161")
private Integer id;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
@Schema(description = "用户昵称")
private String userNickname;
}

View File

@@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.trade.convert.brokerage.withdraw;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawAuditReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawRespVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.withdraw.BrokerageWithdrawDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
* 佣金提现 Convert
*
* @author 芋道源码
*/
@Mapper
public interface BrokerageWithdrawConvert {
BrokerageWithdrawConvert INSTANCE = Mappers.getMapper(BrokerageWithdrawConvert.class);
BrokerageWithdrawDO convert(BrokerageWithdrawAuditReqVO bean);
BrokerageWithdrawRespVO convert(BrokerageWithdrawDO bean);
List<BrokerageWithdrawRespVO> convertList(List<BrokerageWithdrawDO> list);
PageResult<BrokerageWithdrawRespVO> convertPage(PageResult<BrokerageWithdrawDO> page);
default PageResult<BrokerageWithdrawRespVO> convertPage(PageResult<BrokerageWithdrawDO> pageResult, Map<Long, MemberUserRespDTO> userMap) {
PageResult<BrokerageWithdrawRespVO> result = convertPage(pageResult);
for (BrokerageWithdrawRespVO vo : result.getList()) {
vo.setUserNickname(Optional.ofNullable(userMap.get(vo.getUserId())).map(MemberUserRespDTO::getNickname).orElse(""));
}
return result;
}
}

View File

@@ -0,0 +1,94 @@
package cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.withdraw;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.time.LocalDateTime;
/**
* 佣金提现 DO
*
* @author 芋道源码
*/
@TableName("trade_brokerage_withdraw")
@KeySequence("trade_brokerage_withdraw_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BrokerageWithdrawDO extends BaseDO {
/**
* 编号
*/
@TableId
private Integer id;
/**
* 用户编号
*/
private Long userId;
/**
* 提现金额
*/
private Integer price;
/**
* 提现手续费
*/
private Integer feePrice;
/**
* 当前总佣金
*/
private Integer totalPrice;
/**
* 提现类型
* <p>
* 枚举 {@link BrokerageWithdrawTypeEnum}
*/
private Integer type;
/**
* 真实姓名
*/
private String name;
/**
* 账号
*/
private String accountNo;
/**
* 银行名称
*/
private String bankName;
/**
* 开户地址
*/
private String bankAddress;
/**
* 收款码
*/
private String accountQrCodeUrl;
/**
* 状态
* <p>
* 枚举 {@link BrokerageWithdrawStatusEnum}
*/
private Integer status;
/**
* 审核驳回原因
*/
private String auditReason;
/**
* 审核时间
*/
private LocalDateTime auditTime;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,36 @@
package cn.iocoder.yudao.module.trade.dal.mysql.brokerage.withdraw;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawPageReqVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.withdraw.BrokerageWithdrawDO;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper;
/**
* 佣金提现 Mapper
*
* @author 芋道源码
*/
@Mapper
public interface BrokerageWithdrawMapper extends BaseMapperX<BrokerageWithdrawDO> {
default PageResult<BrokerageWithdrawDO> selectPage(BrokerageWithdrawPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageWithdrawDO>()
.eqIfPresent(BrokerageWithdrawDO::getUserId, reqVO.getUserId())
.eqIfPresent(BrokerageWithdrawDO::getType, reqVO.getType())
.likeIfPresent(BrokerageWithdrawDO::getName, reqVO.getName())
.eqIfPresent(BrokerageWithdrawDO::getAccountNo, reqVO.getAccountNo())
.likeIfPresent(BrokerageWithdrawDO::getBankName, reqVO.getBankName())
.eqIfPresent(BrokerageWithdrawDO::getStatus, reqVO.getStatus())
.betweenIfPresent(BrokerageWithdrawDO::getCreateTime, reqVO.getCreateTime())
.orderByAsc(BrokerageWithdrawDO::getStatus).orderByDesc(BrokerageWithdrawDO::getId));
}
default int updateByIdAndStatus(Integer id, Integer status, BrokerageWithdrawDO updateObj) {
return update(updateObj, new LambdaUpdateWrapper<BrokerageWithdrawDO>()
.eq(BrokerageWithdrawDO::getId, id)
.eq(BrokerageWithdrawDO::getStatus, status));
}
}

View File

@@ -0,0 +1,51 @@
package cn.iocoder.yudao.module.trade.service.brokerage.withdraw;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawPageReqVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.withdraw.BrokerageWithdrawDO;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum;
import java.util.Collection;
import java.util.List;
/**
* 佣金提现 Service 接口
*
* @author 芋道源码
*/
public interface BrokerageWithdrawService {
/**
* 审核佣金提现
*
* @param id 佣金编号
* @param status 审核状态
* @param auditReason 驳回原因
*/
void auditBrokerageWithdraw(Integer id, BrokerageWithdrawStatusEnum status, String auditReason);
/**
* 获得佣金提现
*
* @param id 编号
* @return 佣金提现
*/
BrokerageWithdrawDO getBrokerageWithdraw(Integer id);
/**
* 获得佣金提现列表
*
* @param ids 编号
* @return 佣金提现列表
*/
List<BrokerageWithdrawDO> getBrokerageWithdrawList(Collection<Integer> ids);
/**
* 获得佣金提现分页
*
* @param pageReqVO 分页查询
* @return 佣金提现分页
*/
PageResult<BrokerageWithdrawDO> getBrokerageWithdrawPage(BrokerageWithdrawPageReqVO pageReqVO);
}

View File

@@ -0,0 +1,116 @@
package cn.iocoder.yudao.module.trade.service.brokerage.withdraw;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawPageReqVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.withdraw.BrokerageWithdrawDO;
import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.withdraw.BrokerageWithdrawMapper;
import cn.iocoder.yudao.module.trade.enums.MessageTemplateConstants;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum;
import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.BROKERAGE_WITHDRAW_NOT_EXISTS;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.BROKERAGE_WITHDRAW_STATUS_NOT_AUDITING;
/**
* 佣金提现 Service 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
@Resource
private BrokerageWithdrawMapper brokerageWithdrawMapper;
@Resource
private BrokerageRecordService brokerageRecordService;
@Resource
private NotifyMessageSendApi notifyMessageSendApi;
@Override
@Transactional(rollbackFor = Exception.class)
public void auditBrokerageWithdraw(Integer id, BrokerageWithdrawStatusEnum status, String auditReason) {
// 校验存在
BrokerageWithdrawDO withdrawDO = validateBrokerageWithdrawExists(id);
// 校验状态为审核中
if (!BrokerageWithdrawStatusEnum.AUDITING.getStatus().equals(withdrawDO.getStatus())) {
throw exception(BROKERAGE_WITHDRAW_STATUS_NOT_AUDITING);
}
// 更新
BrokerageWithdrawDO updateObj = new BrokerageWithdrawDO()
.setStatus(status.getStatus())
.setAuditReason(auditReason)
.setAuditTime(LocalDateTime.now());
int rows = brokerageWithdrawMapper.updateByIdAndStatus(id, BrokerageWithdrawStatusEnum.AUDITING.getStatus(), updateObj);
if (rows == 0) {
throw exception(BROKERAGE_WITHDRAW_STATUS_NOT_AUDITING);
}
// 驳回时需要退还用户佣金
String templateCode = MessageTemplateConstants.BROKERAGE_WITHDRAW_AUDIT_APPROVE;
if (BrokerageWithdrawStatusEnum.AUDIT_FAIL.equals(status)) {
templateCode = MessageTemplateConstants.BROKERAGE_WITHDRAW_AUDIT_REJECT;
// todo @owen
// brokerageRecordService.addBrokerage(withdrawDO.getUserId(), BrokerageRecordBizTypeEnum.WITHDRAW, withdrawDO.getPrice(), "");
}
// 通知用户
Map<String, Object> templateParams = MapUtil.<String, Object>builder()
.put("createTime", LocalDateTimeUtil.formatNormal(withdrawDO.getCreateTime()))
.put("price", String.format("%.2f", withdrawDO.getPrice() / 100d))
.put("reason", withdrawDO.getAuditReason())
.build();
NotifySendSingleToUserReqDTO reqDTO = new NotifySendSingleToUserReqDTO()
.setUserId(withdrawDO.getUserId())
.setTemplateCode(templateCode).setTemplateParams(templateParams);
notifyMessageSendApi.sendSingleMessageToMember(reqDTO);
}
private BrokerageWithdrawDO validateBrokerageWithdrawExists(Integer id) {
BrokerageWithdrawDO withdrawDO = brokerageWithdrawMapper.selectById(id);
if (withdrawDO == null) {
throw exception(BROKERAGE_WITHDRAW_NOT_EXISTS);
}
return withdrawDO;
}
@Override
public BrokerageWithdrawDO getBrokerageWithdraw(Integer id) {
return brokerageWithdrawMapper.selectById(id);
}
@Override
public List<BrokerageWithdrawDO> getBrokerageWithdrawList(Collection<Integer> ids) {
if (CollUtil.isEmpty(ids)) {
return ListUtil.empty();
}
return brokerageWithdrawMapper.selectBatchIds(ids);
}
@Override
public PageResult<BrokerageWithdrawDO> getBrokerageWithdrawPage(BrokerageWithdrawPageReqVO pageReqVO) {
return brokerageWithdrawMapper.selectPage(pageReqVO);
}
}