mirror of
				https://github.com/YunaiV/ruoyi-vue-pro.git
				synced 2025-10-31 18:49:06 +08:00 
			
		
		
		
	钱包,转账 review 修改
This commit is contained in:
		| @ -9,7 +9,7 @@ CREATE TABLE `pay_transfer` | ||||
|     `app_id`               bigint       NOT NULL COMMENT '应用编号', | ||||
|     `merchant_order_id`    varchar(64)  NOT NULL COMMENT '商户订单编号', | ||||
|     `price`                int          NOT NULL COMMENT '转账金额,单位:分', | ||||
|     `title`                varchar(512) NOT NULL COMMENT '转账标题', | ||||
|     `subject`              varchar(512) NOT NULL COMMENT '转账标题', | ||||
|     `payee_info`           varchar(512) NOT NULL COMMENT '收款人信息,不同类型和渠道不同', | ||||
|     `status`               tinyint      NOT NULL COMMENT '转账状态', | ||||
|     `success_time`         datetime     NULL COMMENT '转账成功时间', | ||||
|  | ||||
| @ -1,5 +1,7 @@ | ||||
| package cn.iocoder.yudao.module.pay.api.transfer.dto; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.common.validation.InEnum; | ||||
| import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum; | ||||
| import lombok.Data; | ||||
|  | ||||
| import javax.validation.constraints.Min; | ||||
| @ -23,7 +25,7 @@ public class PayTransferCreateReqDTO { | ||||
|      * 类型 | ||||
|      */ | ||||
|     @NotNull(message = "转账类型不能为空") | ||||
|     // TODO @jason:枚举的校验 | ||||
|     @InEnum(PayTransferTypeEnum.class) | ||||
|     private Integer type; | ||||
|  | ||||
|     /** | ||||
| @ -35,14 +37,14 @@ public class PayTransferCreateReqDTO { | ||||
|     /** | ||||
|      * 转账金额,单位:分 | ||||
|      */ | ||||
|     // TODO @jason:这个金额是不是非空哈 | ||||
|     @Min(value = 1, message = "转账金额必须大于零") | ||||
|     @NotNull(message = "转账金额不能为空") | ||||
|     private Integer price; | ||||
|  | ||||
|     // TODO @jason:这个标题,是不是不允许空呀 | ||||
|     /** | ||||
|      * 转账标题 | ||||
|      */ | ||||
|     @NotEmpty(message = "转账标题不能为空") | ||||
|     private String title; | ||||
|  | ||||
|     @NotEmpty(message = "收款方信息不能为空") | ||||
|  | ||||
| @ -62,6 +62,7 @@ public interface ErrorCodeConstants { | ||||
|     ErrorCode WALLET_RECHARGE_PACKAGE_AND_PRICE_IS_EMPTY = new ErrorCode(1_007_008_011, "充值金额和充钱套餐不能同时为空"); | ||||
|     ErrorCode WALLET_RECHARGE_PACKAGE_NOT_FOUND = new ErrorCode(1_007_008_012, "钱包充值套餐不存在"); | ||||
|     ErrorCode WALLET_RECHARGE_PACKAGE_IS_DISABLE = new ErrorCode(1_007_008_013, "钱包充值套餐已禁用"); | ||||
|     ErrorCode WALLET_RECHARGE_PACKAGE_NAME_EXISTS = new ErrorCode(1_007_008_014, "钱包充值套餐名称已存在"); | ||||
|  | ||||
|     // ========== 转账模块 1-007-009-000 ========== | ||||
|     ErrorCode PAY_TRANSFER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1_007_009_000, "发起转账报错,错误码:{},错误提示:{}"); | ||||
|  | ||||
| @ -1,8 +1,11 @@ | ||||
| package cn.iocoder.yudao.module.pay.enums.member; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.common.core.IntArrayValuable; | ||||
| import lombok.AllArgsConstructor; | ||||
| import lombok.Getter; | ||||
|  | ||||
| import java.util.Arrays; | ||||
|  | ||||
| /** | ||||
|  * 钱包交易业务分类 | ||||
|  * | ||||
| @ -10,7 +13,7 @@ import lombok.Getter; | ||||
|  */ | ||||
| @AllArgsConstructor | ||||
| @Getter | ||||
| public enum PayWalletBizTypeEnum { | ||||
| public enum PayWalletBizTypeEnum implements IntArrayValuable { | ||||
|  | ||||
|     RECHARGE(1, "充值"), | ||||
|     RECHARGE_REFUND(2, "充值退款"), | ||||
| @ -28,4 +31,10 @@ public enum PayWalletBizTypeEnum { | ||||
|      */ | ||||
|     private final String description; | ||||
|  | ||||
|     public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PayWalletBizTypeEnum::getType).toArray(); | ||||
|  | ||||
|     @Override | ||||
|     public int[] array() { | ||||
|          return ARRAYS; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,41 @@ | ||||
| package cn.iocoder.yudao.module.pay.enums.transfer; | ||||
|  | ||||
| import cn.hutool.core.util.ArrayUtil; | ||||
| import cn.iocoder.yudao.framework.common.core.IntArrayValuable; | ||||
| import lombok.AllArgsConstructor; | ||||
| import lombok.Getter; | ||||
|  | ||||
| import java.util.Arrays; | ||||
|  | ||||
| /** | ||||
|  * 转账类型枚举 | ||||
|  * | ||||
|  * @author jason | ||||
|  */ | ||||
| @AllArgsConstructor | ||||
| @Getter | ||||
| public enum PayTransferTypeEnum implements IntArrayValuable { | ||||
|  | ||||
|     ALIPAY_BALANCE(1, "支付宝余额"), | ||||
|     WX_BALANCE(2, "微信余额"), | ||||
|     BANK_CARD(3, "银行卡"), | ||||
|     WALLET_BALANCE(4, "钱包余额"); | ||||
|  | ||||
|     public static final String ALIPAY_LOGON_ID = "ALIPAY_LOGON_ID"; | ||||
|     public static final String ALIPAY_ACCOUNT_NAME = "ALIPAY_ACCOUNT_NAME"; | ||||
|  | ||||
|     private final Integer type; | ||||
|     private final String name; | ||||
|  | ||||
|     public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PayTransferTypeEnum::getType).toArray(); | ||||
|  | ||||
|     @Override | ||||
|     public int[] array() { | ||||
|         return ARRAYS; | ||||
|     } | ||||
|  | ||||
|     public static PayTransferTypeEnum typeOf(Integer type) { | ||||
|         return ArrayUtil.firstMatch(item -> item.getType().equals(type), values()); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -24,6 +24,11 @@ | ||||
|             <version>${revision}</version> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>cn.iocoder.boot</groupId> | ||||
|             <artifactId>yudao-module-member-api</artifactId> | ||||
|             <version>${revision}</version> | ||||
|         </dependency> | ||||
|         <!-- 业务组件 --> | ||||
|         <dependency> | ||||
|             <groupId>cn.iocoder.boot</groupId> | ||||
|  | ||||
| @ -1,9 +1,12 @@ | ||||
| package cn.iocoder.yudao.module.pay.api.transfer; | ||||
|  | ||||
| import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; | ||||
| import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService; | ||||
| import org.springframework.stereotype.Service; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
|  | ||||
| import javax.annotation.Resource; | ||||
|  | ||||
| /** | ||||
|  * 转账单 API 实现类 | ||||
|  * | ||||
| @ -12,11 +15,11 @@ import org.springframework.validation.annotation.Validated; | ||||
| @Service | ||||
| @Validated | ||||
| public class PayTransferApiImpl implements PayTransferApi { | ||||
|     @Resource | ||||
|     private PayTransferService payTransferService; | ||||
|  | ||||
|     @Override | ||||
|     public Long createTransfer(PayTransferCreateReqDTO reqDTO) { | ||||
|         // TODO @jason:貌似没实现噢 | ||||
|         return null; | ||||
|         return payTransferService.createTransfer(reqDTO); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -17,11 +17,10 @@ import java.util.Map; | ||||
| @Data | ||||
| public class PayDemoTransferCreateReqVO { | ||||
|  | ||||
|     // TODO @jason:这个字段,是不是叫 type 就好了。 | ||||
|     @Schema(description = "转账类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     @NotNull(message = "转账类型不能为空") | ||||
|     @InEnum(PayTransferTypeEnum.class) | ||||
|     private Integer transferType; | ||||
|     private Integer type; | ||||
|  | ||||
|     @NotNull(message = "转账金额不能为空") | ||||
|     @Min(value = 1, message = "转账金额必须大于零") | ||||
|  | ||||
| @ -29,7 +29,7 @@ public class PayTransferController { | ||||
|  | ||||
|     @PostMapping("/submit") | ||||
|     @Operation(summary = "提交转账订单") | ||||
|     // TODO @jason:权限的设置 | ||||
|     // TODO @jason:权限的设置, 管理后台页面加的时候加一下 | ||||
|     public CommonResult<PayTransferSubmitRespVO> submitPayTransfer(@Valid @RequestBody PayTransferSubmitReqVO reqVO) { | ||||
|         PayTransferSubmitRespVO respVO = payTransferService.submitTransfer(reqVO, getClientIP()); | ||||
|         return success(respVO); | ||||
|  | ||||
| @ -1,7 +1,12 @@ | ||||
| package cn.iocoder.yudao.module.pay.controller.admin.wallet; | ||||
|  | ||||
| import cn.hutool.core.collection.CollectionUtil; | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||
| import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||||
| 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.controller.admin.wallet.vo.wallet.PayWalletPageReqVO; | ||||
| import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.wallet.PayWalletRespVO; | ||||
| import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.wallet.PayWalletUserReqVO; | ||||
| @ -19,8 +24,14 @@ import org.springframework.web.bind.annotation.RestController; | ||||
|  | ||||
| import javax.annotation.Resource; | ||||
| import javax.validation.Valid; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.Set; | ||||
|  | ||||
| import static cn.iocoder.yudao.framework.common.enums.UserTypeEnum.MEMBER; | ||||
| import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||||
| import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | ||||
| import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | ||||
|  | ||||
| @Tag(name = "管理后台 - 用户钱包") | ||||
| @RestController | ||||
| @ -31,21 +42,37 @@ public class PayWalletController { | ||||
|  | ||||
|     @Resource | ||||
|     private PayWalletService payWalletService; | ||||
|     @Resource | ||||
|     private MemberUserApi memberUserApi; | ||||
|  | ||||
|     @GetMapping("/get") | ||||
|     @PreAuthorize("@ss.hasPermission('pay:wallet:query')") | ||||
|     @Operation(summary = "获得用户钱包明细") | ||||
|     public CommonResult<PayWalletRespVO> getWallet(PayWalletUserReqVO reqVO) { | ||||
|         PayWalletDO wallet = payWalletService.getOrCreateWallet(reqVO.getUserId(), reqVO.getUserType()); | ||||
|         return success(PayWalletConvert.INSTANCE.convert02(wallet)); | ||||
|         PayWalletDO wallet = payWalletService.getOrCreateWallet(reqVO.getUserId(), MEMBER.getValue()); | ||||
|         MemberUserRespDTO memberUser = memberUserApi.getUser(reqVO.getUserId()); | ||||
|         String nickname = memberUser == null ? "" : memberUser.getNickname(); | ||||
|         String avatar = memberUser == null ? "" : memberUser.getAvatar(); | ||||
|         return success(PayWalletConvert.INSTANCE.convert02(nickname, avatar, wallet)); | ||||
|     } | ||||
|  | ||||
|     @GetMapping("/page") | ||||
|     @Operation(summary = "获得会员钱包分页") | ||||
|     @PreAuthorize("@ss.hasPermission('pay:wallet:query')") | ||||
|     public CommonResult<PageResult<PayWalletRespVO>> getWalletPage(@Valid PayWalletPageReqVO pageVO) { | ||||
|         PageResult<PayWalletDO> pageResult = payWalletService.getWalletPage(pageVO); | ||||
|         return success(PayWalletConvert.INSTANCE.convertPage(pageResult)); | ||||
|         if (StrUtil.isNotEmpty(pageVO.getNickname())) { | ||||
|             Set<Long> userIds = CollectionUtils.convertSet(memberUserApi.getUserListByNickname(pageVO.getNickname()), | ||||
|                     MemberUserRespDTO::getId); | ||||
|             pageVO.setUserIds(userIds); | ||||
|         } | ||||
|         //  暂时支持查询 userType 会员类型。管理员类型还不知道使用场景 | ||||
|         PageResult<PayWalletDO> pageResult = payWalletService.getWalletPage(MEMBER.getValue(),pageVO); | ||||
|         if (CollectionUtil.isEmpty(pageResult.getList())) { | ||||
|             return success(new PageResult<>(pageResult.getTotal())); | ||||
|         } | ||||
|         List<Long> userIds = convertList(pageResult.getList(), PayWalletDO::getUserId); | ||||
|         Map<Long, MemberUserRespDTO> userMap = convertMap(memberUserApi.getUserList(userIds),MemberUserRespDTO::getId); | ||||
|         return success(PayWalletConvert.INSTANCE.convertPage(pageResult, userMap)); | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -10,6 +10,7 @@ import cn.iocoder.yudao.module.pay.service.wallet.PayWalletTransactionService; | ||||
| import io.swagger.v3.oas.annotations.Operation; | ||||
| import io.swagger.v3.oas.annotations.tags.Tag; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.GetMapping; | ||||
| import org.springframework.web.bind.annotation.RequestMapping; | ||||
| @ -32,7 +33,7 @@ public class PayWalletTransactionController { | ||||
|  | ||||
|     @GetMapping("/page") | ||||
|     @Operation(summary = "获得钱包流水分页") | ||||
|     // TODO @jason:权限校验,缺一个 | ||||
|     @PreAuthorize("@ss.hasPermission('pay:wallet:query')") | ||||
|     public CommonResult<PageResult<PayWalletTransactionRespVO>> getWalletTransactionPage( | ||||
|             @Valid PayWalletTransactionPageReqVO pageReqVO) { | ||||
|         PageResult<PayWalletTransactionDO> result = payWalletTransactionService.getWalletTransactionPage(pageReqVO); | ||||
|  | ||||
| @ -20,14 +20,6 @@ public class WalletRechargePackagePageReqVO extends PageParam { | ||||
|     @Schema(description = "套餐名", example = "李四") | ||||
|     private String name; | ||||
|  | ||||
|     // TODO @jason:payPrice 和 bonusPrice 可以去掉。。。一般太少检索啦; | ||||
|  | ||||
|     @Schema(description = "支付金额", example = "16454") | ||||
|     private Integer payPrice; | ||||
|  | ||||
|     @Schema(description = "赠送金额", example = "20887") | ||||
|     private Integer bonusPrice; | ||||
|  | ||||
|     @Schema(description = "状态", example = "2") | ||||
|     private Integer status; | ||||
|  | ||||
|  | ||||
| @ -1,12 +1,14 @@ | ||||
| package cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.wallet; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | ||||
| import cn.iocoder.yudao.framework.common.validation.InEnum; | ||||
| import lombok.*; | ||||
| import io.swagger.v3.oas.annotations.media.Schema; | ||||
| import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||||
| 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 java.util.Collection; | ||||
|  | ||||
| import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | ||||
|  | ||||
| @ -16,12 +18,11 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ | ||||
| @ToString(callSuper = true) | ||||
| public class PayWalletPageReqVO extends PageParam { | ||||
|  | ||||
|     @Schema(description = "用户编号", example = "14138") | ||||
|     private Long userId; | ||||
|     @Schema(description = "用户昵称", example = "李四") | ||||
|     private String nickname; | ||||
|  | ||||
|     @Schema(description = "用户类型", example = "1") | ||||
|     @InEnum(UserTypeEnum.class) | ||||
|     private Integer userType; | ||||
|     @Schema(description = "用户编号", example = "[1,2]") | ||||
|     private Collection<Long> userIds; | ||||
|  | ||||
|     @Schema(description = "创建时间") | ||||
|     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||||
|  | ||||
| @ -19,6 +19,10 @@ public class PayWalletRespVO extends PayWalletBaseVO { | ||||
|     @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||||
|     private LocalDateTime createTime; | ||||
|  | ||||
|     // TODO @jason:要不把用户昵称 + avatar 也读取下? | ||||
|     @Schema(description = "用户昵称") | ||||
|     private String nickname; | ||||
|  | ||||
|     @Schema(description = "用户头像") | ||||
|     private String avatar; | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -1,7 +1,5 @@ | ||||
| package cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.wallet; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | ||||
| import cn.iocoder.yudao.framework.common.validation.InEnum; | ||||
| import io.swagger.v3.oas.annotations.media.Schema; | ||||
| import lombok.Data; | ||||
|  | ||||
| @ -14,10 +12,4 @@ public class PayWalletUserReqVO { | ||||
|     @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     @NotNull(message = "用户编号不能为空") | ||||
|     private Long userId; | ||||
|  | ||||
|     @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     @NotNull(message = "用户类型不能为空") | ||||
|     @InEnum(value = UserTypeEnum.class, message = "用户类型必须是 {value}") | ||||
|     private Integer userType; | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -19,6 +19,7 @@ import javax.annotation.Resource; | ||||
| import javax.validation.Valid; | ||||
|  | ||||
| import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||||
| import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; | ||||
| import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; | ||||
| import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserType; | ||||
|  | ||||
| @ -37,7 +38,7 @@ public class AppPayWalletRechargeController { | ||||
|     public CommonResult<AppPayWalletRechargeCreateRespVO> createWalletRecharge( | ||||
|             @Valid  @RequestBody  AppPayWalletRechargeCreateReqVO reqVO) { | ||||
|         PayWalletRechargeDO walletRecharge = walletRechargeService.createWalletRecharge( | ||||
|                 getLoginUserId(), getLoginUserType(), reqVO); | ||||
|                 getLoginUserId(), getLoginUserType(), getClientIP(), reqVO); | ||||
|         return success(PayWalletRechargeConvert.INSTANCE.convert(walletRecharge)); | ||||
|     } | ||||
|  | ||||
|  | ||||
| @ -3,7 +3,9 @@ package cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge; | ||||
| import io.swagger.v3.oas.annotations.media.Schema; | ||||
| import lombok.Data; | ||||
|  | ||||
| import javax.validation.constraints.AssertTrue; | ||||
| import javax.validation.constraints.Min; | ||||
| import java.util.Objects; | ||||
|  | ||||
| @Schema(description = "用户 APP - 创建钱包充值 Request VO") | ||||
| @Data | ||||
| @ -16,6 +18,8 @@ public class AppPayWalletRechargeCreateReqVO { | ||||
|     @Schema(description = "充值套餐编号", example = "1024") | ||||
|     private Long packageId; | ||||
|  | ||||
|     // TODO @jaosn:写个 AssertTrue 的校验方法,payPrice 和 packageId 必须二选一 | ||||
|  | ||||
|     @AssertTrue(message = "充值金额和充钱套餐不能同时为空") | ||||
|     public boolean validatePayPriceAndPackageId() { | ||||
|         return Objects.nonNull(payPrice) || Objects.nonNull(packageId); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -11,9 +11,9 @@ import org.mapstruct.factory.Mappers; | ||||
| public interface PayTransferConvert { | ||||
|  | ||||
|     PayTransferConvert  INSTANCE = Mappers.getMapper(PayTransferConvert.class); | ||||
|  | ||||
|     @Mapping(source = "title", target = "subject") | ||||
|     PayTransferDO convert(PayTransferCreateReqDTO dto); | ||||
|     @Mapping(source = "transferType", target = "type") | ||||
|  | ||||
|     PayTransferCreateReqDTO convert(PayDemoTransferCreateReqVO vo); | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -1,12 +1,16 @@ | ||||
| package cn.iocoder.yudao.module.pay.convert.wallet; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||
| import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | ||||
| import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; | ||||
| import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.wallet.PayWalletRespVO; | ||||
| import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.wallet.AppPayWalletRespVO; | ||||
| import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; | ||||
| import org.mapstruct.Mapper; | ||||
| import org.mapstruct.factory.Mappers; | ||||
|  | ||||
| import java.util.Map; | ||||
|  | ||||
| @Mapper | ||||
| public interface PayWalletConvert { | ||||
|  | ||||
| @ -14,8 +18,18 @@ public interface PayWalletConvert { | ||||
|  | ||||
|     AppPayWalletRespVO convert(PayWalletDO bean); | ||||
|  | ||||
|     PayWalletRespVO convert02(PayWalletDO bean); | ||||
|     PayWalletRespVO convert02(String nickname,String avatar, PayWalletDO bean); | ||||
|  | ||||
|     PageResult<PayWalletRespVO> convertPage(PageResult<PayWalletDO> page); | ||||
|  | ||||
|     default PageResult<PayWalletRespVO> convertPage(PageResult<PayWalletDO> page, Map<Long, MemberUserRespDTO> userMap){ | ||||
|         PageResult<PayWalletRespVO> pageResult = convertPage(page); | ||||
|         pageResult.getList().forEach( wallet -> MapUtils.findAndThen(userMap, wallet.getUserId(), | ||||
|                 user -> { | ||||
|                     wallet.setNickname(user.getNickname()); | ||||
|                     wallet.setAvatar(user.getAvatar()); | ||||
|                 })); | ||||
|         return pageResult; | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -64,11 +64,11 @@ public class PayTransferDO extends BaseDO { | ||||
|      * 例如说,内部系统 A 的订单号,需要保证每个 PayAppDO 唯一 | ||||
|      */ | ||||
|     private String merchantOrderId; | ||||
|     // TODO @jason:这个字段,要不要改成 subject。。。和 payorderdo 保持一致;哈哈哈,我也忘记为啥当时选了这个名字了。。。 | ||||
|  | ||||
|     /** | ||||
|      * 转账标题 | ||||
|      */ | ||||
|     private String title; | ||||
|     private String subject; | ||||
|  | ||||
|     // ========== 转账相关字段 ========== | ||||
|     /** | ||||
|  | ||||
| @ -11,6 +11,7 @@ import lombok.Data; | ||||
| import java.util.Map; | ||||
|  | ||||
| // TODO @jason:转账是不是类似 refund,不用拓展单呀?支付做拓展单的原因,是因为它存在不确定性,可以切换多种;转账和退款,都是明确方式的; | ||||
| // @芋艿 转账是不是也存在多种方式。 例如转账到银行卡。 可以使用微信,也可以使用支付宝。 支付宝账号余额不够,可以切换到微信 | ||||
| /** | ||||
|  * 转账拓展单 DO | ||||
|  * | ||||
|  | ||||
| @ -17,10 +17,10 @@ public interface PayWalletMapper extends BaseMapperX<PayWalletDO> { | ||||
|                 PayWalletDO::getUserType, userType); | ||||
|     } | ||||
|  | ||||
|     default PageResult<PayWalletDO> selectPage(PayWalletPageReqVO reqVO) { | ||||
|     default PageResult<PayWalletDO> selectPage(Integer userType, PayWalletPageReqVO reqVO) { | ||||
|         return selectPage(reqVO, new LambdaQueryWrapperX<PayWalletDO>() | ||||
|                 .eqIfPresent(PayWalletDO::getUserId, reqVO.getUserId()) | ||||
|                 .eqIfPresent(PayWalletDO::getUserType, reqVO.getUserType()) | ||||
|                 .inIfPresent(PayWalletDO::getUserId, reqVO.getUserIds()) | ||||
|                 .eqIfPresent(PayWalletDO::getUserType, userType) | ||||
|                 .betweenIfPresent(PayWalletDO::getCreateTime, reqVO.getCreateTime()) | ||||
|                 .orderByDesc(PayWalletDO::getId)); | ||||
|     } | ||||
|  | ||||
| @ -12,14 +12,14 @@ import org.apache.ibatis.annotations.Mapper; | ||||
| public interface PayWalletRechargePackageMapper extends BaseMapperX<PayWalletRechargePackageDO> { | ||||
|  | ||||
|     default PageResult<PayWalletRechargePackageDO> selectPage(WalletRechargePackagePageReqVO reqVO) { | ||||
|         // TODO @jason:排序按照充值金额 | ||||
|         return selectPage(reqVO, new LambdaQueryWrapperX<PayWalletRechargePackageDO>() | ||||
|                 .likeIfPresent(PayWalletRechargePackageDO::getName, reqVO.getName()) | ||||
|                 .eqIfPresent(PayWalletRechargePackageDO::getPayPrice, reqVO.getPayPrice()) | ||||
|                 .eqIfPresent(PayWalletRechargePackageDO::getBonusPrice, reqVO.getBonusPrice()) | ||||
|                 .eqIfPresent(PayWalletRechargePackageDO::getStatus, reqVO.getStatus()) | ||||
|                 .betweenIfPresent(PayWalletRechargePackageDO::getCreateTime, reqVO.getCreateTime()) | ||||
|                 .orderByDesc(PayWalletRechargePackageDO::getId)); | ||||
|                 .orderByDesc(PayWalletRechargePackageDO::getPayPrice)); | ||||
|     } | ||||
|  | ||||
|     default PayWalletRechargePackageDO selectByName(String name){ | ||||
|         return selectOne(PayWalletRechargePackageDO::getName, name); | ||||
|     } | ||||
| } | ||||
| @ -46,10 +46,10 @@ public class PayDemoTransferServiceImpl implements PayDemoTransferService { | ||||
|     @Transactional(rollbackFor = Exception.class) | ||||
|     public Long createDemoTransfer(Long userId, @Valid PayDemoTransferCreateReqVO vo) { | ||||
|         // 1 校验收款账号 | ||||
|         validatePayeeInfo(vo.getTransferType(), vo.getPayeeInfo()); | ||||
|         validatePayeeInfo(vo.getType(), vo.getPayeeInfo()); | ||||
|  | ||||
|         // 2 保存示例转账业务表 | ||||
|         PayDemoTransferDO demoTransfer = new PayDemoTransferDO().setUserId(userId).setType(vo.getTransferType()) | ||||
|         PayDemoTransferDO demoTransfer = new PayDemoTransferDO().setUserId(userId).setType(vo.getType()) | ||||
|                 .setPrice(vo.getPrice()).setPayeeInfo(vo.getPayeeInfo()) | ||||
|                 .setTransferStatus(WAITING.getStatus()); | ||||
|         demoTransferMapper.insert(demoTransfer); | ||||
| @ -65,6 +65,7 @@ public class PayDemoTransferServiceImpl implements PayDemoTransferService { | ||||
|     } | ||||
|  | ||||
|     // TODO @jason:可以参考 AppBrokerageWithdrawCreateReqVO 搞下字段哈,进行校验 | ||||
|     // @jason payeeinfo 字段确定改一下 | ||||
|     private void validatePayeeInfo(Integer transferType, Map<String, String> payeeInfo) { | ||||
|         PayTransferTypeEnum transferTypeEnum = typeOf(transferType); | ||||
|         switch (transferTypeEnum) { | ||||
|  | ||||
| @ -79,7 +79,7 @@ public class PayTransferServiceImpl implements PayTransferService { | ||||
|         // 3. 调用三方渠道发起转账 | ||||
|         PayTransferUnifiedReqDTO transferUnifiedReq = new PayTransferUnifiedReqDTO() | ||||
|                 .setOutTransferNo(transferExtension.getNo()).setPrice(transfer.getPrice()) | ||||
|                 .setType(transfer.getType()).setTitle(transfer.getTitle()) | ||||
|                 .setType(transfer.getType()).setTitle(transfer.getSubject()) | ||||
|                 .setPayeeInfo(transfer.getPayeeInfo()).setUserIp(userIp) | ||||
|                 .setChannelExtras(reqVO.getChannelExtras()); | ||||
|         PayTransferRespDTO unifiedTransferResp = client.unifiedTransfer(transferUnifiedReq); | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| package cn.iocoder.yudao.module.pay.service.wallet; | ||||
|  | ||||
| import cn.hutool.core.collection.CollUtil; | ||||
| import cn.hutool.core.collection.ListUtil; | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||
| import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.rechargepackage.WalletRechargePackageCreateReqVO; | ||||
| @ -14,9 +13,6 @@ import org.springframework.stereotype.Service; | ||||
|  | ||||
| import javax.annotation.Resource; | ||||
|  | ||||
| import java.util.Collection; | ||||
| import java.util.List; | ||||
|  | ||||
| import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||||
| import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; | ||||
|  | ||||
| @ -50,6 +46,8 @@ public class PayWalletRechargePackageServiceImpl implements PayWalletRechargePac | ||||
|  | ||||
|     @Override | ||||
|     public Long createWalletRechargePackage(WalletRechargePackageCreateReqVO createReqVO) { | ||||
|         // 校验套餐名是否唯一 | ||||
|         validateRechargePackageNameUnique(null, createReqVO.getName()); | ||||
|         // 插入 | ||||
|         PayWalletRechargePackageDO walletRechargePackage = WalletRechargePackageConvert.INSTANCE.convert(createReqVO); | ||||
|         walletRechargePackageMapper.insert(walletRechargePackage); | ||||
| @ -57,16 +55,33 @@ public class PayWalletRechargePackageServiceImpl implements PayWalletRechargePac | ||||
|         return walletRechargePackage.getId(); | ||||
|     } | ||||
|  | ||||
|     // TODO @jason:校验下,套餐名唯一 | ||||
|     @Override | ||||
|     public void updateWalletRechargePackage(WalletRechargePackageUpdateReqVO updateReqVO) { | ||||
|         // 校验存在 | ||||
|         validateWalletRechargePackageExists(updateReqVO.getId()); | ||||
|         // 校验套餐名是否唯一 | ||||
|         validateRechargePackageNameUnique(updateReqVO.getId(), updateReqVO.getName()); | ||||
|         // 更新 | ||||
|         PayWalletRechargePackageDO updateObj = WalletRechargePackageConvert.INSTANCE.convert(updateReqVO); | ||||
|         walletRechargePackageMapper.updateById(updateObj); | ||||
|     } | ||||
|  | ||||
|     private void validateRechargePackageNameUnique(Long id, String name) { | ||||
|         if (StrUtil.isBlank(name)) { | ||||
|             return; | ||||
|         } | ||||
|         PayWalletRechargePackageDO rechargePackage = walletRechargePackageMapper.selectByName(name); | ||||
|         if (rechargePackage == null) { | ||||
|             return ; | ||||
|         } | ||||
|         if (id == null) { | ||||
|             throw exception(WALLET_RECHARGE_PACKAGE_NAME_EXISTS); | ||||
|         } | ||||
|         if (!id.equals(rechargePackage.getId())) { | ||||
|             throw exception(WALLET_RECHARGE_PACKAGE_NAME_EXISTS); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void deleteWalletRechargePackage(Long id) { | ||||
|         // 校验存在 | ||||
|  | ||||
| @ -16,9 +16,10 @@ public interface PayWalletRechargeService { | ||||
|      * @param userId      用户 id | ||||
|      * @param userType    用户类型 | ||||
|      * @param createReqVO 钱包充值请求 VO | ||||
|      * @param userIp  用户Ip | ||||
|      * @return 钱包充值记录 | ||||
|      */ | ||||
|     PayWalletRechargeDO createWalletRecharge(Long userId, Integer userType, | ||||
|     PayWalletRechargeDO createWalletRecharge(Long userId, Integer userType, String userIp, | ||||
|                                              AppPayWalletRechargeCreateReqVO createReqVO); | ||||
|  | ||||
|     /** | ||||
|  | ||||
| @ -29,7 +29,6 @@ import static cn.hutool.core.util.ObjectUtil.notEqual; | ||||
| import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||||
| import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime; | ||||
| import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; | ||||
| import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; | ||||
| import static cn.iocoder.yudao.module.pay.convert.wallet.PayWalletRechargeConvert.INSTANCE; | ||||
| import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; | ||||
| import static cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum.*; | ||||
| @ -63,13 +62,13 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { | ||||
|  | ||||
|     @Override | ||||
|     @Transactional(rollbackFor = Exception.class) | ||||
|     public PayWalletRechargeDO createWalletRecharge(Long userId, Integer userType, | ||||
|     public PayWalletRechargeDO createWalletRecharge(Long userId, Integer userType, String userIp, | ||||
|                                                     AppPayWalletRechargeCreateReqVO reqVO) { | ||||
|         // 1.1 校验参数 TODO @jason:AppPayWalletRechargeCreateReqVO 看下校验; | ||||
|  | ||||
|         if (Objects.isNull(reqVO.getPayPrice()) && Objects.isNull(reqVO.getPackageId())) { | ||||
|             //  TODO @jason @AssertTrue 貌似没有效果。需要查下原因 | ||||
|             throw exception(WALLET_RECHARGE_PACKAGE_AND_PRICE_IS_EMPTY); | ||||
|         } | ||||
|  | ||||
|         // 1.1 计算充值金额 | ||||
|         int payPrice; | ||||
|         int bonusPrice = 0; | ||||
| @ -87,7 +86,7 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { | ||||
|  | ||||
|         // 2.1 创建支付单 | ||||
|         Long payOrderId = payOrderService.createOrder(new PayOrderCreateReqDTO() | ||||
|                 .setAppId(WALLET_PAY_APP_ID).setUserIp(getClientIP()) // TODO @jason:clientIp 从 controller 传递进来噢 | ||||
|                 .setAppId(WALLET_PAY_APP_ID).setUserIp(userIp) | ||||
|                 .setMerchantOrderId(recharge.getId().toString()) // 业务的订单编号 | ||||
|                 .setSubject(WALLET_RECHARGE_ORDER_SUBJECT).setBody("") | ||||
|                 .setPrice(recharge.getPayPrice()) | ||||
| @ -181,7 +180,7 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { | ||||
|         // 退款失败 | ||||
|         if (PayRefundStatusRespEnum.isFailure(payRefund.getStatus())) { | ||||
|             // 2.2 解冻余额 | ||||
|             payWalletService.unFreezePrice(walletRecharge.getWalletId(), walletRecharge.getTotalPrice()); | ||||
|             payWalletService.unfreezePrice(walletRecharge.getWalletId(), walletRecharge.getTotalPrice()); | ||||
|  | ||||
|             updateObj.setRefundStatus(FAILURE.getStatus()); | ||||
|         } | ||||
|  | ||||
| @ -37,7 +37,7 @@ public interface PayWalletService { | ||||
|      * @param pageReqVO 分页查询 | ||||
|      * @return 会员钱包分页 | ||||
|      */ | ||||
|     PageResult<PayWalletDO> getWalletPage(PayWalletPageReqVO pageReqVO); | ||||
|     PageResult<PayWalletDO> getWalletPage(Integer userType, PayWalletPageReqVO pageReqVO); | ||||
|  | ||||
|     /** | ||||
|      * 钱包订单支付 | ||||
| @ -90,13 +90,12 @@ public interface PayWalletService { | ||||
|      */ | ||||
|     void freezePrice(Long id, Integer price); | ||||
|  | ||||
|     // TODO @jason:unfreeze 是单词哈,f 不用大写 | ||||
|     /** | ||||
|      * 解冻钱包余额 | ||||
|      * | ||||
|      * @param id    钱包编号 | ||||
|      * @param price 解冻金额 | ||||
|      */ | ||||
|     void unFreezePrice(Long id, Integer price); | ||||
|     void unfreezePrice(Long id, Integer price); | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -63,8 +63,8 @@ public class PayWalletServiceImpl implements  PayWalletService { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public PageResult<PayWalletDO> getWalletPage(PayWalletPageReqVO pageReqVO) { | ||||
|         return walletMapper.selectPage(pageReqVO); | ||||
|     public PageResult<PayWalletDO> getWalletPage(Integer userType,PayWalletPageReqVO pageReqVO) { | ||||
|         return walletMapper.selectPage(userType, pageReqVO); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
| @ -196,7 +196,7 @@ public class PayWalletServiceImpl implements  PayWalletService { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void unFreezePrice(Long id, Integer price) { | ||||
|     public void unfreezePrice(Long id, Integer price) { | ||||
|         int updateCounts = walletMapper.unFreezePrice(id, price); | ||||
|         if (updateCounts == 0) { | ||||
|             throw exception(WALLET_FREEZE_PRICE_NOT_ENOUGH); | ||||
|  | ||||
| @ -12,6 +12,7 @@ import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; | ||||
| import cn.iocoder.yudao.module.pay.service.wallet.bo.WalletTransactionCreateReqBO; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.springframework.stereotype.Service; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
|  | ||||
| import javax.annotation.Resource; | ||||
|  | ||||
| @ -22,6 +23,7 @@ import javax.annotation.Resource; | ||||
|  */ | ||||
| @Service | ||||
| @Slf4j | ||||
| @Validated | ||||
| public class PayWalletTransactionServiceImpl implements PayWalletTransactionService { | ||||
|  | ||||
|     /** | ||||
|  | ||||
| @ -1,8 +1,12 @@ | ||||
| package cn.iocoder.yudao.module.pay.service.wallet.bo; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.common.validation.InEnum; | ||||
| import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; | ||||
| import lombok.Data; | ||||
|  | ||||
| import javax.validation.constraints.NotEmpty; | ||||
| import javax.validation.constraints.NotNull; | ||||
|  | ||||
| /** | ||||
|  * 创建钱包流水 BO | ||||
|  * | ||||
| @ -11,12 +15,11 @@ import lombok.Data; | ||||
| @Data | ||||
| public class WalletTransactionCreateReqBO { | ||||
|  | ||||
|     // TODO @jason:bo 的话,最好加个参数校验哈; | ||||
|  | ||||
|     /** | ||||
|      * 钱包编号 | ||||
|      * | ||||
|      */ | ||||
|     @NotNull(message = "钱包编号不能为空") | ||||
|     private Long walletId; | ||||
|  | ||||
|     /** | ||||
| @ -24,11 +27,13 @@ public class WalletTransactionCreateReqBO { | ||||
|      * | ||||
|      * 正值表示余额增加,负值表示余额减少 | ||||
|      */ | ||||
|     @NotNull(message = "交易金额不能为空") | ||||
|     private Integer price; | ||||
|  | ||||
|     /** | ||||
|      * 交易后余额,单位分 | ||||
|      */ | ||||
|     @NotNull(message = "交易后余额不能为空") | ||||
|     private Integer balance; | ||||
|  | ||||
|     /** | ||||
| @ -36,15 +41,19 @@ public class WalletTransactionCreateReqBO { | ||||
|      * | ||||
|      * 枚举 {@link PayWalletBizTypeEnum#getType()} | ||||
|      */ | ||||
|     @NotNull(message = "关联业务分类不能为空") | ||||
|     @InEnum(PayWalletBizTypeEnum.class) | ||||
|     private Integer bizType; | ||||
|  | ||||
|     /** | ||||
|      * 关联业务编号 | ||||
|      */ | ||||
|     @NotEmpty(message = "关联业务编号不能为空") | ||||
|     private String bizId; | ||||
|  | ||||
|     /** | ||||
|      * 流水说明 | ||||
|      */ | ||||
|     @NotEmpty(message = "流水说明不能为空") | ||||
|     private String title; | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 jason
					jason