package cn.superdesk.uniorder.service.invoice.customer.impl.bak;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.superdesk.uniorder.common.bizScene.invoice.customer.InvoiceApplyCustomerScene;
import cn.superdesk.uniorder.common.enums.accounting.AccountingOrderDimCreateByEnum;
import cn.superdesk.uniorder.common.enums.accounting.AccountingOrderInvoiceApplyStatusEnum;
import cn.superdesk.uniorder.common.enums.accounting.AccountingOrderTypeDimEnum;
import cn.superdesk.uniorder.common.enums.common.*;
import cn.superdesk.uniorder.common.enums.invoice.InvoiceApplyAuditStatusEnum;
import cn.superdesk.uniorder.common.enums.invoice.common.InvoiceTypeMoudelXModeEnum;
import cn.superdesk.uniorder.common.enums.invoice.common.PurchaserCompanyTypeEnum;
import cn.superdesk.uniorder.common.enums.invoice.customer.*;
import cn.superdesk.uniorder.common.enums.order.UnifiedOrderCreditTypeDefaultEnum;
import cn.superdesk.uniorder.common.exception.UnifiedOrderRuntimeException;
import cn.superdesk.uniorder.common.exception.constants.ExceptionMsg;
import cn.superdesk.uniorder.common.json.AnJsonUtils;
import cn.superdesk.uniorder.common.lamda.AnLamdaUtils;
import cn.superdesk.uniorder.common.numerical.AnBeanUtils;
import cn.superdesk.uniorder.common.numerical.AnIntegerUtils;
import cn.superdesk.uniorder.common.numerical.AnLongUtils;
import cn.superdesk.uniorder.common.numerical.AnStringUtils;
import cn.superdesk.uniorder.common.rest.response.R;
import cn.superdesk.uniorder.common.security.JwtUtil;
import cn.superdesk.uniorder.common.security.dto.LoginSysUser;
import cn.superdesk.uniorder.dao.convert.Dto2DtoConvertUtils;
import cn.superdesk.uniorder.dao.entity.accounting.score.customer.AccountingScoreCustomer;
import cn.superdesk.uniorder.dao.entity.accounting.unified.customer.AccountingUnifiedCustomer;
import cn.superdesk.uniorder.dao.entity.base.UnifiedOrderGoods;
import cn.superdesk.uniorder.dao.entity.invoice.common.InvoiceBankInfo;
import cn.superdesk.uniorder.dao.entity.invoice.common.InvoiceType;
import cn.superdesk.uniorder.dao.entity.invoice.customer.InvoiceApply;
import cn.superdesk.uniorder.dao.entity.invoice.customer.InvoiceApplyExample;
import cn.superdesk.uniorder.dao.entity.order.ExpressCompany;
import cn.superdesk.uniorder.dao.entity.organisation.SysEnterprise;
import cn.superdesk.uniorder.dao.entity.organisation.SysEnterpriseExtInvoice;
import cn.superdesk.uniorder.dao.entity.sys.SysOderUser;
import cn.superdesk.uniorder.dao.entity.sys.SysUser;
import cn.superdesk.uniorder.dao.mapper.invoice.customer.*;
import cn.superdesk.uniorder.dao.mapper.order.ExpressCompanyMapper;
import cn.superdesk.uniorder.dto.param.accounting.score.customer.AccountingOrderScoreCustomerNotYetDimCreditScene3QueryCriteria;
import cn.superdesk.uniorder.dto.param.invoice.common.InvoiceTypeCacheCriteria;
import cn.superdesk.uniorder.dto.param.invoice.customer.InvoiceApplyCustomerOpAgainInvoiceApplyForm;
import cn.superdesk.uniorder.dto.param.invoice.customer.InvoiceApplyCustomerOpModifyInvoiceTitleForm;
import cn.superdesk.uniorder.dto.param.invoice.customer.InvoiceApplyCustomerQueryCriteria;
import cn.superdesk.uniorder.dto.param.invoice.customer.InvoiceApplyCustomerQueryCriteriaV2_1;
import cn.superdesk.uniorder.dto.param.organisation.SysEnterpriseExtInvoiceParam;
import cn.superdesk.uniorder.dto.vo._common.EnumSelectLongStringVo;
import cn.superdesk.uniorder.dto.vo.invoice.common.InvoiceBankInfoVo;
import cn.superdesk.uniorder.dto.vo.invoice.customer.*;
import cn.superdesk.uniorder.dto.vo.thirdpart.szhtxx.electronicInvoice.SzhtxxElectronicInvoiceFptxxListItemVo;
import cn.superdesk.uniorder.event.invoiceApplyCustomerTrigger.InvoiceApplyCustomerTriggerEventPublisher;
import cn.superdesk.uniorder.event.invoiceApplyCustomerTrigger.TailUpdateAccountingScoreCustomerFieldInvoiceStatusEvent;
import cn.superdesk.uniorder.service.accounting.score.customer.AccountingScoreCustomerService;
import cn.superdesk.uniorder.service.accounting.unified.customer.AccountingUnifiedCustomerService;
import cn.superdesk.uniorder.service.base.ScoreOrderService;
import cn.superdesk.uniorder.service.base.UnifiedOrderCreditService;
import cn.superdesk.uniorder.service.base.UnifiedOrderGoodsService;
import cn.superdesk.uniorder.service.invoice.common.InvoiceBankInfoService;
import cn.superdesk.uniorder.service.invoice.common.InvoiceTypeService;
import cn.superdesk.uniorder.service.invoice.customer.InvoiceApplyCustomerService;
import cn.superdesk.uniorder.service.invoice.customer.InvoiceApplyXGoodsService;
import cn.superdesk.uniorder.service.organisation.SysEnterpriseExtInvoiceService;
import cn.superdesk.uniorder.service.organisation.SysEnterpriseService;
import cn.superdesk.uniorder.service.setting.UnifiedSnConfigService;
import cn.superdesk.uniorder.service.sys.SysOderUserService;
import cn.superdesk.uniorder.service.sys.SysUserService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @Description: Java类作用描述
 * @Author: linjinyu
 * @CreateDate: 2022/3/1 上午11:54
 * @UpdateUser: linjinyu
 * @UpdateDate: 2022/3/1 上午11:54
 * @UpdateRemark: 修改内容
 * @Version: 1.0
 */
@Slf4j
@Service
public class InvoiceApplyCustomerServiceImpl implements InvoiceApplyCustomerService {


    @Autowired
    private InvoiceApplyMapper                    invoiceApplyMapper;
    @Autowired
    private InvoiceApplyMapperEx                  invoiceApplyMapperEx;
    @Autowired
    private InvoiceApplyMapperExScore             invoiceApplyMapperExScore;
    @Autowired
    private InvoiceApplyMapperExScoreV2_1         invoiceApplyMapperExScoreV2_1;
    @Autowired
    private InvoiceApplyMapperExUnified           invoiceApplyMapperExUnified;
    @Autowired
    private InvoiceApplyMapperExUnifiedCompatible invoiceApplyMapperExUnifiedCompatible;
    @Autowired
    private InvoiceApplyMapperExUnifiedClear      invoiceApplyMapperExUnifiedClear;


    @Autowired
    private InvoiceApplyXGoodsMapper  invoiceApplyXGoodsMapper;
    @Autowired
    private InvoiceApplyXGoodsService invoiceApplyXGoodsService;


    @Autowired
    private InvoiceBankInfoService invoiceBankInfoService;


    @Autowired
    private AccountingScoreCustomerService   accountingScoreCustomerService;
    @Autowired
    private AccountingUnifiedCustomerService accountingUnifiedCustomerService;

    @Autowired
    private ScoreOrderService scoreOrderService;

    @Autowired
    private UnifiedOrderGoodsService unifiedOrderGoodsService;

    @Autowired
    private UnifiedOrderCreditService unifiedOrderCreditService;
//


    @Autowired
    private SysOderUserService sysOderUserService;

//	@Autowired
//	private SysConfigService     sysConfigService;

    @Autowired
    private UnifiedSnConfigService unifiedSnConfigService;


    @Autowired
    private ExpressCompanyMapper expressCompanyMapper;

    @Autowired
    private InvoiceTypeService invoiceTypeService;


    @Autowired
    private SysEnterpriseService           sysEnterpriseService;
    @Autowired
    private SysEnterpriseExtInvoiceService sysEnterpriseExtInvoiceService;

    @Autowired
    private SysUserService sysUserService;


    public int updateInvoiceApplyByPrimaryKeySelective(InvoiceApply invoiceApply) {

        return invoiceApplyMapper.updateByPrimaryKeySelective(invoiceApply);
    }

    public int updateFieldBackAccountStatusByCheckRatio(Integer fullCount, Integer seizeCount, Long invoiceApplyId) {

        // return 为 ret 标记 不是计算数量
        if (fullCount.compareTo(0) <= 0) {
            return 0;
        }

        if (seizeCount.compareTo(0) <= 0) {
            return 0;
        }

        InvoiceApplyCustomerBackAccountStatusEnum invoiceApplyBackAccountStatusEnum;
        if (fullCount.compareTo(seizeCount) == 0) {
            invoiceApplyBackAccountStatusEnum = InvoiceApplyCustomerBackAccountStatusEnum.已回款;
        } else {
            invoiceApplyBackAccountStatusEnum = InvoiceApplyCustomerBackAccountStatusEnum.部分回款;
        }

        return updateFieldBackAccountStatusByInvoiceApplyId(invoiceApplyId, invoiceApplyBackAccountStatusEnum);

    }

    public int updateFieldBackAccountStatusByInvoiceApplyId(Long invoiceApplyId, InvoiceApplyCustomerBackAccountStatusEnum invoiceApplyBackAccountStatusEnum) {
//		InvoiceApplyExample example = new InvoiceApplyExample();
//		example.createCriteria()
//				.andIdEqualTo(invoiceApplyId);
        InvoiceApply invoiceApply = new InvoiceApply();
        invoiceApply.setId(invoiceApplyId);
        invoiceApply.setBackAccountStatus(invoiceApplyBackAccountStatusEnum.getKey());

        return invoiceApplyMapper.updateByPrimaryKeySelective(invoiceApply);
    }


    /****************************************** 开票申请 列表的导出Excel数据 start ******************************************/


    /**
     * 客户结算-发票申请管理-opt 导出报表 TODO 目前这个有个问题 Mapper 里边还是 订单维度的 表关联方式 mark by linjinyu 20210317 发现
     *
     * @param params
     * @return
     * @throws UnifiedOrderRuntimeException
     */
    @Override
    public List<ExportExcelInvoiceApplyForceUnifiedDimGoodsVo> findInvoiceApplyFocusUnifiedDimGoods(Map<String, Object> params) throws UnifiedOrderRuntimeException {
        return invoiceApplyMapperExUnified.exportExcelInvoiceApplyFocusUnified(params);
    }

    /**
     * 积分结算-发票申请管理-opt 导出报表
     *
     * @param criteria
     * @return
     * @throws UnifiedOrderRuntimeException
     */
    @Override
    public List<ExportExcelInvoiceApplyCustomerForceScoreDimCreditVo> findInvoiceApplyFocusScoreDimCredit(InvoiceApplyCustomerQueryCriteria criteria) throws UnifiedOrderRuntimeException {


        List<ExportExcelInvoiceApplyCustomerForceScoreDimCreditVo> resultList = invoiceApplyMapperExScore.exportExcelInvoiceApplyFocusScore(criteria);

//        log.info("难道批次为空？\n{}", JSONUtil.toJsonPrettyStr(resultList));

        // 附加信息
        additionalInfoFindInvoiceApplyFocusScoreDimCredit(resultList);

//        清理不对账
        // 如果要求 只要对账数据
        if (ObjectUtil.isNotNull(criteria.getCreditAccountingState()) && criteria.getCreditAccountingState().compareTo(CommonAccountingStateEnum.已对账.getKey()) == 0) {

            // 修正 流水对账 不对账问题
//            if (ObjectUtil.isNotNull(vo.getBatchs()) && vo.getBatchs().equals("wechat")) {
//                x.setAccountingState(CommonAccountingStateEnum.不对账.getKey());
//            } else {
//                x.setAccountingState(CommonAccountingStateEnum.已对账.getKey());
//            }

            List<Predicate<ExportExcelInvoiceApplyCustomerForceScoreDimCreditVo>> filterAccountingStateEq1 = new ArrayList<>();
            filterAccountingStateEq1.add(r -> !r.getBatchs().equals("wechat"));

            // 过滤出客户对账状态位 为 已对账 1
            List<ExportExcelInvoiceApplyCustomerForceScoreDimCreditVo> resultListFilterAccountingStateEq1 = AnLamdaUtils.filters(resultList, filterAccountingStateEq1);

            return resultListFilterAccountingStateEq1;
        }

        return resultList;
    }


    private void additionalInfoFindInvoiceApplyFocusScoreDimCredit(List<ExportExcelInvoiceApplyCustomerForceScoreDimCreditVo> resultList) {

        if (CollUtil.isEmpty(resultList)) {
            return;
        }

        // 别的地方 调用方法 修正关系
//        List<ExportExcelInvoiceApplyCustomerForceScoreDimCreditVo> resultList = invoiceApplyCustomerService.findInvoiceApplyFocusScoreDimCredit(
//                InvoiceApplyCustomerQueryCriteria.builder()
//                        .invoiceApplyIdsSelected(Arrays.asList(invoiceApplyCustomer.getId()))
//                        .creditAccountingState(CommonAccountingStateEnum.已对账.getKey()) // TODO 现在是没作用
//                        .build()
//        );

        List<Long> sysUserIds = new ArrayList<>();

        List<Long> applyUserIds              = resultList.stream().filter(o -> o.getApplyUserId() != null).filter(AnLamdaUtils.distinctByKey(o -> o.getApplyUserId())).map(o -> o.getApplyUserId()).collect(Collectors.toList());
        List<Long> auditUserIds              = resultList.stream().filter(o -> o.getAuditUserId() != null).filter(AnLamdaUtils.distinctByKey(o -> o.getAuditUserId())).map(o -> o.getAuditUserId()).collect(Collectors.toList());
        List<Long> invoiceProgressingUserIds = resultList.stream().filter(o -> o.getInvoiceProgressingUserId() != null).filter(AnLamdaUtils.distinctByKey(o -> o.getInvoiceProgressingUserId())).map(o -> o.getInvoiceProgressingUserId()).collect(Collectors.toList());
        List<Long> makeInvoiceUserIds        = resultList.stream().filter(o -> o.getMakeInvoiceUserId() != null).filter(AnLamdaUtils.distinctByKey(o -> o.getMakeInvoiceUserId())).map(o -> o.getMakeInvoiceUserId()).collect(Collectors.toList());
        List<Long> receiveInvoiceUserIds     = resultList.stream().filter(o -> o.getReceiveInvoiceUserId() != null).filter(AnLamdaUtils.distinctByKey(o -> o.getReceiveInvoiceUserId())).map(o -> o.getReceiveInvoiceUserId()).collect(Collectors.toList());
        List<Long> mailTickUserIds           = resultList.stream().filter(o -> o.getMailTickUserId() != null).filter(AnLamdaUtils.distinctByKey(o -> o.getMailTickUserId())).map(o -> o.getMailTickUserId()).collect(Collectors.toList());
        List<Long> backAccountUserIds        = resultList.stream().filter(o -> o.getBackAccountUserId() != null).filter(AnLamdaUtils.distinctByKey(o -> o.getBackAccountUserId())).map(o -> o.getBackAccountUserId()).collect(Collectors.toList());
        List<Long> updateUserIds             = resultList.stream().filter(o -> o.getUpdateUserId() != null).filter(AnLamdaUtils.distinctByKey(o -> o.getUpdateUserId())).map(o -> o.getUpdateUserId()).collect(Collectors.toList());

        sysUserIds.addAll(applyUserIds);
        sysUserIds.addAll(auditUserIds);
        sysUserIds.addAll(invoiceProgressingUserIds);
        sysUserIds.addAll(makeInvoiceUserIds);
        sysUserIds.addAll(receiveInvoiceUserIds);
        sysUserIds.addAll(mailTickUserIds);
        sysUserIds.addAll(backAccountUserIds);
        sysUserIds.addAll(updateUserIds);

        sysUserIds = sysUserIds.stream().distinct().collect(Collectors.toList());
        log.info("\n{}", JSONUtil.toJsonStr(sysUserIds));
        Map<Long, SysUser> sysUserMap = sysUserService.convertSysUserIds2MapSysUserId2Entity(sysUserIds);

        List<Long> outVirtIds = resultList.stream().map(ExportExcelInvoiceApplyCustomerForceScoreDimCreditVo::getEnterpriseId).distinct().collect(Collectors.toList());

        Map<Long, SysEnterprise>           sysEnterpriseMap           = sysEnterpriseService.findByOutVirtIdsConvertKV(outVirtIds);
        Map<Long, SysEnterpriseExtInvoice> sysEnterpriseExtInvoiceMap = sysEnterpriseExtInvoiceService.findByOutVirtIdsConvertKV(outVirtIds);


        // 20220117 客户发现是错的
        // TODO  "enterpriseName", "companyName", "invoiceBank", "invoiceAccount"
        // TODO  "购方名称", "购方税号", "购方地址电话", "购方银行账号"

        for (ExportExcelInvoiceApplyCustomerForceScoreDimCreditVo vo : resultList) {


            /**
             TODO 积分结算2.1 关系中添加 结算与不结算标识 mark by linjinyu at 20220217
             【后端部分处理-20220217-对映文档-2.积分结算-2.3未对账流水-已整理-20220217】https://www.tapd.cn/33003868/prong/stories/view/1133003868001003945
             目前在对账单中的流水就会标识为已对账,按新逻辑来说,就是微信支付的也会这样标记,然而这里是关系中的是否参考结算,关系表中添加标识是否参与结算,然而关系表中的老数据添加这个标识为结算,新做的对账单才会有可能包含这种存丰结算与不结算的标识
             **/

            // 修正 流水对账 不对账问题
//            if (ObjectUtil.isNotNull(vo.getBatchs()) && vo.getBatchs().equals("wechat")) {
//                x.setAccountingState(CommonAccountingStateEnum.不对账.getKey());
//            } else {
//                x.setAccountingState(CommonAccountingStateEnum.已对账.getKey());
//            }


            /****************************************** 填充 企业 start ******************************************/

            if (null != sysEnterpriseMap.get(vo.getEnterpriseId())) {
                vo.setEnterpriseName(sysEnterpriseMap.get(vo.getEnterpriseId()).getEnterpriseName());
            }

            /****************************************** 填充 企业   end ******************************************/

            /****************************************** 填充 购方发票信息 start ******************************************/

            SysEnterpriseExtInvoice sysEnterpriseExtInvoice = null;

            // SysEnterpriseExtInvoiceId 不为0 证明是新的逻辑 读快照
            if (ObjectUtil.isNotNull(vo.getSysEnterpriseExtInvoiceId()) && vo.getSysEnterpriseExtInvoiceId().compareTo(0L) != 0) {
                sysEnterpriseExtInvoice = AnJsonUtils.toObject(vo.getSysEnterpriseExtInvoiceSnapshot(), SysEnterpriseExtInvoice.class);
            }
            // SysEnterpriseExtInvoiceId 为0 证明是老的逻辑 以企业Id查出发票信息
            else if (null != sysEnterpriseExtInvoiceMap.get(vo.getEnterpriseId())) {
                sysEnterpriseExtInvoice = sysEnterpriseExtInvoiceMap.get(vo.getEnterpriseId());
            }

            if (ObjectUtil.isNotNull(sysEnterpriseExtInvoice)) {

                vo.setPurchaserCompanyName(sysEnterpriseExtInvoice.getCompanyName());
                vo.setPurchaserTaxpayersIDCode(sysEnterpriseExtInvoice.getTaxpayersIDCode());

                vo.setPurchaserBankAccountNumber(StrUtil.format("{}{}", sysEnterpriseExtInvoice.getInvoiceBank(), sysEnterpriseExtInvoice.getInvoiceAccount()));
                vo.setPurchaserAddressPhone(StrUtil.format("{}{}", sysEnterpriseExtInvoice.getInvoiceAddress(), sysEnterpriseExtInvoice.getInvoicePhone()));

                vo.setInvoiceBank(sysEnterpriseExtInvoice.getInvoiceBank());
                vo.setInvoiceAccount(sysEnterpriseExtInvoice.getInvoiceAccount());
                vo.setInvoiceAddress(sysEnterpriseExtInvoice.getInvoiceAddress());
                vo.setInvoicePhone(sysEnterpriseExtInvoice.getInvoicePhone());

                // 购方信息 -> 企业扩展信息-发票抬中
                vo.setPurchaserCompanyType(PurchaserCompanyTypeEnum.getBySelectedInvoiceTitle(sysEnterpriseExtInvoice.getSelectedInvoiceTitle()).getPurchaserCompanyType());
            }

            /****************************************** 填充 购方发票信息   end ******************************************/

            /****************************************** 发票类类 start ******************************************/

            InvoiceType invoiceType = invoiceTypeService.cacheGetEntity(InvoiceTypeCacheCriteria
                    .builder()
                    .hashTable(InvoiceTypeCacheCriteria.HASHTABLE)
                    .hashTableKeyField(InvoiceTypeCacheCriteria.HASHTABLE_KEY_FIELD_ID)
                    .keyField(AnStringUtils.getString(vo.getInvoiceType()))
                    .build()
            );

            if (null != invoiceType) {
                vo.setInvoiceTypeName(invoiceType.getTypeName());
            }

            /****************************************** 发票类类 start ******************************************/

            /****************************************** 开票方式 start ******************************************/

            vo.setInvoiceModeName(InvoiceTypeMoudelXModeEnum.get(vo.getInvoiceMode()).getDesc());

            /****************************************** 开票方式   end ******************************************/

            /****************************************** 修改税率为 税务软件要求 start ******************************************/

//			fixUnifiedOrderGoodsTaxRate(vo);

//			qchNeed20210922

            /****************************************** 修改税率为 税务软件要求   end ******************************************/

        }
    }

    @Deprecated
    private void fixUnifiedOrderGoodsTaxRate(ExportExcelInvoiceApplyCustomerForceScoreDimCreditVo vo) {

        if (null == vo.getUnifiedOrderGoodsTaxRate()) {
            vo.setUnifiedOrderGoodsTaxRate(BigDecimal.ZERO);
        } else {
            BigDecimal temp = vo.getUnifiedOrderGoodsTaxRate().divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
            vo.setUnifiedOrderGoodsTaxRate(temp);
        }

        log.info("修正税率 : {}", vo.getUnifiedOrderGoodsTaxCode());
    }

    /****************************************** 开票申请 列表的导出Excel数据   end ******************************************/


    /****************************************** 发票申请管理 start ******************************************/

    @Override
    public R<List<InvoiceApplyCustomerPageVo>> findViewByPageFocusUnified(Map<String, Object> params, int pageNum, int pageSize) throws UnifiedOrderRuntimeException {

        PageHelper.startPage(pageNum, pageSize);
        List<InvoiceApplyCustomerPageVo>     resultList = invoiceApplyMapperExUnified.selectByCondition(params);
        PageInfo<InvoiceApplyCustomerPageVo> page       = new PageInfo<InvoiceApplyCustomerPageVo>(resultList);
        PageHelper.clearPage();

        return new R<List<InvoiceApplyCustomerPageVo>>(page.getPageNum(), page.getPageSize(), (int) page.getTotal(), resultList);
    }

    @Override
    public List<InvoiceApplyCustomerPageVo> findViewFocusUnified(Map<String, Object> params) throws UnifiedOrderRuntimeException {

        List<InvoiceApplyCustomerPageVo> resultList = invoiceApplyMapperExUnified.selectByCondition(params);

        return resultList;
    }

    @Override
    public InvoiceApplyCustomerHeadDataVo findViewHeadDataFocusUnified(Map<String, Object> params) throws UnifiedOrderRuntimeException {
        return invoiceApplyMapperExUnified.findViewHeadDataFocusUnified(params);
    }

    @Override
    public R<List<InvoiceApplyCustomerPageVo>> findViewByPageFocusScore(InvoiceApplyCustomerQueryCriteria criteria, int pageNum, int pageSize) throws UnifiedOrderRuntimeException {

        PageHelper.startPage(pageNum, pageSize);
        List<InvoiceApplyCustomerPageVo>     resultList = invoiceApplyMapperExScore.findViewByPage(criteria);
        PageInfo<InvoiceApplyCustomerPageVo> page       = new PageInfo<InvoiceApplyCustomerPageVo>(resultList);
        PageHelper.clearPage();

        // 附加信息
        additionalInfoFindViewByPageFocusCommon(resultList);

        return new R<List<InvoiceApplyCustomerPageVo>>(page.getPageNum(), page.getPageSize(), (int) page.getTotal(), resultList);
    }

    @Override
    public List<InvoiceApplyCustomerPageVo> findViewFocusScore(InvoiceApplyCustomerQueryCriteria criteria) {

        List<InvoiceApplyCustomerPageVo> resultList = invoiceApplyMapperExScore.findViewByPage(criteria);

        // 附加信息
        additionalInfoFindViewByPageFocusCommon(resultList);

        return resultList;
    }

    @Override
    public InvoiceApplyCustomerHeadDataVo findViewHeadDataFocusScore(InvoiceApplyCustomerQueryCriteria criteria) throws UnifiedOrderRuntimeException {
        return invoiceApplyMapperExScore.findViewHeadData(criteria);
    }

    @Override
    public R<List<InvoiceApplyCustomerPageVo>> pageQueryInvoiceApplyListFocusScoreV2_1(InvoiceApplyCustomerQueryCriteriaV2_1 queryCriteria) throws UnifiedOrderRuntimeException {

        PageHelper.startPage(queryCriteria.getPageNumber(), queryCriteria.getPageSize());

//        改名 findViewByPage findInvoiceApplyListFocusScoreV2_1
        List<InvoiceApplyCustomerPageVo>     resultList = invoiceApplyMapperExScoreV2_1.findViewByPage(queryCriteria);
        PageInfo<InvoiceApplyCustomerPageVo> page       = new PageInfo<InvoiceApplyCustomerPageVo>(resultList);
        PageHelper.clearPage();

        // 附加信息
        additionalInfoFindViewByPageFocusCommon(resultList);

        patchReviseMark(resultList, LoginSysUser.builder().build());

        return new R<List<InvoiceApplyCustomerPageVo>>(page.getPageNum(), page.getPageSize(), (int) page.getTotal(), resultList);
    }

    @Override
    public List<InvoiceApplyCustomerPageVo> queryInvoiceApplyListFocusScoreV2_1(InvoiceApplyCustomerQueryCriteriaV2_1 criteria) {

        List<InvoiceApplyCustomerPageVo> resultList = invoiceApplyMapperExScoreV2_1.findViewByPage(criteria);

        // 附加信息
        additionalInfoFindViewByPageFocusCommon(resultList);

        patchReviseMark(resultList, LoginSysUser.builder().build());

        return resultList;
    }

    @Override
    public InvoiceApplyCustomerHeadDataVoV2_1 queryInvoiceApplyHeadDataFocusScoreV2_1(InvoiceApplyCustomerQueryCriteriaV2_1 criteria) throws UnifiedOrderRuntimeException {
        return invoiceApplyMapperExScoreV2_1.findViewHeadData(criteria);
    }

    @Override
    public R<List<InvoiceApplyCustomerPageVo>> findInvoiceListByPageFocusScoreV2_1(InvoiceApplyCustomerQueryCriteriaV2_1 queryCriteriaV2_1, LoginSysUser loginSysUser) throws UnifiedOrderRuntimeException {

        PageHelper.startPage(queryCriteriaV2_1.getPageNumber(), queryCriteriaV2_1.getPageSize());

        // 套娃
//        List<InvoiceApplyCustomerPageVo>     resultList = invoiceApplyMapperExScoreV2_1.findInvoiceListByPageV2_1(queryCriteriaV2_1);
        List<InvoiceApplyCustomerPageVo> resultList = findInvoiceListFocusScoreV2_1(queryCriteriaV2_1, loginSysUser);

        PageInfo<InvoiceApplyCustomerPageVo> page = new PageInfo<InvoiceApplyCustomerPageVo>(resultList);
        PageHelper.clearPage();

        return new R<List<InvoiceApplyCustomerPageVo>>(page.getPageNum(), page.getPageSize(), (int) page.getTotal(), resultList);
    }

    @Override
    public List<InvoiceApplyCustomerPageVo> findInvoiceListFocusScoreV2_1(InvoiceApplyCustomerQueryCriteriaV2_1 queryCriteriaV2_1, LoginSysUser loginSysUser) {

        List<InvoiceApplyCustomerPageVo> resultList = invoiceApplyMapperExScoreV2_1.findInvoiceListByPageV2_1(queryCriteriaV2_1);

        // 附加信息
        additionalInfoFindViewByPageFocusCommon(resultList);

        patchReviseMark(resultList, loginSysUser);

        return resultList;
    }

    public void patchReviseMark(List<InvoiceApplyCustomerPageVo> resultList, LoginSysUser loginSysUser) {

        resultList.forEach(vo -> {
            if (ObjectUtil.isNotNull(vo.getNeedReviseMark())
                    && vo.getNeedReviseMark().compareTo(CommonNeedReviseMarkEnum.修正.getKey()) == 0) {


                /****************************************** TODO 在此修一下数据吧 start ******************************************/

                if (ArrayUtil.contains(
                        InvoiceApplyCustomerScene.statusV2_1_Array_InvoiceProgressingSceneRevise(),
                        vo.getInvoiceStatus())
                ) {
                    // 修信息
                    patchFixInfo(vo.getId(), loginSysUser);
                    // 修统计
                    patchFixStatistics(vo.getId(), loginSysUser);
                }


                /****************************************** TODO 在此修一下数据吧   end ******************************************/

                InvoiceApply invoiceApplyEntity = new InvoiceApply();
                invoiceApplyEntity.setId(vo.getId());
                invoiceApplyEntity.setNeedReviseMark(CommonNeedReviseMarkEnum.正常.getKey());

                updateInvoiceApplyByPrimaryKeySelective(invoiceApplyEntity);
            }
        });

    }

    @Override
    public InvoiceApplyCustomerHeadDataVoV2_1 findInvoiceHeadDataFocusScoreV2_1(InvoiceApplyCustomerQueryCriteriaV2_1 queryCriteriaV2_1, LoginSysUser loginSysUser) throws UnifiedOrderRuntimeException {

        return invoiceApplyMapperExScoreV2_1.findInvoiceHeadDataV2_1(queryCriteriaV2_1);
    }

    /**
     * 附加信息 补人员信息 补状态名称
     *
     * @param resultList
     */
    private void additionalInfoFindViewByPageFocusCommon(List<InvoiceApplyCustomerPageVo> resultList) {

        if (CollUtil.isEmpty(resultList)) {
            return;
        }

        List<Long> sysUserIds = new ArrayList<>();

        List<Long> applyUserIds              = resultList.stream().filter(o -> o.getApplyUserId() != null).filter(AnLamdaUtils.distinctByKey(o -> o.getApplyUserId())).map(o -> o.getApplyUserId()).collect(Collectors.toList());
        List<Long> auditUserIds              = resultList.stream().filter(o -> o.getAuditUserId() != null).filter(AnLamdaUtils.distinctByKey(o -> o.getAuditUserId())).map(o -> o.getAuditUserId()).collect(Collectors.toList());
        List<Long> invoiceProgressingUserIds = resultList.stream().filter(o -> o.getInvoiceProgressingUserId() != null).filter(AnLamdaUtils.distinctByKey(o -> o.getInvoiceProgressingUserId())).map(o -> o.getInvoiceProgressingUserId()).collect(Collectors.toList());
        List<Long> makeInvoiceUserIds        = resultList.stream().filter(o -> o.getMakeInvoiceUserId() != null).filter(AnLamdaUtils.distinctByKey(o -> o.getMakeInvoiceUserId())).map(o -> o.getMakeInvoiceUserId()).collect(Collectors.toList());
        List<Long> receiveInvoiceUserIds     = resultList.stream().filter(o -> o.getReceiveInvoiceUserId() != null).filter(AnLamdaUtils.distinctByKey(o -> o.getReceiveInvoiceUserId())).map(o -> o.getReceiveInvoiceUserId()).collect(Collectors.toList());
        List<Long> mailTickUserIds           = resultList.stream().filter(o -> o.getMailTickUserId() != null).filter(AnLamdaUtils.distinctByKey(o -> o.getMailTickUserId())).map(o -> o.getMailTickUserId()).collect(Collectors.toList());
        List<Long> backAccountUserIds        = resultList.stream().filter(o -> o.getBackAccountUserId() != null).filter(AnLamdaUtils.distinctByKey(o -> o.getBackAccountUserId())).map(o -> o.getBackAccountUserId()).collect(Collectors.toList());
        List<Long> updateUserIds             = resultList.stream().filter(o -> o.getUpdateUserId() != null).filter(AnLamdaUtils.distinctByKey(o -> o.getUpdateUserId())).map(o -> o.getUpdateUserId()).collect(Collectors.toList());

        sysUserIds.addAll(applyUserIds);
        sysUserIds.addAll(auditUserIds);
        sysUserIds.addAll(invoiceProgressingUserIds);
        sysUserIds.addAll(makeInvoiceUserIds);
        sysUserIds.addAll(receiveInvoiceUserIds);
        sysUserIds.addAll(mailTickUserIds);
        sysUserIds.addAll(backAccountUserIds);
        sysUserIds.addAll(updateUserIds);

        sysUserIds = sysUserIds.stream().distinct().collect(Collectors.toList());
        log.info("\n{}", JSONUtil.toJsonStr(sysUserIds));
        Map<Long, SysUser> sysUserMap = sysUserService.convertSysUserIds2MapSysUserId2Entity(sysUserIds);

        List<Long>               outVirtIds       = resultList.stream().map(InvoiceApplyCustomerPageVo::getOutVirtId).distinct().collect(Collectors.toList());
        Map<Long, SysEnterprise> sysEnterpriseMap = sysEnterpriseService.findByOutVirtIdsConvertKV(outVirtIds);

        Map<Long, InvoiceType> invoiceTypeMap = invoiceTypeService.convertToMapFieldId2Entity();

        for (InvoiceApplyCustomerPageVo vo : resultList) {

            // 补状态名称
            vo.setAuditStatusName(InvoiceApplyAuditStatusEnum.getDesc(vo.getAuditStatus()));
            vo.setInvoiceProgressingStatusName(InvoiceApplyCustomerInvoiceProgressingStatusEnum.getDesc(vo.getInvoiceStatus()));
            vo.setMakeInvoiceStatusName(InvoiceApplyCustomerMakeInvoiceStatusEnum.getDesc(vo.getMakeInvoiceStatus()));
            vo.setReceiveInvoiceStatusName(InvoiceApplyCustomerReceiveInvoiceStatusEnum.getDesc(vo.getReceiveInvoiceStatus()));
            vo.setMailTickStatusName(InvoiceApplyCustomerMailTickStatusEnum.getDesc(vo.getMailTickStatus()));
            vo.setBackAccountStatusName(InvoiceApplyCustomerBackAccountStatusEnum.getDesc(vo.getBackAccountStatus()));

            if (ObjectUtil.isNotNull(vo.getAccountingOrderInvoiceStatus())) {
                vo.setAccountingOrderInvoiceStatusName(AccountingOrderInvoiceApplyStatusEnum.get(vo.getAccountingOrderInvoiceStatus()).getDesc());
            }

            // 补 开票方式
            if (ObjectUtil.isNotNull(vo.getInvoiceMode())) {
                vo.setInvoiceModeName(InvoiceTypeMoudelXModeEnum.get(vo.getInvoiceMode()).getDesc());
            } else {
                vo.setInvoiceModeName("异常");
            }

            /**************************************** mark by linjinyu at 20220516 v2.3 start ****************************************/

            // 补 订单类型-订单来源-引用enum CommonServiceNoEnum
            if (ObjectUtil.isNotNull(vo.getServiceNo())) {
                vo.setServiceNoName(CommonServiceNoEnum.getByServiceNo(vo.getServiceNo()).getServiceName());
            } else {
                vo.setServiceNoName(CommonServiceNoEnum.UNKNOW.getServiceName());
            }
            // 补 操作来源-引用enum CommonSourceFromEnum
            if (ObjectUtil.isNotNull(vo.getSourceFrom())) {
                vo.setSourceFromName(CommonSourceFromEnum.getBySourceFromCode(vo.getSourceFrom()).getSourceFromName());
            } else {
                vo.setSourceFromName(CommonSourceFromEnum.未知来源.getSourceFromName());
            }

            /**************************************** mark by linjinyu at 20220516 v2.3 start ****************************************/


            // 补 发票种类
            if (invoiceTypeMap.get(AnLongUtils.getLong(vo.getInvoiceType())) != null) {
                vo.setInvoiceTypeName(invoiceTypeMap.get(AnLongUtils.getLong(vo.getInvoiceType())).getTypeName());
            } else {
                vo.setInvoiceTypeName("异常");
            }

            // 补 企业信息
            if (ObjectUtil.isNotNull(sysEnterpriseMap.get(vo.getOutVirtId()))) {
                vo.setOutVirtName(sysEnterpriseMap.get(vo.getOutVirtId()).getEnterpriseName());
                vo.setOutVirtNamesStr(sysEnterpriseMap.get(vo.getOutVirtId()).getEnterpriseName());
            } else {
                vo.setOutVirtName("异常");
                vo.setOutVirtNamesStr("异常");
            }


            // 补人员信息
            if (sysUserMap.get(vo.getApplyUserId()) != null) {
                vo.setApplyUserName(sysUserMap.get(vo.getApplyUserId()).getFullname());
            }
            if (sysUserMap.get(vo.getAuditUserId()) != null) {
                vo.setAuditUserName(sysUserMap.get(vo.getAuditUserId()).getFullname());
            }
            if (sysUserMap.get(vo.getInvoiceProgressingUserId()) != null) {
                vo.setInvoiceProgressingUserName(sysUserMap.get(vo.getInvoiceProgressingUserId()).getFullname());
            }
            if (sysUserMap.get(vo.getMakeInvoiceUserId()) != null) {
                vo.setMakeInvoiceUserName(sysUserMap.get(vo.getMakeInvoiceUserId()).getFullname());
            }
            if (sysUserMap.get(vo.getReceiveInvoiceUserId()) != null) {
                vo.setReceiveInvoiceUserName(sysUserMap.get(vo.getReceiveInvoiceUserId()).getFullname());
            }
            if (sysUserMap.get(vo.getMailTickUserId()) != null) {
                vo.setMailTickUserName(sysUserMap.get(vo.getMailTickUserId()).getFullname());
            }
            if (sysUserMap.get(vo.getBackAccountUserId()) != null) {
                vo.setBackAccountUserName(sysUserMap.get(vo.getBackAccountUserId()).getFullname());
            }
            if (sysUserMap.get(vo.getUpdateUserId()) != null) {
                vo.setUpdateUserName(sysUserMap.get(vo.getUpdateUserId()).getFullname());
            }


        }
    }

    /****************************************** 发票申请管理   end ******************************************/


    /**
     * 审核?-操作 opt 同意?拒绝 TODO 写死 1-未审核;2-同意;3-拒绝;
     *
     * @param params
     * @param loginSysUser
     * @throws UnifiedOrderRuntimeException
     */
    @Override
    @Transactional
    public TailUpdateAccountingScoreCustomerFieldInvoiceStatusEvent opAudit(Map<String, Object> params, LoginSysUser loginSysUser) throws UnifiedOrderRuntimeException {

        List<Long> affectedAccountingOrderIds = new ArrayList<>();

//		LoginSysUser loginSysUser = JwtUtil.getLoginSysUser(token);

        Long    invoiceApplyId = AnLongUtils.getLong(params.get("id"));
        Integer auditStatus    = AnIntegerUtils.getInteger(params.get("auditStatus"));

        InvoiceApply invoiceApply = invoiceApplyMapper.selectByPrimaryKey(invoiceApplyId);

        if (null == invoiceApply) {
            return TailUpdateAccountingScoreCustomerFieldInvoiceStatusEvent
                    .builder()
                    .affectedAccountingOrderIds(affectedAccountingOrderIds)
                    .dim(AccountingOrderTypeDimEnum.未知订单)
                    .loginSysUser(loginSysUser)
                    .build();
        }

        // 更新 审核人 信息
        InvoiceApply invoiceApply4Update = new InvoiceApply();

        invoiceApply4Update.setId(invoiceApplyId);
        invoiceApply4Update.setAuditUserId(loginSysUser.getSysUserId());
        invoiceApply4Update.setAuditTime(DateUtil.date());
        invoiceApply4Update.setAuditStatus(auditStatus);

        invoiceApplyMapper.updateByPrimaryKeySelective(invoiceApply4Update);


        /****************************************** 连带更新这个发票申请 的 对账单 的 开发票状态 ******************************************/

//		InvoiceApplyAuditStatusEnum
//		未审核(1, "未审核"),
//		同意(2, "同意"),
//		拒绝(3, "拒绝");
        // TODO 写死 1-未审核;2-同意;3-拒绝;
        if (auditStatus.compareTo(InvoiceApplyAuditStatusEnum.拒绝.getKey()) == 0) {

            // 得出受影响的对账单 ids
            affectedAccountingOrderIds = invoiceApplyXGoodsService.getAffectedAccountingOrderIdsByInvoiceApplyId(invoiceApplyId);

            /**
             * 通过 对账单 ids(得出受影响的对账单 ids)
             * 再去 较验 对账单 发票状态
             */
//			processTailUpdateAccountingOrderInvoiceStatus(affectedAccountingOrderIds, AccountingOrderTypeDimEnum.get(invoiceApply.getAccountingOrderType()));
//			invoiceApplyTriggerEventPublisher.triggerTailUpdateAccountingOrderInvoiceStatus(affectedAccountingOrderIds, AccountingOrderTypeDimEnum.get(invoiceApply.getAccountingOrderType()));


        }

        return TailUpdateAccountingScoreCustomerFieldInvoiceStatusEvent
                .builder()
                .affectedAccountingOrderIds(affectedAccountingOrderIds)
                .dim(AccountingOrderTypeDimEnum.get(invoiceApply.getAccountingOrderType()))
                .loginSysUser(loginSysUser)
                .build();

        /****************************************** 连带更新这个发票申请 的 对账单 的 开发票状态 ******************************************/
    }


    /**
     * 通过 对账单 ids 来 再查
     * 再去 较验 对账单 发票状态
     *
     * @param affectedAccountingOrderIds
     * @param loginSysUser
     */
    public void processTailUpdateAccountingOrderInvoiceStatus(List<Long> affectedAccountingOrderIds, AccountingOrderTypeDimEnum dim, LoginSysUser loginSysUser) {

        // 提前结束 TODO 是不是会有空的情况
        if (CollUtil.isEmpty(affectedAccountingOrderIds)) {
            return;
        }

        log.info("processTailUpdateAccountingOrderInvoiceStatus params \n{}\n{}\n{}",
                JSONUtil.toJsonStr(affectedAccountingOrderIds),
                dim.getDesc(),
                JSONUtil.toJsonStr(loginSysUser)
        );

        // xml
        // 0 未开票
        // 1 全部开票
        // 2 部分开票
        // 0-未开票;1-已开票;2-部分开票;

        for (Long accountingOrderId : affectedAccountingOrderIds) {

            switch (dim) {
                case 一般订单:
                    // 更新 对账单 开票状态
                    invoiceApplyXGoodsService.checkInvoiceStatusByAccountingOrderIdAndUpdateAccountingEntityFocusUnified(accountingOrderId, loginSysUser);
                    break;
                case 积分订单:
                    // TODO 按 对账单id 去查 发票状态 的方法还没有做
                    // 更新 对账单 开票状态
                    invoiceApplyXGoodsService.checkInvoiceStatusByAccountingOrderIdAndUpdateAccountingEntityFocusScore(accountingOrderId, CommonBeRelatedEnum.级联, loginSysUser);
                    break;
            }
        }
    }


    private static String fetchGroupKeyByInvoiceOrderIdAndOrderSnAndDzOrderIdAndDzOrderGoodsId(InvoiceApplyDetailDimOrderItemVo viewDzOrder) {
        return viewDzOrder.getInvoiceOrderId()
                + "_" + viewDzOrder.getOrderSn()
                // aucuo.id AS dz_order_id
                + "_" + viewDzOrder.getDzOrderId()
                + "_" + viewDzOrder.getDzOrderGoodsId();
    }

    private static String fetchGroupKeyByOrderSnAndUnifiedOrderGoodsId(UnifiedOrderGoods unifiedOrderGoods) {

        return unifiedOrderGoods.getOrderSn()
                + "_" + unifiedOrderGoods.getId();
    }

    private static BigDecimal fetchGroupValue(UnifiedOrderGoods unifiedOrderGoods) {
        return unifiedOrderGoods.getPrice().multiply(new BigDecimal(unifiedOrderGoods.getQuantity()));
    }

    /**
     * 反转
     *
     * @param mapByGroupKeyAndGroupValue
     * @return
     */
    private static Map<BigDecimal, String> reverse(Map<String, BigDecimal> mapByGroupKeyAndGroupValue) {

        Map<BigDecimal, String> mapReverseByGroupKeyAndGroupValue = new HashMap<>();

        for (Map.Entry<String, BigDecimal> _entry : mapByGroupKeyAndGroupValue.entrySet()) {
            mapReverseByGroupKeyAndGroupValue.put(_entry.getValue(), _entry.getKey());
        }

        return mapReverseByGroupKeyAndGroupValue;
    }

    private static List<BigDecimal> aggregate(Map<String, BigDecimal> mapByGroupKeyAndGroupValue) {

        List<BigDecimal> aggregateInput = new ArrayList<>();

        for (Map.Entry<String, BigDecimal> _entry : mapByGroupKeyAndGroupValue.entrySet()) {
            aggregateInput.add(_entry.getValue());
        }

        return aggregateInput;
    }


    /**
     * TODO 重构 mark by linjinyu at 20210201
     *
     * @param invoiceApplyId
     * @return
     */
    public List<InvoiceApplyDetailDimOrderItemVo> findInvoiceApplyDetail20210201Dim1Unified2Goods(Long invoiceApplyId) {

        // invoiceApply.getRealAmount() 老的版本是没有数值的
        InvoiceApply invoiceApply = findById(invoiceApplyId);

        List<InvoiceApplyDetailDimOrderItemVo> dzOrders = new ArrayList<>();


        // 此地方要加工 mark by linjinyu at 20210401
        dzOrders = invoiceApplyMapperExUnifiedCompatible.findInvoiceApplyDetail20210201Dim1Unified2Goods(invoiceApplyId);


        // 这个证明是个老版本 要再分支做
        if (null == invoiceApply.getRealAmount()) {
            return dzOrders;
        }

        if (CollUtil.isEmpty(dzOrders)) {
            return dzOrders;
        }

        // TODO 要添加 验证 看明细加起来是否等于开票申请的金额 可以改装成 开票申请的验证程序

        // 包含两个情况
        // 1. 关联不到uog
        // 2. 只是单纯的金额不对
        BigDecimal goodsAmount = dzOrders
                .stream()
                .map(item -> item.getPrice() == null ? BigDecimal.ZERO : item.getPrice().multiply(new BigDecimal(item.getTotal())))
                .reduce(BigDecimal.ZERO, BigDecimal::add);

//		if (invoiceApply.getRealAmount().compareTo(goodsAmount) != 0) {
//
//			// TODO
//
//			List<String> processOrderSns = dzOrders.stream()
//					.filter(o -> null != o.getOrderSn())
//					.filter(AnLamdaUtils.distinctByKey(o -> o.getOrderSn()))
//					.map(o -> o.getOrderSn())
//					.collect(Collectors.toList());
//
//			// TODO 先写死只处理一个订单的
//			// TODO 还是不能确定 宣布 死亡 mark by linjinyu at 202102011919
////			if (processOrderSns.size() == 1) {
////
////				List<UnifiedOrderGoods> processUnifiedOrderGoodsList = unifiedOrderGoodsService.findByOrderSns(processOrderSns);
////
//////			collect(Collectors.toMap(UnifiedOrderGoods::getId, v -> v, (k, v) -> v));
////
////				Map<String, BigDecimal> mapByGroupKeyAndGroupValue = processUnifiedOrderGoodsList.stream().collect(Collectors.toMap(o -> fetchGroupKeyByOrderSnAndUnifiedOrderGoodsId(o), o -> fetchGroupValue(o)));
////
////				Map<BigDecimal, String> mapReverseByGroupKeyAndGroupValue = reverse(mapByGroupKeyAndGroupValue);
////
////				log.info("\n\n{}\n{}\n\n", JsonUtils.toJson(mapByGroupKeyAndGroupValue), JsonUtils.toJson(mapReverseByGroupKeyAndGroupValue));
////
////				BigDecimal       eqTarget       = invoiceApply.getRealAmount();
////				List<BigDecimal> aggregateInput = aggregate(mapByGroupKeyAndGroupValue);
////
////				Algorithm001 algorithm001 = new Algorithm001();
////
////				List<BigDecimal> result = algorithm001.run(aggregateInput, eqTarget);
////
////				log.info("\n\n{}\n\n", JsonUtils.toJson(result));
////
////				// TODO
////
////				for (BigDecimal toBeUnifiedOrderGoodsId : result) {
////
////					String orderSnJoinUnifiedOrderGoodsIdString = mapReverseByGroupKeyAndGroupValue.get(toBeUnifiedOrderGoodsId);
////
////					String[] orderSnJoinUnifiedOrderGoodsIdArray = orderSnJoinUnifiedOrderGoodsIdString.split("_");
////
////					List<Predicate<ViewDzOrder>> predicatesByTransportGoods = new ArrayList<>();
////					predicatesByTransportGoods.add(r -> r.getOrderSn() != null && r.getOrderSn().equals(orderSnJoinUnifiedOrderGoodsIdArray[0]));
////
////					List<ViewDzOrder> predicatesByPlusGoodsFilter = AnLamdaUtils.filters(dzOrders, predicatesByTransportGoods);
////
////				}
////
////
////			}
//
//
//		}


        /****************************************** 不要看系列 start ******************************************/
//		if (CollUtil.isEmpty(dzOrders)) {
        // 方法2
//						dzOrders = invoiceApplyMapperExUnifiedCompatible.findInvoiceApplyDetailOldDim1Unified2Goods(invoiceApplyDetailVo.getId());
//				FROM
//				invoice_order invo
//				LEFT JOIN accounting_unified_customer aucu ON invo.dz_id = aucu.id
//				LEFT JOIN accounting_unified_customer_order auco ON invo.dz_order_id = auco.id
//				LEFT JOIN accounting_unified_customer_order_goods aucog ON auco.id = aucog.dz_order_id
//				LEFT JOIN invoice_bank invb ON invo.bank_id = invb.id
//						log.info("\n\n\n 方法1 : {}", dzOrders.size());
        // 方法3
//				<!-- 客户结算-发票申请-查看详情 OLD 等 findInvoiceApplyDetailNewDim1Unified2Goods -->
//				dzOrders = invoiceApplyMapperEx.findDzOrderByGoodId(invoiceApplyDetailVo.getId());
//		}
        /****************************************** 不要看系列   end ******************************************/


        return dzOrders;


    }

    /**
     * 前端-客户结算-开票申请-详情
     * 前端-客户结算-发票管理-详情
     *
     * @param params
     * @return
     * @throws UnifiedOrderRuntimeException
     */
    @Override
    public InvoiceApplyCustomerDetailDimGoodsVo getUnifiedCustomerInvoice2GoodsDetail(Map<String, Object> params) throws UnifiedOrderRuntimeException {

        log.info("\n前端-客户结算-开票申请-详情\n" +
                "前端-客户结算-发票管理-详情\n" +
                "params : {}\n", JSONUtil.toJsonStr(params));

//		eg:
//		// 发票申请Id
//		params.put("id", getLong("id"));

        Long invoiceApplyId = AnLongUtils.getLong(params.get("id"));

        InvoiceApply invoiceApply = invoiceApplyMapper.selectByPrimaryKey(invoiceApplyId);

        if (null == invoiceApply) {
            return null;
        }

        log.info("\n前端-客户结算-发票申请-详情\n{}", JSONUtil.toJsonStr(invoiceApply));


        /****************************************** 最终返回 start ******************************************/
        InvoiceApplyCustomerDetailDimGoodsVo finalResponseVo = new InvoiceApplyCustomerDetailDimGoodsVo();
        /****************************************** 最终返回   end ******************************************/

        /****************************************** 查出开票详情 main 部分 TODO 待优化 重构 start ******************************************/

        // TODO 有问题的用法
//		params : {"id":6127}
        List<InvoiceApplyCustomerPageVo> invoiceApplyPageList = invoiceApplyMapperExUnified.selectByCondition(params);
        /****************************************** 查出开票详情 main 部分 TODO 待优化 重构 start ******************************************/


        if (CollUtil.isNotEmpty(invoiceApplyPageList)) {

            InvoiceApplyCustomerPageVo invoiceApplyPage = invoiceApplyPageList.get(0);

            // 问题 mark by linjinyu at 20210312
//			AnBeanUtils.copyProperties(invoiceApplyPage, invoiceApplyDetailVo);
            // 问题 mark by linjinyu at 20210610
//			finalResponseVo = AnBeanUtils.copy(invoiceApplyPage, InvoiceApplyDetailDimGoodsVo.class);
            // 先修改成这样, 有空再重构
            Dto2DtoConvertUtils.invoiceApplyPage2InvoiceApplyDetailDimGoodsVo(invoiceApplyPage, finalResponseVo);

            // 附加信息
            finalResponseVo.setAuditStatusName(InvoiceApplyAuditStatusEnum.get(finalResponseVo.getAuditStatus()).getDesc());// 审核状态 1-未审核;2-已同意;3-已拒绝
            finalResponseVo.setMakeInvoiceStatusName(InvoiceApplyCustomerMakeInvoiceStatusEnum.get(finalResponseVo.getMakeInvoiceStatus()).getDesc());// 开票状态 0-未开票;1-已开票;2-重新开票;
            finalResponseVo.setMailTickStatusName(InvoiceApplyCustomerMailTickStatusEnum.get(finalResponseVo.getMailTickStatus()).getDesc());// 寄票状态:0-未寄票;1-已寄票
            finalResponseVo.setBackAccountStatusName(InvoiceApplyCustomerBackAccountStatusEnum.get(finalResponseVo.getBackAccountStatus()).getDesc());// 回款状态 0-未回款;1-部分回款;2全部回款;


            // 对账单类型 1-一般;2-积分;
            //		invoiceApply.getAccountingOrderType();
            // 对账单 创建维度:0-订单;1-商品;2-流水;
            //		invoiceApply.getDimCreateBy();


            switch (AccountingOrderDimCreateByEnum.get(invoiceApply.getDimCreateBy())) {
                case 订单:

                    List<InvoiceApplyDetailDimOrderItemVo> dzOrders = new ArrayList<>();

                    /****************************************** 填充明细 TODO 重构 start ******************************************/

                    dzOrders = findInvoiceApplyDetail20210201Dim1Unified2Goods(finalResponseVo.getId());

                    log.info("\n\n\n 方法1 : {}", dzOrders.size());


                    /****************************************** 填充明细 TODO 重构   end ******************************************/

                    /****************************************** 重构1 20201113 start ******************************************/

                    // LEFT JOIN sys_oder_user AS real_order_user ON auco.realname_id = real_order_user.user_id
                    // LEFT JOIN sys_oder_user AS examine_order_user ON auco.examine_id = examine_order_user.user_id
                    // real_order_user.realname AS realname,
                    // examine_order_user.realname AS examine_name,

                    /****************************************** 填充 人的信息 start ******************************************/
                    // 得出 排除空
                    List<Long> sysOrderUserIds1 = dzOrders.stream().filter(o -> null != o.getRealnameId()).filter(AnLamdaUtils.distinctByKey(o -> o.getRealnameId())).map(o -> o.getRealnameId()).collect(Collectors.toList());
                    List<Long> sysOrderUserIds2 = dzOrders.stream().filter(o -> null != o.getExamineId()).filter(AnLamdaUtils.distinctByKey(o -> o.getExamineId())).map(o -> o.getExamineId()).collect(Collectors.toList());

                    List<Long> sysOrderUserIdsAll = new ArrayList<>();

                    sysOrderUserIdsAll.addAll(sysOrderUserIds1);
                    sysOrderUserIdsAll.addAll(sysOrderUserIds2);

                    List<Long> sysOrderUserIdsFilter = new ArrayList<>();
                    sysOrderUserIdsFilter = sysOrderUserIdsAll.parallelStream().distinct().collect(Collectors.toList());

                    Map<Long, SysOderUser> resultSysUser = sysOderUserService.convertSysOderUserIds2MapKeyValue(sysOrderUserIdsFilter);

                    for (InvoiceApplyDetailDimOrderItemVo vo : dzOrders) {

                        if (null != vo.getRealnameId() && null != resultSysUser.get(vo.getRealnameId())) {
                            vo.setRealname(resultSysUser.get(vo.getRealnameId()).getRealname());
                        } else {
                            vo.setRealname("-");
                        }

                        if (null != vo.getExamineId() && null != resultSysUser.get(vo.getExamineId())) {
                            vo.setExamineName(resultSysUser.get(vo.getExamineId()).getRealname());
                        } else {
                            vo.setExamineName("-");
                        }
                    }
                    /****************************************** 填充 人的信息   end ******************************************/


                    /****************************************** 重构1 20201113   end ******************************************/


                    finalResponseVo.setDzOrders(dzOrders);
                    break;
                case 商品:

                    List<InvoiceApplyDetailDimGoodsItemV3Vo> invoiceApplyDetailDimGoodsV3VoList = new ArrayList<>();

                    invoiceApplyDetailDimGoodsV3VoList = invoiceApplyMapperExUnifiedClear.findInvoiceApplyDetailInnerInfo(invoiceApplyId);

                    // 附加信息
                    invoiceApplyDetailDimGoodsV3VoList.forEach(AnLamdaUtils.consumerWithIndex((item, index) -> {
                        item.setRowNum(index + 1);
                    }));

                    finalResponseVo.setInnerOrderJoinGoodsList(invoiceApplyDetailDimGoodsV3VoList);

                    // 补充信息 mark by linjinyu at 20210526
                    // 开票信息:
                    // 1. 对账单编号 accountingOrderSn -> private List<String> accountingOrderSns;
                    // 1. 企业信息   purchaseVirtName  -> private List<String> outVirtNames;
                    // 1. 订单数     orderSn -> private Integer orderSnStatisticsCount;
                    // 1. 账单金额? 开票金额 realAmount? goodsAmount累加? -> private BigDecimal invoicedStatisticsCountAmount;


                    List<String> accountingOrderSns = invoiceApplyDetailDimGoodsV3VoList.stream().filter(AnLamdaUtils.distinctByKey(o -> o.getAccountingOrderSn())).map(o -> o.getAccountingOrderSn()).collect(Collectors.toList());
                    finalResponseVo.setAccountingOrderSns(accountingOrderSns);
                    finalResponseVo.setAccountingOrderSnsStr(AnStringUtils.stringListConvertToString(accountingOrderSns));

                    List<String> outVirtNames = invoiceApplyDetailDimGoodsV3VoList.stream().filter(AnLamdaUtils.distinctByKey(o -> o.getPurchaseVirtName())).map(o -> o.getPurchaseVirtName()).collect(Collectors.toList());
                    finalResponseVo.setOutVirtNamesStr(AnStringUtils.stringListConvertToString(outVirtNames));
                    finalResponseVo.setOutVirtNames(outVirtNames);

                    // orderSnCount
                    Long orderSnStatisticsCount = invoiceApplyDetailDimGoodsV3VoList.stream().filter(AnLamdaUtils.distinctByKey(o -> o.getOrderSn())).map(o -> o.getOrderSn()).collect(Collectors.counting());
                    finalResponseVo.setOrderSnStatisticsCount(orderSnStatisticsCount.longValue());

                    BigDecimal invoicedStatisticsCountAmount = invoiceApplyDetailDimGoodsV3VoList
                            .stream()
                            .map(item -> item.getGoodsAmount() == null ? BigDecimal.ZERO : item.getGoodsAmount())
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                    finalResponseVo.setInvoicedStatisticsCountAmount(invoicedStatisticsCountAmount);

                    break;

                case 流水:
                    throw new UnifiedOrderRuntimeException(500, "客户结算 发票 目前不支持 流水维度");

                default:
                    break;
            }


            return finalResponseVo;
        }

        return null;
    }

    /**
     * 积分结算 查看详情
     * 适配 <=积分结算2.0,积分结算2.1
     *
     * @param criteria
     * @return
     * @throws UnifiedOrderRuntimeException
     */
    @Override
    public InvoiceApplyCustomerDetailDimCreditVo getInvoiceApplyCustomerDetailDimCredit(InvoiceApplyCustomerQueryCriteria criteria, LoginSysUser loginSysUser) throws UnifiedOrderRuntimeException {


//		eg:
//		// 发票申请Id
//		params.put("id", getLong("id"));

        Long id = criteria.getId();

        InvoiceApply invoiceApply = invoiceApplyMapper.selectByPrimaryKey(id);

        log.info("\n\ngetUnifiedCustomerInvoice2CreditDetail \n\ninvoiceApply :\n\n{}\n\n", JSONUtil.toJsonStr(invoiceApply));

        if (null == invoiceApply) {
            return null;
        }

        // List<InvoiceApplyPageVo> invoiceApplyPageList = invoiceApplyMapperExScore.findViewByPage(criteria);
        List<InvoiceApplyCustomerPageVo> invoiceApplyPageList = findViewFocusScore(criteria);

        log.info("getUnifiedCustomerInvoice2CreditDetail invoiceApplyPageList :\n{}", JSONUtil.toJsonStr(invoiceApplyPageList));

        InvoiceApplyCustomerDetailDimCreditVo invoiceApplyCustomerDetailDimCreditVo = new InvoiceApplyCustomerDetailDimCreditVo();

        if (CollUtil.isNotEmpty(invoiceApplyPageList)) {

            InvoiceApplyCustomerPageVo invoiceApplyPageVo = invoiceApplyPageList.get(0);

            // 问题  mark by linjinyu at 20210312
//			AnBeanUtils.copyProperties(invoiceApplyPage, invoiceApplyDetailDimCreditVo);
            invoiceApplyCustomerDetailDimCreditVo = AnBeanUtils.copy(invoiceApplyPageVo, InvoiceApplyCustomerDetailDimCreditVo.class);

            // 处理 sysEnterpriseExtInvoiceId 不为0的情况
            if (ObjectUtil.isNotNull(invoiceApplyCustomerDetailDimCreditVo)
                    && ObjectUtil.isNotNull(invoiceApplyCustomerDetailDimCreditVo.getSysEnterpriseExtInvoiceId())
                    && invoiceApplyCustomerDetailDimCreditVo.getSysEnterpriseExtInvoiceId().compareTo(0L) != 0) {
                invoiceApplyCustomerDetailDimCreditVo.setSysEnterpriseExtInvoiceSnapshotEntity(AnJsonUtils.toObject(invoiceApplyCustomerDetailDimCreditVo.getSysEnterpriseExtInvoiceSnapshot(), SysEnterpriseExtInvoiceParam.class));
            }

            /****************************************** start ******************************************/


//			superdesk-uniorder/superdesk-uniorder-web/src/main/java/cn/superdesk/uniorder/controller/accounting/customer/ScoreCustomerStatementController.java
            // 240
            // 得到 发票申请 X 积分流水
            // |---- 筛选条件
            List<Long> idsCredit = invoiceApplyXGoodsService.findCreditSetByInvoicApplyId(id);

            List<InvoiceApplyDetailDimCreditItemVo> setCreditListObj = scoreOrderService.getScoreOrderReconciliationNotYetScene3(
                    AccountingOrderScoreCustomerNotYetDimCreditScene3QueryCriteria.builder()
                            .idsCredit(idsCredit).build(), loginSysUser
            );

            /******************************************   end ******************************************/

            invoiceApplyCustomerDetailDimCreditVo.setDzOrders(setCreditListObj);

            return invoiceApplyCustomerDetailDimCreditVo;
        }

        return null;
    }

    @Override
    public InvoiceApplyCustomerDetailDimCreditVoV2_1 getInvoiceApplyCustomerDetailDimCreditV2_1(InvoiceApplyCustomerQueryCriteriaV2_1 criteria, LoginSysUser loginSysUser) throws UnifiedOrderRuntimeException {

        Long invoiceApplyId = criteria.getId();


        InvoiceApply invoiceApplyCustomerEntity = invoiceApplyMapper.selectByPrimaryKey(invoiceApplyId);

        log.info("\n\ngetUnifiedCustomerInvoice2CreditDetail \n\ninvoiceApply :\n\n{}\n\n", JSONUtil.toJsonStr(invoiceApplyCustomerEntity));

        if (null == invoiceApplyCustomerEntity) {
            return null;
        }

        /****************************************** TODO 在此修一下数据吧 start ******************************************/

        if (ArrayUtil.contains(
                InvoiceApplyCustomerScene.statusV2_1_Array_InvoiceProgressingSceneRevise(),
                invoiceApplyCustomerEntity.getInvoiceStatus())
        ) {
            // 修信息
            patchFixInfo(invoiceApplyCustomerEntity.getId(), loginSysUser);
            // 修统计
            patchFixStatistics(invoiceApplyCustomerEntity.getId(), loginSysUser);
        }


        /****************************************** TODO 在此修一下数据吧   end ******************************************/


//		List<InvoiceApplyCustomerPageVo> invoiceApplyPageList = findViewFocusScore(criteria);
        List<InvoiceApplyCustomerPageVo> invoiceApplyPageList = queryInvoiceApplyListFocusScoreV2_1(criteria);

        if (CollUtil.isEmpty(invoiceApplyPageList)) {
            return null;
        }

        InvoiceApplyCustomerPageVo invoiceApplyPageVo = invoiceApplyPageList.get(0);
        invoiceApplyPageVo.setAccountingOrderIdsStr(AnStringUtils.longListConvertToString(Arrays.asList(invoiceApplyPageVo.getAccountingOrderId())));
        invoiceApplyPageVo.setAccountingOrderSnsStr(AnStringUtils.stringListConvertToString(Arrays.asList(invoiceApplyPageVo.getAccountingOrderSn())));
        // 购方信息
        SysEnterpriseExtInvoiceParam sysEnterpriseExtInvoiceSnapshotEntity = null;
        // 销方信息
        InvoiceBankInfoVo invoiceBankInfoVo = null;

        /****************************************** 购方信息 start ******************************************/


        // 处理 sysEnterpriseExtInvoiceId 不为0的情况
        if (ObjectUtil.isNotNull(invoiceApplyPageVo)
                && ObjectUtil.isNotNull(invoiceApplyPageVo.getSysEnterpriseExtInvoiceId())
                && invoiceApplyPageVo.getSysEnterpriseExtInvoiceId().compareTo(0L) != 0) {
            sysEnterpriseExtInvoiceSnapshotEntity = AnJsonUtils.toObject(invoiceApplyPageVo.getSysEnterpriseExtInvoiceSnapshot(), SysEnterpriseExtInvoiceParam.class);
        }

        /****************************************** 购方信息   end ******************************************/

        /****************************************** 销方信息 start ******************************************/

        AccountingScoreCustomer accountingScoreCustomer = null;
        String                  accountingOrderSn       = null;

        if (StrUtil.isNotBlank(invoiceApplyCustomerEntity.getAccountingOrderSn())) {
            accountingOrderSn = invoiceApplyCustomerEntity.getAccountingOrderSn();
            accountingScoreCustomer = accountingScoreCustomerService.findByAccountingOrderSn(invoiceApplyCustomerEntity.getAccountingOrderSn());
        } else {

            // TODO affectedAccountingOrderIds 这里查不到是什么问题? mark by linjinyu at 20220428
            // 查证 因为 已作废 已红冲 在 表 invoiceApplyXGoods 中的关系没有了
            List<Long> affectedAccountingOrderIds = invoiceApplyXGoodsService.getAffectedAccountingOrderIdsByInvoiceApplyId(invoiceApplyId);

            List<AccountingScoreCustomer> affectedAccountingOrders = accountingScoreCustomerService.findByIds(affectedAccountingOrderIds);

            if (CollUtil.isNotEmpty(affectedAccountingOrders)) {
                accountingScoreCustomer = affectedAccountingOrders.get(0);
                accountingOrderSn = accountingScoreCustomer.getAccountingOrderSn();
            }
        }

        if (ObjectUtil.isNull(accountingScoreCustomer)) {
            throw new UnifiedOrderRuntimeException(500, "无法找到相对映的对账单数据");
        }


        if (StrUtil.isNotBlank(accountingScoreCustomer.getInvoiceBankInfoSnapshot())) {
            invoiceBankInfoVo = AnJsonUtils.toObject(accountingScoreCustomer.getInvoiceBankInfoSnapshot(), InvoiceBankInfoVo.class);
        } else {
            InvoiceBankInfo invoiceBankInfo = invoiceBankInfoService.getInvoiceBankInfoByIdOrNullByDefault(accountingScoreCustomer.getBankInfoId());
            invoiceBankInfoVo = AnBeanUtils.copy(invoiceBankInfo, InvoiceBankInfoVo.class);
        }

        /****************************************** 销方信息   end ******************************************/

        /****************************************** 积分流水 start ******************************************/

        List<InvoiceApplyDetailDimCreditItemVo> setCreditListObj = new ArrayList<>();

        if (ArrayUtil.contains(
                InvoiceApplyCustomerScene.statusV2_1_Array_InvoiceProgressingSceneRevise(),
                invoiceApplyCustomerEntity.getInvoiceStatus())
        ) {

            // superdesk-uniorder/superdesk-uniorder-web/src/main/java/cn/superdesk/uniorder/controller/accounting/customer/ScoreCustomerStatementController.java
            // 240
            // 得到 发票申请 X 积分流水
            // |---- 筛选条件
            List<Long> idsCredit = invoiceApplyXGoodsService.findCreditSetByInvoicApplyId(invoiceApplyId);

            setCreditListObj = scoreOrderService.getScoreOrderReconciliationNotYetScene3(
                    AccountingOrderScoreCustomerNotYetDimCreditScene3QueryCriteria
                            .builder()
                            .idsCredit(idsCredit)
                            .build(),
                    loginSysUser
            );
        }

        /****************************************** 积分流水   end ******************************************/


        /******************************************   end ******************************************/


        return InvoiceApplyCustomerDetailDimCreditVoV2_1.builder()
                .invoiceApplySelectList(frontEndSelectByAccountingOrderSn(accountingOrderSn, AccountingOrderTypeDimEnum.积分订单))
                .invoiceApplyMain(invoiceApplyPageVo)
                .creditList(setCreditListObj)
                .bankInfo(invoiceBankInfoVo)
                .sysEnterpriseExtInvoiceSnapshotEntity(sysEnterpriseExtInvoiceSnapshotEntity).build();


    }


    /**
     * 删除 发票申请
     *
     * @param invoiceApplyId
     * @param loginSysUser
     * @return
     */
    public int opDelete(Long invoiceApplyId, LoginSysUser loginSysUser) {

        // 得出 发票申请关联对账单Ids
        List<Long> affectedAccountingOrderIds = invoiceApplyXGoodsService.getAffectedAccountingOrderIdsByInvoiceApplyId(invoiceApplyId);

        return opDelete(invoiceApplyId, affectedAccountingOrderIds, loginSysUser);
    }

    @Autowired
    private InvoiceApplyCustomerTriggerEventPublisher invoiceApplyCustomerTriggerEventPublisher;

    public int opDelete(Long invoiceApplyId, List<Long> affectedAccountingOrderIds, LoginSysUser loginSysUser) {

        // 标志 20220509 start ----
//        // op撤销开票 这些都 复位吧
//        List<Long> processUnifiedOrderCreditIds = invoiceApplyXGoodsService.findCreditSetByInvoicApplyId(invoiceApplyId);
//        unifiedOrderCreditService.updateFieldInvoiceApplyStatusByUnifiedOrderCreditIds(processUnifiedOrderCreditIds, UnifiedOrderCreditInvoiceApplyStatusEnum.待申请);
//        unifiedOrderCreditService.updateFieldInvoiceMakeStatusByUnifiedOrderCreditIds(processUnifiedOrderCreditIds, UnifiedOrderCreditInvoiceMakeStatusEnum.待开票);
//        unifiedOrderCreditService.updateFieldBackAccountStatusByUnifiedOrderCreditIds(processUnifiedOrderCreditIds, UnifiedOrderCreditBackAccountStatusEnum.未回款);
        // 标志 20220509   end ----


        int retMain   = 0;
        int retSecond = 0;

        // 标志 20220509 start ---- 逻辑修改为
        // 包含流水的三个状态复位
        // 1. InvoiceApplyStatus
        // 2. InvoiceMakeStatus
        // 3. BackAccountStatus
        retSecond = invoiceApplyXGoodsService.dumpXByInvoiceApplyId(invoiceApplyId);

        // 标志 20220509   end ----


        if (CollUtil.isNotEmpty(affectedAccountingOrderIds)) {

            /****************************************  start ****************************************/

            // 之前在此 标记包体001 这个更新受影响的对账单的开票申请状态有个问题，这个状态主要是两边去比，冲突点是，还有别的操作要用到这个关系，时机问题，得优化成

            // 标志 20220509 start ----
            // 对账单相关信息没有在 invoiceApply, 要用 invoiceApplyId 去查 invoiceOrder
//            InvoiceApplyXGoodsExample invoiceOrderExample = new InvoiceApplyXGoodsExample();
//            invoiceOrderExample.createCriteria()
//                    .andInvoiceApplyIdEqualTo(invoiceApplyId);
//
//            retSecond = invoiceApplyXGoodsMapper.deleteByExample(invoiceOrderExample);
            // 标志 20220509   end ----

            /****************************************  start ****************************************/


            /****************************************** 标记包体001 start ******************************************/

            // 恢复对账单 发票申请状态 = 未开票 (20201023 注释 修正为下边代码 会检查 对账单 发票申请状态)
//            AccountingScoreCustomerExample accountingScoreCustomerExample = new AccountingScoreCustomerExample();
//            accountingScoreCustomerExample.createCriteria()
//                    .andIdIn(accountingOrderIds);
//            AccountingScoreCustomer forUpdateInvoiceStatus = new AccountingScoreCustomer();
//            // 20201023 修正 直接 未开票 是有问题要去检查
//            forUpdateInvoiceStatus.setInvoiceStatus(AccountingOrderInvoiceStatusEnum.未开票.getKey());
//            accountingScoreCustomerMapper.updateByExampleSelective(forUpdateInvoiceStatus, accountingScoreCustomerExample);

            // 20220302 屏蔽 改为事件且延迟
//			affectedAccountingOrderIds.forEach(accountingOrderId -> {
//				invoiceApplyXGoodsService.checkInvoiceStatusByAccountingOrderIdAndUpdateAccountingEntityFocusScore(accountingOrderId);
//			});

            // 实际方法为自身 void processTailUpdateAccountingOrderInvoiceStatus(List<Long> affectedAccountingOrderIds, AccountingOrderTypeDimEnum dim);
            invoiceApplyCustomerTriggerEventPublisher.triggerTailUpdateAccountingOrderFieldInvoiceStatus(
                    TailUpdateAccountingScoreCustomerFieldInvoiceStatusEvent.builder()
                            .affectedAccountingOrderIds(affectedAccountingOrderIds)
                            .dim(AccountingOrderTypeDimEnum.积分订单)
                            .invoiceApplyId(invoiceApplyId)
                            .loginSysUser(loginSysUser)
                            .build());

            /****************************************** 标记包体001   end ******************************************/

        }

        retMain = invoiceApplyMapper.deleteByPrimaryKey(invoiceApplyId);

        if (retMain > 0 && retSecond > 0) {
            return 1;
        } else {
            return 0;
        }

    }

    @Override
    public int opModifyInvoiceTitle(InvoiceApplyCustomerOpModifyInvoiceTitleForm form, LoginSysUser loginSysUser) {

        int ret = 0;

        SysEnterpriseExtInvoice sysEnterpriseExtInvoice = sysEnterpriseExtInvoiceService.findById(form.getSysEnterpriseExtInvoiceId());

        if (ObjectUtil.isNotEmpty(sysEnterpriseExtInvoice)) {

            InvoiceApply invoiceApply = new InvoiceApply();

            invoiceApply.setId(form.getInvoiceApplyId());

            invoiceApply.setSysEnterpriseExtInvoiceId(form.getSysEnterpriseExtInvoiceId());
            invoiceApply.setSysEnterpriseExtInvoiceSnapshot(JSONUtil.toJsonStr(sysEnterpriseExtInvoice));

            invoiceApply.setUpdateTime(DateUtil.date());
            invoiceApply.setUpdateUserId(loginSysUser.getSysUserId());

            invoiceApply.setUpdateTime(DateUtil.date());
            invoiceApply.setUpdateUserId(loginSysUser.getSysUserId());

            ret = invoiceApplyMapper.updateByPrimaryKeySelective(invoiceApply);

        }

        log.info("opModifyInvoiceTitle params {} {}\n", JSONUtil.toJsonStr(form), JSONUtil.toJsonStr(loginSysUser), JSONUtil.toJsonStr(sysEnterpriseExtInvoice));

        return ret;

    }

    /**
     * 操作-opt 发票登记 (过) TODO 还是得重构 mark by linjinyu at 20210311
     *
     * @param params
     * @param loginSysUser
     * @throws UnifiedOrderRuntimeException
     */
    @Override
    public void opRegister(Map<String, Object> params, LoginSysUser loginSysUser) throws UnifiedOrderRuntimeException {

//		LoginSysUser loginSysUser = JwtUtil.getLoginSysUser(token);


        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        Long   invoiceApplyId = Long.valueOf(params.get("id").toString());
        String invoiceNumber  = params.get("invoiceNumber").toString();
        String dateStr        = params.get("datestr").toString();


        // 1. 判定发票号是不是重复登记的问题
        InvoiceApplyExample example = new InvoiceApplyExample();
        example.createCriteria()
                .andInvoiceNumberEqualTo(invoiceNumber)
                .andMakeInvoiceStatusEqualTo(InvoiceApplyCustomerMakeInvoiceStatusEnum.已开票.getKey());
        List<InvoiceApply> invoiceApplyList = invoiceApplyMapper.selectByExample(example);

        if (CollUtil.isNotEmpty(invoiceApplyList)) {
            throw new UnifiedOrderRuntimeException(ExceptionMsg.INVOICE_EXIST);
        }

        // 2. 更新发票主体的 相关信息
        InvoiceApply invoiceApply = new InvoiceApply();
        invoiceApply.setId(invoiceApplyId);
        // |---- 开票登记(处理)人
        invoiceApply.setMakeInvoiceUserId(loginSysUser.getSysUserId());
        // |---- 开票日期
        try {
            invoiceApply.setMakeInvoiceTime(sdf.parse(dateStr));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        invoiceApply.setMakeInvoiceStatus(InvoiceApplyCustomerMakeInvoiceStatusEnum.已开票.getKey());
        // |---- 发票号 税局出来的
        invoiceApply.setInvoiceNumber(invoiceNumber);
        invoiceApplyMapper.updateByPrimaryKeySelective(invoiceApply);
    }

    /**
     * 操作-opt 寄票登记 (过)  TODO 还是得重构 mark by linjinyu at 20210311
     *
     * @param sendInvoiceRegisterList
     * @param loginSysUser
     * @throws UnifiedOrderRuntimeException
     */
    @Deprecated
    @Override
    @Transactional
    public void invoiceRegisterSend(List<Map> sendInvoiceRegisterList, LoginSysUser loginSysUser) throws UnifiedOrderRuntimeException {

//		LoginSysUser loginSysUser = JwtUtil.getLoginSysUser(token);

        for (Map map : sendInvoiceRegisterList) {

            InvoiceApply invoiceApply = new InvoiceApply();

            invoiceApply.setId(Long.valueOf(map.get("id").toString()));

            // 已邮寄 不在这里展现 InvoiceStatus 作为 开票进展状态
//			invoiceApply.setInvoiceStatus(InvoiceApplyCustomerInvoiceProgressingStatusEnum.已邮寄.getKey());

            invoiceApply.setMailTickTime(DateUtil.date());
            invoiceApply.setMailTickUserId(loginSysUser.getSysUserId());
            invoiceApply.setMailTickStatus(InvoiceApplyCustomerMailTickStatusEnum.已寄票.getKey());

            invoiceApply.setExpressCompanyId(Long.valueOf(map.get("expressCompanyId").toString()));
            if (map.get("expressNo") != null) {
                invoiceApply.setExpressNo(map.get("expressNo").toString());
            }

            invoiceApplyMapper.updateByPrimaryKeySelective(invoiceApply);
        }
    }

    /**
     * 操作-opt 重新开票
     *
     * @param params
     * @param loginSysUser
     * @throws UnifiedOrderRuntimeException
     */
    @Override
    @Transactional
    public TailUpdateAccountingScoreCustomerFieldInvoiceStatusEvent opAgainSzhtxxElectronicInvoice(
            InvoiceApplyCustomerOpAgainInvoiceApplyForm form,
            InvoiceApply invoiceApplyEntity,
            SzhtxxElectronicInvoiceFptxxListItemVo fptxxListItemVo,
            LoginSysUser loginSysUser) throws UnifiedOrderRuntimeException {

        // 如果这个发票信息 回款状态 0-未回款;1-部分回款;2全部回款;
        // 意思 就是回款过的就不能重新开票

        Integer[] passBackAccountStatusArray = {
                InvoiceApplyCustomerBackAccountStatusEnum.未回款.getKey(),
                InvoiceApplyCustomerBackAccountStatusEnum.发票红冲.getKey()
        };

        if (!ArrayUtil.contains(passBackAccountStatusArray, invoiceApplyEntity.getBackAccountStatus())) {
            // 该发票已回款
            throw new UnifiedOrderRuntimeException(ExceptionMsg.INVOICE_HAVE_BACK);
        }


        // 发票申请审核状态 变成 拒绝
        invoiceApplyEntity.setAuditStatus(InvoiceApplyAuditStatusEnum.拒绝.getKey());

        // 登记开票状态 变成 重新开票 且 清除 发票号
        // 【【结算中心-测试环境】积分结算-发票申请管理-线上开票方式【重新开票】后，无需影响其“开票状态”，仍显示“已开票”即可】https://www.tapd.cn/33003868/bugtrace/bugs/view?bug_id=1133003868001004900
//        invoiceApplyEntity.setMakeInvoiceStatus(InvoiceApplyCustomerMakeInvoiceStatusEnum.重新开票.getKey());

        // 申请状态 变成 已红冲
        invoiceApplyEntity.setInvoiceStatus(InvoiceApplyCustomerInvoiceProgressingStatusEnum.已红冲.getKey());

        invoiceApplyEntity.setUpdateTime(DateUtil.date());
        invoiceApplyEntity.setUpdateUserId(loginSysUser.getSysUserId());

        // 原因
        invoiceApplyEntity.setRemark2(form.getReason());

        invoiceApplyMapper.updateByPrimaryKey(invoiceApplyEntity);


        // 得出受影响的对账单 ids
        List<Long> affectedAccountingOrderIds = invoiceApplyXGoodsService.getAffectedAccountingOrderIdsByInvoiceApplyId(invoiceApplyEntity.getId());

        // 对账单相关信息没有在 invoiceApply, 要用 invoiceApplyId 去查 invoiceOrder
//        InvoiceApplyXGoodsExample invoiceOrderExample = new InvoiceApplyXGoodsExample();
//        invoiceOrderExample.createCriteria()
//                .andInvoiceApplyIdEqualTo(invoiceApplyEntity.getId());
//
//        int retSecond = invoiceApplyXGoodsMapper.deleteByExample(invoiceOrderExample);

        int retSecond = 0;

        // 标志 20220509 start ---- 逻辑修改为
        // 包含流水的三个状态复位
        // 1. InvoiceApplyStatus
        // 2. InvoiceMakeStatus
        // 3. BackAccountStatus
        retSecond = invoiceApplyXGoodsService.dumpXByInvoiceApplyId(invoiceApplyEntity.getId());

        /**
         * 通过 对账单 ids(得出受影响的对账单 ids)
         * 再去 较验 对账单 发票状态
         */
        return TailUpdateAccountingScoreCustomerFieldInvoiceStatusEvent
                .builder()
                .affectedAccountingOrderIds(affectedAccountingOrderIds)
                .dim(AccountingOrderTypeDimEnum.积分订单)
                .invoiceApplyId(invoiceApplyEntity.getId())
                .loginSysUser(loginSysUser)
                .build();

        // 实际方法为自身 void processTailUpdateAccountingOrderInvoiceStatus(List<Long> affectedAccountingOrderIds, AccountingOrderTypeDimEnum dim);
//        invoiceApplyCustomerTriggerEventPublisher.triggerTailUpdateAccountingOrderInvoiceStatus(
//                TailUpdateAccountingOrderInvoiceStatusEvent
//                        .builder()
//                        .affectedAccountingOrderIds(affectedAccountingOrderIds)
//                        .dim(AccountingOrderTypeDimEnum.积分订单)
//                        .invoiceApplyId(invoiceApplyEntity.getId())
//                        .loginSysUser(loginSysUser)
//                        .build());

    }

    /**
     * 客户结算-发票管理-opt 导入发票信息
     *
     * @param list
     * @param token
     * @throws UnifiedOrderRuntimeException
     */
    @Override
    @Transactional
    public String importInvoiceExcel(List<Map<String, Object>> list, String token) throws UnifiedOrderRuntimeException {

        LoginSysUser loginSysUser = JwtUtil.getLoginSysUser(token);

        List<InvoiceApply> processInvoiceApplyArrayList = new ArrayList<>();

        boolean flag  = true;
        String  error = "";
        int     h     = 1;

        for (Map<String, Object> map : list) {

            String invoiceApplySn = map.get("invoiceApplySn").toString();
            String invoiceNumber  = map.get("invoiceNumber").toString();

            InvoiceApplyExample example = new InvoiceApplyExample();
            example.createCriteria()
                    .andInvoiceApplySnEqualTo(invoiceApplySn)
//					.andAuditStatusEqualTo(InvoiceApplyAuditStatusEnum.同意.getKey())
            ;
            List<InvoiceApply> invoiceApplyList = invoiceApplyMapper.selectByExample(example);

            if (CollUtil.isNotEmpty(invoiceApplyList)) {

                InvoiceApply invoiceApply = invoiceApplyList.get(0);

                invoiceApply.setMakeInvoiceStatus(InvoiceApplyCustomerMakeInvoiceStatusEnum.已开票.getKey());
                invoiceApply.setMakeInvoiceUserId(loginSysUser.getSysUserId());
                invoiceApply.setMakeInvoiceTime(DateUtil.date());

                invoiceApply.setInvoiceNumber(invoiceNumber);

                processInvoiceApplyArrayList.add(invoiceApply);

            } else {
                flag = false;
                error += "第" + h + "行 , " + invoiceApplySn + " , 该<发票申请号>错误 或 不存在 或 审核状态 未审核通过(不等于 已同意). \n";
            }

            InvoiceApplyExample example1 = new InvoiceApplyExample();
            example1.createCriteria()
                    .andInvoiceNumberEqualTo(invoiceNumber)// 发票号 税局 产生的
                    .andMakeInvoiceStatusEqualTo(InvoiceApplyCustomerMakeInvoiceStatusEnum.已开票.getKey());
            List<InvoiceApply> invoiceApplyList1 = invoiceApplyMapper.selectByExample(example1);

            if (invoiceApplyList1 != null && invoiceApplyList1.size() > 0) {
                flag = false;
                error += "第" + h + "行 , " + invoiceNumber + " , 该<发票号>已存在, 不能重复导入. \n";
            }

            h++;
        }

        if (flag) {
            for (InvoiceApply invoiceApply : processInvoiceApplyArrayList) {
                invoiceApplyMapper.updateByPrimaryKeySelective(invoiceApply);
            }
        }
//		else {
//			throw new SuperdeskUniOrderException(500, error);
//		}

        return error;
    }

    /**
     * 客户结算-发票管理-opt 导入寄票信息
     *
     * @param list
     * @param token
     * @throws UnifiedOrderRuntimeException
     */
    @Override
    @Transactional
    public String importSendInvoiceExcel(List<Map<String, Object>> list, String token) throws UnifiedOrderRuntimeException {

        LoginSysUser loginSysUser = JwtUtil.getLoginSysUser(token);

        List<InvoiceApply> invoiceApplyProcessList = new ArrayList<>();

        boolean flag  = true;
        String  error = "";
        int     h     = 1;

        for (Map<String, Object> map : list) {


            String invoiceNumber = map.get("invoiceNumber").toString();

            InvoiceApplyExample example = new InvoiceApplyExample();
            example.createCriteria()
                    .andInvoiceNumberEqualTo(invoiceNumber)
                    .andMakeInvoiceStatusEqualTo(InvoiceApplyCustomerMakeInvoiceStatusEnum.已开票.getKey());
            List<InvoiceApply> invoiceApplyList = invoiceApplyMapper.selectByExample(example);

            if (invoiceApplyList != null && invoiceApplyList.size() > 0) {

                InvoiceApply invoiceApply = invoiceApplyList.get(0);

                invoiceApply.setMailTickUserId(loginSysUser.getSysUserId());
                invoiceApply.setMailTickTime(DateUtil.date());
                invoiceApply.setMailTickStatus(InvoiceApplyCustomerMailTickStatusEnum.已寄票.getKey());

                String expressCompanyName = map.get("expressCompanyName").toString();

                List<ExpressCompany> expressCompanyList = expressCompanyMapper.selectByCompanyName(expressCompanyName);

                if (expressCompanyList != null && expressCompanyList.size() > 0) {
                    ExpressCompany expressCompany = expressCompanyList.get(0);
                    invoiceApply.setExpressCompanyId(expressCompany.getId());
                } else {
                    flag = false;
                    error += "第" + h + "行," + expressCompanyName + ",该快递公司名称不正确.";
                }

                if (map.get("expressNo") != null) {
                    String expressNo = map.get("expressNo").toString();
                    invoiceApply.setExpressNo(expressNo);
                }

                invoiceApplyProcessList.add(invoiceApply);

            } else {
                flag = false;
                error += "第" + h + "行," + invoiceNumber + ",该发票号未开票.";
            }
            h++;
        }

        if (flag) {
            for (InvoiceApply invoiceApply : invoiceApplyProcessList) {
                invoiceApplyMapper.updateByPrimaryKeySelective(invoiceApply);
            }
        }
//		else {
//			throw new SuperdeskUniOrderException(500, error);
//		}

        return error;
    }


    @Override
    public List<InvoiceApply> findAll(Map<String, Object> params) {
        return invoiceApplyMapperEx.findAll(params);
    }

    @Override
    public InvoiceApply findById(Long id) {
        return invoiceApplyMapper.selectByPrimaryKey(id);
    }

    @Override
    public List<InvoiceApply> findByIds(List<Long> invoiceApplyIds) {

        InvoiceApplyExample example = new InvoiceApplyExample();
        example.createCriteria()
                .andIdIn(invoiceApplyIds);

        List<InvoiceApply> resultList = invoiceApplyMapper.selectByExample(example);

        return resultList;
    }

    @Override
    public R<List<InvoiceApply>> findInvoiceByPageNew(Map<String, Object> params, int pageNo, int pageSize) {

        PageHelper.startPage(pageNo, pageSize);

        List<InvoiceApply> resultList = invoiceApplyMapperEx.findAll(params);

        PageInfo<InvoiceApply> page = new PageInfo<InvoiceApply>(resultList);
        PageHelper.clearPage();

        return new R<List<InvoiceApply>>(page.getPageNum(), page.getPageSize(), (int) page.getTotal(), resultList);
    }

    /**
     * 通过 orderSn 查找从属在 哪个开票申请中
     *
     * @param invQuery
     * @return
     */
    @Override
//	@Cacheable(keyGenerator = "findByXXKeyGenerator")
    public List<InvoiceApply> findByOrderSn(Map<String, Object> invQuery) {

        if (null == invQuery.get("orderSn")) {
            return null;
        }

        return invoiceApplyMapperEx.findInvoiceByOrderSn(invQuery);
    }

    @Override
    public List<InvoiceApply> findByAccountingOrderSn(String accountingOrderSn, AccountingOrderTypeDimEnum accountingOrderTypeDimEnum) {

        if (ObjectUtil.isEmpty(accountingOrderSn)) {
            return null;
        }
        // 目前
        // invoice_apply.accounting_order_id accounting_order_sn 都为空的, 是后补的字段, 但没写补丁, 只能从invoice_apply_x_goods 表查
        // invoice_apply_x_goods.accounting_order_sn 都为空的, 是后补的字段, 但没写补丁

        List<InvoiceApply> resultList      = new ArrayList<>();
        List<Long>         invoiceApplyIds = new ArrayList<>();

        switch (accountingOrderTypeDimEnum) {
            case 一般订单:
                AccountingUnifiedCustomer accountingUnifiedCustomer = accountingUnifiedCustomerService.findByAccountingOrderSn(accountingOrderSn);

                invoiceApplyIds = invoiceApplyXGoodsService.findInvoiceApplySetByAccountingOrderId(accountingUnifiedCustomer.getId(), accountingOrderTypeDimEnum);
                break;
            case 积分订单:
                AccountingScoreCustomer accountingScoreCustomer = accountingScoreCustomerService.findByAccountingOrderSn(accountingOrderSn);

                invoiceApplyIds = invoiceApplyXGoodsService.findInvoiceApplySetByAccountingOrderId(accountingScoreCustomer.getId(), accountingOrderTypeDimEnum);
                break;
        }

        if (CollUtil.isNotEmpty(invoiceApplyIds)) {
            resultList = findByIds(invoiceApplyIds);
        }


        return resultList;
    }

    public List<EnumSelectLongStringVo> frontEndSelectByAccountingOrderSn(String accountingOrderSn, AccountingOrderTypeDimEnum accountingOrderTypeDimEnum) {

        List<EnumSelectLongStringVo> selectLongStringVoList = new ArrayList<>();
        List<InvoiceApply>           resultList             = findByAccountingOrderSn(accountingOrderSn, accountingOrderTypeDimEnum);

        resultList.forEach(item -> {

            selectLongStringVoList.add(EnumSelectLongStringVo.builder()
                    .key(item.getId())
                    .desc(item.getInvoiceApplySn())
                    .build());
        });

        return selectLongStringVoList;
    }

    @Override
    public InvoiceApply findByInvoiceApplySn(String invoiceApplySn, LoginSysUser loginSysUser) {

        InvoiceApplyExample example = new InvoiceApplyExample();
        example.createCriteria()
                .andInvoiceApplySnEqualTo(invoiceApplySn);

        List<InvoiceApply> resultList = invoiceApplyMapper.selectByExampleWithBLOBs(example);

        if (CollUtil.isNotEmpty(resultList)) {
            return resultList.get(0);
        } else {
            return null;
        }
    }

    @Override
    public Map<String, InvoiceApply> findInvoiceByOrderSnList(List<String> orderSnList) {

        log.info("findInvoiceByOrderSnList 1 .size {}", orderSnList.size());

        if (CollUtil.isEmpty(orderSnList)) {
            return null;
        }

        Map<String, InvoiceApply> result = new HashMap<>();

        Map<String, Object> invQuery = new HashMap<>();
        invQuery.put("orderSnList", orderSnList);
        List<OrderSnMapInvoiceApplyVo> resultList = invoiceApplyMapperEx.findInvoiceByOrderSnList(invQuery);

        log.info("findInvoiceByOrderSnList 2 .size {}", resultList.size());

        try {
            for (OrderSnMapInvoiceApplyVo item : resultList) {


                InvoiceApply temp = new InvoiceApply();

                // 问题  mark by linjinyu at 20210312
//				AnBeanUtils.copyProperties(item, temp);

                temp = AnBeanUtils.copy(item, InvoiceApply.class);

                log.info(AnJsonUtils.toPrettyJson(temp));

                log.info("这个为空的? {}", item.toString());
                log.info("这个为空的? {}", temp.toString());

                result.put(item.getOrderSn(), temp);
            }
        } catch (BeansException e) {
            e.printStackTrace();
        }


        return result;

    }

    @Override
    public List<InvoiceApply> query4CheckIsOverdue() {


        // 得出要催款的发票数据
//		SELECT *
//		FROM `invoice_apply`
//		WHERE
//	    	audit_status = 2 //发票申请审核部分-审核状态 1-未审核;2-已同意;3-已拒绝
//	       	AND make_invoice_status = 1 // 发票登记部分-开票状态 0-未开票;1-已开票;2-重新开票;
//	       	AND invoice_status = 1 // 发票状态 0未邮寄 1已邮寄 2已作废
//	       	AND back_account_status in (0,1) // 回款状态 0-未回款;1-部分回款;2全部回款;


        List<InvoiceApply> result = new ArrayList<>();

        InvoiceApplyExample example = new InvoiceApplyExample();
        example.createCriteria()
                .andAuditStatusEqualTo(2)
                .andMakeInvoiceStatusEqualTo(1)
                .andInvoiceStatusEqualTo(1)
                .andBackAccountStatusIn(Arrays.asList(0, 1));

        result = invoiceApplyMapper.selectByExample(example);


        return result;

    }


    public static List<Long> arrToListRemoval(String[] arrStr) {
        List<Long> list = new ArrayList<>();
        for (int i = 0; i < arrStr.length; i++) {
            if (!list.contains(arrStr[i])) {
                list.add(Long.valueOf(arrStr[i]));
            }
        }
        return list;
    }


    // 未写完 有问题 大概是弃了
    @Deprecated
    public void validatedInvoiceApplyRelationTable() {


        // TODO mark by linjinyu 20201113

        // 1. 开票申请 先添加三个字段 ,  分别记录 1. 此申请是用什么关联关系 2. 关联关系 方法1 明细数据  3. 关联关系 方法2 明细数据  ... ---- 已完成
        // 2. 找出 标记是有效的开票申请 记录 (有可能 修正为 且 发票正常的记录?) | 方向2 找出 字段 relation_mode 标记为 -1的记录
        // 3. TODO 未写完...

        List<InvoiceApply> processInvoiceApplyList = new ArrayList<>();

        InvoiceApplyExample exampleForProcessList = new InvoiceApplyExample();
        exampleForProcessList.createCriteria()
                .andRelationModeEqualTo(-1);

        processInvoiceApplyList = invoiceApplyMapper.selectByExample(exampleForProcessList);

        for (InvoiceApply invoiceApply : processInvoiceApplyList) {


            List<InvoiceApplyDetailDimOrderItemVo> mode01 = new ArrayList<>();
            List<InvoiceApplyDetailDimOrderItemVo> mode02 = new ArrayList<>();
            List<InvoiceApplyDetailDimOrderItemVo> mode03 = new ArrayList<>();


            // findDzOrderByGoodIdNew
            // 方法1
            mode01 = invoiceApplyMapperExUnifiedCompatible.findInvoiceApplyDetailNewDim1Unified2Goods(invoiceApply.getId());
            // 方法2
            mode02 = invoiceApplyMapperExUnifiedCompatible.findInvoiceApplyDetailOldDim1Unified2Goods(invoiceApply.getId());
            // 方法3
//			mode03 = invoiceApplyMapperEx.findDzOrderByGoodId(invoiceApply.getId());

            InvoiceApply invoiceApplyForUpdate = new InvoiceApply();
            invoiceApplyForUpdate.setId(invoiceApply.getId());
            invoiceApplyForUpdate.setErrorCheckRelation01(0L);
            invoiceApplyForUpdate.setErrorCheckRelation02(0L);

            if (CollUtil.isNotEmpty(mode01)) {
                invoiceApplyForUpdate.setErrorCheckRelation01(Long.parseLong(String.valueOf(mode01.size())));
            }

            if (CollUtil.isNotEmpty(mode02)) {
                invoiceApplyForUpdate.setErrorCheckRelation01(Long.parseLong(String.valueOf(mode02.size())));
            }

            invoiceApplyMapper.updateByPrimaryKeySelective(invoiceApplyForUpdate);

        }


    }

    /****************************************** 补丁程序 start ******************************************/


    public void patchFixInfo(Long invoiceApplyId, LoginSysUser loginSysUser) {

        InvoiceApply invoiceApply = new InvoiceApply();
        invoiceApply.setId(invoiceApplyId);

        List<Long>                    affectedAccountingOrderIds = invoiceApplyXGoodsService.getAffectedAccountingOrderIdsByInvoiceApplyId(invoiceApplyId);
        List<AccountingScoreCustomer> affectedAccountingOrders   = accountingScoreCustomerService.findByIds(affectedAccountingOrderIds);

        log.info("patchFixInfo -> 对账单\n{}\n{}", JSONUtil.toJsonStr(affectedAccountingOrderIds), JSONUtil.toJsonPrettyStr(affectedAccountingOrders));

        if (CollUtil.isNotEmpty(affectedAccountingOrders)) {

            invoiceApply.setAccountingOrderQuantity(affectedAccountingOrderIds.size());

            AccountingScoreCustomer accountingScoreCustomer = affectedAccountingOrders.get(0);

            invoiceApply.setAccountingOrderId(accountingScoreCustomer.getId());
            invoiceApply.setAccountingOrderSn(accountingScoreCustomer.getAccountingOrderSn());

            SysEnterprise sysEnterprise = sysEnterpriseService.findByOutVirtId(accountingScoreCustomer.getEnterpriseId());

            log.info("patchFixInfo -> 企业信息\n{}", JSONUtil.toJsonPrettyStr(sysEnterprise));

            if (ObjectUtil.isNotNull(sysEnterprise)) {
                invoiceApply.setSysOrgId(0L);
                invoiceApply.setSysVirtId(sysEnterprise.getId());
                invoiceApply.setOutOrgId(sysEnterprise.getOrganizationId());
                invoiceApply.setOutVirtId(sysEnterprise.getEnterpriseId());
            }

            log.info("patchFixInfo -> 修正数据:\n{}", JSONUtil.toJsonPrettyStr(invoiceApply));

            invoiceApplyMapper.updateByPrimaryKeySelective(invoiceApply);

        }

    }

    public void patchFixStatistics(Long invoiceApplyId, LoginSysUser loginSysUser) {

        InvoiceApply invoiceApply = new InvoiceApply();
        invoiceApply.setId(invoiceApplyId);

        List<Long> idsCredit = invoiceApplyXGoodsService.findCreditSetByInvoicApplyId(invoiceApplyId);

        List<InvoiceApplyDetailDimCreditItemVo> invoiceApplyDetailDimCreditItemVoList = scoreOrderService.getScoreOrderReconciliationNotYetScene3(
                AccountingOrderScoreCustomerNotYetDimCreditScene3QueryCriteria.builder()
                        .idsCredit(idsCredit).build(), loginSysUser
        );

        Integer quantityOrder       = 0;
        Integer quantityOrderGoods  = 0;
        Integer quantityOrderCredit = 0;

        quantityOrder = invoiceApplyDetailDimCreditItemVoList.stream().filter(AnLamdaUtils.distinctByKey(o -> o.getUnifiedOrderId())).collect(Collectors.toList()).size();
        quantityOrderGoods = invoiceApplyDetailDimCreditItemVoList.stream().filter(AnLamdaUtils.distinctByKey(o -> o.getUnifiedOrderGoodsId())).collect(Collectors.toList()).size();
        quantityOrderCredit = invoiceApplyDetailDimCreditItemVoList.size();

        invoiceApply.setOrderQuantity(quantityOrder);
        invoiceApply.setGoodsQuantity(quantityOrderGoods);
        invoiceApply.setCreditQuantity(quantityOrderCredit);

        /****************************************** 统计各项数量   end ******************************************/

        /****************************************** 统计各项金额 start ******************************************/

        // 对账单-订单金额 - 积分结算2.1 新加 取该对账单中所有流水的结算金额总和 等于 结算金额+微信金额 也称之为统计金额
        BigDecimal statisticsTotalAmount = BigDecimal.ZERO;
        // 对账单-结算金额 - 之前的 - 取该对账单中所有积分类型为非`微信支付`的结算金额总和,目前创建对账单成功时服务端默认`微信支付`流水不参与结算,其他积分类型的流水参与结算,未来由业务操作人员选择结算积分类型来计算
        BigDecimal accountingAmount = BigDecimal.ZERO;
        // 对账单-微信金额 - 积分结算2.1 新加 取该对账单中所有积分类型为`微信支付`的结算金额总和 也称之为不对账金额 不结算金额
        BigDecimal unAccountingAmount = BigDecimal.ZERO;

        List<Predicate<InvoiceApplyDetailDimCreditItemVo>> predicatesByAccounting = new ArrayList<>();
        predicatesByAccounting.add(r -> null != r.getCreditType() && r.getCreditType().compareTo(UnifiedOrderCreditTypeDefaultEnum.微信支付.getKey()) != 0);

        List<Predicate<InvoiceApplyDetailDimCreditItemVo>> predicatesByUnAccounting = new ArrayList<>();
        predicatesByUnAccounting.add(r -> null != r.getCreditType() && r.getCreditType().compareTo(UnifiedOrderCreditTypeDefaultEnum.微信支付.getKey()) == 0);

        // 如果本来数据 是没这个流水Id 是找不出来的
        List<InvoiceApplyDetailDimCreditItemVo> findByAccountingCreditList   = AnLamdaUtils.filters(invoiceApplyDetailDimCreditItemVoList, predicatesByAccounting);
        List<InvoiceApplyDetailDimCreditItemVo> findByUnAccountingCreditList = AnLamdaUtils.filters(invoiceApplyDetailDimCreditItemVoList, predicatesByUnAccounting);

        statisticsTotalAmount = invoiceApplyDetailDimCreditItemVoList
                .stream()
                .map(item -> item.getBalance() == null ? BigDecimal.ZERO : item.getBalance())
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        if (CollUtil.isNotEmpty(findByAccountingCreditList)) {
            accountingAmount = findByAccountingCreditList
                    .stream()
                    .map(item -> item.getBalance() == null ? BigDecimal.ZERO : item.getBalance())
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
        }

        if (CollUtil.isNotEmpty(findByUnAccountingCreditList)) {
            unAccountingAmount = findByUnAccountingCreditList
                    .stream()
                    .map(item -> item.getBalance() == null ? BigDecimal.ZERO : item.getBalance())
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
        }

        invoiceApply.setRealAmount(accountingAmount);
        invoiceApply.setUnAccountingAmount(unAccountingAmount);
        invoiceApply.setInvoiceApplyAmount(statisticsTotalAmount);

        invoiceApplyMapper.updateByPrimaryKeySelective(invoiceApply);

    }

    public int pathFixFieldServiceNoSourceFrom(
            String accountingOrderSn, AccountingOrderTypeDimEnum accountingOrderTypeDimEnum,
            String serviceNo, String sourceFrom, LoginSysUser loginSysUser) {

        int ret = 0;

        List<InvoiceApply> invoiceApplyCustomerList = findByAccountingOrderSn(accountingOrderSn, accountingOrderTypeDimEnum);

        if (CollUtil.isNotEmpty(invoiceApplyCustomerList)) {

            // 1. 目前不存在混合订单的情况，所以能直接传导

            List<Long> processInvoiceApplyIds = invoiceApplyCustomerList
                    .stream()
                    .filter(AnLamdaUtils.distinctByKey(o -> o.getId()))
                    .map(o -> o.getId())
                    .collect(Collectors.toList());

            InvoiceApplyExample example = new InvoiceApplyExample();
            example.createCriteria()
                    .andIdIn(processInvoiceApplyIds);

            InvoiceApply sample = new InvoiceApply();
            sample.setServiceNo(serviceNo);
            sample.setSourceFrom(sourceFrom);

            ret = invoiceApplyMapper.updateByExampleSelective(sample, example);


        }

        return ret;
    }

    @Override
    public void deleteByAccountingOrderSn(String accountingOrderSn) {
        InvoiceApplyExample invoiceApplyExample = new InvoiceApplyExample();
        invoiceApplyExample.createCriteria().andAccountingOrderSnEqualTo(accountingOrderSn);
        invoiceApplyMapper.deleteByExample(invoiceApplyExample);
    }

    @Override
    public void patchInvoiceApplyCustomerFixV2_1() {


        PageHelper.startPage(1, 100);
        InvoiceApplyExample example = new InvoiceApplyExample();
        example.createCriteria()
                .andAccountingOrderIdIsNull();

        List<InvoiceApply>     resultList = invoiceApplyMapper.selectByExample(example);
        PageInfo<InvoiceApply> page       = new PageInfo<InvoiceApply>(resultList);
        PageHelper.clearPage();

        if (CollUtil.isNotEmpty(resultList)) {
            resultList.forEach(invoiceApplyCustomerEntity -> {

                if (ArrayUtil.contains(
                        InvoiceApplyCustomerScene.statusV2_1_Array_InvoiceProgressingSceneRevise(),
                        invoiceApplyCustomerEntity.getInvoiceStatus())
                ) {
                    patchFixInfo(invoiceApplyCustomerEntity.getId(), LoginSysUser.builder().build());
                    patchFixStatistics(invoiceApplyCustomerEntity.getId(), LoginSysUser.builder().build());
                }
            });
        }
    }
}
