longz
2026-07-21 700cbb19a285e639bb05404503efa3da9988c083
分账可开关
3个文件已添加
17个文件已修改
690 ■■■■■ 已修改文件
ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/model/TShoppingOrder.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/model/TVipOrder.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/SiteMapper.xml 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/test/java/com/ruoyi/chargingPile/mapper/SiteMapperVisibilityTest.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TOrderInvoiceController.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TShoppingOrderController.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TVipOrderController.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/PayOrderInfoDto.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/mapper/TChargingOrderMapper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TShoppingOrderServiceImpl.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml 250 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/controller/TOrderInvoiceControllerTest.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/service/impl/ChargingOrderShareConfigurationTest.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/service/impl/PlatformRevenueAnalysisTest.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TGoodsController.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/TVipServiceImpl.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/controller/IcbcPayController.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/icbc/service/IcbcPaymentFlowRecorder.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-payment/src/test/java/com/ruoyi/payment/controller/IcbcPayControllerDispatchTest.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/model/TShoppingOrder.java
@@ -93,7 +93,7 @@
    @TableField("payment_status")
    private Integer paymentStatus;
    @ApiModelProperty(value = "支付方式(1=微信,2=支付宝)")
    @ApiModelProperty(value = "支付方式(1=微信,2=支付宝,3=工商银行)")
    @TableField("payment_type")
    private Integer paymentType;
ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/model/TVipOrder.java
@@ -80,7 +80,7 @@
    @TableField("payment_status")
    private Integer paymentStatus;
    @ApiModelProperty(value = "支付方式(1=微信,2=支付宝)")
    @ApiModelProperty(value = "支付方式(1=微信,2=支付宝,3=工商银行)")
    @TableField("payment_type")
    private Integer paymentType;
ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/SiteMapper.xml
@@ -196,7 +196,6 @@
            </if>
            AND ts.del_flag = ${@com.ruoyi.common.core.enums.DelFlagEnum@NO.getCode()}
            AND ts.status = ${@com.ruoyi.common.core.enums.status.SiteStatusEnum@NORMAL_USE.getCode()}
            AND ts.accounting_strategy_id IS NOT NULL
            AND (tp.partner_type IS NULL OR tp.partner_type != 3)
        </where>
        <if test="query.sortType != null">
ruoyi-service/ruoyi-chargingPile/src/test/java/com/ruoyi/chargingPile/mapper/SiteMapperVisibilityTest.java
@@ -6,6 +6,7 @@
import java.nio.file.Files;
import java.nio.file.Paths;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
class SiteMapperVisibilityTest {
@@ -19,5 +20,6 @@
        assertTrue(mapper.contains("p.partner_type = 3"));
        assertTrue(mapper.contains("member_discount_flag as memberDiscountFlag"));
        assertTrue(mapper.contains("CASE WHEN ts.member_discount_flag = 1 THEN tasd.vipElectrovalence"));
        assertFalse(mapper.contains("ts.accounting_strategy_id IS NOT NULL"));
    }
}
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TOrderInvoiceController.java
@@ -230,7 +230,10 @@
        if (invoice.getBillingTime() != null) {
            export.setBillingTime(DateUtils.localDateTimeToString(invoice.getBillingTime()));
        }
        return ExcelExportUtil.exportExcel(new ExportParams(), OrderInvoiceExport.class, Collections.singletonList(export));
        return ExcelExportUtil.exportExcel(
                new ExportParams(),
                OrderInvoiceExport.class,
                new ArrayList<>(Collections.singletonList(export)));
    }
    private String buildInvoiceFileName(TOrderInvoiceVO invoice) {
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TShoppingOrderController.java
@@ -36,11 +36,14 @@
import com.ruoyi.other.api.feignClient.CouponClient;
import com.ruoyi.other.api.feignClient.GoodsClient;
import com.ruoyi.payment.api.feignClient.AliPaymentClient;
import com.ruoyi.payment.api.feignClient.IcbcPaymentClient;
import com.ruoyi.payment.api.feignClient.WxPaymentClient;
import com.ruoyi.payment.api.model.RefundReq;
import com.ruoyi.payment.api.model.RefundResp;
import com.ruoyi.payment.api.model.WxPaymentRefundModel;
import com.ruoyi.payment.api.vo.WxRefundNotifyResp;
import com.ruoyi.payment.api.vo.IcbcRefundReq;
import com.ruoyi.payment.api.vo.IcbcRefundResp;
import com.ruoyi.system.api.domain.SysUser;
import com.ruoyi.system.api.feignClient.SysUserClient;
import io.swagger.annotations.Api;
@@ -81,6 +84,8 @@
    private AliPaymentClient aliPaymentClient;
    @Resource
    private WxPaymentClient wxPaymentClient;
    @Resource
    private IcbcPaymentClient icbcPaymentClient;
    @Resource
    private AppCouponClient appCouponClient;
    @Resource
@@ -208,7 +213,7 @@
        tShoppingOrderRefund.setPayTime(byId.getPayTime());
        tShoppingOrderRefund.setPayCode(byId.getSerialNumber());
        tShoppingOrderRefund.setPayAmount(byId.getPaymentAmount());
        tShoppingOrderRefund.setPayType(1);
        tShoppingOrderRefund.setPayType(byId.getPaymentType());
        tShoppingOrderRefund.setShoppingOrderId(byId.getId());
        tShoppingOrderRefund.setRefundAmount(byId.getPaymentAmount());
        tShoppingOrderRefund.setRefundStatus(1);
@@ -276,6 +281,30 @@
                    shoppingOrderService.updateById(byId);
                }
                break;
            case 3:
                IcbcRefundReq icbcRefundReq = new IcbcRefundReq();
                icbcRefundReq.setOutTradeNo(byId.getCode());
                icbcRefundReq.setOrderId(byId.getSerialNumber());
                icbcRefundReq.setOutRefundNo(tShoppingOrderRefund.getCode());
                icbcRefundReq.setRefundAmount(byId.getPaymentAmount());
                icbcRefundReq.setTotalAmount(byId.getPaymentAmount());
                icbcRefundReq.setReason("后台购物订单退款");
                R<IcbcRefundResp> icbcRefundResult = icbcPaymentClient.refund(icbcRefundReq);
                IcbcRefundResp icbcRefundResp = icbcRefundResult == null ? null : icbcRefundResult.getData();
                if (icbcRefundResult == null || icbcRefundResult.getCode() != 200 || icbcRefundResp == null || !"SUCCESS".equals(icbcRefundResp.getStatus())) {
                    return AjaxResult.error(icbcRefundResult == null ? "工行退款服务无响应" : icbcRefundResult.getMsg());
                }
                tShoppingOrderRefund.setRefundStatus(2);
                tShoppingOrderRefund.setRefundSerialNumber(icbcRefundResp.getRefundId());
                tShoppingOrderRefund.setRefundTime(LocalDateTime.now());
                shoppingOrderRefundService.save(tShoppingOrderRefund);
                byId.setStatus(4);
                byId.setRefundCode(tShoppingOrderRefund.getCode());
                byId.setRefundAmount(byId.getPaymentAmount());
                byId.setRefundStatus(2);
                byId.setRefundSerialNumber(icbcRefundResp.getRefundId());
                byId.setRefundTime(LocalDateTime.now());
                break;
        }
        shoppingOrderService.updateById(byId);
        return AjaxResult.success();
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TVipOrderController.java
@@ -141,9 +141,18 @@
    @PostMapping("/callBack")
    public R callBack(@RequestParam("code")String code,@RequestParam("outTradeNo")String outTradeNo){
        TVipOrder one = vipOrderService.lambdaQuery().eq(TVipOrder::getCode, code).one();
        one.setSerialNumber(outTradeNo);
        one.setPaymentStatus(2);
        vipOrderService.updateById(one);
        if (one == null) {
            return R.fail("会员订单不存在");
        }
        boolean updated = vipOrderService.update(new LambdaUpdateWrapper<TVipOrder>()
                .eq(TVipOrder::getId, one.getId())
                .eq(TVipOrder::getPaymentStatus, 1)
                .set(TVipOrder::getSerialNumber, outTradeNo)
                .set(TVipOrder::getPaymentStatus, 2)
                .set(TVipOrder::getPayTime, LocalDateTime.now()));
        if (!updated) {
            return R.ok();
        }
        GiveVipDto giveVipDto = new GiveVipDto();
        giveVipDto.setVipId(one.getVipId());
        giveVipDto.setType(one.getVipType());
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/PayOrderInfoDto.java
@@ -16,7 +16,7 @@
    private String code;
    @ApiModelProperty("支付流水号")
    private String tradeNo;
    @ApiModelProperty("1微信2支付宝")
    @ApiModelProperty("1微信2支付宝3工商银行")
    private Integer payType;
    @ApiModelProperty("支付金额")
    private BigDecimal payAmount;
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/mapper/TChargingOrderMapper.java
@@ -96,6 +96,8 @@
    List<SixCircleDto> circle(@Param("siteIds")List<Integer> siteIds,@Param("sixBefore")LocalDate sixBefore, @Param("partnerView") Boolean partnerView);
    BigDecimal sumSuccessfulShareAmount(@Param("siteIds") List<Integer> siteIds);
    Map<String, Object> countAll(@Param("siteIds")List<Integer> siteIds, @Param("partnerView") Boolean partnerView);
    List<Map<String, Object>> chargingOrderShareIncomeByPayChannel(@Param("sixBefore")LocalDate sixBefore,@Param("siteIds") List<Integer> siteIds);
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java
@@ -88,6 +88,7 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@@ -168,6 +169,8 @@
    private IcbcPaymentClient icbcPaymentClient;
    @Resource
    private TChargingOrderShareRecordMapper chargingOrderShareRecordMapper;
    @Value("${icbc.share.online-enabled:false}")
    private boolean icbcOnlineShareEnabled;
    @Resource
    private ChargingOrderSettlementExecutor chargingOrderSettlementExecutor;
    @Resource
@@ -3111,7 +3114,11 @@
    
    @Override
    public Map<String, Object> countAll(List<Integer> siteIds, Boolean partnerView) {
        return this.baseMapper.countAll(siteIds, partnerView);
        Map<String, Object> result = this.baseMapper.countAll(siteIds, partnerView);
        if (!Boolean.TRUE.equals(partnerView) && result != null) {
            result.put("commission_amount", this.baseMapper.sumSuccessfulShareAmount(siteIds));
        }
        return result;
    }
    /**
@@ -5237,7 +5244,7 @@
            shoppingOrderRefund.setRefundContent("后台退款");
            shoppingOrderRefund.setRefundReason("后台退款");
            shoppingOrderRefund.setRefundRemark(payOrderQueryDto.getRemark());
            shoppingOrderRefund.setRefundTotalAmount(shoppingOrder.getRefundAmount().add(payOrderQueryDto.getRefundAmount()));
            shoppingOrderRefund.setRefundTotalAmount(money(shoppingOrder.getRefundAmount()).add(payOrderQueryDto.getRefundAmount()));
            shoppingOrderRefund.setPayAmount(shoppingOrder.getPaymentAmount());
            if (1 == shoppingOrder.getPaymentType()) {
@@ -5281,6 +5288,29 @@
                    shoppingOrderRefundService.save(shoppingOrderRefund);
                }
            }
            if (3 == shoppingOrder.getPaymentType()) {
                IcbcRefundReq refundReq = new IcbcRefundReq();
                refundReq.setOutTradeNo(shoppingOrder.getCode());
                refundReq.setOrderId(shoppingOrder.getSerialNumber());
                refundReq.setOutRefundNo(shoppingOrderRefund.getRefundCode());
                refundReq.setRefundAmount(payOrderQueryDto.getRefundAmount());
                refundReq.setTotalAmount(shoppingOrder.getPaymentAmount());
                refundReq.setReason("后台商城订单退款");
                R<IcbcRefundResp> refundResult = icbcPaymentClient.refund(refundReq);
                IcbcRefundResp refundResp = refundResult == null ? null : refundResult.getData();
                if (refundResult == null || refundResult.getCode() != 200 || refundResp == null || !"SUCCESS".equals(refundResp.getStatus())) {
                    return R.fail(refundResult == null ? "工行退款服务无响应"
                            : firstNotBlank(refundResp == null ? null : refundResp.getRawResponse(), refundResult.getMsg(), "工行退款失败"));
                }
                shoppingOrder.setRefundStatus(2);
                shoppingOrder.setRefundAmount(money(shoppingOrder.getRefundAmount()).add(payOrderQueryDto.getRefundAmount()));
                shoppingOrder.setRefundSerialNumber(refundResp.getRefundId());
                shoppingOrder.setRefundTime(LocalDateTime.now());
                shoppingOrderService.updateById(shoppingOrder);
                shoppingOrderRefund.setRefundStatus(2);
                shoppingOrderRefund.setRefundSerialNumber(refundResp.getRefundId());
                shoppingOrderRefundService.save(shoppingOrderRefund);
            }
//                if(3 == tChargingOrder.getPaymentType()){
//                    RefundReq dto = new RefundReq();
//                    dto.setOutTradeNo(tChargingOrder.getCode());
@@ -5318,7 +5348,7 @@
            vipOrderRefund.setRefundContent("后台退款");
            vipOrderRefund.setRefundReason("后台退款");
            vipOrderRefund.setRefundRemark(payOrderQueryDto.getRemark());
            vipOrderRefund.setRefundTotalAmount(vipOrder.getRefundAmount().add(payOrderQueryDto.getRefundAmount()));
            vipOrderRefund.setRefundTotalAmount(money(vipOrder.getRefundAmount()).add(payOrderQueryDto.getRefundAmount()));
            vipOrderRefund.setPayAmount(vipOrder.getPaymentAmount());
            
            if (1 == vipOrder.getPaymentType()) {
@@ -5361,6 +5391,27 @@
                    vipOrderService.updateById(vipOrder);
                    vipOrderRefundService.save(vipOrderRefund);
                }
            }
            if (3 == vipOrder.getPaymentType()) {
                IcbcRefundReq refundReq = new IcbcRefundReq();
                refundReq.setOutTradeNo(vipOrder.getCode());
                refundReq.setOrderId(vipOrder.getSerialNumber());
                refundReq.setOutRefundNo(vipOrderRefund.getRefundCode());
                refundReq.setRefundAmount(payOrderQueryDto.getRefundAmount());
                refundReq.setTotalAmount(vipOrder.getPaymentAmount());
                refundReq.setReason("后台会员订单退款");
                R<IcbcRefundResp> refundResult = icbcPaymentClient.refund(refundReq);
                IcbcRefundResp refundResp = refundResult == null ? null : refundResult.getData();
                if (refundResult == null || refundResult.getCode() != 200 || refundResp == null || !"SUCCESS".equals(refundResp.getStatus())) {
                    return R.fail(refundResult == null ? "工行退款服务无响应"
                            : firstNotBlank(refundResp == null ? null : refundResp.getRawResponse(), refundResult.getMsg(), "工行退款失败"));
                }
                vipOrder.setRefundStatus(2);
                vipOrder.setRefundAmount(money(vipOrder.getRefundAmount()).add(payOrderQueryDto.getRefundAmount()));
                vipOrderService.updateById(vipOrder);
                vipOrderRefund.setRefundStatus(2);
                vipOrderRefund.setRefundSerialNumber(refundResp.getRefundId());
                vipOrderRefundService.save(vipOrderRefund);
            }
//            if(3 == tChargingOrder.getPaymentType()){
//                RefundReq dto = new RefundReq();
@@ -7531,11 +7582,13 @@
            record.setSubMerId(partner.getIcbcSubMerId());
            record.setSubMerPrtclNo(partner.getIcbcSubMerPrtclNo());
        }
        boolean needOnlineShare = shouldProcessIcbcOnlineShare(payChannel, record.getShareAmount(), partner);
        boolean needOnlineShare = shouldProcessIcbcOnlineShare(icbcOnlineShareEnabled, payChannel, record.getShareAmount(), partner);
        record.setNeedOnlineShare(needOnlineShare);
        record.setOnlineShareStatus(needOnlineShare ? "INIT" : "RECORDED");
        if ("ICBC".equals(payChannel) && record.getShareAmount().compareTo(BigDecimal.ZERO) > 0 && !needOnlineShare) {
            record.setFailReason("未配置完整工行二级商户参数,仅记录本地分账");
            record.setFailReason(icbcOnlineShareEnabled
                    ? "未配置完整工行二级商户参数,仅记录本地分账"
                    : "工行线上分账已关闭,仅记录本地分账");
        }
        record.setRetryCount(0);
        record.setDelFlag(false);
@@ -7728,7 +7781,12 @@
    }
    static boolean shouldProcessIcbcOnlineShare(String payChannel, BigDecimal shareAmount, Partner partner) {
        return "ICBC".equals(payChannel)
        return shouldProcessIcbcOnlineShare(true, payChannel, shareAmount, partner);
    }
    static boolean shouldProcessIcbcOnlineShare(boolean onlineShareEnabled, String payChannel, BigDecimal shareAmount, Partner partner) {
        return onlineShareEnabled
                && "ICBC".equals(payChannel)
                && shareAmount != null
                && shareAmount.compareTo(BigDecimal.ZERO) > 0
                && partner != null
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TShoppingOrderServiceImpl.java
@@ -2,6 +2,7 @@
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.account.api.dto.GrantCouponDto;
@@ -29,11 +30,15 @@
import com.ruoyi.other.api.feignClient.CouponClient;
import com.ruoyi.other.api.feignClient.GoodsClient;
import com.ruoyi.payment.api.feignClient.AliPaymentClient;
import com.ruoyi.payment.api.feignClient.IcbcPaymentClient;
import com.ruoyi.payment.api.feignClient.WxPaymentClient;
import com.ruoyi.payment.api.model.RefundReq;
import com.ruoyi.payment.api.model.RefundResp;
import com.ruoyi.payment.api.model.WxPaymentRefundModel;
import com.ruoyi.payment.api.vo.AliQueryOrder;
import com.ruoyi.payment.api.vo.IcbcPaymentResp;
import com.ruoyi.payment.api.vo.IcbcRefundReq;
import com.ruoyi.payment.api.vo.IcbcRefundResp;
import com.ruoyi.payment.api.vo.NotifyV3PayDecodeRespBody;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
@@ -85,6 +90,9 @@
    @Resource
    private AliPaymentClient aliPaymentClient;
    @Resource
    private IcbcPaymentClient icbcPaymentClient;
    @Resource
    private TShoppingOrderRefundService shoppingOrderRefundService;
@@ -387,7 +395,7 @@
        BigDecimal refundAmount = shoppingOrder.getPaymentAmount().subtract(bigDecimal);
        //先查询第三方订单状态订单是否退款
        //支付方式(1=微信,2=支付宝)
        // 支付方式(1=微信,2=支付宝,3=工商银行)
        Integer paymentType = shoppingOrder.getPaymentType();
        if(1 == paymentType){
            NotifyV3PayDecodeRespBody data = wxPaymentClient.queryOrderInfo(shoppingOrder.getCode()).getData();
@@ -413,6 +421,13 @@
            }
            if("WAIT_BUYER_PAY".equals(tradeStatus)){
                return AjaxResult.error("订单正在支付中,不能操作退款");
            }
        }
        if (3 == paymentType) {
            R<IcbcPaymentResp> queryResult = icbcPaymentClient.query(shoppingOrder.getCode());
            IcbcPaymentResp queryResp = queryResult == null ? null : queryResult.getData();
            if (queryResult == null || queryResult.getCode() != 200 || queryResp == null || !"0".equals(queryResp.getStatus())) {
                return AjaxResult.error(queryResult == null ? "工行支付查询无响应" : "订单尚未支付成功,不能退款");
            }
        }
        //退款成功后需要判断商品库存类型后决定是否需要回退库存
@@ -473,6 +488,22 @@
                SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-DDTHH:mm:ss+TIMEZONE");
                AjaxResult success = cancelShoppingOrderWxRefund(resp.getOutTradeNo(), resp.getTradeNo(), "SUCCESS", sdf1.format(new Date()));
            }
        }
        if (3 == paymentType) {
            IcbcRefundReq refundReq = new IcbcRefundReq();
            refundReq.setOutTradeNo(shoppingOrder.getCode());
            refundReq.setOrderId(shoppingOrder.getSerialNumber());
            refundReq.setOutRefundNo(shoppingOrderRefund.getRefundCode());
            refundReq.setRefundAmount(refundAmount);
            refundReq.setTotalAmount(shoppingOrder.getPaymentAmount());
            refundReq.setReason("取消商城订单");
            R<IcbcRefundResp> refundResult = icbcPaymentClient.refund(refundReq);
            IcbcRefundResp refundResp = refundResult == null ? null : refundResult.getData();
            if (refundResult == null || refundResult.getCode() != 200 || refundResp == null || !"SUCCESS".equals(refundResp.getStatus())) {
                return AjaxResult.error(refundResult == null ? "工行退款无响应" : refundResult.getMsg());
            }
            shoppingOrderRefundService.save(shoppingOrderRefund);
            cancelShoppingOrderWxRefund(shoppingOrderRefund.getRefundCode(), refundResp.getRefundId(), "SUCCESS", refundResp.getRefundTime());
        }
        return AjaxResult.success();
    }
@@ -588,12 +619,19 @@
    @Override
    public void callBack(String code,String outTradeNo) {
        //改变订单状态
        TShoppingOrder shoppingOrder = this.baseMapper.selectOne(Wrappers.lambdaQuery(TShoppingOrder.class).eq(TShoppingOrder::getCode, code));
        shoppingOrder.setPaymentStatus(2);
        shoppingOrder.setSerialNumber(outTradeNo);
        shoppingOrder.setPayTime(LocalDateTime.now());
        this.updateById(shoppingOrder);
        if (shoppingOrder == null) {
            throw new IllegalArgumentException("商城订单不存在:" + code);
        }
        boolean updated = this.update(new LambdaUpdateWrapper<TShoppingOrder>()
                .eq(TShoppingOrder::getId, shoppingOrder.getId())
                .eq(TShoppingOrder::getPaymentStatus, 1)
                .set(TShoppingOrder::getPaymentStatus, 2)
                .set(TShoppingOrder::getSerialNumber, outTradeNo)
                .set(TShoppingOrder::getPayTime, LocalDateTime.now()));
        if (!updated) {
            return;
        }
        //如果是优惠券,赠送优惠券
        if (shoppingOrder.getOrderType()==2){
            GrantCouponDto grantCouponDto = new GrantCouponDto();
ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml
@@ -407,162 +407,120 @@
    </select>
    <select id="charge" resultType="com.ruoyi.order.dto.SixChargingDto">
        <choose>
        <when test="partnerView != null and partnerView">
        SELECT
        DATE_FORMAT(a.create_time, '%m') AS MONTH,
        ROUND(SUM(IFNULL(s.electricity_share_amount, 0)), 2) AS electrovalence,
        ROUND(SUM(IFNULL(s.service_share_amount, 0)), 2) AS service_charge
        FROM t_charging_order a
        LEFT JOIN (
            SELECT charging_order_id,
            SUM(IFNULL(electricity_share_amount, 0)) AS electricity_share_amount,
            SUM(IFNULL(service_share_amount, 0)) AS service_share_amount
            FROM t_charging_order_share_record
            WHERE del_flag = 0 AND charging_order_id IS NOT NULL AND online_share_status = 'SUCCESS'
            GROUP BY charging_order_id
        ) s ON a.id = s.charging_order_id
        <where>
            a.del_flag = 0 and a.recharge_payment_status = 2
            <if test="sixBefore != null">
                AND a.create_time &gt;= #{sixBefore}
            </if>
            <if test="siteIds != null and siteIds.size() > 0">
                AND a.site_id IN
                <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
                    #{siteId}
                </foreach>
            </if>
        </where>
        GROUP BY DATE_FORMAT(a.create_time, '%m')
        </when>
        <otherwise>
        SELECT
        DATE_FORMAT(a.create_time, '%m') AS MONTH,
        SUM(IFNULL(b.period_electric_price, 0)) AS electrovalence,
        SUM(
            CASE
            WHEN a.order_source = 0 THEN IFNULL(b.period_service_price, 0)
            WHEN a.order_source = 1 THEN IFNULL(b.period_service_price, 0)
            ELSE IFNULL(b.period_service_price, 0) * 0.8
            END
        ) AS service_charge
        FROM
        t_charging_order a
        LEFT JOIN t_charging_order_accounting_strategy b ON a.id = b.charging_order_id
        <where>
            a.del_flag = 0 and a.recharge_payment_status = 2 and a.status = 5
            <if test="sixBefore != null">
                AND a.create_time &gt;= #{sixBefore}
            </if>
            <if test="siteIds != null and siteIds.size() > 0">
                AND a.site_id IN
                <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
                    #{siteId}
                </foreach>
            </if>
        </where>
        GROUP BY
        DATE_FORMAT(a.create_time, '%m')
        </otherwise>
            <when test="partnerView != null and partnerView">
                SELECT DATE_FORMAT(create_time, '%m') AS MONTH,
                       ROUND(SUM(IFNULL(electricity_share_amount, 0)), 2) AS electrovalence,
                       ROUND(SUM(IFNULL(service_share_amount, 0)), 2) AS service_charge
                FROM t_charging_order_share_record
                WHERE del_flag = 0 AND online_share_status IN ('SUCCESS', 'RECORDED')
                <if test="sixBefore != null">
                    AND create_time &gt;= #{sixBefore}
                </if>
                <if test="siteIds != null and siteIds.size() > 0">
                    AND site_id IN
                    <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
                        #{siteId}
                    </foreach>
                </if>
                GROUP BY DATE_FORMAT(create_time, '%m')
            </when>
            <otherwise>
                SELECT DATE_FORMAT(billing_cycle, '%m') AS MONTH,
                       ROUND(SUM(IFNULL(total_electricity_charge, 0)), 2) AS electrovalence,
                       ROUND(SUM(IFNULL(total_service_fee, 0) - IFNULL(tripartite_commission, 0)), 2) AS service_charge
                FROM t_charging_settlement_bill
                WHERE statistical_date_type = 1 AND site_id != 0
                <if test="sixBefore != null">
                    AND billing_cycle &gt;= #{sixBefore}
                </if>
                <if test="siteIds != null and siteIds.size() > 0">
                    AND site_id IN
                    <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
                        #{siteId}
                    </foreach>
                </if>
                GROUP BY DATE_FORMAT(billing_cycle, '%m')
            </otherwise>
        </choose>
    </select>
    <select id="circle" resultType="com.ruoyi.order.dto.SixCircleDto">
        <choose>
        <when test="partnerView != null and partnerView">
        SELECT
        a.site_id as siteId,
        ROUND(SUM(IFNULL(s.share_amount, 0)), 2) AS paymentAmount
        FROM t_charging_order a
        LEFT JOIN (
            SELECT charging_order_id, SUM(IFNULL(share_amount, 0)) AS share_amount
            FROM t_charging_order_share_record
            WHERE del_flag = 0 AND charging_order_id IS NOT NULL AND online_share_status = 'SUCCESS'
            GROUP BY charging_order_id
        ) s ON a.id = s.charging_order_id
        <where>
            a.del_flag = 0 and a.recharge_payment_status = 2
            <if test="siteIds != null and siteIds.size() > 0">
                AND a.site_id IN
                <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
                    #{siteId}
                </foreach>
            </if>
            <if test="sixBefore != null">
                AND a.create_time &gt;= #{sixBefore}
            </if>
        </where>
        GROUP BY a.site_id
        </when>
        <otherwise>
        SELECT
        a.site_id as siteId,
        ROUND(SUM(CASE
        WHEN a.order_source = 0 THEN IFNULL(b.period_electric_price, 0) + IFNULL(b.period_service_price, 0)
        WHEN a.order_source = 1 THEN IFNULL(b.period_electric_price, 0) + IFNULL(b.period_service_price, 0)
        ELSE (IFNULL(b.period_electric_price, 0) + IFNULL(b.period_service_price, 0) * 0.8)
        END), 2) AS paymentAmount
        FROM
        t_charging_order a
        LEFT JOIN t_charging_order_accounting_strategy b ON a.id = b.charging_order_id
        <where>
            a.del_flag = 0 and a.recharge_payment_status = 2 and a.status = 5
            <if test="siteIds != null and siteIds.size() > 0">
                AND a.site_id IN
                <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
                    #{siteId}
                </foreach>
            </if>
            <if test="sixBefore != null">
                AND a.create_time &gt;= #{sixBefore}
            </if>
        </where>
        GROUP BY a.site_id
        </otherwise>
            <when test="partnerView != null and partnerView">
                SELECT site_id AS siteId,
                       ROUND(SUM(IFNULL(share_amount, 0)), 2) AS paymentAmount
                FROM t_charging_order_share_record
                WHERE del_flag = 0 AND online_share_status IN ('SUCCESS', 'RECORDED')
                <if test="siteIds != null and siteIds.size() > 0">
                    AND site_id IN
                    <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
                        #{siteId}
                    </foreach>
                </if>
                <if test="sixBefore != null">
                    AND create_time &gt;= #{sixBefore}
                </if>
                GROUP BY site_id
            </when>
            <otherwise>
                SELECT site_id AS siteId,
                       ROUND(SUM(IFNULL(total_electricity_charge, 0) + IFNULL(total_service_fee, 0)
                           - IFNULL(tripartite_commission, 0)), 2) AS paymentAmount
                FROM t_charging_settlement_bill
                WHERE statistical_date_type = 1 AND site_id != 0
                <if test="siteIds != null and siteIds.size() > 0">
                    AND site_id IN
                    <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
                        #{siteId}
                    </foreach>
                </if>
                <if test="sixBefore != null">
                    AND billing_cycle &gt;= #{sixBefore}
                </if>
                GROUP BY site_id
            </otherwise>
        </choose>
    </select>
    <select id="countAll" resultType="java.util.Map">
        SELECT
        <choose>
        <when test="partnerView != null and partnerView">
        ROUND(SUM(IFNULL(s.electricity_share_amount, 0)), 2) AS electrovalence,
        ROUND(SUM(IFNULL(s.service_share_amount, 0)), 2) AS service_charge,
        ROUND(SUM(IFNULL(s.share_amount, 0)), 2) AS commission_amount,
        0 AS sharing_amount
        </when>
        <otherwise>
        ROUND(SUM(IFNULL(b.period_electric_price, 0)), 2) AS electrovalence,
        ROUND(SUM(CASE WHEN a.order_source = 2 THEN IFNULL(b.period_service_price, 0) * 0.8 ELSE IFNULL(b.period_service_price, 0) END), 2) AS service_charge,
        ROUND(SUM(IFNULL(s.share_amount, 0)), 2) AS commission_amount,
        ROUND(SUM(CASE WHEN a.order_source = 2 THEN IFNULL(b.period_service_price, 0) * 0.2 ELSE 0 END), 2) AS sharing_amount
        </otherwise>
            <when test="partnerView != null and partnerView">
                SELECT COALESCE(ROUND(SUM(IFNULL(electricity_share_amount, 0)), 2), 0) AS electrovalence,
                       COALESCE(ROUND(SUM(IFNULL(service_share_amount, 0)), 2), 0) AS service_charge,
                       COALESCE(ROUND(SUM(IFNULL(share_amount, 0)), 2), 0) AS commission_amount,
                       0 AS sharing_amount
                FROM t_charging_order_share_record
                WHERE del_flag = 0 AND online_share_status IN ('SUCCESS', 'RECORDED')
                <if test="siteIds != null and siteIds.size() > 0">
                    AND site_id IN
                    <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
                        #{siteId}
                    </foreach>
                </if>
            </when>
            <otherwise>
                SELECT COALESCE(ROUND(SUM(IFNULL(total_electricity_charge, 0)), 2), 0) AS electrovalence,
                       COALESCE(ROUND(SUM(IFNULL(total_service_fee, 0) - IFNULL(tripartite_commission, 0)), 2), 0) AS service_charge,
                       0 AS commission_amount,
                       COALESCE(ROUND(SUM(IFNULL(tripartite_commission, 0)), 2), 0) AS sharing_amount
                FROM t_charging_settlement_bill
                WHERE statistical_date_type = 1 AND site_id != 0
                <if test="siteIds != null and siteIds.size() > 0">
                    AND site_id IN
                    <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
                        #{siteId}
                    </foreach>
                </if>
            </otherwise>
        </choose>
        FROM t_charging_order a
        LEFT JOIN (
            SELECT charging_order_id,
            SUM(IFNULL(period_electric_price, 0)) AS period_electric_price,
            SUM(IFNULL(period_service_price, 0)) AS period_service_price
            FROM t_charging_order_accounting_strategy
            GROUP BY charging_order_id
        ) b ON a.id = b.charging_order_id
        LEFT JOIN (
            SELECT charging_order_id,
            SUM(IFNULL(electricity_share_amount, 0)) AS electricity_share_amount,
            SUM(IFNULL(service_share_amount, 0)) AS service_share_amount,
            SUM(IFNULL(share_amount, 0)) AS share_amount
            FROM t_charging_order_share_record
            WHERE del_flag = 0 AND charging_order_id IS NOT NULL AND online_share_status = 'SUCCESS'
            GROUP BY charging_order_id
        ) s ON a.id = s.charging_order_id
        WHERE a.del_flag = 0 AND a.recharge_payment_status = 2
        <if test="partnerView == null or !partnerView">
            AND a.status = 5
        </if>
    </select>
    <select id="sumSuccessfulShareAmount" resultType="java.math.BigDecimal">
        SELECT COALESCE(ROUND(SUM(IFNULL(share_amount, 0)), 2), 0)
        FROM t_charging_order_share_record
        WHERE del_flag = 0 AND online_share_status IN ('SUCCESS', 'RECORDED')
        <if test="siteIds != null and siteIds.size() > 0">
            AND a.site_id IN
            AND site_id IN
            <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
                #{siteId}
            </foreach>
ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/controller/TOrderInvoiceControllerTest.java
New file
@@ -0,0 +1,29 @@
package com.ruoyi.order.controller;
import com.ruoyi.order.api.vo.TOrderInvoiceVO;
import org.apache.poi.ss.usermodel.Workbook;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import java.math.BigDecimal;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertNotNull;
class TOrderInvoiceControllerTest {
    @Test
    void buildsWorkbookForSingleInvoice() {
        TOrderInvoiceVO invoice = new TOrderInvoiceVO();
        invoice.setId(2034946998168854530L);
        invoice.setCode("16120260320185546502");
        invoice.setName("测试企业");
        invoice.setTotalAmount(new BigDecimal("51.20"));
        TOrderInvoiceController controller = new TOrderInvoiceController();
        Workbook workbook = ReflectionTestUtils.invokeMethod(controller, "buildInvoiceWorkbook", invoice);
        assertNotNull(workbook);
        assertDoesNotThrow(() -> workbook.close());
    }
}
ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/service/impl/ChargingOrderShareConfigurationTest.java
@@ -20,6 +20,7 @@
        partner.setIcbcSubMerPrtclNo("2310119900550201");
        assertTrue(TChargingOrderServiceImpl.shouldProcessIcbcOnlineShare("ICBC", new BigDecimal("1.00"), partner));
        assertFalse(TChargingOrderServiceImpl.shouldProcessIcbcOnlineShare(false, "ICBC", new BigDecimal("1.00"), partner));
        assertFalse(TChargingOrderServiceImpl.shouldProcessIcbcOnlineShare("ICBC", BigDecimal.ZERO, partner));
        assertFalse(TChargingOrderServiceImpl.shouldProcessIcbcOnlineShare("BALANCE", new BigDecimal("1.00"), partner));
    }
ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/service/impl/PlatformRevenueAnalysisTest.java
New file
@@ -0,0 +1,62 @@
package com.ruoyi.order.service.impl;
import com.ruoyi.order.mapper.TChargingOrderMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
class PlatformRevenueAnalysisTest {
    private TChargingOrderServiceImpl service;
    private TChargingOrderMapper mapper;
    private List<Integer> siteIds;
    @BeforeEach
    void setUp() {
        service = new TChargingOrderServiceImpl();
        mapper = mock(TChargingOrderMapper.class);
        siteIds = new ArrayList<>();
        siteIds.add(122);
        siteIds.add(123);
        ReflectionTestUtils.setField(service, "baseMapper", mapper);
    }
    @Test
    void platformViewAddsSuccessfulPartnerShareAmount() {
        Map<String, Object> totals = new HashMap<>();
        totals.put("electrovalence", new BigDecimal("100.00"));
        when(mapper.countAll(siteIds, false)).thenReturn(totals);
        when(mapper.sumSuccessfulShareAmount(siteIds)).thenReturn(new BigDecimal("12.34"));
        Map<String, Object> result = service.countAll(siteIds, false);
        assertSame(totals, result);
        assertEquals(new BigDecimal("12.34"), result.get("commission_amount"));
        verify(mapper).sumSuccessfulShareAmount(siteIds);
    }
    @Test
    void partnerViewUsesShareRecordTotalsWithoutASecondQuery() {
        Map<String, Object> totals = new HashMap<>();
        totals.put("commission_amount", new BigDecimal("8.90"));
        when(mapper.countAll(siteIds, true)).thenReturn(totals);
        Map<String, Object> result = service.countAll(siteIds, true);
        assertSame(totals, result);
        assertEquals(new BigDecimal("8.90"), result.get("commission_amount"));
        verify(mapper, never()).sumSuccessfulShareAmount(siteIds);
    }
}
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TGoodsController.java
@@ -36,10 +36,11 @@
import com.ruoyi.other.service.TGoodsService;
import com.ruoyi.other.util.RedisLock;
import com.ruoyi.payment.api.feignClient.AliPaymentClient;
import com.ruoyi.payment.api.feignClient.WxPaymentClient;
import com.ruoyi.payment.api.feignClient.IcbcPaymentClient;
import com.ruoyi.payment.api.vo.AliPaymentReq;
import com.ruoyi.payment.api.vo.AliPaymentResp;
import com.ruoyi.payment.api.vo.PaymentOrder;
import com.ruoyi.payment.api.vo.IcbcPaymentReq;
import com.ruoyi.payment.api.vo.IcbcPaymentResp;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
@@ -80,7 +81,7 @@
    @Resource
    private TCouponService couponService;
    @Resource
    private WxPaymentClient wxPaymentClient;
    private IcbcPaymentClient icbcPaymentClient;
    @Resource
    private RedisService redisService;
    
@@ -379,18 +380,31 @@
        exchangeDto.setVipDiscount(vipDiscount);
        exchangeDto.setUserId(userId);
        exchangeDto.setPhone(user.getPhone());
        boolean wechatMiniProgramPay = exchangeDto.getPayMethod() == 1;
        if (wechatMiniProgramPay) {
            exchangeDto.setPayMethod(3);
        }
        //创建订单
        TShoppingOrder shopOrder = orderClient.shopCreate(exchangeDto).getData();
        if (exchangeDto.getPayMethod()==1) {
            //调起支付
            PaymentOrder paymentOrder = new PaymentOrder();
            paymentOrder.setCode(shopOrder.getCode());
            paymentOrder.setAmount(exchangeDto.getPayPrice());
            paymentOrder.setOpenId(user.getWxOpenid());
            paymentOrder.setDescription("购买商品");
            R<Map<String, Object>> mapR = wxPaymentClient.orderPay(paymentOrder);
            mapR.getData().put("orderId",shopOrder.getId().toString());
            return    mapR;
        if (wechatMiniProgramPay) {
            IcbcPaymentReq paymentReq = new IcbcPaymentReq();
            paymentReq.setOutTradeNo(shopOrder.getCode());
            paymentReq.setAmount(exchangeDto.getPayPrice());
            paymentReq.setOpenId(user.getWxOpenid());
            paymentReq.setPaymentType(1);
            paymentReq.setSubject("购买商品");
            paymentReq.setBody(exchangeDto.getTitle());
            R<IcbcPaymentResp> paymentResult = icbcPaymentClient.payment(paymentReq);
            if (paymentResult == null || paymentResult.getCode() != 200 || paymentResult.getData() == null) {
                return R.fail(paymentResult == null ? "工行支付无响应" : paymentResult.getMsg());
            }
            IcbcPaymentResp paymentResp = paymentResult.getData();
            if (!"SUCCESS".equals(paymentResp.getStatus())) {
                return R.fail(paymentResp.getRawResponse());
            }
            Map<String, Object> data = JSON.parseObject(JSON.toJSONString(paymentResp), Map.class);
            data.put("orderId", shopOrder.getId().toString());
            return R.ok(data);
        }else {
            AliPaymentReq req = new AliPaymentReq();
            req.setOutTradeNo(shopOrder.getCode());
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/TVipServiceImpl.java
@@ -20,10 +20,11 @@
import com.ruoyi.other.service.TVipService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.payment.api.feignClient.AliPaymentClient;
import com.ruoyi.payment.api.feignClient.WxPaymentClient;
import com.ruoyi.payment.api.feignClient.IcbcPaymentClient;
import com.ruoyi.payment.api.vo.AliPaymentReq;
import com.ruoyi.payment.api.vo.AliPaymentResp;
import com.ruoyi.payment.api.vo.PaymentOrder;
import com.ruoyi.payment.api.vo.IcbcPaymentReq;
import com.ruoyi.payment.api.vo.IcbcPaymentResp;
import org.apache.poi.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -52,7 +53,7 @@
    private AppUserClient appUserClient;
    @Resource
    private WxPaymentClient wxPaymentClient;
    private IcbcPaymentClient icbcPaymentClient;
    @Resource
    private AliPaymentClient aliPaymentClient;
@@ -109,7 +110,7 @@
        shopOrder.setDiscountAmount(discountMoney);
        shopOrder.setPaymentAmount(payMoney);
        shopOrder.setPaymentStatus(1);
        shopOrder.setPaymentType(payType);
        shopOrder.setPaymentType(payType == 1 ? 3 : payType);
        shopOrder.setPayTime(LocalDateTime.now());
        shopOrder.setDelFlag(false);
        R<Long> longR = orderClient.addVipOrder(shopOrder);
@@ -118,13 +119,22 @@
        }
    
        if (payType==1){
            //调起支付
            PaymentOrder paymentOrder = new PaymentOrder();
            paymentOrder.setCode(shopOrder.getCode());
            paymentOrder.setAmount(shopOrder.getPaymentAmount());
            paymentOrder.setOpenId(user.getWxOpenid());
            paymentOrder.setDescription("购买会员");
            return AjaxResult.success(wxPaymentClient.orderPay(paymentOrder).getData());
            IcbcPaymentReq paymentReq = new IcbcPaymentReq();
            paymentReq.setOutTradeNo(shopOrder.getCode());
            paymentReq.setAmount(shopOrder.getPaymentAmount());
            paymentReq.setOpenId(user.getWxOpenid());
            paymentReq.setPaymentType(1);
            paymentReq.setSubject("购买会员");
            paymentReq.setBody(shopOrder.getTitle());
            R<IcbcPaymentResp> paymentResult = icbcPaymentClient.payment(paymentReq);
            if (paymentResult == null || paymentResult.getCode() != 200 || paymentResult.getData() == null) {
                return AjaxResult.error(paymentResult == null ? "工行支付无响应" : paymentResult.getMsg());
            }
            IcbcPaymentResp paymentResp = paymentResult.getData();
            if (!"SUCCESS".equals(paymentResp.getStatus())) {
                return AjaxResult.error(paymentResp.getRawResponse());
            }
            return AjaxResult.success(paymentResp);
        }else {
            AliPaymentReq req = new AliPaymentReq();
            req.setOutTradeNo(shopOrder.getCode());
ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/controller/IcbcPayController.java
@@ -4,6 +4,7 @@
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.order.api.feignClient.ChargingOrderClient;
import com.ruoyi.order.api.feignClient.OrderClient;
import com.ruoyi.payment.api.vo.IcbcPaymentReq;
import com.ruoyi.payment.api.vo.IcbcPaymentResp;
import com.ruoyi.payment.api.vo.IcbcRefundReq;
@@ -51,6 +52,9 @@
    @Resource
    private ChargingOrderClient chargingOrderClient;
    @Resource
    private OrderClient orderClient;
    @PostMapping("/payment")
    public R<IcbcPaymentResp> payment(@RequestBody IcbcPaymentReq req) {
@@ -242,7 +246,7 @@
                        callback.get("out_trade_no"), callback.get("transaction_id"));
            }
            log.info("工行支付回调解析结果:{}", JSON.toJSONString(callback));
            dispatchChargingOrderCallback(callback);
            dispatchPaymentCallback(callback);
            success = true;
        } catch (Exception e) {
            log.error("工行支付回调处理失败,已记录原始请求并返回fail等待重试", e);
@@ -304,7 +308,7 @@
        return values == null || values.length == 0 ? null : values[0];
    }
    private void dispatchChargingOrderCallback(Map<String, String> callback) {
    void dispatchPaymentCallback(Map<String, String> callback) {
        String outTradeNo = callback.get("out_trade_no");
        String transactionId = callback.get("transaction_id");
        String attach = callback.get("attach");
@@ -312,6 +316,17 @@
            log.info("工行测试支付回调成功,订单号:{},流水号:{},支付类型:{}", outTradeNo, transactionId, attach);
            return;
        }
        if (outTradeNo != null && outTradeNo.startsWith("HY")) {
            orderClient.vipCallBack(outTradeNo, transactionId);
            return;
        }
        if (outTradeNo != null && outTradeNo.startsWith("GW")) {
            orderClient.callBack(outTradeNo, transactionId);
            return;
        }
        if (outTradeNo == null || !outTradeNo.startsWith("CD")) {
            throw new IllegalArgumentException("工行回调订单类型不支持:" + outTradeNo);
        }
        Integer paymentType = Integer.valueOf(attach);
        if (Integer.valueOf(1).equals(paymentType)) {
            chargingOrderClient.chargingOrderWXCallback(outTradeNo, transactionId, attach);
ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/icbc/service/IcbcPaymentFlowRecorder.java
@@ -32,7 +32,7 @@
            JSONObject responseObject = parseObject(responseJson);
            IcbcPaymentFlowRecord record = new IcbcPaymentFlowRecord();
            record.setOutTradeNo(outTradeNo);
            record.setBusinessType(outTradeNo != null && outTradeNo.startsWith("ICBCTEST") ? "TEST" : "CHARGING_ORDER");
            record.setBusinessType(resolveBusinessType(outTradeNo));
            record.setEventType(eventType);
            record.setPaymentType(paymentType);
            record.setAmount(amount);
@@ -89,4 +89,17 @@
    private String truncate(String value, int maxLength) {
        return value == null || value.length() <= maxLength ? value : value.substring(0, maxLength);
    }
    private String resolveBusinessType(String outTradeNo) {
        if (outTradeNo != null && outTradeNo.startsWith("ICBCTEST")) {
            return "TEST";
        }
        if (outTradeNo != null && outTradeNo.startsWith("HY")) {
            return "VIP_ORDER";
        }
        if (outTradeNo != null && outTradeNo.startsWith("GW")) {
            return "SHOPPING_ORDER";
        }
        return "CHARGING_ORDER";
    }
}
ruoyi-service/ruoyi-payment/src/test/java/com/ruoyi/payment/controller/IcbcPayControllerDispatchTest.java
New file
@@ -0,0 +1,60 @@
package com.ruoyi.payment.controller;
import com.ruoyi.order.api.feignClient.ChargingOrderClient;
import com.ruoyi.order.api.feignClient.OrderClient;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.HashMap;
import java.util.Map;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
@ExtendWith(MockitoExtension.class)
class IcbcPayControllerDispatchTest {
    @Mock
    private ChargingOrderClient chargingOrderClient;
    @Mock
    private OrderClient orderClient;
    @InjectMocks
    private IcbcPayController controller;
    @Test
    void dispatchesVipOrderByOrderPrefix() {
        controller.dispatchPaymentCallback(callback("HY202607210001", "ICBC-VIP-1", "1"));
        verify(orderClient).vipCallBack("HY202607210001", "ICBC-VIP-1");
        verifyNoInteractions(chargingOrderClient);
    }
    @Test
    void dispatchesShoppingOrderByOrderPrefix() {
        controller.dispatchPaymentCallback(callback("GW202607210001", "ICBC-SHOP-1", "1"));
        verify(orderClient).callBack("GW202607210001", "ICBC-SHOP-1");
        verifyNoInteractions(chargingOrderClient);
    }
    @Test
    void keepsChargingOrderPaymentTypeDispatch() {
        controller.dispatchPaymentCallback(callback("CD202607210001", "ICBC-CHARGE-1", "1"));
        verify(chargingOrderClient).chargingOrderWXCallback("CD202607210001", "ICBC-CHARGE-1", "1");
        verifyNoInteractions(orderClient);
    }
    private Map<String, String> callback(String outTradeNo, String transactionId, String attach) {
        Map<String, String> callback = new HashMap<>();
        callback.put("out_trade_no", outTradeNo);
        callback.put("transaction_id", transactionId);
        callback.put("attach", attach);
        return callback;
    }
}