mitao
2025-03-26 f708174b00e73a501dca4eb5ffb23520b4be3f67
Merge branch 'dev' of http://120.76.84.145:10101/gitblit/r/java/xizang into dev
5个文件已修改
342 ■■■■ 已修改文件
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/BankOutController.java 201 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/TencentMailUtil.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/FlowListenerService.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TBillServiceImpl.java 113 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/BankOutController.java
@@ -6,6 +6,7 @@
import com.alibaba.fastjson.TypeReference;
import com.ruoyi.common.constant.AmountConstant;
import com.ruoyi.common.enums.BillTypeEnum;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.dto.TBillDto;
import com.ruoyi.system.model.TOrderBill;
@@ -13,9 +14,7 @@
import com.ruoyi.system.service.TBillService;
import com.ruoyi.system.service.TOrderBillService;
import com.ruoyi.system.service.TPayOrderService;
import com.taxi591.bankapi.dto.CovertPayBackResult;
import com.taxi591.bankapi.dto.QueryBillRequest;
import com.taxi591.bankapi.dto.QueryBillResponse;
import com.taxi591.bankapi.dto.*;
import com.taxi591.bankapi.service.BankService;
import com.taxi591.bankapi.service.SignatureAndVerification;
import lombok.extern.slf4j.Slf4j;
@@ -28,9 +27,14 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -54,13 +58,188 @@
    @Autowired
    TPayOrderService payOrderService;
    public static String getRequestBody(HttpServletRequest request)
            throws IOException {
        /** 读取httpbody内容 */
        StringBuilder httpBody = new StringBuilder();
        BufferedReader br = null;
        try {
            br = new BufferedReader(new InputStreamReader(
                    request.getInputStream()));
            String line = null;
            while ((line = br.readLine()) != null) {
                httpBody.append(line);
            }
        } catch (IOException ex) {
            throw ex;
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }
        return httpBody.toString();
    }
    @PostMapping(value = "payCallback")
    public @ResponseBody String payCallback(HttpServletRequest request){
        CovertPayBackResult result = bankService.covertPayCallBack(request, (billRequest) -> {
            tBillService.completePay(billRequest);
            return true;
        });
        return result.getBack();
    public void payCallback(HttpServletRequest servletRequest,HttpServletResponse servletResponse){
        String request = null;
        String responseJson = null;
        try {
            log.info("--------进入getRequest4Sale----------------------------------");
            // 接收报文
            String requestContent = getRequestBody(servletRequest).trim();
            String signatureString = requestContent.substring(0,
                    requestContent.indexOf("||"));
            log.info("-----ChargeBillController------------截取报文的signatureString:{}", signatureString);
            String requestBody = requestContent.substring(signatureString
                    .length() + 2);
            log.info("-----ChargeBillController------------截取报文的requestBody:{}", requestBody);
            //如果有双引号,则截取双引号内requestBody的内容
            Pattern p=Pattern.compile("\"");
            Matcher m=p.matcher(requestBody);
            while(m.find()){
                requestBody=requestBody.replace(m.group(), "");
                log.info("-----ChargeBillController------如果有双引号,则截取后的requestBody:{}", requestBody);
            }
            //requestBody是base64加密后的数据,需解析出来
            request = new String(
                    com.alibaba.fastjson.util.Base64.decodeFast(requestBody));
            log.info("-----ChargeBillController------------解析完成后的requestBody-------{}" + request);
            ChargeBillRequest chargeBillRequest = JSON.parseObject(request,
                    new TypeReference<ChargeBillRequest>() {
                    });
            boolean b = signatureAndVerification.read_cer_and_verify_sign(requestBody,
                    signatureString);
            if (!b){
                throw new ServiceException("验签失败");
            }
            /** 销账报文重发次数,通过resendTimes此字段识别销账报文是否为重发的,0表示首次、1表示重发一次,2表示重发2次,最多重发3次*/
            if(chargeBillRequest!=null && "0".equals(chargeBillRequest.getMessage().getInfo().getResendTimes())){
                ChargeBillResponse chargeBillResponse = new ChargeBillResponse(
                        chargeBillRequest);
                ChargeBillResponse.Message respMessage = chargeBillResponse
                        .getMessage();
                ChargeBillResponse.Message.Head respHead = chargeBillResponse
                        .getMessage().getHead();
                ChargeBillResponse.Message.Info respInfo = chargeBillResponse
                        .getMessage().getInfo();
                respHead.setTransFlag("02");
                respHead.setTimeStamp(DateUtil.format(new Date(),"yyyyMMddHHmmssSSS"));
                // respHead.setChannel("MBNK");
                respHead.setChannel(chargeBillRequest.getMessage().getHead()
                        .getChannel());
                // respHead.setTranCode("chargeBill");
                respHead.setTransCode(chargeBillRequest.getMessage().getHead()
                        .getTransCode());
                respHead.setTransSeqNum(chargeBillRequest.getMessage().getHead()
                        .getTransSeqNum());
                //测试销账返回报文中,本来是销账成功的报文,但是不要送0000成功码   (JF190510134746710555这个流水号是在Demo的returnCode设置成null的时候产生的,流水状态为6;)
                String epayCode = chargeBillRequest.getMessage().getInfo()
                        .getEpayCode();
                String traceNo = chargeBillRequest.getMessage().getInfo()
                        .getTraceNo();
                String numOpenMerchantOrder = chargeBillRequest.getMessage()
                        .getInfo().getNumOpenMerchantOrder();
                respInfo.setNumOpenMerchantOrder(numOpenMerchantOrder);
                respInfo.setEpayCode(epayCode);
                respInfo.setTraceNo(traceNo);
                try{
                    tBillService.completePay(chargeBillRequest);
                    respHead.setReturnCode("0000");
                    respHead.setReturnMessage("账单缴费成功");
                }catch (Exception e){
                    respHead.setReturnCode("1111");
                    respHead.setReturnMessage("账单处理失败");
                    log.error("支付第一次回调出现异常,{}",request,e);
                }
                //第一次处理失败,不退款
                respInfo.setRefundFlag("false");
                respMessage.setInfo(respInfo);
                respMessage.setHead(respHead);
                chargeBillResponse.setMessage(respMessage);
                responseJson = JSON.toJSONString(chargeBillResponse);
                //加签名
                String signatrue = signatureAndVerification
                        .signWhithsha1withrsa(responseJson);
                log.info("-----ChargeBillController------------responseJson打印结果是(responseJson加密前):" + responseJson);
                responseJson = signatrue + "||"
                        + new String(Base64.encodeBase64(responseJson.getBytes("utf-8")));
                log.info("-----ChargeBillController------------responseJson打印结果是(responseJson加密后):" + responseJson);
                servletResponse.setCharacterEncoding("utf-8");
                servletResponse.setContentType("text/plain");
                servletResponse.getWriter().write(responseJson);
            }else{
                //销账报文重发次数,通过resendTimes此字段识别销账报文是否为重发的,0表示首次、1表示重发一次,2表示重发2次,最多重发3次
                //商户端要注意销账重复通知的情况,要进行订单唯一性处理
                ChargeBillResponse chargeBillResponse = new ChargeBillResponse(
                        chargeBillRequest);
                ChargeBillResponse.Message respMessage = chargeBillResponse
                        .getMessage();
                ChargeBillResponse.Message.Head respHead = chargeBillResponse
                        .getMessage().getHead();
                ChargeBillResponse.Message.Info respInfo = chargeBillResponse
                        .getMessage().getInfo();
                respHead.setTransFlag("02");
                respHead.setTimeStamp(DateUtil.format(new Date(),"yyyyMMddHHmmssSSS"));
                // respHead.setChannel("MBNK");
                respHead.setChannel(chargeBillRequest.getMessage().getHead()
                        .getChannel());
                // respHead.setTranCode("chargeBill");
                respHead.setTransCode(chargeBillRequest.getMessage().getHead()
                        .getTransCode());
                respHead.setTransSeqNum(chargeBillRequest.getMessage().getHead()
                        .getTransSeqNum());
                try{
                    tBillService.completePay(chargeBillRequest);
                    respHead.setReturnCode("0000");
                    respHead.setReturnMessage("账单缴费成功");
                }catch (Exception e){
                    respHead.setReturnCode("1111");
                    respHead.setReturnMessage("账单处理失败");
                    log.error("支付第一次回调出现异常,{}",request,e);
                }
                // 再次推送未处理成功,则返回退款标志
                if (!"0000".equals(respHead.getReturnCode())) {
                    respInfo.setRefundFlag("true");
                }
                String epayCode = chargeBillRequest.getMessage().getInfo()
                        .getEpayCode();
                String traceNo = chargeBillRequest.getMessage().getInfo()
                        .getTraceNo();
                String numOpenMerchantOrder = chargeBillRequest.getMessage()
                        .getInfo().getNumOpenMerchantOrder();
                respInfo.setNumOpenMerchantOrder(numOpenMerchantOrder);
                respInfo.setEpayCode(epayCode);
                respInfo.setTraceNo(traceNo);
                respMessage.setInfo(respInfo);
                respMessage.setHead(respHead);
                chargeBillResponse.setMessage(respMessage);
                responseJson = JSON.toJSONString(chargeBillResponse);
                //加签名
                String signatrue = signatureAndVerification
                        .signWhithsha1withrsa(responseJson);
                log.info("-----ChargeBillController------------responseJson打印结果是(responseJson加密前):" + responseJson);
                responseJson = signatrue + "||"
                        + new String(Base64.encodeBase64(responseJson.getBytes("utf-8")));
                log.info("-----ChargeBillController------------responseJson打印结果是(responseJson加密后):" + responseJson);
                servletResponse.setCharacterEncoding("utf-8");
                servletResponse.setContentType("text/plain");
                servletResponse.getWriter().write(responseJson);
            }
        }catch (Exception e) {
            log.error("处理支付回调发生异常:返回内容:{}",request,e);
        }
    }
    @PostMapping(value = "queryBill")
@@ -99,8 +278,8 @@
                    .getInfo();
            //缴费账单子账单
            ArrayList<QueryBillResponse.Message.Info.Bill> respBills = new ArrayList<QueryBillResponse.Message.Info.Bill>();
            ArrayList<QueryBillResponse.Message.Info.Bill.DescDetail> respDescDetail =
                    new ArrayList<QueryBillResponse.Message.Info.Bill.DescDetail>();
//            ArrayList<QueryBillResponse.Message.Info.Bill.DescDetail> respDescDetail =
//                    new ArrayList<QueryBillResponse.Message.Info.Bill.DescDetail>();
            QueryBillResponse.Message.Info.Bill respBill = respInfo.new Bill();
            //缴费子商户账单
//            ArrayList<QueryBillResponse.Message.Info.Bill.SplitSubMerInfo> splitSubMerInfos = new ArrayList<QueryBillResponse.Message.Info.Bill.SplitSubMerInfo>();
ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java
@@ -1,6 +1,7 @@
package com.ruoyi.common.utils;
import com.ruoyi.common.core.domain.model.LoginUserApplet;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@@ -13,6 +14,7 @@
 * 
 * @author ruoyi
 */
@Slf4j
public class SecurityUtils
{
    /**
@@ -69,8 +71,10 @@
        }
        catch (Exception e)
        {
            throw new ServiceException("获取用户账户异常", HttpStatus.UNAUTHORIZED);
            log.error("获取用户信息发生异常",e);
//            throw new ServiceException("获取用户账户异常", HttpStatus.UNAUTHORIZED);
        }
        return "";
    }
    /**
     * 获取用户账户小程序
ruoyi-common/src/main/java/com/ruoyi/common/utils/TencentMailUtil.java
@@ -14,13 +14,11 @@
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.*;
import java.util.concurrent.CompletableFuture;
@Component
@@ -149,9 +147,9 @@
                tempFilePath.add(Paths.get(filePath));
                FileDataSource source = new FileDataSource(filePath);
                messageBodyPart.setDataHandler(new DataHandler(source));
                String filenameEncode = MimeUtility.encodeText(fileName, "UTF-8", "base64");
                // String encodedFileName = Base64.getEncoder().encodeToString(fileName.getBytes(StandardCharsets.UTF_8));
                // String filenameEncode = MimeUtility.encodeText(encodedFileName);
                // String filenameEncode = MimeUtility.encodeText(fileName, "UTF-8", "base64");
                String encodedFileName = Base64.getEncoder().encodeToString(fileName.getBytes(StandardCharsets.UTF_8));
                String filenameEncode = MimeUtility.encodeText(encodedFileName);
                messageBodyPart.setFileName(filenameEncode);
                messageBodyPart.setHeader("Content-Transfer-Encoding", "base64");
                messageBodyPart.setHeader("Content-Disposition", "attachment");
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/FlowListenerService.java
@@ -301,7 +301,6 @@
                    }
                    List<TContractRentType> contractRentTypes = contractRentTypeService.list();
                    TContractRentType tContractRentType = contractRentTypes.stream().filter(e -> e.getContractId().equals(contract.getId())).findFirst().orElse(null);
                    // 生成第一笔账单
                    // 第一次应缴费日期
                    LocalDateTime firstPayTime = contract.getStartTime().plusDays(10).withHour(0).withMinute(0).withSecond(0);
@@ -455,7 +454,7 @@
                            if (dayOfMonth == 1) {
                                money = money.add(contract.getMonthRent());
                            } else {
                                long allDays = ChronoUnit.DAYS.between(contract.getStartPayTime(), contract.getStartPayTime().with(TemporalAdjusters.lastDayOfMonth())) + 1;
                                long allDays = ChronoUnit.DAYS.between(rentBill.getStartTime(), rentBill.getStartTime().with(TemporalAdjusters.lastDayOfMonth())) ;
                                money =money.add(contract.getMonthRent().divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(allDays)));
                            }
                            // 后续
@@ -463,15 +462,16 @@
                                rentBill.setPayableFeesMoney(money);
                                rentBill.setOutstandingMoney(rentBill.getPayableFeesMoney());
                            }else{
                                LocalDateTime localDateTime = rentBill.getStartTime().plusMonths(1).with(TemporalAdjusters.lastDayOfMonth());
//                                LocalDateTime localDateTime = rentBill.getStartTime().plusMonths(1).with(TemporalAdjusters.lastDayOfMonth());
                                LocalDateTime localDateTime = rentBill.getStartTime().with(TemporalAdjusters.lastDayOfMonth()).plusDays(1);
                                while (true){
                                    if (localDateTime.isBefore(rentBill.getEndTime())){
                                        localDateTime = localDateTime.plusMonths(1);
                                        money = money.add(contract.getMonthRent());
                                    }else{
                                        money = money.add(contract.getMonthRent().divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(ChronoUnit.DAYS.between(rentBill.getEndTime(),localDateTime.with(TemporalAdjusters.firstDayOfMonth()))+1)));
                                        money = money.add(contract.getMonthRent().divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(ChronoUnit.DAYS.between(rentBill.getEndTime(),localDateTime.with(TemporalAdjusters.firstDayOfMonth())))));
                                        break;
                                    }
                                    localDateTime = localDateTime.plusMonths(1).with(TemporalAdjusters.lastDayOfMonth());
                                }
                                rentBill.setPayableFeesMoney(money);
                                rentBill.setOutstandingMoney(rentBill.getPayableFeesMoney());
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TBillServiceImpl.java
@@ -144,6 +144,7 @@
        if (isok){
            try {
                TBill save = new TBill();
                save.setId(tBill.getId());
                TBill presist = getById(tBill.getId());
                //如果账单是已缴费状态,本方法不再进行更新账单
                if (presist.getPayFeesStatus().equals("3")){
@@ -343,62 +344,66 @@
        String uuid = UUID.fastUUID().toString();
        boolean lock = redisCache.trylockLoop(CacheConstants.COMPLETE_PAY_LOCK_KEY + orderNo, uuid, 60);
        if (lock){
            TPayOrder order = tPayOrderService.getById(orderNo);
            if (order==null){
                throw new ServiceException("订单不存在");
            }
            if (StringUtils.isNotEmpty(order.getPayNo())){
                log.info("订单号已处理:{}",orderNo);
                return;
            }
            /**
             * 更新订单状态
             */
            TPayOrder save = new TPayOrder();
            save.setId(order.getId());
            save.setStatus(1);
            save.setPayNo(billRequest.getMessage().getInfo().getTraceNo());
            save.setPayType(billRequest.getMessage().getHead().getChannel());
            try {
                save.setPayTime(DateUtils.parseDate(billRequest.getMessage().getHead().getTimeStamp(),"yyyyMMddHHmmssSSS"));
            } catch (ParseException e) {
                throw new ServiceException("日期格式化错误");
                TPayOrder order = tPayOrderService.getById(orderNo);
                if (order==null){
                    throw new ServiceException("订单不存在");
                }
                if (StringUtils.isNotEmpty(order.getPayNo())){
                    log.info("订单号已处理:{}",orderNo);
                    return;
                }
                /**
                 * 更新订单状态
                 */
                TPayOrder save = new TPayOrder();
                save.setId(order.getId());
                save.setStatus(1);
                save.setPayNo(billRequest.getMessage().getInfo().getTraceNo());
                save.setPayType(billRequest.getMessage().getHead().getChannel());
                try {
                    save.setPayTime(DateUtils.parseDate(billRequest.getMessage().getHead().getTimeStamp(),"yyyyMMddHHmmssSSS"));
                } catch (ParseException e) {
                    throw new ServiceException("日期格式化错误");
                }
                save.setCallbackTime(new Date());
                BigDecimal payAmount = new BigDecimal(billRequest.getMessage().getInfo().getPayBillAmt());
                save.setActPayAmount(payAmount
                        .multiply(AmountConstant.b100).longValue());
                save.setStatus(1);
                save.setPayInfo(billRequest.getMessage().toString());
                tPayOrderService.updateById(save);
                /**
                 * 更新账单状态
                 */
                List<TOrderBill> orderBills = orderBillService.getByOrderNo(order.getId());
                List<TBill> bills = orderBills.stream().map(ob -> getById(ob.getBillId())).collect(Collectors.toList());
                lockAndUpdateByAmountBatch(bills,payAmount,(bill)->{
                    TFlowManagement saveFlow = new TFlowManagement();
                    saveFlow.setPayType(1);
                    saveFlow.setPayer(order.getUserId());
                    saveFlow.setPayTime(DateUtils.dateToLocalDateTime(save.getPayTime()));
                    saveFlow.setSysSerialNumber(OrderNos.getDid(30));
                    saveFlow.setBankSerialNumber(save.getPayNo());
                    saveFlow.setFlowType(2);
                    saveFlow.setPaymentBillId(bill.getId());
                    saveFlow.setDeductionMoney(bill.getDeductionMoney());
                    saveFlow.setFlowMoney(payAmount);
                    saveFlow.setRemainingMoney(bill.getOutstandingMoney());
                    saveFlow.setPreOutstand(bill.getPreOutstand());
                    tFlowManagementService.save(saveFlow);
                });
//                TBankFlow bankFlow = new TBankFlow();
//                bankFlow.setPayType(1);
//                bankFlow.setPayer(order.getUserId());
//                bankFlow.setPayTime(DateUtils.dateToLocalDateTime(save.getPayTime()));
//                bankFlow.setBankSerialNumber(save.getPayNo());
//                bankFlow.setFlowMoney(payAmount);
//                bankFlow.setFlowStatus(1);
//                tBankFlowService.save(bankFlow);
            }finally {
                redisCache.unlock(CacheConstants.COMPLETE_PAY_LOCK_KEY + orderNo,uuid);
            }
            save.setCallbackTime(new Date());
            BigDecimal payAmount = new BigDecimal(billRequest.getMessage().getInfo().getPayBillAmt());
            save.setActPayAmount(payAmount
                    .multiply(AmountConstant.b100).longValue());
            save.setStatus(1);
            save.setPayInfo(billRequest.getMessage().toString());
            tPayOrderService.updateById(save);
            /**
             * 更新账单状态
             */
            List<TOrderBill> orderBills = orderBillService.getByOrderNo(order.getId());
            List<TBill> bills = orderBills.stream().map(ob -> getById(ob.getBillId())).collect(Collectors.toList());
            lockAndUpdateByAmountBatch(bills,payAmount,(bill)->{
                TFlowManagement saveFlow = new TFlowManagement();
                saveFlow.setPayType(1);
                saveFlow.setPayer(order.getUserId());
                saveFlow.setPayTime(DateUtils.dateToLocalDateTime(save.getPayTime()));
                saveFlow.setSysSerialNumber(OrderNos.getDid(30));
                saveFlow.setBankSerialNumber(save.getPayNo());
                saveFlow.setFlowType(2);
                saveFlow.setPaymentBillId(bill.getId());
                saveFlow.setDeductionMoney(bill.getDeductionMoney());
                saveFlow.setFlowMoney(payAmount);
                saveFlow.setRemainingMoney(bill.getOutstandingMoney());
                saveFlow.setPreOutstand(bill.getPreOutstand());
                tFlowManagementService.save(saveFlow);
            });
            TBankFlow bankFlow = new TBankFlow();
            bankFlow.setPayType(1);
            bankFlow.setPayer(order.getUserId());
            bankFlow.setPayTime(DateUtils.dateToLocalDateTime(save.getPayTime()));
            bankFlow.setBankSerialNumber(save.getPayNo());
            bankFlow.setFlowMoney(payAmount);
            bankFlow.setFlowStatus(1);
            tBankFlowService.save(bankFlow);
        }