package com.clx.performance.service.impl.settle;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.clx.performance.dao.OwnerAccountPasswordDao;
import com.clx.order.feign.OrderFeign;
import com.clx.order.vo.feign.FeignOrderVO;
import com.clx.performance.component.NetworkSyncComponent;
import com.clx.performance.dao.breakcontract.BreakContractSettlementOwnerDao;
import com.clx.performance.dao.settle.SettlementLogDao;
import com.clx.performance.dao.settle.SettlementOwnerDao;
import com.clx.performance.dao.settle.SettlementOwnerDetailDao;
import com.clx.performance.dao.settle.SettlementPlatformAccountDao;
import com.clx.performance.dto.InvoicingStatusNotifyDTO;
import com.clx.performance.enums.OrderChildLogEnum;
import com.clx.performance.enums.PerformanceResultEnum;
import com.clx.performance.enums.settle.SettlementLogEnum;
import com.clx.performance.enums.settle.SettlementOwnerDetailEnum;
import com.clx.performance.enums.settle.SettlementOwnerEnum;
import com.clx.performance.enums.settle.SettlementWayEnum;
import com.clx.performance.model.OwnerAccountPassword;
import com.clx.performance.enums.PlatformAccountConfigEnum;
import com.clx.performance.enums.settle.*;
import com.clx.performance.model.breakcontract.BreakContractSettlementOwner;
import com.clx.performance.model.settle.SettlementLog;
import com.clx.performance.model.settle.SettlementOwner;
import com.clx.performance.model.settle.SettlementOwnerDetail;
import com.clx.performance.model.settle.SettlementPlatformAccount;
import com.clx.performance.param.pc.owner.*;
import com.clx.performance.service.OwnerAccountService;
import com.clx.performance.service.PlatformAccountConfigService;
import com.clx.performance.service.settle.SettlementLogService;
import com.clx.performance.service.settle.SettlementMqHandlerService;
import com.clx.performance.service.settle.SettlementOwnerService;
import com.clx.performance.struct.settle.SettlementLogStruct;
import com.clx.performance.struct.settle.SettlementOwnerStruct;
import com.clx.performance.utils.MyMD5Util;
import com.clx.performance.utils.excel.ExcelData;
import com.clx.performance.utils.excel.ExcelField;
import com.clx.performance.utils.excel.ExcelSheet;
import com.clx.performance.utils.excel.ExcelUtil;
import com.clx.performance.vo.pc.carrier.settle.*;
import com.clx.performance.vo.pc.owner.settle.OwnerPageSettlementOwnerVO;
import com.clx.performance.vo.pc.owner.settle.SettlementPlatformAccountVO;
import com.clx.user.vo.pc.owner.OwnerBindCardVO;
import com.msl.common.exception.ServiceSystemException;
import com.msl.user.data.UserSessionData;
import com.msl.user.utils.TokenUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author liruixin
 * Date 2023-10-12
 * Time 09:43
 */
@Slf4j
@Service
@AllArgsConstructor
public class SettlementOwnerServiceImpl  implements SettlementOwnerService {

    private final SettlementOwnerDao settlementOwnerDao;

    private final SettlementOwnerDetailDao settlementOwnerDetailDao;

    private final SettlementOwnerStruct settlementOwnerStruct;

    private final SettlementLogDao settlementLogDao;

    private final SettlementLogStruct settlementLogStruct;

    private final SettlementPlatformAccountDao settlementPlatformAccountDao;

    private final SettlementLogService settlementLogService;

    private final OwnerAccountService ownerAccountService;

    private final OwnerAccountPasswordDao ownerAccountPasswordDao;

    private final NetworkSyncComponent networkSyncComponent;
    private final SettlementMqHandlerService settlementMqHandlerService;

    private final PlatformAccountConfigService platformAccountConfigService;
    private final OrderFeign orderFeign;
    private final BreakContractSettlementOwnerDao breakContractSettlementOwnerDao;



    @Override
    public CarrierSettlementOwnerDetailVO getCarrierSettlementOwnerDetail(Integer id) {
        //结算单详情
        SettlementOwner settlementOwner =settlementOwnerDao.getEntityByKey(id).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);
        CarrierSettlementOwnerDetailVO detail = settlementOwnerStruct.convertToDetail(settlementOwner);

        String settlementNo = settlementOwner.getSettlementNo();
        //合并结算单
        List<SettlementOwner> mergeSettlementNos = settlementOwnerDao.getMergeSettlementNos(settlementNo);
        detail.setMergers(settlementOwnerStruct.convertToMergeList(mergeSettlementNos));

        //操作日志
        List<SettlementLog> settlementLogs = settlementLogDao.getSettlementLogs(settlementNo);
        List<SettlementLogVO> settlementLogVOS = settlementLogStruct.convert(settlementLogs);
        detail.setSettlementLogs(settlementLogVOS);
        return detail;

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateConfirmSettlement(Integer id) {
        //结算单详情
        SettlementOwner settlementOwner =settlementOwnerDao.getEntityByKey(id).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);

        //状态判断
        if(!Objects.equals(settlementOwner.getStatus(), SettlementOwnerEnum.Status.OWNER_TO_BE_CONFIRMED.getCode())){
            throw new ServiceSystemException(PerformanceResultEnum.SETTLEMENT_ORDER_STATUS_CHANGED);
        }

        String settlementNo = settlementOwner.getSettlementNo();
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        //保存结算单日志----货主确认结算单
        settlementLogService.saveSettlementLog(settlementNo,
                SettlementLogEnum.Type.OWNER_TO_BE_CONFIRMED.getCode(),SettlementLogEnum.Type.OWNER_TO_BE_CONFIRMED.getMsg(),
                OrderChildLogEnum.CreateType.OWNER.getCode(),loginUserInfo.getUserNo(),loginUserInfo.getUserName());
        int status;
        if(settlementOwner.getSettlementFreight().compareTo(BigDecimal.ZERO) >0){
            status = SettlementOwnerEnum.Status.SHIPPER_TO_PAYMENT.getCode();
        }else if(settlementOwner.getSettlementFreight().compareTo(BigDecimal.ZERO) <0){
            status = SettlementOwnerEnum.Status.PLATFORM_TO_PAYMENT.getCode();
        }else{
            status = SettlementOwnerEnum.Status.COMPLETED.getCode();
            //保存结算单日志----已完结
            settlementLogService.saveSettlementLog(settlementNo,
                    SettlementLogEnum.Type.COMPLETED.getCode(),SettlementLogEnum.Type.COMPLETED.getMsg(),
                    OrderChildLogEnum.CreateType.OWNER.getCode(),loginUserInfo.getUserNo(),loginUserInfo.getUserName());
        }

        if(Objects.equals(settlementOwner.getInvoiceType(),SettlementOwnerEnum.InvoiceType.ORDINARY.getCode())){
            if(settlementOwner.getInvoiceFreight().compareTo(BigDecimal.ZERO) <=0 ){
                settlementOwnerDao.updateInvoiceStatusById(settlementOwner.getId(),SettlementOwnerEnum.InvoiceStatus.NO_NEED_INVOICE.getCode());
                settlementOwnerDetailDao.updateInvoiceStatusBySettlementNo(settlementNo, SettlementOwnerDetailEnum.InvoiceStatus.NO_INVOICE.getCode());
            }
            if(settlementOwner.getSettlementFreight().compareTo(BigDecimal.ZERO) == 0){
                settlementOwnerDetailDao.updateFinalPaymentStatusBySettlementNo(settlementNo, SettlementOwnerDetailEnum.FinalPaymentStatus.NO_REQUIRE.getCode());
            }
        } else {
            if (settlementOwner.getSettlementFreight().compareTo(BigDecimal.ZERO) == 0 &&
                settlementOwner.getInvoiceFreight().compareTo(BigDecimal.ZERO) >= 0
            ) {
                //TODO 通知网络货运做货主计费开票标识通知
                List<SettlementOwnerDetail> settlementOwnerDetailList = settlementOwnerDetailDao.getBySettlementNoAndInvoiceType(settlementNo,
                        SettlementDriverEnum.InvoiceType.ONLINE.getCode(),SettlementOwnerDetailEnum.InvoiceStatus.NO.getCode());
                networkSyncComponent.ownerSettlementSync(settlementOwner, settlementOwnerDetailList);
            }

        }

        //更新状态
        settlementOwnerDao.updateStatusBySettlementNo(settlementNo,status);
    }

    @Override
    public SettlementPlatformAccountVO getSettlementPlatformAccount() {
        //平台账号
        SettlementPlatformAccount platformAccount = settlementPlatformAccountDao.getSettlementPlatformAccount();
        //返回对象
        SettlementPlatformAccountVO vo = new SettlementPlatformAccountVO();
        if(Objects.nonNull(platformAccount)){
            vo.setPayee(platformAccount.getCardHolder());
            vo.setPayeeBankCardNo(platformAccount.getBankCardNo());
            vo.setPayeeBankName(platformAccount.getBankName());
        }

        //当前账号
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        OwnerBindCardVO card = ownerAccountService.getOwnerBindCard(loginUserInfo.getUserNo());
        if(Objects.nonNull(card)){
            vo.setPaymentBankCardNo(card.getOwnerBankAccount());
            vo.setPaymentBankName(card.getOwnerAccountBank());
        }
        return vo;
    }

    @Override
    public SettlementPlatformAccountVO getSettlementPlatformAccountById(Integer id) {
        //返回对象
        SettlementPlatformAccountVO vo = new SettlementPlatformAccountVO();
        SettlementOwner settlementOwner = settlementOwnerDao.getEntityByKey(id).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);

        List<CarrierPagePlatformAccountConfigVO> configs =
                platformAccountConfigService.getPlatformAccountConfigByType(
                        PlatformAccountConfigEnum.BusinessType.SETTLE.getCode(),
                        PlatformAccountConfigEnum.OwnerType.COMPANY.getCode(),
                        settlementOwner.getInvoiceType(),
                        settlementOwner.getInvoicingCompanyId(),
                        PlatformAccountConfigEnum.ConfigRange.COLLECTION.getCode());
        if(CollectionUtils.isEmpty(configs)){
            throw new ServiceSystemException(PerformanceResultEnum.PLATFORM_ACCOUNT_CONFIG_IS_NULL);
        }
        if(configs.size() > 1){
            throw new ServiceSystemException(PerformanceResultEnum.PLATFORM_ACCOUNT_CONFIG_MANY);
        }
        vo.setPayee(configs.get(0).getCompanyName());
        vo.setPayeeBankCardNo(configs.get(0).getBankCardNo());
        vo.setPayeeBankName(configs.get(0).getBankName());

        //当前账号
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        OwnerBindCardVO card = ownerAccountService.getOwnerBindCard(loginUserInfo.getUserNo());
        if(Objects.nonNull(card)){
            vo.setPaymentBankCardNo(card.getOwnerBankAccount());
            vo.setPaymentBankName(card.getOwnerAccountBank());
        }
        return vo;
    }

    @Override
    public SettlementPlatformAccountVO getBreakSettlementPlatformAccount(Integer id) {
        //返回对象
        SettlementPlatformAccountVO vo = new SettlementPlatformAccountVO();
        BreakContractSettlementOwner settlementOwner = breakContractSettlementOwnerDao.getEntityByKey(id).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);
        FeignOrderVO orderInfoFeign = orderFeign.getOrderInfoFeign(settlementOwner.getOrderNo());

        List<CarrierPagePlatformAccountConfigVO> configs =
                platformAccountConfigService.getPlatformAccountConfigByType(
                        PlatformAccountConfigEnum.BusinessType.BREAK.getCode(),
                        PlatformAccountConfigEnum.OwnerType.COMPANY.getCode(),
                        null,
                        orderInfoFeign.getInvoicingCompanyId(),
                        PlatformAccountConfigEnum.ConfigRange.COLLECTION.getCode());
        if(CollectionUtils.isEmpty(configs)){
            throw new ServiceSystemException(PerformanceResultEnum.PLATFORM_ACCOUNT_CONFIG_IS_NULL);
        }
        if(configs.size() > 1){
            throw new ServiceSystemException(PerformanceResultEnum.PLATFORM_ACCOUNT_CONFIG_MANY);
        }
        vo.setPayee(configs.get(0).getCompanyName());
        vo.setPayeeBankCardNo(configs.get(0).getBankCardNo());
        vo.setPayeeBankName(configs.get(0).getBankName());

        //当前账号
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        OwnerBindCardVO card = ownerAccountService.getOwnerBindCard(loginUserInfo.getUserNo());
        if(Objects.nonNull(card)){
            vo.setPaymentBankCardNo(card.getOwnerBankAccount());
            vo.setPaymentBankName(card.getOwnerAccountBank());
        }
        return vo;
    }


    @Override
    public SettlementPlatformAccountVO getCarrierSettlementPlatformAccount(String settlementNo){

        /*//平台账号
        SettlementPlatformAccount platformAccount = settlementPlatformAccountDao.getSettlementPlatformAccount();
        if(Objects.nonNull(platformAccount)){
            vo.setPaymentBankCardNo(platformAccount.getBankCardNo());
            vo.setPaymentBankName(platformAccount.getBankName());
        }*/

        //返回对象
        SettlementPlatformAccountVO vo = new SettlementPlatformAccountVO();
        SettlementOwner settlementOwner = settlementOwnerDao.selectBySettlementNo(settlementNo).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);

        List<CarrierPagePlatformAccountConfigVO> configs =
                platformAccountConfigService.getPlatformAccountConfigByType(
                        PlatformAccountConfigEnum.BusinessType.SETTLE.getCode(),
                        PlatformAccountConfigEnum.OwnerType.COMPANY.getCode(),
                        PlatformAccountConfigEnum.InvoiceType.ORDINARY.getCode(),
                        settlementOwner.getInvoicingCompanyId(),
                        PlatformAccountConfigEnum.ConfigRange.PAY.getCode());
        if(CollectionUtils.isEmpty(configs)){
            throw new ServiceSystemException(PerformanceResultEnum.PLATFORM_ACCOUNT_CONFIG_IS_NULL);
        }
        if(configs.size() > 1){
            throw new ServiceSystemException(PerformanceResultEnum.PLATFORM_ACCOUNT_CONFIG_MANY);
        }
        vo.setPaymentBankCardNo(configs.get(0).getBankCardNo());
        vo.setPaymentBankName(configs.get(0).getBankName());

        //货主账号
        OwnerBindCardVO card = ownerAccountService.getOwnerBindCard(settlementOwner.getOwnerUserNo());
        if(Objects.nonNull(card)){
            vo.setPayee(card.getName());
            vo.setPayeeBankName(card.getOwnerAccountBank());
            vo.setPayeeBankCardNo(card.getOwnerBankAccount());
        }
        return vo;
    }


    @Override
    public void updatePaymentSettlement(OwnerPaymentSettlementParam param) {
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        if (StringUtils.equals(loginUserInfo.getProductCode(), "carrier-owner-app")) {
            OwnerAccountPassword entity = ownerAccountPasswordDao.findEntityByUserNo(loginUserInfo.getUserNo());
            try {
                boolean b = MyMD5Util.validPassword(param.getAccountPassword(), entity.getPassword());
                if (!b) {
                    throw new ServiceSystemException(PerformanceResultEnum.PASSWORD_CHECK_FAIL);
                }
            } catch (Exception e) {
                throw new ServiceSystemException(PerformanceResultEnum.PASSWORD_CHECK_FAIL);
            }
        }


        //结算单详情
        SettlementOwner settlementOwner =settlementOwnerDao.getEntityByKey(param.getId()).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);

        //状态判断
        if(!Objects.equals(settlementOwner.getStatus(), SettlementOwnerEnum.Status.SHIPPER_TO_PAYMENT.getCode())){
            throw new ServiceSystemException(PerformanceResultEnum.SETTLEMENT_ORDER_STATUS_CHANGED);
        }

        String settlementNo = settlementOwner.getSettlementNo();
        //更新状态为平台确认货主付款
        SettlementOwner settlement = SettlementOwner.builder().payee(param.getPayee()).payeeBankCardNo(param.getPayeeBankCardNo())
                .payeeBankName(param.getPayeeBankName()).paymentBankCardNo(param.getPaymentBankCardNo())
                .paymentBankName(param.getPaymentBankName()).paymentImg(param.getPaymentImg())
                .settlementNo(settlementOwner.getSettlementNo())
                .status(SettlementOwnerEnum.Status.PLATFORM_CONFIRMED_OWNER_PAYMENT.getCode()).build();
        settlementOwnerDao.updatePayment(settlement);

        //保存结算单日志
        settlementLogService.saveSettlementLog(settlementNo,
                SettlementLogEnum.Type.SHIPPER_TO_PAYMENT.getCode(),SettlementLogEnum.Type.SHIPPER_TO_PAYMENT.getMsg(),
                OrderChildLogEnum.CreateType.OWNER.getCode(),loginUserInfo.getUserNo(),loginUserInfo.getUserName());
    }

    @Override
    public void updatePaymentConfirmSettlement(Integer id) {

        //结算单详情
        SettlementOwner settlementOwner =settlementOwnerDao.getEntityByKey(id).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);

        //状态判断
        if(!Objects.equals(settlementOwner.getStatus(), SettlementOwnerEnum.Status.OWNER_CONFIRMED_PLATFORM_PAYMENT.getCode())){
            throw new ServiceSystemException(PerformanceResultEnum.SETTLEMENT_ORDER_STATUS_CHANGED);
        }

        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        String settlementNo = settlementOwner.getSettlementNo();

        //更新状态
        settlementOwnerDao.updateStatusBySettlementNo(settlementNo,SettlementOwnerEnum.Status.COMPLETED.getCode());

        Integer finalPaymentStatus = null;
        if(Objects.equals(settlementOwner.getInvoiceType(),SettlementOwnerEnum.InvoiceType.ORDINARY.getCode())){  //普通单
            if(settlementOwner.getSettlementFreight().compareTo(BigDecimal.ZERO)!= 0){  //结算金额!=0,结算单收款方付款确认后，更新状态为“是”
                finalPaymentStatus = SettlementOwnerDetailEnum.FinalPaymentStatus.YES.getCode();
            }else{ //结算金额=0，默认无需支付。
                finalPaymentStatus = SettlementOwnerDetailEnum.FinalPaymentStatus.NO_REQUIRE.getCode();
            }
        }else{ //网运单
            if(settlementOwner.getSettlementFreight().compareTo(BigDecimal.ZERO) > 0){  //结算金额>0的,结算单收款方付款确认后，更新状态为“是”
                finalPaymentStatus = SettlementOwnerDetailEnum.FinalPaymentStatus.YES.getCode();
            }else if(settlementOwner.getSettlementFreight().compareTo(BigDecimal.ZERO) ==  0){   //结算金额=0的，默认“无需支付”。
                finalPaymentStatus = SettlementOwnerDetailEnum.FinalPaymentStatus.NO_REQUIRE.getCode();
            }
        }
        if(Objects.nonNull(finalPaymentStatus)){
            settlementOwnerDetailDao.updateFinalPaymentStatusBySettlementNo(settlementNo, finalPaymentStatus);

        }

        //保存结算单日志
        settlementLogService.saveSettlementLog(settlementNo,
                SettlementLogEnum.Type.OWNER_CONFIRMED_PLATFORM_PAYMENT.getCode(),SettlementLogEnum.Type.OWNER_CONFIRMED_PLATFORM_PAYMENT.getMsg(),
                OrderChildLogEnum.CreateType.OWNER.getCode(),loginUserInfo.getUserNo(),loginUserInfo.getUserName());

        //保存结算单日志
        settlementLogService.saveSettlementLog(settlementNo,
                SettlementLogEnum.Type.COMPLETED.getCode(),SettlementLogEnum.Type.COMPLETED.getMsg(),
                OrderChildLogEnum.CreateType.OWNER.getCode(),loginUserInfo.getUserNo(),loginUserInfo.getUserName());


    }

    @Override
    public IPage<CarrierPageSettlementOwnerVO> pageCarrierSettlementOwner(PageCarrierSettlementOwnerParam param) {
        IPage<SettlementOwner> page =  settlementOwnerDao.pageCarrierSettlementOwner(param);
        List<CarrierPageSettlementOwnerVO> list = settlementOwnerStruct.convertCarrierList(
                page.getRecords());
        return new Page<CarrierPageSettlementOwnerVO>().setRecords(list).setTotal(page.getTotal()).setPages(page.getPages());
    }

    @Override
    public IPage<OwnerPageSettlementOwnerVO> pageSettlementOwner(PageOwnerSettlementParam param) {
        Long userNo = TokenUtil.getLoginUserInfo().getUserNo();
        IPage<SettlementOwner> page = settlementOwnerDao.pageSettlementOwner(userNo,param);
        List<OwnerPageSettlementOwnerVO> list = settlementOwnerStruct.convertOwnerList(page.getRecords());
        return new Page<OwnerPageSettlementOwnerVO>().setRecords(list).setTotal(page.getTotal()).setPages(page.getPages());
    }

    @Override
    public SXSSFWorkbook exportCarrierSettlementOwnerPageList(PageCarrierSettlementOwnerParam param) {
        param.setPage(1);
        param.setPageSize(1000000);
        IPage<SettlementOwner> page =  settlementOwnerDao.pageCarrierSettlementOwner(param);
        List<CarrierPageSettlementOwnerVO> list = settlementOwnerStruct.convertCarrierList(
                page.getRecords());

        // 组装表头
        List<ExcelField> fieldList = new ArrayList<>();
        fieldList.add(new ExcelField(0, "序号", "index", 2000));
        fieldList.add(new ExcelField(1, "结算单号", "settlementNo", 5000));
        fieldList.add(new ExcelField(2, "开票标识", "invoiceType", 5000));
        fieldList.add(new ExcelField(3, "货主编码", "ownerUserNo", 5000));
        fieldList.add(new ExcelField(4, "货主名称", "ownerUserName", 5000));
        fieldList.add(new ExcelField(5, "结算方式", "settlementWay", 5000));
        fieldList.add(new ExcelField(6, "订单编号", "orderNo", 15000));
        fieldList.add(new ExcelField(7, "实际净重", "weight", 5000));
        fieldList.add(new ExcelField(8, "实际运费金额", "freight", 5000));
        fieldList.add(new ExcelField(9, "预付运费金额", "prepayFreight", 5000));
        fieldList.add(new ExcelField(10, "货损吨数", "lossWeight", 5000));
        fieldList.add(new ExcelField(11, "货损金额", "lossFreight", 5000));
        fieldList.add(new ExcelField(12, "开票服务费", "invoiceServiceFee", 5000));
        fieldList.add(new ExcelField(13, "借款抵扣金额", "loanFreight", 5000));
        fieldList.add(new ExcelField(14, "结算金额", "settlementFreight", 5000));
        fieldList.add(new ExcelField(15, "开票金额", "invoiceFreight", 5000));
        fieldList.add(new ExcelField(16, "开票公司", "invoiceCompany", 5000));
        fieldList.add(new ExcelField(17, "创建时间", "createTime", 5000));
        fieldList.add(new ExcelField(18, "状态", "status", 5000));

        // 组装数据
        List<List<ExcelData>> dataList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {

            CarrierPageSettlementOwnerVO dto = list.get(i);
            List<ExcelData> rowData = new ArrayList<>();

            rowData.add(new ExcelData(i + 1));
            rowData.add(new ExcelData(dto.getSettlementNo()));
            rowData.add(new ExcelData(SettlementOwnerEnum.InvoiceType.getMsgByCode(dto.getInvoiceType())));
            rowData.add(new ExcelData(String.valueOf(dto.getOwnerUserNo())));
            rowData.add(new ExcelData(dto.getOwnerName()));
            rowData.add(new ExcelData(SettlementWayEnum.WayType.getMsgByCode(dto.getSettlementWay())));
            rowData.add(new ExcelData(dto.getOrderNo()));
            rowData.add(new ExcelData(dto.getWeight()));
            rowData.add(new ExcelData(dto.getFreight().movePointLeft(2)));
            rowData.add(new ExcelData(dto.getPrepayFreight().movePointLeft(2)));
            rowData.add(new ExcelData(dto.getLossWeight()));
            rowData.add(new ExcelData(dto.getLossFreight().movePointLeft(2)));
            rowData.add(new ExcelData(dto.getInvoiceServiceFee().movePointLeft(2)));
            rowData.add(new ExcelData(dto.getLoanFreight().movePointLeft(2)));
            rowData.add(new ExcelData(dto.getSettlementFreight().movePointLeft(2)));
            rowData.add(new ExcelData(dto.getInvoiceFreight().movePointLeft(2)));
            rowData.add(new ExcelData(dto.getInvoicingCompanyShorterName()));
            rowData.add(new ExcelData(dto.getCreateTime()));
            rowData.add(new ExcelData(SettlementOwnerEnum.Status.getMsgByCode(dto.getStatus())));

            dataList.add(rowData);
        }

        ExcelSheet excelSheet = new ExcelSheet("货主结算单", "货主结算单", fieldList, dataList);

        //创建excel
        return ExcelUtil.create(excelSheet);
    }

    @Override
    public CarrierSettlementOwnerCompanyVO getCarrierSettlementOwnerInvoiceCompany(Integer id) {
        //结算单详情
        SettlementOwner settlementOwner =settlementOwnerDao.getEntityByKey(id).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);
        CarrierSettlementOwnerCompanyVO detail = settlementOwnerStruct.convertToCompany(settlementOwner);
        return detail;
    }

    @Override
    public CarrierSettlementOwnerCompanyContactVO getCarrierSettlementOwnerCompanyContact(Integer id) {
        //结算单详情
        SettlementOwner settlementOwner =settlementOwnerDao.getEntityByKey(id).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);
        CarrierSettlementOwnerCompanyContactVO detail = settlementOwnerStruct.convertToCompanyContact(settlementOwner);
        return detail;
    }

    @Override
    public CarrierSettlementOwnerPayeeVO getCarrierSettlementOwnerPayee(Integer id) {
        //结算单详情
        SettlementOwner settlementOwner =settlementOwnerDao.getEntityByKey(id).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);
        CarrierSettlementOwnerPayeeVO detail = settlementOwnerStruct.convertToPayee(settlementOwner);
        return detail;
    }

    @Override
    public CarrierSettlementOwnerExpressVO getCarrierSettlementOwnerExpress(Integer id) {
        //结算单详情
        SettlementOwner settlementOwner =settlementOwnerDao.getEntityByKey(id).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);
        CarrierSettlementOwnerExpressVO detail = settlementOwnerStruct.convertToExpress(settlementOwner);
        return detail;
    }
    @Override
    public void uploadInvoiceImg(UploadInvoiceImgParam param){
        String settlementNo = param.getSettlementNo();
        settlementOwnerDao.uploadInvoiceImg(settlementNo,param.getInvoiceImg());

        settlementOwnerDao.updateStatusBySettlementNo(settlementNo
                ,SettlementOwnerEnum.Status.OWNER_TO_BE_CONFIRMED.getCode());
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        //保存结算单日志----上传结算凭证
        settlementLogService.saveSettlementLog(settlementNo,
                SettlementLogEnum.Type.UPLOAD_SETTLEMENT.getCode(),SettlementLogEnum.Type.UPLOAD_SETTLEMENT.getMsg(),
                OrderChildLogEnum.CreateType.PLATFORM.getCode(),loginUserInfo.getUserNo(),loginUserInfo.getUserName());

    }

    @Override
    public void saveExpress(SaveExpressParam param){
        String settlementNo = param.getSettlementNo();
        SettlementOwner settlementOwner = settlementOwnerDao.selectBySettlementNo(settlementNo).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);

        settlementOwnerDao.saveExpress(settlementNo,param.getExpressCompany(),param.getExpressNo());

        if(Objects.equals(settlementOwner.getInvoiceType(),SettlementOwnerEnum.InvoiceType.ORDINARY.getCode())){
            int invoiceStatus;
            int detailInvoiceStatus;
            if(settlementOwner.getInvoiceFreight().compareTo(BigDecimal.ZERO) > 0 ){ //结算单开票金额>0结算单填写发票物流单号以后，更新状态为“是”
                invoiceStatus = SettlementOwnerEnum.InvoiceStatus.INVOICED.getCode();
                detailInvoiceStatus =  SettlementOwnerDetailEnum.InvoiceStatus.YES.getCode();
            }else{  //结算单开票金额<=0的结算单，货主确认结算单后，更新状态为“无需开票”
                invoiceStatus = SettlementOwnerEnum.InvoiceStatus.NO_NEED_INVOICE.getCode();
                detailInvoiceStatus =  SettlementOwnerDetailEnum.InvoiceStatus.NO_INVOICE.getCode();
            }
            settlementOwnerDao.updateInvoiceStatusById(settlementOwner.getId(),invoiceStatus);
            settlementOwnerDetailDao.updateInvoiceStatusBySettlementNo(settlementNo, detailInvoiceStatus);
        }

        settlementOwnerDao.updateStatusBySettlementNo(settlementNo
                ,SettlementOwnerEnum.Status.COMPLETED.getCode());

        if(!Objects.equals(settlementOwner.getStatus(),SettlementOwnerEnum.Status.COMPLETED.getCode())){
            UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
            //保存结算单日志----邮寄发票
            settlementLogService.saveSettlementLog(settlementNo,
                    SettlementLogEnum.Type.INVOICE_TO_BE_MAILED.getCode(),SettlementLogEnum.Type.INVOICE_TO_BE_MAILED.getMsg(),
                    OrderChildLogEnum.CreateType.PLATFORM.getCode(),loginUserInfo.getUserNo(),loginUserInfo.getUserName());
            //保存结算单日志----已完结
            settlementLogService.saveSettlementLog(settlementNo,
                    SettlementLogEnum.Type.COMPLETED.getCode(),SettlementLogEnum.Type.COMPLETED.getMsg(),
                    OrderChildLogEnum.CreateType.PLATFORM.getCode(),loginUserInfo.getUserNo(),loginUserInfo.getUserName());
        }else{
            UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
            //保存结算单日志----邮寄发票
            settlementLogService.saveSettlementLog(settlementNo,
                    SettlementLogEnum.Type.INVOICE_TO_BE_MAILED.getCode(),SettlementLogEnum.Type.INVOICE_TO_BE_MAILED.getMsg(),
                    OrderChildLogEnum.CreateType.PLATFORM.getCode(),loginUserInfo.getUserNo(),loginUserInfo.getUserName());
        }

    }

    @Override
    public void savePayee(SavePayeeParam param){
        String settlementNo = param.getSettlementNo();
        settlementOwnerDao.savePayee(settlementNo,
                param.getPayee(),
                param.getPayeeBankName(),
                param.getPayeeBankCardNo(),
                param.getPaymentImg(),
                param.getPaymentBankCardNo(),
                param.getPaymentBankName(),
                param.getPaymentAmount());

        settlementOwnerDao.updateStatusBySettlementNo(settlementNo
                ,SettlementOwnerEnum.Status.OWNER_CONFIRMED_PLATFORM_PAYMENT.getCode());
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        //保存结算单日志----平台付款
        settlementLogService.saveSettlementLog(settlementNo,
                SettlementLogEnum.Type.PLATFORM_TO_PAYMENT.getCode(),SettlementLogEnum.Type.PLATFORM_TO_PAYMENT.getMsg(),
                OrderChildLogEnum.CreateType.PLATFORM.getCode(),loginUserInfo.getUserNo(),loginUserInfo.getUserName());
    }

    @Override
    public void updateStatusByOrderNo(String orderNo, Integer settlementPeriodType, Integer fromStatus, Integer toStatus){
        boolean b = settlementOwnerDao.updateStatusByOrderNo(orderNo, settlementPeriodType, fromStatus, toStatus);
        log.info("结算单更改状态结果:{}", b);
    }

    @Override
    public void payeeConfirm(String settlementNo){
        SettlementOwner settlementOwner = settlementOwnerDao.selectBySettlementNo(settlementNo).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);
        //更新是否已付尾款状态
        Integer finalPaymentStatus = null;
        if(Objects.equals(settlementOwner.getInvoiceType(),SettlementOwnerEnum.InvoiceType.ORDINARY.getCode())){  //普通单
            if(settlementOwner.getSettlementFreight().compareTo(BigDecimal.ZERO)!= 0){  //结算金额!=0,结算单收款方付款确认后，更新状态为“是”
                finalPaymentStatus = SettlementOwnerDetailEnum.FinalPaymentStatus.YES.getCode();
            }else{ //结算金额=0，默认无需支付。
                finalPaymentStatus = SettlementOwnerDetailEnum.FinalPaymentStatus.NO_REQUIRE.getCode();
            }
        }else{ //网运单
            settlementOwnerDetailDao.updateFinalPaymentStatusBySettlementNoForOnline(settlementNo, SettlementOwnerDetailEnum.FinalPaymentStatus.YES.getCode());

//            if(settlementOwner.getPrepayFreight().compareTo(BigDecimal.ZERO) == 0){  //结算金额>0的,结算单收款方付款确认后，更新状态为“是”
//                finalPaymentStatus = SettlementOwnerDetailEnum.FinalPaymentStatus.YES.getCode();
//            }
///*            else if(settlementOwner.getSettlementFreight().compareTo(BigDecimal.ZERO) ==  0){   //结算金额=0的，默认“无需支付”。
//                finalPaymentStatus = SettlementOwnerDetailEnum.FinalPaymentStatus.NO_REQUIRE.getCode();
//            }*/
        }
        if(Objects.nonNull(finalPaymentStatus)){
            settlementOwnerDetailDao.updateFinalPaymentStatusBySettlementNo(settlementNo, finalPaymentStatus);
        }
        if(settlementOwner.getInvoiceFreight().compareTo(BigDecimal.ZERO) < 0){
            settlementOwnerDao.updateStatusBySettlementNo(settlementNo,SettlementOwnerEnum.Status.COMPLETED.getCode());
        }else{
            if (Objects.equals(settlementOwner.getInvoiceType(), SettlementOwnerEnum.InvoiceType.ONLINE.getCode())) {
                settlementOwnerDao.updateStatusBySettlementNo(settlementNo,SettlementOwnerEnum.Status.COMPLETED.getCode());
                //TODO 通知网络货运做货主计费开票标识通知
                List<SettlementOwnerDetail> settlementOwnerDetailList = settlementOwnerDetailDao.getBySettlementNoAndInvoiceType(settlementNo,
                        SettlementDriverEnum.InvoiceType.ONLINE.getCode(),SettlementOwnerDetailEnum.InvoiceStatus.NO.getCode());
                networkSyncComponent.ownerSettlementSync(settlementOwner,settlementOwnerDetailList);

            }else{
                settlementOwnerDao.updateStatusBySettlementNo(settlementNo,SettlementOwnerEnum.Status.INVOICE_TO_BE_MAILED.getCode());
            }
        }

        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        //保存结算单日志
        settlementLogService.saveSettlementLog(settlementNo,
                SettlementLogEnum.Type.PLATFORM_CONFIRMED_OWNER_PAYMENT.getCode(),SettlementLogEnum.Type.PLATFORM_CONFIRMED_OWNER_PAYMENT.getMsg(),
                OrderChildLogEnum.CreateType.PLATFORM.getCode(),loginUserInfo.getUserNo(),loginUserInfo.getUserName());

        if(Objects.equals(settlementOwner.getInvoiceStatus(),SettlementOwnerEnum.InvoiceType.ONLINE.getCode())){//网运单
            //保存结算单日志
            settlementLogService.saveSettlementLog(settlementNo,
                    SettlementLogEnum.Type.COMPLETED.getCode(),SettlementLogEnum.Type.COMPLETED.getMsg(),
                    OrderChildLogEnum.CreateType.PLATFORM.getCode(),loginUserInfo.getUserNo(),loginUserInfo.getUserName());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void invoicingStatusNotify(InvoicingStatusNotifyDTO invoicingStatusNotifyDTO) {
        List<String> childNoList = invoicingStatusNotifyDTO.getChildNoList();
        if (CollectionUtil.isEmpty(childNoList)) {
            return;
        }
        SettlementOwnerDetail settlementOwnerDetail = settlementOwnerDetailDao.getByChildNo(childNoList.get(0)).get();
        String settlementNo = settlementOwnerDetail.getSettlementNo();
        List<SettlementOwnerDetail> list = settlementOwnerDetailDao.getBySettlementNoAndInvoiceType(settlementNo,
            SettlementOwnerEnum.InvoiceType.ONLINE.getCode(),SettlementOwnerDetailEnum.InvoiceStatus.NO.getCode());
        if (CollectionUtil.isEmpty(list)) {
            log.info("开票结果回调查询当前结算单均已开完票,结算单信息为{}", settlementNo);
            return;
        }
        settlementOwnerDetailDao.updateSettlementByChildNoList(childNoList);

        if (list.size() == childNoList.size()) {
            log.info("当前是结算单所有计费都已经开票");
            settlementOwnerDao.updateInvoiceStatusBySettlementNo(settlementNo, SettlementOwnerEnum.InvoiceStatus.INVOICED.getCode());
        } else {
            log.info("当前是结算单部分开票");
            settlementOwnerDao.updateInvoiceStatusBySettlementNo(settlementNo, SettlementOwnerEnum.InvoiceStatus.NO_NEED_INVOICE.getCode());
        }
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void mergeOwnerSettlement(MergeOwnerSettlementParam param) {
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        LocalDateTime now = LocalDateTime.now();
        if(param.getList().size() < 2){
            throw new ServiceSystemException(PerformanceResultEnum.DATA_NOT_FIND,"请选择至少两条记录");
        }
        //查询结算单数据
        List<SettlementOwner>  settlementOwnersList = settlementOwnerDao.listInField(SettlementOwner :: getId,param.getList());
        if(!Objects.equals(param.getList().size(),settlementOwnersList.size())){
            log.warn("查询的货主结算单数据和实际查询出来的货主结算单数量不一致，结算单id集合：{}",param.getList());
            throw new ServiceSystemException(PerformanceResultEnum.DATA_NOT_FIND);
        }
        //同一货主，同一开票标识，同一结算方式的结算单可支持手动合并
        List<String> settlementNos = new ArrayList<>();
        //货主编码
        Long ownerUserNo = null;
        //开票标识：1网运单 2普通单
        Integer invoiceType = null;
        //结算方式  1装车净重 2卸车净重
        Integer settlementWay = null;
        //开票公司ID
        Integer invoicingCompanyId = null;
        //开票公司上报标识
        Integer reportFlag  = null ;
        String tip = "结算单状态“待对账”且同一货主，同一开票标识，同一结算方式，同一开票公司，同一上报标识 支持合并";
        SettlementOwner merge = null;
        String settlementNo = settlementMqHandlerService.settlementNoGenerate();

        for (SettlementOwner item : settlementOwnersList) {
            if(Objects.equals(SettlementOwnerEnum.MergeSettlementFlag.MERGE.getCode(),item.getMergeSettlementFlag())
                    || Objects.equals(SettlementOwnerEnum.MergeStatus.YES.getCode(),item.getMergeStatus())){
                log.warn("货主结算单号:{}  结算单不允许二次合并",item.getSettlementNo());
                throw new ServiceSystemException(PerformanceResultEnum.DATA_REPEAT,"结算单不允许二次合并");
            }
            if(!Objects.equals(SettlementOwnerEnum.Status.TO_BE_ACCOUNT.getCode(),item.getStatus())){
                log.warn("货主结算单号:{}  的结算状态非待对账",item.getSettlementNo());
                throw new ServiceSystemException(PerformanceResultEnum.DATA_REPEAT,tip);
            }
            if(Objects.nonNull(ownerUserNo) && !Objects.equals(ownerUserNo,item.getOwnerUserNo())){
                log.warn("货主结算单号:{}  在本批次中不属于同一货主",item.getSettlementNo());
                throw new ServiceSystemException(PerformanceResultEnum.DATA_REPEAT,tip);
            }
            if(Objects.nonNull(invoiceType) && !Objects.equals(invoiceType,item.getInvoiceType())){
                log.warn("货主结算单号:{}  在本批次中不属于同一开票标志",item.getSettlementNo());
                throw new ServiceSystemException(PerformanceResultEnum.DATA_REPEAT,tip);
            }
            if(Objects.nonNull(settlementWay) && !Objects.equals(settlementWay,item.getSettlementWay())){
                log.warn("货主结算单号:{}  在本批次中不属于同一结算方式",item.getSettlementNo());
                throw new ServiceSystemException(PerformanceResultEnum.DATA_REPEAT,tip);
            }
            if(Objects.nonNull(invoicingCompanyId) && !Objects.equals(invoicingCompanyId,item.getInvoicingCompanyId())){
                log.warn("货主结算单号:{}  在本批次中不属于同一开票公司",item.getSettlementNo());
                throw new ServiceSystemException(PerformanceResultEnum.DATA_REPEAT,tip);
            }
            if(Objects.nonNull(reportFlag) && !Objects.equals(reportFlag,item.getReportFlag())){
                log.warn("货主结算单号:{}  在本批次中不属于同一上报标识",item.getSettlementNo());
                throw new ServiceSystemException(PerformanceResultEnum.DATA_REPEAT,tip);
            }
            ownerUserNo  = item.getOwnerUserNo();
            invoiceType  = item.getInvoiceType();
            settlementWay = item.getSettlementWay();
            invoicingCompanyId = item.getInvoicingCompanyId();
            reportFlag = item.getReportFlag();
            settlementNos.add(item.getSettlementNo());

            //合并数据
            if(Objects.nonNull(merge)){
                merge.setWeight(merge.getWeight().add(item.getWeight()));
                merge.setFreight(merge.getFreight().add(item.getFreight()));
                merge.setLossFreight(merge.getLossFreight().add(item.getLossFreight()));
                merge.setLossWeight(merge.getLossWeight().add(item.getLossWeight()));
                merge.setPrepayFreight(merge.getPrepayFreight().add(item.getPrepayFreight()));
                merge.setSettlementFreight(merge.getSettlementFreight().add(item.getSettlementFreight()));
                merge.setInvoiceFreight(merge.getInvoiceFreight().add(item.getInvoiceFreight()));

            }else{
                merge = item;
                merge.setId(null);
                merge.setId(null);
                merge.setOrderNo("");
                merge.setSettlementNo(settlementNo);
                merge.setSettlementSubNo(null);
                merge.setMergedBy(loginUserInfo.getUserName());
                merge.setMergeTime(LocalDateTime.now());
                merge.setMergeSettlementFlag(SettlementOwnerEnum.MergeSettlementFlag.MERGE.getCode());
            }

        }

        //更新结算单
        settlementOwnerDao.updateSettlementMerge(settlementNo,settlementNos,loginUserInfo.getUserName(),now);
        //插入合并单
        settlementOwnerDao.saveEntity(merge);
        //更新货主运单计费明细
        settlementOwnerDetailDao.updateSettlementMerge(settlementNo,settlementNos);
    }

}
