Administrator
10 hours ago 22365a84b9e181c2fc2d9084c90024a2728d200e
feat(order): 添加XT支付功能和确认收款功能

- 新增XT支付创建订单接口和支付接口
- 添加管理员确认收款功能,支持订单状态更新
- 集成XT支付链接配置和支付流程
- 在订单列表界面添加确认收款按钮和操作
- 更新支付方式常量,支持XT支付类型
- 添加XT支付相关的数据传输对象和验证
- 修复LWPAY支付成功消息显示问题
1 files added
9 files modified
145 ■■■■■ changed files
src/main/java/cc/mrbird/febs/mall/controller/AdminMallOrderController.java 12 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/dependentStation/ApiMallOrderController.java 45 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/dependentStation/constant/OrderConstants.java 3 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/dto/ApiOrderPayDto.java 2 ●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/dto/XtPayCreateOrderDto.java 18 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/IAdminMallOrderService.java 2 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/IApiMallOrderInfoService.java 2 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/AdminMallOrderService.java 30 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallOrderInfoServiceImpl.java 15 ●●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/modules/order/orderList.html 16 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/AdminMallOrderController.java
@@ -135,6 +135,18 @@
    }
    /**
     * 订单列表-确认收款
     *
     * @param id
     * @return
     */
    @GetMapping("insurePay/{id}")
    @ControllerEndpoint(operation = "订单列表-确认收款", exceptionMessage = "操作失败")
    public FebsResponse insurePay(@NotNull(message = "{required}") @PathVariable Long id) {
        return adminMallOrderService.insurePay(id);
    }
    /**
     * 订单列表-取消发货
     *
     * @param id
src/main/java/cc/mrbird/febs/mall/controller/dependentStation/ApiMallOrderController.java
@@ -176,6 +176,49 @@
        return new FebsResponse().success().data(iXcxPayService.getTemplateId());
    }
    // ==================== XT 支付 ====================
    /**
     * 创建订单并通过 XT 支付
     * <p>
     * 流程:创建订单 → 通过 XT 支付链接
     * <p>
     */
    @ApiOperation(value = "创建订单-XT支付", notes = "创建订单并返回XT支付")
    @PostMapping(value = "/createOrderByXtPay")
    @Limit(key = "createOrderByXtPay", period = 1, count = 1, name = "XT下单", prefix = "limit", limitType = LimitType.IP)
    public FebsResponse createOrderByXtPay(@RequestBody @Validated XtPayCreateOrderDto lwPayDto) {
        // 1. 创建订单
        AddOrderDto addOrderDto = lwPayDto.getOrder();
        Long orderId = mallOrderInfoService.createOrder(addOrderDto);
        // 2. 获取订单详情
        MallOrderInfo order = mallOrderInfoService.getById(orderId);
        if (order != null
                && OrderStatusEnum.WAIT_PAY.getValue() == order.getStatus()
        ){
            return mallOrderInfoService.createOrderByXtPay();
        }
        return new FebsResponse().fail().message("Payment channel exception");
    }
    @ApiOperation(value = "XT支付", notes = "XT支付")
    @PostMapping(value = "/payOrderByXtPay", produces = "application/json")
    public FebsResponse payOrderByXtPay(@RequestBody @Validated ApiOrderPayDto payDto) {
        Long orderId = payDto.getOrderId();
        Integer payType = payDto.getPayType();
        // 2. 获取订单详情
        MallOrderInfo order = mallOrderInfoService.getById(orderId);
        if (order != null
                && OrderConstants.PAY_TYPE_XT == payType
                && OrderStatusEnum.WAIT_PAY.getValue() == order.getStatus()
        ){
            return mallOrderInfoService.createOrderByXtPay();
        }
        return new FebsResponse().fail().message("Payment channel exception");
    }
    // ==================== LWPAY 支付 ====================
    /**
@@ -260,7 +303,7 @@
                result.put("orderNo", order.getOrderNo());
                result.put("amount", order.getAmount());
                result.put("payUrl", payUrl);
                return new FebsResponse().success().data(result).message("下单成功");
                return new FebsResponse().success().data(result).message("success");
            } catch (Exception e) {
                log.error("LWPAY 代收下单失败: orderId={}", orderId, e);
                return new FebsResponse().fail().message("Payment channel exception: " + e.getMessage());
src/main/java/cc/mrbird/febs/mall/controller/dependentStation/constant/OrderConstants.java
@@ -29,12 +29,13 @@
    public static final String ORDER_STATE = "order_state";
    /**
     * 支付方式 1-微信 2-支付宝 3-USDT
     * 支付方式 1-微信 2-支付宝 3-USDT 4-LWPAY支付 5-XT支付
     */
    public static final Integer PAY_TYPE_WECHAT = 1;
    public static final Integer PAY_TYPE_ALIPAY = 2;
    public static final Integer PAY_TYPE_USDT = 3;
    public static final Integer PAY_TYPE_SYSTEM = 4;
    public static final Integer PAY_TYPE_XT = 5;
    public static final String ORDER_PAY_TYPE = "order_pay_type";
    public static final String TRC20_SYSTEM_ADDRESS = "pay.trc20.address";
src/main/java/cc/mrbird/febs/mall/dto/ApiOrderPayDto.java
@@ -17,6 +17,6 @@
    private Long orderId;
    @NotNull(message = "支付方式不能为空")
    @ApiModelProperty(value = "支付方式 1-微信 2-支付宝 3-USDT 4-LwPAY", example = "you_ke_*****")
    @ApiModelProperty(value = "支付方式 1-微信 2-支付宝 3-USDT 4-LwPAY 5-XTPAY", example = "you_ke_*****")
    private Integer payType;
}
src/main/java/cc/mrbird/febs/mall/dto/XtPayCreateOrderDto.java
New file
@@ -0,0 +1,18 @@
package cc.mrbird.febs.mall.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
@Data
@ApiModel(value = "XtPayCreateOrderDto", description = "支付下单参数")
public class XtPayCreateOrderDto {
    @Valid
    @NotNull(message = "订单信息不能为空")
    @ApiModelProperty(value = "订单信息", required = true)
    private AddOrderDto order;
}
src/main/java/cc/mrbird/febs/mall/service/IAdminMallOrderService.java
@@ -80,4 +80,6 @@
    FebsResponse deliverPdfGoods(Long id);
    FebsResponse cancelDeliver(Long id);
    FebsResponse insurePay(Long id);
}
src/main/java/cc/mrbird/febs/mall/service/IApiMallOrderInfoService.java
@@ -48,4 +48,6 @@
    FebsResponse createOrderVerify(ApiCreateOrderVerifyDto apiCreateOrderVerifyDto);
    FebsResponse chooseCoupon(ApiChooseCouponDto chooseCouponDto);
    FebsResponse createOrderByXtPay();
}
src/main/java/cc/mrbird/febs/mall/service/impl/AdminMallOrderService.java
@@ -5,6 +5,7 @@
import cc.mrbird.febs.common.enumerates.*;
import cc.mrbird.febs.common.exception.FebsException;
import cc.mrbird.febs.common.utils.ValidateEntityUtils;
import cc.mrbird.febs.mall.controller.dependentStation.constant.OrderConstants;
import cc.mrbird.febs.mall.dto.*;
import cc.mrbird.febs.mall.entity.*;
import cc.mrbird.febs.mall.mapper.*;
@@ -16,6 +17,7 @@
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.best.javaSdk.ClientParamEnum;
@@ -31,6 +33,7 @@
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Slf4j
@@ -617,6 +620,33 @@
    }
    @Override
    public FebsResponse insurePay(Long id) {
        // 1. 查询订单
        MallOrderInfo order = mallOrderInfoMapper.selectById(id);
        if (order == null) {
            return new FebsResponse().fail().message("订单不存在,刷新后重试");
        }
        // 2. 幂等检查(避免重复回调)
        if (OrderStatusEnum.WAIT_PAY.getValue() != order.getStatus()) {
            return new FebsResponse().fail().message("订单不是代付款状态");
        }
        // 3. 更新订单状态为待发货
        mallOrderInfoMapper.update(
                null,
                Wrappers.lambdaUpdate(MallOrderInfo.class)
                        .set(MallOrderInfo::getStatus, OrderStatusEnum.WAIT_SHIPPING.getValue())
                        .set(MallOrderInfo::getPayTime, new Date())
                        .set(MallOrderInfo::getPayMethod, "XT支付")
                        .set(MallOrderInfo::getPayResult, "1")
                        .eq(MallOrderInfo::getId, order.getId())
        );
        return new FebsResponse().success();
    }
    @Override
    public void deliverGoodsByOrderNo(DeliverGoodsDto deliverGoodsDto) {
        MallOrderInfo mallOrderInfo = mallOrderInfoMapper.selectByOrderNo(deliverGoodsDto.getOrderNo());
        if (mallOrderInfo == null) {
src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallOrderInfoServiceImpl.java
@@ -1002,4 +1002,19 @@
        return new FebsResponse().success().data(objects);
    }
    @Override
    public FebsResponse createOrderByXtPay() {
        DataDictionaryCustom dataDictionaryCustom = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(
                "PAY_LINK", "XT_LINK"
        );
        if (ObjectUtil.isEmpty(dataDictionaryCustom)){
            return new FebsResponse().fail().message("Payment channel exception");
        }
        if (StrUtil.isEmpty(dataDictionaryCustom.getValue())){
            return new FebsResponse().fail().message("Payment channel exception");
        }
        return new FebsResponse().success().data(dataDictionaryCustom.getValue());
    }
}
src/main/resources/templates/febs/views/modules/order/orderList.html
@@ -357,6 +357,11 @@
                    cancelOrder(data.id);
                });
            }
            if (layEvent === 'insurePay') {
                febs.modal.confirm('收款', '确认收款?', function () {
                    insurePay(data.id);
                });
            }
            if (layEvent === 'deliverPdfGoods') {
                febs.modal.confirm('一键发货', '确认一键发货?', function (index) {
                    layer.close(index);
@@ -396,6 +401,13 @@
        function cancelOrder(id) {
            febs.get(ctx + 'admin/order/cancelOrder/' + id, null, function () {
                febs.alert.success('操作成功');
                $query.click();
            });
        }
        function insurePay(id) {
            febs.get(ctx + 'admin/order/insurePay/' + id, null, function () {
                febs.alert.success('操作成功');
                $query.click();
            });
@@ -682,7 +694,9 @@
                        // {field: 'wxOrderNo', title: '支付订单号', minWidth: 120,align:'left'},
                        {title: '操作',
                            templet: function (d) {
                                if(d.status === 2){
                                if(d.status === 1){
                                    return '<button class="layui-btn layui-btn-normal layui-btn-xs" lay-event="insurePay" shiro:hasPermission="user:update">确认收款</button>'
                                }else if(d.status === 2){
                                    return '<button class="layui-btn layui-btn-normal layui-btn-xs" lay-event="deliverGoods" shiro:hasPermission="user:update">发货</button>'
                                    +'<button class="layui-btn layui-btn-normal layui-btn-xs" lay-event="seeOrder" shiro:hasPermission="user:update">详情</button>'
                                    // +''