Răsfoiți Sursa

钱包部分功能

xucaiqin 2 ani în urmă
părinte
comite
70abe71f83

+ 6 - 2
sckw-common/sckw-common-redis/src/main/java/com/sckw/redis/constant/RedisConstant.java

@@ -71,8 +71,12 @@ public class RedisConstant {
      */
     public static final String SETTLEMENT_KEY = "sckw:kst:%s";
     /**
-     * 钱包企业关联关系
+     * 企业关联钱包
      */
-    public static final String WALLET = "wallet:uid";
+    public static final String WALLET_ENT = "wallet:ent";
+    /**
+     * 钱包关联企业
+     */
+    public static final String WALLET_UID = "wallet:uid";
 
 }

+ 45 - 0
sckw-modules/sckw-payment/src/main/java/com/sckw/payment/controller/WalletController.java

@@ -0,0 +1,45 @@
+package com.sckw.payment.controller;
+
+import com.sckw.core.web.response.HttpResult;
+import com.sckw.payment.model.vo.req.WalletDetailReq;
+import com.sckw.payment.service.WalletService;
+import jakarta.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 钱包
+ *
+ * @author xucaiqin
+ * @date 2023-08-28 15:36:48
+ */
+@Validated
+@RestController
+@RequestMapping("/wallet")
+public class WalletController {
+    @Resource
+    private WalletService walletService;
+
+    /**
+     * 钱包总览信息
+     *
+     * @return
+     */
+    @GetMapping("overview")
+    public HttpResult overview() {
+        return HttpResult.ok(walletService.walletOverview());
+    }
+
+    /**
+     * 查询资金明细
+     *
+     * @return
+     */
+    @GetMapping("detail")
+    public HttpResult detail(WalletDetailReq walletDetailReq) {
+        return HttpResult.ok(walletService.walletDetail(walletDetailReq));
+    }
+
+}

+ 1 - 1
sckw-modules/sckw-payment/src/main/java/com/sckw/payment/model/vo/req/AddWalletReq.java

@@ -18,7 +18,7 @@ import java.math.BigDecimal;
 @Setter
 public class AddWalletReq extends BasePara implements MoneyChange {
     /**
-     * 支付通道字典值
+     * 支付通道 huifu
      */
     @NotBlank(message = "支付通道不能为空")
     private String channel;

+ 23 - 0
sckw-modules/sckw-payment/src/main/java/com/sckw/payment/model/vo/req/CashPageReq.java

@@ -0,0 +1,23 @@
+package com.sckw.payment.model.vo.req;
+
+import com.sckw.core.model.vo.BasePara;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 提现记录
+ *
+ * @author xucaiqin
+ * @date 2023-08-29 09:14:04
+ */
+@Getter
+@Setter
+public class CashPageReq extends BasePara {
+    /**
+     * 支付通道 huifu
+     */
+    private String channel;
+
+    private String entName;
+
+}

+ 7 - 5
sckw-modules/sckw-payment/src/main/java/com/sckw/payment/model/vo/req/CashWalletReq.java

@@ -1,6 +1,5 @@
 package com.sckw.payment.model.vo.req;
 
-import com.sckw.core.model.vo.BasePara;
 import com.sckw.payment.model.vo.res.MoneyChange;
 import jakarta.validation.constraints.Digits;
 import jakarta.validation.constraints.NotBlank;
@@ -19,15 +18,18 @@ import java.math.BigDecimal;
  */
 @Getter
 @Setter
-public class CashWalletReq extends BasePara implements MoneyChange {
+public class CashWalletReq implements MoneyChange {
     /**
-     * 支付通道字典值
+     * 支付通道 huifu
      */
     @NotBlank(message = "支付通道不能为空")
     private String channel;
 
-    @NotBlank(message = "合作企业不能为空")
-    private String entId;
+    @NotBlank(message = "uid不能为空")
+    private String uid;
+
+    @NotBlank(message = "filter不能为空")
+    private String filter;
 
     @Positive(message = "提现金额必须大于0")
     @Digits(message = "小数位数过长或金额过大", integer = 10, fraction = 2)

+ 23 - 0
sckw-modules/sckw-payment/src/main/java/com/sckw/payment/model/vo/req/PrePayReq.java

@@ -0,0 +1,23 @@
+package com.sckw.payment.model.vo.req;
+
+import com.sckw.core.model.vo.BasePara;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 预付请求参数
+ *
+ * @author xucaiqin
+ * @date 2023-08-29 09:14:04
+ */
+@Getter
+@Setter
+public class PrePayReq extends BasePara {
+    /**
+     * 支付通道 1
+     */
+    private String channel;
+
+    private String entName;
+
+}

+ 38 - 0
sckw-modules/sckw-payment/src/main/java/com/sckw/payment/model/vo/req/RefundReq.java

@@ -0,0 +1,38 @@
+package com.sckw.payment.model.vo.req;
+
+import com.sckw.payment.model.vo.res.MoneyChange;
+import jakarta.validation.constraints.Digits;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Positive;
+import jakarta.validation.constraints.Size;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+/**
+ * 退款
+ *
+ * @author xucaiqin
+ * @date 2023-08-29 09:14:04
+ */
+@Getter
+@Setter
+public class RefundReq  implements MoneyChange {
+    /**
+     * 支付通道字典值
+     */
+    @NotBlank(message = "支付通道不能为空")
+    private String channel;
+
+    @NotBlank(message = "合作企业不能为空")
+    private String entId;
+
+    @Positive(message = "提现金额必须大于0")
+    @Digits(message = "小数位数过长或金额过大", integer = 10, fraction = 2)
+    private BigDecimal money;
+
+    @Size(message = "备注不能超过200字")
+    private String remark;
+
+}

+ 27 - 2
sckw-modules/sckw-payment/src/main/java/com/sckw/payment/service/KwpWalletRelationService.java

@@ -38,7 +38,7 @@ public class KwpWalletRelationService {
         if (Objects.isNull(entId)) {
             return null;
         }
-        String uid = (String) redisTemplate.opsForHash().get(RedisConstant.WALLET, String.valueOf(entId));
+        String uid = (String) redisTemplate.opsForHash().get(RedisConstant.WALLET_ENT, String.valueOf(entId));
         if (StringUtils.isNotBlank(uid)) {
             return uid;
         }
@@ -49,10 +49,35 @@ public class KwpWalletRelationService {
             return null;
         }
         uid = kwpWalletRelation.getUid();
-        redisTemplate.opsForHash().put(RedisConstant.WALLET, String.valueOf(entId), uid);
+        redisTemplate.opsForHash().put(RedisConstant.WALLET_ENT, String.valueOf(entId), uid);
         return uid;
     }
 
+    /**
+     * 通过中台uid反查关联的企业
+     *
+     * @param uid 中台uid
+     * @return
+     */
+    public Long getEnt(String uid) {
+        if (StringUtils.isBlank(uid)) {
+            return null;
+        }
+        Long entId = (Long) redisTemplate.opsForHash().get(RedisConstant.WALLET_UID, uid);
+        if (Objects.nonNull(entId)) {
+            return entId;
+        }
+        KwpWalletRelation kwpWalletRelation = relationMapper.selectOne(new LambdaQueryWrapper<KwpWalletRelation>()
+                .eq(KwpWalletRelation::getUid, uid)
+                .eq(KwpWalletRelation::getDelFlag, 0).last("limit 1"));
+        if (Objects.isNull(kwpWalletRelation)) {
+            return null;
+        }
+        entId = kwpWalletRelation.getEntId();
+        redisTemplate.opsForHash().put(RedisConstant.WALLET_UID, uid, entId);
+        return entId;
+    }
+
     /**
      * 保存关联信息
      *

+ 1 - 1
sckw-modules/sckw-payment/src/main/java/com/sckw/payment/service/PayCenterService.java

@@ -452,7 +452,7 @@ public class PayCenterService {
      * @param filter
      * @return
      */
-    public R<Object> transfer(String uid, ChannelEnum channel, Long money, String filter) {
+    public R<Object> transfer(String uid, String filter, ChannelEnum channel, Long money) {
         String sync = postHttp(PayCenterEnum.TRANSFER, new HashMap<>() {{
             put("uid", uid);
             put("channel", channel);

+ 324 - 0
sckw-modules/sckw-payment/src/main/java/com/sckw/payment/service/WalletService.java

@@ -0,0 +1,324 @@
+package com.sckw.payment.service;
+
+import com.sckw.core.exception.BusinessException;
+import com.sckw.core.model.page.PageRes;
+import com.sckw.core.utils.CollectionUtils;
+import com.sckw.core.web.context.LoginUserHolder;
+import com.sckw.payment.api.model.constant.ChannelEnum;
+import com.sckw.payment.api.model.dto.Order;
+import com.sckw.payment.api.model.dto.WalletDto;
+import com.sckw.payment.api.model.dto.common.R;
+import com.sckw.payment.api.model.dto.page.CashPage;
+import com.sckw.payment.api.model.dto.page.PrePayIndexPage;
+import com.sckw.payment.model.vo.req.*;
+import com.sckw.payment.model.vo.res.FundVo;
+import com.sckw.payment.model.vo.res.WalletDetail;
+import com.sckw.system.api.RemoteSystemService;
+import com.sckw.system.api.model.dto.res.EntCacheResDto;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 钱包
+ *
+ * @author xucaiqin
+ * @date 2023-08-28 15:38:53
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class WalletService {
+    private final PayCenterService payCenterService;
+    private final KwpWalletRelationService walletRelationService;
+    private final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 2, TimeUnit.MINUTES, new LinkedBlockingQueue<>(12));
+    @DubboReference(version = "1.0.0", group = "design", check = false)
+    private RemoteSystemService remoteSystemService;
+
+    /**
+     * 查询企业钱包总览信息
+     *
+     * @return
+     */
+    public WalletDetail walletOverview() {
+        Long entId = LoginUserHolder.getEntId();
+        String relation = walletRelationService.getRelation(entId);
+        if (StringUtils.isBlank(relation)) {
+            throw new BusinessException("暂未开通电子钱包");
+        }
+        R<List<WalletDto>> wallet = payCenterService.wallet(relation, null, "");
+        long sum = 0;
+        if (wallet.getStatus()) {
+            List<WalletDto> data = CollectionUtils.isEmpty(wallet.getData()) ? new ArrayList<>() : wallet.getData();
+            for (WalletDto datum : data) {
+                sum += datum.getMoney();
+            }
+        }
+        return new WalletDetail(LoginUserHolder.getEntName(), String.valueOf(sum), String.valueOf(sum / 100.0D), 0);
+    }
+
+    /**
+     * 查询资金明细
+     *
+     * @return
+     */
+    public Object walletDetail(WalletDetailReq walletDetailReq) {
+        Long entId = LoginUserHolder.getEntId();
+        String entName = walletDetailReq.getEntName();
+        //todo-xcq 确认下拉选规则参数
+        ChannelEnum channelEnum = null;
+        if (StringUtils.isNotBlank(walletDetailReq.getChannel())) {
+            channelEnum = ChannelEnum.getByValue(walletDetailReq.getChannel());
+            if (Objects.isNull(channelEnum)) {
+                throw new BusinessException("支付通道不存在");
+            }
+        }
+        //查询我方企业开通的渠道
+        String relation = walletRelationService.getRelation(entId);
+        if (StringUtils.isBlank(relation)) {
+            throw new BusinessException("暂未开通电子钱包");
+        }
+        List<WalletDto> res = new ArrayList<>();
+        List<Long> list = new ArrayList<>();
+        //筛选企业名称
+        if (StringUtils.isNotBlank(entName)) {
+            List<EntCacheResDto> entCacheResDto = remoteSystemService.queryEntCacheByName(entName);
+            //未筛选出数据
+            if (CollectionUtils.isEmpty(entCacheResDto)) {
+                return PageRes.handPage(walletDetailReq.getPage(), walletDetailReq.getPageSize(), new ArrayList<>());
+            }
+            list = entCacheResDto.stream().map(EntCacheResDto::getId).toList();
+        }
+
+        //搜索指定往来单位
+        if (!CollectionUtils.isEmpty(list)) {
+            for (Long aLong : list) {
+                R<List<WalletDto>> wallet = payCenterService.wallet(relation, channelEnum, String.valueOf(aLong));
+                if (wallet.getStatus()) {
+                    List<WalletDto> data = wallet.getData();
+                    res.addAll(data);
+                }
+            }
+        } else {
+            //不搜索往来单位
+            R<List<WalletDto>> wallet = payCenterService.wallet(relation, channelEnum, "");
+            if (wallet.getStatus()) {
+                List<WalletDto> data = wallet.getData();
+                res.addAll(data);
+            }
+        }
+        List<FundVo> vo = new ArrayList<>();
+        FundVo fundVo;
+
+        //组装res数据
+        for (WalletDto re : res) {
+            fundVo = new FundVo();
+            BeanUtils.copyProperties(re, fundVo);
+            fundVo.setChannelLabel(ChannelEnum.getDesc(re.getChannel()));
+            vo.add(fundVo);
+        }
+        return PageRes.handPage(walletDetailReq.getPage(), walletDetailReq.getPageSize(), vo);
+    }
+
+
+    /**
+     * 新增账目
+     *
+     * @return
+     */
+    public Object addWallet(AddWalletReq addWalletReq) {
+        Long entId1 = LoginUserHolder.getEntId();
+        String uid = walletRelationService.getRelation(entId1);
+        if (StringUtils.isBlank(uid)) {
+            throw new BusinessException("您暂未开通电子钱包");
+        }
+        String entId = addWalletReq.getEntId();
+        String filter = walletRelationService.getRelation(Long.parseLong(entId));
+        if (StringUtils.isBlank(filter)) {
+            throw new BusinessException("合作单位暂未开通电子钱包");
+        }
+        ChannelEnum channelEnum = ChannelEnum.getByValue(addWalletReq.getChannel());
+        if (Objects.isNull(channelEnum)) {
+            throw new BusinessException("支付通道不能为空");
+        }
+
+        //1.开通钱包
+        R<Object> objectR = payCenterService.walletIndex(uid, channelEnum, filter, "");
+        if (!objectR.getStatus()) {
+            throw new BusinessException(StringUtils.isBlank(objectR.getMsg()) ? "钱包开通失败" : objectR.getMsg());
+        }
+        //2.发起预支付
+        R<Order> orderR = payCenterService.advancePayApply("", channelEnum, filter, addWalletReq.bigMoney(addWalletReq.getMoney()));
+        if (!orderR.getStatus()) {
+            throw new BusinessException(StringUtils.isBlank(orderR.getMsg()) ? "预支付失败" : orderR.getMsg());
+        }
+        return orderR.getData();
+    }
+
+    /**
+     * 账目充值
+     *
+     * @return
+     */
+    public Object addWalletMoney(AddWalletReq addWalletReq) {
+        Long entId1 = LoginUserHolder.getEntId();
+        String uid = walletRelationService.getRelation(entId1);
+        if (StringUtils.isBlank(uid)) {
+            throw new BusinessException("您暂未开通电子钱包");
+        }
+        String entId = addWalletReq.getEntId();
+        String filter = walletRelationService.getRelation(Long.parseLong(entId));
+        if (StringUtils.isBlank(filter)) {
+            throw new BusinessException("合作单位暂未开通电子钱包");
+        }
+        ChannelEnum channelEnum = ChannelEnum.getByValue(addWalletReq.getChannel());
+        if (Objects.isNull(channelEnum)) {
+            throw new BusinessException("支付通道不能为空");
+        }
+        //发起预支付
+        R<Order> orderR = payCenterService.advancePayApply(uid, channelEnum, filter, addWalletReq.bigMoney(addWalletReq.getMoney()));
+        if (!orderR.getStatus()) {
+            throw new BusinessException(StringUtils.isBlank(orderR.getMsg()) ? "预支付失败" : orderR.getMsg());
+        }
+        return orderR.getData();
+    }
+
+    /**
+     * 提现
+     * 1.余额转出
+     * 2.申请提现
+     *
+     * @return
+     */
+    public Object cashOUt(CashWalletReq cashWalletReq) {
+        ChannelEnum byChannel = ChannelEnum.getByChannel(cashWalletReq.getChannel());
+        //余额转出
+        R<Object> transfer = payCenterService.transfer(cashWalletReq.getUid(), cashWalletReq.getFilter(), byChannel, cashWalletReq.bigMoney(cashWalletReq.getMoney()));
+        if (!transfer.getStatus()) {
+            throw new BusinessException(StringUtils.isNotBlank(transfer.getMsg()) ? transfer.getMsg() : "提现异常");
+        }
+        R<Order> orderR = payCenterService.withdrawTake(cashWalletReq.getUid(), byChannel, cashWalletReq.bigMoney(cashWalletReq.getMoney()), cashWalletReq.getRemark());
+        if (!orderR.getStatus()) {
+            throw new BusinessException(StringUtils.isNotBlank(orderR.getMsg()) ? orderR.getMsg() : "申请提现异常");
+        }
+        return orderR.getData();
+    }
+
+    /**
+     * 转账
+     *
+     * @return
+     */
+    public Object transfer() {
+        return null;
+    }
+
+
+    /**
+     * 提现记录
+     *
+     * @return
+     */
+    public Object cashList(CashPageReq cashPageReq) {
+        Long entId = LoginUserHolder.getEntId();
+        String uid = walletRelationService.getRelation(entId);
+        if (StringUtils.isBlank(uid)) {
+            return null;
+        }
+        ChannelEnum channelEnum = null;
+        if (StringUtils.isNotBlank(cashPageReq.getChannel())) {
+            channelEnum = ChannelEnum.getByValue(cashPageReq.getChannel());
+            if (Objects.isNull(channelEnum)) {
+                throw new BusinessException("选择渠道异常");
+            }
+        }
+        String entName = cashPageReq.getEntName();
+        if (StringUtils.isNotBlank(entName)) {
+            //todo 转换企业名称为filter
+
+        }
+        //查询中台接口
+        R<CashPage> cashPageR = payCenterService.withdrawIndex(uid, channelEnum, cashPageReq.getPage(), cashPageReq.getPageSize());
+        if (!cashPageR.getStatus()) {
+            return null;
+        }
+        //组装数据
+        return cashPageR.getData();
+    }
+
+    /**
+     * 预付记录
+     *
+     * @return
+     */
+    public Object prePayList(PrePayReq prePayReq) {
+        Long entId = LoginUserHolder.getEntId();
+        String uid = walletRelationService.getRelation(entId);
+        if (StringUtils.isBlank(uid)) {
+            return null;
+        }
+        ChannelEnum channelEnum = null;
+        if (StringUtils.isNotBlank(prePayReq.getChannel())) {
+            channelEnum = ChannelEnum.getByValue(prePayReq.getChannel());
+            if (Objects.isNull(channelEnum)) {
+                throw new BusinessException("选择渠道异常");
+            }
+        }
+        String entName = prePayReq.getEntName();
+        if (StringUtils.isNotBlank(entName)) {
+            //todo 转换企业名称为 filter
+
+        }
+        //
+        R<PrePayIndexPage> prePayIndexPageR = payCenterService.advancePayIndex(uid, channelEnum, "", prePayReq.getPage(), prePayReq.getPageSize());
+
+        return null;
+    }
+
+    /**
+     * 新增预付
+     *
+     * @return
+     */
+    public Object addPrePay() {
+        return null;
+    }
+
+    /**
+     * 预付追加
+     *
+     * @return
+     */
+    public Object prePayAppend() {
+        return null;
+    }
+
+    /**
+     * 申请退款
+     *
+     * @return
+     */
+    public Object applyRefund(RefundReq refundReq) {
+        return null;
+    }
+
+    /**
+     * 发起退款
+     *
+     * @return
+     */
+    public Object launchRefund() {
+        return null;
+    }
+
+}