puzhibing
2026-05-16 b3d1411517baca17d92dcfe3a0933cdc342b3145
Merge branch '1.1' of http://120.76.84.145:10101/gitblit/r/java/Robotaxi into 1.0

# Conflicts:
# xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/payFront/CreditOrderQueryDto.java
# xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/payFront/XpPayFrontClientFallbackFactory.java
# xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/payFront/XpPayFrontClient.java
# xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/order/XpOrder.java
# xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpInvoiceController.java
# xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpOrderController.java
# xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
8个文件已添加
17个文件已修改
897 ■■■■■ 已修改文件
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/controller/TokenController.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/controller/XpAppUserController.java 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/mapper/XpPayFrontMapper.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/IXpPayFrontService.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/impl/XpPayFrontServiceImpl.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/resources/mapper/account/XpPayFrontMapper.xml 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/payFront/CreditOrderQueryDto.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/order/XpOrderClientFallbackFactory.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/order/XpOrderClient.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/payFront/XpPayFrontClient.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/account/XpPayFront.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/order/XpOrder.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-itinerary-boot/src/main/java/com/xiaopeng/itinerary/controller/XpPricingController.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/pom.xml 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpInvoiceController.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpOrderController.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/model/vo/XpOrderHistoryListVO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/IXpOrderService.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java 276 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/utils/TaskOrderSendSmsUtil.java 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/resources/mapper/order/XpOrderMapper.xml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/HttpTestController.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/util/MinistryOfTransport.java 206 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicle-convoy-boot/src/main/resources/files/易点智慧出行-营副-20250716.pdf 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicle-convoy-boot/src/main/resources/files/陈志远新复印件.pdf 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/controller/TokenController.java
@@ -158,7 +158,7 @@
    @PostMapping("/maintenance-app/base/v1/getVerificationCode")
    public R<?> verificationCodeLogin(@RequestBody AppLoginGetCodeDTO appLoginPasswordDTO) {
        if (StringUtils.isBlank(appLoginPasswordDTO.getPhoneNumber())) {
            return R.fail("璐﹀彿涓嶅瓨鍦?");
            return R.fail("手机号不能为空!");
        }
        XpOperationsUser xpOperationsUser = xpOperationsUserService.lambdaQuery()
                .in(XpOperationsUser::getPhoneNumber, SensitiveDataCryptoUtil.queryValues(appLoginPasswordDTO.getPhoneNumber()))
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/controller/XpAppUserController.java
@@ -1,11 +1,23 @@
package com.xiaopeng.account.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xiaopeng.account.mapper.XpPayFrontMapper;
import com.xiaopeng.account.model.dto.CollectAddrDTO;
import com.xiaopeng.account.service.IXpAppUserService;
import com.xiaopeng.api.dto.payFront.CreditPaySignDto;
import com.xiaopeng.api.dto.payFront.CreditPaySignQueryDto;
import com.xiaopeng.api.dto.payFront.UnsignCreditPayDto;
import com.xiaopeng.api.dto.statistics.StatisticsQueryDTO;
import com.xiaopeng.api.dto.statistics.UserStatisticsDTO;
import com.xiaopeng.api.feignClient.payFront.XpPayFrontClient;
import com.xiaopeng.api.model.account.XpAppUser;
import com.xiaopeng.api.model.account.XpPayFront;
import com.xiaopeng.api.vo.payFront.CreditPaySignQueryVo;
import com.xiaopeng.api.vo.payFront.CreditPaySignVo;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.utils.OrderCodeUtil;
import com.xiaopeng.common.core.web.domain.BaseModel;
import com.xiaopeng.unifiedverification.interceptor.XpClientCheck;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -34,6 +46,13 @@
    @Resource
    private IXpAppUserService xpAppUserService;
    @Resource
    private XpPayFrontClient xpPayFrontClient;
    @Resource
    private XpPayFrontMapper xpPayFrontMapper;
    /**
     * 获取用户统计数据(内部接口)
@@ -84,9 +103,25 @@
    public R<Boolean> appUserGetPayPwd(HttpServletRequest request) {
        // uid已通过拦截器otp校验,可以直接使用
        String uid = request.getHeader("XP-Uid");
        //调用其他接口获取 免密结果 todo yyy
        Boolean is = true;
        return R.ok(is);
        //调用其他接口获取 免密结果
        Boolean signed = false;
        CreditPaySignQueryDto creditPaySignQueryDto = new CreditPaySignQueryDto();
        creditPaySignQueryDto.setUid(Long.valueOf(uid));
        creditPaySignQueryDto.setBusinessId("xp-robotaxi");
        creditPaySignQueryDto.setCategory("009001");
        creditPaySignQueryDto.setBusinessOrderId(OrderCodeUtil.getOrderCode("MMZF"));
        R<CreditPaySignQueryVo> creditPaySignQueryVoR = xpPayFrontClient.queryCreditPaySign(creditPaySignQueryDto);
        if (creditPaySignQueryVoR.getCode()==200) {
            CreditPaySignQueryVo data = creditPaySignQueryVoR.getData();
            // 查看是否有签约的
            long count = data.getSignList().stream().filter(e -> e.getStatus().equals("VALID")).count();
            if (count > 0){
                signed = true;
            }
        }
        return R.ok(signed);
    }
    /**
@@ -95,12 +130,61 @@
    @PostMapping("/api/v1/mini-program/appUser/setPayPwd")
    @ApiOperation(value = "个人中心-设置免密结果", tags = {"小程序-设置免密结果"})
    @XpClientCheck(checkToken = false, checkOtpToken = true)
    public R<?> appUserSetPayPwd(HttpServletRequest request) {
    public R<?> appUserSetPayPwd(@RequestParam Integer status,HttpServletRequest request) {
        // uid已通过拦截器otp校验,可以直接使用
        String uid = request.getHeader("XP-Uid");
        //调用其他接口设置免密结果 todo yyy
        //调用其他接口设置免密结果
        if(status==1){
            CreditPaySignDto creditPaySignDto = new CreditPaySignDto();
            creditPaySignDto.setUid(Long.valueOf(uid));
            creditPaySignDto.setBusinessId("xp-robotaxi");
            creditPaySignDto.setCategory("009001");
            creditPaySignDto.setBusinessOrderId(OrderCodeUtil.getOrderCode("MMZF"));
            creditPaySignDto.setPayType("13");
            R<CreditPaySignVo> creditPaySignVoR = xpPayFrontClient.creditPaySign(creditPaySignDto);
            if(creditPaySignVoR.getCode()==200){
                CreditPaySignVo data = creditPaySignVoR.getData();
                XpPayFront xpPayFront = new XpPayFront();
                xpPayFront.setUserId(Long.valueOf(uid));
                xpPayFront.setBusinessOrderId(OrderCodeUtil.getOrderCode("MMZF"));
                xpPayFrontMapper.insert(xpPayFront);
                return R.ok(data);
            }
        }else {
            UnsignCreditPayDto unsignCreditPayDto = new UnsignCreditPayDto();
            unsignCreditPayDto.setUid(Long.valueOf(uid));
            unsignCreditPayDto.setBusinessId("xp-robotaxi");
            unsignCreditPayDto.setCategory("009001");
            String businessOrderId= null;
            // 查询用户开通的id
            List<XpPayFront> xpPayFronts = xpPayFrontMapper.selectList(new LambdaQueryWrapper<XpPayFront>().eq(XpPayFront::getUserId, Long.valueOf(uid)).orderByDesc(BaseModel::getCreateTime));
            if(xpPayFronts.size()>0){
                businessOrderId = xpPayFronts.get(0).getBusinessOrderId();
            }
            if(businessOrderId==null){
                return R.ok();
            }
            unsignCreditPayDto.setBusinessOrderId(businessOrderId);
            unsignCreditPayDto.setPayType("13");
            R<?> unsignCreditPayVoR = xpPayFrontClient.unsign(unsignCreditPayDto);
            if(unsignCreditPayVoR.getCode()==200){
                // 移除信息
                xpPayFrontMapper.delete(new LambdaQueryWrapper<XpPayFront>().eq(XpPayFront::getUserId, Long.valueOf(uid)));
                return R.ok();
            }
        }
        return R.ok();
    }
//-----------------------------------------------app接口------------------------------------------
}
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/mapper/XpPayFrontMapper.java
New file
@@ -0,0 +1,16 @@
package com.xiaopeng.account.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xiaopeng.api.model.account.XpPayFront;
/**
 * <p>
 * 用户免密支付记录 Mapper 接口
 * </p>
 *
 * @author xiaopeng
 * @since 2026-05-14
 */
public interface XpPayFrontMapper extends BaseMapper<XpPayFront> {
}
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/IXpPayFrontService.java
New file
@@ -0,0 +1,16 @@
package com.xiaopeng.account.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xiaopeng.api.model.account.XpPayFront;
/**
 * <p>
 * 用户免密支付记录 服务类
 * </p>
 *
 * @author xiaopeng
 * @since 2026-05-14
 */
public interface IXpPayFrontService extends IService<XpPayFront> {
}
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/impl/XpPayFrontServiceImpl.java
New file
@@ -0,0 +1,20 @@
package com.xiaopeng.account.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaopeng.account.mapper.XpPayFrontMapper;
import com.xiaopeng.account.service.IXpPayFrontService;
import com.xiaopeng.api.model.account.XpPayFront;
import org.springframework.stereotype.Service;
/**
 * <p>
 * 用户免密支付记录 服务实现类
 * </p>
 *
 * @author xiaopeng
 * @since 2026-05-14
 */
@Service
public class XpPayFrontServiceImpl extends ServiceImpl<XpPayFrontMapper, XpPayFront> implements IXpPayFrontService {
}
xp-robotaxi-account-boot/src/main/resources/mapper/account/XpPayFrontMapper.xml
New file
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xiaopeng.account.mapper.XpPayFrontMapper">
    <sql id="Base_Column_List">
        id, user_id, business_order_id, is_deleted, create_time, update_time, create_by, update_by
    </sql>
</mapper>
xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/payFront/CreditOrderQueryDto.java
@@ -12,7 +12,7 @@
    @ApiModelProperty(value = "业务方id")
    @NotBlank(message = "业务方id不能为空")
    private String businessId;
    private String businessId="xp-robotaxi";
    @ApiModelProperty(value = "业务方订单id")
    @NotBlank(message = "业务方订单id不能为空")
@@ -27,7 +27,7 @@
    @ApiModelProperty(value = "业务方类目,由支付中心分配")
    @NotBlank(message = "业务方类目不能为空")
    private String category;
    private String category="009001";
    @ApiModelProperty(value = "支付类型(芝麻后付or微信支付分),13: 微信支付分")
    @NotBlank(message = "支付类型不能为空")
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/order/XpOrderClientFallbackFactory.java
@@ -50,6 +50,12 @@
            }
            @Override
            public R<Long> hasUnPayOrder(String uid) {
                log.error("查询未支付订单失败,原因: {}", cause.getMessage());
                return R.ok(0L);
            }
            @Override
            public R<XpOrder> queryOrderById(Long orderId) {
                log.error("根据订单id查询订单信息查询失败,原因: {}", cause.getMessage());
                return R.fail("根据订单id查询订单信息查询失败" + cause.getMessage());
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/order/XpOrderClient.java
@@ -43,6 +43,12 @@
    @PostMapping("/logan/inner/order/has-unpaid-order")
    R<Long> hasUnPaodOrder(@RequestParam String uid);
    /**
     * 查询是否有未支付订单
     */
    @PostMapping("/logan/inner/order/has-unpay-order")
    R<Long> hasUnPayOrder(@RequestParam String uid);
    /**
     * 通过订单id查询订单信息
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/payFront/XpPayFrontClient.java
@@ -35,9 +35,12 @@
        fallbackFactory = XpPayFrontClientFallbackFactory.class)
public interface XpPayFrontClient {
    // 微信支付分开通接口
    @PostMapping("/logan/pay/creditPay/sign")
    R<CreditPaySignVo> creditPaySign(@RequestBody CreditPaySignDto dto);
    // 主动查询开通结果接口
    @PostMapping("/logan/pay/creditPay/sign/query")
    R<CreditPaySignQueryVo> queryCreditPaySign(@RequestBody CreditPaySignQueryDto dto);
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/account/XpPayFront.java
New file
@@ -0,0 +1,38 @@
package com.xiaopeng.api.model.account;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.xiaopeng.common.core.web.domain.BaseModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
 * <p>
 * 用户免密支付记录
 * </p>
 *
 * @author xiaopeng
 * @since 2026-05-14
 */
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("xp_pay_front")
@ApiModel(value = "XpPayFront对象", description = "用户免密支付记录")
public class XpPayFront extends BaseModel {
    private static final long serialVersionUID = 1L;
    @TableId(value = "id", type = IdType.ASSIGN_ID)
    private Long id;
    @ApiModelProperty(value = "用户ID")
    private Long userId;
    @ApiModelProperty(value = "开通免密的businessOrderId")
    private String businessOrderId;
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/order/XpOrder.java
@@ -238,6 +238,10 @@
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime tripEnd;
    @ApiModelProperty(value = "短信发送状态 0=未发送 1=已发送")
    @TableField("sms_status")
    private Integer smsStatus;
    @ApiModelProperty(value = "队列名称")
    @TableField("queue_name")
@@ -273,4 +277,9 @@
    @ApiModelProperty(value = "发票id")
    @TableField("invoice_id")
    private String invoiceId;
    @ApiModelProperty(value = "信用下单接口获取的支付中心授权单号(商户订单号)")
    @TableField("auth_order_id")
    private String authOrderId;
}
xp-robotaxi-itinerary-boot/src/main/java/com/xiaopeng/itinerary/controller/XpPricingController.java
@@ -7,6 +7,7 @@
import com.xiaopeng.api.dto.map.RouteStaleCheckDto;
import com.xiaopeng.api.dto.map.SelectNavigationRouteDto;
import com.xiaopeng.api.dto.operation.LonLatDto;
import com.xiaopeng.api.feignClient.order.XpOrderClient;
import com.xiaopeng.api.model.operation.XpPricing;
import com.xiaopeng.api.vo.HotFixInfoVo;
import com.xiaopeng.api.vo.operation.MultiRouteAndFareVo;
@@ -52,13 +53,15 @@
    private final IXpGeoQueryEntityService xpGeoQueryEntityService;
    private final RedisService redisService;
    private final ImageTagProcessor imageTagProcessor;
    private final XpOrderClient xpOrderClient;
    public XpPricingController(XpPricingService xpPricingService, IXpGeoQueryEntityService xpGeoQueryEntityService, RedisService redisService, ImageTagProcessor imageTagProcessor) {
    public XpPricingController(XpPricingService xpPricingService, IXpGeoQueryEntityService xpGeoQueryEntityService, RedisService redisService, ImageTagProcessor imageTagProcessor, XpOrderClient xpOrderClient) {
        this.xpPricingService = xpPricingService;
        this.xpGeoQueryEntityService = xpGeoQueryEntityService;
        this.redisService = redisService;
        this.imageTagProcessor = imageTagProcessor;
        this.xpOrderClient = xpOrderClient;
    }
@@ -115,6 +118,14 @@
    @XpClientCheck(checkToken = false, checkOtpToken = true)
    public R<?> saveOrder(@RequestBody @Validated XpOrderDto dto, HttpServletRequest request) {
        String uid = request.getHeader("XP-Uid");
        R<Long> hasOrderResult = xpOrderClient.hasUnPayOrder(uid);
        if (hasOrderResult == null || R.isError(hasOrderResult)) {
            return R.fail("订单状态查询失败");
        }
        Long existingOrderId = hasOrderResult.getData();
        if (existingOrderId != null && existingOrderId > 0) {
            return R.fail("有未支付订单");
        }
        String orderId = xpPricingService.saveOrder(dto, uid);
        if(orderId==null){
            String language = request.getHeader("language");
xp-robotaxi-order-boot/pom.xml
@@ -15,6 +15,13 @@
    </description>
    <dependencies>
        <dependency>
            <groupId>com.xiaopeng</groupId>
            <artifactId>xp-basics-signature</artifactId>
            <version>0.1.11</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpInvoiceController.java
@@ -53,7 +53,6 @@
    /**
     * 查询开票数据(批量)
     *
     * @param query
     * @return
     */
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpOrderController.java
@@ -166,6 +166,23 @@
    }
    /**
     * 查询是否有未支付订单
     * 返回0 可以下单,非0为未支付订单ID
     */
    @PostMapping("/logan/inner/order/has-unpay-order")
    @ApiOperation(value = "查询是否有未支付订单", tags = {"内部接口"})
    public R<Long> hasUnPayOrder(String uid) {
        XpOrder order = xpOrderService.getOne(new LambdaQueryWrapper<XpOrder>()
                .eq(XpOrder::getAppUserId, Long.parseLong(uid))
                .eq(XpOrder::getStatus, 8)
                .last("LIMIT 1"));
        if (order != null) {
            return R.ok(order.getId());
        }
        return R.ok(0L);
    }
    /**
     * 通过订单id查询订单信息
     *
     * @param orderId 订单id
@@ -996,11 +1013,13 @@
    @GetMapping("/api/v1/mini-program/order/queryOrderStatusFromOrderId")
    @XpClientCheck(checkToken = false, checkOtpToken = true)
    public R<OrderStatusFromOrderIdVo> queryOrderStatusFromOrderId(Long orderId) {
        XpOrder order = xpOrderService.getById(orderId);
        OrderStatusFromOrderIdVo orderStatusFromOrderIdVo = new OrderStatusFromOrderIdVo();
        orderStatusFromOrderIdVo.setOrderId(order.getId());
        orderStatusFromOrderIdVo.setStatus(order.getStatus());
        return R.ok(orderStatusFromOrderIdVo);
        return R.ok( xpOrderService.queryOrderStatusFromOrderId(orderId));
    }
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/model/vo/XpOrderHistoryListVO.java
@@ -67,5 +67,7 @@
    private Integer invoiceStatus;
}
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/IXpOrderService.java
@@ -301,4 +301,13 @@
     * @return
     */
    UserOrderInfoVo getOrderHistoryInfo(Long orderId);
    /**
     * 获取订单状态
     * @param orderId
     * @return
     */
    OrderStatusFromOrderIdVo queryOrderStatusFromOrderId(Long orderId);
}
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
@@ -21,10 +21,8 @@
import com.xiaopeng.api.dto.map.OrderRouteAndFareDto;
import com.xiaopeng.api.dto.map.RouteAndFareDto;
import com.xiaopeng.api.dto.operation.LonLatDto;
import com.xiaopeng.api.dto.order.GetOrderNumDto;
import com.xiaopeng.api.dto.order.HistoryEndPointsDto;
import com.xiaopeng.api.dto.order.HistoryStartPointsDto;
import com.xiaopeng.api.dto.order.PopOrderDto;
import com.xiaopeng.api.dto.order.*;
import com.xiaopeng.api.dto.payFront.*;
import com.xiaopeng.api.dto.pushMessage.SendMessageDTO;
import com.xiaopeng.api.dto.statistics.DailyCountDTO;
import com.xiaopeng.api.dto.statistics.OrderStatisticsDTO;
@@ -61,6 +59,7 @@
import com.xiaopeng.api.vo.operation.NearestNextVo;
import com.xiaopeng.api.vo.operation.RouteVo;
import com.xiaopeng.api.vo.order.*;
import com.xiaopeng.api.vo.payFront.*;
import com.xiaopeng.api.vo.order.FareBreakdownVo;
import com.xiaopeng.api.vo.payFront.CreditOrderCreateVo;
import com.xiaopeng.api.vo.payFront.CreditPaySignQueryVo;
@@ -78,6 +77,7 @@
import com.xiaopeng.common.core.exception.ServiceException;
import com.xiaopeng.common.core.utils.DateUtils;
import com.xiaopeng.common.core.utils.GeodesyUtil;
import com.xiaopeng.common.core.utils.OrderCodeUtil;
import com.xiaopeng.common.core.utils.StringUtils;
import com.xiaopeng.common.core.web.domain.BaseModel;
import com.xiaopeng.common.core.web.page.PageInfo;
@@ -3353,105 +3353,110 @@
    public R payment(XpOrderPayDto dto, String uid) {
        XpOrder order = this.getById(dto.getOrderId());
        HashMap<String, Object> resultMap = new HashMap<>();
        // 1.0 免密  //查询是否开通免密
        // 1先查用户是否申请  申请了拿到通过的businessOrderId
//        boolean signed = false;
//        CreditPaySignQueryDto creditPaySignQueryDto = new CreditPaySignQueryDto();
//        creditPaySignQueryDto.setUid(Long.valueOf(uid));
//        creditPaySignQueryDto.setBusinessId("xp-robotaxi");
//        creditPaySignQueryDto.setCategory("009001");
//        creditPaySignQueryDto.setBusinessOrderId("");
//        R<CreditPaySignQueryVo> creditPaySignQueryVoR = xpPayFrontClient.queryCreditPaySign(creditPaySignQueryDto);
//        if (creditPaySignQueryVoR.getCode()==200) {
//            CreditPaySignQueryVo data = creditPaySignQueryVoR.getData();
//            // 查看是否有签约的
//            long count = data.getSignList().stream().filter(e -> e.getStatus().equals("VALID")).count();
//            if (count > 0){
//                signed = true;
//            }
//        }
//
//
//        if(signed){
//            // y已签约 1.信用下单
//            CreditOrderCreateDto creditOrderCreateDto = new CreditOrderCreateDto();
//            creditOrderCreateDto.setUid(Long.valueOf(uid));
//            creditOrderCreateDto.setBusinessId("xp-robotaxi");
//            creditOrderCreateDto.setCategory("xp_robotaxi_api");
//            creditOrderCreateDto.setBusinessOrderId("");
//            creditOrderCreateDto.setSubject("009001");
//            creditOrderCreateDto.setPayType("13");
//
//
//            // 信用下单
//            ArrayList<CreditOrderCreateDto.PostPayment> postPayments = new ArrayList<>(1);
//            CreditOrderCreateDto.PostPayment postPayment = new CreditOrderCreateDto.PostPayment();
//            postPayment.setName("收费标准");
//            postPayment.setDescription("行程价格动态浮动,具体详情可在费用详情或计价规则查看");
//            postPayments.add(postPayment);
//            creditOrderCreateDto.setPostPayments(postPayments);
//            R<CreditOrderCreateVo> creditOrderCreateVoR = xpPayFrontClient.createCreditOrder(creditOrderCreateDto);
//            if(creditOrderCreateVoR.getCode()==200){
//                CreditOrderCreateVo data = creditOrderCreateVoR.getData();
//                resultMap.put("status", 1);
//                resultMap.put("value", data);
//                return R.ok(resultMap);
//            }
//
//        }else {
//
//            // 未签约
//            // 调用预下单接口
//            XpOrder order = this.getById(dto.getOrderId());
//            CreditPrecreateDto creditPrecreateDto = new CreditPrecreateDto();
//            creditPrecreateDto.setUid(uid);
//            creditPrecreateDto.setBizId("xp-robotaxi");
//            creditPrecreateDto.setBizOrderId("");
//            creditPrecreateDto.setPayScene(99);
//            creditPrecreateDto.setAmount(order.getOrderMoney().multiply(new BigDecimal(100)).intValue());
//            creditPrecreateDto.setCategory("009001");
//            creditPrecreateDto.setTitle("信用下单");
//            creditPrecreateDto.setDetail("信用下单");
//
//            HashMap<String, String> businessExtend = new HashMap<>();
//            businessExtend.put("returnUrl", "");
//            businessExtend.put("notifyUrl", "");
//            creditPrecreateDto.setBusinessExtend(businessExtend);
//
//            R<CreditPrecreateVo> creditPrecreateVoR = xpPayFrontClient.precreate(creditPrecreateDto);
//            if (creditPrecreateVoR.getCode()==200) {
//                CreditPrecreateVo data = creditPrecreateVoR.getData();
//                resultMap.put("status", 2);
//                resultMap.put("value", data);
//                return R.ok(resultMap);
//            }
//        }
        boolean signed = false;
        CreditPaySignQueryDto creditPaySignQueryDto = new CreditPaySignQueryDto();
        creditPaySignQueryDto.setUid(Long.valueOf(uid));
        creditPaySignQueryDto.setBusinessId("xp-robotaxi");
        creditPaySignQueryDto.setCategory("009001");
        creditPaySignQueryDto.setBusinessOrderId(OrderCodeUtil.getOrderCode("MMZF"));
        R<CreditPaySignQueryVo> creditPaySignQueryVoR = xpPayFrontClient.queryCreditPaySign(creditPaySignQueryDto);
        if (creditPaySignQueryVoR.getCode()==200) {
            CreditPaySignQueryVo data = creditPaySignQueryVoR.getData();
            // 查看是否有签约的
            long count = data.getSignList().stream().filter(e -> e.getStatus().equals("VALID")).count();
            if (count > 0){
                signed = true;
            }
        }
        if(signed){
            // y已签约 1.信用下单
            CreditOrderCreateDto creditOrderCreateDto = new CreditOrderCreateDto();
            creditOrderCreateDto.setUid(Long.valueOf(uid));
            creditOrderCreateDto.setBusinessId("xp-robotaxi");
            creditOrderCreateDto.setCategory("009001");
            creditOrderCreateDto.setBusinessOrderId("");
            creditOrderCreateDto.setSubject("小鹏集团|robotaxi");
            creditOrderCreateDto.setPayType("13");
            // 信用下单
            ArrayList<CreditOrderCreateDto.PostPayment> postPayments = new ArrayList<>(1);
            CreditOrderCreateDto.PostPayment postPayment = new CreditOrderCreateDto.PostPayment();
            postPayment.setName("收费标准");
            postPayment.setDescription("行程价格动态浮动,具体详情可在费用详情或计价规则查看");
            postPayments.add(postPayment);
            creditOrderCreateDto.setPostPayments(postPayments);
            R<CreditOrderCreateVo> creditOrderCreateVoR = xpPayFrontClient.createCreditOrder(creditOrderCreateDto);
            if(creditOrderCreateVoR.getCode()==200){
                CreditOrderCreateVo data = creditOrderCreateVoR.getData();
                resultMap.put("status", 1);
                resultMap.put("value", data);
                order.setPayType(3);
                order.setAuthOrderId(data.getAuthOrderId());
                return R.ok(resultMap);
            }
        }else {
            // 未签约
            // 调用预下单接口
            CreditPrecreateDto creditPrecreateDto = new CreditPrecreateDto();
            creditPrecreateDto.setUid(uid);
            creditPrecreateDto.setBizId("xp-robotaxi");
            creditPrecreateDto.setBizOrderId("");
            creditPrecreateDto.setPayScene(99);
            creditPrecreateDto.setAmount(order.getOrderMoney().multiply(new BigDecimal(100)).intValue());
            creditPrecreateDto.setCategory("009001");
            creditPrecreateDto.setTitle("信用下单");
            creditPrecreateDto.setDetail("信用下单");
            HashMap<String, String> businessExtend = new HashMap<>();
            businessExtend.put("returnUrl", "");
            businessExtend.put("notifyUrl", "");
            creditPrecreateDto.setBusinessExtend(businessExtend);
            R<CreditPrecreateVo> creditPrecreateVoR = xpPayFrontClient.precreate(creditPrecreateDto);
            if (creditPrecreateVoR.getCode()==200) {
                CreditPrecreateVo data = creditPrecreateVoR.getData();
                resultMap.put("status", 2);
                resultMap.put("value", data);
                return R.ok(resultMap);
            }
        }
        // mvp版本不做支付 使用优惠券抵扣为0元订单处理 处理订单状态即可
        XpOrder order = this.getById(dto.getOrderId());
        order.setStatus(9);
        order.setAppUserId(null);
        if (order.getCouponId() != null) {
            UseUserCouponDto useUserCouponDto = new UseUserCouponDto();
            useUserCouponDto.setUserCouponId(order.getCouponId());
            R<BigDecimal> decimalR = xpAppUserCouponClient.useUserCoupon(useUserCouponDto);
            if (decimalR.getCode() == 200) {
                order.setCouponMoney(decimalR.getData());
                if (order.getCouponMoney().compareTo(order.getOrderMoney()) > 0) {
                    order.setPayMoney(BigDecimal.ZERO);
                    order.setCouponMoney(order.getOrderMoney());
                } else {
                    order.setPayMoney(order.getOrderMoney().subtract(decimalR.getData()));
                }
            }
        }
        baseMapper.updateById(order);
        bootCommonService.setCache_orderStatus(order.getId(), order, null);
        return R.ok();
//        XpOrder order = this.getById(dto.getOrderId());
//        order.setStatus(9);
//        order.setAppUserId(null);
//        if (order.getCouponId() != null) {
//            UseUserCouponDto useUserCouponDto = new UseUserCouponDto();
//            useUserCouponDto.setUserCouponId(order.getCouponId());
//            R<BigDecimal> decimalR = xpAppUserCouponClient.useUserCoupon(useUserCouponDto);
//            if (decimalR.getCode() == 200) {
//                order.setCouponMoney(decimalR.getData());
//                if (order.getCouponMoney().compareTo(order.getOrderMoney()) > 0) {
//                    order.setPayMoney(BigDecimal.ZERO);
//                    order.setCouponMoney(order.getOrderMoney());
//                } else {
//                    order.setPayMoney(order.getOrderMoney().subtract(decimalR.getData()));
//                }
//            }
//        }
//        baseMapper.updateById(order);
//        bootCommonService.setCache_orderStatus(order.getId(), order, null);
        return R.fail();
    }
    /**
@@ -3858,13 +3863,13 @@
                vo.setVin(vehicle.getVehicleVin());
                vo.setPassengerUid(order.getAppUserId());
                BaseVehicleUserDto deliver = bluetoothUnlockClient.deliver(vo);
//                if(null == deliver){
//                    throw new ServiceException("下发蓝牙token失败");
//                }
//                if(deliver.getCode() != 0){
//                    log.error("下发蓝牙token失败:{} {}", deliver.getMsg(), order.getOrderNumber());
//                    throw new ServiceException(deliver.getMsg());
//                }
                if(null == deliver){
                    throw new ServiceException("下发蓝牙token失败");
                }
                if(deliver.getCode() != 0){
                    log.error("下发蓝牙token失败:{} {}", deliver.getMsg(), order.getOrderNumber());
                    throw new ServiceException(deliver.getMsg());
                }
                log.info("下发蓝牙token成功:{} {}", deliver.getData(), order.getOrderNumber());
            }
@@ -4732,6 +4737,59 @@
        return vo;
    }
    /**
     * 查询订单状态
     * @param orderId
     * @return
     */
    @Override
    public OrderStatusFromOrderIdVo queryOrderStatusFromOrderId(Long orderId) {
        XpOrder order = this.getById(orderId);
        if(order==null){
            return null;
        }
        if(order.getPayType()==3){
            // 免密查询 如果成功则调用结算
            CreditOrderQueryDto dto = new CreditOrderQueryDto();
            dto.setBusinessOrderId(OrderCodeUtil.getOrderCode("MMZF"));
            dto.setAuthOrderId(order.getAuthOrderId());
            dto.setPayType("13");
            R<CreditOrderQueryVo> creditOrderQueryVoR = xpPayFrontClient.queryCreditOrder(dto);
            if(creditOrderQueryVoR.getCode()==200){
                CreditOrderQueryVo creditOrderQueryVo = creditOrderQueryVoR.getData();
                if(creditOrderQueryVo.getCreditOrderStatus().equals("DONE")){
                    // 订单确认 需要吊起扣款
                    CreditOrderWxPayDto creditOrderWxPayDto = new CreditOrderWxPayDto();
                    creditOrderWxPayDto.setBusinessOrderId(OrderCodeUtil.getOrderCode("MMZF"));
                    creditOrderWxPayDto.setAuthOrderId(order.getAuthOrderId());
                    creditOrderWxPayDto.setPayCallbackUrl("13");
                    creditOrderWxPayDto.setTotalAmount( order.getOrderMoney().multiply(BigDecimal.valueOf(100)).longValue());
                    creditOrderWxPayDto.setSubject("小鹏集团|robotaxi");
                    creditOrderWxPayDto.setPayType("13");
                    List<CreditOrderCreateDto.PostPayment> postPayments = new ArrayList<>();
                    CreditOrderCreateDto.PostPayment postPayment = new CreditOrderCreateDto.PostPayment();
                    postPayment.setName("收费标准");
                    postPayment.setDescription("行程价格动态浮动,具体详情可在费用详情或计价规则查看");
                    postPayments.add(postPayment);
                    creditOrderWxPayDto.setPostPayments(postPayments);
                    R<CreditOrderWxPayVo> creditOrderWxPayVoR = xpPayFrontClient.creditOrderWxPay(creditOrderWxPayDto);
                }else if(creditOrderQueryVo.getCreditOrderStatus().equals("CREATED") || creditOrderQueryVo.getCreditOrderStatus().equals("DOING")){
                }
            }
        }else {
            // 微信支付也需要查询下
        }
        OrderStatusFromOrderIdVo orderStatusFromOrderIdVo = new OrderStatusFromOrderIdVo();
        orderStatusFromOrderIdVo.setOrderId(order.getId());
        orderStatusFromOrderIdVo.setStatus(order.getStatus());
        return orderStatusFromOrderIdVo;
    }
    /**
     * 发票列表
@@ -4741,18 +4799,22 @@
    @Override
    public List<XpInvoiceVo> invoiceList(XpOrderInvoiceQuery query) {
        // 格式:yyyyMM 转yyyy-MM
        query.setStartTime(query.getStartTime().substring(0, 4) + "-" + query.getStartTime().substring(4, 6));
        query.setEndTime(query.getEndTime().substring(0, 4) + "-" + query.getEndTime().substring(4, 6));
        DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyyMM");
        LocalDateTime startTime = YearMonth.parse(query.getStartTime(), monthFormatter)
                .atDay(1)
                .atStartOfDay();
        LocalDateTime endTime = YearMonth.parse(query.getEndTime(), monthFormatter)
                .atEndOfMonth()
                .atTime(23, 59, 59);
        List<XpOrder> list =null;
        // 通过uid 和时间查出来数据  先判断是否传入了分页
        if (query.getPageNo()!=null && query.getPageSize()!=null) {
            Page<XpOrder> page = new Page<>(query.getPageNo(), query.getPageSize());
            Page<XpOrder> orderPage = this.baseMapper.selectPage(page, new LambdaQueryWrapper<XpOrder>().eq(XpOrder::getAppUserId, Long.valueOf(query.getUid())).ge(XpOrder::getStatus, 9).between(BaseModel::getCreateTime, query.getStartTime(), query.getEndTime()));
            Page<XpOrder> orderPage = this.baseMapper.selectPage(page, new LambdaQueryWrapper<XpOrder>().eq(XpOrder::getAppUserId, Long.valueOf(query.getUid())).ge(XpOrder::getStatus, 9).between(BaseModel::getCreateTime, startTime, endTime));
            list = orderPage.getRecords();
        }else {
            list = this.baseMapper.selectList(new LambdaQueryWrapper<XpOrder>().eq(XpOrder::getAppUserId, Long.valueOf(query.getUid())).ge(XpOrder::getStatus, 9).between(BaseModel::getCreateTime, query.getStartTime(), query.getEndTime()));
            list = this.baseMapper.selectList(new LambdaQueryWrapper<XpOrder>().eq(XpOrder::getAppUserId, Long.valueOf(query.getUid())).ge(XpOrder::getStatus, 9).between(BaseModel::getCreateTime, startTime, endTime));
        }
        if(list.isEmpty()){
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/utils/TaskOrderSendSmsUtil.java
New file
@@ -0,0 +1,107 @@
package com.xiaopeng.order.utils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.xiaopeng.api.dto.account.UcUserInfo;
import com.xiaopeng.api.dto.operation.SmsDto;
import com.xiaopeng.api.feignClient.account.UserResourcesClient;
import com.xiaopeng.api.feignClient.operation.SmsClient;
import com.xiaopeng.api.model.order.XpOrder;
import com.xiaopeng.api.vo.operation.SmsVo;
import com.xiaopeng.common.core.enums.OrderStatusEnum;
import com.xiaopeng.common.core.utils.StringUtils;
import com.xiaopeng.order.service.IXpOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
@Slf4j
@Component
public class TaskOrderSendSmsUtil {
    private static final int SMS_SENT = 1;
    private static final int BATCH_SIZE = 200;
    @Resource
    private IXpOrderService xpOrderService;
    @Resource
    private UserResourcesClient userResourcesClient;
    @Resource
    private SmsClient smsClient;
//    @Value("${sms.appid:}")
//    private String smsAppId;
//
//    @Value("${sms.order-pay.template-code:RobotaxiOrderPaySmsTpl}")
//    private String orderPayTemplateCode;
//
//    @Value("${sms.order-pay.app-push-config-code:RobotaxiOrderPaySms}")
//    private String orderPayAppPushConfigCode;
    /**
     * 每分钟查询一次待支付超过24小时且未发送短信的订单。
     */
    @Scheduled(cron = "0 */1 * * * ?")
    public void sendPendingPaymentSms() {
        LocalDateTime deadline = LocalDateTime.now().minusHours(24);
        List<XpOrder> orders = xpOrderService.list(new LambdaQueryWrapper<XpOrder>()
                .eq(XpOrder::getStatus, OrderStatusEnum.APPROVAL_REJECTION.getCode())
                .le(XpOrder::getTripEnd, deadline)
                .and(wrapper -> wrapper.isNull(XpOrder::getSmsStatus).or().ne(XpOrder::getSmsStatus, SMS_SENT))
                .orderByAsc(XpOrder::getTripEnd)
                .last("LIMIT " + BATCH_SIZE));
        if (orders == null || orders.isEmpty()) {
            return;
        }
        for (XpOrder order : orders) {
            try {
                sendSms(order);
            } catch (Exception e) {
                log.error("待支付订单短信发送失败,订单ID: {}, 订单号: {}", order.getId(), order.getOrderNumber(), e);
            }
        }
    }
    private void sendSms(XpOrder order) {
        if (order.getAppUserId() == null) {
            log.warn("待支付订单短信发送跳过,用户ID为空,订单ID: {}", order.getId());
            return;
        }
        UcUserInfo userInfo = userResourcesClient.getBaseUserByUid(String.valueOf(order.getAppUserId()));
        if (userInfo == null || StringUtils.isBlank(userInfo.getMobile())) {
            log.warn("待支付订单短信发送跳过,手机号为空,订单ID: {}, 用户ID: {}", order.getId(), order.getAppUserId());
            return;
        }
        SmsVo smsVo = new SmsVo();
        smsVo.setAppId("");
        smsVo.setPushType(1);
        smsVo.setReceivers(userInfo.getMobile());
        smsVo.setTemplateCode("orderPayTemplateCode");
        smsVo.setAppPushConfigCode("orderPayAppPushConfigCode");
        smsVo.setParams(new HashMap<>());
        smsVo.getParams().put("orderNo", order.getOrderNumber());
        SmsDto result = smsClient.pushSms(smsVo);
        if (result == null || result.getCode() == null || result.getCode() != 200) {
            log.warn("待支付订单短信发送未成功,订单ID: {}, 返回: {}", order.getId(), result);
            return;
        }
        order.setAppUserId(null);
        order.setSmsStatus(SMS_SENT);
        boolean updated = xpOrderService.updateById(order);
        if (!updated) {
            log.warn("待支付订单短信状态更新失败,订单ID: {}", order.getId());
        }
    }
}
xp-robotaxi-order-boot/src/main/resources/mapper/order/XpOrderMapper.xml
@@ -47,7 +47,7 @@
    <select id="getHistoryOrderList" resultType="com.xiaopeng.order.model.vo.XpOrderHistoryListVO">
        select start_point_name as originAddress, end_point_name as destinationAddress,start_point_id as startPointId,end_point_id as endPointId,
        DATE_FORMAT(create_time, '%H:%i') AS orderTime, pay_money as amount,create_time as time,DATE_FORMAT(create_time,'%Y-%m-%d') AS timeStr,
        id as orderId,status from xp_order where app_user_id = #{uid} and is_deleted = 0
        id as orderId,status,invoice_status invoiceStatus from xp_order where app_user_id = #{uid} and is_deleted = 0
        <if test="query.status != null">
            and status = #{query.status}
        </if>
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/HttpTestController.java
@@ -33,4 +33,34 @@
            return R.fail(e.getMessage());
        }
    }
    /**
     * 测试报送网约车平台公司基本信息(PTJB)
     */
    @ResponseBody
    @RequestMapping("/base/v0.1/testPushPtjb")
    public R<String> testPushPtjb(){
        try {
            String result = ministryOfTransport.pushPlatformBaseInfo();
            return R.ok(result);
        }catch (Exception e){
            e.printStackTrace();
            return R.fail(e.getMessage());
        }
    }
    /**
     * 测试报送网约车平台公司运营规模信息(PTYYGM)
     */
    @ResponseBody
    @RequestMapping("/base/v0.1/testPushPtyygm")
    public R<String> testPushPtyygm(){
        try {
            String result = ministryOfTransport.pushPlatformOperationScaleInfo();
            return R.ok(result);
        }catch (Exception e){
            e.printStackTrace();
            return R.fail(e.getMessage());
        }
    }
}
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/util/MinistryOfTransport.java
@@ -2,16 +2,18 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
@@ -19,6 +21,7 @@
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
@@ -49,7 +52,13 @@
    private final String url = "https://wycapi.jtj.gz.gov.cn/api/app/common/binapi";
    private final String filePath = "src/main/resources/files/";
    private static final String PTJB_SYMBOL = "XPQCB67N_S0612018007357G";
    private static final String PROTOCOL_VERSION = "V2.0";
    private static final DateTimeFormatter FILE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
    private static final DateTimeFormatter DATA_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
    /**
@@ -58,61 +67,180 @@
     */
    public String getToken(){
        try {
            String format = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
            String format = LocalDateTime.now().format(FILE_TIME_FORMATTER);
            String filename = platform + "_TOKEN_ACCESS_REQ_" + format + ".json";
            HttpPost post = new HttpPost(url);
            JSONObject body = new JSONObject();
            body.put("platform", platform);
            body.put("key", key);
            InputStream in = new ByteArrayInputStream(body.toJSONString().getBytes("UTF-8"));
            String md5 = hash(in);
            in.reset();
            return uploadJsonFile(filename, body.toJSONString(), platform);
        }catch (Exception e){
            log.error("获取交通部token失败", e);
        }
        return null;
    }
    /**
     * 报送网约车平台公司基本信息(PTJB)
     *
     * @return 监管平台原始响应
     */
    public String pushPlatformBaseInfo() {
        String token = parseToken(getToken());
        JSONObject item = buildPlatformBaseInfo();
        JSONObject body = new JSONObject();
        JSONArray items = new JSONArray();
        items.add(item);
        body.put("items", items);
        String format = LocalDateTime.now().format(FILE_TIME_FORMATTER);
        String filename = platform + "_BASIC_PTJB_REQ_" + format + ".json";
        return uploadJsonFile(filename, body.toJSONString(), token);
    }
    /**
     * 报送网约车平台公司运营规模信息(PTYYGM)
     *
     * @return 监管平台原始响应
     */
    public String pushPlatformOperationScaleInfo() {
        String token = parseToken(getToken());
        JSONObject item = buildPlatformOperationScaleInfo();
        JSONObject body = new JSONObject();
        JSONArray items = new JSONArray();
        items.add(item);
        body.put("items", items);
        String format = LocalDateTime.now().format(FILE_TIME_FORMATTER);
        String filename = platform + "_BASIC_PTYYGM_REQ_" + format + ".json";
        return uploadJsonFile(filename, body.toJSONString(), token);
    }
    private JSONObject buildPlatformBaseInfo() {
        JSONObject item = new JSONObject();
        item.put("symbol", PTJB_SYMBOL);
        item.put("companyId", companyId);
        item.put("companyName", "广州易点智慧出行科技有限公司");
        item.put("identifier", "91440101MA5AWEB67N");
        item.put("contactPhone", "18306304567");
        item.put("address", "440000");
        item.put("businessScope", "网络预约出租汽车客运");
        item.put("contactAddress", "广州市天河区岑村丰庄大街10号T2");
        item.put("economicType", "159");
        item.put("regCapital", "壹仟万元(人民币)");
        item.put("legalName", "陈志远");
        item.put("legalId", "445221199101121937");
        item.put("legalPhone", "15915905487");
        item.put("legalPhoto", encodePdf("陈志远新复印件.pdf"));
        item.put("legalPhotoId", "");
        item.put("identifierPhoto", encodePdf("易点智慧出行-营副-20250716.pdf"));
        item.put("state", "0");
        item.put("flag", "1");
        item.put("updateTime", LocalDateTime.now().format(DATA_TIME_FORMATTER));
        item.put("serviceItem", "网络预约出租汽车服务");
        item.put("servicePromise", "严格遵守国家及地方有关网络预约出租汽车经营的法律法规及行业规范,依法取得相关许可,证照齐全、亮证经营");
        item.put("protocolVersion", PROTOCOL_VERSION);
        return item;
    }
    private JSONObject buildPlatformOperationScaleInfo() {
        JSONObject item = new JSONObject();
        item.put("symbol", PTJB_SYMBOL);
        item.put("companyId", companyId);
        item.put("vehicleNum", "1"); //TODO 后续补充完整
        item.put("driverNum", "1"); //TODO 后续补充完整
        item.put("flag", "1");
        item.put("updateTime", LocalDateTime.now().format(DATA_TIME_FORMATTER));
        item.put("protocolVersion", PROTOCOL_VERSION);
        return item;
    }
    private String encodePdf(String filename) {
        if (StringUtils.isBlank(filename)) {
            return "";
        }
        String resourcePath = "files/" + filename.trim();
        ClassPathResource resource = new ClassPathResource(resourcePath);
        try {
            long contentLength = resource.contentLength();
            if (contentLength > 10 * 1024 * 1024) {
                throw new RuntimeException("文件超过10M: " + filename);
            }
            try (InputStream inputStream = resource.getInputStream()) {
                byte[] bytes = new byte[(int) contentLength];
                int offset = 0;
                int read;
                while (offset < bytes.length && (read = inputStream.read(bytes, offset, bytes.length - offset)) != -1) {
                    offset += read;
                }
                if (offset != bytes.length) {
                    throw new RuntimeException("文件读取不完整: " + filename);
                }
                return Base64.getEncoder().encodeToString(bytes);
            }
        } catch (Exception e) {
            throw new RuntimeException("读取PDF文件失败: " + filename, e);
        }
    }
    private String uploadJsonFile(String filename, String jsonBody, String auth) {
        try {
            byte[] bytes = jsonBody.getBytes("UTF-8");
            String md5 = hash(new ByteArrayInputStream(bytes));
            HttpPost post = new HttpPost(url);
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            post.addHeader("binfile-md5", md5);
            post.addHeader("binfile-auth", platform);
            post.addHeader("binfile-auth", auth);
            post.addHeader("binfile-gzip", "false");
            post.addHeader("binfile-reqlen", String.valueOf(in.available()));
            builder.addBinaryBody("binFile", in, ContentType.DEFAULT_BINARY, filename);// 文件
            post.addHeader("binfile-reqlen", String.valueOf(bytes.length));
            builder.addBinaryBody("binFile", new ByteArrayInputStream(bytes), ContentType.DEFAULT_BINARY, filename);
            builder.addTextBody("filename", filename, ContentType.create(ContentType.DEFAULT_TEXT.getMimeType(), "UTF-8"));
            post.setEntity(builder.build());
            int connTimeout = 10000;
            int soTimeout = -1;
            HttpClientBuilder clientBuilder = HttpClientBuilder.create();
            RequestConfig.Builder configBuilder = RequestConfig.custom();
            if (connTimeout > 0) configBuilder.build();
            if (soTimeout > 0) configBuilder.setSocketTimeout(soTimeout);
            clientBuilder.setDefaultRequestConfig(configBuilder.build());
            if (!false) clientBuilder.disableContentCompression();
            CloseableHttpClient client = clientBuilder.build();
            HttpResponse response = client.execute(post);
            log.info("response.toString() = \n"+response.toString());
            log.info("response.getStatusLine().getStatusCode() = \n"+response.getStatusLine().getStatusCode());
            InputStream ins = response.getEntity().getContent();
            byte[] s = new byte[1024];
            while(ins.read(s,0,1024) != -1){
                String str = new String(s,"UTF-8");
                System.out.println(str);
            RequestConfig requestConfig = RequestConfig.custom()
                    .setConnectTimeout(10000)
                    .build();
            clientBuilder.setDefaultRequestConfig(requestConfig);
            clientBuilder.disableContentCompression();
            try (CloseableHttpClient client = clientBuilder.build()) {
                HttpResponse response = client.execute(post);
                String responseBody = response.getEntity() == null ? "" : EntityUtils.toString(response.getEntity(), "UTF-8");
                log.info("交通部接口响应 status={}, filename={}, responseLength={}",
                        response.getStatusLine().getStatusCode(), filename, responseBody.length());
                return responseBody;
            }
            log.info("内容:"+ EntityUtils.toString(response.getEntity()));
            return EntityUtils.toString(response.getEntity());
        }catch (Exception e){
            e.printStackTrace();
        } catch (Exception e) {
            throw new RuntimeException("上传交通部接口文件失败: " + filename, e);
        }
        return null;
    }
    private String parseToken(String tokenResponse) {
        if (StringUtils.isBlank(tokenResponse)) {
            throw new RuntimeException("交通部token响应为空");
        }
        try {
            JSONObject response = JSON.parseObject(tokenResponse);
            String token = response.getString("token");
            if (StringUtils.isNotBlank(token)) {
                return token;
            }
            JSONArray items = response.getJSONArray("items");
            if (items != null && !items.isEmpty()) {
                token = items.getJSONObject(0).getString("token");
                if (StringUtils.isNotBlank(token)) {
                    return token;
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("解析交通部token失败: " + tokenResponse, e);
        }
        throw new RuntimeException("交通部token响应中未找到token: " + tokenResponse);
    }
    private static char[] commonDigit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
    public static void main(String[] args) throws ClientProtocolException, IOException
    {
    }
    public static String hash(InputStream in)
    {
xp-robotaxi-vehicle-convoy-boot/src/main/resources/files/易点智慧出行-营副-20250716.pdf
Binary files differ
xp-robotaxi-vehicle-convoy-boot/src/main/resources/files/陈志远新复印件.pdf
Binary files differ