feat:礼物提现
This commit is contained in:
1 parent
b6373210c8
commit
557b7d637e
24 files changed
+1234
-4
No files matched your search
@@ -293,4 +293,29 @@ CREATE TABLE `pay_wallet_user_transition`
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 32 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '钱包(用户之间的相互转账、赠送)';
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 32 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '钱包(用户之间的相互转账、赠送)';
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for pay_wallet_tx_auth
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `pay_wallet_tx_auth`;
|
||||
CREATE TABLE `pay_wallet_tx_auth`
|
||||
(
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '钱包提现',
|
||||
`user_id` bigint NOT NULL COMMENT '用户id',
|
||||
`wallet_id` bigint NOT NULL COMMENT '钱包id',
|
||||
`biz_type` varchar(36) NOT NULL COMMENT '提现类型',
|
||||
`biz_id` bigint DEFAULT NULL COMMENT '提现类型绑定id',
|
||||
`tx_price` int NOT NULL COMMENT '提现金额',
|
||||
`title` varchar(256) DEFAULT NULL COMMENT '提现title',
|
||||
`check_status` varchar(36) NOT NULL COMMENT '提现状态',
|
||||
`check_time` datetime DEFAULT NULL COMMENT '审核时间',
|
||||
`tx_refuse` varchar(256) DEFAULT NULL COMMENT '提现拒绝信息',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 32 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '提现金额审核';
|
||||
+9
@@ -1,6 +1,7 @@
|
||||
package cn.iocoder.yudao.module.trade.api.brokerage;
|
||||
|
||||
import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageAddDTO;
|
||||
import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageWechatTransferDTO;
|
||||
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
|
||||
|
||||
import javax.validation.Valid;
|
||||
@@ -13,10 +14,18 @@ public interface TradeBrokerageRecordApi {
|
||||
|
||||
/**
|
||||
* 增加佣金【多级分佣】
|
||||
*
|
||||
* @param userId 会员编号
|
||||
* @param bizType 业务类型
|
||||
* @param list 请求参数列表
|
||||
*/
|
||||
void addBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, @Valid List<BrokerageAddDTO> list);
|
||||
|
||||
/**
|
||||
* 微信转账
|
||||
* @param id 提现单id
|
||||
* @param userId 会员id
|
||||
* @param price 金额(分)
|
||||
*/
|
||||
BrokerageWechatTransferDTO wechatTransfer(Long id, Long userId, Integer price);
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package cn.iocoder.yudao.module.trade.api.brokerage.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class BrokerageWechatTransferDTO {
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
// ========== 其它字段 ==========
|
||||
|
||||
/**
|
||||
* 渠道 package 信息
|
||||
* <p>
|
||||
* 特殊:目前只有微信转账有这个东西!!!
|
||||
*
|
||||
* @see <a href="https://pay.weixin.qq.com/doc/v3/merchant/4012716430">JSAPI 调起用户确认收款</a>
|
||||
*/
|
||||
private String channelPackageInfo;
|
||||
}
|
||||
+65
-1
@@ -1,25 +1,89 @@
|
||||
package cn.iocoder.yudao.module.trade.api.brokerage;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.pay.api.refund.dto.PayTransferCreateRespDTO;
|
||||
import cn.iocoder.yudao.module.pay.api.transfer.PayTransferApi;
|
||||
import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO;
|
||||
import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum;
|
||||
import cn.iocoder.yudao.module.system.api.social.SocialUserApi;
|
||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
|
||||
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
|
||||
import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageAddDTO;
|
||||
import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageWechatTransferDTO;
|
||||
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageWithdrawDO;
|
||||
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
|
||||
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
|
||||
import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageRecordService;
|
||||
import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
|
||||
|
||||
@Service
|
||||
@Validated
|
||||
public class TradeBrokerageRecordApiImpl implements TradeBrokerageRecordApi {
|
||||
|
||||
@Resource
|
||||
private TradeOrderProperties tradeOrderProperties;
|
||||
|
||||
@Resource
|
||||
private BrokerageRecordService brokerageRecordService;
|
||||
|
||||
@Resource
|
||||
private SocialUserApi socialUserApi;
|
||||
@Resource
|
||||
private PayTransferApi payTransferApi;
|
||||
|
||||
@Override
|
||||
public void addBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, List<BrokerageAddDTO> list) {
|
||||
brokerageRecordService.addBrokerage(userId, bizType, BeanUtils.toBean(list, BrokerageAddReqBO.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信转账
|
||||
*
|
||||
* @param id 提现单id
|
||||
* @param userId 会员id
|
||||
* @param price 金额(分)
|
||||
*/
|
||||
@Override
|
||||
public BrokerageWechatTransferDTO wechatTransfer(Long id, Long userId, Integer price) {
|
||||
// 1.1 获取微信 openid
|
||||
SocialUserRespDTO socialUser = socialUserApi.getSocialUserByUserId(UserTypeEnum.MEMBER.getValue(), userId, SocialTypeEnum.WECHAT_MINI_APP.getType());
|
||||
if (ObjectUtil.isEmpty(socialUser)) return null;
|
||||
// 1.2 构建请求
|
||||
Map<String, String> channelExtras = new HashMap<>();
|
||||
List<Map<String, String>> sceneReportInfos = new ArrayList<>();
|
||||
sceneReportInfos.add(new LinkedHashMap<String, String>() {{
|
||||
put("infoType", "岗位类型");
|
||||
put("infoContent", "分销员");
|
||||
}});
|
||||
sceneReportInfos.add(new LinkedHashMap<String, String>() {{
|
||||
put("infoType", "报酬说明");
|
||||
put("infoContent", "邀请新用户有礼,提现" + MoneyUtils.fenToYuanStr(price) + "元");
|
||||
}});
|
||||
channelExtras.put("sceneId", "1005");
|
||||
channelExtras.put("sceneReportInfos", JSONUtil.toJsonStr(sceneReportInfos));
|
||||
PayTransferCreateReqDTO payTransferCreateReqDTO = new PayTransferCreateReqDTO()
|
||||
.setAppKey(tradeOrderProperties.getPayAppKey())
|
||||
.setChannelCode("wx_lite")
|
||||
.setType(PayTransferTypeEnum.WX_BALANCE.getType())
|
||||
.setMerchantTransferId(String.valueOf(id))
|
||||
.setPrice(price)
|
||||
.setSubject("佣金报酬")
|
||||
.setOpenid(socialUser.getOpenid())
|
||||
.setUserIp(getClientIP())
|
||||
.setChannelExtras(channelExtras);
|
||||
// 2. 发起请求
|
||||
PayTransferCreateRespDTO transfer = payTransferApi.createTransfer(payTransferCreateReqDTO);
|
||||
return BeanUtils.toBean(transfer, BrokerageWechatTransferDTO.class);
|
||||
}
|
||||
}
|
||||
+47
@@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.member.api.config.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户信息 Response DTO
|
||||
*
|
||||
@@ -14,19 +16,64 @@ public class MemberConfigRespDTO {
|
||||
* 积分抵扣开关
|
||||
*/
|
||||
private Boolean pointTradeDeductEnable;
|
||||
|
||||
/**
|
||||
* 积分抵扣,单位:分
|
||||
* <p>
|
||||
* 1 积分抵扣多少分
|
||||
*/
|
||||
private Integer pointTradeDeductUnitPrice;
|
||||
|
||||
/**
|
||||
* 积分抵扣最大值
|
||||
*/
|
||||
private Integer pointTradeDeductMaxPrice;
|
||||
|
||||
/**
|
||||
* 1 元赠送多少分
|
||||
*/
|
||||
private Integer pointTradeGivePoint;
|
||||
|
||||
/**
|
||||
* 普通用户每天可以和几个人聊天
|
||||
*/
|
||||
private Integer defaultChatUserCout;
|
||||
|
||||
/**
|
||||
* 普通用户每天可以和人发几次消息
|
||||
*/
|
||||
private Integer defaultChatUserMsgCout;
|
||||
|
||||
/**
|
||||
* vip用户每天可以和几个人聊天
|
||||
*/
|
||||
private Integer vipChatUserCout;
|
||||
|
||||
/**
|
||||
* vip用户每天可以和人发几次消息
|
||||
*/
|
||||
private Integer vipChatUserMsgCout;
|
||||
|
||||
/**
|
||||
* vip查看微信次数
|
||||
*/
|
||||
private Integer vipLookWechtCout;
|
||||
|
||||
/**
|
||||
* 礼物提现比例
|
||||
* `giftCashRatio`可以兑换1人民币
|
||||
*/
|
||||
private Integer giftCashRatio;
|
||||
|
||||
/**
|
||||
* 新人入驻天数判断
|
||||
* 入驻未满`newPersonDays`都是新人用户
|
||||
*/
|
||||
private Integer newPersonDays;
|
||||
|
||||
/**
|
||||
* 举报类型
|
||||
*/
|
||||
private List<String> reportTypeList;
|
||||
|
||||
}
|
||||
+2
@@ -17,6 +17,7 @@ import cn.iocoder.yudao.module.member.service.opentype.BO.OpenTypeExtBO;
|
||||
import cn.iocoder.yudao.module.member.service.opentype.OpenTypeService;
|
||||
import cn.iocoder.yudao.module.member.service.user.BO.MemberTagExtBO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.security.core.parameters.P;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -39,6 +40,7 @@ public class MemberRecentTagServiceImp implements MemberRecentTagService {
|
||||
private MemberRecentTagMapper memberRecentTagMapper;
|
||||
|
||||
@Resource
|
||||
@Lazy
|
||||
private OpenTypeService openTypeService;
|
||||
@Resource
|
||||
private MemberConfigService memberConfigService;
|
||||
|
||||
+3
@@ -9,6 +9,8 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
||||
*/
|
||||
public interface ErrorCodeConstants {
|
||||
|
||||
ErrorCode EMPTY = new ErrorCode(1_007_999_999, "{}");
|
||||
|
||||
// ========== APP 模块 1-007-000-000 ==========
|
||||
ErrorCode APP_NOT_FOUND = new ErrorCode(1_007_000_000, "App 不存在");
|
||||
ErrorCode APP_IS_DISABLE = new ErrorCode(1_007_000_002, "App 已经被禁用");
|
||||
@@ -79,6 +81,7 @@ public interface ErrorCodeConstants {
|
||||
// ========== 钱包用户转账模块 1-007-010-000 ==========
|
||||
ErrorCode WALLET_USER_TRANSFER_NOT_FOUND = new ErrorCode(1_007_010_000, "用户转账单不存在");
|
||||
ErrorCode WALLET_USER_TRANSFER_NOT_SELF = new ErrorCode(1_007_010_001, "自己不能给自己送出礼物");
|
||||
ErrorCode WALLET_TX_AUTH_NOT_EXISTS = new ErrorCode(1_007_010_002, "用户申请提现记录不存在");
|
||||
|
||||
// ========== 示例订单 1-007-900-000 ==========
|
||||
ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1_007_900_000, "示例订单不存在");
|
||||
|
||||
+1
@@ -23,6 +23,7 @@ public enum PayWalletBizTypeEnum implements ArrayValuable<Integer> {
|
||||
BROKERAGE_WITHDRAW(6, "分佣提现"),
|
||||
GIFT(7, "送礼物"),
|
||||
RECEIVE_GIFT(8, "收到礼物"),
|
||||
RECEIVE_GIFT_TX(9, "礼物提现"),
|
||||
;
|
||||
|
||||
/**
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package cn.iocoder.yudao.module.pay.enums.wallet;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 钱包提现业务类型
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum PayWalletTxAuthBizTypeEnum implements ArrayValuable<String> {
|
||||
|
||||
GIFT_TX_AUTH("1", "礼物提现审核"),
|
||||
;
|
||||
|
||||
/**
|
||||
* 业务分类
|
||||
*/
|
||||
private final String type;
|
||||
/**
|
||||
* 说明
|
||||
*/
|
||||
private final String description;
|
||||
|
||||
public static final String[] ARRAYS = Arrays.stream(values()).map(PayWalletTxAuthBizTypeEnum::getType).toArray(String[]::new);
|
||||
|
||||
@Override
|
||||
public String[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
public static PayWalletTxAuthBizTypeEnum valueByTypeOf(String type) {
|
||||
return Arrays.stream(values()).filter(item -> item.getType().equals(type)).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package cn.iocoder.yudao.module.pay.enums.wallet;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 钱包提现审核状态
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum PayWalletTxAuthStatusEnum implements ArrayValuable<String> {
|
||||
|
||||
TX_AUTH_AWAIT("1", "待审核"),
|
||||
AUTH_SUCCESS("2", "审核通过"),
|
||||
AUTH_FAIL("3", "审核不通过"),
|
||||
AUTH_TX_SUCCESS("4", "已提现"),
|
||||
AUTH_TX_ERROR("5", "提现失败"),
|
||||
;
|
||||
|
||||
/**
|
||||
* 业务分类
|
||||
*/
|
||||
private final String type;
|
||||
/**
|
||||
* 说明
|
||||
*/
|
||||
private final String description;
|
||||
|
||||
public static final String[] ARRAYS = Arrays.stream(values()).map(PayWalletTxAuthStatusEnum::getType).toArray(String[]::new);
|
||||
|
||||
@Override
|
||||
public String[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
public static PayWalletTxAuthStatusEnum valueOfByType(String type) {
|
||||
return Arrays.stream(values()).filter(item -> item.getType().equals(type)).findFirst().orElse(null);
|
||||
}
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
package cn.iocoder.yudao.module.pay.controller.admin.wallet;
|
||||
|
||||
import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO;
|
||||
import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.txauth.WalletTxAuthCheckReqVO;
|
||||
import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.txauth.WalletTxAuthPageReqVO;
|
||||
import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.txauth.WalletTxAuthRespVO;
|
||||
import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.txauth.WalletTxAuthSaveReqVO;
|
||||
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.WalletTxAuthDO;
|
||||
import cn.iocoder.yudao.module.pay.service.wallet.WalletTxAuthService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
||||
import javax.annotation.security.PermitAll;
|
||||
import javax.validation.constraints.*;
|
||||
import javax.validation.*;
|
||||
import javax.servlet.http.*;
|
||||
import java.util.*;
|
||||
import java.io.IOException;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
||||
|
||||
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
|
||||
|
||||
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
|
||||
|
||||
@Slf4j
|
||||
@Tag(name = "管理后台 - 提现金额审核")
|
||||
@RestController
|
||||
@RequestMapping("/pay/wallet-tx-auth")
|
||||
@Validated
|
||||
public class WalletTxAuthController {
|
||||
|
||||
@Resource
|
||||
private WalletTxAuthService walletTxAuthService;
|
||||
|
||||
@PostMapping("/check")
|
||||
@Operation(summary = "审核")
|
||||
public CommonResult<Boolean> check(@Valid @RequestBody WalletTxAuthCheckReqVO dto) {
|
||||
return success(walletTxAuthService.check(dto));
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建提现金额审核")
|
||||
@PreAuthorize("@ss.hasPermission('pay:wallet-tx-auth:create')")
|
||||
public CommonResult<Long> createWalletTxAuth(@Valid @RequestBody WalletTxAuthSaveReqVO createReqVO) {
|
||||
return success(walletTxAuthService.createWalletTxAuth(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新提现金额审核")
|
||||
@PreAuthorize("@ss.hasPermission('pay:wallet-tx-auth:update')")
|
||||
public CommonResult<Boolean> updateWalletTxAuth(@Valid @RequestBody WalletTxAuthSaveReqVO updateReqVO) {
|
||||
walletTxAuthService.updateWalletTxAuth(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除提现金额审核")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('pay:wallet-tx-auth:delete')")
|
||||
public CommonResult<Boolean> deleteWalletTxAuth(@RequestParam("id") Long id) {
|
||||
walletTxAuthService.deleteWalletTxAuth(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得提现金额审核")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('pay:wallet-tx-auth:query')")
|
||||
public CommonResult<WalletTxAuthRespVO> getWalletTxAuth(@RequestParam("id") Long id) {
|
||||
WalletTxAuthDO walletTxAuth = walletTxAuthService.getWalletTxAuth(id);
|
||||
return success(BeanUtils.toBean(walletTxAuth, WalletTxAuthRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得提现金额审核分页")
|
||||
@PreAuthorize("@ss.hasPermission('pay:wallet-tx-auth:query')")
|
||||
public CommonResult<PageResult<WalletTxAuthRespVO>> getWalletTxAuthPage(@Valid WalletTxAuthPageReqVO pageReqVO) {
|
||||
PageResult<WalletTxAuthRespVO> pageResult = walletTxAuthService.getWalletTxAuthPage(pageReqVO);
|
||||
return success(pageResult);
|
||||
}
|
||||
|
||||
@GetMapping("/export-excel")
|
||||
@Operation(summary = "导出提现金额审核 Excel")
|
||||
@PreAuthorize("@ss.hasPermission('pay:wallet-tx-auth:export')")
|
||||
@ApiAccessLog(operateType = EXPORT)
|
||||
public void exportWalletTxAuthExcel(@Valid WalletTxAuthPageReqVO pageReqVO, HttpServletResponse response) throws IOException {
|
||||
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
||||
List<WalletTxAuthRespVO> list = walletTxAuthService.getWalletTxAuthPage(pageReqVO).getList();
|
||||
// 导出 Excel
|
||||
ExcelUtils.write(response, "提现金额审核.xls", "数据", WalletTxAuthRespVO.class, list);
|
||||
}
|
||||
|
||||
@PostMapping("/update-transfer")
|
||||
@Operation(summary = "更新转账记录(回调)")
|
||||
@PermitAll
|
||||
public CommonResult<Boolean> updateTransfer(@RequestBody PayRefundNotifyReqDTO notifyReqDTO) {
|
||||
log.info("[updateTransfer][notifyReqDTO({})]", notifyReqDTO);
|
||||
walletTxAuthService.updateTransfer(notifyReqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.txauth;
|
||||
|
||||
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 WalletTxAuthCheckReqVO {
|
||||
|
||||
@Schema(description = "提现id")
|
||||
@NotNull(message = "提现id不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "审核状态")
|
||||
@NotEmpty(message = "审核状态不能为空")
|
||||
private String checkStatus;
|
||||
|
||||
@Schema(description = "拒绝信息")
|
||||
private String txRefuse;
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.txauth;
|
||||
|
||||
import lombok.*;
|
||||
import java.util.*;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
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 WalletTxAuthPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "用户id", example = "22189")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "钱包id", example = "25463")
|
||||
private Long walletId;
|
||||
|
||||
@Schema(description = "提现类型", example = "1")
|
||||
private String bizType;
|
||||
|
||||
@Schema(description = "提现类型绑定id", example = "25829")
|
||||
private Long bizId;
|
||||
|
||||
@Schema(description = "提现金额", example = "18586")
|
||||
private Integer txPrice;
|
||||
|
||||
@Schema(description = "提现title")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "提现状态", example = "2")
|
||||
private String checkStatus;
|
||||
|
||||
@Schema(description = "审核时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] checkTime;
|
||||
|
||||
@Schema(description = "提现拒绝信息")
|
||||
private String txRefuse;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.txauth;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.alibaba.excel.annotation.*;
|
||||
|
||||
@Schema(description = "管理后台 - 提现金额审核 Response VO")
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class WalletTxAuthRespVO {
|
||||
|
||||
@Schema(description = "钱包提现", requiredMode = Schema.RequiredMode.REQUIRED, example = "30337")
|
||||
@ExcelProperty("钱包提现")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "用户id", requiredMode = Schema.RequiredMode.REQUIRED, example = "22189")
|
||||
@ExcelProperty("用户id")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "钱包id", requiredMode = Schema.RequiredMode.REQUIRED, example = "25463")
|
||||
@ExcelProperty("钱包id")
|
||||
private Long walletId;
|
||||
|
||||
@Schema(description = "提现类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@ExcelProperty("提现类型")
|
||||
private String bizType;
|
||||
|
||||
@Schema(description = "提现类型绑定id", example = "25829")
|
||||
@ExcelProperty("提现类型绑定id")
|
||||
private Long bizId;
|
||||
|
||||
@Schema(description = "提现金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "18586")
|
||||
@ExcelProperty("提现金额")
|
||||
private Integer txPrice;
|
||||
|
||||
@Schema(description = "提现title")
|
||||
@ExcelProperty("提现title")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "提现状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
@ExcelProperty("提现状态")
|
||||
private String checkStatus;
|
||||
|
||||
@Schema(description = "审核时间")
|
||||
@ExcelProperty("审核时间")
|
||||
private LocalDateTime checkTime;
|
||||
|
||||
@Schema(description = "提现拒绝信息")
|
||||
@ExcelProperty("提现拒绝信息")
|
||||
private String txRefuse;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 用户相关
|
||||
*/
|
||||
@Schema(description = "用户昵称")
|
||||
private String memberNickname;
|
||||
|
||||
@Schema(description = "用户头像")
|
||||
private String memberAvatar;
|
||||
|
||||
@Schema(description = "用户手机")
|
||||
private String memberMobile;
|
||||
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.txauth;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.*;
|
||||
import java.util.*;
|
||||
import javax.validation.constraints.*;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 提现金额审核新增/修改 Request VO")
|
||||
@Data
|
||||
public class WalletTxAuthSaveReqVO {
|
||||
|
||||
@Schema(description = "钱包提现", requiredMode = Schema.RequiredMode.REQUIRED, example = "30337")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "用户id", requiredMode = Schema.RequiredMode.REQUIRED, example = "22189")
|
||||
@NotNull(message = "用户id不能为空")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "钱包id", requiredMode = Schema.RequiredMode.REQUIRED, example = "25463")
|
||||
@NotNull(message = "钱包id不能为空")
|
||||
private Long walletId;
|
||||
|
||||
@Schema(description = "提现类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotEmpty(message = "提现类型不能为空")
|
||||
private String bizType;
|
||||
|
||||
@Schema(description = "提现类型绑定id", example = "25829")
|
||||
private Long bizId;
|
||||
|
||||
@Schema(description = "提现金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "18586")
|
||||
@NotNull(message = "提现金额不能为空")
|
||||
private Integer txPrice;
|
||||
|
||||
@Schema(description = "提现title")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "提现状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
@NotEmpty(message = "提现状态不能为空")
|
||||
private String checkStatus;
|
||||
|
||||
@Schema(description = "审核时间")
|
||||
private LocalDateTime checkTime;
|
||||
|
||||
@Schema(description = "提现拒绝信息")
|
||||
private String txRefuse;
|
||||
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package cn.iocoder.yudao.module.pay.controller.app.wallet;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent;
|
||||
import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.UserIdempotentKeyResolver;
|
||||
import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.txauth.WalletTxAuthPageReqVO;
|
||||
import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.txauth.WalletTxAuthRespVO;
|
||||
import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.txauth.AppWalletTxAuthGiftApplyReqVo;
|
||||
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.WalletTxAuthDO;
|
||||
import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletTxAuthBizTypeEnum;
|
||||
import cn.iocoder.yudao.module.pay.service.wallet.WalletTxAuthService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
|
||||
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserType;
|
||||
|
||||
@Tag(name = "用户 APP - 提现金额审核")
|
||||
@RestController
|
||||
@RequestMapping("/pay/wallet-tx-auth")
|
||||
@Validated
|
||||
public class AppWalletTxAuthController {
|
||||
|
||||
@Resource
|
||||
private WalletTxAuthService walletTxAuthService;
|
||||
|
||||
@PostMapping("/gift/apply")
|
||||
@Operation(summary = "礼物申请提现")
|
||||
@Idempotent(timeout = 3, timeUnit = TimeUnit.SECONDS, keyResolver = UserIdempotentKeyResolver.class, message = "正在提现中,请稍后重试")
|
||||
public CommonResult<Long> apply(@RequestBody AppWalletTxAuthGiftApplyReqVo dto) {
|
||||
dto.setUserId(getLoginUserId());
|
||||
dto.setUserType(getLoginUserType());
|
||||
return success(walletTxAuthService.giftApply(dto));
|
||||
}
|
||||
|
||||
@GetMapping("/detail")
|
||||
@Operation(summary = "获取提现金额审核详情")
|
||||
public CommonResult<WalletTxAuthDO> detail(@RequestParam("id") Long id) {
|
||||
return success(walletTxAuthService.getWalletTxAuth(id));
|
||||
}
|
||||
|
||||
@GetMapping("/gift/page")
|
||||
@Operation(summary = "礼物提现记录")
|
||||
public CommonResult<PageResult<WalletTxAuthRespVO>> getWalletTxAuthPage(@Valid WalletTxAuthPageReqVO pageReqVO) {
|
||||
pageReqVO.setUserId(getLoginUserId());
|
||||
pageReqVO.setBizType(PayWalletTxAuthBizTypeEnum.GIFT_TX_AUTH.getType());
|
||||
PageResult<WalletTxAuthRespVO> pageResult = walletTxAuthService.getWalletTxAuthPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, WalletTxAuthRespVO.class));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package cn.iocoder.yudao.module.pay.controller.app.wallet.vo.txauth;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Schema(description = "用户 APP - 用户申请礼物提现")
|
||||
@Data
|
||||
public class AppWalletTxAuthGiftApplyReqVo {
|
||||
|
||||
@Schema(description = "用户id")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "用户类型")
|
||||
private Integer userType;
|
||||
|
||||
@Schema(description = "礼物金额")
|
||||
@NotNull(message = "礼物金额不能为空")
|
||||
private Integer giftPrice;
|
||||
|
||||
@Schema(description = "微信号")
|
||||
@NotEmpty(message = "微信号不能为空")
|
||||
private String wechatNum;
|
||||
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
package cn.iocoder.yudao.module.pay.dal.dataobject.wallet;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
|
||||
/**
|
||||
* 提现金额审核 DO
|
||||
*/
|
||||
@TableName("pay_wallet_tx_auth")
|
||||
@KeySequence("pay_wallet_tx_auth_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class WalletTxAuthDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 钱包提现
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 钱包id
|
||||
*/
|
||||
private Long walletId;
|
||||
|
||||
/**
|
||||
* 提现类型
|
||||
*/
|
||||
private String bizType;
|
||||
|
||||
/**
|
||||
* 提现类型绑定id
|
||||
*/
|
||||
private Long bizId;
|
||||
|
||||
/**
|
||||
* 提现缘都金额
|
||||
*/
|
||||
private Integer txYdPrice;
|
||||
|
||||
/**
|
||||
* 提现金额
|
||||
*/
|
||||
private Integer txPrice;
|
||||
|
||||
/**
|
||||
* 提现title
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 提现状态
|
||||
*/
|
||||
private String checkStatus;
|
||||
|
||||
/**
|
||||
* 审核时间
|
||||
*/
|
||||
private LocalDateTime checkTime;
|
||||
|
||||
/**
|
||||
* 提现拒绝信息
|
||||
*/
|
||||
private String txRefuse;
|
||||
|
||||
/**
|
||||
* 提现转账信息
|
||||
*/
|
||||
private Long payTransferId;
|
||||
|
||||
/**
|
||||
* 渠道商户编号
|
||||
*/
|
||||
private String channelMchId;
|
||||
|
||||
/**
|
||||
* 渠道 package 信息
|
||||
*/
|
||||
private String channelPackageInfo;
|
||||
|
||||
/**
|
||||
* 到账时间
|
||||
*/
|
||||
private LocalDateTime dzTime;
|
||||
|
||||
}
|
||||
+42
@@ -140,6 +140,48 @@ public interface PayWalletMapper extends BaseMapperX<PayWalletDO> {
|
||||
update(null, lambdaUpdateWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当消费(提现)时候,更新钱包(礼物)
|
||||
*/
|
||||
default int updateWhenGiftConsumption(Long id, Integer price) {
|
||||
LambdaUpdateWrapper<PayWalletDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<PayWalletDO>()
|
||||
.setSql(" gift_balance = gift_balance - " + price
|
||||
+ ", gift_total_expense = gift_total_expense + " + price)
|
||||
.eq(PayWalletDO::getId, id)
|
||||
.ge(PayWalletDO::getGiftBalance, price); // cas 逻辑
|
||||
return update(null, lambdaUpdateWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 冻结钱包部分余额(礼物金额)
|
||||
*
|
||||
* @param id 钱包 id
|
||||
* @param price 冻结金额
|
||||
*/
|
||||
default int freezeGiftPrice(Long id, Integer price) {
|
||||
LambdaUpdateWrapper<PayWalletDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<PayWalletDO>()
|
||||
.setSql(" gift_balance = gift_balance - " + price
|
||||
+ ", gift_freeze_price = gift_freeze_price + " + price)
|
||||
.eq(PayWalletDO::getId, id)
|
||||
.ge(PayWalletDO::getGiftBalance, price); // cas 逻辑
|
||||
return update(null, lambdaUpdateWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解冻钱包余额(礼物金额)
|
||||
*
|
||||
* @param id 钱包 id
|
||||
* @param price 解冻金额
|
||||
*/
|
||||
default int unfreezeGiftPrice(Long id, Integer price) {
|
||||
LambdaUpdateWrapper<PayWalletDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<PayWalletDO>()
|
||||
.setSql(" gift_balance = gift_balance + " + price
|
||||
+ ", gift_freeze_price = gift_freeze_price - " + price)
|
||||
.eq(PayWalletDO::getId, id)
|
||||
.ge(PayWalletDO::getGiftFreezePrice, price); // cas 逻辑
|
||||
return update(null, lambdaUpdateWrapper);
|
||||
}
|
||||
|
||||
|
||||
/* *************************************** end 礼物相关 end *************************************** */
|
||||
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package cn.iocoder.yudao.module.pay.dal.mysql.wallet;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.txauth.WalletTxAuthPageReqVO;
|
||||
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.WalletTxAuthDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 提现金额审核 Mapper
|
||||
*/
|
||||
@Mapper
|
||||
public interface WalletTxAuthMapper extends BaseMapperX<WalletTxAuthDO> {
|
||||
|
||||
default PageResult<WalletTxAuthDO> selectPage(WalletTxAuthPageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<WalletTxAuthDO>()
|
||||
.eqIfPresent(WalletTxAuthDO::getUserId, reqVO.getUserId())
|
||||
.eqIfPresent(WalletTxAuthDO::getWalletId, reqVO.getWalletId())
|
||||
.eqIfPresent(WalletTxAuthDO::getBizType, reqVO.getBizType())
|
||||
.eqIfPresent(WalletTxAuthDO::getBizId, reqVO.getBizId())
|
||||
.eqIfPresent(WalletTxAuthDO::getTxPrice, reqVO.getTxPrice())
|
||||
.eqIfPresent(WalletTxAuthDO::getTitle, reqVO.getTitle())
|
||||
.eqIfPresent(WalletTxAuthDO::getCheckStatus, reqVO.getCheckStatus())
|
||||
.betweenIfPresent(WalletTxAuthDO::getCheckTime, reqVO.getCheckTime())
|
||||
.eqIfPresent(WalletTxAuthDO::getTxRefuse, reqVO.getTxRefuse())
|
||||
.betweenIfPresent(WalletTxAuthDO::getCreateTime, reqVO.getCreateTime())
|
||||
.orderByDesc(WalletTxAuthDO::getId));
|
||||
}
|
||||
|
||||
}
|
||||
+23
-2
@@ -66,8 +66,13 @@ public interface PayWalletService {
|
||||
* @param price 扣减金额
|
||||
* @return 钱包流水
|
||||
*/
|
||||
PayWalletTransactionDO reduceWalletBalance(Long walletId, Long bizId,
|
||||
PayWalletBizTypeEnum bizType, Integer price);
|
||||
PayWalletTransactionDO reduceWalletBalance(Long walletId, Long bizId, PayWalletBizTypeEnum bizType, Integer price);
|
||||
|
||||
/**
|
||||
* 减少礼物钱包(提现)
|
||||
*/
|
||||
PayWalletTransactionDO reduceWalletGiftBalance(Long walletId, String bizId, PayWalletBizTypeEnum bizType, Integer price);
|
||||
|
||||
|
||||
/**
|
||||
* 增加钱包余额
|
||||
@@ -94,6 +99,14 @@ public interface PayWalletService {
|
||||
*/
|
||||
void freezePrice(Long id, Integer price);
|
||||
|
||||
/**
|
||||
* 冻结钱包部分余额(送礼物)
|
||||
*
|
||||
* @param id 钱包编号
|
||||
* @param price 冻结金额
|
||||
*/
|
||||
void freezeGiftPrice(Long id, Integer price);
|
||||
|
||||
/**
|
||||
* 解冻钱包余额
|
||||
*
|
||||
@@ -102,4 +115,12 @@ public interface PayWalletService {
|
||||
*/
|
||||
void unfreezePrice(Long id, Integer price);
|
||||
|
||||
/**
|
||||
* 解冻钱包余额(送礼物)
|
||||
*
|
||||
* @param id 钱包编号
|
||||
* @param price 解冻金额
|
||||
*/
|
||||
void unfreezeGiftPrice(Long id, Integer price);
|
||||
|
||||
}
|
||||
+53
@@ -249,6 +249,43 @@ public class PayWalletServiceImpl implements PayWalletService {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 减少礼物钱包(提现)
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@SneakyThrows
|
||||
public PayWalletTransactionDO reduceWalletGiftBalance(Long walletId, String bizId, PayWalletBizTypeEnum bizType, Integer price) {
|
||||
// 1. 获取钱包
|
||||
PayWalletDO payWallet = getWallet(walletId);
|
||||
if (payWallet == null) {
|
||||
log.error("[addWalletBalance][用户钱包({})不存在]", walletId);
|
||||
throw exception(WALLET_NOT_FOUND);
|
||||
}
|
||||
// 2. 加锁,更新钱包余额(目的:避免钱包流水的并发更新时,余额变化不连贯)
|
||||
return lockRedisDAO.lock(walletId, UPDATE_TIMEOUT_MILLIS, () -> {
|
||||
// 3. 更新钱包金额
|
||||
switch (bizType) {
|
||||
case RECEIVE_GIFT: // 收到礼物
|
||||
walletMapper.updateWhenGiftConsumption(payWallet.getId(), price);
|
||||
break;
|
||||
default: {
|
||||
throw new UnsupportedOperationException("待实现:" + bizType);
|
||||
}
|
||||
}
|
||||
// 4. 生成钱包流水
|
||||
Integer afterBalance = payWallet.getBalance() - price;
|
||||
WalletTransactionCreateReqBO transactionCreateReqBO = new WalletTransactionCreateReqBO()
|
||||
.setWalletId(payWallet.getId())
|
||||
.setPrice(-price)
|
||||
.setBalance(afterBalance)
|
||||
.setBizId(bizId)
|
||||
.setBizType(bizType.getType())
|
||||
.setTitle(bizType.getDescription());
|
||||
return walletTransactionService.createWalletTransaction(transactionCreateReqBO);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void freezePrice(Long id, Integer price) {
|
||||
int updateCounts = walletMapper.freezePrice(id, price);
|
||||
@@ -257,6 +294,14 @@ public class PayWalletServiceImpl implements PayWalletService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void freezeGiftPrice(Long id, Integer price) {
|
||||
int updateCounts = walletMapper.freezeGiftPrice(id, price);
|
||||
if (updateCounts == 0) {
|
||||
throw exception(WALLET_BALANCE_NOT_ENOUGH);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unfreezePrice(Long id, Integer price) {
|
||||
int updateCounts = walletMapper.unFreezePrice(id, price);
|
||||
@@ -265,4 +310,12 @@ public class PayWalletServiceImpl implements PayWalletService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unfreezeGiftPrice(Long id, Integer price) {
|
||||
int updateCounts = walletMapper.unfreezeGiftPrice(id, price);
|
||||
if (updateCounts == 0) {
|
||||
throw exception(WALLET_FREEZE_PRICE_NOT_ENOUGH);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package cn.iocoder.yudao.module.pay.service.wallet;
|
||||
|
||||
import java.util.*;
|
||||
import javax.validation.*;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO;
|
||||
import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.txauth.WalletTxAuthCheckReqVO;
|
||||
import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.txauth.WalletTxAuthPageReqVO;
|
||||
import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.txauth.WalletTxAuthRespVO;
|
||||
import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.txauth.WalletTxAuthSaveReqVO;
|
||||
import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.txauth.AppWalletTxAuthGiftApplyReqVo;
|
||||
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.WalletTxAuthDO;
|
||||
|
||||
/**
|
||||
* 提现金额审核 Service 接口
|
||||
*/
|
||||
public interface WalletTxAuthService {
|
||||
|
||||
/**
|
||||
* 更新转账记录(回调)
|
||||
*/
|
||||
void updateTransfer(PayRefundNotifyReqDTO notifyReqDTO);
|
||||
|
||||
/**
|
||||
* 礼物申请提现
|
||||
*/
|
||||
Long giftApply(@Valid AppWalletTxAuthGiftApplyReqVo dto);
|
||||
|
||||
/**
|
||||
* 审核
|
||||
*/
|
||||
Boolean check(@Valid WalletTxAuthCheckReqVO dto);
|
||||
|
||||
/**
|
||||
* 创建提现金额审核
|
||||
*/
|
||||
Long createWalletTxAuth(@Valid WalletTxAuthSaveReqVO createReqVO);
|
||||
|
||||
/**
|
||||
* 更新提现金额审核
|
||||
*/
|
||||
void updateWalletTxAuth(@Valid WalletTxAuthSaveReqVO updateReqVO);
|
||||
|
||||
/**
|
||||
* 删除提现金额审核
|
||||
*/
|
||||
void deleteWalletTxAuth(Long id);
|
||||
|
||||
/**
|
||||
* 获得提现金额审核
|
||||
*/
|
||||
WalletTxAuthDO getWalletTxAuth(Long id);
|
||||
|
||||
/**
|
||||
* 获得提现金额审核分页
|
||||
*/
|
||||
PageResult<WalletTxAuthRespVO> getWalletTxAuthPage(WalletTxAuthPageReqVO pageReqVO);
|
||||
}
|
||||
+260
@@ -0,0 +1,260 @@
|
||||
package cn.iocoder.yudao.module.pay.service.wallet;
|
||||
|
||||
import cn.hutool.core.collection.IterUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.member.api.config.MemberConfigApi;
|
||||
import cn.iocoder.yudao.module.member.api.config.dto.MemberConfigRespDTO;
|
||||
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
|
||||
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
|
||||
import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO;
|
||||
import cn.iocoder.yudao.module.pay.api.transfer.PayTransferApiImpl;
|
||||
import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferRespDTO;
|
||||
import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.txauth.WalletTxAuthCheckReqVO;
|
||||
import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.txauth.WalletTxAuthPageReqVO;
|
||||
import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.txauth.WalletTxAuthRespVO;
|
||||
import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.txauth.WalletTxAuthSaveReqVO;
|
||||
import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.txauth.AppWalletTxAuthGiftApplyReqVo;
|
||||
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
|
||||
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.WalletTxAuthDO;
|
||||
import cn.iocoder.yudao.module.pay.dal.mysql.wallet.WalletTxAuthMapper;
|
||||
import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum;
|
||||
import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
|
||||
import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletTxAuthBizTypeEnum;
|
||||
import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletTxAuthStatusEnum;
|
||||
import cn.iocoder.yudao.module.trade.api.brokerage.TradeBrokerageRecordApi;
|
||||
import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageWechatTransferDTO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
* 提现金额审核 Service 实现类
|
||||
*
|
||||
* @author 聊天交友
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@Validated
|
||||
public class WalletTxAuthServiceImpl implements WalletTxAuthService {
|
||||
|
||||
@Resource
|
||||
private WalletTxAuthMapper walletTxAuthMapper;
|
||||
@Resource
|
||||
private PayWalletService walletService;
|
||||
@Resource
|
||||
private PayTransferApiImpl payTransferApi;
|
||||
|
||||
@Resource
|
||||
private MemberConfigApi memberConfigApi;
|
||||
@Resource
|
||||
private MemberUserApi memberUserApi;
|
||||
@Resource
|
||||
private TradeBrokerageRecordApi tradeBrokerageRecordApi;
|
||||
|
||||
/**
|
||||
* 更新转账记录(回调)
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateTransfer(PayRefundNotifyReqDTO notifyReqDTO) {
|
||||
Long id = notifyReqDTO.getPayRefundId();
|
||||
PayTransferRespDTO transfer = payTransferApi.getTransfer(id);
|
||||
WalletTxAuthDO detail = walletTxAuthMapper.selectOne(new LambdaQueryWrapperX<WalletTxAuthDO>()
|
||||
.eq(WalletTxAuthDO::getPayTransferId, id)
|
||||
);
|
||||
if (ObjectUtil.isEmpty(detail)) {
|
||||
log.error("|更新转账记录(回调)|,提现记录不存在,不进行操作notifyReqDTO:{}", JSONUtil.toJsonStr(notifyReqDTO));
|
||||
return;
|
||||
}
|
||||
if (PayTransferStatusEnum.isWaiting(transfer.getStatus())) {
|
||||
log.info("|更新转账记录(回调)|,转账正在等待中,不进行操作notifyReqDTO:{}", JSONUtil.toJsonStr(notifyReqDTO));
|
||||
return;
|
||||
}
|
||||
if (PayTransferStatusEnum.isInProgress(transfer.getStatus())) {
|
||||
log.info("|更新转账记录(回调)|,转账正在进行中,不进行操作notifyReqDTO:{}", JSONUtil.toJsonStr(notifyReqDTO));
|
||||
return;
|
||||
}
|
||||
if (PayTransferStatusEnum.isClosed(transfer.getStatus())) {
|
||||
// 解冻
|
||||
walletService.unfreezeGiftPrice(detail.getWalletId(), detail.getTxYdPrice());
|
||||
WalletTxAuthDO updateObj = new WalletTxAuthDO();
|
||||
updateObj.setId(detail.getId());
|
||||
updateObj.setCheckStatus(PayWalletTxAuthStatusEnum.AUTH_TX_ERROR.getType());
|
||||
walletTxAuthMapper.updateById(updateObj);
|
||||
}
|
||||
if (PayTransferStatusEnum.isClosed(transfer.getStatus())) {
|
||||
// 解冻
|
||||
walletService.unfreezeGiftPrice(detail.getWalletId(), detail.getTxYdPrice());
|
||||
// 进行扣款
|
||||
walletService.reduceWalletGiftBalance(detail.getWalletId(), String.valueOf(detail.getId()), PayWalletBizTypeEnum.RECEIVE_GIFT_TX, detail.getTxYdPrice());
|
||||
WalletTxAuthDO updateObj = new WalletTxAuthDO();
|
||||
updateObj.setId(detail.getId());
|
||||
updateObj.setCheckStatus(PayWalletTxAuthStatusEnum.AUTH_TX_SUCCESS.getType());
|
||||
updateObj.setDzTime(LocalDateTime.now());
|
||||
walletTxAuthMapper.updateById(updateObj);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 礼物申请提现
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long giftApply(AppWalletTxAuthGiftApplyReqVo dto) {
|
||||
// 礼物配置
|
||||
MemberConfigRespDTO config = memberConfigApi.getConfig();
|
||||
if (ObjectUtil.isEmpty(config) || ObjectUtil.isEmpty(config.getGiftCashRatio())) {
|
||||
throw exception(EMPTY, "请先配置礼物提现比例");
|
||||
}
|
||||
// 查询用户
|
||||
MemberUserRespDTO user = memberUserApi.getUser(dto.getUserId());
|
||||
if (ObjectUtil.isEmpty(user)) {
|
||||
throw exception(EMPTY, "提现用户不存在");
|
||||
}
|
||||
// 查询用户钱包
|
||||
PayWalletDO wallet = walletService.getOrCreateWallet(dto.getUserId(), dto.getUserType());
|
||||
int afterGiftBalance = wallet.getGiftBalance() - dto.getGiftPrice();
|
||||
if (afterGiftBalance < 0) {
|
||||
throw exception(EMPTY, "提现金额大于礼物余额");
|
||||
}
|
||||
// 计算提现金额
|
||||
int txPrice = BigDecimal.valueOf(dto.getGiftPrice()).divide(BigDecimal.valueOf(config.getGiftCashRatio()), 2, RoundingMode.HALF_UP).intValue();
|
||||
// 添加记录
|
||||
WalletTxAuthDO walletTxAuth = new WalletTxAuthDO();
|
||||
walletTxAuth.setUserId(dto.getUserId());
|
||||
walletTxAuth.setWalletId(wallet.getId());
|
||||
walletTxAuth.setBizType(PayWalletTxAuthBizTypeEnum.GIFT_TX_AUTH.getType());
|
||||
walletTxAuth.setBizId(null);
|
||||
walletTxAuth.setTxPrice(txPrice);
|
||||
walletTxAuth.setTxYdPrice(dto.getGiftPrice());
|
||||
walletTxAuth.setTitle("用户" + user.getNickname() + "申请礼物提现:" + MoneyUtils.fenToYuanStr(txPrice) + "元");
|
||||
walletTxAuth.setCheckStatus(PayWalletTxAuthStatusEnum.TX_AUTH_AWAIT.getType());
|
||||
walletTxAuthMapper.insert(walletTxAuth);
|
||||
return walletTxAuth.getWalletId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 审核
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean check(WalletTxAuthCheckReqVO dto) {
|
||||
WalletTxAuthDO detail = walletTxAuthMapper.selectById(dto.getId());
|
||||
if (ObjectUtil.isEmpty(detail)) {
|
||||
throw exception(WALLET_TX_AUTH_NOT_EXISTS);
|
||||
}
|
||||
if (ObjectUtil.notEqual(PayWalletTxAuthStatusEnum.TX_AUTH_AWAIT.getType(), detail.getCheckStatus())) {
|
||||
throw exception(EMPTY, "已审核,无需重复审核");
|
||||
}
|
||||
WalletTxAuthDO updateObj = new WalletTxAuthDO();
|
||||
updateObj.setId(dto.getId());
|
||||
updateObj.setCheckStatus(dto.getCheckStatus());
|
||||
updateObj.setTxRefuse(dto.getTxRefuse());
|
||||
updateObj.setCheckTime(LocalDateTime.now());
|
||||
// 审核通过
|
||||
if (ObjectUtil.equals(PayWalletTxAuthStatusEnum.AUTH_SUCCESS.getType(), dto.getCheckStatus())) {
|
||||
BrokerageWechatTransferDTO wechatTransfer = tradeBrokerageRecordApi.wechatTransfer(detail.getId(), detail.getUserId(), detail.getTxPrice());
|
||||
if (ObjectUtil.isEmpty(wechatTransfer)) {
|
||||
throw exception(EMPTY, "发起微信转账失败");
|
||||
}
|
||||
PayTransferRespDTO transfer = payTransferApi.getTransfer(wechatTransfer.getId());
|
||||
if (ObjectUtil.isEmpty(transfer)) {
|
||||
throw exception(EMPTY, "查询转账记录失败");
|
||||
}
|
||||
updateObj.setPayTransferId(wechatTransfer.getId());
|
||||
updateObj.setChannelMchId(transfer.getChannelMchId());
|
||||
updateObj.setChannelPackageInfo(wechatTransfer.getChannelPackageInfo());
|
||||
// 应该冻结操作金额的数量
|
||||
walletService.freezeGiftPrice(detail.getWalletId(), detail.getTxYdPrice());
|
||||
}
|
||||
walletTxAuthMapper.updateById(updateObj);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long createWalletTxAuth(WalletTxAuthSaveReqVO createReqVO) {
|
||||
// 插入
|
||||
WalletTxAuthDO walletTxAuth = BeanUtils.toBean(createReqVO, WalletTxAuthDO.class);
|
||||
walletTxAuthMapper.insert(walletTxAuth);
|
||||
// 返回
|
||||
return walletTxAuth.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateWalletTxAuth(WalletTxAuthSaveReqVO updateReqVO) {
|
||||
// 校验存在
|
||||
validateWalletTxAuthExists(updateReqVO.getId());
|
||||
// 更新
|
||||
WalletTxAuthDO updateObj = BeanUtils.toBean(updateReqVO, WalletTxAuthDO.class);
|
||||
walletTxAuthMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteWalletTxAuth(Long id) {
|
||||
// 校验存在
|
||||
validateWalletTxAuthExists(id);
|
||||
// 删除
|
||||
walletTxAuthMapper.deleteById(id);
|
||||
}
|
||||
|
||||
private void validateWalletTxAuthExists(Long id) {
|
||||
if (walletTxAuthMapper.selectById(id) == null) {
|
||||
throw exception(WALLET_TX_AUTH_NOT_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WalletTxAuthDO getWalletTxAuth(Long id) {
|
||||
return walletTxAuthMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<WalletTxAuthRespVO> getWalletTxAuthPage(WalletTxAuthPageReqVO pageReqVO) {
|
||||
PageResult<WalletTxAuthRespVO> pageResult = new PageResult<>();
|
||||
|
||||
PageResult<WalletTxAuthDO> pageList = walletTxAuthMapper.selectPage(pageReqVO);
|
||||
|
||||
List<WalletTxAuthRespVO> listResult = BeanUtils.toBean(pageList.getList(), WalletTxAuthRespVO.class);
|
||||
disposePageList(listResult);
|
||||
pageResult.setTotal(pageList.getTotal());
|
||||
pageResult.setList(listResult);
|
||||
return pageResult;
|
||||
}
|
||||
|
||||
private void disposePageList(List<WalletTxAuthRespVO> list) {
|
||||
if (ObjectUtil.isEmpty(list)) return;
|
||||
List<Long> userIds = list.stream().map(WalletTxAuthRespVO::getUserId).distinct().collect(Collectors.toList());
|
||||
if (ObjectUtil.isNotEmpty(userIds)) {
|
||||
List<MemberUserRespDTO> userList = memberUserApi.getUserList(userIds);
|
||||
Map<Long, MemberUserRespDTO> userMap = IterUtil.toMap(userList, MemberUserRespDTO::getId);
|
||||
for (WalletTxAuthRespVO item : list) {
|
||||
MemberUserRespDTO target = userMap.get(item.getUserId());
|
||||
if (ObjectUtil.isEmpty(target)) continue;
|
||||
item.setMemberAvatar(target.getAvatar());
|
||||
item.setMemberNickname(target.getNickname());
|
||||
item.setMemberMobile(target.getMobile());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user