package com.njzscloud.supervisory.order.service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
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.google.common.base.Strings;
import com.njzscloud.common.core.ex.Exceptions;
import com.njzscloud.common.mp.support.PageParam;
import com.njzscloud.common.mp.support.PageResult;
import com.njzscloud.common.mqtt.util.Mqtt;
import com.njzscloud.common.security.support.UserDetail;
import com.njzscloud.common.security.util.SecurityUtil;
import com.njzscloud.common.sn.support.SnUtil;
import com.njzscloud.common.ws.support.Websocket;
import com.njzscloud.common.ws.support.WsMsg;
import com.njzscloud.supervisory.biz.constant.AuditStatus;
import com.njzscloud.supervisory.biz.constant.BizObj;
import com.njzscloud.supervisory.biz.pojo.entity.*;
import com.njzscloud.supervisory.biz.service.*;
import com.njzscloud.supervisory.constant.Constant;
import com.njzscloud.supervisory.device.pojo.entity.DeviceLocalizerEntity;
import com.njzscloud.supervisory.device.service.DeviceLocalizerService;
import com.njzscloud.supervisory.discount.pojo.DiscountManageEntity;
import com.njzscloud.supervisory.discount.service.DiscountManageService;
import com.njzscloud.supervisory.expense.contant.*;
import com.njzscloud.supervisory.expense.pojo.entity.ExpenseItemsConfigEntity;
import com.njzscloud.supervisory.expense.service.ExpenseItemsConfigService;
import com.njzscloud.supervisory.goods.contant.MoneyStrategy;
import com.njzscloud.supervisory.hsoa.Hsoa;
import com.njzscloud.supervisory.hsoa.constant.PushType;
import com.njzscloud.supervisory.hsoa.pojo.entity.HsoaRecode;
import com.njzscloud.supervisory.hsoa.pojo.param.PushVehicleTrajectoryParam;
import com.njzscloud.supervisory.hsoa.pojo.result.HsoaResult;
import com.njzscloud.supervisory.hsoa.service.HsoaService;
import com.njzscloud.supervisory.money.contant.MoneyChangeCategory;
import com.njzscloud.supervisory.money.pojo.entity.MoneyAccountEntity;
import com.njzscloud.supervisory.money.pojo.entity.MoneyChangeDetailEntity;
import com.njzscloud.supervisory.money.service.MoneyAccountService;
import com.njzscloud.supervisory.money.service.MoneyChangeDetailService;
import com.njzscloud.supervisory.order.contant.*;
import com.njzscloud.supervisory.order.mapper.OrderInfoMapper;
import com.njzscloud.supervisory.order.pojo.entity.*;
import com.njzscloud.supervisory.order.pojo.param.*;
import com.njzscloud.supervisory.order.pojo.result.*;
import com.njzscloud.supervisory.order.utils.FileUtil;
import com.njzscloud.supervisory.station.pojo.entity.StationManageEntity;
import com.njzscloud.supervisory.station.service.StationManageService;
import com.njzscloud.supervisory.sys.auth.pojo.result.MyResult;
import com.njzscloud.supervisory.sys.dict.pojo.DictItemEntity;
import com.njzscloud.supervisory.sys.dict.service.DictItemService;
import com.njzscloud.supervisory.sys.role.pojo.entity.RoleEntity;
import com.njzscloud.supervisory.sys.role.service.RoleService;
import com.njzscloud.supervisory.sys.stationletter.constant.WarnCategory;
import com.njzscloud.supervisory.sys.user.pojo.entity.UserEntity;
import com.njzscloud.supervisory.sys.user.pojo.result.SysUserRoleEntity;
import com.njzscloud.supervisory.sys.user.service.UserRoleService;
import com.njzscloud.supervisory.sys.user.service.UserService;
import com.njzscloud.supervisory.voicebox.service.CloudVoiceboxService;
import com.njzscloud.supervisory.wxPay.contant.TempType;
import com.njzscloud.supervisory.wxPay.dto.RefundRequestDto;
import com.njzscloud.supervisory.wxPay.param.TemplateMessageParam;
import com.njzscloud.supervisory.wxPay.service.PaymentService;
import com.njzscloud.supervisory.wxPay.service.WechatTemplateMessageService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

import static com.njzscloud.supervisory.constant.Constant.CERTIFICATE_SN_CODE;
import static com.njzscloud.supervisory.constant.Constant.ROLE_JG;

/**
 * 订单信息
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderInfoService extends ServiceImpl<OrderInfoMapper, OrderInfoEntity> {

    private final BizAuditConfigService bizAuditConfigService;
    private final OrderGoodsService orderGoodsService;
    private final OrderCargoPlaceService orderCargoPlaceService;
    private final OrderCarInOutService orderCarInOutService;
    private final OrderExpenseItemsService orderExpenseItemsService;
    private final ExpenseItemsConfigService expenseItemsConfigService;
    private final TruckLocationTrackService truckLocationTrackService;
    private final BizWarnService bizWarnService;
    private final StationManageService stationManageService;
    private final CloudVoiceboxService cloudVoiceboxService;
    private final MoneyAccountService moneyAccountService;
    private final MoneyChangeDetailService moneyChangeDetailService;
    private final PaymentService paymentService;
    private final WechatTemplateMessageService wechatTemplateMessageService;
    private final BizDriverService bizDriverService;
    private final BizCompanyService bizCompanyService;
    private final RoleService roleService;
    private final UserRoleService userRoleService;
    private final UserService userService;
    private final DiscountManageService discountManageService;
    private final HsoaService hsoaService;
    private final DictItemService dictItemService;
    private final AtomicBoolean test_thread_running = new AtomicBoolean(false);
    private final DeviceLocalizerService deviceLocalizerService;
    Thread test_thread = null;
    @Value("${app.check-gps:false}")
    private boolean checkGps;

    /**
     * 新增
     */
    public void add(AddOrderInfoParam addOrderInfoParam, String orderSn) {
        Long stationId = addOrderInfoParam.getStationId();
        BizCompanyEntity stationInfo = bizCompanyService.getById(stationId);
        Assert.notNull(stationInfo, () -> Exceptions.clierr("站点信息错误"));
        // Assert.isTrue(Integer.valueOf(1).equals(stationInfo.getStationType()), () -> Exceptions.clierr("系统暂未对接，预约失败"));
        Assert.isFalse(this.exists(Wrappers.<OrderInfoEntity>lambdaQuery().eq(OrderInfoEntity::getSn, addOrderInfoParam.getSn())), () -> Exceptions.exception("订单创建失败，订单号重复"));
        AddOrderCargoPlaceParam cargoPlace = addOrderInfoParam.getCargoPlace();
        long cargoPlaceId = orderCargoPlaceService.add(cargoPlace);
        Long userId = SecurityUtil.currentUserId();

        Long transCompanyId = addOrderInfoParam.getTransCompanyId();
        OrderStatus orderStatus = transCompanyId == null ? OrderStatus.YiYuYue : OrderStatus.DaiPaiDan;


        Long goodsId = addOrderInfoParam.getGoodsId();

        Long orderGoodsId = orderGoodsService.add(goodsId, null);

        orderSn = orderSn == null ? SnUtil.next() : orderSn;
        OrderCategory orderCategory = addOrderInfoParam.getOrderCategory();
        OrderInfoEntity orderInfoEntity = BeanUtil.copyProperties(addOrderInfoParam, OrderInfoEntity.class)
                .setSn(orderCategory == OrderCategory.DuanBoChu ? orderSn + "-1" : orderSn)
                .setCargoPlaceId(cargoPlaceId)
                .setUserId(userId)
                .setOrderStatus(orderStatus)
                .setGoodsId(orderGoodsId)
                .setAssignmentTransTime(transCompanyId == null ? null : LocalDateTime.now());
        this.save(orderInfoEntity);

        OrderGoodsEntity entity = orderGoodsService.getById(orderGoodsId);
        // 添加付费项，计算费用，需要称重在更新
        settleForTransCompany(this.getById(orderInfoEntity.getId()), entity);

        Long orderId = orderInfoEntity.getId();
        if (orderCategory == OrderCategory.DuanBoChu) {
            Long targetStationId = addOrderInfoParam.getTargetStationId();
            this.add(addOrderInfoParam.setOrderCategory(OrderCategory.DuanBoRu)
                            .setTargetOrderId(orderId)
                            .setTargetStationId(stationId)
                            .setStationId(targetStationId),
                    orderSn + "-2");

        } else if (orderCategory == OrderCategory.DuanBoRu) {
            this.updateById(new OrderInfoEntity().setId(addOrderInfoParam.getTargetOrderId())
                    .setTargetOrderId(orderId));
        }
        if (transCompanyId != null) {
            BizCompanyEntity transCompanyEntity = baseMapper.getTransInfo(transCompanyId);
            cloudVoiceboxService.play(transCompanyEntity.getUserId(), "您有新的待分配订单，请及时处理");
            // 通知清运公司
            try {
                TemplateMessageParam param = new TemplateMessageParam();
                param.setUserId(transCompanyEntity.getUserId());
                param.setTempType(TempType.TRANS_COMPANY.getVal());
                param.setSn(orderInfoEntity.getSn());
                param.setGoodsName(entity.getGoodsName());
                param.setStartAddress(cargoPlace.getAddress());
                wechatTemplateMessageService.sendTemplateMessage(param);
            } catch (Exception e) {
                log.error("通知失败", e);
            }
        } else {
            cloudVoiceboxService.play(1L, "您有新的待分配订单，请及时处理");
        }
    }

    public PaymentContextResult paymentContext(Long orderId) {
        return this.baseMapper.paymentContext(orderId);
    }

    /**
     * 修改
     */
    public void modify(ModifyOrderParam modifyOrderParam) {
    }

    /**
     * 删除
     */
    @Transactional(rollbackFor = Exception.class)
    public void del(List<Long> ids) {
        this.removeBatchByIds(ids);
    }

    /**
     * 详情
     */
    public OrderPagingResult detail(Long id) {
        List<String> routes = baseMapper.getRoute(id);
        OrderPagingResult orderPagingResult = baseMapper.detail(Wrappers.<OrderPagingResult>query()
                .in("a.id", id));
        orderPagingResult.setRoute(routes);
        return orderPagingResult;
    }

    /**
     * 分页查询
     */
    public PageResult<OrderPagingResult> paging(PageParam pageParam, OrderPagingSearchParam orderPagingSearchParam) {
        String sn = orderPagingSearchParam.getSn();
        String licensePlate = orderPagingSearchParam.getLicensePlate();
        String nickname = orderPagingSearchParam.getNickname();
        String phone = orderPagingSearchParam.getPhone();
        LocalDateTime startTime = orderPagingSearchParam.getStartTime();
        LocalDateTime endTime = orderPagingSearchParam.getEndTime();
        Long transCompanyId = orderPagingSearchParam.getTransCompanyId();
        Long goodsId = orderPagingSearchParam.getGoodsId();
        Page<OrderPagingResult> page = pageParam.toPage();
        Long stationId = orderPagingSearchParam.getStationId();
        // List<Long> stationIds = this.getStationIds();
        // if (!stationIds.isEmpty()) {
        //     stationId = null;
        // }
        String area = orderPagingSearchParam.getArea();
        OrderCategory orderCategory = orderPagingSearchParam.getOrderCategory();
        String transCompanyName = orderPagingSearchParam.getTransCompanyName();
        String driverName = orderPagingSearchParam.getDriverName();
        LocalDateTime startPayTime = orderPagingSearchParam.getStartPayTime();
        LocalDateTime endPayTime = orderPagingSearchParam.getEndPayTime();
        LocalDateTime startOutTime = orderPagingSearchParam.getStartOutTime();
        LocalDateTime endOutTime = orderPagingSearchParam.getEndOutTime();
        QueryWrapper<OrderPagingResult> ew = Wrappers.<OrderPagingResult>query()
                .eq(stationId != null && stationId > 0, "a.station_id", stationId)
                // .in(!stationIds.isEmpty(), "a.station_id", stationIds)
                .like(StrUtil.isNotBlank(sn), "a.sn", sn)
                .like(StrUtil.isNotBlank(licensePlate), "e.license_plate", licensePlate)
                .like(StrUtil.isNotBlank(nickname), "a.contacts", nickname)
                .like(StrUtil.isNotBlank(phone), "a.phone", phone)
                .like(StrUtil.isNotBlank(transCompanyName), "g.company_name", transCompanyName)
                .like(StrUtil.isNotBlank(driverName), "f.driver_name", driverName)
                .ge(startTime != null, "a.create_time", startTime)
                .le(endTime != null, "a.create_time", endTime)
                .ge(startOutTime != null, "d.out_time", startOutTime)
                .le(endOutTime != null, "d.out_time", endOutTime)
                .eq(orderCategory != null, "a.order_category", orderCategory)
                .eq(null != transCompanyId, "a.trans_company_id", transCompanyId)
                .eq("a.deleted", 0)
                .eq(StrUtil.isNotBlank(area), "b.area", area)
                .eq(null != goodsId, "c.origin_goods_id", goodsId)
                .ge(startPayTime != null, "a.pay_time", startPayTime)
                .le(endPayTime != null, "a.pay_time", endPayTime);
        OrderViewType type = orderPagingSearchParam.getType();
        Assert.notNull(type, () -> Exceptions.clierr("订单类型不能为空"));
        switch (type) {
            case DaiPaiDan:
                dispatchEW(orderPagingSearchParam, page, ew);
                break;
            case YuYue:
                bookingEW(orderPagingSearchParam, page, ew);
                break;
            case LiShi:
                historyEW(orderPagingSearchParam, page, ew);
                break;
            case QuXiao:
                cancelEW(orderPagingSearchParam, page, ew);
                break;
            case ShouGong:
                autoEW(orderPagingSearchParam, page, ew);
                break;
            case ShiShi:
                realtimeEW(orderPagingSearchParam, page, ew);
                break;
            case KanLiao:
                checkEW(orderPagingSearchParam, page, ew);
                break;
        }
        page.addOrder(OrderItem.desc("a.create_time"), OrderItem.desc("a.id"));
        return PageResult.of(baseMapper.paging(page, ew));
    }

    private void dispatchEW(OrderPagingSearchParam orderPagingSearchParam, Page<OrderPagingResult> page, QueryWrapper<OrderPagingResult> ew) {
        MyResult userDetail = SecurityUtil.loginUser();
        Long userId = SecurityUtil.currentUserId();
        BizObj bizObj = userDetail.getBizObj();
        if (BizObj.isTrans(bizObj)) {
            ew
                    .in("a.order_category", OrderCategory.PuTong, OrderCategory.DuanBoChu)
                    .in("a.order_status", OrderStatus.DaiPaiDan, OrderStatus.DaiJieDan)
                    .eq("g.user_id", userId);
            return;
        }
        if (BizObj.isDriver(bizObj)) {
            ew
                    .in("a.order_category", OrderCategory.PuTong, OrderCategory.DuanBoChu)
                    .eq("a.order_status", OrderStatus.DaiJieDan)
                    .eq("f.user_id", userId);
            return;
        }
        Set<String> roles = userDetail.getRoles();
        if (SecurityUtil.isAdmin() || roles.contains(Constant.ROLE_STATION_MANAGE)) {
            ew
                    .eq("a.order_status", OrderStatus.YiYuYue)
                    .isNull("a.trans_company_id ")
            ;
            return;
        }
    }

    private void bookingEW(OrderPagingSearchParam orderPagingSearchParam, Page<OrderPagingResult> page, QueryWrapper<OrderPagingResult> ew) {
        MyResult userDetail = SecurityUtil.loginUser();
        Long userId = SecurityUtil.currentUserId();
        BizObj bizObj = userDetail.getBizObj();
        page.addOrder(OrderItem.desc("a.assignment_trans_time"), OrderItem.desc("a.assignment_driver_time"));

        if (BizObj.isWaste(bizObj)) {
            ew
                    .in("a.order_status", OrderStatus.YiYuYue, OrderStatus.DaiPaiDan, OrderStatus.DaiJieDan, OrderStatus.YiJieDan)
                    .eq("a.user_id", userId)
            ;
            return;
        }

        Set<String> roles = userDetail.getRoles();
        if (SecurityUtil.isAdmin() || roles.contains(Constant.ROLE_STATION_MANAGE)) {
            ew
                    .in("a.order_status", OrderStatus.DaiPaiDan, OrderStatus.DaiJieDan, OrderStatus.YiJieDan)
            ;
            return;
        }
    }

    private void realtimeEW(OrderPagingSearchParam orderPagingSearchParam, Page<OrderPagingResult> page, QueryWrapper<OrderPagingResult> ew) {
        MyResult userDetail = SecurityUtil.loginUser();
        Long userId = SecurityUtil.currentUserId();
        BizObj bizObj = userDetail.getBizObj();
        page.addOrder(OrderItem.desc("a.driver_confirm_time"));

        if (BizObj.isWaste(bizObj)) {
            ew
                    .in("a.order_status", OrderStatus.QingYunZhong, OrderStatus.YiJinChang, OrderStatus.YiChuChang)
                    .eq("a.user_id", userId)
            ;
            return;
        }
        if (BizObj.isTrans(bizObj)) {
            ew
                    .in("a.order_status", OrderStatus.YiJieDan, OrderStatus.QingYunZhong, OrderStatus.YiJinChang, OrderStatus.YiChuChang)
                    .eq("g.user_id", userId)
            ;
            return;
        }
        if (BizObj.isDriver(bizObj)) {
            ew
                    .eq("f.user_id", userId)
                    .in("a.order_status", OrderStatus.YiJieDan, OrderStatus.QingYunZhong, OrderStatus.YiJinChang, OrderStatus.YiChuChang)
            ;
            return;
        }

        Set<String> roles = userDetail.getRoles();
        if (SecurityUtil.isAdmin() || roles.contains(Constant.ROLE_STATION_MANAGE)) {
            ew
                    .in("a.order_status", OrderStatus.QingYunZhong, OrderStatus.YiJinChang, OrderStatus.YiChuChang)
            ;
            return;
        }
    }

    private void historyEW(OrderPagingSearchParam orderPagingSearchParam, Page<OrderPagingResult> page, QueryWrapper<OrderPagingResult> ew) {
        MyResult userDetail = SecurityUtil.loginUser();
        Long userId = SecurityUtil.currentUserId();
        BizObj bizObj = userDetail.getBizObj();
        if (null != page) {
            page.addOrder(OrderItem.desc("d.out_time"));
        }

        if (BizObj.isWaste(bizObj)) {
            ew
                    .eq("a.order_status", OrderStatus.YiWanCheng)
                    .eq("a.user_id", userId)
            ;
            return;
        }
        if (BizObj.isTrans(bizObj)) {
            ew
                    .eq("a.order_status", OrderStatus.YiWanCheng)
                    .eq("g.user_id", userId)
            ;
            return;
        }

        if (BizObj.isDriver(bizObj)) {
            ew
                    .eq("a.order_status", OrderStatus.YiWanCheng)
                    .eq("f.user_id", userId)
            ;
            return;
        }

        Set<String> roles = userDetail.getRoles();
        if (SecurityUtil.isAdmin() || roles.contains(Constant.ROLE_STATION_MANAGE)) {
            ew
                    .eq("a.order_status", OrderStatus.YiWanCheng)
            ;
            return;
        }
    }

    private void cancelEW(OrderPagingSearchParam orderPagingSearchParam, Page<OrderPagingResult> page, QueryWrapper<OrderPagingResult> ew) {
        MyResult userDetail = SecurityUtil.loginUser();
        Long userId = SecurityUtil.currentUserId();
        BizObj bizObj = userDetail.getBizObj();

        if (BizObj.isWaste(bizObj)) {
            ew
                    .eq("a.order_status", OrderStatus.YiQuXiao)
                    .eq("a.user_id", userId)
            ;
            return;
        }

        Set<String> roles = userDetail.getRoles();
        if (SecurityUtil.isAdmin() || roles.contains(Constant.ROLE_STATION_MANAGE)) {
            ew
                    .eq("a.order_status", OrderStatus.YiQuXiao)
            ;
            return;
        }
    }

    private void autoEW(OrderPagingSearchParam orderPagingSearchParam, Page<OrderPagingResult> page, QueryWrapper<OrderPagingResult> ew) {
        UserDetail userDetail = SecurityUtil.loginUser();
        Set<String> roles = userDetail.getRoles();
        if (SecurityUtil.isAdmin() || roles.contains(Constant.ROLE_STATION_MANAGE)) {
            ew
                    .ne("a.auto_order", 3)
            ;
            return;
        }
    }

    private void checkEW(OrderPagingSearchParam orderPagingSearchParam, Page<OrderPagingResult> page, QueryWrapper<OrderPagingResult> ew) {
        MyResult userDetail = SecurityUtil.loginUser();
        BizObj bizObj = userDetail.getBizObj();
        if (BizObj.isSiBang(bizObj)) {
            CheckStatus checkStatus = orderPagingSearchParam.getCheckStatus();
            List<StationManageEntity> stationManageEntityList = stationManageService.list(Wrappers.lambdaQuery(StationManageEntity.class)
                    .eq(StationManageEntity::getUserId, userDetail.getUserId()));
            if (CollUtil.isEmpty(stationManageEntityList)) {
                throw Exceptions.clierr("当前用户不是站点管理员");
            }
            List<Long> collect = stationManageEntityList.stream().map(StationManageEntity::getStationId).collect(Collectors.toList());
            if (checkStatus == CheckStatus.YiKanLiao) {
                ew
                        .eq("a.check_status", checkStatus)
                        .in("a.order_status", OrderStatus.YiJinChang, OrderStatus.YiChuChang, OrderStatus.YiWanCheng)
                        .in("a.station_id", collect)

                ;
            } else if (checkStatus == CheckStatus.WeiKanLiao) {
                ew
                        .eq("a.check_status", checkStatus)
                        .in("a.order_status", OrderStatus.YiJinChang)
                        .in("a.station_id", collect)

                ;
            } else {
                ew
                        .in("a.order_status", OrderStatus.QingYunZhong)
                        .in("a.station_id", collect)
                ;
            }
            return;
        }
    }

    public PageResult<OrderPagingResult> auditPaging(PageParam pageParam, OrderPagingSearchParam orderPagingSearchParam) {
        UserDetail userDetail = SecurityUtil.loginUser();
        Set<String> roles = userDetail.getRoles();
        Assert.isTrue(CollUtil.isNotEmpty(roles) && roles.contains(ROLE_JG), () -> Exceptions.clierr("非监管角色，不能查看"));

        List<String> areaList = bizAuditConfigService.list(Wrappers.<BizAuditConfigEntity>lambdaQuery().in(BizAuditConfigEntity::getAreaRole, roles))
                .stream().map(BizAuditConfigEntity::getArea).distinct().collect(Collectors.toList());
        List<String> cityList = bizAuditConfigService.list(Wrappers.<BizAuditConfigEntity>lambdaQuery().in(BizAuditConfigEntity::getCityRole, roles))
                .stream().map(BizAuditConfigEntity::getArea).distinct().collect(Collectors.toList());
        List<String> cityAreaList = bizAuditConfigService.list(Wrappers.<BizAuditConfigEntity>lambdaQuery()
                        .isNull(BizAuditConfigEntity::getAreaRole).isNull(BizAuditConfigEntity::getCityRole))
                .stream().map(BizAuditConfigEntity::getArea).distinct().collect(Collectors.toList());

        if (CollUtil.isEmpty(areaList) && CollUtil.isEmpty(cityList) && CollUtil.isEmpty(cityAreaList)) {
            return PageResult.of(pageParam.toPage());
        }
        AuditStatus auditStatus = orderPagingSearchParam.getAuditStatus();
        Page<OrderPagingResult> page = pageParam.toPage();
        page.orders().clear();   // 移除所有入参排序
        if ("2".equals(orderPagingSearchParam.getAuditType()) || auditStatus == AuditStatus.TongGuo) {
            page.addOrder(OrderItem.desc("a.shi_audit_time"));
        } else {
            page.addOrder(OrderItem.desc("a.create_time"));
        }
        QueryWrapper<OrderPagingResult> ew = Wrappers.query();
        if (Boolean.TRUE.equals(orderPagingSearchParam.getIsCertificatePaging())) {
            ew.isNotNull("a.certificate_sn");
        }
        String sn = orderPagingSearchParam.getSn();
        String nickname = orderPagingSearchParam.getNickname();
        String phone = orderPagingSearchParam.getPhone();
        String licensePlate = orderPagingSearchParam.getLicensePlate();
        LocalDateTime startTime = orderPagingSearchParam.getStartTime();
        LocalDateTime endTime = orderPagingSearchParam.getEndTime();

        ew
                .like(StrUtil.isNotBlank(sn), "a.sn", sn)
                .like(StrUtil.isNotBlank(nickname), "a.contacts", nickname)
                .like(StrUtil.isNotBlank(phone), "a.phone", phone)
                .like(StrUtil.isNotBlank(licensePlate), "e.license_plate", licensePlate)
                .ge(startTime != null, "e.create_time", startTime)
                .le(endTime != null, "e.create_time", endTime)
                .in("a.order_category", OrderCategory.PuTong, OrderCategory.DuanBoChu)
        ;

        if (auditStatus != null) {
            if (auditStatus == AuditStatus.DaiShenHe) {
                ew
                        .eq("a.order_status", OrderStatus.YiJieDan)
                        .and(it ->
                                it.or(CollUtil.isNotEmpty(areaList), it0 -> it0.in("b.area", areaList).eq("a.audit_status", AuditStatus.QuDaiShenHe))
                                        .or(CollUtil.isNotEmpty(cityList), it1 -> it1.in("b.area", cityList).eq("a.audit_status", AuditStatus.ShiDaiShenHe))
                                        .or(CollUtil.isNotEmpty(cityAreaList), it2 -> it2.in("b.area", cityAreaList).eq("a.audit_status", AuditStatus.DaiShenHe))
                        )
                ;
            } else if (auditStatus == AuditStatus.TongGuo) {
                ew
                        .in("a.order_status", OrderStatus.YiJieDan, OrderStatus.QingYunZhong, OrderStatus.YiJinChang, OrderStatus.YiChuChang, OrderStatus.YiWanCheng)
                        .and(it ->
                                it.or(CollUtil.isNotEmpty(areaList), it0 -> it0.in("b.area", areaList).in("a.audit_status", AuditStatus.ShiDaiShenHe, AuditStatus.TongGuo))
                                        .or(CollUtil.isNotEmpty(cityList), it1 -> it1.in("b.area", cityList).eq("a.audit_status", AuditStatus.TongGuo))
                                        .or(CollUtil.isNotEmpty(cityAreaList), it2 -> it2.in("b.area", cityAreaList).eq("a.audit_status", AuditStatus.TongGuo))
                        );
            } else if (auditStatus == AuditStatus.BoHui) {
                ew
                        .and(it -> it
                                .in("a.order_status", OrderStatus.YiJieDan, OrderStatus.QingYunZhong, OrderStatus.YiJinChang, OrderStatus.YiChuChang, OrderStatus.YiWanCheng)
                                .or(it1 -> it1.eq("a.audit_status", AuditStatus.BoHui).eq("a.order_status", OrderStatus.YiQuXiao))
                        )
                        .and(it ->
                                it.or(CollUtil.isNotEmpty(areaList), it0 -> it0.in("b.area", areaList).eq("a.audit_status", AuditStatus.BoHui))
                                        .or(CollUtil.isNotEmpty(cityList), it1 -> it1.in("b.area", cityList).eq("a.audit_status", AuditStatus.BoHui))
                                        .or(CollUtil.isNotEmpty(cityAreaList), it2 -> it2.in("b.area", cityAreaList).eq("a.audit_status", AuditStatus.BoHui))
                        );
            }
        } else {
            String auditType = orderPagingSearchParam.getAuditType();
            // 1-->待审核
            if ("1".equals(auditType)) {
                ew
                        .eq("a.order_status", OrderStatus.YiJieDan)
                        .and(it ->
                                it.or(CollUtil.isNotEmpty(areaList), it0 -> it0.in("b.area", areaList).in("a.audit_status", AuditStatus.QuDaiShenHe, AuditStatus.ShiDaiShenHe))
                                        .or(CollUtil.isNotEmpty(cityList), it1 -> it1.in("b.area", cityList).eq("a.audit_status", AuditStatus.ShiDaiShenHe))
                                        .or(CollUtil.isNotEmpty(cityAreaList), it2 -> it2.in("b.area", cityAreaList).eq("a.audit_status", AuditStatus.DaiShenHe))
                        );
            } else if ("2".equals(auditType)) { // 2-->已审核
                ew
                        .and(it -> it.in("a.order_status", OrderStatus.YiJieDan, OrderStatus.QingYunZhong, OrderStatus.YiJinChang, OrderStatus.YiChuChang, OrderStatus.YiWanCheng)
                                .or(it1 -> it1.eq("a.audit_status", AuditStatus.BoHui).eq("a.order_status", OrderStatus.YiQuXiao))
                        )
                        .and(it ->
                                it.or(CollUtil.isNotEmpty(areaList), it0 -> it0.in("b.area", areaList).in("a.audit_status", AuditStatus.ShiDaiShenHe, AuditStatus.TongGuo))
                                        .or(CollUtil.isNotEmpty(cityList), it1 -> it1.in("b.area", cityList).in("a.audit_status", AuditStatus.TongGuo, AuditStatus.BoHui))
                                        .or(CollUtil.isNotEmpty(cityAreaList), it2 -> it2.in("b.area", cityAreaList).in("a.audit_status", AuditStatus.TongGuo, AuditStatus.BoHui))
                        );
            } else {
                ew
                        .and(it -> it
                                .in("a.order_status", OrderStatus.YiJieDan, OrderStatus.QingYunZhong, OrderStatus.YiJinChang, OrderStatus.YiChuChang, OrderStatus.YiWanCheng)
                                .or(it1 -> it1.eq("a.audit_status", AuditStatus.BoHui).eq("a.order_status", OrderStatus.YiQuXiao))
                        )
                        .and(it ->
                                it.or(CollUtil.isNotEmpty(areaList), it0 -> it0.in("b.area", areaList))
                                        .or(CollUtil.isNotEmpty(cityList), it1 -> it1.in("b.area", cityList))
                                        .or(CollUtil.isNotEmpty(cityAreaList), it2 -> it2.in("b.area", cityAreaList)))
                ;
            }
        }

        return PageResult.of(baseMapper.paging(page, ew));
    }

    @Transactional(rollbackFor = Exception.class)
    public void batchAudit(BatchAuditOrderParam param) {
        List<Long> orderIds = param.getOrderIds();
        Assert.notEmpty(orderIds, () -> Exceptions.clierr("订单ID列表不能为空"));
        for (Long orderId : orderIds) {
            AuditOrderParam auditOrderParam = new AuditOrderParam()
                    .setId(orderId)
                    .setAuditStatus(param.getAuditStatus())
                    .setAuditMemo(param.getAuditMemo())
                    .setAuditPicture(param.getAuditPicture());
            audit(auditOrderParam);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void audit(AuditOrderParam auditOrderParam) {
        OrderPagingResult detail = detail(auditOrderParam.getId());
        Assert.notNull(detail, () -> Exceptions.clierr("订单不存在"));
        AuditStatus auditStatus = detail.getAuditStatus();
        Assert.isTrue(auditStatus == AuditStatus.QuDaiShenHe
                        || auditStatus == AuditStatus.ShiDaiShenHe
                        || auditStatus == AuditStatus.DaiShenHe,
                () -> Exceptions.clierr("订单已审核"));

        AuditStatus newAuditStatus = auditOrderParam.getAuditStatus();

        Assert.isTrue(newAuditStatus == AuditStatus.TongGuo || newAuditStatus == AuditStatus.BoHui, () -> Exceptions.clierr("未指明审核结果"));

        Set<String> roles = SecurityUtil.loginUser().getRoles();
        BizAuditConfigEntity config = bizAuditConfigService.getOne(Wrappers.<BizAuditConfigEntity>query()
                .eq("area", detail.getArea()));
        Assert.notNull(config, () -> Exceptions.exception("您没有权限审核该订单"));
        String areaRole = config.getAreaRole();
        String cityRole = config.getCityRole();
        if (!roles.contains(areaRole) && !roles.contains(cityRole)) {
            throw Exceptions.clierr("您没有权限审核该订单");
        }

        Long quAuditUserId = null;
        Long shiAuditUserId = null;
        String quAuditPicture = null;
        String shiAuditPicture = null;
        String shiAuditMemo = null;
        LocalDateTime shiAuditTime = null;
        String quAuditMemo = null;
        LocalDateTime quAuditTime = null;
        if (auditStatus == AuditStatus.QuDaiShenHe) {
            if (StrUtil.isNotBlank(areaRole) && roles.contains(areaRole)) {
                quAuditUserId = SecurityUtil.currentUserId();
                quAuditPicture = auditOrderParam.getAuditPicture();
                quAuditMemo = auditOrderParam.getAuditMemo();
                quAuditTime = LocalDateTime.now();
                auditStatus = newAuditStatus == AuditStatus.TongGuo ? AuditStatus.ShiDaiShenHe : newAuditStatus;
            } else {
                throw Exceptions.clierr("您没有权限审核该订单");
            }
        } else if (auditStatus == AuditStatus.ShiDaiShenHe) {
            if (StrUtil.isNotBlank(cityRole) && roles.contains(cityRole)) {
                shiAuditUserId = SecurityUtil.currentUserId();
                shiAuditPicture = auditOrderParam.getAuditPicture();
                shiAuditMemo = auditOrderParam.getAuditMemo();
                shiAuditTime = LocalDateTime.now();
                auditStatus = newAuditStatus;
            } else {
                throw Exceptions.clierr("您没有权限审核该订单");
            }
        } else if (auditStatus == AuditStatus.DaiShenHe) {
            quAuditUserId = SecurityUtil.currentUserId();
            shiAuditUserId = SecurityUtil.currentUserId();
            quAuditPicture = auditOrderParam.getAuditPicture();
            shiAuditPicture = auditOrderParam.getAuditPicture();
            quAuditMemo = auditOrderParam.getAuditMemo();
            quAuditTime = LocalDateTime.now();
            shiAuditMemo = auditOrderParam.getAuditMemo();
            shiAuditTime = LocalDateTime.now();
            auditStatus = newAuditStatus;
        }

        // detail.setAuditStatus(newAuditStatus);
        // detail.setAuditMemo(auditOrderParam.getAuditMemo());
        String certificateSn = null;
        CheckStatus checkStatus = null;
        if (auditStatus == AuditStatus.TongGuo) {
            certificateSn = SnUtil.next(CERTIFICATE_SN_CODE);
            checkStatus = CheckStatus.WeiKanLiao;
        }

        this.updateById(new OrderInfoEntity()
                .setId(detail.getId())
                .setAuditStatus(auditStatus)
                .setQuAuditUserId(quAuditUserId)
                .setShiAuditUserId(shiAuditUserId)
                .setQuAuditPicture(quAuditPicture)
                .setShiAuditPicture(shiAuditPicture)
                .setShiAuditTime(shiAuditTime)
                .setShiAuditMemo(shiAuditMemo)
                .setQuAuditTime(quAuditTime)
                .setQuAuditMemo(quAuditMemo)
                .setCertificateSn(certificateSn)
                .setCheckStatus(checkStatus)
                .setOrderStatus(newAuditStatus == AuditStatus.BoHui ? OrderStatus.YiQuXiao : null)
        );
        if (newAuditStatus == AuditStatus.BoHui) {
            baseMapper.busyDriver(detail.getDriverId(), Boolean.FALSE);
            baseMapper.busyTruck(detail.getTruckId(), Boolean.FALSE);
        }
        OrderCategory orderCategory = detail.getOrderCategory();
        if (orderCategory == OrderCategory.DuanBoRu) return;
        // auditStatus为市待审核状态通知市，通过状态通知司机
        try {
            TemplateMessageParam param = new TemplateMessageParam();
            param.setUserId(detail.getDriverUserId());
            param.setSn(detail.getSn());
            OrderGoodsEntity entity = orderGoodsService.getById(detail.getGoodsId());
            param.setGoodsName(entity.getGoodsName());
            param.setLicensePlate(detail.getLicensePlate());
            param.setCompanyName(detail.getTransCompanyName());
            param.setCreateTime(detail.getCreateTime());
            if (AuditStatus.ShiDaiShenHe.equals(auditStatus)) {
                RoleEntity roleEntity = roleService.getOne(Wrappers.lambdaQuery(RoleEntity.class).eq(
                        RoleEntity::getRoleCode, config.getCityRole()));
                List<SysUserRoleEntity> userIds = userRoleService.list(Wrappers.lambdaQuery(SysUserRoleEntity.class)
                        .eq(SysUserRoleEntity::getRoleId, roleEntity.getId()));
                for (SysUserRoleEntity userRoleEntity : userIds) {
                    param = new TemplateMessageParam();
                    param.setSn(detail.getSn());
                    param.setCfCompanyName(detail.getNickname());
                    param.setTempType(TempType.AUDIT_PENDING.getVal());
                    param.setUserId(userRoleEntity.getUserId());
                    param.setGoodsName(entity.getGoodsName());
                    param.setCompanyName(detail.getTransCompanyName());
                    param.setCreateTime(detail.getCreateTime());
                    wechatTemplateMessageService.sendTemplateMessage(param);
                }
            } else if (AuditStatus.TongGuo.equals(auditStatus)) {
                param.setTempType(TempType.AUDIT_OK.getVal());
                param.setDriverName(detail.getDriverName());
                param.setEndAddress(detail.getStationName());
                wechatTemplateMessageService.sendTemplateMessage(param);
            } else if (AuditStatus.BoHui.equals(auditStatus)) {
                param.setTempType(TempType.AUDIT_REJECT.getVal());
                param.setStartAddress(detail.getAddress());
                wechatTemplateMessageService.sendTemplateMessage(param);
            }
        } catch (Exception e) {
            log.error("通知失败", e);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void check(CheckGoodsParam checkGoodsParam) {
        Long orderId = checkGoodsParam.getOrderId();
        OrderInfoEntity oldOrder = this.getById(orderId);
        Assert.notNull(oldOrder, () -> Exceptions.clierr("订单不存在"));
        CheckStatus checkStatus = oldOrder.getCheckStatus();
        Assert.isFalse(checkStatus == null, () -> Exceptions.clierr("当前订单无需看料"));
        Assert.isFalse(CheckStatus.YiKanLiao == checkStatus, () -> Exceptions.clierr("当前订单已看料"));

        // 查询站点企业信息，判断是否为站点且配置了非称重产品
        Long stationId = oldOrder.getStationId();
        BizCompanyEntity stationCompany = bizCompanyService.getById(stationId);
        boolean isStationWithNoWeighGoods = stationCompany != null
                && Boolean.TRUE.equals(stationCompany.getStation())
                && CollUtil.isNotEmpty(stationCompany.getGoodsIds());

        // 如果是站点且配置了非称重产品，则判断订单产品是否属于非称重产品
        boolean isNoWeighProductOrder = false;
        if (isStationWithNoWeighGoods) {
            // 通过订单的 goodsId 查询 order_goods 表获取 origin_goods_id
            OrderGoodsEntity orderGoods = orderGoodsService.getById(oldOrder.getGoodsId());
            if (orderGoods != null) {
                Long originGoodsId = orderGoods.getOriginGoodsId();
                // 判断 originGoodsId 是否在企业的非称重产品 goodsIds 集合中
                isNoWeighProductOrder = stationCompany.getGoodsIds()
                        .contains(originGoodsId.toString());
            }
        }

        // 如果是非称重产品订单，直接完成订单
        if (isNoWeighProductOrder) {
            // 获取支付上下文，获取支付方式
            PaymentContextResult paymentCtx = paymentContext(orderId);
            String settlementWay = paymentCtx != null ? paymentCtx.getSettlementWay() : null;

            this.updateById(new OrderInfoEntity()
                    .setId(orderId)
                    .setCheckPhoto(checkGoodsParam.getCheckPhoto())
                    .setCheckTime(LocalDateTime.now())
                    .setCheckStatus(CheckStatus.YiKanLiao)
                    .setCheckerId(SecurityUtil.currentUserId())
                    .setOrderStatus(OrderStatus.YiWanCheng)
                    .setPaymentStatus(PaymentStatus.YiZhiFu)
                    .setFinishTime(LocalDateTime.now())
                    .setSettlementWay(settlementWay)
            );
        } else {
            // 普通产品订单，仅更新看料状态
            Assert.isTrue(oldOrder.getOrderStatus() == OrderStatus.YiJinChang, () -> Exceptions.clierr("当前订单状态，无法看料"));
            this.updateById(new OrderInfoEntity()
                    .setId(orderId)
                    .setCheckPhoto(checkGoodsParam.getCheckPhoto())
                    .setCheckTime(LocalDateTime.now())
                    .setCheckStatus(CheckStatus.YiKanLiao)
                    .setCheckerId(SecurityUtil.currentUserId())
            );
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void batchAssignment(BatchAssignmentOrderParam param) {
        List<Long> orderIds = param.getOrderIds();
        Assert.notEmpty(orderIds, () -> Exceptions.clierr("订单ID列表不能为空"));
        Assert.notNull(param.getDriverId(), () -> Exceptions.clierr("司机ID不能为空"));
        for (Long orderId : orderIds) {
            AssignmentOrderParam assignmentOrderParam = new AssignmentOrderParam()
                    .setOrderId(orderId)
                    .setDriverId(param.getDriverId());
            OrderInfoEntity oldOrder = this.getById(orderId);
            Assert.notNull(oldOrder, () -> Exceptions.clierr("订单不存在, orderId: " + orderId));
            assignmentDriver(assignmentOrderParam, oldOrder);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void batchConfirm(BatchConfirmOrderParam param) {
        List<Long> orderIds = param.getOrderIds();
        Assert.notEmpty(orderIds, () -> Exceptions.clierr("订单ID列表不能为空"));
        Assert.notNull(param.getTruckId(), () -> Exceptions.clierr("车辆ID不能为空"));
        for (Long orderId : orderIds) {
            confirm(orderId, param.getTruckId());
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void assignment(AssignmentOrderParam assignmentOrderParam) {
        OrderInfoEntity oldOrder = this.getById(assignmentOrderParam.getOrderId());
        Assert.notNull(oldOrder, () -> Exceptions.clierr("订单不存在"));
        boolean assignmented = assignmentTrafficCompany(assignmentOrderParam, oldOrder);
        if (assignmented) {
            oldOrder.setOrderStatus(OrderStatus.DaiPaiDan);
        }
        assignmentDriver(assignmentOrderParam, oldOrder);
        if (assignmented) {
            Long transCompanyId = assignmentOrderParam.getTransCompanyId();
            BizCompanyEntity transCompanyEntity = baseMapper.getTransInfo(transCompanyId);
            cloudVoiceboxService.play(transCompanyEntity.getUserId(), "您有新的待分配订单，请及时处理");
        }
    }

    private void assignmentDriver(AssignmentOrderParam assignmentOrderParam, OrderInfoEntity orderInfo) {
        Long driverId = assignmentOrderParam.getDriverId();
        if (driverId == null) return;
        Assert.isNull(orderInfo.getDriverId(), () -> Exceptions.clierr("当前订单已分配司机，无需重复分配"));
        Assert.isTrue(orderInfo.getOrderStatus() == OrderStatus.DaiPaiDan, () -> Exceptions.clierr("当前订单状态，无法分配司机"));
        // 查询订单及相关支付上下文
        PaymentContextResult ctx = paymentContext(orderInfo.getId());
        if (SettlementWay.BALANCE.getVal().equals(ctx.getSettlementWay())) {
            // 如果该笔订单的清运公司支付方式为余额支付时，需在分配之前查询当前清运公司余额是否充足，
            // 不足则提示余额不足，不允许在派司机
            if (ctx.getCompanyBalance().compareTo(BigDecimal.ZERO) < 0) {
                // 已经是负数，禁止再次支付
                throw Exceptions.clierr("公司账户余额不足");
            }
        }
        // baseMapper.busyDriver(driverId, Boolean.TRUE);

        OrderCategory orderCategory = orderInfo.getOrderCategory();
        if (orderCategory == OrderCategory.DuanBoChu) {
            this.updateById(new OrderInfoEntity()
                    .setId(orderInfo.getTargetOrderId())
                    .setDriverId(driverId)
                    .setAssignmentDriverTime(LocalDateTime.now())
                    .setOrderStatus(OrderStatus.DaiJieDan));
        }

        this.updateById(new OrderInfoEntity()
                .setId(orderInfo.getId())
                .setDriverId(driverId)
                .setAssignmentDriverTime(LocalDateTime.now())
                .setOrderStatus(OrderStatus.DaiJieDan)
        );
        // 通知司机
        try {
            BizDriverEntity driverEntity = bizDriverService.getById(driverId);
            TemplateMessageParam param = new TemplateMessageParam();
            param.setUserId(driverEntity.getUserId());
            param.setTempType(TempType.DRIVER.getVal());
            param.setSn(orderInfo.getSn());
            param.setDriverName(driverEntity.getDriverName());
            OrderCargoPlaceEntity cargoPlace = orderCargoPlaceService.getById(orderInfo.getCargoPlaceId());
            param.setStartAddress(cargoPlace.getAddress());
            BizCompanyEntity companyEntity = bizCompanyService.getById(orderInfo.getStationId());
            param.setEndAddress(companyEntity.getStationName());
            wechatTemplateMessageService.sendTemplateMessage(param);
        } catch (Exception e) {
            log.error("通知失败", e);
        }
    }

    private boolean assignmentTrafficCompany(AssignmentOrderParam assignmentOrderParam,
                                             OrderInfoEntity orderInfo) {
        Long transCompanyId = assignmentOrderParam.getTransCompanyId();
        if (transCompanyId == null) return false;
        Assert.isNull(orderInfo.getTransCompanyId(), () -> Exceptions.clierr("当前订单已分配清运公司，无需重复分配"));
        Assert.isTrue(orderInfo.getOrderStatus() == OrderStatus.YiYuYue, () -> Exceptions.clierr("当前订单状态，无法分配清运公司"));

        Long orderInfoId = orderInfo.getId();
        this.updateById(new OrderInfoEntity()
                .setId(orderInfoId)
                .setTransCompanyId(transCompanyId)
                .setAssignmentTransTime(LocalDateTime.now())
                .setOrderStatus(OrderStatus.DaiPaiDan)
        );
//        OrderInfoEntity orderInfoEntity = this.getById(orderInfoId);
//        settleForTransCompany(orderInfoEntity, 0);
        // 通知清运公司
        try {
            TemplateMessageParam param = new TemplateMessageParam();
            BizCompanyEntity transCompanyEntity = baseMapper.getTransInfo(transCompanyId);
            param.setUserId(transCompanyEntity.getUserId());
            param.setTempType(TempType.TRANS_COMPANY.getVal());
            param.setSn(orderInfo.getSn());
            OrderGoodsEntity entity = orderGoodsService.getById(orderInfo.getGoodsId());
            param.setGoodsName(entity.getGoodsName());
            OrderCargoPlaceEntity cargoPlace = orderCargoPlaceService.getById(orderInfo.getCargoPlaceId());
            param.setStartAddress(cargoPlace.getAddress());
            wechatTemplateMessageService.sendTemplateMessage(param);
        } catch (Exception e) {
            log.error("通知失败", e);
        }
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    public void confirm(Long orderId, Long truckId) {
        OrderInfoEntity orderInfo = this.getById(orderId);
        Assert.notNull(orderInfo, () -> Exceptions.clierr("订单不存在"));
        Assert.isTrue(orderInfo.getOrderStatus() == OrderStatus.DaiJieDan, () -> Exceptions.clierr("当前订单状态，无法确认接单"));
        long driverId = orderInfo.getDriverId();
        long userId = SecurityUtil.currentUserId();
        Long driverId_ = baseMapper.getDriverId(userId);
        Assert.isTrue(driverId_ != null && driverId == driverId_, () -> Exceptions.clierr("您没有权限确认此单"));
        // baseMapper.busyTruck(truckId, Boolean.TRUE);
        OrderCargoPlaceEntity cargoPlaceEntity = orderCargoPlaceService.getById(orderInfo.getCargoPlaceId());
        String area = cargoPlaceEntity.getArea();
        BizAuditConfigEntity bizAuditConfigEntity = bizAuditConfigService.getOne(Wrappers.lambdaQuery(BizAuditConfigEntity.class).eq(BizAuditConfigEntity::getArea, area));

        AuditStatus auditStatus = AuditStatus.DaiShenHe;
        if (bizAuditConfigEntity != null) {
            String areaRole = bizAuditConfigEntity.getAreaRole();
            String cityRole = bizAuditConfigEntity.getCityRole();
            if (areaRole != null && cityRole != null) {
                auditStatus = AuditStatus.QuDaiShenHe;
            } else if (areaRole == null && cityRole != null) {
                auditStatus = AuditStatus.ShiDaiShenHe;
            }
        }
        this.updateById(new OrderInfoEntity()
                .setId(orderInfo.getId())
                .setDriverConfirmTime(LocalDateTime.now())
                .setAuditStatus(auditStatus)
                .setTruckId(truckId)
                .setOrderStatus(OrderStatus.YiJieDan)
        );
        try {
            // 通知审核人
            RoleEntity roleEntity = new RoleEntity();
            if (null != bizAuditConfigEntity && !Strings.isNullOrEmpty(bizAuditConfigEntity.getAreaRole())
                    && AuditStatus.QuDaiShenHe.equals(auditStatus)) {
                roleEntity = roleService.getOne(Wrappers.lambdaQuery(RoleEntity.class).eq(
                        RoleEntity::getRoleCode, bizAuditConfigEntity.getAreaRole()));
            } else if (null != bizAuditConfigEntity && !Strings.isNullOrEmpty(bizAuditConfigEntity.getCityRole())
                    && AuditStatus.ShiDaiShenHe.equals(auditStatus)) {
                roleEntity = roleService.getOne(Wrappers.lambdaQuery(RoleEntity.class).eq(
                        RoleEntity::getRoleCode, bizAuditConfigEntity.getCityRole()));
            }
            if (null != roleEntity && null != roleEntity.getId()) {
                List<SysUserRoleEntity> userIds = userRoleService.list(Wrappers.lambdaQuery(SysUserRoleEntity.class)
                        .eq(SysUserRoleEntity::getRoleId, roleEntity.getId()));
                UserEntity orderUserEntity = userService.getById(orderInfo.getUserId());
                OrderGoodsEntity entity = orderGoodsService.getById(orderInfo.getGoodsId());
                BizCompanyEntity companyEntity = bizCompanyService.getById(orderInfo.getTransCompanyId());
                Set<String> openId = new HashSet<>();
                TemplateMessageParam param;
                for (SysUserRoleEntity userRoleEntity : userIds) {
                    UserEntity userEntity = userService.getById(userRoleEntity.getUserId());
                    if (null != userEntity && !Strings.isNullOrEmpty(userEntity.getOpenid())) {
                        if (openId.add(userEntity.getOpenid())) {
                            param = new TemplateMessageParam();
                            param.setUserId(userRoleEntity.getUserId());
                            param.setTempType(TempType.AUDIT_PENDING.getVal());
                            param.setSn(orderInfo.getSn());
                            param.setCfCompanyName(orderUserEntity.getNickname());
                            param.setGoodsName(entity.getGoodsName());
                            param.setCompanyName(companyEntity.getCompanyName());
                            param.setCreateTime(orderInfo.getCreateTime());
                            log.info("发送审核通知模板消息，参数：{}", param);
                            wechatTemplateMessageService.sendTemplateMessage(param);
                        }
                    } else {
                        log.info("未查到用户信息：{}", userRoleEntity.getUserId());
                    }
                }
            }
        } catch (Exception e) {
            log.error("通知失败", e);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void startTrans(StartTransportOrderParam startTransportOrderParam) {
        OrderInfoEntity orderInfo = this.getById(startTransportOrderParam.getOrderId());
        Assert.notNull(orderInfo, () -> Exceptions.clierr("订单不存在"));
        Assert.isTrue(orderInfo.getOrderStatus() == OrderStatus.YiJieDan, () -> Exceptions.clierr("当前订单状态，无法开始运输"));
        Assert.isTrue(orderInfo.getAuditStatus() == AuditStatus.TongGuo, () -> Exceptions.clierr("当前订单未审核完成，无法开始运输"));
        Long truckId = orderInfo.getTruckId();
        Long driverId = orderInfo.getDriverId();
        Boolean driverHasInProgress = baseMapper.hasInProgressOrder(driverId,
                Arrays.asList(OrderStatus.QingYunZhong.getVal(), OrderStatus.YiJinChang.getVal(), OrderStatus.YiChuChang.getVal()));
        Assert.isFalse(driverHasInProgress, () -> Exceptions.clierr("您有正在进行中的订单，不能清运"));
        Long orderInfoId = orderInfo.getId();

        OrderGoodsEntity entity = orderGoodsService.getById(orderInfo.getGoodsId());
        Assert.notNull(entity, () -> Exceptions.clierr("产品不存在"));

        if (MoneyWay.IN.getVal().equals(entity.getMoneyWay()) && OrderCategory.PuTong.equals(orderInfo.getOrderCategory())) {
            // 入场付费无称重，不需要更新付费项
            // 处理公司支付
            handleCompanyPay(orderInfo, Boolean.TRUE, new BigDecimal("0"), Boolean.FALSE);
        }

        baseMapper.busyDriver(driverId, Boolean.TRUE);
        baseMapper.busyTruck(truckId, Boolean.TRUE);

        // 查询站点企业信息，判断是否为站点且配置了非称重产品
        Long stationId = orderInfo.getStationId();
        BizCompanyEntity stationCompany = bizCompanyService.getById(stationId);
        boolean isStationWithNoWeighGoods = stationCompany != null
                && Boolean.TRUE.equals(stationCompany.getStation())
                && CollUtil.isNotEmpty(stationCompany.getGoodsIds());

        // 如果是站点且配置了非称重产品，则判断订单产品是否属于非称重产品
        boolean isNoWeighProductOrder = false;
        if (isStationWithNoWeighGoods) {
            // 通过订单的 goodsId 查询 order_goods 表获取 origin_goods_id
            OrderGoodsEntity orderGoods = orderGoodsService.getById(orderInfo.getGoodsId());
            if (orderGoods != null) {
                Long originGoodsId = orderGoods.getOriginGoodsId();
                // 判断 originGoodsId 是否在企业的非称重产品 goodsIds 集合中
                isNoWeighProductOrder = stationCompany.getGoodsIds()
                        .contains(originGoodsId.toString());
            }
        }
        OrderStatus orderStatus = OrderStatus.QingYunZhong;
        if (isNoWeighProductOrder) {
            orderStatus =  OrderStatus.YiJinChang;
        }
        this.updateById(new OrderInfoEntity()
                .setId(orderInfoId)
                .setCargoPhoto(startTransportOrderParam.getCargoPhoto())
                .setOrderStatus(orderStatus)
                .setTransTime(LocalDateTime.now())
        );

        Assert.notNull(truckId, () -> Exceptions.clierr("订单未分配车辆"));
        BizTruckEntity truckInfo = baseMapper.getTruckInfo(truckId);
        Assert.notNull(truckInfo, () -> Exceptions.clierr("车辆不存在"));

        String gpsId = truckInfo.getGps();
        String licensePlate = truckInfo.getLicensePlate();
        if (checkGps) {
            Assert.notEmpty(gpsId, () -> Exceptions.clierr("车辆未绑定GPS"));
            DeviceLocalizerEntity deviceLocalizerEntity = baseMapper.gpsLastOnlineTime(gpsId);
            LocalDateTime lastTime = deviceLocalizerEntity.getLastTime();

            boolean after = lastTime == null || lastTime.isBefore(LocalDateTime.now().minusMinutes(5));
            if (after) {
                bizWarnService.save(new BizWarnEntity()
                        .setWarnCategory(WarnCategory.EQUIPMENT.getVal())
                        .setWarnContent(StrUtil.format("{} 绑定的 GPS 设备已离线，设备号：{}", licensePlate, gpsId))
                        .setOrderId(orderInfoId)
                );
                return;
            }
        }

        startTrack(gpsId, licensePlate, orderInfoId, truckId);

        CompletableFuture.runAsync(() -> Websocket.publish(new WsMsg().setEvent("down/order/status_change")
                .setData(MapUtil.builder()
                        .put("sn", orderInfo.getSn())
                        .put("licensePlate", licensePlate)
                        .put("orderStatus", OrderStatus.QingYunZhong)
                        .build()))).exceptionally(e -> {
            log.error("订单状态改变事件发布失败，订单{}，状态{}", orderInfo.getSn(), OrderStatus.QingYunZhong, e);
            return null;
        });
    }

    public boolean handleCompanyPay(OrderInfoEntity orderInfo, Boolean isIn, BigDecimal changeMoney, Boolean isChange) {
        PaymentContextResult ctx = paymentContext(orderInfo.getId());
        BigDecimal payMoney = ctx.getSettleMoney();
        if (isChange) {
            payMoney = changeMoney;
        }
        if (payMoney != null && payMoney.compareTo(BigDecimal.ZERO) > 0) {
            if (OrderCategory.PuTong.equals(orderInfo.getOrderCategory())) {
                if (!SettlementWay.CASH.getVal().equals(ctx.getSettlementWay())) {
                    String way = SettlementWay.BALANCE.getVal().equals(ctx.getSettlementWay()) ?
                            SettlementWay.BALANCE.getTxt() : SettlementWay.MONTH.getTxt();
                    BigDecimal oldBalance = ctx.getCompanyBalance();
                    BigDecimal newBalance = oldBalance.subtract(payMoney);
                    // 更新账户余额（支持负数余额）
                    MoneyAccountEntity companyAccount = new MoneyAccountEntity()
                            .setId(ctx.getCompanyAccountId())
                            .setMoney(newBalance);
                    moneyAccountService.updateById(companyAccount);

                    // 记录资金变动明细
                    MoneyChangeDetailEntity changeDetail = new MoneyChangeDetailEntity()
                            .setCompanyId(ctx.getTransCompanyId())
                            .setOrderId(orderInfo.getId())
                            .setMoneyAccountId(companyAccount.getId())
                            .setOldMoney(oldBalance)
                            // 扣减为负数
                            .setDelta(payMoney.negate())
                            .setNewMoney(newBalance)
                            .setMoneyChangeCategory(MoneyChangeCategory.DingDanKouKuan)
                            .setMemo("订单支付扣款，订单号：" + orderInfo.getSn() + "，结算方式：" + way);

                    moneyChangeDetailService.save(changeDetail);

                    log.info("公司账户扣减成功，用户ID：{}，扣减金额：{}，余额：{} -> {}，结算方式：{}",
                            ctx.getCompanyUserId(), payMoney, oldBalance, newBalance, ctx.getSettlementWay());

                    // 更新订单支付状态为已支付
                    return updateOrderPaymentStatus(orderInfo, ctx, isIn);
                }
            } else if (OrderCategory.DuanBoRu.equals(orderInfo.getOrderCategory())) {
                // 短驳入订单，增加营收
                BigDecimal oldRevenue = ctx.getRevenue();
                BigDecimal newRevenue = oldRevenue.add(payMoney);
                // 更新账户营收
                MoneyAccountEntity companyAccount = new MoneyAccountEntity()
                        .setId(ctx.getCompanyAccountId())
                        .setRevenue(newRevenue);
                moneyAccountService.updateById(companyAccount);

                // 记录资金变动明细
                MoneyChangeDetailEntity changeDetail = new MoneyChangeDetailEntity()
                        .setCompanyId(ctx.getTransCompanyId())
                        .setOrderId(orderInfo.getId())
                        .setMoneyAccountId(companyAccount.getId())
                        .setOldMoney(oldRevenue)
                        // 扣减为负数
                        .setDelta(payMoney)
                        .setNewMoney(newRevenue)
                        .setMoneyChangeCategory(MoneyChangeCategory.DuanBoYingShou)
                        .setMemo("短驳营收，订单号：" + orderInfo.getSn());

                moneyChangeDetailService.save(changeDetail);

                log.info("公司营收增加成功，用户ID：{}，扣减金额：{}，余额：{} -> {}",
                        ctx.getCompanyUserId(), payMoney, oldRevenue, newRevenue);
                // 更新订单支付状态为已支付
                return updateOrderPaymentStatus(orderInfo, ctx, isIn);
            }
        } else {
            // 如果支付金额为0，则直接改状态
            // 更新订单支付状态为已支付
            return updateOrderPaymentStatus(orderInfo, ctx, isIn);
        }
        return false;
    }

    private boolean updateOrderPaymentStatus(OrderInfoEntity orderInfo, PaymentContextResult ctx, Boolean isIn) {
        OrderInfoEntity entity = new OrderInfoEntity();
        entity.setId(orderInfo.getId());
        entity.setPaymentStatus(PaymentStatus.YiZhiFu);
        entity.setSettlementWay(ctx.getSettlementWay());
        entity.setPayTime(LocalDateTime.now());
        if (!isIn) {
            entity.setOrderStatus(OrderStatus.YiWanCheng);
            this.updateById(entity);
            return true;
        } else {
            this.updateById(entity);
            return false;
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void orderTimeOut() {
        log.info("检查超时订单");
        List<OrderInfoEntity> timeOutOrderList = this.list(Wrappers.<OrderInfoEntity>lambdaQuery()
                .isNotNull(OrderInfoEntity::getShiAuditTime)
                .le(OrderInfoEntity::getShiAuditTime, LocalDateTime.now().minusHours(12))
                .notIn(OrderInfoEntity::getOrderStatus, OrderStatus.YiJinChang, OrderStatus.YiChuChang, OrderStatus.YiWanCheng)
        );
        if (CollUtil.isEmpty(timeOutOrderList)) return;
        log.info("有超时订单：{} 个", timeOutOrderList.size());
        for (OrderInfoEntity orderInfoEntity : timeOutOrderList) {
            Long id = orderInfoEntity.getId();
            String sn = orderInfoEntity.getSn();
            boolean exists = bizWarnService.exists(Wrappers.<BizWarnEntity>lambdaQuery().eq(BizWarnEntity::getOrderId, id).eq(BizWarnEntity::getWarnCategory, WarnCategory.SAFETY.getVal()));
            if (exists) continue;
            bizWarnService.save(new BizWarnEntity()
                    .setWarnCategory(WarnCategory.SAFETY.getVal())
                    .setWarnContent(StrUtil.format("订单：{}，已超时", sn))
                    .setOrderId(id)
            );
        }
    }

    public void startTrackOrder(Long orderId) {
        OrderInfoEntity orderInfo = this.getById(orderId);
        Long truckId = orderInfo.getTruckId();
        BizTruckEntity truckInfo = baseMapper.getTruckInfo(truckId);
        String gpsId = truckInfo.getGps();
        String licensePlate = truckInfo.getLicensePlate();
        startTrack(gpsId, licensePlate, orderId, truckId);
    }

    public void stopTrackOrder(Long orderId) {
        OrderInfoEntity orderInfo = this.getById(orderId);
        Long truckId = orderInfo.getTruckId();
        BizTruckEntity truckInfo = baseMapper.getTruckInfo(truckId);
        String gpsId = truckInfo.getGps();
        stopTrack(gpsId);
    }

    @Transactional(rollbackFor = Exception.class)
    public void cancel(Long orderId, String reason) {
        OrderInfoEntity orderInfo = this.getById(orderId);
        Assert.notNull(orderInfo, () -> Exceptions.clierr("订单不存在"));
        OrderStatus orderStatus = orderInfo.getOrderStatus();
        if (!SecurityUtil.isAdmin()) {
            Assert.isTrue(orderStatus == OrderStatus.YiYuYue
                            || orderStatus == OrderStatus.DaiPaiDan
                            || orderStatus == OrderStatus.DaiJieDan
                            || orderStatus == OrderStatus.YiJieDan,
                    () -> Exceptions.clierr("当前订单状态，无法取消"));
            AuditStatus auditStatus = orderInfo.getAuditStatus();
            Assert.isFalse(auditStatus == AuditStatus.TongGuo, () -> Exceptions.clierr("当前订单状态，无法取消"));
        }
        // 退款
        // 验证订单状态
        if (PaymentStatus.YiZhiFu.equals(orderInfo.getPaymentStatus())) {
            RefundRequestDto dto = new RefundRequestDto();
            dto.setOrderId(orderId);
            dto.setRefundAmount(orderInfo.getSettleMoney());
            dto.setOutTradeNo(orderInfo.getOutTradeNo());
            dto.setReason("订单取消");
            // 获取支付上下文
            PaymentContextResult ctx = this.paymentContext(orderId);
            paymentService.refund(dto, ctx, Boolean.FALSE);
            this.lambdaUpdate()
                    .eq(OrderInfoEntity::getId, orderId)
                    .set(OrderInfoEntity::getPaymentStatus, PaymentStatus.YiTuiKuan)
                    .set(OrderInfoEntity::getRefundMoney, orderInfo.getSettleMoney())
                    .set(OrderInfoEntity::getRefundTime, LocalDateTime.now())
                    .set(OrderInfoEntity::getCancelReason, reason)
                    .set(OrderInfoEntity::getOrderStatus, OrderStatus.YiQuXiao)
                    .update();
        } else {
            this.updateById(new OrderInfoEntity()
                    .setId(orderInfo.getId())
                    .setCancelReason(reason)
                    .setOrderStatus(OrderStatus.YiQuXiao)
            );
        }
        Long driverId = orderInfo.getDriverId();
        Long truckId = orderInfo.getTruckId();
        if (driverId != null) baseMapper.busyDriver(driverId, Boolean.FALSE);
        if (truckId != null) baseMapper.busyTruck(truckId, Boolean.FALSE);
        CompletableFuture.runAsync(() -> {
            String licensePlate = null;
            if (truckId != null) {
                BizTruckEntity truckInfo = baseMapper.getTruckInfo(truckId);
                licensePlate = truckInfo.getLicensePlate();
            }
            Websocket.publish(new WsMsg().setEvent("down/order/status_change")
                    .setData(MapUtil.builder()
                            .put("sn", orderInfo.getSn())
                            .put("licensePlate", licensePlate)
                            .put("orderStatus", OrderStatus.YiJinChang)
                            .build()));
        }).exceptionally(e -> {
            log.error("订单状态改变事件发布失败，订单{}，状态{}", orderInfo.getSn(), OrderStatus.YiQuXiao, e);
            return null;
        });
        // TODO 关闭 GPS 定位
        CompletableFuture.runAsync(() -> {
            if (truckId == null) {
                return;
            }
            BizTruckEntity truckInfo = baseMapper.getTruckInfo(truckId);
            if (truckInfo == null) {
                return;
            }
            String gpsId = truckInfo.getGps();
            if (StrUtil.isBlank(gpsId)) {
                return;
            }
            stopTrack(gpsId);
        }).exceptionally(ex -> {
            log.error("数据获取失败", ex);
            return null;
        });
    }

    @Transactional(rollbackFor = Exception.class)
    public void modifyGoods(ModifyOrderGoodsParam modifyOrderGoodsParam) {
        OrderInfoEntity orderInfoEntity = this.getById(modifyOrderGoodsParam.getOrderId());
        Assert.notNull(orderInfoEntity, () -> Exceptions.clierr("订单不存在"));
        OrderStatus orderStatus = orderInfoEntity.getOrderStatus();
        Assert.isTrue(orderStatus != OrderStatus.YiChuChang
                        && orderStatus != OrderStatus.YiWanCheng
                        && orderStatus != OrderStatus.YiQuXiao
                , () -> Exceptions.clierr("当前订单状态，无法修改商品"));
        Long targetOrderId = orderInfoEntity.getTargetOrderId();
        if (targetOrderId != null) {
            OrderInfoEntity targetOrderInfo = this.getById(targetOrderId);
            Assert.notNull(targetOrderInfo, () -> Exceptions.clierr("关联订单不存在"));
            orderGoodsService.modify(new OrderGoodsEntity()
                    .setId(targetOrderInfo.getGoodsId())
                    .setGoodsCategoryId(modifyOrderGoodsParam.getGoodsCategoryId())
                    .setOriginGoodsId(modifyOrderGoodsParam.getOriginGoodsId())
            );
        }

        orderGoodsService.modify(new OrderGoodsEntity()
                .setId(orderInfoEntity.getGoodsId())
                .setGoodsCategoryId(modifyOrderGoodsParam.getGoodsCategoryId())
                .setOriginGoodsId(modifyOrderGoodsParam.getOriginGoodsId())
        );
    }

    /**
     * 车辆进场
     *
     * @param i 0-->自动、1-->手动
     */
    @Transactional(rollbackFor = Exception.class)
    public void truckComing(TruckComingOrderParam truckComingOrderParam, int i) {
        OrderInfoEntity orderInfoEntity = this.getById(truckComingOrderParam.getOrderId());
        Assert.notNull(orderInfoEntity, () -> Exceptions.clierr("订单不存在"));
        OrderStatus orderStatus = orderInfoEntity.getOrderStatus();

        Assert.isTrue(orderStatus == OrderStatus.QingYunZhong, () -> Exceptions.clierr("当前订单状态，无法进场"));

        OrderCategory orderCategory = orderInfoEntity.getOrderCategory();
        long carInOutId = orderCarInOutService.truckComing(truckComingOrderParam, orderCategory);
        CheckStatus checkStatus = null;
        if (orderInfoEntity.getOrderCategory() == OrderCategory.DuanBoChu) {
            checkStatus = CheckStatus.YiKanLiao;
        }
        this.updateById(new OrderInfoEntity()
                .setAutoOrder(3 ^ i)
                .setId(orderInfoEntity.getId())
                .setCarInOutId(carInOutId)
                .setOrderStatus(OrderStatus.YiJinChang)
                .setCheckStatus(checkStatus)
        );

        CompletableFuture.runAsync(() -> {
            Long truckId = orderInfoEntity.getTruckId();
            BizTruckEntity truckInfo = baseMapper.getTruckInfo(truckId);
            String licensePlate = truckInfo.getLicensePlate();
            Websocket.publish(new WsMsg().setEvent("down/order/status_change")
                    .setData(MapUtil.builder()
                            .put("sn", orderInfoEntity.getSn())
                            .put("licensePlate", licensePlate)
                            .put("orderStatus", OrderStatus.YiJinChang)
                            .build()));
        }).exceptionally(e -> {
            log.error("订单状态改变事件发布失败，订单{}，状态{}", orderInfoEntity.getSn(), OrderStatus.YiJinChang, e);
            return null;
        });
    }

    /**
     * 车辆出场
     *
     * @param i 0-->自动、1-->手动
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean truckLeaving(TruckLeavingOrderParam truckLeavingOrderParam, int i) {
        Long orderId = truckLeavingOrderParam.getOrderId();
        OrderInfoEntity orderInfoEntity = this.getById(orderId);
        Long truckId = orderInfoEntity.getTruckId();
        boolean result = false;
        try {
            Assert.notNull(orderInfoEntity, () -> Exceptions.clierr("订单不存在"));
            OrderStatus orderStatus = orderInfoEntity.getOrderStatus();
            Assert.isTrue(orderStatus == OrderStatus.YiJinChang, () -> Exceptions.clierr("当前订单状态，无法出场"));
            OrderCategory orderCategory = orderInfoEntity.getOrderCategory();

            Integer settleWeight = orderCarInOutService.truckOut(orderInfoEntity.getCarInOutId(), truckLeavingOrderParam, orderCategory, truckId);
            // 结算（目前仅针对清运公司）：
            // 1) 复制“产品”到 order_expense_items；
            // 2) 从 expense_items_config 读取可用付费项并按 scope 过滤（all / customer_type=QiYe|GeTi / customer 包含 trans_company_id）；
            // 3) 合并集合，计算 total_money 与 settle_money，并批量落库。
            OrderGoodsEntity entity = orderGoodsService.getById(orderInfoEntity.getGoodsId());
            Assert.notNull(entity, () -> Exceptions.clierr("产品不存在"));
            if (MoneyWay.OUT.getVal().equals(entity.getMoneyWay())) {
                // 计算费用，出厂付费可能需要称重，需要更新付费项
                updateOrderItems(orderInfoEntity.getId(), orderInfoEntity.getTransCompanyId(), settleWeight, Boolean.FALSE);
                orderInfoEntity = this.getById(orderId);
            }

            PaymentStatus paymentStatus = orderInfoEntity.getPaymentStatus();

            OrderStatus newOrderStatus = paymentStatus == PaymentStatus.WeiZhiFu ? OrderStatus.YiChuChang : OrderStatus.YiWanCheng;
            this.updateById(new OrderInfoEntity()
                    .setAutoOrder(3 ^ (i << 1))
                    .setId(orderInfoEntity.getId())
                    .setOrderStatus(newOrderStatus)
            );

            if (orderInfoEntity.getOrderCategory() == OrderCategory.DuanBoChu) {
                Long targetOrderId = orderInfoEntity.getTargetOrderId();

                this.updateById(new OrderInfoEntity()
                        .setId(targetOrderId)
                        // 接单
                        .setDriverConfirmTime(orderInfoEntity.getDriverConfirmTime())
                        .setTruckId(truckId)

                        // 审核
                        .setAuditStatus(orderInfoEntity.getAuditStatus())
                        .setQuAuditUserId(orderInfoEntity.getQuAuditUserId())
                        .setShiAuditUserId(orderInfoEntity.getShiAuditUserId())
                        .setQuAuditPicture(orderInfoEntity.getQuAuditPicture())
                        .setShiAuditPicture(orderInfoEntity.getShiAuditPicture())
                        .setShiAuditTime(orderInfoEntity.getShiAuditTime())
                        .setShiAuditMemo(orderInfoEntity.getShiAuditMemo())
                        .setQuAuditTime(orderInfoEntity.getQuAuditTime())
                        .setQuAuditMemo(orderInfoEntity.getQuAuditMemo())
                        .setCertificateSn(orderInfoEntity.getCertificateSn())
                        .setCheckStatus(CheckStatus.WeiKanLiao)
                        // 开始清运
                        .setCargoPhoto(orderInfoEntity.getCargoPhoto())
                        .setOrderStatus(OrderStatus.QingYunZhong)
                        .setTransTime(orderInfoEntity.getTransTime())
                );
            } else {
                baseMapper.busyDriver(orderInfoEntity.getDriverId(), Boolean.FALSE);
                baseMapper.busyTruck(orderInfoEntity.getTruckId(), Boolean.FALSE);
            }

            // 计算本单净重（或结算重量），作为结算时的数量依据

            OrderInfoEntity orderInfoEntity_ = orderInfoEntity;
            CompletableFuture.runAsync(() -> {
                BizTruckEntity truckInfo = baseMapper.getTruckInfo(truckId);
                String licensePlate = truckInfo.getLicensePlate();
                Websocket.publish(new WsMsg().setEvent("down/order/status_change")
                        .setData(MapUtil.builder()
                                .put("sn", orderInfoEntity_.getSn())
                                .put("licensePlate", licensePlate)
                                .put("orderStatus", newOrderStatus)
                                .build()));
            }).exceptionally(e -> {
                log.error("订单状态改变事件发布失败，订单{}，状态{}", orderInfoEntity_.getSn(), newOrderStatus, e);
                return null;
            });

            // 出厂付费
            if (OrderCategory.PuTong.equals(orderInfoEntity.getOrderCategory()) && MoneyWay.OUT.getVal().equals(entity.getMoneyWay())) {
                // 计算费用，出厂付费可能需要称重，需要更新付费项
                // updateOrderItems(orderInfoEntity.getId(), settleWeight, Boolean.FALSE);

                // 扣费
                result = handleCompanyPay(orderInfoEntity, Boolean.FALSE, new BigDecimal("0"), Boolean.FALSE);
            } else if (OrderCategory.DuanBoRu.equals(orderInfoEntity.getOrderCategory())) {
                // 扣费
                result = handleCompanyPay(orderInfoEntity, Boolean.FALSE, new BigDecimal("0"), Boolean.FALSE);
            }
            OrderPagingResult detail = this.detail(orderId);
            pushData(detail);
        } finally {
            if (orderInfoEntity.getOrderCategory() != OrderCategory.DuanBoChu) {
                // 关闭 GPS
                BizTruckEntity truckInfo = baseMapper.getTruckInfo(truckId);
                String gpsId = truckInfo.getGps();
                stopTrack(gpsId);
            }

        }
        return result;
    }

    public void pushData(OrderPagingResult detail) {
        Long orderId = detail.getId();
        List<String> routes = baseMapper.getRoute(orderId);
        detail.setRoute(routes);
        CompletableFuture.runAsync(() -> {
            HsoaResult<?> result = hsoaService.pushProvincialSave(detail);
            HsoaRecode hsoaRecode = new HsoaRecode()
                    .setOrderId(orderId)
                    .setOrderSn(detail.getSn())
                    .setLicensePlate(detail.getLicensePlate())
                    .setPushType(PushType.LianDan);
            if (result == null || !result.isSuccess()) {
                Hsoa.relogin();
                log.error("推送订单数据失败，数据Id：{}", orderId);
                hsoaService.save(hsoaRecode.setSuccess(Boolean.FALSE));
            } else {
                hsoaService.save(hsoaRecode.setSuccess(Boolean.TRUE));
            }
        }).exceptionally(e -> {
            log.error("推送订单数据失败，数据Id：{}", orderId, e);
            return null;
        });
    }

    /**
     * 计算付费项的总金额
     * 根据计费类型（弹性计费/固定计费）选择不同的计算策略
     *
     * @param item 付费项实体
     * @return 总金额
     */
    private BigDecimal calculateItemTotalMoney(OrderExpenseItemsEntity item) {
        // 判断是否为清运服务费的弹性计费
        if ((ExpenseItemCategory.QingYunFuWuFei.getVal().equals(item.getExpenseItemCategory())
                || ExpenseItemCategory.ZhongZhuanYunYingFei.getVal().equals(item.getExpenseItemCategory()))
                && MoneyStrategy.Dun.getVal().equals(item.getMoneyStrategy())
                && BillingType.ELASTICITY.getVal().equals(item.getBillingType())) {
            // 弹性计费逻辑
            // 1. 将数量（公斤）转换为吨
            BigDecimal actualWeight = new BigDecimal(item.getQuantity() == null ? 0 : item.getQuantity())
                    .divide(new BigDecimal("1000"), 6, BigDecimal.ROUND_HALF_UP);

            // 2. 获取弹性计费参数
            BigDecimal basicWeight = item.getBasicWeight();
            BigDecimal basicPrice = item.getBasicPrice();
            BigDecimal everyWeight = item.getEveryWeight();
            BigDecimal everyPrice = item.getEveryPrice();

            // 3. 计算总金额
            if (actualWeight.compareTo(basicWeight) <= 0) {
                // 实际重量小于等于基础磅重，使用基础价格
                return basicPrice;
            } else {
                // 实际重量大于基础磅重，计算超出部分的档次
                BigDecimal exceedWeight = actualWeight.subtract(basicWeight);
                // 计算需要多少档（向上取整）
                int tiers = exceedWeight.divide(everyWeight, 0, BigDecimal.ROUND_UP).intValue();
                // 总金额 = 基础价格 + 档次 * 每档单价
                return basicPrice.add(everyPrice.multiply(new BigDecimal(tiers)));
            }
        } else {
            // 固定计费逻辑: total_money = quantity * unit_price
            BigDecimal quantity = new BigDecimal(item.getQuantity() == null ? 0 : item.getQuantity());
            // 如果计费策略是按吨，数量需要除以1000
            if (MoneyStrategy.Dun.getVal().equals(item.getMoneyStrategy())) {
                quantity = quantity.divide(new BigDecimal("1000"), 6, BigDecimal.ROUND_HALF_UP);
            }
            return item.getUnitPrice().multiply(quantity);
        }
    }

    /**
     * 计算付费项的优惠金额
     *
     * @param companyId 清运公司id
     * @param item      付费项实体
     * @return 总金额
     */
    private BigDecimal calculateItemDiscountMoney(Long companyId, OrderExpenseItemsEntity item) {
        BigDecimal discountMoney = new BigDecimal("0");
        Long goodsId = null;
        Long itemId = null;
        if (ExpenseItemCategory.ChanPin.getVal().equals(item.getExpenseItemCategory())) {
            OrderGoodsEntity entity = orderGoodsService.getById(item.getOriginExpenseItemId());
            if (null == entity) {
                return discountMoney;
            }
            goodsId = entity.getOriginGoodsId();
        } else if (ExpenseItemCategory.QingYunFuWuFei.getVal().equals(item.getExpenseItemCategory())
                || ExpenseItemCategory.ZhongZhuanYunYingFei.getVal().equals(item.getExpenseItemCategory())) {
            itemId = item.getOriginExpenseItemId();
        }
        List<DiscountManageEntity> discountList = discountManageService.list(Wrappers.lambdaQuery(DiscountManageEntity.class)
                .eq(DiscountManageEntity::getCompanyId, companyId)
                .in(null != goodsId, DiscountManageEntity::getGoodsIds, goodsId)
                .eq(null != itemId, DiscountManageEntity::getExpenseId, itemId)
                .eq(DiscountManageEntity::getDeleted, Boolean.FALSE));
        if (null != discountList && discountList.size() > 0) {
            for (DiscountManageEntity discount : discountList) {
                if (DiscountType.DISCOUNT.getVal().equals(discount.getType())) {
                    discountMoney = discountMoney.subtract(discount.getMoney());
                } else if (DiscountType.RAISE.getVal().equals(discount.getType())) {
                    discountMoney = discountMoney.add(discount.getMoney());
                }
            }
        }
        return discountMoney;
    }

    /**
     * 计算并设置付费项的金额（总金额、结算金额）
     *
     * @param item 付费项实体
     */
    private void calculateAndSetItemMoney(OrderExpenseItemsEntity item, Long companyId, Boolean isChange) {
        // 计算总金额
        BigDecimal totalMoney = calculateItemTotalMoney(item);

        // 计算优惠金额（有正负）
        BigDecimal discountMoney = calculateItemDiscountMoney(companyId, item);

        // settle_money = total_money + discount_money + revise_money（discount、revise 可为正负）
        BigDecimal discount = discountMoney == null ? BigDecimal.ZERO : discountMoney;
        BigDecimal revise = item.getReviseMoney() == null ? BigDecimal.ZERO : item.getReviseMoney();
        BigDecimal settle = totalMoney.add(discount).add(revise);
        if (isChange) {
            item.setTotalMoney(totalMoney).setSettleMoney(settle).setDiscountMoney(discount).setChangeMoney(settle);
        } else {
            item.setTotalMoney(totalMoney).setSettleMoney(settle).setDiscountMoney(discount);
        }
    }

    /**
     * 根据付费项列表更新订单汇总金额
     *
     * @param orderId 订单ID
     * @param items   付费项列表（已经计算好金额）
     */
    private void updateOrderTotalMoney(Long orderId, List<OrderExpenseItemsEntity> items, Boolean isChange, Boolean isAdd) {
        BigDecimal totalDiscountMoney = BigDecimal.ZERO;
        BigDecimal totalReviseMoney = BigDecimal.ZERO;
        BigDecimal totalSettleMoney = BigDecimal.ZERO;
        BigDecimal totalTotalMoney = BigDecimal.ZERO;
        BigDecimal totalChangeMoney = BigDecimal.ZERO;

        // 汇总各项金额
        for (OrderExpenseItemsEntity item : items) {
            BigDecimal discount = item.getDiscountMoney() == null ? BigDecimal.ZERO : item.getDiscountMoney();
            BigDecimal revise = item.getReviseMoney() == null ? BigDecimal.ZERO : item.getReviseMoney();
            BigDecimal change = item.getChangeMoney() == null ? BigDecimal.ZERO : item.getChangeMoney();
            totalDiscountMoney = totalDiscountMoney.add(discount);
            totalReviseMoney = totalReviseMoney.add(revise);
            totalSettleMoney = totalSettleMoney.add(item.getSettleMoney());
            totalTotalMoney = totalTotalMoney.add(item.getTotalMoney());
            totalChangeMoney = totalChangeMoney.add(change);
        }

        OrderInfoEntity orderInfoEntity = new OrderInfoEntity();
        orderInfoEntity.setId(orderId);
        // 更新订单表的优惠金额; 手动修正金额;结算金额;总金额;
        if (isChange) {
            orderInfoEntity.setChangeMoney(totalChangeMoney);
        } else {
            orderInfoEntity.setDiscountMoney(totalDiscountMoney);
            orderInfoEntity.setReviseMoney(totalReviseMoney);
            orderInfoEntity.setSettleMoney(totalSettleMoney);
            orderInfoEntity.setTotalMoney(totalTotalMoney);
            if (!isAdd) {
                orderInfoEntity.setPaymentStatus(PaymentStatus.WeiZhiFu);
            }
        }
        this.updateById(orderInfoEntity);
    }

    /**
     * 计算付费项列表的金额并更新订单汇总金额
     *
     * @param orderId 订单ID
     * @param items   付费项列表
     */
    private void calculateItemsAndUpdateOrder(Long orderId, Long companyId, List<OrderExpenseItemsEntity> items) {
        // 计算各付费项金额
        for (OrderExpenseItemsEntity item : items) {
            calculateAndSetItemMoney(item, companyId, Boolean.FALSE);
        }

        // 批量更新付费项（包含quantity和所有金额字段）
        orderExpenseItemsService.updateBatchById(items);

        // 更新订单汇总金额
        updateOrderTotalMoney(orderId, items, Boolean.FALSE, Boolean.TRUE);
    }

    public void updateOrderItems(Long orderId, Long companyId, Integer settleWeight, Boolean isChange) {
        List<OrderExpenseItemsEntity> extraItems = orderExpenseItemsService.list(Wrappers.lambdaQuery(OrderExpenseItemsEntity.class)
                .eq(OrderExpenseItemsEntity::getOrderId, orderId)
                .eq(OrderExpenseItemsEntity::getDeleted, Boolean.FALSE));

        // 更新数量：按车计费数量=1，否则=称重数量
        for (OrderExpenseItemsEntity item : extraItems) {
            item.setQuantity(MoneyStrategy.Che.getVal().equals(item.getMoneyStrategy()) ? 1 : settleWeight);
            // 重新计算金额（totalMoney、settleMoney）
            calculateAndSetItemMoney(item, companyId, isChange);
        }

        // 批量更新付费项（包含quantity和所有金额字段）
        orderExpenseItemsService.updateBatchById(extraItems);

        // 汇总并更新订单总金额
        updateOrderTotalMoney(orderId, extraItems, isChange, Boolean.FALSE);
    }

    /**
     * 清运公司结算
     * 1. 将订单产品复制为一条付费项（ExpenseItemCategory=ChanPin）
     * 2. 查询并按 scope 过滤付费项配置（all / customer_type=QiYe|GeTi / customer 包含 trans_company_id）
     * 3. 合并集合，计算金额（total_money=quantity*unit_price，settle_money=total_money+discount_money+revise_money），批量入库
     */
    @Transactional(rollbackFor = Exception.class)
    public void settleForTransCompany(OrderInfoEntity orderInfoEntity, OrderGoodsEntity orderGoods) {
        Long orderId = orderInfoEntity.getId();

        // 第一步：复制产品信息为付费项记录
        BigDecimal unitPrice = orderGoods.getUnitPrice();
        OrderExpenseItemsEntity productItem = new OrderExpenseItemsEntity()
                .setExpenseItemCategory(ExpenseItemCategory.ChanPin.getVal())
                .setOrderId(orderId)
                .setOriginExpenseItemId(orderGoods.getId())
                .setExpenseItemName(orderGoods.getGoodsName())
                .setUnitPrice(unitPrice)
                .setUnit(orderGoods.getUnit())
                .setMoneyStrategy(orderGoods.getMoneyStrategy() == null ? null : orderGoods.getMoneyStrategy().getVal())
                .setMoneyConfigId(orderGoods.getMoneyConfigId())
                .setTaxRate(orderGoods.getTaxRate())
                .setQuantity((orderGoods.getMoneyStrategy() == MoneyStrategy.Che) ? 1 : 0);


        // 第二步：读取启用的付费项配置，并按 scope 过滤
        List<ExpenseItemsConfigEntity> configs = expenseItemsConfigService.list(Wrappers.<ExpenseItemsConfigEntity>lambdaQuery()
                .eq(ExpenseItemsConfigEntity::getCanuse, Boolean.TRUE)
                .eq(ExpenseItemsConfigEntity::getDeleted, Boolean.FALSE));

        Long transCompanyId = orderInfoEntity.getTransCompanyId();
        Long goodsId = orderGoods.getOriginGoodsId();
        Long stationId = orderInfoEntity.getStationId();
        List<OrderExpenseItemsEntity> extraItems = configs.stream()
                .filter(cfg -> {
                    Scope scope = cfg.getScope();
                    GoodsScope goodsScope = cfg.getGoodsScope();
                    StationsScope stationsScope = cfg.getStationScope();
                    List<String> companyIds = cfg.getCompanyIds();
                    List<String> goodsIds = cfg.getGoodsIds();
                    List<String> stationsIds = cfg.getStationIds();

                    // 判断客户范围
                    boolean isComTrue;
                    if (scope == Scope.ALL) {
                        isComTrue = true; // 所有客户都匹配
                    } else {
                        isComTrue = companyIds != null && transCompanyId != null && companyIds.contains(String.valueOf(transCompanyId));
                    }

                    // 判断产品范围
                    boolean isGoodsTrue;
                    if (goodsScope == GoodsScope.ALL) {
                        isGoodsTrue = true; // 所有产品都匹配
                    } else {
                        isGoodsTrue = goodsIds != null && goodsId != null && goodsIds.contains(String.valueOf(goodsId));
                    }

                    // 判断站点范围
                    boolean isStationsTrue;
                    if (stationsScope == StationsScope.ALL) {
                        isStationsTrue = true; // 所有站点都匹配
                    } else {
                        isStationsTrue = stationsIds != null && stationId != null && stationsIds.contains(String.valueOf(stationId));
                    }

                    // 只有当三个条件都为true时，才返回true
                    return isComTrue && isGoodsTrue && isStationsTrue;
                })
                // 复制配置为订单付费项（数量口径与产品一致：按车=1，否则=settleWeight）
                .map(cfg -> new OrderExpenseItemsEntity()
                        .setExpenseItemCategory(cfg.getExpenseItemCategory())
                        .setOrderId(orderId)
                        .setOriginExpenseItemId(cfg.getId())
                        .setExpenseItemName(cfg.getExpenseItemName())
                        .setUnitPrice(cfg.getUnitPrice())
                        .setUnit(cfg.getUnit())
                        .setMoneyStrategy(cfg.getMoneyStrategy())
                        .setMoneyConfigId(cfg.getMoneyConfigId())
                        .setScope(cfg.getScope())
                        .setBizObj(cfg.getBizObj())
                        .setCompanyIds(cfg.getCompanyIds())
                        .setGoodsScope(cfg.getGoodsScope())
                        .setGoodsIds(cfg.getGoodsIds())
                        .setBillingType(cfg.getBillingType())
                        .setBasicWeight(cfg.getBasicWeight())
                        .setBasicPrice(cfg.getBasicPrice())
                        .setEveryWeight(cfg.getEveryWeight())
                        .setEveryPrice(cfg.getEveryPrice())
                        .setTaxRate(cfg.getTaxRate())
                        .setQuantity(MoneyStrategy.Che.getVal().equals(cfg.getMoneyStrategy()) ? 1 : 0))
                .collect(Collectors.toList());

        // 第三步：合并集合并计算金额，然后批量落库
        if (productItem != null) extraItems.add(0, productItem);
        if (extraItems.isEmpty()) {
            return;
        }

        // 批量保存付费项
        orderExpenseItemsService.saveBatch(extraItems);

        // 计算付费项金额并更新订单汇总
        calculateItemsAndUpdateOrder(orderId, transCompanyId, extraItems);
    }

    public OrderPagingResult pendingOrder(String licensePlate) {
        return baseMapper.pendingOrder(Wrappers.query()
                .eq("e.license_plate", licensePlate)
                .in("a.order_status", Arrays.asList(OrderStatus.QingYunZhong, OrderStatus.YiJinChang))
                .orderByDesc("a.trans_time")
        );
    }

    public PageResult<OrderPagingResult> dispatchPaging(PageParam pageParam, OrderPagingSearchParam orderPagingSearchParam) {
        AuditStatus auditStatus = orderPagingSearchParam.getAuditStatus();
/*         String orderStatus = orderPagingSearchParam.getOrderStatus();
        List<String> orderStatusList = null;
        if (StrUtil.isNotBlank(orderStatus)) {
            orderStatusList = Arrays.stream(orderStatus.split(",")).collect(Collectors.toList());
        } */
        CheckStatus checkStatus = orderPagingSearchParam.getCheckStatus();
        String sn = orderPagingSearchParam.getSn();
        String licensePlate = orderPagingSearchParam.getLicensePlate();
        String nickname = orderPagingSearchParam.getNickname();
        String phone = orderPagingSearchParam.getPhone();
        LocalDateTime startTime = orderPagingSearchParam.getStartTime();
        LocalDateTime endTime = orderPagingSearchParam.getEndTime();
        Page<OrderPagingResult> page = pageParam.toPage();
        page.addOrder(OrderItem.desc("a.create_time"));
        Long stationId = orderPagingSearchParam.getStationId();
        QueryWrapper<OrderPagingResult> ew = Wrappers.<OrderPagingResult>query()
                .eq(stationId != null, " a.station_id", stationId)
                .like(StrUtil.isNotBlank(sn), "a.sn", sn)
                .like(StrUtil.isNotBlank(licensePlate), "a.license_plate", licensePlate)
                .like(StrUtil.isNotBlank(nickname), "h.nickname", nickname)
                .like(StrUtil.isNotBlank(phone), "h.phone", phone)
                .eq(auditStatus != null, "a.audit_status", auditStatus)
                // .in(CollUtil.isNotEmpty(orderStatusList), "a.order_status", orderStatusList)
                .eq(checkStatus != null, "a.check_status", checkStatus)
                .ge(startTime != null, "a.create_time", startTime)
                .le(endTime != null, "a.create_time", endTime);
        MyResult userDetail = SecurityUtil.loginUser();
        BizObj bizObj = userDetail.getBizObj();
        if (bizObj != null) {
            if (bizObj.isTrans()) {
                ew.eq("a.order_status", OrderStatus.DaiPaiDan)
                        .isNotNull("a.trans_company_id");
            } else if (bizObj.isWaste()) {
                ew.eq("a.order_status", OrderStatus.DaiPaiDan)
                        .isNull("a.user_id");
            } else {
                ew.isNull("a.trans_company_id");
            }
        } else {
            ew.isNull("a.trans_company_id");
        }
        return PageResult.of(baseMapper.paging(page, ew));
    }

    public OrderCertificateResult certificate(OrderCertificateParam orderCertificateParam) {
        Integer width = orderCertificateParam.getWidth();
        Integer height = orderCertificateParam.getHeight();
        if (width == null) {
            width = 300;
        }
        if (height == null) {
            height = 300;
        }
        String imgType = orderCertificateParam.getImgType();
        if (imgType == null) {
            imgType = ImgUtil.IMAGE_TYPE_JPG;
        }

        String qrcode = QrCodeUtil.generateAsBase64(orderCertificateParam.getLink() + "?orderId=" + orderCertificateParam.getOrderId(), new QrConfig(width, height), imgType);

        return new OrderCertificateResult()
                .setOrderDetail(this.detail(orderCertificateParam.getOrderId()))
                .setCertificateQrcode(qrcode);
    }

    public OrderPagingResult obtainWeighBill(Long orderId) {
        OrderPagingResult result = baseMapper.obtainWeighBill(orderId);
        BizAuditConfigEntity bizAuditConfigEntity = bizAuditConfigService.getOne(Wrappers.lambdaQuery(BizAuditConfigEntity.class)
                .eq(BizAuditConfigEntity::getArea, result.getArea()));
        if (null != bizAuditConfigEntity && !Strings.isNullOrEmpty(bizAuditConfigEntity.getAreaRole())) {
            RoleEntity roleEntity = roleService.getOne(Wrappers.lambdaQuery(RoleEntity.class).eq(
                    RoleEntity::getRoleCode, bizAuditConfigEntity.getAreaRole()));
            if (null != roleEntity && null != roleEntity.getId()) {
                result.setRoleName(roleEntity.getRoleName());
            }
        }
        if (!Strings.isNullOrEmpty(result.getGps())) {
            List<DeviceLocalizerEntity> list = deviceLocalizerService.list(Wrappers.lambdaQuery(DeviceLocalizerEntity.class).
                    eq(DeviceLocalizerEntity::getTerminalId, result.getGps())
                    .eq(DeviceLocalizerEntity::getDeleted, Boolean.FALSE));
            if (null != list && !list.isEmpty()) {
                result.setLocalizerCategory(list.get(0).getLocalizerCategory().getVal());
            }
        }

        return result;
    }

    public TrainBillResult trainBill(Long orderId) {
        OrderPagingResult orderDetail = detail(orderId);
        return BeanUtil.copyProperties(orderDetail, TrainBillResult.class);
    }

    @Transactional(rollbackFor = Exception.class)
    public void batchAdd(AddOrderInfoParam addOrderInfoParam) {
        Integer truckCount = addOrderInfoParam.getTruckCount();
        String orderSn = null;
        if (truckCount > 1) {
            orderSn = SnUtil.next();
        }
        for (int i = 0; i < truckCount; i++) {
            add(addOrderInfoParam, orderSn == null ? null : (orderSn + "-" + (i + 1)));
        }
    }

    public void export(HttpServletResponse response, OrderPagingSearchParam searchParam) throws IOException {
        LocalDateTime startTime = searchParam.getStartTime();
        LocalDateTime endTime = searchParam.getEndTime();
        String transCompanyName = searchParam.getTransCompanyName();
        String driverName = searchParam.getDriverName();
        OrderCategory orderCategory = searchParam.getOrderCategory();
        String area = searchParam.getArea();
        Long goodsId = searchParam.getGoodsId();
        String sn = searchParam.getSn();
        // 客户名称
        String nickname = searchParam.getNickname();
        // 产废单位
        String companyName = searchParam.getCompanyName();
        String licensePlate = searchParam.getLicensePlate();
        LocalDateTime startOutTime = searchParam.getStartOutTime();
        LocalDateTime endOutTime = searchParam.getEndOutTime();
        QueryWrapper<OrderPagingResult> ew = Wrappers.<OrderPagingResult>query()
                .eq(null != searchParam.getStationId() && searchParam.getStationId() > 0, "a.station_id", searchParam.getStationId())
                .like(StrUtil.isNotBlank(searchParam.getSn()), "a.sn", searchParam.getSn())
                .like(StrUtil.isNotBlank(searchParam.getLicensePlate()), "d.license_plate", searchParam.getLicensePlate())
                .like(StrUtil.isNotBlank(searchParam.getPhone()), "a.phone", searchParam.getPhone())
                .like(StrUtil.isNotBlank(searchParam.getNickname()), "a.contacts", searchParam.getNickname())
                .like(StrUtil.isNotBlank(transCompanyName), "g.company_name", transCompanyName)
                .like(StrUtil.isNotBlank(driverName), "f.driver_name", driverName)
                .ge(startTime != null, "a.create_time", startTime)
                .le(endTime != null, "a.create_time", endTime)
                .eq(orderCategory != null, "a.order_category", orderCategory)
                .eq(null != searchParam.getTransCompanyId(), "a.trans_company_id", searchParam.getTransCompanyId())
                .eq("a.deleted", 0)
                .eq(StrUtil.isNotBlank(area), "h.area", area)
                .eq(goodsId != null, "og.origin_goods_id", goodsId)
                .like(StrUtil.isNotBlank(sn), "a.sn", sn)
                .like(StrUtil.isNotBlank(nickname), "a.contacts", nickname)
                .like(StrUtil.isNotBlank(companyName), "j.company_name", companyName)
                .like(StrUtil.isNotBlank(transCompanyName), "g.company_name", transCompanyName)
                .like(StrUtil.isNotBlank(licensePlate), "d.license_plate", licensePlate)
                .ge(startOutTime != null, "ocio.out_time", startOutTime)
                .le(endOutTime != null, "ocio.out_time", endOutTime);
        historyEW(searchParam, null, ew);
        List<OrderExportResult> list = baseMapper.exportList(ew);
        List<OrderExportDetailResult> detailResults = baseMapper.exportDetailList(Wrappers.<OrderPagingResult>query()
                .in("oei.order_id", list.stream().map(OrderExportResult::getId).collect(Collectors.toList()))
        );
        List<Map<String, Object>> downList = new ArrayList<>();
        List<DictItemEntity> dictItems = dictItemService.list(Wrappers.<DictItemEntity>lambdaQuery()
                .eq(DictItemEntity::getDictKey, "expense_item_category")
                .eq(DictItemEntity::getDeleted, Boolean.FALSE)
                .orderByAsc(DictItemEntity::getSort));
        int i = 1;
        for (OrderExportResult result : list) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("序号", i);
            map.put("订单号", result.getSn());
            map.put("日期", result.getTransTime());
            map.put("中转站", result.getStationName());
            map.put("运输公司", result.getTransCompanyName());
            map.put("车牌号", result.getLicensePlate());
            map.put("车辆类型", result.getTruckCategory());
            map.put("方量（方）", result.getEstimatedQuantity());
            map.put("进场时间", result.getInTime());
            map.put("产废单位", result.getCfCompanyName());
            map.put("所属区域", result.getAreaName());
            map.put("产废地址", result.getTownName() + result.getAddress());
            map.put("入场磅重（吨）", result.getRoughWeight());
            map.put("皮重（吨）", result.getTareWeight());
            map.put("净重（吨）", result.getSettleWeight());
            map.put("驾驶员", result.getDriverName());
            map.put("产品", result.getGoodsName());
            List<OrderExportDetailResult> details = detailResults.stream()
                    .filter(t -> t.getOrderId().equals(result.getId()))
                    .collect(Collectors.toList());
            // 根据dictItems动态添加费用列
            if (null != dictItems && !dictItems.isEmpty()) {
                for (DictItemEntity dictItem : dictItems) {
                    String headerName = "ChanPin".equals(dictItem.getVal()) ? "处置费" : dictItem.getTxt();
                    BigDecimal amount = BigDecimal.ZERO;

                    if (!details.isEmpty()) {
                        Optional<OrderExportDetailResult> matchedDetail = details.stream()
                                .filter(detail -> dictItem.getVal().equals(detail.getExpenseItemCategory()))
                                .findFirst();
                        if (matchedDetail.isPresent()) {
                            amount = matchedDetail.get().getSettleMoney();
                        }
                    }

                    map.put(headerName, amount);
                }
            }

            map.put("备注", result.getCheckerMemo());
            downList.add(map);
            i++;
        }
        FileUtil.downloadExcel(downList, response, "收运统计表.xlsx");
    }

    private void startTrack(String gpsId, String licensePlate, Long orderInfoId, Long truckId) {
        if (StrUtil.isBlank(gpsId)) return;
        OrderPagingResult orderDetail = detail(orderInfoId);

        CompletableFuture.runAsync(() -> {
            Mqtt.subscribe(gpsId + "/track_location", (msg) -> {
                RealtimeLocationResult realtimeLocationResult = msg.getMsg(RealtimeLocationResult.class);
                if (realtimeLocationResult == null) {
                    return;
                }
                double speed = realtimeLocationResult.getSpeed();
                if (realtimeLocationResult.isOverspeed()) {
                    bizWarnService.save(new BizWarnEntity()
                            .setWarnCategory(WarnCategory.SPEED.getVal())
                            .setWarnContent(StrUtil.format("{} 已超速，当前时速 {}km/h", licensePlate, speed))
                            .setOrderId(orderInfoId)
                    );
                }
                // log.info("mqtt 收到消息：{} {}", gpsId + "/track_location", realtimeLocationResult);
                String time = realtimeLocationResult.getTime();
                double latitude = realtimeLocationResult.getLatitude();
                double longitude = realtimeLocationResult.getLongitude();

                if (latitude <= 0 && longitude <= 0) {
                    return;
                }

                int direction = realtimeLocationResult.getDirection();
                TruckLocationTrackEntity entity = new TruckLocationTrackEntity()
                        .setOrderId(orderInfoId)
                        .setTruckId(truckId)
                        .setTerminalId(gpsId)
                        .setLatitude(latitude)
                        .setLongitude(longitude)
                        .setAltitude(realtimeLocationResult.getAltitude())
                        .setSpeed(speed)
                        .setLocationTime(DateUtil.parseLocalDateTime(time))
                        .setDirection(direction)
                        .setOverspeed(realtimeLocationResult.isOverspeed())
                        .setCompensate(realtimeLocationResult.getType() == 1);
                truckLocationTrackService.save(entity);
                try {
                    String transCompanyName = orderDetail.getTransCompanyName();
                    PushVehicleTrajectoryParam param = new PushVehicleTrajectoryParam()
                            .setCompanyName(transCompanyName)
                            .setTransportLicense(orderDetail.getCertificateSn())
                            .setPlateNumber(licensePlate)
                            .setVehicleType(orderDetail.getTruckCategory())
                            .setLongitude(longitude + "")
                            .setLatitude(latitude + "")
                            .setSpeed(speed)
                            .setDirection(direction + 0.0)
                            .setStateType("正常行驶")
                            .setAlarmType("无")
                            .setLoadStatus("2")
                            .setSealedStatus("1")
                            .setLiftStatus("0")
                            .setAccStatus(1)
                            .setGpsTime(time)
                            .setLocationMode("WGS84");

                    HsoaRecode hsoaRecode = new HsoaRecode()
                            .setOrderId(orderInfoId)
                            .setOrderSn(orderDetail.getSn())
                            .setLicensePlate(licensePlate)
                            .setPushType(PushType.GuiJi);
                    HsoaResult<?> result = Hsoa.pushVehicleTrajectory(param);
                    if (result == null || !result.isSuccess()) {
                        Hsoa.relogin();
                        log.error("推送定位数据失败，数据Id：{}", entity.getId());
                        hsoaService.save(hsoaRecode.setSuccess(Boolean.FALSE));
                    } else {
                        hsoaService.save(hsoaRecode.setSuccess(Boolean.TRUE));
                    }
                } catch (Exception e) {
                    log.error("推送定位数据失败，数据Id：{}", entity.getId(), e);
                }
            });
            /* Mqtt.publish("location/track", MapUtil.builder()
                    .put("terminalId", gpsId)
                    .put("interval", 1)
                    .build()); */
        }).whenComplete((aVoid, throwable) -> {
            if (throwable != null) {
                log.error("开启GPS失败", throwable);
            }
        });
    }

    private void stopTrack(String gpsId) {
        CompletableFuture.runAsync(() -> {
            Assert.notEmpty(gpsId, () -> Exceptions.clierr("车辆未绑定GPS"));
            /* Mqtt.publish("location/track", MapUtil.builder()
                    .put("terminalId", gpsId)
                    .put("interval", 0)
                    .build()); */
            Mqtt.unsubscribe(gpsId + "/track_location");
        }).whenComplete((aVoid, throwable) -> {
            if (throwable != null) {
                log.error("关闭GPS失败", throwable);
            }
        });
    }

    public void gpsTest(String sn, int count) {
        if (count <= 0) {
            if (test_thread != null) {
                test_thread_running.set(false);
            }
            return;
        }
        Assert.isTrue(count <= 1000, () -> Exceptions.clierr("数量必须大于0且小于等于1000"));
        OrderInfoEntity orderInfo = this.getOne(Wrappers.lambdaQuery(OrderInfoEntity.class).eq(OrderInfoEntity::getSn, sn));
        Assert.notNull(orderInfo, () -> Exceptions.clierr("订单不存在"));
        Page<TruckLocationTrackEntity> page = truckLocationTrackService.page(new Page<>(1, count), Wrappers.lambdaQuery(TruckLocationTrackEntity.class)
                .eq(TruckLocationTrackEntity::getOrderId, 1982687926996865026L)
                .orderByAsc(TruckLocationTrackEntity::getLocationTime)
        );
        List<TruckLocationTrackEntity> records = page.getRecords();
        if (CollUtil.isEmpty(records)) {
            Assert.notNull(orderInfo, () -> Exceptions.clierr("无数据"));
        }

        test_thread = new Thread(() -> {
            for (TruckLocationTrackEntity record : records) {
                if (!test_thread_running.get()) {
                    break;
                }
                truckLocationTrackService.save(new TruckLocationTrackEntity()
                        .setOrderId(orderInfo.getId())
                        .setTruckId(record.getTruckId())
                        .setTerminalId(record.getTerminalId())
                        .setLatitude(record.getLatitude())
                        .setLongitude(record.getLongitude())
                        .setAltitude(record.getAltitude())
                        .setSpeed(record.getSpeed())
                        .setLocationTime(LocalDateTime.now())
                        .setDirection(record.getDirection())
                        .setOverspeed(record.getOverspeed())
                        .setCompensate(record.getCompensate()));
                ThreadUtil.sleep(1000);
            }
            log.info("{} 数据导入完成", orderInfo.getSn());
        });
        test_thread_running.set(true);
        test_thread.start();

    }

    /**
     * 改价 （只考虑进场时多退少补）
     * 进场付费多退少补，出厂只重新配置订单付费项，出厂时会重新计算费用
     */
    @Transactional(rollbackFor = Exception.class)
    public void changePrice(ChangePriceParam param) {
        OrderInfoEntity order = this.getById(param.getOrderId());
        Assert.notNull(order, () -> Exceptions.clierr("订单不存在"));
        Assert.isFalse(null == order.getGoodsId(), () -> Exceptions.clierr("订单商品信息不存在"));
        OrderGoodsEntity orderGoodsEntity = orderGoodsService.getById(order.getGoodsId());
        String oldMoneyWay = orderGoodsEntity.getMoneyWay();
        if (ChangePriceType.GOODS.getVal().equals(param.getChangePriceType())) {
            // 变更产品与单价，单价如果为空当0计算，依然不加入订单付费项
            Assert.isFalse(null == param.getGoodsId(), () -> Exceptions.clierr("产品ID不可为空"));
            // 删除原来的订单产品数据
            orderGoodsService.removeById(order.getGoodsId());
            // 添加新的订单产品
            Long orderGoodsId = orderGoodsService.add(param.getGoodsId(), param.getUnitPrice());
            // 更新订单表goodsId
            this.updateById(new OrderInfoEntity()
                    .setId(param.getOrderId())
                    .setGoodsId(orderGoodsId)
            );
            // 因更改产品可能影响到订单服务费的付费项，所以直接删除原有订单付费项，重新匹配
            orderExpenseItemsService.remove(Wrappers.<OrderExpenseItemsEntity>lambdaQuery()
                    .in(OrderExpenseItemsEntity::getOrderId, param.getOrderId()));
            // 新增订单付费项
            OrderGoodsEntity entity = orderGoodsService.getById(orderGoodsId);
            String newMoneyWay = entity.getMoneyWay();
            OrderExpenseItemsEntity productItem = new OrderExpenseItemsEntity()
                    .setExpenseItemCategory(ExpenseItemCategory.ChanPin.getVal())
                    .setOrderId(param.getOrderId())
                    .setOriginExpenseItemId(orderGoodsId)
                    .setExpenseItemName(entity.getGoodsName())
                    .setUnitPrice(param.getUnitPrice())
                    .setUnit(entity.getUnit())
                    .setMoneyStrategy(entity.getMoneyStrategy() == null ? null : entity.getMoneyStrategy().getVal())
                    .setMoneyConfigId(entity.getMoneyConfigId())
                    .setTaxRate(entity.getTaxRate())
                    .setQuantity((entity.getMoneyStrategy() == MoneyStrategy.Che) ? 1 : 0);
//            orderExpenseItemsService.save(productItem);

            // 第二步：读取启用的付费项配置，并按 scope 过滤
            List<ExpenseItemsConfigEntity> configs = expenseItemsConfigService.list(Wrappers.<ExpenseItemsConfigEntity>lambdaQuery()
                    .eq(ExpenseItemsConfigEntity::getCanuse, Boolean.TRUE)
                    .eq(ExpenseItemsConfigEntity::getDeleted, Boolean.FALSE));

            Long transCompanyId = order.getTransCompanyId();
            Long goodsId = entity.getOriginGoodsId();
            Long stationId = order.getStationId();
            List<OrderExpenseItemsEntity> extraItems = configs.stream()
                    .filter(cfg -> {
                        Scope scope = cfg.getScope();
                        GoodsScope goodsScope = cfg.getGoodsScope();
                        StationsScope stationsScope = cfg.getStationScope();
                        List<String> companyIds = cfg.getCompanyIds();
                        List<String> goodsIds = cfg.getGoodsIds();
                        List<String> stationsIds = cfg.getStationIds();

                        // 判断客户范围
                        boolean isComTrue;
                        if (scope == Scope.ALL) {
                            isComTrue = true; // 所有客户都匹配
                        } else {
                            isComTrue = companyIds != null && transCompanyId != null && companyIds.contains(String.valueOf(transCompanyId));
                        }

                        // 判断产品范围
                        boolean isGoodsTrue;
                        if (goodsScope == GoodsScope.ALL) {
                            isGoodsTrue = true; // 所有产品都匹配
                        } else {
                            isGoodsTrue = goodsIds != null && goodsId != null && goodsIds.contains(String.valueOf(goodsId));
                        }

                        // 判断站点范围
                        boolean isStationsTrue;
                        if (stationsScope == StationsScope.ALL) {
                            isStationsTrue = true; // 所有站点都匹配
                        } else {
                            isStationsTrue = stationsIds != null && stationId != null && stationsIds.contains(String.valueOf(stationId));
                        }

                        // 只有当三个条件都为true时，才返回true
                        return isComTrue && isGoodsTrue && isStationsTrue;
                    })
                    // 复制配置为订单付费项（数量口径与产品一致：按车=1，否则=settleWeight）
                    .map(cfg -> new OrderExpenseItemsEntity()
                            .setExpenseItemCategory(cfg.getExpenseItemCategory())
                            .setOrderId(param.getOrderId())
                            .setOriginExpenseItemId(cfg.getId())
                            .setExpenseItemName(cfg.getExpenseItemName())
                            .setUnitPrice(cfg.getUnitPrice())
                            .setUnit(cfg.getUnit())
                            .setMoneyStrategy(cfg.getMoneyStrategy())
                            .setMoneyConfigId(cfg.getMoneyConfigId())
                            .setScope(cfg.getScope())
                            .setBizObj(cfg.getBizObj())
                            .setCompanyIds(cfg.getCompanyIds())
                            .setGoodsScope(cfg.getGoodsScope())
                            .setGoodsIds(cfg.getGoodsIds())
                            .setBillingType(cfg.getBillingType())
                            .setBasicWeight(cfg.getBasicWeight())
                            .setBasicPrice(cfg.getBasicPrice())
                            .setEveryWeight(cfg.getEveryWeight())
                            .setEveryPrice(cfg.getEveryPrice())
                            .setTaxRate(cfg.getTaxRate())
                            .setQuantity(MoneyStrategy.Che.getVal().equals(cfg.getMoneyStrategy()) ? 1 : 0))
                    .collect(Collectors.toList());

            // 第三步：合并集合并计算金额，然后批量落库
            if (productItem != null) extraItems.add(0, productItem);
            if (extraItems.isEmpty()) {
                return;
            }

            // 批量保存付费项
            orderExpenseItemsService.saveBatch(extraItems);
            // 退款
            if (MoneyWay.IN.getVal().equals(oldMoneyWay) && MoneyWay.OUT.getVal().equals(newMoneyWay)) {
                // 如果从进场付费改成了出厂付费，则全部退款，在出厂时会重新称重计算费用，否则重新计费，并多退少补
                if (PaymentStatus.YiZhiFu.getVal().equals(order.getPaymentStatus().getVal())) {
                    RefundRequestDto dto = new RefundRequestDto();
                    dto.setOrderId(order.getId());
                    dto.setRefundAmount(order.getSettleMoney());
                    dto.setOutTradeNo(order.getOutTradeNo());
                    dto.setReason("订单改价，进场->出厂");
                    // 获取支付上下文
                    PaymentContextResult ctx = this.paymentContext(order.getId());
                    paymentService.refund(dto, ctx, Boolean.TRUE);
                    this.lambdaUpdate()
                            .eq(OrderInfoEntity::getId, order.getId())
                            .set(OrderInfoEntity::getSettleMoney, new BigDecimal("0"))
                            .set(OrderInfoEntity::getTotalMoney, new BigDecimal("0"))
                            .set(OrderInfoEntity::getPaymentStatus, PaymentStatus.WeiZhiFu)
                            .update();
                }
            } else if (MoneyWay.IN.getVal().equals(oldMoneyWay) && MoneyWay.IN.getVal().equals(newMoneyWay)) {
                // 重新计算，多退少补
                reSettlement(order, oldMoneyWay);
            }
            // 更新产品不用考虑出厂问题，在称重时会重新计算费用并付费
        } else if (ChangePriceType.SERVICE_FEE_PRICE.getVal().equals(param.getChangePriceType())) {
            // 变更服务费单价
            if (null != param.getServiceFeeList() && param.getServiceFeeList().size() > 0) {
                List<OrderItemsParams> params = param.getServiceFeeList();
                for (OrderItemsParams itemsParam : params) {
                    OrderExpenseItemsEntity expenseItemsEntity = orderExpenseItemsService.getById(itemsParam.getId());
                    if (null == expenseItemsEntity) {
                        throw Exceptions.clierr("服务费不存在，请检查参数");
                    }
                    if (BillingType.ELASTICITY.getVal().equals(expenseItemsEntity.getBillingType())) {
                        throw Exceptions.clierr("弹性计费不可改价");
                    }
                    OrderExpenseItemsEntity itemsEntity = new OrderExpenseItemsEntity();
                    itemsEntity.setId(itemsParam.getId());
                    itemsEntity.setUnitPrice(itemsParam.getUnitPrice());
                    orderExpenseItemsService.updateById(itemsEntity);
                }
                // 重新计算，多退少补
                reSettlement(order, oldMoneyWay);
            } else {
                throw Exceptions.clierr("清运服务费不可为空");
            }
        } else if (ChangePriceType.WEIGHT.getVal().equals(param.getChangePriceType())) {
            // 变更磅重，勘料在出厂之前，出厂会重新称重，所以只需要改毛重，不需要更新净重，
            // 也不需要退款，按车不需要退款，按吨不可能在进场就付费
            Assert.isFalse(null == param.getRoughWeight(), () -> Exceptions.clierr("毛重不可为空"));
            OrderCarInOutEntity carInOutEntity = new OrderCarInOutEntity();
            carInOutEntity.setId(order.getCarInOutId());
            carInOutEntity.setRoughWeight(param.getRoughWeight());
            orderCarInOutService.updateById(carInOutEntity);
        }
    }

    /**
     * 重新计算，多退少补
     */
    public void reSettlement(OrderInfoEntity order, String oldMoneyWay) {
        // 旧的结算金额
        BigDecimal oldSettleMoney = order.getSettleMoney();
        // 计算费用
        updateOrderItems(order.getId(), order.getTransCompanyId(), 0, Boolean.TRUE);

        // 多退少补 获取改价后的订单信息
        OrderInfoEntity newOrder = this.getById(order.getId());
        // 新的结算金额
        BigDecimal newMoney = newOrder.getSettleMoney() == null ? BigDecimal.ZERO : newOrder.getSettleMoney();
        // 如果之前的计费方式就是入场付费，并且订单为已支付时，才需要多退少补；
        // 如果之前的计费方式就是出场付费，勘料时一定是未支付，所以不必走下面的多退少补流程
        if (MoneyWay.IN.getVal().equals(oldMoneyWay) && PaymentStatus.YiZhiFu.getVal().equals(order.getPaymentStatus().getVal())) {
            // 比较改价后金额和结算金额
            if (newMoney.compareTo(oldSettleMoney) > 0) {
                // 改价后金额大于结算金额，需要付款（多付）
                BigDecimal payAmount = newMoney.subtract(oldSettleMoney);
                // 处理公司支付
                handleCompanyPay(newOrder, Boolean.TRUE, payAmount, Boolean.TRUE);
                // TODO: 微信支付暂不处理
                // paymentService.pay(order, payAmount);
            } else if (newMoney.compareTo(oldSettleMoney) < 0) {
                // 改价后金额小于结算金额，需要退款（少补）
                BigDecimal refundAmount = oldSettleMoney.subtract(newMoney);
                // 调用退款接口
                RefundRequestDto dto = new RefundRequestDto();
                dto.setOrderId(order.getId());
                dto.setRefundAmount(refundAmount);
                dto.setOutTradeNo(order.getOutTradeNo());
                dto.setReason("订单改价，进场->进场，退差额");
                // 获取支付上下文
                PaymentContextResult ctx = this.paymentContext(order.getId());
                paymentService.refund(dto, ctx, Boolean.TRUE);
            }
            // 如果金额相等，则不需要处理
        }
    }

    public void forwarded(Long orderId, String area, String areaName) {
        OrderInfoEntity order = this.getById(orderId);
        Assert.notNull(order, () -> Exceptions.clierr("订单不存在"));
        if (null != order.getCargoPlaceId()) {
            OrderCargoPlaceEntity cargoPlaceEntity = orderCargoPlaceService.getById(order.getCargoPlaceId());
            if (null != cargoPlaceEntity) {
                OrderCargoPlaceEntity placeEntity = new OrderCargoPlaceEntity();
                placeEntity.setId(cargoPlaceEntity.getId());
                placeEntity.setArea(area);
                placeEntity.setAreaName(areaName);
                orderCargoPlaceService.updateById(placeEntity);
                BizAuditConfigEntity bizAuditConfigEntity = bizAuditConfigService.getOne(Wrappers.lambdaQuery(BizAuditConfigEntity.class)
                        .eq(BizAuditConfigEntity::getArea, area));
                try {
                    // 通知审核人
                    RoleEntity roleEntity = new RoleEntity();
                    if (null != bizAuditConfigEntity && !Strings.isNullOrEmpty(bizAuditConfigEntity.getAreaRole())) {
                        roleEntity = roleService.getOne(Wrappers.lambdaQuery(RoleEntity.class).eq(
                                RoleEntity::getRoleCode, bizAuditConfigEntity.getAreaRole()));
                    }
                    if (null != roleEntity && null != roleEntity.getId()) {
                        List<SysUserRoleEntity> userIds = userRoleService.list(Wrappers.lambdaQuery(SysUserRoleEntity.class)
                                .eq(SysUserRoleEntity::getRoleId, roleEntity.getId()));
                        TemplateMessageParam param = new TemplateMessageParam();
                        param.setTempType(TempType.AUDIT_PENDING.getVal());
                        param.setSn(order.getSn());
                        UserEntity orderUserEntity = userService.getById(order.getUserId());
                        param.setCfCompanyName(orderUserEntity.getNickname());
                        OrderGoodsEntity entity = orderGoodsService.getById(order.getGoodsId());
                        param.setGoodsName(entity.getGoodsName());
                        BizCompanyEntity companyEntity = bizCompanyService.getById(order.getTransCompanyId());
                        param.setCompanyName(companyEntity.getCompanyName());
                        param.setCreateTime(order.getCreateTime());
                        Set<String> openId = new HashSet<>();
                        for (SysUserRoleEntity userRoleEntity : userIds) {
                            UserEntity userEntity = userService.getById(userRoleEntity.getUserId());
                            if (null != userEntity && !Strings.isNullOrEmpty(userEntity.getOpenid())) {
                                if (openId.add(userEntity.getOpenid())) {
                                    param.setUserId(userRoleEntity.getUserId());
                                    log.info("转办发送审核通知模板消息，参数：{}", param);
                                    wechatTemplateMessageService.sendTemplateMessage(param);
                                }
                            } else {
                                log.info("转办未查到用户信息：{}", userRoleEntity.getUserId());
                            }
                        }
                    }
                } catch (Exception e) {
                    log.error("通知失败", e);
                }
            } else {
                throw Exceptions.clierr("未查询到装货地址");
            }
        } else {
            throw Exceptions.clierr("装货地址不存在");
        }
    }

    public List<Map<String, Object>> pushProvincial(List<String> orderSns) {
        List<Map<String, Object>> list = new ArrayList<>(orderSns.size());
        for (String orderSn : orderSns) {
            try {
                OrderInfoEntity orderInfo = this.getOne(Wrappers.<OrderInfoEntity>lambdaQuery().eq(OrderInfoEntity::getSn, orderSn));
                Long orderId = orderInfo.getId();
                OrderPagingResult detail = this.detail(orderId);
                List<String> routes = baseMapper.getRoute(orderId);
                detail.setRoute(routes);
                HsoaResult<?> hsoaResult = hsoaService.pushProvincialSave(detail);
                list.add(MapUtil.<String, Object>builder()
                        .put("result", hsoaResult)
                        .put("id", orderId)
                        .put("sn", orderSn)
                        .build());
            } catch (Exception e) {
                list.add(MapUtil.<String, Object>builder()
                        .put("result", "失败")
                        .put("sn", orderSn)
                        .build());
                log.error("单号：{}", orderSn, e);
            }
        }
        return list;
    }

    public Map<String, Object> statistics(OrderStatisticsParam param) {
        List<String> areaCode = param.getAreaCode();
        Long goodsId = param.getGoodsId();
        Integer year = param.getYear();
        Integer month = param.getMonth();
        LocalDateTime start = null;
        LocalDateTime end = null;
        if (year != null) {
            if (month == null) {
                start = LocalDateTime.of(year, 1, 1, 0, 0, 0);
                end = LocalDateTime.of(year, 12, 31, 23, 59, 59);
            } else {
                start = LocalDateTime.of(year, month, 1, 0, 0, 0);
                end = start.plusMonths(1).minusSeconds(1);
            }
        }

        List<Map<String, Object>> statisticsByArea = baseMapper.statisticsByArea(Wrappers.query()
                .in(CollUtil.isNotEmpty(areaCode), "b.area", areaCode)
                .eq("a.deleted", 0)
                .in("a.order_status", OrderStatus.YiWanCheng, OrderStatus.YiChuChang)
                .groupBy("b.area")
        );
        List<Map<String, Object>> statisticsByAreaGoods = baseMapper.statisticsByAreaGoods(Wrappers.query()
                .in(CollUtil.isNotEmpty(areaCode), "b.area", areaCode)
                .eq("a.deleted", 0)
                .between(start != null, "a.create_time", start, end)
                .eq(goodsId != null, "d.origin_goods_id", goodsId)
                .in("a.order_status", OrderStatus.YiWanCheng, OrderStatus.YiChuChang)
                .groupBy("b.area", "d.origin_goods_id")
        );
        return MapUtil.<String, Object>builder()
                .put("statisticsByArea", statisticsByArea)
                .put("statisticsByAreaGoods", statisticsByAreaGoods)
                .build();
    }

    public PageResult<OrderPagingResult> statisticsDetail(PageParam pageParam, OrderPagingSearchParam orderPagingSearchParam) {
        String area = orderPagingSearchParam.getArea();
        Long goodsId = orderPagingSearchParam.getGoodsId();
        String sn = orderPagingSearchParam.getSn();
        // 客户名称
        String nickname = orderPagingSearchParam.getNickname();
        // 产废单位
        String companyName = orderPagingSearchParam.getCompanyName();
        String transCompanyName = orderPagingSearchParam.getTransCompanyName();
        String licensePlate = orderPagingSearchParam.getLicensePlate();

        LocalDateTime startTime = orderPagingSearchParam.getStartTime();
        LocalDateTime endTime = orderPagingSearchParam.getEndTime();

        LocalDateTime startOutTime = orderPagingSearchParam.getStartOutTime();
        LocalDateTime endOutTime = orderPagingSearchParam.getEndOutTime();

        Page<OrderPagingResult> page = pageParam.toPage();

        QueryWrapper<OrderPagingResult> ew = Wrappers.<OrderPagingResult>query()
                .eq("a.deleted", 0)
                .eq("b.area", area)
                .eq("c.origin_goods_id", goodsId)
                .like(StrUtil.isNotBlank(sn), "a.sn", sn)
                .like(StrUtil.isNotBlank(nickname), "a.contacts", nickname)
                .like(StrUtil.isNotBlank(companyName), "j.company_name", companyName)
                .like(StrUtil.isNotBlank(transCompanyName), "g.company_name", transCompanyName)
                .like(StrUtil.isNotBlank(licensePlate), "e.license_plate", licensePlate)
                .ge(startTime != null, "a.create_time", startTime)
                .le(endTime != null, "a.create_time", endTime)
                .ge(startOutTime != null, "d.out_time", startOutTime)
                .le(endOutTime != null, "d.out_time", endOutTime)
                .eq("a.order_status", OrderStatus.YiWanCheng);
        return PageResult.of(baseMapper.paging(page, ew));
    }

    public List<Long> getStationIds() {
        MyResult userDetail = SecurityUtil.loginUser();
        List<StationManageEntity> stationManageEntityList = stationManageService.list(Wrappers.lambdaQuery(StationManageEntity.class)
                .eq(StationManageEntity::getUserId, userDetail.getUserId()));
        if (CollUtil.isEmpty(stationManageEntityList)) {
            throw Exceptions.clierr("当前用户不是站点管理员");
        }
        return stationManageEntityList.stream()
                .map(StationManageEntity::getStationId)
                .collect(Collectors.toList());
    }
}
