Просмотр исходного кода

feature: 补助到账功能
1.补助定时任务到账(写在backstage项目中)
2.对资金收支的业务处理逻辑进行了优化(充值/批量充值、退款/批量退款、补助到账)

luoyb 1 год назад
Родитель
Сommit
8e004679f1
17 измененных файлов с 733 добавлено и 58 удалено
  1. 2 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/RuoYiBackstageApplication.java
  2. 353 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/business/payments/PayBaseBusiness.java
  3. 171 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/business/payments/PayOrderBusiness.java
  4. 1 1
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/business/payments/PaymentsBusiness.java
  5. 1 2
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/business/payments/strategy/PaymentsStrategyContent.java
  6. 1 2
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/cardCenter/controller/PtCardController.java
  7. 16 1
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/cardCenter/domain/vo/PtSubsidyitemVo.java
  8. 4 3
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/cardCenter/mapper/PtSubsidyitemMapper.java
  9. 6 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/cardCenter/service/IPtSubsidyitemService.java
  10. 9 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/cardCenter/service/impl/PtSubsidyitemServiceImpl.java
  11. 0 7
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/consumption/domain/bo/XfCreditAccountBackBo.java
  12. 0 2
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/consumption/service/impl/XfCreditAccountBackServiceImpl.java
  13. 93 29
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/payment/controller/PtBagController.java
  14. 31 9
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/payment/domain/bo/PurseInOutBo.java
  15. 2 2
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/payment/service/impl/PtBagServiceImpl.java
  16. 37 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/task/SubsidyScheduled.java
  17. 6 0
      ruoyi-modules/ruoyi-backstage/src/main/resources/mapper/cardCenter/cardOperation/PtSubsidyitemMapper.xml

+ 2 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/RuoYiBackstageApplication.java

@@ -4,6 +4,7 @@ import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
+import org.springframework.scheduling.annotation.EnableScheduling;
 
 /**
  * 系统模块
@@ -12,6 +13,7 @@ import org.springframework.boot.context.metrics.buffering.BufferingApplicationSt
  */
 @EnableDubbo
 @SpringBootApplication
+@EnableScheduling
 public class RuoYiBackstageApplication {
     public static void main(String[] args) {
         SpringApplication application = new SpringApplication(RuoYiBackstageApplication.class);

+ 353 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/business/payments/PayBaseBusiness.java

@@ -0,0 +1,353 @@
+package org.dromara.backstage.business.payments;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.backstage.basics.domain.vo.PtWorkstationVo;
+import org.dromara.backstage.basics.service.IPtWorkstationService;
+import org.dromara.backstage.cardCenter.domain.bo.PtSubsidyitemBo;
+import org.dromara.backstage.cardCenter.domain.vo.PtCardVo;
+import org.dromara.backstage.cardCenter.domain.vo.PtSubsidyitemVo;
+import org.dromara.backstage.cardCenter.service.IPtCardService;
+import org.dromara.backstage.cardCenter.service.IPtSubsidyitemService;
+import org.dromara.backstage.consumption.domain.bo.XfCreditAccountBackBo;
+import org.dromara.backstage.consumption.domain.bo.XfCreditAccountBo;
+import org.dromara.backstage.consumption.domain.bo.XfUserTotalBo;
+import org.dromara.backstage.consumption.domain.vo.XfCreditAccountBackVo;
+import org.dromara.backstage.consumption.domain.vo.XfCreditAccountVo;
+import org.dromara.backstage.consumption.domain.vo.XfTermVo;
+import org.dromara.backstage.consumption.domain.vo.XfUserTotalVo;
+import org.dromara.backstage.consumption.service.IXfCreditAccountBackService;
+import org.dromara.backstage.consumption.service.IXfCreditAccountService;
+import org.dromara.backstage.consumption.service.IXfTermService;
+import org.dromara.backstage.consumption.service.IXfUserTotalService;
+import org.dromara.backstage.payment.domain.bo.PtBagBo;
+import org.dromara.backstage.payment.domain.bo.PurseInOutBo;
+import org.dromara.backstage.payment.domain.vo.PtBagVo;
+import org.dromara.backstage.payment.domain.vo.PtUserAccountVo;
+import org.dromara.backstage.payment.service.IPtBagService;
+import org.dromara.backstage.payment.service.IPtUserAccountService;
+import org.dromara.common.core.enums.CreditStatusEnum;
+import org.dromara.common.core.enums.CreditTypeEnum;
+import org.dromara.common.core.exception.consume.ConsumeException;
+import org.dromara.common.core.exception.payments.PaymentsException;
+import org.dromara.common.core.utils.MessageUtils;
+import org.dromara.common.core.utils.RecordIdUtils;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.text.MessageFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * name: PayBaseBusiness
+ * package: org.dromara.backstage.business.payments
+ * description: 资金收支业务基础逻辑处理
+ * date: 2024-10-30 07:42:46 07:42
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@RequiredArgsConstructor
+@Service
+@Slf4j
+public class PayBaseBusiness {
+    private final IPtWorkstationService workstationService;
+    private final IPtUserAccountService userAccountService;
+    private final IXfTermService termService;
+    private final IPtCardService cardService;
+    private final IPtBagService bagService;
+    private final IXfCreditAccountBackService creditAccountBackService;
+    private final IXfCreditAccountService creditAccountService;
+    private final IXfUserTotalService userTotalService;
+    private final IPtSubsidyitemService subsidyItemService;
+    /**
+     * 检查资金收支的账户信息,资金收支必须有对应的收支账户
+     * @param orderBo 资金收支业务对象
+     * @return 账户信息
+     */
+    public PtUserAccountVo checkUserAccount(PurseInOutBo orderBo){
+        PtUserAccountVo userAccountVo = userAccountService.queryById(orderBo.getUserId());
+        if(ObjUtil.isEmpty(userAccountVo)){
+            throw new PaymentsException(MessageFormat.format("无此账户信息,账户Id:{0}",orderBo.getUserId()));
+        }
+        return userAccountVo;
+    }
+
+    /**
+     * 检查资金收支对应的卡片信息,只要开通了一卡通账户就可以资金收支,因此卡片信息是可能为空的
+     * @param orderBo 资金收支业务对象
+     * @return 卡片信息
+     */
+    public PtCardVo checkUserCard(PurseInOutBo orderBo){
+        PtCardVo ptCardVo;
+        if (orderBo.getCardId() != null && orderBo.getCardId() > 0) {
+            //如果传入了cardId,根据cardId查询卡片信息
+            ptCardVo = cardService.queryById(orderBo.getCardId());
+        } else {
+            //查询当前人的正常主卡
+            ptCardVo = cardService.queryMainCardByUserId(orderBo.getUserId());
+        }
+        return ptCardVo;
+    }
+
+    /**
+     * 检查资金收支钱包信息,资金收支必须有对应的收支钱包
+     * @param orderBo 资金收支业务对象
+     * @return 钱包信息
+     */
+    public PtBagVo checkUserBag(PurseInOutBo orderBo){
+        PtBagVo ptBagVo = bagService.queryByUserBagCode(orderBo.getUserId(), orderBo.getBagCode());
+        if(ObjUtil.isEmpty(ptBagVo)){
+            throw new PaymentsException(MessageFormat.format("无此账户钱包信息,账户Id:{0},钱包代码:{1}",orderBo.getUserId(),orderBo.getBagCode()));
+        }
+        return ptBagVo;
+    }
+
+    /**
+     * 检查资金收支消费设备信息,有些收支操作是通过专用消费机操作的,设备信息有可能为空
+     * @param orderBo 资金收支业务对象
+     * @return 设备信息
+     */
+    public XfTermVo checkTerm(PurseInOutBo orderBo){
+        if(orderBo.getTermNo()==null || orderBo.getTermNo()==0L){
+            return null;
+        }
+        return termService.queryByNo(orderBo.getTermNo());
+    }
+
+    /**
+     * 检查资金收支消费工作站信息,有些收支操作是通过工作站操作,工作站信息有可能为空
+     * @param orderBo 资金收支业务对象
+     * @return 工作站信息
+     */
+    public PtWorkstationVo checkWorkStation(PurseInOutBo orderBo){
+        if(orderBo.getStationId()==null || orderBo.getStationId()==0L){
+            return null;
+        }
+        //这里的工作站Id实际上对应的是工作站的编号
+        return workstationService.queryById(orderBo.getStationId());
+    }
+
+    /**
+     * 计算收支操作后的钱包余额
+     * @param bagVo 钱包信息
+     * @param orderBo 收支订单业务对象
+     */
+    public void calculateBalance(PtBagVo bagVo,PurseInOutBo orderBo){
+        if (Objects.requireNonNull(orderBo.getCreditType()) == CreditTypeEnum.TERM_CONSUME) {
+            //管理费实际是不扣钱包余额的
+            orderBo.setBalance(bagVo.getBalance());
+        } else {
+            orderBo.setBalance(bagVo.getBalance().add(orderBo.getReceiptMoney()));
+        }
+    }
+    /**
+     * 收支入账前校验收支原始记录
+     *
+     * @param originalId 原始记录Id
+     */
+    public void ValidOriginalRecord(String originalId) {
+        String message;
+        XfCreditAccountBackVo xfCreditaccountbackVo = creditAccountBackService.queryById(originalId);
+        if (ObjUtil.isEmpty(xfCreditaccountbackVo)) {
+            message = MessageUtils.message("payments.OriginalRecord.get", originalId);
+            throw new PaymentsException("[资金收支]-[原始记录]", message);
+        }
+        String accountId = xfCreditaccountbackVo.getCreditId();
+        if (StrUtil.isNotEmpty(accountId)) {
+            message = MessageUtils.message("payments.OriginalRecord.isPost", originalId, accountId);
+            throw new PaymentsException("[资金收支]-[原始记录]", message);
+        }
+    }
+    /**
+     * 生成原始收支记录(收支流水备份表)
+     *
+     * @param bo            资金收支信息
+     * @param accountVo     资金收支账户信息
+     * @param cardVo        资金收支卡片信息
+     * @param termVo        资金收支消费设备信息
+     * @param workstationVo 资金收支工作站信息
+     * @return 原始收支记录
+     */
+    public XfCreditAccountBackVo createOriginalRecord(PurseInOutBo bo, PtUserAccountVo accountVo, PtCardVo cardVo, PtBagVo bagVo, XfTermVo termVo, PtWorkstationVo workstationVo) {
+        XfCreditAccountBackBo xfCreditaccountbackBo = new XfCreditAccountBackBo();
+        String backId = getRecordKeyId(bo, accountVo, bagVo);
+        xfCreditaccountbackBo.setBackId(backId);
+
+        //设置交易数据
+        xfCreditaccountbackBo.setCreditTime(new Date());
+        xfCreditaccountbackBo.setCreditType(bo.getCreditType().code().toString());
+        xfCreditaccountbackBo.setReceiptMoney(bo.getReceiptMoney());
+        xfCreditaccountbackBo.setPayStyle(bo.getPayStyle());
+        xfCreditaccountbackBo.setCreditStatus(CreditStatusEnum.CREATE.code());
+        xfCreditaccountbackBo.setUseType(bo.getUseType().code());
+        xfCreditaccountbackBo.setOperatorId(bo.getOperatorId());
+
+        //设置交易人数据
+        xfCreditaccountbackBo.setUserId(bo.getUserId());
+
+        //设置交易卡片数据mq
+        if (ObjUtil.isNotEmpty(cardVo)) {
+            xfCreditaccountbackBo.setCardNo(cardVo.getCardNo());
+        }
+        //设置账户钱包信息
+        xfCreditaccountbackBo.setBagType(bagVo.getBagCode());
+        xfCreditaccountbackBo.setCardValue(bo.getBalance());
+
+        //设置交易设备信息
+        if (ObjUtil.isNotEmpty(termVo)) {
+            xfCreditaccountbackBo.setTermNo(termVo.getTermNo());
+            xfCreditaccountbackBo.setTermRecordId(bo.getTermRecordId());
+        }
+
+        //设置交易工作站信息
+        if (ObjUtil.isNotEmpty(workstationVo)) {
+            xfCreditaccountbackBo.setStationId(workstationVo.getStationId());
+        }
+
+        XfCreditAccountBackVo creditAccountBackVo = creditAccountBackService.createOriginalRecord(xfCreditaccountbackBo);
+        if (ObjUtil.isEmpty(creditAccountBackVo)) {
+            String message = MessageUtils.message("payments.OriginalRecord.create", JSONUtil.parse(bo));
+            throw new PaymentsException("资金收支-原始记录", message);
+        }
+        return creditAccountBackVo;
+    }
+
+    /**
+     * 收支记账(收支流水表)
+     *
+     * @param bo            资金收支信息
+     * @param accountVo     资金收支账户信息
+     * @param cardVo        资金收支卡片信息
+     * @param termVo        资金收支消费设备信息
+     * @param workstationVo 资金收支工作站信息
+     * @param originalId    原始收支记录Id(收支备份表主键)
+     * @return 正式收支记录
+     */
+    public XfCreditAccountVo keepAccounts(PurseInOutBo bo, PtUserAccountVo accountVo, PtCardVo cardVo, PtBagVo bagVo, XfTermVo termVo, PtWorkstationVo workstationVo, String originalId) {
+        XfCreditAccountBo xfCreditaccountbo = new XfCreditAccountBo();
+        String accountId = getRecordKeyId(bo, accountVo, bagVo);
+        xfCreditaccountbo.setCreditId(accountId);
+
+        //设置交易数据
+        xfCreditaccountbo.setCreditTime(DateUtil.date());
+        xfCreditaccountbo.setCreditType(bo.getCreditType().code().toString());
+        xfCreditaccountbo.setReceiptMoney(bo.getReceiptMoney());
+        xfCreditaccountbo.setPayStyle(bo.getPayStyle());
+        xfCreditaccountbo.setUseType(bo.getUseType().code());
+
+        //设置交易账户信息
+        xfCreditaccountbo.setUserId(accountVo.getUserId());
+        xfCreditaccountbo.setUserNumb(accountVo.getUserNumb());
+        xfCreditaccountbo.setRealName(accountVo.getRealName());
+        xfCreditaccountbo.setDeptId(accountVo.getDeptId());
+        xfCreditaccountbo.setDeptName(accountVo.getDeptName());
+        //设置设备信息
+        if(ObjUtil.isNotEmpty(termVo)) {
+            xfCreditaccountbo.setTermNo(termVo.getTermNo());
+            xfCreditaccountbo.setTermName(termVo.getTermName());
+            xfCreditaccountbo.setTermRecordId(bo.getTermRecordId());
+        }
+        if(ObjUtil.isNotEmpty(workstationVo)) {
+            //设置工作站信息
+            xfCreditaccountbo.setStationNumb(workstationVo.getStationNumb());
+            xfCreditaccountbo.setStationName(workstationVo.getStationName());
+        }
+        //设置卡片信息
+        xfCreditaccountbo.setCardNo(cardVo.getCardNo());
+        xfCreditaccountbo.setCardValue(bo.getBalance());
+        xfCreditaccountbo.setCardType(cardVo.getCardType());
+        xfCreditaccountbo.setCardCount(bagVo.getRechargeCount() + 1);
+        xfCreditaccountbo.setCardTypeName(cardVo.getCardTypeName());
+        xfCreditaccountbo.setMainCard(cardVo.getMainCard());
+        //设置钱包信息
+        xfCreditaccountbo.setBagType(bagVo.getBagCode());
+        // 设置操作员信息
+        xfCreditaccountbo.setOperatorId(bo.getOperatorId());
+        xfCreditaccountbo.setOperatorName(bo.getOperatorName());
+
+        xfCreditaccountbo.setOriginalId(originalId);
+
+        XfCreditAccountVo creditAccountVo = creditAccountService.keepAccounts(xfCreditaccountbo);
+        if (ObjUtil.isEmpty(creditAccountVo)) {
+            String message = MessageUtils.message("payments.keepAccounts.create", originalId);
+            throw new PaymentsException("资金收支-收支入账", message);
+        }
+        return creditAccountVo;
+    }
+
+    /**
+     * 处理个人日统计表
+     * @param bo 收支信息
+     * @param accountVo 账户信息
+     * @param cardVo 账户卡片信息
+     */
+    public void createOrUpdateUserTotal(PurseInOutBo bo, PtUserAccountVo accountVo, PtCardVo cardVo) {
+        XfUserTotalBo xfUserTotalBo = new XfUserTotalBo();
+        xfUserTotalBo.setUserId(accountVo.getUserId());
+        xfUserTotalBo.setUserNumb(accountVo.getUserNumb());
+        xfUserTotalBo.setRealName(accountVo.getRealName());
+        xfUserTotalBo.setDeptName(accountVo.getDeptName());
+        xfUserTotalBo.setCardNo(cardVo.getCardNo());
+        xfUserTotalBo.setDateDay(DateUtil.format(new Date(), "yyyy-MM-dd"));
+        xfUserTotalBo.setUseType(bo.getUseType().code());
+        xfUserTotalBo.setCreditMoney(bo.getReceiptMoney());
+
+        userTotalService.createOrUpdateUserTotal(xfUserTotalBo);
+    }
+
+    /**
+     * 更新钱包余额
+     * @param bo 收支业务对象
+     * @return 更新后钱包余额
+     */
+    public PtBagVo updateBalance(PurseInOutBo bo) {
+        PtBagBo bagBo = BeanUtil.copyProperties(bo, PtBagBo.class);
+        return bagService.updateBalanceByBo(bagBo);
+    }
+
+    /**
+     * 更新原始订单的入账状态
+     * @param bo 收支信息
+     * @param status 入账状态
+     * @param cardValue 入账后账户余额
+     */
+    public void updateOriginalOrderStatus(PurseInOutBo bo, Integer status, BigDecimal cardValue) {
+        creditAccountBackService.updateStatusById(bo.getOriginalId(), status, bo.getCreditId(), cardValue);
+    }
+
+    public List<PtSubsidyitemVo> selectPostSubsidyItem(){
+        return subsidyItemService.selectPostSubsidyItem();
+    }
+    public boolean updatePostSubsidyItemStatus(PtSubsidyitemBo bo){
+        return subsidyItemService.updateByBo(bo);
+    }
+    /**
+     * 生成资金收支备份表和收支表的32位主键Id
+     *
+     * @param bo        资金收支信息
+     * @param accountVo 人员账户信息
+     * @param bagVo     账户钱包信息
+     * @return 生成的记录Id
+     */
+    @NotNull
+    private String getRecordKeyId(PurseInOutBo bo, PtUserAccountVo accountVo, PtBagVo bagVo) {
+        BigDecimal a = new BigDecimal(100);
+        int key3 = 0;
+        if (bo.getReceiptMoney().compareTo(BigDecimal.ZERO) > 0) {
+            key3 = bo.getReceiptMoney().multiply(a).intValue();
+        } else {
+            key3 = bo.getReceiptMoney().negate().multiply(a).intValue();
+        }
+        return RecordIdUtils.getRecordId(new Date(), Short.parseShort(bo.getCreditType().code().toString()), Integer.parseInt(accountVo.getUserNo().toString()), key3, Integer.parseInt(bagVo.getBagCode()));
+    }
+}

+ 171 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/business/payments/PayOrderBusiness.java

@@ -0,0 +1,171 @@
+package org.dromara.backstage.business.payments;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.hutool.json.JSONUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.backstage.basics.domain.vo.PtWorkstationVo;
+import org.dromara.backstage.cardCenter.domain.bo.PtSubsidyitemBo;
+import org.dromara.backstage.cardCenter.domain.vo.PtCardVo;
+import org.dromara.backstage.cardCenter.domain.vo.PtSubsidyitemVo;
+import org.dromara.backstage.cardCenter.service.IPtSubsidyitemService;
+import org.dromara.backstage.consumption.domain.vo.XfCreditAccountBackVo;
+import org.dromara.backstage.consumption.domain.vo.XfCreditAccountVo;
+import org.dromara.backstage.consumption.domain.vo.XfTermVo;
+import org.dromara.backstage.payment.domain.bo.PurseInOutBo;
+import org.dromara.backstage.payment.domain.vo.PtBagVo;
+import org.dromara.backstage.payment.domain.vo.PtUserAccountVo;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.enums.BalanceUpdateEnum;
+import org.dromara.common.core.enums.CreditStatusEnum;
+import org.dromara.common.core.enums.CreditTypeEnum;
+import org.dromara.common.core.enums.SystemUseTypeEnum;
+import org.dromara.common.core.exception.consume.ConsumeException;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * name: PayOrderBusiness
+ * package: org.dromara.backstage.business.payments
+ * description: 和资金收支相关的订单处理逻辑
+ * date: 2024-10-29 22:43:50 22:43
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@RequiredArgsConstructor
+@Service
+@Slf4j
+public class PayOrderBusiness {
+
+    private final PayBaseBusiness payBaseBusiness;
+    public XfCreditAccountBackVo createOrder(PurseInOutBo orderBo) {
+        log.info("[{}订单信息验证-[{}]",orderBo.getCreditType().message(), JSONUtil.toJsonStr(orderBo));
+        // 获取创建订单的辅助信息
+        PtUserAccountVo userAccountVo = payBaseBusiness.checkUserAccount(orderBo);
+        PtCardVo userCardVo = payBaseBusiness.checkUserCard(orderBo);
+        PtBagVo userBagVo = payBaseBusiness.checkUserBag(orderBo);
+        XfTermVo termVo = payBaseBusiness.checkTerm(orderBo);
+        PtWorkstationVo workstationVo = payBaseBusiness.checkWorkStation(orderBo);
+
+        // 生成原始订单记录
+        // 生成原始订单记录前先计算收支后的钱包余额,这里只是记录下收支完成后的钱包应有余额,但还没有实际更新钱包余额
+        log.info("[{}订单验证通过,创建订单]-[{}]",orderBo.getCreditType().message(), JSONUtil.toJsonStr(orderBo));
+        payBaseBusiness.calculateBalance(userBagVo,orderBo);
+        return payBaseBusiness.createOriginalRecord(orderBo, userAccountVo,
+            userCardVo, userBagVo, termVo, workstationVo);
+    }
+
+    @Transactional(rollbackFor = ConsumeException.class)
+    public PtBagVo postOrder(PurseInOutBo orderBo) {
+        payBaseBusiness.ValidOriginalRecord(orderBo.getOriginalId());
+        // 获取入库订单的辅助信息
+        PtUserAccountVo userAccountVo = payBaseBusiness.checkUserAccount(orderBo);
+        PtCardVo userCardVo = payBaseBusiness.checkUserCard(orderBo);
+        PtBagVo userBagVo = payBaseBusiness.checkUserBag(orderBo);
+        XfTermVo termVo = payBaseBusiness.checkTerm(orderBo);
+        PtWorkstationVo workstationVo = payBaseBusiness.checkWorkStation(orderBo);
+        // 生成收支明细表
+        log.info("[{}订单处理收支明细]-[{}]",orderBo.getCreditType().message(), JSONUtil.toJsonStr(orderBo));
+        XfCreditAccountVo orderDetailVo = payBaseBusiness.keepAccounts(orderBo, userAccountVo, userCardVo, userBagVo, termVo, workstationVo, orderBo.getOriginalId());
+        orderBo.setCreditId(orderDetailVo.getCreditId());
+
+        //如果交易类型不为收管理费,则继续下面的操作以完成订单入库
+        if(!orderBo.getCreditType().equals(CreditTypeEnum.COMMISSION_CHARGE)){
+            // TODO 2024-10-29 22:54:57 luoyibo 处理个人日统计表
+            log.info("[{}订单处理人日统计表]-[{}]",orderBo.getCreditType().message(), JSONUtil.toJsonStr(orderBo));
+            payBaseBusiness.createOrUpdateUserTotal(orderBo, userAccountVo, userCardVo);
+
+            // TODO 2024-10-29 22:55:48 luoyibo 更新个人钱包余额
+            log.info("[{}订单处理钱包余额]-[{}]",orderBo.getCreditType().message(), JSONUtil.toJsonStr(orderBo));
+            PtBagVo afterBagVo = payBaseBusiness.updateBalance(orderBo);
+
+            // TODO 2024-10-30 14:43:15 luoyibo 入账成功,更新原始订单的入账状态
+            log.info("[{}订单更新入账状态]-[{}]",orderBo.getCreditType().message(), JSONUtil.toJsonStr(orderBo));
+            payBaseBusiness.updateOriginalOrderStatus(orderBo, CreditStatusEnum.SUCCESS.code(), afterBagVo.getBalance());
+
+            return afterBagVo;
+        }
+        return null;
+    }
+
+    @Transactional(rollbackFor = ConsumeException.class)
+    public R<Object> createNormalOrder(PurseInOutBo orderBo) {
+        //将收支请求写入原始收支记录表
+        log.info("[准备创建{}订单-[{}]",orderBo.getCreditType().message(), JSONUtil.toJsonStr(orderBo));
+        XfCreditAccountBackVo OriginalOrder = createOrder(orderBo);
+        orderBo.setOriginalId(OriginalOrder.getBackId());
+
+        //原始收支记录成功,收支入账
+        log.info("[{}订单入账]-[{}]",orderBo.getCreditType().message(), JSONUtil.toJsonStr(orderBo));
+        PtBagVo result = postOrder(orderBo);
+
+        return R.ok(result);
+    }
+    @Transactional(rollbackFor = ConsumeException.class)
+    public R<Object> createSubsidyOrder(){
+        List<String> infoList = new ArrayList<>();
+        Map<String, Integer> mapCount = new HashMap<>();
+        mapCount.put("successCount",0);
+        mapCount.put("errorCount",0);
+
+        List<PtSubsidyitemVo> list = payBaseBusiness.selectPostSubsidyItem();
+        if(ObjUtil.isEmpty(list)||list.size()<=0){
+            return R.ok("没有需要入账的补助明细");
+        }
+        list.forEach(item->{
+            PurseInOutBo orderBo = createSubsidyPostBo(item);
+            int successCount;
+            int errorCount;
+
+            try {
+                R<Object> result = createNormalOrder(orderBo);
+                if (result.getCode() == R.SUCCESS) {
+                    successCount = mapCount.get("successCount");
+                    successCount ++;
+                    mapCount.put("successCount",successCount);
+                    item.setGetDate(DateUtil.date());
+                    item.setFillStatus("Y");
+                    PtSubsidyitemBo bo = BeanUtil.copyProperties(item, PtSubsidyitemBo.class);
+                    payBaseBusiness.updatePostSubsidyItemStatus(bo);
+                } else {
+                    errorCount = mapCount.get("errorCount");
+                    errorCount ++;
+                    mapCount.put("errorCount",errorCount);
+                    infoList.add(MessageFormat.format("[补助到账失败]-[补助信息:{0}]-[错误信息:{1}]", JSONUtil.toJsonStr(orderBo), result.getData().toString()));
+                }
+            } catch (Exception e) {
+                infoList.add(MessageFormat.format("[补助到账失败]-[补助信息:{0}]-[错误信息:{1}]", JSONUtil.toJsonStr(orderBo), e.getMessage()));
+            }
+        });
+        log.info("补助到账完成,成功[{}]条,失败[{}]条", mapCount.get("successCount"), mapCount.get("errorCount"));
+        infoList.forEach(log::error);
+        return R.ok();
+    }
+
+    public static PurseInOutBo createSubsidyPostBo(PtSubsidyitemVo item) {
+        PurseInOutBo orderBo = new PurseInOutBo();
+        orderBo.setUserId(item.getUserId());
+        orderBo.setBagCode(item.getBagCode());
+        orderBo.setPayStyle("4");
+        orderBo.setTakeCommission("0");
+        orderBo.setReceiptMoney(item.getFillMoney());
+        orderBo.setOperationMode(BalanceUpdateEnum.RECHARGE);
+        orderBo.setCreditType(CreditTypeEnum.SUBSIDY_MACHINE_RECHARGE);
+        orderBo.setOperatorId(item.getOperatorId());
+        orderBo.setOperatorName(item.getOperatorName());
+        orderBo.setUseType(SystemUseTypeEnum.CONSUME);
+
+        return orderBo;
+    }
+
+}

+ 1 - 1
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/business/payments/PaymentsBusiness.java

@@ -126,7 +126,7 @@ public class PaymentsBusiness {
         //设置交易卡片数据mq
         if (ObjUtil.isNotEmpty(cardVo)) {
             xfCreditaccountbackBo.setCardNo(cardVo.getCardNo());
-            xfCreditaccountbackBo.setMainCard(cardVo.getMainCard());
+            //xfCreditaccountbackBo.setMainCard(cardVo.getMainCard());
         }
         //设置账户钱包信息
         xfCreditaccountbackBo.setBagType(bagVo.getBagCode());

+ 1 - 2
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/business/payments/strategy/impl/PaymentsStrategyContent.java → ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/business/payments/strategy/PaymentsStrategyContent.java

@@ -1,6 +1,5 @@
-package org.dromara.backstage.business.payments.strategy.impl;
+package org.dromara.backstage.business.payments.strategy;
 
-import org.dromara.backstage.business.payments.strategy.IPaymentsStrategy;
 import org.dromara.backstage.payment.domain.bo.PtBagBo;
 import org.dromara.backstage.payment.domain.vo.PtBagVo;
 import org.springframework.beans.factory.annotation.Autowired;

+ 1 - 2
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/cardCenter/controller/PtCardController.java

@@ -6,7 +6,7 @@ import jakarta.servlet.http.HttpServletResponse;
 import jakarta.validation.constraints.NotEmpty;
 import jakarta.validation.constraints.NotNull;
 import lombok.RequiredArgsConstructor;
-import org.dromara.backstage.business.payments.strategy.impl.PaymentsStrategyContent;
+import org.dromara.backstage.business.payments.strategy.PaymentsStrategyContent;
 import org.dromara.backstage.cardCenter.domain.bo.PtCardBo;
 import org.dromara.backstage.cardCenter.domain.vo.PtCardVo;
 import org.dromara.backstage.cardCenter.service.IPtCardService;
@@ -17,7 +17,6 @@ import org.dromara.common.core.constant.Constants;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.core.enums.CreditTypeEnum;
 import org.dromara.common.core.enums.SystemUseTypeEnum;
-import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.validate.AddGroup;
 import org.dromara.common.core.validate.EditGroup;
 import org.dromara.common.excel.utils.ExcelUtil;

+ 16 - 1
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/cardCenter/domain/vo/PtSubsidyitemVo.java

@@ -1,5 +1,6 @@
 package org.dromara.backstage.cardCenter.domain.vo;
 
+import java.math.BigDecimal;
 import java.util.Date;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import org.dromara.backstage.cardCenter.domain.PtSubsidyitem;
@@ -58,7 +59,7 @@ public class PtSubsidyitemVo implements Serializable {
      * 补助金额
      */
     @ExcelProperty(value = "补助金额")
-    private Long fillMoney;
+    private BigDecimal fillMoney;
 
     /**
      * 预计到账时间
@@ -115,6 +116,10 @@ public class PtSubsidyitemVo implements Serializable {
     @ExcelProperty(value = "部门名称")
     private String deptName;
 
+    /*
+     * 入账钱包
+     */
+    private String bagCode;
     /**
      * 备注
      */
@@ -130,4 +135,14 @@ public class PtSubsidyitemVo implements Serializable {
 
     @ExcelProperty(value = "补助名称")
     private String subsidyName;
+
+    /**
+     * 操作员Id
+     */
+    private Long operatorId;
+
+    /**
+     * 操作员姓名
+     */
+    private String operatorName;
 }

+ 4 - 3
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/cardCenter/mapper/PtSubsidyitemMapper.java

@@ -2,7 +2,6 @@ package org.dromara.backstage.cardCenter.mapper;
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import org.apache.ibatis.annotations.Param;
-import org.dromara.backstage.basics.domain.PtOperator;
 import org.dromara.backstage.cardCenter.domain.PtSubsidyitem;
 import org.dromara.backstage.cardCenter.domain.bo.PtSubsidyReportBo;
 import org.dromara.backstage.cardCenter.domain.bo.PtSubsidyitemBo;
@@ -22,7 +21,9 @@ public interface PtSubsidyitemMapper extends BaseMapperPlus<PtSubsidyitem, PtSub
     Page<PtSubsidyitemVo> customPageList(Page<PtSubsidyitem> page, PtSubsidyitemBo bo
         , @Param("beginFillDate") String beginFillDate, @Param("endFillDate") String endFillDate);
 
-    List<PtSubsidyReportVo> queryReportList(@Param("bo")PtSubsidyReportBo bo);
-    Page<PtSubsidyReportVo> queryReportPageList(@Param("page") Page<PtSubsidyReportVo> page, @Param("bo")PtSubsidyReportBo bo);
+    List<PtSubsidyReportVo> queryReportList(@Param("bo") PtSubsidyReportBo bo);
 
+    Page<PtSubsidyReportVo> queryReportPageList(@Param("page") Page<PtSubsidyReportVo> page, @Param("bo") PtSubsidyReportBo bo);
+
+    List<PtSubsidyitemVo> selectPostSubsidyItem(@Param("justDate") String justDate);
 }

+ 6 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/cardCenter/service/IPtSubsidyitemService.java

@@ -71,4 +71,10 @@ public interface IPtSubsidyitemService {
      * @return 是否删除成功
      */
     Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+
+    /**
+     * 查询入账的补助明细
+     * @return 补助明细
+     */
+    List<PtSubsidyitemVo> selectPostSubsidyItem();
 }

+ 9 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/cardCenter/service/impl/PtSubsidyitemServiceImpl.java

@@ -1,5 +1,6 @@
 package org.dromara.backstage.cardCenter.service.impl;
 
+import cn.hutool.core.date.DateUtil;
 import org.dromara.backstage.basics.domain.bo.PtAccountBo;
 import org.dromara.backstage.basics.domain.vo.PtAccountVo;
 import org.dromara.backstage.basics.mapper.PtAccountMapper;
@@ -188,4 +189,12 @@ public class PtSubsidyitemServiceImpl implements IPtSubsidyitemService {
         }
         return baseMapper.deleteByIds(ids) > 0;
     }
+    /**
+     * 查询入账的补助明细
+     * @return 补助明细
+     */
+    @Override
+    public List<PtSubsidyitemVo> selectPostSubsidyItem() {
+        return baseMapper.selectPostSubsidyItem(DateUtil.date().toString("yyyy-MM-dd HH:mm:ss"));
+    }
 }

+ 0 - 7
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/consumption/domain/bo/XfCreditAccountBackBo.java

@@ -32,7 +32,6 @@ public class XfCreditAccountBackBo extends BaseEntity {
     /**
      * 记录Id
      */
-    @NotNull(message = "记录Id不能为空", groups = { AddGroup.class, EditGroup.class })
     private Long recordId;
 
     /**
@@ -60,21 +59,15 @@ public class XfCreditAccountBackBo extends BaseEntity {
      */
     private BigDecimal cardValue;
 
-    /**
-     * 是否主卡,见sys_yes_no字典类别
-     */
-    private String mainCard;
 
     /**
      * 钱包类型
      */
-    @NotBlank(message = "钱包类型不能为空", groups = { AddGroup.class, EditGroup.class })
     private String bagType;
 
     /**
      * 使用类型,100-消费系统
      */
-    @NotNull(message = "使用类型,100-消费系统不能为空", groups = { AddGroup.class, EditGroup.class })
     private Integer useType;
 
     /**

+ 0 - 2
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/consumption/service/impl/XfCreditAccountBackServiceImpl.java

@@ -81,7 +81,6 @@ public class XfCreditAccountBackServiceImpl implements IXfCreditAccountBackServi
         lqw.eq(bo.getTermRecordId() != null, XfCreditAccountBack::getTermRecordId, bo.getTermRecordId());
         lqw.eq(bo.getCardNo() != null, XfCreditAccountBack::getCardNo, bo.getCardNo());
         lqw.eq(bo.getCardValue() != null, XfCreditAccountBack::getCardValue, bo.getCardValue());
-        lqw.eq(StringUtils.isNotBlank(bo.getMainCard()), XfCreditAccountBack::getMainCard, bo.getMainCard());
         lqw.eq(StringUtils.isNotBlank(bo.getBagType()), XfCreditAccountBack::getBagType, bo.getBagType());
         lqw.eq(bo.getUseType() != null, XfCreditAccountBack::getUseType, bo.getUseType());
         lqw.eq(bo.getStationId() != null, XfCreditAccountBack::getStationId, bo.getStationId());
@@ -90,7 +89,6 @@ public class XfCreditAccountBackServiceImpl implements IXfCreditAccountBackServi
         lqw.eq(StringUtils.isNotBlank(bo.getCreditType()), XfCreditAccountBack::getCreditType, bo.getCreditType());
         lqw.eq(StringUtils.isNotBlank(bo.getPayStyle()), XfCreditAccountBack::getPayStyle, bo.getPayStyle());
         lqw.eq(bo.getReceiptMoney() != null, XfCreditAccountBack::getReceiptMoney, bo.getReceiptMoney());
-        //lqw.eq(bo.getCreditStatus() != null, XfCreditaccountback::getCreditStatus, bo.getCreditStatus());
         lqw.eq(bo.getGroupId() != null, XfCreditAccountBack::getGroupId, bo.getGroupId());
         lqw.eq(StringUtils.isNotBlank(bo.getCreditId()), XfCreditAccountBack::getCreditId, bo.getCreditId());
         lqw.eq(StringUtils.isNotBlank(bo.getOriginalId()), XfCreditAccountBack::getOriginalId, bo.getOriginalId());

+ 93 - 29
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/payment/controller/PtBagController.java

@@ -2,20 +2,23 @@ package org.dromara.backstage.payment.controller;
 
 import cn.dev33.satoken.annotation.SaCheckPermission;
 import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.json.JSONUtil;
 import jakarta.servlet.http.HttpServletResponse;
 import jakarta.validation.constraints.NotEmpty;
 import jakarta.validation.constraints.NotNull;
 import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.dromara.backstage.business.errfill.ErrFillBusiness;
-import org.dromara.backstage.business.payments.strategy.impl.PaymentsStrategyContent;
+import org.dromara.backstage.business.payments.PayOrderBusiness;
+import org.dromara.backstage.business.payments.strategy.PaymentsStrategyContent;
 import org.dromara.backstage.cardCenter.service.IPtCardService;
 import org.dromara.backstage.consumption.domain.bo.ConsumptionBo;
 import org.dromara.backstage.payment.domain.bo.PtBagBo;
+import org.dromara.backstage.payment.domain.bo.PurseInOutBo;
 import org.dromara.backstage.payment.domain.vo.PtBagVo;
 import org.dromara.backstage.payment.domain.vo.PtUserAccountVo;
 import org.dromara.backstage.payment.service.IPtBagService;
 import org.dromara.backstage.payment.service.IPtUserAccountService;
-import org.dromara.backstage.payment.service.impl.PtBagServiceImpl;
 import org.dromara.common.core.constant.Constants;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.core.enums.CreditTypeEnum;
@@ -36,8 +39,8 @@ import org.springframework.web.bind.annotation.*;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.text.MessageFormat;
+import java.util.ArrayList;
 import java.util.List;
-import java.util.Optional;
 
 /**
  * 账户钱包
@@ -49,6 +52,7 @@ import java.util.Optional;
 @Validated
 @RequiredArgsConstructor
 @RestController
+@Slf4j
 @RequestMapping("/payment/ptBag")
 public class PtBagController extends BaseController {
 
@@ -58,13 +62,14 @@ public class PtBagController extends BaseController {
     private final PaymentsStrategyContent paymentsStrategyContent;
     private final ErrFillBusiness errFillBusiness;
     private final IPtBagService bagService;
+    private final PayOrderBusiness payOrderBusiness;
 
     //根据userId查询账户余额
 //    @SaCheckPermission("payment:ptBag:query")
     @GetMapping("/selectSelfAccountBalance")
     public R<String> selectAccountBalanceByIds() {
         String userIds = String.valueOf(LoginHelper.getUserId());
-        return R.ok("",ptBagService.selectAccountBalanceByIds(userIds));
+        return R.ok("", ptBagService.selectAccountBalanceByIds(userIds));
     }
 
     /**
@@ -141,14 +146,25 @@ public class PtBagController extends BaseController {
     @Log(title = "账户钱包", businessType = BusinessType.UPDATE)
     @RepeatSubmit()
     @PostMapping("/recharge")
-    public R<PtBagVo> recharge(@Validated(EditGroup.class) @RequestBody PtBagBo bo) {
+    public R<PtBagVo> recharge(@Validated(EditGroup.class) @RequestBody PurseInOutBo bo) {
         bo.setUseType(SystemUseTypeEnum.CONSUME);
-        PtBagBo commissionBo = computeCommission(bo);
-        if (commissionBo != null) {
-            paymentsStrategyContent.createOrder(commissionBo);
+        PurseInOutBo commissionBo = computeCommission(bo);
+        try {
+            if (commissionBo != null) {
+                R<Object> commissionResult = payOrderBusiness.createNormalOrder(bo);
+                if (commissionResult.getCode() != R.SUCCESS) {
+                    return R.fail(commissionResult.getMsg());
+                }
+            }
+            R<Object> result = payOrderBusiness.createNormalOrder(bo);
+            if (result.getCode() == R.SUCCESS) {
+                return R.ok((PtBagVo) result.getData());
+            } else {
+                return R.fail(result.getMsg());
+            }
+        } catch (Exception e) {
+            return R.fail(e.getMessage());
         }
-        PtBagVo vo = paymentsStrategyContent.createOrder(bo);
-        return R.ok(vo);
     }
 
     /**
@@ -158,7 +174,7 @@ public class PtBagController extends BaseController {
     @Log(title = "账户钱包", businessType = BusinessType.UPDATE)
     @RepeatSubmit()
     @PostMapping("/refund")
-    public R<PtBagVo> refund(@Validated(EditGroup.class) @RequestBody PtBagBo bo) {
+    public R<PtBagVo> refund(@Validated(EditGroup.class) @RequestBody PurseInOutBo bo) {
         //校验钱包余额是否充足
         PtBagVo bagVo = bagService.queryByUserBagCode(bo.getUserId(), bo.getBagCode());
         if (bagVo.getBalance().compareTo(bo.getReceiptMoney()) < 0) {
@@ -167,8 +183,16 @@ public class PtBagController extends BaseController {
         bo.setUseType(SystemUseTypeEnum.CONSUME);
         //退款是记支出,所以金额设置为负数
         bo.setReceiptMoney(bo.getReceiptMoney().negate());
-        PtBagVo vo = paymentsStrategyContent.createOrder(bo);
-        return R.ok(vo);
+        try {
+            R<Object> result = payOrderBusiness.createNormalOrder(bo);
+            if (result.getCode() == R.SUCCESS) {
+                return R.ok((PtBagVo) result.getData());
+            } else {
+                return R.fail(result.getMsg());
+            }
+        } catch (Exception e) {
+            return R.fail(e.getMessage());
+        }
     }
 
     /**
@@ -178,20 +202,38 @@ public class PtBagController extends BaseController {
     @Log(title = "批量账户充值", businessType = BusinessType.UPDATE)
     @RepeatSubmit()
     @PostMapping("/recharge/{userIds}")
-    public R<Void> batchRecharge(@Validated(EditGroup.class) @RequestBody PtBagBo bo, @PathVariable Long[] userIds) {
+    public R<String> batchRecharge(@Validated(EditGroup.class) @RequestBody PurseInOutBo bo, @PathVariable Long[] userIds) {
+        // TODO 2024-10-30 09:49:36 luoyibo 这里最好是提前处理下工作站信息
+        List<String> resultList = new ArrayList<>();
+        int succesCount = 0;
+        int errorCount = 0;
         BigDecimal doValue = bo.getReceiptMoney();
         bo.setUseType(SystemUseTypeEnum.CONSUME);
         for (Long userId : userIds) {
             bo.setUserId(userId);
             bo.setReceiptMoney(doValue);
-            PtBagBo commissionBo = computeCommission(bo);
-            if (commissionBo != null) {
-                paymentsStrategyContent.createOrder(commissionBo);
+            PurseInOutBo commissionBo = computeCommission(bo);
+            try {
+                if (commissionBo != null) {
+                    R<Object> commissionResult = payOrderBusiness.createNormalOrder(bo);
+                    if (commissionResult.getCode() != R.SUCCESS) {
+                        resultList.add(MessageFormat.format("[收管理费失败]-[管理费信息:{0}]-[错误信息:{1}]", JSONUtil.toJsonStr(bo), commissionResult.getData().toString()));
+                    }
+                }
+                R<Object> result = payOrderBusiness.createNormalOrder(bo);
+                if (result.getCode() == R.SUCCESS) {
+                    succesCount++;
+                } else {
+                    errorCount++;
+                    resultList.add(MessageFormat.format("[充值失败]-[充值信息:{0}]-[错误信息:{1}]", JSONUtil.toJsonStr(bo), result.getData().toString()));
+                }
+            } catch (Exception e) {
+                errorCount++;
+                resultList.add(MessageFormat.format("[充值失败]-[充值信息:{0}]-[错误信息:{1}]", JSONUtil.toJsonStr(bo), e.getMessage()));
             }
-            paymentsStrategyContent.createOrder(bo);
         }
-
-        return R.ok();
+        resultList.forEach(log::error);
+        return R.ok(MessageFormat.format("批量充值完成,成功[{0}]条,失败[{1}]条", succesCount, errorCount));
     }
 
     /**
@@ -201,16 +243,37 @@ public class PtBagController extends BaseController {
     @Log(title = "账户批量退款", businessType = BusinessType.UPDATE)
     @RepeatSubmit()
     @PostMapping("/refund/{userIds}")
-    public R<Void> batchRefund(@Validated(EditGroup.class) @RequestBody PtBagBo bo, @PathVariable Long[] userIds) {
+    public R<Void> batchRefund(@Validated(EditGroup.class) @RequestBody PurseInOutBo bo, @PathVariable Long[] userIds) {
+        List<String> resultList = new ArrayList<>();
+        int succesCount = 0;
+        int errorCount = 0;
         bo.setUseType(SystemUseTypeEnum.CONSUME);
-        BigDecimal doValue = bo.getReceiptMoney().negate();
+        BigDecimal doValue = bo.getReceiptMoney();
+        //退款是记支出,所以金额设置为负数
+        bo.setReceiptMoney(doValue.negate());
         for (Long userId : userIds) {
-            //退款是记支出,所以金额设置为负数
-            bo.setReceiptMoney(doValue);
             bo.setUserId(userId);
-            paymentsStrategyContent.createOrder(bo);
+            PtBagVo bagVo = bagService.queryByUserBagCode(userId, bo.getBagCode());
+            if (bagVo.getBalance().compareTo(doValue) < 0) {
+                errorCount++;
+                resultList.add(MessageFormat.format("[退款失败]-[退款信息:{0}]-[错误信息:余额不足,当前余额:{1}]",JSONUtil.toJsonStr(bo), bagVo.getBalance()));
+            } else {
+                try {
+                    R<Object> result = payOrderBusiness.createNormalOrder(bo);
+                    if (result.getCode() == R.SUCCESS) {
+                        succesCount++;
+                    } else {
+                        errorCount++;
+                        resultList.add(MessageFormat.format("[退款失败]-[退款信息:{0}]-[错误信息:{1}]", JSONUtil.toJsonStr(bo), result.getData().toString()));
+                    }
+                } catch (Exception e) {
+                    errorCount++;
+                    resultList.add(MessageFormat.format("[退款失败]-[退款信息:{0}]-[错误信息:{1}]", JSONUtil.toJsonStr(bo), e.getMessage()));
+                }
+            }
         }
-        return R.ok();
+        resultList.forEach(log::error);
+        return R.ok(MessageFormat.format("批量退款完成,成功[{0}]条,失败[{1}]条", succesCount, errorCount));
     }
 
     /**
@@ -248,7 +311,7 @@ public class PtBagController extends BaseController {
     /**
      * 计算管理费
      */
-    private PtBagBo computeCommission(PtBagBo bo) {
+    private PurseInOutBo computeCommission(PurseInOutBo bo) {
         if (bo.getTakeCommission().equals(Constants.TAKE_COMMISSION)) {
             Long cardType = bo.getCardTypeId();
             if (bo.getCardTypeId() == null) {
@@ -257,10 +320,11 @@ public class PtBagController extends BaseController {
             }
             bo.setCardTypeId(cardType);
             //如果要收管理费,则计算管理费
-            BigDecimal commission = cardService.computeCommission(bo);
+            PtBagBo bagBo = BeanUtil.copyProperties(bo, PtBagBo.class);
+            BigDecimal commission = cardService.computeCommission(bagBo);
             if (commission.compareTo(BigDecimal.ZERO) > 0) {
                 //如果管理费>0,是要入资金收支记录的
-                PtBagBo commissionBo = new PtBagBo();
+                PurseInOutBo commissionBo = new PurseInOutBo();
                 BeanUtil.copyProperties(bo, commissionBo);
                 commissionBo.setReceiptMoney(commission);
                 commissionBo.setCreditType(CreditTypeEnum.COMMISSION_CHARGE);

+ 31 - 9
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/payment/domain/bo/PurseInOutBo.java

@@ -1,16 +1,16 @@
 package org.dromara.backstage.payment.domain.bo;
 
-import com.baomidou.mybatisplus.annotation.TableId;
 import jakarta.validation.constraints.NotBlank;
 import jakarta.validation.constraints.NotNull;
 import lombok.Data;
-import lombok.EqualsAndHashCode;
 import org.dromara.common.core.enums.BalanceUpdateEnum;
 import org.dromara.common.core.enums.CreditTypeEnum;
 import org.dromara.common.core.enums.SystemUseTypeEnum;
 import org.dromara.common.core.validate.AddGroup;
 import org.dromara.common.core.validate.EditGroup;
 
+import java.io.Serial;
+import java.io.Serializable;
 import java.math.BigDecimal;
 
 /**
@@ -24,17 +24,13 @@ import java.math.BigDecimal;
  * @since JDK 1.8
  */
 @Data
-public class PurseInOutBo {
-    /**
-     * 资金收支入账钱包Id
-     */
-    @NotNull(message = "钱包Id不能为空", groups = { EditGroup.class })
-    private Long bagId;
+public class PurseInOutBo implements Serializable {
 
+    @Serial
+    private static final long serialVersionUID = 5830503618923729067L;
     /**
      * 资金收支入账所属账户Id
      */
-    @NotNull(message = "所属账户Id不能为空", groups = { AddGroup.class, EditGroup.class })
     private Long userId;
 
     /**
@@ -43,6 +39,10 @@ public class PurseInOutBo {
     @NotBlank(message = "钱包代码", groups = { AddGroup.class, EditGroup.class })
     private String bagCode;
 
+    /**
+     * 钱包余额
+     */
+    private BigDecimal balance;
     /**
      * 资金来源
      */
@@ -56,6 +56,7 @@ public class PurseInOutBo {
     /**
      * 资金收支入账金额
      */
+    //@NotBlank(message = "收支金额", groups = { AddGroup.class, EditGroup.class })
     private BigDecimal receiptMoney;
 
     /**
@@ -70,10 +71,19 @@ public class PurseInOutBo {
      * 资金收支入账对应卡片Id,可能为空
      */
     private Long cardId;
+
+    /**
+     * 资金收支入账对应卡片类别Id,可能为空
+     */
+    private Long cardTypeId;
     /**
      * 资金收支入账操作的设备机号,可能为空
      */
     private Long termNo;
+    /**
+     * 机器流水号,一般是消费机上传数据时会有此值
+     */
+    private Long termRecordId;
     /**
      * 资金收支入账的工作站编号,可能为空
      */
@@ -83,11 +93,23 @@ public class PurseInOutBo {
      */
     private Long operatorId;
 
+    /**
+     * 操作员姓名
+     */
+    private String operatorName;
     /**
      * 系统使用类型
      */
     private SystemUseTypeEnum useType;
 
+    /**
+     * 原始记录Id
+     */
+    private String originalId;
+    /**
+     * 入账记录Id
+     */
+    private String creditId;
     /**
      * 校园端流水号,一般使用第三方支付会有此编号
      * 如:微信充值、微信扫码充值、银行圈存等,会先生成一笔请求支付的订单,支付成功后才会有一卡通系统的资金收支入账

+ 2 - 2
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/payment/service/impl/PtBagServiceImpl.java

@@ -309,8 +309,8 @@ public class PtBagServiceImpl implements IPtBagService {
         BigDecimal after = BigDecimal.ZERO;
         //账户现有余额
         BigDecimal balance  = bag.getBalance();
-        //退款金额
-        BigDecimal doValue = bo.getReceiptMoney();
+        //退款金额,传入的金额为负数,转换成正数进行余额处理
+        BigDecimal doValue = bo.getReceiptMoney().negate();
         //如果账户现有余额比退款金额大,则最后余额为账户余额-退款金额,否则为0
         if(balance.compareTo(doValue)>0){
             after = balance.subtract(doValue);

+ 37 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/task/SubsidyScheduled.java

@@ -0,0 +1,37 @@
+package org.dromara.backstage.task;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.backstage.business.payments.PayOrderBusiness;
+import org.dromara.common.core.domain.R;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+/**
+ * name: SubsidyScheduled
+ * package: org.dromara.backstage.task
+ * description: 补助到账定时任务
+ * date: 2024-10-30 17:05:59 17:05
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class SubsidyScheduled implements CommandLineRunner {
+    private final PayOrderBusiness subsidyOrderBusiness;
+
+    @Scheduled(fixedDelay = 1 * 60 * 1000)
+    public void rechargeSubsidy(){
+        R<Object> result = subsidyOrderBusiness.createSubsidyOrder();
+        log.info(result.getMsg());
+    }
+
+    @Override
+    public void run(String... args) throws Exception {
+
+    }
+}

+ 6 - 0
ruoyi-modules/ruoyi-backstage/src/main/resources/mapper/cardCenter/cardOperation/PtSubsidyitemMapper.xml

@@ -120,4 +120,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         group by fillDate, subsidyType,createByName
         order by fillDate desc,subsidyType desc,createByName desc
     </select>
+    <select id="selectPostSubsidyItem" resultType="org.dromara.backstage.cardCenter.domain.vo.PtSubsidyitemVo">
+        SELECT tpsi.*,tps.bag_code,tps.create_by AS operatorId,tsu.real_name AS operatorName FROM t_pt_subsidyItem tpsi
+        INNER JOIN t_pt_subsidy tps  ON tps.main_id=tpsi.main_id AND tps.del_flag='0' AND tps.audit_status='Y'
+        LEFT JOIN t_sys_user tsu ON tsu.user_id=tps.create_by AND tsu.del_flag='0'
+        WHERE tpsi.del_flag='0' AND tpsi.fill_status='N'
+    </select>
 </mapper>