package com.njzscloud.supervisory.order.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
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.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.supervisory.biz.constant.AuditStatus;
import com.njzscloud.supervisory.biz.constant.BizObj;
import com.njzscloud.supervisory.biz.pojo.entity.BizAuditConfigEntity;
import com.njzscloud.supervisory.biz.pojo.entity.BizTruckEntity;
import com.njzscloud.supervisory.biz.pojo.entity.BizWarnEntity;
import com.njzscloud.supervisory.biz.pojo.entity.TruckLocationTrackEntity;
import com.njzscloud.supervisory.biz.service.BizAuditConfigService;
import com.njzscloud.supervisory.biz.service.BizWarnService;
import com.njzscloud.supervisory.biz.service.TruckLocationTrackService;
import com.njzscloud.supervisory.config.AppProperties;
import com.njzscloud.supervisory.constant.Constant;
import com.njzscloud.supervisory.expense.contant.ExpenseItemCategory;
import com.njzscloud.supervisory.expense.contant.Scope;
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.order.contant.CheckStatus;
import com.njzscloud.supervisory.order.contant.OrderCategory;
import com.njzscloud.supervisory.order.contant.OrderStatus;
import com.njzscloud.supervisory.order.contant.OrderViewType;
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.sys.auth.pojo.result.MyResult;
import com.njzscloud.supervisory.sys.stationletter.constant.WarnCategory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
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 AppProperties appProperties;

    private static void stopTuqiangTrack(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);
            }
        });
    }

    /**
     * 新增
     */
    @Transactional(rollbackFor = Exception.class)
    public void add(AddOrderInfoParam addOrderInfoParam) {
        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);

        OrderInfoEntity orderInfoEntity = BeanUtil.copyProperties(addOrderInfoParam, OrderInfoEntity.class)
                .setSn(SnUtil.next())
                .setCargoPlaceId(cargoPlaceId)
                .setUserId(userId)
                .setOrderStatus(orderStatus)
                .setGoodsId(orderGoodsId);
        this.save(orderInfoEntity);

        Long orderId = orderInfoEntity.getId();
        OrderCategory orderCategory = addOrderInfoParam.getOrderCategory();
        if (orderCategory == OrderCategory.DuanBoChu) {
            this.add(addOrderInfoParam.setOrderCategory(OrderCategory.DuanBoRu)
                    .setTargetOrderId(orderId)
                    .setTargetStationId(addOrderInfoParam.getStationId())
                    .setStationId(addOrderInfoParam.getTargetStationId())
            );

        } else if (orderCategory == OrderCategory.DuanBoRu) {
            this.updateById(new OrderInfoEntity().setId(addOrderInfoParam.getTargetOrderId())
                    .setTargetOrderId(orderId));
        }
    }

    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) {
        return baseMapper.detail(Wrappers.<OrderPagingResult>query()
                .in("a.id", id));
    }

    /**
     * 分页查询
     */
    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();
        Page<OrderPagingResult> page = pageParam.toPage();
        page.addOrder(OrderItem.desc("a.create_time"));
        QueryWrapper<OrderPagingResult> ew = Wrappers.<OrderPagingResult>query()
                .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)
                .ge(startTime != null, "a.create_time", startTime)
                .le(endTime != null, "a.create_time", endTime);
        OrderViewType type = orderPagingSearchParam.getType();
        Assert.notNull(type, () -> Exceptions.clierr("订单类型不能为空"));
        switch (type) {
            case DaiPaiDan:
                dispatchEW(orderPagingSearchParam, ew);
                break;
            case YuYue:
                bookingEW(orderPagingSearchParam, ew);
                break;
            case LiShi:
                historyEW(orderPagingSearchParam, ew);
                break;
            case QuXiao:
                cancelEW(orderPagingSearchParam, ew);
                break;
            case ShouGong:
                autoEW(orderPagingSearchParam, ew);
                break;
            case ShiShi:
                realtimeEW(orderPagingSearchParam, ew);
                break;
            case KanLiao:
                checkEW(orderPagingSearchParam, ew);
                break;
        }

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

    private void dispatchEW(OrderPagingSearchParam orderPagingSearchParam, QueryWrapper<OrderPagingResult> ew) {
        MyResult userDetail = SecurityUtil.loginUser();
        Long userId = SecurityUtil.currentUserId();
        BizObj bizObj = userDetail.getBizObj();
        if (BizObj.isTrans(bizObj)) {
            ew
                    .in("a.order_status", OrderStatus.DaiPaiDan, OrderStatus.DaiJieDan)
                    .eq("g.user_id", userId);
            return;
        }
        if (BizObj.isDriver(bizObj)) {
            ew
                    .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)) {
            Long stationId = orderPagingSearchParam.getStationId();
            Assert.notNull(stationId, () -> Exceptions.clierr("请选择站点"));
            ew
                    .eq("a.station_id", stationId)
                    .eq("a.order_status", OrderStatus.YiYuYue)
                    .isNull("a.trans_company_id ")
            ;
            return;
        }
    }

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

        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)) {
            Long stationId = orderPagingSearchParam.getStationId();
            Assert.notNull(stationId, () -> Exceptions.clierr("请选择站点"));
            ew
                    .eq("a.station_id", stationId)
                    .in("a.order_status", OrderStatus.DaiPaiDan, OrderStatus.DaiJieDan, OrderStatus.YiJieDan)
            ;
            return;
        }
    }

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

        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)) {
            Long stationId = orderPagingSearchParam.getStationId();
            Assert.notNull(stationId, () -> Exceptions.clierr("请选择站点"));
            ew
                    .eq("a.station_id", stationId)
                    .in("a.order_status", OrderStatus.QingYunZhong, OrderStatus.YiJinChang, OrderStatus.YiChuChang)
            ;
            return;
        }
    }

    private void historyEW(OrderPagingSearchParam orderPagingSearchParam, 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.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)) {
            Long stationId = orderPagingSearchParam.getStationId();
            Assert.notNull(stationId, () -> Exceptions.clierr("请选择站点"));
            ew
                    .eq("a.station_id", stationId)
                    .eq("a.order_status", OrderStatus.YiWanCheng)
            ;
            return;
        }
    }

    private void cancelEW(OrderPagingSearchParam orderPagingSearchParam, 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)) {
            Long stationId = orderPagingSearchParam.getStationId();
            Assert.notNull(stationId, () -> Exceptions.clierr("请选择站点"));
            ew
                    .eq("a.station_id", stationId)
                    .eq("a.order_status", OrderStatus.YiQuXiao)
            ;
            return;
        }
    }

    private void autoEW(OrderPagingSearchParam orderPagingSearchParam, QueryWrapper<OrderPagingResult> ew) {
        UserDetail userDetail = SecurityUtil.loginUser();
        Set<String> roles = userDetail.getRoles();
        if (SecurityUtil.isAdmin() || roles.contains(Constant.ROLE_STATION_MANAGE)) {
            Long stationId = orderPagingSearchParam.getStationId();
            Assert.notNull(stationId, () -> Exceptions.clierr("请选择站点"));
            ew
                    .eq("a.station_id", stationId)
                    .ne("a.auto_order", 3)
            ;
            return;
        }
    }

    private void checkEW(OrderPagingSearchParam orderPagingSearchParam, QueryWrapper<OrderPagingResult> ew) {
        MyResult userDetail = SecurityUtil.loginUser();
        BizObj bizObj = userDetail.getBizObj();
        if (BizObj.isSiBang(bizObj)) {
            CheckStatus checkStatus = orderPagingSearchParam.getCheckStatus();
            if (checkStatus == CheckStatus.YiKanLiao) {
                ew
                        .eq("a.check_status", checkStatus)
                        .in("a.order_status", OrderStatus.YiJinChang, OrderStatus.YiChuChang, OrderStatus.YiWanCheng)

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

                ;
            } else {
                ew
                        .in("a.order_status", OrderStatus.QingYunZhong);
            }
            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());

        Page<OrderPagingResult> page = pageParam.toPage();
        page.addOrder(OrderItem.desc("a.create_time"));
        QueryWrapper<OrderPagingResult> ew = Wrappers.<OrderPagingResult>query();
        AuditStatus auditStatus = orderPagingSearchParam.getAuditStatus();

        if (auditStatus != null) {
            if (auditStatus == AuditStatus.DaiShenHe) {
                ew
                        .eq("a.order_status", OrderStatus.YiJieDan)
                        .and(it ->
                                it.in(CollUtil.isNotEmpty(areaList), "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.in(CollUtil.isNotEmpty(areaList), "b.area", areaList).eq("a.audit_status", AuditStatus.ShiDaiShenHe)
                                        .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
                        .in("a.order_status", OrderStatus.YiJieDan, OrderStatus.QingYunZhong, OrderStatus.YiJinChang, OrderStatus.YiChuChang, OrderStatus.YiWanCheng)
                        .and(it ->
                                it.in(CollUtil.isNotEmpty(areaList), "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 {
            ew
                    .in("a.order_status", OrderStatus.YiJieDan, OrderStatus.QingYunZhong, OrderStatus.YiJinChang, OrderStatus.YiChuChang, OrderStatus.YiWanCheng)
                    .and(it ->
                            it.in(CollUtil.isNotEmpty(areaList), "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));
    }

    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()));
        String areaRole = config.getAreaRole();
        String cityRole = config.getCityRole();
        if (!roles.contains(areaRole) && !roles.contains(cityRole)) {
            throw Exceptions.clierr("您没有权限审核该订单");
        }

        Long quAuditUserId = null;
        Long shiAuditUserId = null;
        if (auditStatus == AuditStatus.QuDaiShenHe) {
            if (StrUtil.isNotBlank(areaRole) && roles.contains(areaRole)) {
                quAuditUserId = SecurityUtil.currentUserId();

                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();
                auditStatus = newAuditStatus;
            } else {
                throw Exceptions.clierr("您没有权限审核该订单");
            }
        } else if (auditStatus == AuditStatus.DaiShenHe) {
            quAuditUserId = SecurityUtil.currentUserId();
            shiAuditUserId = SecurityUtil.currentUserId();
            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)
                .setCertificateSn(certificateSn)
                .setAuditTime(LocalDateTime.now())
                .setCheckStatus(checkStatus)
                .setAuditMemo(auditOrderParam.getAuditMemo())
        );
    }

    @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("当前订单已看料"));
        Assert.isTrue(oldOrder.getOrderStatus() == OrderStatus.YiJinChang, () -> Exceptions.clierr("当前订单状态，无法看料"));

        this.updateById(new OrderInfoEntity()
                .setId(orderId)
                .setCheckPhoto(checkGoodsParam.getCheckPhoto())
                .setCheckStatus(CheckStatus.YiKanLiao)
                .setCheckerId(SecurityUtil.currentUserId())
        );
    }

    @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);
    }

    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("当前订单状态，无法分配司机"));

        baseMapper.busyDriver(driverId, Boolean.TRUE);

        this.updateById(new OrderInfoEntity()
                .setId(orderInfo.getId())
                .setDriverId(driverId)
                .setOrderStatus(OrderStatus.DaiJieDan)
        );
    }

    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("当前订单状态，无法分配清运公司"));

        this.updateById(new OrderInfoEntity()
                .setId(orderInfo.getId())
                .setTransCompanyId(transCompanyId)
                .setOrderStatus(OrderStatus.DaiPaiDan)
        );
        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())
                .setAuditStatus(auditStatus)
                .setTruckId(truckId)
                .setOrderStatus(OrderStatus.YiJieDan)
        );
    }

    @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 orderInfoId = orderInfo.getId();
        this.updateById(new OrderInfoEntity()
                .setId(orderInfoId)
                .setCargoPhoto(startTransportOrderParam.getCargoPhoto())
                .setOrderStatus(OrderStatus.QingYunZhong)
                .setTransTime(LocalDateTime.now())
        );
        // TODO 获取 GPS
        Long truckId = orderInfo.getTruckId();
        Assert.notNull(truckId, () -> Exceptions.clierr("订单未分配车辆"));
        BizTruckEntity truckInfo = baseMapper.getTruckInfo(truckId);
        Assert.notNull(truckInfo, () -> Exceptions.clierr("车辆不存在"));
        String gpsId = truckInfo.getGps();
        String licensePlate = truckInfo.getLicensePlate();

        startTuqiangTrack(gpsId, licensePlate, orderInfoId, truckId);
    }

    private void startTuqiangTrack(String gpsId, String licensePlate, Long orderInfoId, Long truckId) {
        CompletableFuture.runAsync(() -> {
            Assert.notEmpty(gpsId, () -> Exceptions.clierr("车辆未绑定GPS"));
            Mqtt.subscribe(gpsId + "/track_location", (msg) -> {
                RealtimeLocationResult realtimeLocationResult = msg.getMsg(RealtimeLocationResult.class);
                if (realtimeLocationResult == null) {
                    return;
                }
                if (realtimeLocationResult.isOverspeed()) {
                    bizWarnService.save(new BizWarnEntity()
                            .setWarnCategory(WarnCategory.SPEED.getVal())
                            .setWarnContent(StrUtil.format("{} 已超速，当前时速 {}km/h", licensePlate, realtimeLocationResult.getSpeed()))
                            .setOrderId(orderInfoId)
                    );
                }
                log.info("mqtt 收到消息：{} {}", gpsId + "/track_location", realtimeLocationResult);
                TruckLocationTrackEntity entity = new TruckLocationTrackEntity()
                        .setOrderId(orderInfoId)
                        .setTruckId(truckId)
                        .setTerminalId(gpsId)
                        .setLatitude(realtimeLocationResult.getLatitude())
                        .setLongitude(realtimeLocationResult.getLongitude())
                        .setAltitude(realtimeLocationResult.getAltitude())
                        .setSpeed(realtimeLocationResult.getSpeed())
                        .setLocationTime(LocalDateTime.now())
                        .setDirection(realtimeLocationResult.getDirection())
                        .setOverspeed(realtimeLocationResult.isOverspeed())
                        .setCompensate(realtimeLocationResult.getType() == 1);
                truckLocationTrackService.save(entity);
                truckLocationTrackService.cache(entity);
            });
            Mqtt.publish("location/track", MapUtil.builder()
                    .put("terminalId", gpsId)
                    .put("interval", 3)
                    .build());
        }).whenComplete((aVoid, throwable) -> {
            if (throwable != null) {
                log.error("开启GPS失败", throwable);
            }
        });
    }

    public void startTuqiangTrack(String orderId) {
        OrderInfoEntity orderInfo = this.getOne(Wrappers.lambdaQuery(OrderInfoEntity.class)
                .eq(OrderInfoEntity::getSn, orderId)
                .or().eq(OrderInfoEntity::getId, orderId)
        );
        Long orderInfoId = orderInfo.getId();
        Long truckId = orderInfo.getTruckId();
        BizTruckEntity truckInfo = baseMapper.getTruckInfo(truckId);
        String gpsId = truckInfo.getGps();
        String licensePlate = truckInfo.getLicensePlate();
        startTuqiangTrack(gpsId, licensePlate, orderInfoId, truckId);
    }

    public void stopTrack(String orderId) {
        OrderInfoEntity orderInfo = this.getOne(Wrappers.lambdaQuery(OrderInfoEntity.class)
                .eq(OrderInfoEntity::getSn, orderId)
                .or().eq(OrderInfoEntity::getId, orderId)
        );
        Long truckId = orderInfo.getTruckId();
        BizTruckEntity truckInfo = baseMapper.getTruckInfo(truckId);
        String gpsId = truckInfo.getGps();
        stopTuqiangTrack(gpsId);
    }

    public void cancel(Long orderId) {
        OrderInfoEntity orderInfo = this.getById(orderId);
        Assert.notNull(orderInfo, () -> Exceptions.clierr("订单不存在"));
        OrderStatus orderStatus = orderInfo.getOrderStatus();
        Assert.isTrue(orderStatus == OrderStatus.YiYuYue
                        || orderStatus == OrderStatus.DaiPaiDan
                        || orderStatus == OrderStatus.DaiJieDan
                , () -> Exceptions.clierr("当前订单状态，无法取消"));
        this.updateById(new OrderInfoEntity()
                .setId(orderInfo.getId())
                .setOrderStatus(OrderStatus.YiQuXiao)
        );
        // TODO 关闭 GPS 定位
        Long truckId = orderInfo.getTruckId();
        BizTruckEntity truckInfo = baseMapper.getTruckInfo(truckId);
        String gpsId = truckInfo.getGps();
        stopTuqiangTrack(gpsId);
    }

    @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();
        if (orderStatus == OrderStatus.YiJinChang) {
            Long carInOutId = orderInfoEntity.getCarInOutId();
            if (carInOutId == null) {
                log.warn("订单{}不存在关联的车辆进场记录", orderInfoEntity.getId());
                return;
            }
            OrderCarInOutEntity orderCarInOutEntity = orderCarInOutService.getById(carInOutId);
            if (orderCarInOutEntity == null) {
                log.warn("订单{}不存在关联的车辆进场记录", orderInfoEntity.getId());
                return;
            }
            LocalDateTime inTime = orderCarInOutEntity.getInTime();

            long interval = Duration.between(inTime, LocalDateTime.now()).toMillis() / 1000;
            int inOutGap = appProperties.getInOutGap();
            if (inOutGap <= 0) {
                inOutGap = 300;
            }
            if (interval <= inOutGap) {
                log.warn("车辆进场时间间隔不能小于{}秒，订单{}", inOutGap, orderInfoEntity.getSn());
                return;
            }
            log.info("进道闸转出道闸，订单{}", orderInfoEntity.getSn());
            truckLeaving(new TruckLeavingOrderParam()
                            .setOrderId(orderInfoEntity.getId())
                            .setWeight(truckComingOrderParam.getWeight())
                            .setFrontPhoto(truckComingOrderParam.getFrontPhoto())
                            .setBodyPhoto(truckComingOrderParam.getBodyPhoto()),
                    0);
            return;
        }
        Assert.isTrue(orderStatus == OrderStatus.QingYunZhong, () -> Exceptions.clierr("当前订单状态，无法进场"));

        OrderCategory orderCategory = orderInfoEntity.getOrderCategory();
        long carInOutId = orderCarInOutService.truckComing(truckComingOrderParam, orderCategory);

        this.updateById(new OrderInfoEntity()
                .setAutoOrder(3 ^ i)
                .setId(orderInfoEntity.getId())
                .setCarInOutId(carInOutId)
                .setOrderStatus(OrderStatus.YiJinChang)
        );
    }

    /**
     * 车辆出场
     *
     * @param i 0-->自动、1-->手动
     */
    @Transactional(rollbackFor = Exception.class)
    public void truckLeaving(TruckLeavingOrderParam truckLeavingOrderParam, int i) {
        OrderInfoEntity orderInfoEntity = this.getById(truckLeavingOrderParam.getOrderId());
        Long truckId = orderInfoEntity.getTruckId();
        try {
            Assert.notNull(orderInfoEntity, () -> Exceptions.clierr("订单不存在"));
            OrderStatus orderStatus = orderInfoEntity.getOrderStatus();
            Assert.isTrue(orderStatus == OrderStatus.YiJinChang, () -> Exceptions.clierr("当前订单状态，无法出场"));
            baseMapper.busyDriver(orderInfoEntity.getDriverId(), Boolean.FALSE);
            baseMapper.busyTruck(orderInfoEntity.getTruckId(), Boolean.FALSE);
            this.updateById(new OrderInfoEntity()
                    .setAutoOrder(3 ^ (i << 1))
                    .setId(orderInfoEntity.getId())
                    .setOrderStatus(OrderStatus.YiChuChang)
            );
            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，并批量落库。
            settleForTransCompany(orderInfoEntity, settleWeight);
        } finally {
            // TODO 关闭 GPS
            BizTruckEntity truckInfo = baseMapper.getTruckInfo(truckId);
            String gpsId = truckInfo.getGps();
            stopTuqiangTrack(gpsId);
        }
    }

    /**
     * 清运公司结算
     * 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），批量入库
     */
    private void settleForTransCompany(OrderInfoEntity orderInfoEntity, Integer settleWeight) {
        Long orderId = orderInfoEntity.getId();
        OrderGoodsEntity orderGoods = orderGoodsService.getById(orderInfoEntity.getGoodsId());
        Assert.notNull(orderGoods, () -> Exceptions.clierr("订单产品不存在"));

        // 数量口径：计费策略=按车(Che) 时数量=1，否则数量=settleWeight
        int quantityByStrategy = (orderGoods.getMoneyStrategy() == MoneyStrategy.Che) ? 1 : settleWeight;

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

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

        Long transCompanyId = orderInfoEntity.getTransCompanyId();
        List<OrderExpenseItemsEntity> extraItems = configs.stream()
                .filter(cfg -> {
                    Scope scope = cfg.getScope();
                    if (scope == Scope.ALL) return true;
                    if (scope == Scope.CUSTOMER_TYPE) {
                        BizObj bizObj = cfg.getBizObj();
                        return bizObj == BizObj.QiYe || bizObj == BizObj.GeTi;
                    }
                    if (scope == Scope.CUSTOMER) {
                        List<String> companyIds = cfg.getCompanyIds();
                        return companyIds != null && transCompanyId != null && companyIds.contains(String.valueOf(transCompanyId));
                    }
                    return false;
                })
                // 复制配置为订单付费项（数量口径与产品一致：按车=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())
                        .setTaxRate(cfg.getTaxRate())
                        .setQuantity("Che".equals(cfg.getMoneyStrategy()) ? 1 : settleWeight))
                .collect(Collectors.toList());

        // 第三步：合并集合并计算金额，然后批量落库
        extraItems.add(0, productItem);

        for (OrderExpenseItemsEntity item : extraItems) {
            // total_money = quantity * unit_price 如果计费策略是按吨，总金额计算时数量需要÷1000，
            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);
            }

            BigDecimal totalMoney = item.getUnitPrice().multiply(quantity);
            // settle_money = total_money + discount_money + revise_money（discount、revise 可为正负）
            BigDecimal discount = item.getDiscountMoney() == null ? BigDecimal.ZERO : item.getDiscountMoney();
            BigDecimal revise = item.getReviseMoney() == null ? BigDecimal.ZERO : item.getReviseMoney();
            BigDecimal settle = totalMoney.add(discount).add(revise);
            item.setTotalMoney(totalMoney).setSettleMoney(settle);
        }

        orderExpenseItemsService.saveBatch(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) {
        return baseMapper.obtainWeighBill(orderId);
    }

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