package cn.superdesk.uniorder.service.organisation.impl;

import cn.hutool.core.date.DateUtil;
import cn.superdesk.uniorder.common.enums.accounting.AccountingOrderBackAccountStatusEnum;
import cn.superdesk.uniorder.common.enums.accounting.AccountingOrderDimCreateByEnum;
import cn.superdesk.uniorder.common.enums.accounting.AccountingOrderLogicModeEnum;
import cn.superdesk.uniorder.common.exception.utils.AssertUtils;
import cn.superdesk.uniorder.common.numerical.AnBeanUtils;
import cn.superdesk.uniorder.common.numerical.AnCollectionUtils;
import cn.superdesk.uniorder.common.numerical.AnIntegerUtils;
import cn.superdesk.uniorder.common.rest.response.R;
import cn.superdesk.uniorder.dao.entity.accounting.unified.customer.*;
import cn.superdesk.uniorder.dao.entity.base.UnifiedOrder;
import cn.superdesk.uniorder.dao.entity.base.UnifiedOrderExample;
import cn.superdesk.uniorder.dao.entity.base.UnifiedOrderGoods;
import cn.superdesk.uniorder.dao.entity.invoice.customer.InvoiceApply;
import cn.superdesk.uniorder.dao.entity.invoice.customer.InvoiceApplyXGoods;
import cn.superdesk.uniorder.dao.entity.invoice.customer.InvoiceApplyXGoodsExample;
import cn.superdesk.uniorder.dao.entity.organisation.SysEnterpriseExtAccounting;
import cn.superdesk.uniorder.dao.entity.organisation.SysEnterpriseExtAccountingExample;
import cn.superdesk.uniorder.dao.mapper.accounting.unified.customer.*;
import cn.superdesk.uniorder.dao.mapper.base.UnifiedOrderMapper;
import cn.superdesk.uniorder.dao.mapper.invoice.customer.InvoiceApplyMapper;
import cn.superdesk.uniorder.dao.mapper.invoice.customer.InvoiceApplyMapperEx;
import cn.superdesk.uniorder.dao.mapper.invoice.customer.InvoiceApplyXGoodsMapper;
import cn.superdesk.uniorder.dao.mapper.invoice.customer.InvoiceApplyXGoodsMapperEx;
import cn.superdesk.uniorder.dao.mapper.organisation.SysEnterpriseExtAccountingMapper;
import cn.superdesk.uniorder.dao.mapper.organisation.SysEnterpriseExtAccountingMapperEx;
import cn.superdesk.uniorder.dto.vo.accounting.extend.ReportBeOverdueOfStatementOfAccountOfView;
import cn.superdesk.uniorder.dto.vo.invoice.customer.extend.ReportBeOverdueOfInvoiceOfView;
import cn.superdesk.uniorder.service.accounting.unified.customer.AccountingUnifiedCustomerService;
import cn.superdesk.uniorder.service.accounting.unified.customer.AccountingUnifiedCustomerXGoodsService;
import cn.superdesk.uniorder.service.order.base.UnifiedOrderCreditService;
import cn.superdesk.uniorder.service.order.base.UnifiedOrderGoodsService;
import cn.superdesk.uniorder.service.order.base.UnifiedOrderService;
import cn.superdesk.uniorder.service.invoice.customer.InvoiceApplyCustomerService;
import cn.superdesk.uniorder.service.organisation.SysEnterpriseExtAccountingService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.BiFunction;
import java.util.stream.Collectors;

/**
 * @Description: 企业信息-扩展-对账相关
 * @Author: linjinyu
 * @Email linjinyu@avic-s.com
 * @CreateDate: 2020-08-20 17:51:19
 * @UpdateUser: linjinyu
 * @UpdateDate: 2020-08-20 17:51:19
 * @UpdateRemark: 修改内容
 * @Version: 1.0
 */
@Service
public class SysEnterpriseExtAccountingServiceImpl implements SysEnterpriseExtAccountingService {

    @Autowired
    private SysEnterpriseExtAccountingMapper   sysEnterpriseExtAccountingMapper;
    @Autowired
    private SysEnterpriseExtAccountingMapperEx sysEnterpriseExtAccountingMapperEx;

    @Autowired
    private InvoiceApplyXGoodsMapper    invoiceOrderMapper;
    @Autowired
    private InvoiceApplyXGoodsMapperEx  invoiceOrderMapperEx;
    @Autowired
    private InvoiceApplyMapper          invoiceAppleMapper;
    @Autowired
    private InvoiceApplyMapperEx        invoiceApplyMapperEx;
    @Autowired
    private InvoiceApplyCustomerService invoiceApplyService;

    @Autowired
    private UnifiedOrderMapper unifiedOrderMapper;

    @Autowired
    private UnifiedOrderService       unifiedOrderService;
    @Autowired
    private UnifiedOrderGoodsService  unifiedOrderGoodsService;
    @Autowired
    private UnifiedOrderCreditService unifiedOrderCreditService;

    @Autowired
    private AccountingUnifiedCustomerMapper       accountingUnifiedCustomerMapper;
    @Autowired
    private AccountingUnifiedCustomerMapperEx     accountingUnifiedCustomerMapperEx;
    @Autowired
    private AccountingUnifiedCustomerXGoodsMapper accountingUnifiedCustomerXGoodsMapper;

    @Autowired
    private AccountingUnifiedCustomerService       accountingUnifiedCustomerService;
    @Autowired
    private AccountingUnifiedCustomerXGoodsService accountingUnifiedCustomerXGoodsService;

    @Autowired
    private AccountingUnifiedCustomerOrderMapper      accountingUnifiedCustomerOrderMapper;
    @Autowired
    private AccountingUnifiedCustomerOrderGoodsMapper accountingUnifiedCustomerOrderGoodsMapper;


    /****************************************** extends BaseService 部分 start ******************************************/

    @Override
    public int insertSelective(SysEnterpriseExtAccounting entity) {
        return sysEnterpriseExtAccountingMapper.insertSelective(entity);
    }

    @Override
    public int updateByPrimaryKeySelective(SysEnterpriseExtAccounting entity) {
        return sysEnterpriseExtAccountingMapper.updateByPrimaryKeySelective(entity);
    }

    @Override
    public void deleteObj(Long id) {
    }

    @Override
    public SysEnterpriseExtAccounting findById(Long id) {
        return sysEnterpriseExtAccountingMapper.selectByPrimaryKey(id);
    }

    @Override
    public PageInfo<SysEnterpriseExtAccounting> findByPaging(Map<String, Object> conditions, Integer pageNun, Integer pageSize) {
        return null;
    }

    @Override
    public List<SysEnterpriseExtAccounting> findAll(Map<String, Object> queryMap) {
        return null;
    }

    /****************************************** extends BaseService 部分   end ******************************************/


    public void addSysEnterpriseExtAccounting(SysEnterpriseExtAccounting entity) {
        sysEnterpriseExtAccountingMapperEx.insertSelective(entity);
    }

    public void updateSysEnterpriseExtAccounting(SysEnterpriseExtAccounting entity) {
        SysEnterpriseExtAccounting originEntity = sysEnterpriseExtAccountingMapper.selectByPrimaryKey(entity.getId());
        AssertUtils.notNull(originEntity);
        AnBeanUtils.copy(entity, originEntity);
        sysEnterpriseExtAccountingMapper.updateByPrimaryKey(originEntity);
    }

    public void deleteSysEnterpriseExtAccounting(Long id) {
        sysEnterpriseExtAccountingMapper.deleteByPrimaryKey(id);
    }

    public SysEnterpriseExtAccounting findSysEnterpriseExtAccountingById(Long id) {


//		SysEnterpriseExtAccounting entity = sysEnterpriseExtAccountingMapper.selectByPrimaryKey(id);
//		AssertUtil.notNull(entity);

        SysEnterpriseExtAccounting        entity  = null;
        SysEnterpriseExtAccountingExample example = new SysEnterpriseExtAccountingExample();
        example.createCriteria()
                .andDeletedEqualTo(false)
                .andSysVirtIdEqualTo(id);

        example.setOrderByClause("is_default DESC , update_time DESC");

        List<SysEnterpriseExtAccounting> result = sysEnterpriseExtAccountingMapper.selectByExample(example);

        if (AnCollectionUtils.isNotEmpty(result)) {
            entity = result.get(0);
        }

        return entity;
    }

    public R<List<SysEnterpriseExtAccounting>> pageQuery(Map<String, Object> conditions, int pageNun, int pageSize) {

        // 样例 保留
//		SysEnterpriseExtAccounting sysEnterpriseExtAccountingConditions = BeanUtils.mapToBean(conditions,SysEnterpriseExtAccounting.class);

        SysEnterpriseExtAccountingExample          example  = new SysEnterpriseExtAccountingExample();
        SysEnterpriseExtAccountingExample.Criteria criteria = example.createCriteria();

        PageHelper.startPage(pageNun, pageSize);
        List<SysEnterpriseExtAccounting>     resultList = sysEnterpriseExtAccountingMapper.selectByExample(example);
        PageInfo<SysEnterpriseExtAccounting> page       = new PageInfo<SysEnterpriseExtAccounting>(resultList);
        PageHelper.clearPage();

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

    }


    public SysEnterpriseExtAccounting findSysEnterpriseExtAccountingByOutVirtId(Long outVirtId) {


//		SysEnterpriseExtAccounting entity = sysEnterpriseExtAccountingMapper.selectByPrimaryKey(id);
//		AssertUtil.notNull(entity);

        SysEnterpriseExtAccounting        entity  = null;
        SysEnterpriseExtAccountingExample example = new SysEnterpriseExtAccountingExample();
        example.createCriteria()
                .andDeletedEqualTo(false)
                .andOutVirtIdEqualTo(outVirtId);

        example.setOrderByClause("is_default DESC , update_time DESC");

        List<SysEnterpriseExtAccounting> result = sysEnterpriseExtAccountingMapper.selectByExample(example);

        if (AnCollectionUtils.isNotEmpty(result)) {
            entity = result.get(0);
        }

        return entity;
    }

    public SysEnterpriseExtAccounting findSysEnterpriseExtAccountingByOutVirtIdWithIn(Long outVirtId) {

        //		@ApiModelProperty("rule_of_account\n" +
//				"//\t\t1. 账单确认日期 (+ 指定天数)\n" +
//				"//\t\t2. 寄票日期 (+ 指定天数)\n" +
//				"//\t\t3. 指定日期 (每月?号)")
//		private Integer ruleOfAccount;
//		@ApiModelProperty("rule_of_account 3 每月几号")
//		private Integer dayOfMonth;
//		@ApiModelProperty("rule_of_account 1 2 回款周期 账期-会计期间")

        //	6、企业未设置回款周期,直接在未对账商品创建账单,默认根据账单的寄票时间+30为是否逾期的判断条件

        SysEnterpriseExtAccounting sysEnterpriseExtAccounting = null;

        if (null == outVirtId) {
            return getSysEnterpriseExtAccountingByNull();
        }

        sysEnterpriseExtAccounting = findSysEnterpriseExtAccountingByOutVirtId(outVirtId);

        if (null == sysEnterpriseExtAccounting) {

            return getSysEnterpriseExtAccountingByNull();
        } else {
            return sysEnterpriseExtAccounting;
        }


    }

    /**
     * 默认 开票时间 周期 0
     *
     * @return
     */
    public SysEnterpriseExtAccounting getSysEnterpriseExtAccountingByNull() {
        SysEnterpriseExtAccounting sysEnterpriseExtAccounting = new SysEnterpriseExtAccounting();
        sysEnterpriseExtAccounting.setRuleOfAccount(4);
        sysEnterpriseExtAccounting.setAccountPeriod(0);
        return sysEnterpriseExtAccounting;
    }


    public ReportBeOverdueOfInvoiceOfView checkInvoiceApplyCustomerIsOverdue(InvoiceApply invoiceApply) {


        // 发票申请审核部分-审核人Id-后台帐号 auditUserId
        // 发票申请审核部分-审核状态 1-未审核;2-已同意;3-已拒绝 auditStatus
        // 2. 已经寄票


//		apply_user_id	bigint(20)			否	无	发票申请部分-发票申请人Id-后台帐号
//		apply_time	datetime			是	NULL	发票申请部分-发票申请时间
//
//		audit_user_id	bigint(20)			是	NULL	发票申请审核部分-审核人Id-后台帐号
//		audit_status	tinyint(3)			是	1	发票申请审核部分-审核状态 1-未审核;2-已同意;3-已拒绝
//		audit_time	datetime			是	NULL	发票申请审核部分-审核时间
//
//		make_invoice_user_id	bigint(20)			是	NULL	发票登记部分-开票人登记人-后台帐号
//		make_invoice_time	datetime			是	NULL	发票登记部分-开票时间
//		make_invoice_status	tinyint(3)			是	0	发票登记部分-开票状态 0-未开票;1-已开票;2-重新开票;
//
//		express_company_id	bigint(11)			是	NULL	寄票登记部分-快递公司ID
//		express_no	varchar(50)	utf8_general_ci		是	NULL	寄票登记部分-快递单号
//		mail_tick_time	datetime			是	NULL	寄票登记部分-寄票时间
//		invoice_status	tinyint(3)			是	0	发票状态 0未邮寄 1已邮寄 2已作废

//				关键字 "/sendInvoiceRegister" 是没有寄票登记人记录的 mark by linjinyu at 20210311

//		back_account_status	tinyint(3)			是	0	回款状态 0-未回款;1-部分回款;2全部回款;


        // 得出要催款的发票数据
//		SELECT * FROM `invoice_apply` WHERE audit_status = 2 AND make_invoice_status = 1 AND invoice_status = 1 AND back_account_status in (0,1)

        // nnd 又做不下去了,这个开票申请是没有项目企业的

//		invoiceApply
        // |---- 如果 outVirtId 为空,再去较验吧 也可以当作为 //	6、企业未设置回款周期,直接在未对账商品创建账单,默认根据账单的寄票时间+30为是否逾期的判断条件
//		getInvoiceApplyCustomerIsOverdue()

        // => 生成报告

        SysEnterpriseExtAccounting sysEnterpriseExtAccounting = findSysEnterpriseExtAccountingByOutVirtIdWithIn(invoiceApply.getOutVirtId());

//		@ApiModelProperty("rule_of_account\n" +
//				"//\t\t1. 账单确认日期 (+ 指定天数)\n" +
//				"//\t\t2. 寄票日期 (+ 指定天数)\n" +
//				"//\t\t3. 指定日期 (每月?号)")
//		private Integer ruleOfAccount;
//		@ApiModelProperty("rule_of_account 3 每月几号")
//		private Integer dayOfMonth;
//		@ApiModelProperty("rule_of_account 1 2 回款周期 账期-会计期间")

        ruleOfAccountMappings.get(sysEnterpriseExtAccounting.getRuleOfAccount()).apply(invoiceApply, sysEnterpriseExtAccounting);


        return new ReportBeOverdueOfInvoiceOfView();
    }

    private static final Map<Integer, BiFunction<InvoiceApply, SysEnterpriseExtAccounting, String>> ruleOfAccountMappings = new HashMap<>();

    static {

        // 初始化
        ruleOfAccountMappings.put(1, (_invoiceApply, _sysEnterpriseExtAccounting) -> doActionRuleOfAccount1(_invoiceApply, _sysEnterpriseExtAccounting));
        ruleOfAccountMappings.put(2, (_invoiceApply, _sysEnterpriseExtAccounting) -> doActionRuleOfAccount2(_invoiceApply, _sysEnterpriseExtAccounting));
        ruleOfAccountMappings.put(3, (_invoiceApply, _sysEnterpriseExtAccounting) -> doActionRuleOfAccount3(_invoiceApply, _sysEnterpriseExtAccounting));
    }

    static String doActionRuleOfAccount1(InvoiceApply invoiceApply, SysEnterpriseExtAccounting sysEnterpriseExtAccounting) {

        return "doActionRuleOfAccount1";
    }

    static String doActionRuleOfAccount2(InvoiceApply invoiceApply, SysEnterpriseExtAccounting sysEnterpriseExtAccounting) {
        return "doActionRuleOfAccount2";
    }

    static String doActionRuleOfAccount3(InvoiceApply invoiceApply, SysEnterpriseExtAccounting sysEnterpriseExtAccounting) {
        return "doActionRuleOfAccount2";
    }


    /****************************************** 回款逾期 从对账单角度 start ******************************************/

    /**
     * order by SysEnterpriseExtAccounting.isDefault DESC,SysEnterpriseExtAccounting.id DESC
     * 回款规则:3种 ruleOfAccount
     * 1. 寄票日期 + accountPeriod
     * 2. 账单确认日期 + accountPeriod
     * 3. 指定日期 每月 dayOfMonth
     *
     * @param accountingUnifiedCustomer
     * @return
     */
    public ReportBeOverdueOfStatementOfAccountOfView checkAccountingUnifiedCustomerIsOverdue(AccountingUnifiedCustomer accountingUnifiedCustomer) {


        StringBuffer record = new StringBuffer();

        record
                .append("AccountingOrderId : ").append(accountingUnifiedCustomer.getId())
                .append("AccountingOrderSn : ").append(accountingUnifiedCustomer.getAccountingOrderSn());

        ReportBeOverdueOfStatementOfAccountOfView report = new ReportBeOverdueOfStatementOfAccountOfView();


        // 如果这个对账单全部回款 证明没有逾期 返回没有逾期

        /****************************************** Fail fast 20210113 start ******************************************/
        // 0-未回款;1-部分回款;2-全部回款
        if (accountingUnifiedCustomer.getBackAccountStatus().equals(AccountingOrderBackAccountStatusEnum.全部回款.getKey())) {

            // 是否逾期:
            // -2-没办
            // -1-没办法判定(没有任务开票记录);
            //  0-没有;
            //  1-逾期;
            report.setIsOverdue(0);
            return report;
        }

        Integer accountingX = 0;

        List<AccountingUnifiedCustomerXGoods> accountingUnifiedCustomerXGoods = null;

        AccountingUnifiedCustomerXGoodsExample exampleXGoodsLogicMode = new AccountingUnifiedCustomerXGoodsExample();
        exampleXGoodsLogicMode.createCriteria()
                .andAccountingOrderIdEqualTo(accountingUnifiedCustomer.getId());

        switch (AccountingOrderLogicModeEnum.get(accountingUnifiedCustomer.getLogicMode())) {
            case 早期:

                // 这里是这坑位,不知道早期改了多少版,然而关联关系是怎样的,目前只按我知道的那一种去做
                accountingUnifiedCustomerXGoods = accountingUnifiedCustomerXGoodsMapper.selectByExample(exampleXGoodsLogicMode);

                // 是否有问题 主要是针对 未知情况
                Integer hasError = 0;

                // 如果为空 证明没有转换
                if (AnCollectionUtils.isEmpty(accountingUnifiedCustomerXGoods)) {

                    // TODO 转换

                    /****************************************** 这些记录是怎么回事呢？ start ******************************************/
                    // 正在显示第 0-24 行 (共 2032 行, 查询花费 0.0746 秒。)
                    // SELECT * FROM `accounting_unified_customer_order` aucuo LEFT JOIN unified_order uo on aucuo.order_id = uo.id WHERE uo.id is null
                    // 至 2019-03-07 16:24:50
                    // 至 2020-06-12 00:00:00 TODO 都还有 能删除吗？

                    /****************************************** 存在于641个对账单 start ******************************************/
                    // 正在显示第 0-24 行 (共 641 行, 查询花费 0.0051 秒。)
                    // SELECT DISTINCT aucuo.dz_id FROM `accounting_unified_customer_order` aucuo LEFT JOIN unified_order uo on aucuo.order_id = uo.id WHERE uo.id is null

                    /****************************************** 开始逻辑 start ******************************************/
                    List<AccountingUnifiedCustomerOrder> accountingUnifiedCustomerOrderList = new ArrayList<>();

                    AccountingUnifiedCustomerOrderExample accountingUnifiedCustomerOrderExample = new AccountingUnifiedCustomerOrderExample();
                    accountingUnifiedCustomerOrderExample.createCriteria()
                            .andDzIdEqualTo(accountingUnifiedCustomer.getId());
                    accountingUnifiedCustomerOrderList = accountingUnifiedCustomerOrderMapper.selectByExample(accountingUnifiedCustomerOrderExample);

                    if (AnCollectionUtils.isEmpty(accountingUnifiedCustomerOrderList)) {

                    } else {

                        /****************************************** 问题又来了 不知道 什么时候 弃用 accounting_unified_customer_order_goods start ******************************************/


//						正在显示第 0-24 行 (共 70221 行, 查询花费 0.0089 秒。)
//						SELECT * FROM `accounting_unified_customer_order_goods`

//						大概是有三种情况
//						1. sys_good
//						2. accounting_unified_customer_order_goods
//						3. unified_order_goods

                        /****************************************** unified_order_goods start ******************************************/
//						正在显示第 0-24 行 (共 63608 行, 查询花费 0.0095 秒。)
//						SELECT * FROM `accounting_unified_customer_order_goods` aucuog LEFT JOIN unified_order_goods uog on aucuog.good_id = uog.id WHERE uog.id is null

//						正在显示第 0-24 行 (共 12185 行, 查询花费 0.0340 秒。)
//						SELECT * FROM `accounting_unified_customer_order_goods` aucuog LEFT JOIN unified_order_goods uog on aucuog.good_id = uog.id WHERE uog.id is NOT null

                        // 最新的方式 出来的
//						正在显示第 0-24 行 (共 11398 行, 查询花费 0.0201 秒。)
//						SELECT *
//						FROM `accounting_unified_customer_order_goods` aucuog
//							LEFT JOIN unified_order_goods uog on aucuog.good_id = uog.id and aucuog.optionname = uog.goods_name
//						WHERE uog.id is NOT null


                        /****************************************** sys_good start ******************************************/
//						正在显示第 0-24 行 (共 55015 行, 查询花费 0.0097 秒。)
//						SELECT * FROM `accounting_unified_customer_order_goods` aucuog LEFT JOIN sys_good sg on aucuog.good_id = sg.id WHERE sg.id is null

//						正在显示第 0-24 行 (共 20778 行, 查询花费 0.0106 秒。)
//						SELECT * FROM `accounting_unified_customer_order_goods` aucuog LEFT JOIN sys_good sg on aucuog.good_id = sg.id WHERE sg.id is NOT null

//						正在显示第 0-24 行 (共 17778 行, 查询花费 0.0096 秒。)
//						SELECT *
//						FROM `accounting_unified_customer_order_goods` aucuog
//							LEFT JOIN sys_good sg on aucuog.good_id = sg.id and aucuog.other_field1 = sg.other_field1
//						WHERE sg.id is NOT null


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

//						正在显示第 0-24 行 (共 43111 行, 查询花费 0.0088 秒。)
//						SELECT * FROM `accounting_unified_customer_order_goods` aucuog LEFT JOIN unified_order_goods uog on aucuog.good_id = uog.id LEFT JOIN sys_good sg on aucuog.good_id = sg.id WHERE uog.id is null AND sg.id is null

//						43111 20778 12185 = 70221

//						70221 -17778(sys_good)-11398(unified_order_goods) =41045

//						正在显示第 0-24 行 (共 43111 行, 查询花费 0.0069 秒。)
//						SELECT
//								*
//						FROM `accounting_unified_customer_order_goods` aucuog
//							LEFT JOIN unified_order_goods uog on aucuog.good_id = uog.id
//							LEFT JOIN sys_good sg on aucuog.good_id = sg.id
//						WHERE
//							uog.id is null
//							and
//							sg.id is null

                        /****************************************** 证明 accounting_unified_customer_order_goods 的 dz_order_id 是对的 start ******************************************/
//						MySQL 返回的查询结果为空 (即零行)。 (查询花费 0.1575 秒。)
//						SELECT * FROM `accounting_unified_customer_order_goods` aucuog LEFT JOIN accounting_unified_customer_order aucuo on aucuog.dz_order_id = aucuo.id WHERE aucuo.id is null


                        // TODO 算了,没办法,先做已知的情况, 既然是订单维度,就用订单维度的方式 先去做吧

                        /****************************************** 先检验对账单 订单 start ******************************************/


                        List<Long>          processUnifiedOrderIds  = accountingUnifiedCustomerOrderList.stream().map(o -> o.getOrderId()).collect(Collectors.toList());
                        List<UnifiedOrder>  processUnifiedOrderList = null;
                        UnifiedOrderExample unifiedOrderExample     = new UnifiedOrderExample();
                        unifiedOrderExample.clear();
                        unifiedOrderExample.createCriteria()
                                .andIdIn(processUnifiedOrderIds);
                        processUnifiedOrderList = unifiedOrderMapper.selectByExample(unifiedOrderExample);

                        if (accountingUnifiedCustomerOrderList.size() > processUnifiedOrderList.size()) {
                            hasError = 1;
                            record.append(" 对账单 订单 数据 比 基础数据 订单 大: ").append(accountingUnifiedCustomerOrderList.size()).append(" . ").append(processUnifiedOrderList.size());
                        } else if (accountingUnifiedCustomerOrderList.size() < processUnifiedOrderList.size()) {
                            hasError = 1;
                            record.append(" 对账单 订单 数据 比 基础数据 订单 小: ").append(accountingUnifiedCustomerOrderList.size()).append(" . ").append(processUnifiedOrderList.size());
                        } else {

                            record.append(" 对账单 订单 数据 与 基础数据 订单 条数相等 : ").append(accountingUnifiedCustomerOrderList.size()).append(" . ").append(processUnifiedOrderList.size());

                            for (AccountingUnifiedCustomerOrder accountingUnifiedCustomerOrder : accountingUnifiedCustomerOrderList) {

                                List<UnifiedOrderGoods> unifiedOrderGoodsList = new ArrayList<>();
                                unifiedOrderGoodsList = unifiedOrderGoodsService.findByOrderSn(accountingUnifiedCustomerOrder.getOrderSn());

                                // 大概的作用类似批次
                                Date processDate = DateUtil.date();

                                List<AccountingUnifiedCustomerXGoods> processAccountingUnifiedCustomerXGoodsList = new ArrayList<>();

                                for (UnifiedOrderGoods unifiedOrderGoods : unifiedOrderGoodsList) {

                                    /****************************************** 关联 start ******************************************/
                                    // 重构 mark by linjinyu at 20210113
                                    processAccountingUnifiedCustomerXGoodsList.add(accountingUnifiedCustomerXGoodsService.composeAccountingUnifiedCustomerXGoods02(accountingUnifiedCustomer, accountingUnifiedCustomerOrder, unifiedOrderGoods, AccountingOrderDimCreateByEnum.订单, processDate));
                                    // 重构 再再 mark by linjinyu at 20210202 修改为 批量插入
                                    /****************************************** 关联   end ******************************************/

                                }

                                accountingUnifiedCustomerXGoodsService.insertBatch(processAccountingUnifiedCustomerXGoodsList);


                            }

                        }
                    }

                    if (hasError.equals(0)) {
                        accountingUnifiedCustomerXGoods = accountingUnifiedCustomerXGoodsMapper.selectByExample(exampleXGoodsLogicMode);
                    }
                }
                break;

            case 后期:

                accountingUnifiedCustomerXGoods = accountingUnifiedCustomerXGoodsMapper.selectByExample(exampleXGoodsLogicMode);

                break;
            default:
                break;
        }

        // 以上代码 为就是 这个
        accountingX = accountingUnifiedCustomerXGoods.size();


        /****************************************** 发票信息 invoice_apply 准备 start ******************************************/

//		invoice_apply

//		make_invoice_user_id	bigint(20)			是	NULL	发票登记部分-开票人登记人-后台帐号
//		make_invoice_time	datetime			是	NULL	发票登记部分-开票时间
//		make_invoice_status	tinyint(3)			是	0	发票登记部分-开票状态 0-未开票;1-已开票;2-重新开票;

//		mail_tick_time	datetime			是	NULL	寄票登记部分-寄票时间
//		express_company_id	bigint(11)			是	NULL	寄票登记部分-快递公司ID
//		express_no	varchar(50)	utf8_general_ci		是	NULL	寄票登记部分-快递单号

//		invoice_status	tinyint(3)			是	0	发票状态 0未邮寄 1已邮寄 2已作废

//		back_account_status	tinyint(3)			是	0	回款状态 0-未回款;1-部分回款;2全部回款;

        /****************************************** 发票关联信息 invoice_order start ******************************************/

//		invoice_order
//		invoice_apply_id 	bigint(11)			是	NULL	invoice_apply.id-发票申请Id

//		accounting_order_type	tinyint(3)			否	0	对账单类型 1-一般;2-积分;
//		dim_create_by	tinyint(3)			否	0	对账单 创建维度:0-订单;1-商品;2-流水;

//		dz_order_id	bigint(11)			是	NULL
//		                                            accounting_order_type=1 dim_create_by=0 代表 accounting_unified_customer_order.id
//		                                            accounting_order_type=1 dim_create_by=1 代表 unified_order.id
//		                                            accounting_order_type=2 dim_create_by=2 代表 unified_order.id
//
//		dz_good_id 	bigint(11)			是	NULL	商品id unified_order_goods.id
//		unified_order_credit_id	bigint(20)			否	0	unifiedOrderCreditId

//		dz_id	bigint(11)			是	NULL	账单id 1. 一般 accounting_unified_customer.id 2. 积分 accounting_score_customer.id

//		back_status	tinyint(3)			是	0	是否已回款 0未回款 1已回款
//		bank_id	bigint(11)			是	NULL	银行流水Id
//		back_time	datetime			是	NULL	回款时间


//		accounting_unified_customer
//		accounting_status	tinyint(3)			否	无	对账单(结算单)状态:0-未确认;1-已确认;-1-已取消;
//		update_time	datetime			是	NULL
//		update_user_id	bigint(20)			是	NULL
//		back_account_status	tinyint(2)			是	0	0-未回款;1-部分回款;2-全部回款


        /****************************************** 以上 start ******************************************/

        // 如果这个对账单0-未回款;1-部分回款; 还得重新查一次

        /******************************************  start ******************************************/
//		推导出
//		1. 从invoice_order.dz_id 反推

        List<InvoiceApplyXGoods>  invoiceXList          = null;
        InvoiceApplyXGoodsExample exampleOfInvoiceOrder = new InvoiceApplyXGoodsExample();
        exampleOfInvoiceOrder.createCriteria()
                .andAccountingOrderIdEqualTo(accountingUnifiedCustomer.getId());
        invoiceXList = invoiceOrderMapper.selectByExample(exampleOfInvoiceOrder);

        // 如果这个为空 证明 没有开票 就没有回款 直接 返回  -1-没办法判定(没有任务开票记录);
        if (AnCollectionUtils.isEmpty(invoiceXList)) {
            report.setIsOverdue(-1);
        }

        // TODO 此处还要得出比较重要的信息


        // 基于 对账单Id 查出来的 有可能是一个对账单 对多 开票
        Integer invoiceXCount = 0;
        // 已回款 计数
        Integer invoiceXBackAccountStatusEq1 = 0;


        invoiceXCount = invoiceXList.size();
        invoiceXBackAccountStatusEq1 = AnIntegerUtils.getInteger(invoiceXList.stream().filter(o -> null != o.getBackStatus() && o.getBackStatus().equals(1)).count());


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

        // TODO 再要判定出这个对账单 是 1*N 还是 1*1
        // key invoiceApplyId : values List<InvoiceOrder>
        Map<Long, List<InvoiceApplyXGoods>> transferMapGroupByInvoiceApplyId = invoiceXList.parallelStream()
                .collect(Collectors.groupingBy(e -> fetchGroupKeyByInvoiceApplyId(e), Collectors.toList()));

        // 1 为 1*1; >1 为 1*N;
        Integer isManyMap = transferMapGroupByInvoiceApplyId.size();


        /****************************************** 这部分可能要再重构,还没想好1*1 1*N 是否有共性与能否拉平的问题 start ******************************************/


        for (Map.Entry<Long, List<InvoiceApplyXGoods>> _entry : transferMapGroupByInvoiceApplyId.entrySet()) {


            Integer _invoiceXCount                = _entry.getValue().size();
            Integer _invoiceXBackAccountStatusEq1 = AnIntegerUtils.getInteger(_entry.getValue().stream().filter(o -> null != o.getBackStatus() && o.getBackStatus().equals(1)).count());

            // 更新发票 回款状态
            invoiceApplyService.updateFieldBackAccountStatusByCheckRatio(_invoiceXCount, _invoiceXBackAccountStatusEq1, _entry.getKey());
            // TODO 更新对账单 回款状态
            accountingUnifiedCustomerService.updateFieldBackAccountStatusByInvoiceX(_entry.getValue());
            // TODO 更新订单 回款状态
            unifiedOrderService.updateFieldBackAccountStatusByInvoiceX(_entry.getValue());
            // TODO 更新商品 回款状态
            unifiedOrderGoodsService.updateFieldBackAccountStatusByInvoiceX(_entry.getValue());

        }
        /****************************************** 这部分可能要再重构,还没想好1*1 1*N 是否有共性与能否拉平的问题   end ******************************************/


        return report;

    }

    private Long fetchGroupKeyByInvoiceApplyId(InvoiceApplyXGoods invoiceOrder) {
        return invoiceOrder.getInvoiceApplyId();
    }


    /**
     * 包装
     *
     * @param accountingOrderSn
     * @return
     */
    public ReportBeOverdueOfStatementOfAccountOfView checkAccountingUnifiedCustomerIsOverdue(String accountingOrderSn) {

        ReportBeOverdueOfStatementOfAccountOfView report = new ReportBeOverdueOfStatementOfAccountOfView();

        AccountingUnifiedCustomerExample example = new AccountingUnifiedCustomerExample();
        example.createCriteria()
                .andAccountingOrderSnEqualTo(accountingOrderSn);
        List<AccountingUnifiedCustomer> result = accountingUnifiedCustomerMapper.selectByExample(example);

        if (AnCollectionUtils.isEmpty(result)) {
            report.setIsOverdue(-1);
            return report;
        }

        AccountingUnifiedCustomer accountingUnifiedCustomer = result.get(0);

        return checkAccountingUnifiedCustomerIsOverdue(accountingUnifiedCustomer);

    }

    /**
     * 包装
     * 从 客户结算对账 对账单出发
     * TODO 做不下去呀 , 问了财务,也没有这个说法,财务 萍姐也是从发票的角度去 催款的 mark by linjinyu at 20210310
     *
     * @param accountingOrderId
     * @return
     */
    public ReportBeOverdueOfStatementOfAccountOfView checkAccountingUnifiedCustomerIsOverdue(Long accountingOrderId) {

        ReportBeOverdueOfStatementOfAccountOfView report = new ReportBeOverdueOfStatementOfAccountOfView();

        AccountingUnifiedCustomer accountingUnifiedCustomer = accountingUnifiedCustomerMapper.selectByPrimaryKey(accountingOrderId);

        if (null == accountingUnifiedCustomer) {
            report.setIsOverdue(-1);
            return report;
        }

        return checkAccountingUnifiedCustomerIsOverdue(accountingUnifiedCustomer);

    }

    /****************************************** 回款逾期 从对账单角度   end ******************************************/

}
