package cn.superdesk.uniorder.service.invoice.supplier.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.superdesk.uniorder.common.enums.accounting.AccountingOrderDimCreateByEnum;
import cn.superdesk.uniorder.common.enums.common.CommonServiceNoEnum;
import cn.superdesk.uniorder.common.enums.common.CommonSourceFromEnum;
import cn.superdesk.uniorder.common.enums.invoice.InvoiceApplyAuditStatusEnum;
import cn.superdesk.uniorder.common.enums.invoice.supplier.*;
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.AnCollectionUtils;
import cn.superdesk.uniorder.common.numerical.AnLongUtils;
import cn.superdesk.uniorder.common.rest.response.R;
import cn.superdesk.uniorder.common.security.dto.LoginSysUser;
import cn.superdesk.uniorder.dao.convert.DtoSugarUpUtils;
import cn.superdesk.uniorder.dao.entity.accounting.unified.supplier.AccountingUnifiedSupplier;
import cn.superdesk.uniorder.dao.entity.invoice.common.InvoiceType;
import cn.superdesk.uniorder.dao.entity.invoice.supplier.InvoiceApplySupplier;
import cn.superdesk.uniorder.dao.entity.invoice.supplier.InvoiceApplySupplierExample;
import cn.superdesk.uniorder.dao.entity.invoice.supplier.InvoiceApplySupplierXGoods;
import cn.superdesk.uniorder.dao.entity.invoice.supplier.InvoiceApplySupplierXGoodsExample;
import cn.superdesk.uniorder.dao.entity.sys.SysUser;
import cn.superdesk.uniorder.dao.mapper.accounting.unified.supplier.AccountingUnifiedSupplierXGoodsMapperEx;
import cn.superdesk.uniorder.dao.mapper.accounting.unified.supplier.AccountingUnifiedSupplierXOrderMapperEx;
import cn.superdesk.uniorder.dao.mapper.invoice.supplier.InvoiceApplySupplierMapper;
import cn.superdesk.uniorder.dao.mapper.invoice.supplier.InvoiceApplySupplierMapperEx;
import cn.superdesk.uniorder.dao.mapper.invoice.supplier.InvoiceApplySupplierXGoodsMapper;
import cn.superdesk.uniorder.dao.mapper.invoice.supplier.InvoiceApplySupplierXGoodsMapperEx;
import cn.superdesk.uniorder.dto.param.invoice.supplier.InvoiceApplySupplierPageVoListQueryCriteria;
import cn.superdesk.uniorder.dto.param.invoice.supplier.InvoiceApplySupplierQueryCriteria;
import cn.superdesk.uniorder.dto.param.invoice.supplier.status.InvoiceApplySupplierOpCommonDimAccountingOrderForm;
import cn.superdesk.uniorder.dto.vo.accounting.unified.supplier.AccountingOrderUnifiedSuplierCheckAmountErrorForFixDimGoods;
import cn.superdesk.uniorder.dto.vo.accounting.unified.supplier.AccountingOrderUnifiedSuplierCheckAmountErrorForFixDimOrder;
import cn.superdesk.uniorder.dto.vo.invoice.supplier.InvoiceApplySupplierHeadVo;
import cn.superdesk.uniorder.dto.vo.invoice.supplier.InvoiceApplySupplierPageVo;
import cn.superdesk.uniorder.dto.vo.invoice.supplier.InvoiceApplySupplierSelectGoodsVo;
import cn.superdesk.uniorder.dto.vo.invoice.supplier.InvoiceApplySupplierXUnifiedOrderGoodsEdVo;
import cn.superdesk.uniorder.service.accounting.unified.supplier.AccountingUnifiedSupplierFieldAccountingStatusService;
import cn.superdesk.uniorder.service.accounting.unified.supplier.AccountingUnifiedSupplierService;
import cn.superdesk.uniorder.service.accounting.unified.supplier.AccountingUnifiedSupplierXGoodsService;
import cn.superdesk.uniorder.service.invoice.common.InvoiceTypeService;
import cn.superdesk.uniorder.service.invoice.supplier.InvoiceApplySupplierService;
import cn.superdesk.uniorder.service.invoice.supplier.InvoiceApplySupplierXGoodsService;
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.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

@Slf4j
@Service
public class InvoiceApplySupplierServiceImpl implements InvoiceApplySupplierService {


    @Autowired
    private InvoiceApplySupplierMapper   invoiceApplySupplierMapper;
    @Autowired
    private InvoiceApplySupplierMapperEx invoiceApplySupplierMapperEx;
    @Autowired
    private InvoiceApplySupplierService  invoiceApplySupplierService;

    @Autowired
    private InvoiceApplySupplierXGoodsMapper   invoiceApplySupplierXGoodsMapper;
    @Autowired
    private InvoiceApplySupplierXGoodsMapperEx invoiceApplySupplierXGoodsMapperEx;
    @Autowired
    private InvoiceApplySupplierXGoodsService  invoiceApplySupplierXGoodsService;

    @Autowired
    private InvoiceTypeService invoiceTypeService;

    @Autowired
    private AccountingUnifiedSupplierXOrderMapperEx accountingUnifiedSupplierXOrderMapperEx;
    @Autowired
    private AccountingUnifiedSupplierXGoodsMapperEx accountingUnifiedSupplierXGoodsMapperEx;


    @Autowired
    private AccountingUnifiedSupplierService                      accountingUnifiedSupplierService;
    @Autowired
    private AccountingUnifiedSupplierXGoodsService                accountingUnifiedSupplierXGoodsService;
    @Autowired
    private AccountingUnifiedSupplierFieldAccountingStatusService accountingUnifiedSupplierFieldAccountingStatusService;

    @Autowired
    private SysUserService sysUserService;


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


    @Override
    public int insertSelective(InvoiceApplySupplier entity) {
        return invoiceApplySupplierMapper.insertSelective(entity);
    }

    @Override
    public int updateByPrimaryKeySelective(InvoiceApplySupplier entity) {
        return invoiceApplySupplierMapper.updateByPrimaryKeySelective(entity);
    }


    @Override
    public void deleteObj(Long id) {

        invoiceApplySupplierMapper.deleteByPrimaryKey(id);
    }

    @Override
    public InvoiceApplySupplier findById(Long id) {
        return invoiceApplySupplierMapper.selectByPrimaryKey(id);
    }

    @Override
    public List<InvoiceApplySupplier> findByIds(List<Long> invoiceApplyIds) {
        InvoiceApplySupplierExample example = new InvoiceApplySupplierExample();
        example.createCriteria()
                .andIdIn(invoiceApplyIds);

        List<InvoiceApplySupplier> resultList = invoiceApplySupplierMapper.selectByExample(example);

        return resultList;
    }

    public List<InvoiceApplySupplier> findByAccountingOrderSn(String accountingOrderSn) {

        // v2.1 发版就已经修正
//		invoice_apply_supplier_x_goods.accounting_order_id 后补的 目前为null 还没有做数据补丁
//		invoice_apply_supplier_x_goods.accounting_order_type 后补的 目前为null 预留 等同于 invoice_apply_supplier.accounting_order_type
//		invoice_apply_supplier_x_goods.dim_create_by 后补的 目前为null 预留 等同于 invoice_apply_supplier.dim_create_by
//		invoice_apply_supplier_x_goods.invoice_apply_id 后补的 目前为null 还没有做数据补丁

//		供应商结算2.0 后,以下两个值是正确的,没值代表是改逻辑前的
//		invoice_apply_supplier.accounting_order_id
//		invoice_apply_supplier.accounting_order_sn

        InvoiceApplySupplierExample example = new InvoiceApplySupplierExample();
        example.createCriteria()
                .andAccountingOrderSnEqualTo(accountingOrderSn);

        List<InvoiceApplySupplier> resultList = invoiceApplySupplierMapper.selectByExample(example);

        return resultList;
    }


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

    @Override
    public List<InvoiceApplySupplier> findAll(Map<String, Object> queryMap) {

        return invoiceApplySupplierMapperEx.findAll(queryMap);
    }


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


    public void addInvoiceApplySupplier(InvoiceApplySupplier entity) {
        invoiceApplySupplierMapper.insertSelective(entity);
    }

    public void updateInvoiceApplySupplier(InvoiceApplySupplier entity) {
        InvoiceApplySupplier originEntity = invoiceApplySupplierMapper.selectByPrimaryKey(entity.getId());
//		AssertUtil.notNull(originEntity);
        AnBeanUtils.copy(entity, originEntity);
        invoiceApplySupplierMapper.updateByPrimaryKey(originEntity);
    }

    public int updateInvoiceApplySupplierByPrimaryKeySelective(InvoiceApplySupplier entity) {
        return invoiceApplySupplierMapper.updateByPrimaryKeySelective(entity);
    }

    public void deleteInvoiceApplySupplier(Long id) {
        invoiceApplySupplierMapper.deleteByPrimaryKey(id);
    }

    public InvoiceApplySupplier findInvoiceApplySupplierById(Long id) {
        InvoiceApplySupplier entity = invoiceApplySupplierMapper.selectByPrimaryKey(id);
//		AssertUtil.notNull(entity);
        return entity;
    }

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

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

        // TODO 喜欢用Map 还是 Bean 自己喜欢... 后期添加 转 InvoiceApplySupplierExample.Criteria
        // InvoiceApplySupplier invoiceApplySupplierConditions = BeanUtils.mapToBean(conditions,InvoiceApplySupplier.class);

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

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

    }

    public R<List<InvoiceApplySupplier>> pageQueryGenericParam(InvoiceApplySupplierQueryCriteria queryCriteria) {

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

        // TODO 添加条件... 后期添加 queryCriteria 转 InvoiceApplySupplierExample.Criteria

        PageHelper.startPage(queryCriteria.getPageNumber(), queryCriteria.getPageSize());
        List<InvoiceApplySupplier>     resultList = invoiceApplySupplierMapper.selectByExample(example);
        PageInfo<InvoiceApplySupplier> page       = new PageInfo<InvoiceApplySupplier>(resultList);
        PageHelper.clearPage();

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

    }


    /****************************************** 重构前存在 start ******************************************/


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

        PageHelper.startPage(pageNo, pageSize);

        List<InvoiceApplySupplier> resultList = invoiceApplySupplierMapperEx.findAll(params);

        PageInfo<InvoiceApplySupplier> pageInfo = new PageInfo<InvoiceApplySupplier>(resultList);
        PageHelper.clearPage();

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

    }

    @Override
    public R<List<InvoiceApplySupplierPageVo>> queryInvoiceApplySupplierPageVoList(InvoiceApplySupplierPageVoListQueryCriteria queryCriteria, LoginSysUser loginSysUser) {

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

        List<InvoiceApplySupplier> resultList = invoiceApplySupplierMapperEx.queryInvoiceApplySupplierPageVoList(queryCriteria);

        PageInfo<InvoiceApplySupplier> pageInfo = new PageInfo<InvoiceApplySupplier>(resultList);
        PageHelper.clearPage();

        //
        List<InvoiceApplySupplierPageVo> convertResultList = convertToPageVo(resultList);

        additionalInfoFindViewByPageFocusCommon(convertResultList);

        DtoSugarUpUtils.sugarUpInvoiceApplySupplierPageVo(convertResultList);

        return new R<List<InvoiceApplySupplierPageVo>>(pageInfo.getPageNum(), pageInfo.getPageSize(), (int) pageInfo.getTotal(), convertResultList);
    }

    private List<InvoiceApplySupplierPageVo> convertToPageVo(List<InvoiceApplySupplier> resultList) {


        List<InvoiceApplySupplierPageVo> convertResultList = new ArrayList<>();

        resultList.forEach(item -> {
            InvoiceApplySupplierPageVo vo = AnBeanUtils.copy(item, InvoiceApplySupplierPageVo.class);

            convertResultList.add(vo);
        });

        return convertResultList;

    }

    private void additionalInfoFindViewByPageFocusCommon(List<InvoiceApplySupplierPageVo> 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.getPayoffAccountUserId() != null).filter(AnLamdaUtils.distinctByKey(o -> o.getPayoffAccountUserId())).map(o -> o.getPayoffAccountUserId()).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 = sysUserIds.stream().distinct().collect(Collectors.toList());

        log.info("\n{}", AnJsonUtils.toJson(sysUserIds));

        Map<Long, SysUser>     sysUserMap     = sysUserService.convertSysUserIds2MapSysUserId2Entity(sysUserIds);
        Map<Long, InvoiceType> invoiceTypeMap = invoiceTypeService.convertToMapFieldId2Entity();

        for (InvoiceApplySupplierPageVo vo : resultList) {

            // 补 状态名称
            vo.setAuditStatusName(InvoiceApplyAuditStatusEnum.getDesc(vo.getAuditStatus()));
            vo.setInvoiceProgressingStatusName(InvoiceApplySupplierInvoiceProgressingStatusEnum.getDesc(vo.getInvoiceStatus()));
            vo.setMakeInvoiceStatusName(InvoiceApplySupplierMakeInvoiceStatusEnum.getDesc(vo.getMakeInvoiceStatus()));
            vo.setReceiveInvoiceStatusName(InvoiceApplySupplierReceiveInvoiceStatusEnum.getDesc(vo.getReceiveInvoiceStatus()));
            vo.setMailTickStatusName(InvoiceApplySupplierMailTickStatusEnum.getDesc(vo.getMailTickStatus()));
            vo.setPayoffAccountStatusName(InvoiceApplySupplierPayOffAccountStatusEnum.getDesc(vo.getPayoffAccountStatus()));

            // 补 人员信息
            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.getPayoffAccountUserId()) != null) {
                vo.setPayoffAccountUserName(sysUserMap.get(vo.getPayoffAccountUserId()).getFullname());
            }

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

            // 补 订单类型-订单来源-引用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.UNKNOW.getSourceFromName());
            }

        }


    }

    @Override
    public InvoiceApplySupplierHeadVo getInvoiceApplyListHeadSum(Map<String, Object> params) {

        return invoiceApplySupplierMapperEx.getDataPageHead(params);
    }

    /**
     * <p>
     * -- accountingOrderSn aus.accounting_order_sn
     * -- ids uog.id
     * <p>
     * <p>
     * -- 弃用 supplierId    uo.sale_id
     * -- 弃用 supplierName  uo.sale_name
     *
     * @param params
     * @return
     */
    @Override
    public List<InvoiceApplySupplierSelectGoodsVo> getStatementOfAccountGoodsListByAccountingOrderSn(String accountingOrderSn) {

        Map<String, Object> params = new HashMap<>();
        params.put("accountingOrderSn", accountingOrderSn);
        params.put("orderBy", "uo.create_time asc, uo.order_sn asc");

        List<InvoiceApplySupplierSelectGoodsVo> resultList = new ArrayList<>();

        AccountingUnifiedSupplier statementOfAccount = accountingUnifiedSupplierService.findByAccountingOrderSn(accountingOrderSn);

        // 处理 对账单维度 差异 TODO 待重构
        switch (AccountingOrderDimCreateByEnum.get(statementOfAccount.getDimCreateBy())) {

            case 订单:

//                result = unifiedSupplierInvMapperEx.getStatementOfAccountDimOrder2GoodsList(params);

                // 先得出一份 对账单 X 商品 的数据
                List<AccountingOrderUnifiedSuplierCheckAmountErrorForFixDimOrder> statementOfAccountDetailDimOrder2GoodsResultList = accountingUnifiedSupplierXOrderMapperEx.checkAmountErrorForFixDimOrder(params);

                for (AccountingOrderUnifiedSuplierCheckAmountErrorForFixDimOrder itemDim0 : statementOfAccountDetailDimOrder2GoodsResultList) {

                    InvoiceApplySupplierSelectGoodsVo vo0 = new InvoiceApplySupplierSelectGoodsVo();

                    vo0.setAccountingOrderId(itemDim0.getAccountingOrderId());
                    vo0.setAccountingOrderSn(itemDim0.getAccountingOrderSn());

                    vo0.setUnifiedOrderId(itemDim0.getUnifiedOrderId());
                    vo0.setOrderSn(itemDim0.getOrderSn());

                    vo0.setUnifiedOrderGoodsId(itemDim0.getUnifiedOrderGoodsId());
                    vo0.setGoodsId(itemDim0.getGoodsId());
                    vo0.setOutSnapshotOrderGoodsId(itemDim0.getOutSnapshotOrderGoodsId());

                    vo0.setGoodsName(itemDim0.getGoodsName());
                    vo0.setGoodsAlias(itemDim0.getGoodsAlias());

                    // vo0.setPrice(itemDim0.getPrice());
                    vo0.setCostPrice(itemDim0.getCostPrice());
                    vo0.setQuantity(itemDim0.getQuantity());

                    vo0.setUnit(itemDim0.getUnit());
                    // vo0.setTaxRate(itemDim0.getTaxRate());
                    // vo0.setTaxCode(itemDim0.getTaxCode());

                    vo0.setMerchTaxRate(itemDim0.getMerchTaxRate());
                    vo0.setMerchTaxCode(itemDim0.getMerchTaxCode());
                    vo0.setMerchTaxId(itemDim0.getMerchTaxId());

                    // vo0.setOperationTaxRate(itemDim0.getOperationTaxRate());
                    // vo0.setOperationTaxCode(itemDim0.getOperationTaxCode());
                    // vo0.setOperationTaxId(itemDim0.getOperationTaxId());

                    resultList.add(vo0);
                }

                break;
            case 商品:

                // 先得出一份 对账单 X 商品 的数据
                List<AccountingOrderUnifiedSuplierCheckAmountErrorForFixDimGoods> statementOfAccountDetailDimGoods2GoodsResultList = accountingUnifiedSupplierXGoodsMapperEx.checkAmountErrorForFixDimGoods(params);

                for (AccountingOrderUnifiedSuplierCheckAmountErrorForFixDimGoods itemDim1 : statementOfAccountDetailDimGoods2GoodsResultList) {

                    InvoiceApplySupplierSelectGoodsVo vo1 = new InvoiceApplySupplierSelectGoodsVo();

                    vo1.setAccountingOrderId(itemDim1.getAccountingOrderId());
                    vo1.setAccountingOrderSn(itemDim1.getAccountingOrderSn());

                    vo1.setUnifiedOrderId(itemDim1.getUnifiedOrderId());
                    vo1.setOrderSn(itemDim1.getOrderSn());

                    vo1.setUnifiedOrderGoodsId(itemDim1.getUnifiedOrderGoodsId());
                    vo1.setGoodsId(itemDim1.getGoodsId());
                    vo1.setOutSnapshotOrderGoodsId(itemDim1.getOutSnapshotOrderGoodsId());

                    vo1.setGoodsName(itemDim1.getGoodsName());
                    vo1.setGoodsAlias(itemDim1.getGoodsAlias());

                    // vo1.setPrice(itemDim1.getPrice());
                    vo1.setCostPrice(itemDim1.getCostPrice());
                    vo1.setQuantity(itemDim1.getQuantity());

                    vo1.setUnit(itemDim1.getUnit());

                    // vo1.setTaxRate(itemDim1.getTaxRate());
                    // vo1.setTaxCode(itemDim1.getTaxCode());

                    vo1.setMerchTaxRate(itemDim1.getMerchTaxRate());
                    vo1.setMerchTaxCode(itemDim1.getMerchTaxCode());
                    vo1.setMerchTaxId(itemDim1.getMerchTaxId());

                    // vo1.setOperationTaxRate(itemDim1.getOperationTaxRate());
                    // vo1.setOperationTaxCode(itemDim1.getOperationTaxCode());
                    // vo1.setOperationTaxId(itemDim1.getOperationTaxId());


                    resultList.add(vo1);
                }
                break;
            default:

                break;
        }

        DtoSugarUpUtils.sugarUpInvoiceApplySupplierSelectGoodsVo(resultList);

        return resultList;
    }

    /**
     * TODO 待重构
     *
     * @param processSysUnifiedOrderGoodsIds
     * @return
     */
    public List<InvoiceApplySupplierSelectGoodsVo> getStatementOfAccountGoodsListBySysUnifiedOrderGoodsIds(String accountingOrderSn, List<Long> processSysUnifiedOrderGoodsIds) {

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

        Map<String, Object> params = new HashMap<>();
        params.put("accountingOrderSn", accountingOrderSn);
        params.put("unifiedOrderGoodsIds", processSysUnifiedOrderGoodsIds);


        // 先得出一份 对账单 X 商品 的数据
        List<AccountingOrderUnifiedSuplierCheckAmountErrorForFixDimGoods> temp = accountingUnifiedSupplierXGoodsMapperEx.checkAmountErrorForFixDimGoods(params);

        for (AccountingOrderUnifiedSuplierCheckAmountErrorForFixDimGoods itemDim1 : temp) {

            InvoiceApplySupplierSelectGoodsVo vo1 = new InvoiceApplySupplierSelectGoodsVo();

            vo1.setAccountingOrderId(itemDim1.getAccountingOrderId());
            vo1.setAccountingOrderSn(itemDim1.getAccountingOrderSn());

            vo1.setUnifiedOrderId(itemDim1.getUnifiedOrderId());
            vo1.setOrderSn(itemDim1.getOrderSn());

            vo1.setUnifiedOrderGoodsId(itemDim1.getUnifiedOrderGoodsId());
            vo1.setGoodsId(itemDim1.getGoodsId());
            vo1.setOutSnapshotOrderGoodsId(itemDim1.getOutSnapshotOrderGoodsId());

            vo1.setGoodsName(itemDim1.getGoodsName());
            vo1.setGoodsAlias(itemDim1.getGoodsAlias());

            // vo.setPrice(item.getPrice());
            vo1.setCostPrice(itemDim1.getCostPrice());
            vo1.setQuantity(itemDim1.getQuantity());

            // vo1.setTaxRate(itemDim1.getTaxRate());
            // vo1.setTaxCode(itemDim1.getTaxCode());

            vo1.setMerchTaxRate(itemDim1.getMerchTaxRate());
            vo1.setMerchTaxCode(itemDim1.getMerchTaxCode());
            vo1.setMerchTaxId(itemDim1.getMerchTaxId());

            // vo1.setOperationTaxRate(itemDim1.getOperationTaxRate());
            // vo1.setOperationTaxCode(itemDim1.getOperationTaxCode());
            // vo1.setOperationTaxId(itemDim1.getOperationTaxId());


            result.add(vo1);
        }

        return result;

    }

    @Override
    public List<InvoiceApplySupplierSelectGoodsVo> invoiceApplySelectFocusUnified(String accountingOrderSn) {

        List<InvoiceApplySupplierSelectGoodsVo>          result             = new ArrayList<>();
        List<InvoiceApplySupplierSelectGoodsVo>          resultFilter       = new ArrayList<>();
        List<InvoiceApplySupplierXUnifiedOrderGoodsEdVo> appliedGoodsVoList = new ArrayList<>();

        // 某对账单的记录
        result = getStatementOfAccountGoodsListByAccountingOrderSn(accountingOrderSn);

        // 基于对账单Sn 反查 有作用的 开票申请 再得出 商品

        appliedGoodsVoList = invoiceApplySupplierXGoodsMapperEx.getInvoiceApplyXUnifiedOrderGoodsEd(accountingOrderSn);

        if (AnCollectionUtils.isNotEmpty(appliedGoodsVoList)) {

            List<Long> appliedGoodsIds = appliedGoodsVoList.stream().filter(AnLamdaUtils.distinctByKey(o -> o.getUnifiedOrderGoodsId())).map(o -> o.getUnifiedOrderGoodsId()).collect(Collectors.toList());

            // 排除在 容器 内记录
            List<Predicate<InvoiceApplySupplierSelectGoodsVo>> predicatesByOne = new ArrayList<>();
            predicatesByOne.add(r -> !appliedGoodsIds.contains(r.getUnifiedOrderGoodsId()));

            resultFilter = AnLamdaUtils.filters(result, predicatesByOne);

        } else {
            resultFilter = result;
        }

        log.info("\n开票申请 搜索 accountingOrderSn : {}\n\n\n\n原始数据 : {}\n排除商品 : {}\n过滤结果 : {}\n\n\n\n",
                accountingOrderSn,
                AnJsonUtils.toJson(result), AnJsonUtils.toJson(appliedGoodsVoList), AnJsonUtils.toJson(resultFilter));

        return resultFilter;
    }

    /**
     * 这个供应商对账 开票申请好像逻辑上是没变,基于订单|商品维度创建的对账单是同样兼容
     *
     * @param invoiceApplyEntity
     * @param processList
     * @return
     */
    @Transactional
    @Override
    public InvoiceApplySupplier opInvoiceApply(InvoiceApplySupplier invoiceApplyEntity, List<InvoiceApplySupplierXGoods> processList) {

        int ret = invoiceApplySupplierMapper.insert(invoiceApplyEntity);

        log.info("opInvoiceApply 主表 ret = {}", ret);

        processList.forEach(item -> {
            item.setInvoiceApplyId(invoiceApplyEntity.getId());
        });

        log.info("{}", JSONUtil.toJsonStr(processList));

        try {
            invoiceApplySupplierXGoodsMapperEx.insertBatch(processList);
        } catch (Exception e) {
            e.printStackTrace();
        }


        /****************************************** mark by linjinyu 20201104 start ******************************************/

        // TODO 相关于状态要更新
        // 0. 得出 这个 开票申请 影响的 对账单
        // 1. 对账单 开票状态 要作判定
        // 2. 对商品 开票状态 修改 AccountingOrderInvoiceStatusEnum TODO 目前没有字段

        // 关联 更新 "对账单" 开票申请状态 初始化 开票进展状态
        opBecomeInvalidTailAccountingOrderRunUpdateInvoiceStatusBasisOfX(Arrays.asList(invoiceApplyEntity.getInvoiceApplySn()));

        /****************************************** mark by linjinyu 20201104   end ******************************************/

        return invoiceApplyEntity;
    }


    public String opPhysicsDelete(InvoiceApplySupplier entity, LoginSysUser loginSysUser) {

        // TODO 怎样溯源|留痕? 有空再想 mark by linjinyu at 20211216


        // 依懒 关系
        // 关联 更新 "对账单" AccountingUnifiedSupplier
        // 1. 开票申请状态 0-未开票;1-全部开票;2-部分开票; - 判定得出 - AccountingUnifiedSupplier.invoiceApplyStatus
        // 2. 开票申请进度 AccountingUnifiedSupplier.invoiceStatus(InvoiceApplySupplierInvoiceProgressingStatusEnum.待开票.getKey());
        opBecomeInvalidTailAccountingOrderRunUpdateInvoiceStatusBasisOfX(Arrays.asList(entity.getInvoiceApplySn()));

        // 清除 关系 X
        opBecomeInvalidTailCleanInvoiceApplySupplierXGoods(Arrays.asList(entity.getInvoiceApplySn()));

        int ret = invoiceApplySupplierMapper.deleteByPrimaryKey(entity.getId());

        return "";
    }

    /**
     * 供应商结算-货款管理-row opt 重新开票 mark by linjinyu 20201104
     *
     * @param entity
     */
    @Override
    public String opBecomeInvalid(InvoiceApplySupplier entity, LoginSysUser loginSysUser) {

        /****************************************** opBecomeInvalid 操作变动逻辑 start ******************************************/

        String reason = StrUtil.format("撤销开票[撤销人:{},撤销时间:{},原因:{}]", loginSysUser.getFullName(), DateUtil.now(), "");
        opBecomeInvalidStateFlow(entity, reason, loginSysUser);

        /****************************************** mark by linjinyu 20201104   end ******************************************/

        // 依懒 关系 X
        opBecomeInvalidTailAccountingOrderRunOpCancelByStateMachine(Arrays.asList(entity.getInvoiceApplySn()), loginSysUser);// 单个的维度与对账单维度差异

        // 清除 关系 X
        opBecomeInvalidTailCleanInvoiceApplySupplierXGoods(Arrays.asList(entity.getInvoiceApplySn()));

        return "";
    }

    // DimAccountingOrder
    public String opBecomeInvalid(List<InvoiceApplySupplier> entitys, InvoiceApplySupplierOpCommonDimAccountingOrderForm form, LoginSysUser loginSysUser) {


        String reason = form.createReason(loginSysUser);

        entitys.forEach(entity -> {

            opBecomeInvalidStateFlow(entity, reason, loginSysUser);

//				if (ret == 1) {
//					count++;
//				}

        });

        // 依懒 关系 X
        // 关联 撤消 "对账单" AccountingUnifiedSupplier
        List<String> invoiceApplySns = entitys.stream().filter(AnLamdaUtils.distinctByKey(o -> o.getInvoiceApplySn())).map(o -> o.getInvoiceApplySn()).collect(Collectors.toList());
        opBecomeInvalidTailAccountingOrderRunOpCancelByStateMachine(invoiceApplySns, loginSysUser);

        // 清除 关系 X
        opBecomeInvalidTailCleanInvoiceApplySupplierXGoods(invoiceApplySns);

        return "";
    }

    private int opBecomeInvalidStateFlow(InvoiceApplySupplier entity, String reason, LoginSysUser loginSysUser) {

        InvoiceApplySupplier invoiceApplySupplier4Update = new InvoiceApplySupplier();

        invoiceApplySupplier4Update.setId(entity.getId());

        // 设置 撤消原因 格式 : 撤销开票[撤销人:{},撤销时间:{},原因:{}]
        invoiceApplySupplier4Update.setRemark(reason);

        // 设置申请状态 已作废 记录 时间 与 操作人
        invoiceApplySupplier4Update.setInvoiceStatus(InvoiceApplySupplierInvoiceProgressingStatusEnum.已作废.getKey());
        invoiceApplySupplier4Update.setInvoiceProgressingTime(DateUtil.date());
        invoiceApplySupplier4Update.setInvoiceProgressingUserId(loginSysUser.getSysUserId());

        // 设置开票状态 已撤消(弃) 记录 时间 与 操作人
//		invoiceApplySupplier4Update.setMakeInvoiceStatus(InvoiceApplySupplierMakeInvoiceStatusEnum.已撤消.getKey());
        invoiceApplySupplier4Update.setMakeInvoiceTime(DateUtil.date());
        invoiceApplySupplier4Update.setMakeInvoiceUserId(loginSysUser.getSysUserId());
        invoiceApplySupplier4Update.setMakeInvoiceUserName(loginSysUser.getFullName());

        int ret = updateInvoiceApplySupplierByPrimaryKeySelective(invoiceApplySupplier4Update);

        // TODO 相关于状态要更新
        // 0. 得出 这个 开票申请 影响的 对账单
        // 1. 对账单 开票状态 要作判定
        // 2. 对商品 开票状态 修改 AccountingOrderInvoiceStatusEnum TODO 目前没有字段


        // 关联 更新 "对账单" AccountingUnifiedSupplier
        // 1. 开票申请状态 0-未开票;1-全部开票;2-部分开票; - 判定得出 - AccountingUnifiedSupplier.invoiceApplyStatus
        // 2. 开票申请进度 AccountingUnifiedSupplier.invoiceStatus(InvoiceApplySupplierInvoiceProgressingStatusEnum.待开票.getKey());
//		opBecomeInvalidTailAccountingOrderUpdateInvoiceStatusBasisOfX(entity.getInvoiceApplySn());

        // 清除 关系 X
//		opBecomeInvalidTailCleanInvoiceApplySupplierXGoods(entity.getInvoiceApplySn());

        return ret;
    }

    private int opBecomeInvalidTailCleanInvoiceApplySupplierXGoods(List<String> invoiceApplySns) {
        // 删除 关联关系 invoiceApplyXGoodsItem
        int ret = invoiceApplySupplierXGoodsMapperEx.deleteByInvoiceApplySns(invoiceApplySns);
        return ret;
    }

    /**
     * 依懒 关系 X
     * 关联 更新 "对账单" AccountingUnifiedSupplier
     * 1. 开票申请状态 0-未开票;1-全部开票;2-部分开票; - 判定得出 - AccountingUnifiedSupplier.invoiceApplyStatus
     * 2. 开票申请进度 AccountingUnifiedSupplier.invoiceStatus(InvoiceApplySupplierInvoiceProgressingStatusEnum.待开票.getKey());
     *
     * @param invoiceApplySns
     */
    private void opBecomeInvalidTailAccountingOrderRunUpdateInvoiceStatusBasisOfX(List<String> invoiceApplySns) {

        List<String> affectedAccountingOrderSns = invoiceApplySupplierXGoodsService.getAffectedAccountingOrderSnsByInvoiceApplySns(invoiceApplySns);

        for (String processAccountingOrderSn : affectedAccountingOrderSns) {
            invoiceApplySupplierXGoodsService.checkInvoiceApplyStatusByAccountingOrderSnAndUpdateAccountingEntityFocusSupplier(processAccountingOrderSn);
        }
    }

    /**
     * 依懒 关系 X
     * 关联 撤消 "对账单" AccountingUnifiedSupplier
     *
     * @param invoiceApplySns
     * @param loginSysUser
     */
    private void opBecomeInvalidTailAccountingOrderRunOpCancelByStateMachine(List<String> invoiceApplySns, LoginSysUser loginSysUser) {

        List<String> affectedAccountingOrderSns = invoiceApplySupplierXGoodsService.getAffectedAccountingOrderSnsByInvoiceApplySns(invoiceApplySns);

        log.info("opBecomeInvalidTailAccountingOrderRunOpCancelByStateMachine 撤消 \n开票申请编号__ : {}\n受影响对账单编号 : {}", JSONUtil.toJsonStr(invoiceApplySns), JSONUtil.toJsonStr(affectedAccountingOrderSns));

        for (String processAccountingOrderSn : affectedAccountingOrderSns) {

            AccountingUnifiedSupplier accountingUnifiedSupplier = accountingUnifiedSupplierService.findByAccountingOrderSn(processAccountingOrderSn);
            accountingUnifiedSupplierFieldAccountingStatusService.opCancelByStateMachine(accountingUnifiedSupplier, loginSysUser);
        }


    }


    @Override
    public void deleteInvoiceApplySupplierBatch(String accountingOrderSn) {
        InvoiceApplySupplierExample example = new InvoiceApplySupplierExample();
        example.createCriteria().andAccountingOrderSnEqualTo(accountingOrderSn);
        invoiceApplySupplierMapper.deleteByExample(example);
    }


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


    public void patchInvoiceApplyFieldStatistics() {

        // 先得到全部对账

        // 已拒绝的关联关系也没了,没必要拉出来了
        InvoiceApplySupplierExample example = new InvoiceApplySupplierExample();
        example.createCriteria()
//                <!-- 1-未审核;2-同意;3-拒绝 -->
//                inva.audit_status in (1,2)
                .andAuditStatusIn(Arrays.asList(1, 2));

        List<InvoiceApplySupplier> processInvoiceApplyList = invoiceApplySupplierMapper.selectByExample(example);

        // 每个开票申请
        for (InvoiceApplySupplier invoiceApplyEntity4Process : processInvoiceApplyList) {

            List<InvoiceApplySupplierSelectGoodsVo> invoiceApplySupplierSelectGoodsVoList = new ArrayList<>();

            // 得到每份关联数据
            InvoiceApplySupplierXGoodsExample getInvoiceApplyXExample = new InvoiceApplySupplierXGoodsExample();
            getInvoiceApplyXExample.clear();
            getInvoiceApplyXExample.createCriteria()
                    .andInvoiceApplySnEqualTo(invoiceApplyEntity4Process.getInvoiceApplySn());

            List<InvoiceApplySupplierXGoods> X = invoiceApplySupplierXGoodsMapper.selectByExample(getInvoiceApplyXExample);


            // 假定每份数据都可能 包含多个对账单
            Map<String, List<Long>> processAccountingOrderList = X.parallelStream()
                    .collect(Collectors.groupingBy(InvoiceApplySupplierXGoods::getAccountingOrderSn, Collectors.mapping(InvoiceApplySupplierXGoods::getGoodsId, Collectors.toList())));

            for (Map.Entry<String, List<Long>> _entry : processAccountingOrderList.entrySet()) {

                List<InvoiceApplySupplierSelectGoodsVo> sampleData = invoiceApplySupplierService.getStatementOfAccountGoodsListBySysUnifiedOrderGoodsIds(_entry.getKey(), _entry.getValue());

                if (AnCollectionUtils.isNotEmpty(sampleData)) {
                    invoiceApplySupplierSelectGoodsVoList.addAll(sampleData);
                }
            }


            InvoiceApplySupplier invoiceApplyEntity4Update = new InvoiceApplySupplier();

            invoiceApplyEntity4Update.setId(invoiceApplyEntity4Process.getId());

            /****************************************** 统计 start ******************************************/

            Long accountingOrderSnCount = invoiceApplySupplierSelectGoodsVoList.stream().filter(AnLamdaUtils.distinctByKey(o -> o.getAccountingOrderSn())).map(o -> o.getAccountingOrderSn()).collect(Collectors.counting());
            Long orderSnCount           = invoiceApplySupplierSelectGoodsVoList.stream().filter(AnLamdaUtils.distinctByKey(o -> o.getOrderSn())).map(o -> o.getOrderSn()).collect(Collectors.counting());
            Long goodsQuantity          = invoiceApplySupplierSelectGoodsVoList.stream().map(o -> o.getUnifiedOrderGoodsId()).collect(Collectors.counting());
            Long goodsItemQuantity      = invoiceApplySupplierSelectGoodsVoList.stream().map(o -> o.getQuantity()).collect(Collectors.counting());

            BigDecimal goodsAmount = invoiceApplySupplierSelectGoodsVoList
                    .stream()
                    .map(item -> item.getCostPrice() == null ? BigDecimal.ZERO : item.getPrice().multiply(new BigDecimal(item.getQuantity())))
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            BigDecimal goodsCostAmount = invoiceApplySupplierSelectGoodsVoList
                    .stream()
                    .map(item -> item.getCostPrice() == null ? BigDecimal.ZERO : item.getCostPrice().multiply(new BigDecimal(item.getQuantity())))
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            invoiceApplyEntity4Update.setAccountingOrderQuantity(accountingOrderSnCount.intValue());
            invoiceApplyEntity4Update.setOrderQuantity(orderSnCount.intValue());
            invoiceApplyEntity4Update.setOrderAmount(goodsCostAmount);
            invoiceApplyEntity4Update.setGoodsAmount(goodsAmount);
            invoiceApplyEntity4Update.setGoodsCostAmount(goodsCostAmount);
            invoiceApplyEntity4Update.setGoodsQuantity(goodsQuantity.intValue());
            invoiceApplyEntity4Update.setGoodsItemQuantity(goodsItemQuantity.intValue());

            invoiceApplySupplierMapper.updateByPrimaryKeySelective(invoiceApplyEntity4Update);

            /****************************************** 统计   end ******************************************/

        }


    }

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

        int ret = 0;

        List<InvoiceApplySupplier> invoiceApplySupplierList = findByAccountingOrderSn(accountingOrderSn);

        if (CollUtil.isNotEmpty(invoiceApplySupplierList)) {

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

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

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

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

            ret = invoiceApplySupplierMapper.updateByExampleSelective(sample, example);


        }

        return ret;
    }


}
