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

feat(order): 添加充电订单详情和威富通退款查询接口

- 新增AppletChargeController的queryOrder接口获取充电订单详情
- ChargeOrderInfoMapper及XML中增加queryOrder查询方法及相关字段联表查询
- ChargeOrderInfoService及实现类添加queryOrder方法实现
- WFTOrderService新增refundOrder接收userId参数,更新账户退款逻辑支持账户退款类型
- 新增queryRefund方法实现威富通退款查询逻辑,支持多参数优先级及退款状态解析
- AppletWFTOrderController添加退款查询接口映射及参数
- UserAccountServiceImpl完善账户退款处理,退款时清空账户余额
- 调整ChargeOrderInfoVO添加接口编码、接口名称及充电站名称字段
- SystemConstants新增账户退款相关常量定义
- 取消WechatPayV3Utils中的@PostConstruct注解避免自动初始化风险
wzq 1 день назад
Родитель
Сommit
e7eb9d1e9f

+ 14 - 4
src/main/java/com/zsElectric/boot/business/controller/applet/AppletChargeController.java

@@ -16,10 +16,7 @@ import jakarta.validation.Valid;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.poi.ss.formula.functions.T;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 @Tag(name = "充电订单相关接口")
 @Slf4j
@@ -43,6 +40,19 @@ public class AppletChargeController {
         return Result.success(page);
     }
 
+    /**
+     * 充电订单详情
+     *
+     * @param chargeOrderNo
+     * @return
+     */
+    @Operation(summary = "充电订单详情")
+    @GetMapping("/queryOrder/{chargeOrderNo}")
+    public Result<ChargeOrderInfoVO> queryOrder(@PathVariable("chargeOrderNo") String chargeOrderNo) {
+        ChargeOrderInfoVO infoVO = chargeOrderInfoService.queryOrder(chargeOrderNo);
+        return Result.success(infoVO);
+    }
+
     /**
      * 启用充电
      *

+ 18 - 14
src/main/java/com/zsElectric/boot/business/controller/applet/AppletWFTOrderController.java

@@ -2,11 +2,13 @@ package com.zsElectric.boot.business.controller.applet;
 
 import com.zsElectric.boot.business.model.form.applet.AppLevelOrderForm;
 import com.zsElectric.boot.business.model.form.applet.AppUserPayForm;
+import com.zsElectric.boot.business.model.vo.applet.WFTRefundQueryVO;
 import com.zsElectric.boot.business.service.WFTOrderService;
 import com.zsElectric.boot.common.annotation.Log;
 import com.zsElectric.boot.common.enums.LogModuleEnum;
 import com.zsElectric.boot.common.util.IPUtils;
 import com.zsElectric.boot.core.web.Result;
+import com.zsElectric.boot.security.util.SecurityUtils;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -17,6 +19,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.*;
 
 import java.io.IOException;
+import java.util.Map;
 
 /**
  * 威富通订单控制器
@@ -139,7 +142,8 @@ public class AppletWFTOrderController {
     @PutMapping("/refundOrder")
     @Log(value = "账户退款", module = LogModuleEnum.APP_ORDER)
     public Result<String> refundOrder() throws Exception {
-        return Result.success(wftOrderService.refundOrder());
+        Long userId = SecurityUtils.getUserId();
+        return Result.success(wftOrderService.refundOrder(userId));
     }
 
     /**
@@ -165,17 +169,17 @@ public class AppletWFTOrderController {
      * @param refundId 平台退款单号(与outTradeNo/transactionId/outRefundNo四选一,优先级最高)
      * @return 退款查询结果
      */
-//    @Operation(summary = "查询退款")
-//    @GetMapping("/refund/query")
-//    public Result<WFTRefundQueryVO> queryRefund(
-//            @Parameter(description = "商户订单号(四选一)") @RequestParam(required = false) String outTradeNo,
-//            @Parameter(description = "平台订单号(四选一)") @RequestParam(required = false) String transactionId,
-//            @Parameter(description = "商户退款单号(四选一)") @RequestParam(required = false) String outRefundNo,
-//            @Parameter(description = "平台退款单号(四选一,优先级最高)") @RequestParam(required = false) String refundId) {
-//
-//        WFTRefundQueryVO result = wftOrderService.queryRefundVO(
-//                outTradeNo, transactionId, outRefundNo, refundId);
-//
-//        return Result.success(result);
-//    }
+    @Operation(summary = "查询退款")
+    @GetMapping("/refund/query")
+    public Result<Map<String, Object>> queryRefund(
+            @Parameter(description = "商户订单号(四选一)") @RequestParam(required = false) String outTradeNo,
+            @Parameter(description = "平台订单号(四选一)") @RequestParam(required = false) String transactionId,
+            @Parameter(description = "商户退款单号(四选一)") @RequestParam(required = false) String outRefundNo,
+            @Parameter(description = "平台退款单号(四选一,优先级最高)") @RequestParam(required = false) String refundId) {
+
+        Map<String, Object> result = wftOrderService.queryRefund(
+                outTradeNo, transactionId, outRefundNo, refundId);
+
+        return Result.success(result);
+    }
 }

+ 2 - 0
src/main/java/com/zsElectric/boot/business/mapper/ChargeOrderInfoMapper.java

@@ -28,4 +28,6 @@ public interface ChargeOrderInfoMapper extends BaseMapper<ChargeOrderInfo> {
     Page<ChargeOrderInfoVO> getChargeOrderInfoPage(Page<ChargeOrderInfoVO> page, ChargeOrderInfoQuery queryParams);
 
     Page<ChargeOrderInfoVO> getPage(Page<Object> objectPage,@Param("queryParams") AppChargeOrderInfoQuery queryParams);
+
+    ChargeOrderInfoVO queryOrder(@Param("chargeOrderNo") String chargeOrderNo);
 }

+ 6 - 0
src/main/java/com/zsElectric/boot/business/model/vo/ChargeOrderInfoVO.java

@@ -114,4 +114,10 @@ public class ChargeOrderInfoVO implements Serializable {
     private Integer version;
     @Schema(description = "逻辑删除(0-未删除 1-已删除)")
     private Integer isDeleted;
+    @Schema(description = "充电设备接口编码")
+    private String connectorId;
+    @Schema(description = "充电设备接口名称")
+    private String connectorName;
+    @Schema(description = "充电站名称")
+    private String stationName;
 }

+ 2 - 0
src/main/java/com/zsElectric/boot/business/service/ChargeOrderInfoService.java

@@ -71,4 +71,6 @@ public interface ChargeOrderInfoService extends IService<ChargeOrderInfo> {
      * @param chargeOrderId 充电订单ID
      */
     void orderSettlement(Long chargeOrderId);
+
+    ChargeOrderInfoVO queryOrder(String chargeOrderNo);
 }

+ 153 - 13
src/main/java/com/zsElectric/boot/business/service/WFTOrderService.java

@@ -3,18 +3,12 @@ package com.zsElectric.boot.business.service;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import com.google.gson.Gson;
-import com.google.gson.JsonObject;
 import com.zsElectric.boot.business.mapper.*;
 import com.zsElectric.boot.business.model.entity.*;
 import com.zsElectric.boot.business.model.form.applet.AppLevelOrderForm;
 import com.zsElectric.boot.business.model.form.applet.AppUserPayForm;
-import com.zsElectric.boot.business.model.vo.applet.WFTOrderVO;
-import com.zsElectric.boot.business.model.vo.applet.WechatPayParamsVO;
 import com.zsElectric.boot.common.constant.SystemConstants;
 import com.zsElectric.boot.core.exception.BusinessException;
-import com.zsElectric.boot.core.pay.WFT.WFTConstants;
-import com.zsElectric.boot.core.pay.WechatUrlConstants;
 import com.zsElectric.boot.core.pay.swiftpass.config.SwiftpassConfig;
 import com.zsElectric.boot.core.pay.swiftpass.util.PayUtill;
 import com.zsElectric.boot.core.pay.swiftpass.util.SignUtil;
@@ -22,14 +16,12 @@ import com.zsElectric.boot.core.pay.swiftpass.util.SignUtils;
 import com.zsElectric.boot.core.pay.swiftpass.util.XmlUtils;
 import com.zsElectric.boot.security.util.SecurityUtils;
 import jakarta.annotation.Resource;
-import jakarta.servlet.ServletException;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.validation.Valid;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.io.IOException;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.text.SimpleDateFormat;
@@ -774,11 +766,11 @@ public class WFTOrderService {
      * @return
      */
     @Transactional(rollbackFor = Exception.class)
-    public String refundOrder() throws Exception {
+    public String refundOrder(Long userId) throws Exception {
 
         //查询账户余额
         UserAccount userAccount =
-                userAccountService.getOne(Wrappers.<UserAccount>lambdaQuery().eq(UserAccount::getUserId, SecurityUtils.getUserId()).last("limit 1"));
+                userAccountService.getOne(Wrappers.<UserAccount>lambdaQuery().eq(UserAccount::getUserId, userId).last("limit 1"));
         if (userAccount.getBalance().compareTo(BigDecimal.ZERO) == 0) {
             return  "账户余额为 0";
         }
@@ -817,12 +809,12 @@ public class WFTOrderService {
             }
             if ((userOrderInfo.getOrderMoney().subtract(userOrderInfo.getRefundMoney())).compareTo(refundMoney) < 0) {
                 //退款金额小于订单金额,则先退订单金额
-                refundOrder(userOrderInfo,userOrderInfo.getOrderMoney().subtract(userOrderInfo.getRefundMoney()), "账户退款", SystemConstants.STATUS_ONE);
+                refundOrder(userOrderInfo,userOrderInfo.getOrderMoney().subtract(userOrderInfo.getRefundMoney()), "账户退款", SystemConstants.STATUS_TWO);
                 //账户变动及日志记录
                 userAccountService.updateAccountBalanceAndLog(
                         SecurityUtils.getUserId(),
                         userOrderInfo.getOrderMoney().subtract(userOrderInfo.getRefundMoney()),
-                        SystemConstants.CHANGE_TYPE_REDUCE,
+                        SystemConstants.ACCOUNT_REFUND,
                         SystemConstants.ACCOUNT_LOG_REFUND_NOTE,
                         userOrderInfo.getId()
                 );
@@ -832,7 +824,7 @@ public class WFTOrderService {
                 refundMoney = refundMoney.subtract(userOrderInfo.getOrderMoney());
             }
         }
-        return "账户退款,预计3个工作日内分一笔或多笔退还!如未收到,请联系客服!";
+        return "账户退款,预计3个工作日内分一笔或多笔退还!到期如未收到,请联系客服处理!";
     }
 
     public void refundOrder(UserOrderInfo userOrderInfo, BigDecimal refundAmount, String reason, Integer type) throws Exception {
@@ -890,4 +882,152 @@ public class WFTOrderService {
         }
 
     }
+    /**
+     * 退款查询
+     *
+     * 应用场景:
+     * 1. 提交退款申请后,通过调用该接口查询退款状态
+     * 2. 退款有一定延时,请在3个工作日后重新查询退款状态
+     *
+     * 参数优先级:
+     * refund_id > out_refund_no > transaction_id > out_trade_no
+     *
+     * 退款状态:
+     * - SUCCESS:退款成功
+     * - FAIL:退款失败
+     * - PROCESSING:退款处理中
+     * - CHANGE:转入代发,退款到银行发现用户的卡作废或者冻结了,
+     *           导致原路退款银行卡失败,资金回流到商户的现金帐号,
+     *           需要商户人工干预,通过线下或者平台转账的方式进行退款
+     *
+     * @param outTradeNo 商户订单号(四选一)
+     * @param transactionId 平台订单号(四选一)
+     * @param outRefundNo 商户退款单号(四选一)
+     * @param refundId 平台退款单号(四选一,优先级最高)
+     * @return 退款查询结果
+     */
+    public Map<String, Object> queryRefund(String outTradeNo, String transactionId, 
+                                           String outRefundNo, String refundId) {
+        log.info("========== 开始查询退款状态 ==========");
+        log.info("查询参数: outTradeNo={}, transactionId={}, outRefundNo={}, refundId={}",
+                outTradeNo, transactionId, outRefundNo, refundId);
+
+        try {
+            // 1. 参数校验 - 四个参数至少需要一个
+            if (outTradeNo == null && transactionId == null && 
+                outRefundNo == null && refundId == null) {
+                log.error("退款查询参数不能全为空");
+                Map<String, Object> errorResult = new HashMap<>();
+                errorResult.put("status", "500");
+                errorResult.put("msg", "查询参数不能全为空,请提供 outTradeNo/transactionId/outRefundNo/refundId 中的任意一个");
+                return errorResult;
+            }
+
+            // 2. 构建查询请求参数
+            SortedMap<String, String> queryParams = new TreeMap<>();
+            
+            // 按优先级添加参数:refund_id > out_refund_no > transaction_id > out_trade_no
+            if (refundId != null && !refundId.trim().isEmpty()) {
+                queryParams.put("refund_id", refundId);
+            } else if (outRefundNo != null && !outRefundNo.trim().isEmpty()) {
+                queryParams.put("out_refund_no", outRefundNo);
+            } else if (transactionId != null && !transactionId.trim().isEmpty()) {
+                queryParams.put("transaction_id", transactionId);
+            } else if (outTradeNo != null && !outTradeNo.trim().isEmpty()) {
+                queryParams.put("out_trade_no", outTradeNo);
+            }
+            
+            queryParams.put("sign_type", "RSA_1_256"); // 签名方式
+
+            // 3. 调用威富通退款查询API
+            PayUtill payUtill = new PayUtill();
+            Map<String, Object> queryResult = payUtill.refundQuery(queryParams, swiftpassConfig);
+
+            log.info("威富通退款查询返回结果: {}", queryResult);
+
+            // 4. 解析查询结果
+            if ("200".equals(queryResult.get("status"))) {
+                @SuppressWarnings("unchecked")
+                Map<String, String> dataMap = (Map<String, String>) queryResult.get("data");
+                
+                if (dataMap == null) {
+                    log.error("退款查询结果数据为空");
+                    queryResult.put("status", "500");
+                    queryResult.put("msg", "查询结果数据为空");
+                    return queryResult;
+                }
+
+                // 5. 检查业务结果
+                String status = dataMap.get("status");
+                String resultCode = dataMap.get("result_code");
+                
+                if (!"0".equals(status) || !"0".equals(resultCode)) {
+                    log.error("退款查询失败: status={}, result_code={}, err_code={}, err_msg={}",
+                            status, resultCode, dataMap.get("err_code"), dataMap.get("err_msg"));
+                    queryResult.put("status", "500");
+                    queryResult.put("msg", dataMap.get("err_msg"));
+                    return queryResult;
+                }
+
+                // 6. 解析退款记录信息
+                Integer refundCount = Integer.parseInt(dataMap.getOrDefault("refund_count", "0"));
+                log.info("退款笔数: {}", refundCount);
+
+                // 7. 构造返回结果
+                Map<String, Object> result = new HashMap<>();
+                result.put("status", "200");
+                result.put("mch_id", dataMap.get("mch_id"));
+                result.put("trade_type", dataMap.get("trade_type"));
+                result.put("out_transaction_id", dataMap.get("out_transaction_id"));
+                result.put("transaction_id", dataMap.get("transaction_id"));
+                result.put("out_trade_no", dataMap.get("out_trade_no"));
+                result.put("refund_count", refundCount);
+
+                // 8. 解析退款记录列表(支持多笔退款)
+                if (refundCount > 0) {
+                    java.util.List<Map<String, Object>> refundList = new java.util.ArrayList<>();
+                    
+                    for (int i = 0; i < refundCount; i++) {
+                        Map<String, Object> refundRecord = new HashMap<>();
+                        String suffix = "_" + i;
+                        
+                        // 提取每笔退款的详细信息
+                        refundRecord.put("out_refund_id", dataMap.get("out_refund_id" + suffix));
+                        refundRecord.put("out_refund_no", dataMap.get("out_refund_no" + suffix));
+                        refundRecord.put("refund_id", dataMap.get("refund_id" + suffix));
+                        refundRecord.put("refund_channel", dataMap.get("refund_channel" + suffix));
+                        refundRecord.put("refund_fee", dataMap.get("refund_fee" + suffix));
+                        refundRecord.put("coupon_refund_fee", dataMap.get("coupon_refund_fee" + suffix));
+                        refundRecord.put("refund_time", dataMap.get("refund_time" + suffix));
+                        refundRecord.put("refund_status", dataMap.get("refund_status" + suffix));
+                        refundRecord.put("refund_status_info", dataMap.get("refund_status_info" + suffix));
+                        
+                        refundList.add(refundRecord);
+                        
+                        log.info("退款记录[{}]: refund_id={}, refund_status={}, refund_fee={}",
+                                i, refundRecord.get("refund_id"), 
+                                refundRecord.get("refund_status"), 
+                                refundRecord.get("refund_fee"));
+                    }
+                    
+                    result.put("refund_list", refundList);
+                }
+
+                log.info("退款查询成功");
+                return result;
+            } else {
+                log.error("退款查询调用失败: {}", queryResult);
+                return queryResult;
+            }
+
+        } catch (Exception e) {
+            log.error("查询退款状态异常", e);
+            Map<String, Object> errorResult = new HashMap<>();
+            errorResult.put("status", "500");
+            errorResult.put("msg", "系统异常: " + e.getMessage());
+            return errorResult;
+        } finally {
+            log.info("========== 退款状态查询完成 ==========");
+        }
+    }
 }

+ 5 - 0
src/main/java/com/zsElectric/boot/business/service/impl/ChargeOrderInfoServiceImpl.java

@@ -306,6 +306,11 @@ public class ChargeOrderInfoServiceImpl extends ServiceImpl<ChargeOrderInfoMappe
         );
     }
 
+    @Override
+    public ChargeOrderInfoVO queryOrder(String chargeOrderNo) {
+        return baseMapper.queryOrder(chargeOrderNo);
+    }
+
     /**
      * 创建商户订单号
      * 要求 32个字符内,只能是数字、大小写字母_-|*且在同一个商户号下唯一

+ 7 - 1
src/main/java/com/zsElectric/boot/business/service/impl/UserAccountServiceImpl.java

@@ -140,8 +140,14 @@ public class UserAccountServiceImpl extends ServiceImpl<UserAccountMapper, UserA
             // 减去账户余额
             userAccount.setRedeemBalance(finalBalance);
         }
+        //退款
+        else if (SystemConstants.ACCOUNT_REFUND.equals(changeType)) {
+            // 清空账户余额,兑换余额不可退
+            finalBalance = BigDecimal.ZERO;
+            userAccount.setBalance(finalBalance);
+        }
         else{
-            // 减少余额,有限减少兑换余额,不够的再减抵用余额
+            // 减少余额,优先减少兑换余额,不够的再减抵用余额
             if (userAccount.getRedeemBalance().compareTo(changeAmount) >= 0) {
                 // 兑换余额充足,直接减少
                 finalBalance = userAccount.getBalance().subtract(changeAmount);

+ 2 - 1
src/main/java/com/zsElectric/boot/common/constant/SystemConstants.java

@@ -52,11 +52,12 @@ public interface SystemConstants {
     String ACCOUNT_LOG_BACK_TAX_NOTE = "补缴欠费";
 
     /**
-     * 变更记录类型  1-增加 2-减少
+     * 变更记录类型  1-增加 2-减少 3-兑换增加 账户退款
      */
     Integer CHANGE_TYPE_ADD = 1;
     Integer CHANGE_TYPE_REDUCE = 2;
     Integer REDEEM_CHANGE_TYPE_ADD = 3;
+    Integer ACCOUNT_REFUND = 4;
 
     /**
      * 账户类型  1-个人账户 2-集团账户

+ 1 - 1
src/main/java/com/zsElectric/boot/core/pay/WechatPayV3Utils.java

@@ -43,7 +43,7 @@ public class WechatPayV3Utils {
 
 
     // 初始化证书和客户端
-    @PostConstruct
+    //@PostConstruct
     public void init() {
         try {
             // 加载商户私钥

+ 115 - 50
src/main/resources/mapper/business/ChargeOrderInfoMapper.xml

@@ -78,69 +78,134 @@
     </select>
     <select id="getPage" resultType="com.zsElectric.boot.business.model.vo.ChargeOrderInfoVO">
         SELECT
-        id,
-        user_id,
-        order_type,
-        equipment_id,
-        charge_order_no,
-        start_time,
-        end_time,
-        charge_time,
-        status,
-        third_party_total_cost,
-        third_party_serverfee,
-        third_party_elecfee,
-        total_charge,
-        real_cost,
-        real_service_cost,
-        stop_type,
-        phone_num,
-        plate_num,
-        stop_reason,
-        charge_details,
-        third_party_station_id,
-        pre_amt,
-        real_predict_service_cost,
-        masp_amount,
-        masp_real_amount,
-        total_masp_money,
-        masp_status,
-        masp_time,
-        masp_desc,
-        discount_money,
-        discount_desc,
-        discount_info_id,
-        real_third_cost,
-        firm_id,
-        firm_price,
-        coupon_price,
-        coupon_id,
-        remark,
-        create_by,
-        create_time,
-        update_by,
-        update_time,
-        version,
-        is_deleted
+        coi.id,
+        coi.user_id,
+        coi.order_type,
+        coi.equipment_id,
+        coi.charge_order_no,
+        coi.start_time,
+        coi.end_time,
+        coi.charge_time,
+        coi.status,
+        coi.third_party_total_cost,
+        coi.third_party_serverfee,
+        coi.third_party_elecfee,
+        coi.total_charge,
+        coi.real_cost,
+        coi.real_service_cost,
+        coi.stop_type,
+        coi.phone_num,
+        coi.plate_num,
+        coi.stop_reason,
+        coi.charge_details,
+        coi.third_party_station_id,
+        coi.pre_amt,
+        coi.real_predict_service_cost,
+        coi.masp_amount,
+        coi.masp_real_amount,
+        coi.total_masp_money,
+        coi.masp_status,
+        coi.masp_time,
+        coi.masp_desc,
+        coi.discount_money,
+        coi.discount_desc,
+        coi.discount_info_id,
+        coi.real_third_cost,
+        coi.firm_id,
+        coi.firm_price,
+        coi.coupon_price,
+        coi.coupon_id,
+        coi.remark,
+        coi.create_by,
+        coi.create_time,
+        coi.update_by,
+        coi.update_time,
+        coi.version,
+        coi.is_deleted,
+        pci.connector_id,
+        pci.connector_name,
+        psi.station_name
         FROM
-        c_charge_order_info
+        c_charge_order_info coi
+        left JOIN third_party_connector_info pci ON coi.connector_id = pci.connector_id
+        LEFT JOIN third_party_station_info psi ON pci.station_id = psi.station_id
         <where>
-            is_deleted = 0
+            coi.is_deleted = 0
             <if test="queryParams.userId != null">
-                AND user_id = #{queryParams.userId}
+                AND coi.user_id = #{queryParams.userId}
             </if>
             <if test="queryParams.status != null">
-                AND status = #{queryParams.status}
+                AND coi.status = #{queryParams.status}
             </if>
             <if test="queryParams.startTime != null">
-                AND create_time <![CDATA[  >=  ]]> #{queryParams.startTime,jdbcType=DATE}
+                AND coi.create_time <![CDATA[  >=  ]]> #{queryParams.startTime,jdbcType=DATE}
             </if>
             <if test="queryParams.endTime != null">
-                AND create_time <![CDATA[  <=  ]]> #{queryParams.endTime,jdbcType=DATE}
+                AND coi.create_time <![CDATA[  <=  ]]> #{queryParams.endTime,jdbcType=DATE}
             </if>
         </where>
         ORDER BY
         create_time DESC
     </select>
+    <select id="queryOrder" resultType="com.zsElectric.boot.business.model.vo.ChargeOrderInfoVO">
+        SELECT
+        coi.id,
+        coi.user_id,
+        coi.order_type,
+        coi.equipment_id,
+        coi.charge_order_no,
+        coi.start_time,
+        coi.end_time,
+        coi.charge_time,
+        coi.status,
+        coi.third_party_total_cost,
+        coi.third_party_serverfee,
+        coi.third_party_elecfee,
+        coi.total_charge,
+        coi.real_cost,
+        coi.real_service_cost,
+        coi.stop_type,
+        coi.phone_num,
+        coi.plate_num,
+        coi.stop_reason,
+        coi.charge_details,
+        coi.third_party_station_id,
+        coi.pre_amt,
+        coi.real_predict_service_cost,
+        coi.masp_amount,
+        coi.masp_real_amount,
+        coi.total_masp_money,
+        coi.masp_status,
+        coi.masp_time,
+        coi.masp_desc,
+        coi.discount_money,
+        coi.discount_desc,
+        coi.discount_info_id,
+        coi.real_third_cost,
+        coi.firm_id,
+        coi.firm_price,
+        coi.coupon_price,
+        coi.coupon_id,
+        coi.remark,
+        coi.create_by,
+        coi.create_time,
+        coi.update_by,
+        coi.update_time,
+        coi.version,
+        coi.is_deleted,
+        pci.connector_id,
+        pci.connector_name,
+        psi.station_name
+        FROM
+        c_charge_order_info coi
+        left JOIN third_party_connector_info pci ON coi.connector_id = pci.connector_id
+        LEFT JOIN third_party_station_info psi ON pci.station_id = psi.station_id
+        <where>
+            coi.is_deleted = 0
+            <if test="chargeOrderNo != null and chargeOrderNo !=''">
+                AND coi.charge_order_no = #{chargeOrderNo}
+            </if>
+        </where>
+    </select>
 
 </mapper>