package cn.superdesk.uniorder.service.thirdpart.qchjc.statistics.impl;

import cn.hutool.core.io.FileUtil;
import cn.superdesk.uniorder.common.enums.thirdpart.jd.SysQuartzScheduleTaskStatementOfAccountRunStateEnum;
import cn.superdesk.uniorder.common.excel.ExcelResponse;
import cn.superdesk.uniorder.common.numerical.AnBeanUtils;
import cn.superdesk.uniorder.common.numerical.AnDateUtils;
import cn.superdesk.uniorder.common.rest.response.R;
import cn.superdesk.uniorder.common.security.dto.LoginSysUser;
import cn.superdesk.uniorder.dao.entity.base.UnifiedOrderGoods;
import cn.superdesk.uniorder.dao.entity.statistics.prayable.*;
import cn.superdesk.uniorder.dao.entity.sys.notify.SysNotify;
import cn.superdesk.uniorder.dao.mapper._statistics.*;
import cn.superdesk.uniorder.dao.mapper.base.UnifiedOrderGoodsMapper;
import cn.superdesk.uniorder.dto._constant.ResourceConstant;
import cn.superdesk.uniorder.dto.param.accounting.statistics.ReceivableDetailDataQueryParam;
import cn.superdesk.uniorder.dto.param.accounting.statistics.ReceivableStatisticsPageQueryParam;
import cn.superdesk.uniorder.dto.vo._statistics.ReceivableDayDataVo;
import cn.superdesk.uniorder.dto.vo._statistics.ReceivableStatisticsExportDateExcelVo;
import cn.superdesk.uniorder.dto.vo._statistics.payable.*;
import cn.superdesk.uniorder.notify.NotifyUtils;
import cn.superdesk.uniorder.service.thirdpart.qchjc.statistics.PayableStatisticsService;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.excel.write.metadata.fill.FillWrapper;
import com.alibaba.fastjson2.JSON;
import com.github.pagehelper.PageHelper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author xc
 * @description
 * @date 2022/4/1 11:43
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PayableStatisticsServiceImpl implements PayableStatisticsService {

    @Autowired
    private ResourceConstant excelExportConstant;

    private static final String TEMPLATE_EXPORT_EXCEL_PAYABLE_STATISTIC = "exportPayableStatistic.xlsx";


    //应收查询Mapper
    private final ReceivableStatisticsMapper receivableStatisticsMapper;

    //应付查询Mapper
    private final PayableStatisticsMapper payableStatisticsMapper;


    private final UnifiedOrderGoodsMapper unifiedOrderGoodsMapper;


    //应付明细Mapper
    private final StPayableDetailDataEntityMapper stPayableDetailDataEntityMapper;



    //应付每日明细
    private final StPayableDayDataEntityMapper stPayableDayDataEntityMapper;


    //应付供应商帐单未冲销记录
    private final StPayableChargeAgainstRecordEntityMapper stPayableChargeAgainstRecordEntityMapper;




    /***
     * 保存应付明细数据
     * @param queryParam
     */
    @Override
    public void savePayableDetailData(ReceivableDetailDataQueryParam queryParam, LoginSysUser loginSysUser) {

        log.info("\n===>保存应付明细数据-savePayableDetailData 参数:{}", JSON.toJSONString(queryParam));

        //查询应付明细数据
        List<PayableDetailDataVo> receivableDetailDataVoList = payableStatisticsMapper.queryPayableDetailData(queryParam);

        //Map<String, List<PayableDetailDataVo>> orderSnMap = receivableDetailDataVoList.stream().collect(Collectors.groupingBy(PayableDetailDataVo::getOrderSn));
        //Map<String, PayableDetailDataVo> orderSnMap = receivableDetailDataVoList.stream().collect(Collectors.toMap(PayableDetailDataVo::getOrderSn, Function.identity()));

        List<String> orderSnList  = receivableDetailDataVoList.stream().map(PayableDetailDataVo::getOrderSn).collect(Collectors.toList());
        orderSnList.add("ME20210303143102088615");
        queryParam.setOrderSnList(orderSnList);


        //同步处理 - 商户承担运费
        List<PayableDetailDataVo> listFreightDetailData =  payableStatisticsMapper.queryPayableFreightDetailData(queryParam);


        //补帐单字段
        for(PayableDetailDataVo payableDetailDataVo :listFreightDetailData){

            /*if(orderSnMap.containsKey(payableDetailDataVo.getOrderSn())){
                PayableDetailDataVo payableDetailDataVo1 = orderSnMap.get(payableDetailDataVo.getOrderSn());
                if(null != payableDetailDataVo1){
                    payableDetailDataVo.setAccountingOrderSn(payableDetailDataVo1.getAccountingOrderSn());
                    //payableDetailDataVo.setC
                }
            }*/
            payableDetailDataVo.setAccountingOrderSn(queryParam.getAccountingOrderSn());
        }
        receivableDetailDataVoList.addAll(listFreightDetailData);



        log.info("\n===>保存应付明细数据-查询应付明细数据 条数:{}", receivableDetailDataVoList.size());

        //保存应付明细数据
        int num = 1;
        for(PayableDetailDataVo payableDetailDataVo : receivableDetailDataVoList){

            log.info("\n===>保存应付明细数据-当前处理第:{} 条", num);
            ++ num;

            StPayableDetailDataEntity stPayableDetailDataEntity = AnBeanUtils.copy(payableDetailDataVo, StPayableDetailDataEntity.class);


            //生成该应付流水数据时计算：税额=该应付流水的结算成本-成本(不含税)，保留小数点两位
            stPayableDetailDataEntity.setTaxAmount(stPayableDetailDataEntity.getBalanceCost().subtract(stPayableDetailDataEntity.getCostNoTax()));


            //#应付账款=成本（不含税）+税额
            //#costNoTax+tax_amount 代码计算
            stPayableDetailDataEntity.setPayableAmount(stPayableDetailDataEntity.getCostNoTax().add(stPayableDetailDataEntity.getTaxAmount()));


            //生成该应付流水数据时计算：成本（不含税）=该应付流水的结算成本/（1+税率），金额四舍五入，保留小数点两位
            stPayableDetailDataEntity.setCostNoTax(stPayableDetailDataEntity.getBalanceCost().divide(BigDecimal.ZERO.add(stPayableDetailDataEntity.getMerchTaxRate()),2, BigDecimal.ROUND_HALF_DOWN));


            if(StringUtils.isNotEmpty(stPayableDetailDataEntity.getRefundOrderSn())){ //售后订单
                //转为负值
                stPayableDetailDataEntity.setGoodsQuantity(- stPayableDetailDataEntity.getGoodsQuantity());
                stPayableDetailDataEntity.setCostNoTax(stPayableDetailDataEntity.getCostNoTax().negate());
                stPayableDetailDataEntity.setPayableAmount(stPayableDetailDataEntity.getPayableAmount().negate());
            }

            stPayableDetailDataEntity.setCreateUserId(loginSysUser.getSysUserId());
            stPayableDetailDataEntity.setCreatedAt(new Date());
            stPayableDetailDataEntity.setCreateUserName(loginSysUser.getFullName());
            stPayableDetailDataEntity.setAccountAt(new Date());
            stPayableDetailDataEntity.setAccountState(Byte.valueOf("0"));//入账状态 0未入账 1已入账 3撤销入账 4已撤销
            stPayableDetailDataEntity.setAccountingOrderSn(payableDetailDataVo.getAccountingOrderSn());
            stPayableDetailDataEntity.setAccountingState(Byte.valueOf("1"));////对账状态 1-已确认;-1-已取消
            stPayableDetailDataEntity.setDataType(Byte.valueOf("1"));


            //客户结算中心id
            StPayableDetailDataEntityExample stReceivableDetailDataEntityExample = new StPayableDetailDataEntityExample();
            stReceivableDetailDataEntityExample.createCriteria().andCreditIdEqualTo(stPayableDetailDataEntity.getCreditId());

            //数据库是否存在 不存在 才保存明细和 改应收统计状态
            Integer accountStateNum = stPayableDetailDataEntityMapper.selectByExample(stReceivableDetailDataEntityExample).size();
            if (accountStateNum == 0) { //定时任务保存 不做更新 需要时在修改

                //明细数据
                stPayableDetailDataEntityMapper.insertSelective(stPayableDetailDataEntity);

                //更新商品-应收统计状态 为 已统计
                UnifiedOrderGoods unifiedOrderGoods = new UnifiedOrderGoods();
                unifiedOrderGoods.setId(stPayableDetailDataEntity.getGoodsId());
                //unifiedOrderGoods.setPayableStatisticsState(ReceivablePayableStatisticsStatusEnum.已统计.getStatus());
                unifiedOrderGoods.setUpdateTime(new Date());
                unifiedOrderGoodsMapper.updateByPrimaryKeySelective(unifiedOrderGoods);
            } else {
                log.info("\n===>保存应付明细数据-savePayableDetailData creditId-客户结算中心id:{} 存在入明细数据 请检查程序\n", stPayableDetailDataEntity.getCreditId());
            }

        }


    }


    /**
     * 应付明细数据定时任务到每日数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void savePrayableDetailDataToDayData(ReceivableDetailDataQueryParam queryParam, LoginSysUser loginSysUser) {

        log.info("\n===>应付明细数据定时任务到每日数据-savePrayableDetailDataToDayData 参数:{}", JSON.toJSONString(queryParam));


        //查询应付明细数据_已汇总

        queryParam.setAccountState(Byte.valueOf("0"));//入账状态 0未入账 1已入账 3撤销入账 4已撤销
        List<PayableDayDataVo> payableDayDataVoList = payableStatisticsMapper.queryPrayableDayData(queryParam);

        log.info("\n===>应付明细数据定时任务到每日数据-查询应付每日数据 条数:{}", payableDayDataVoList.size());

        int num = 1;
        for (PayableDayDataVo payableDayDataVo : payableDayDataVoList) {

            log.info("\n===>应付明细数据定时任务到每日数据-当前处理第:{} 条", num);
            ++num;

            //应收每日数据
            StPayableDayDataEntity stReceivableDayDataEntity = AnBeanUtils.copy(payableDayDataVo, StPayableDayDataEntity.class);
            //入账类型 1系统入账 2手工记账
            stReceivableDayDataEntity.setAccountType(Byte.valueOf("1"));
            stReceivableDayDataEntity.setCreateUserId(loginSysUser.getSysUserId());
            stReceivableDayDataEntity.setCreatedAt(new Date());
            stReceivableDayDataEntity.setCreateUserName(loginSysUser.getFullName());
            stReceivableDayDataEntity.setAccountAt(new Date());
            stReceivableDayDataEntity.setAccountType(Byte.valueOf("1"));//入账类型 1-正常入账 2-撤销入账
            stReceivableDayDataEntity.setAccountingOrderSn(payableDayDataVo.getAccountingOrderSn());
            stReceivableDayDataEntity.setAccountWay(Byte.valueOf("0"));//入账方式 0系统入账 1手工记账


            StPayableDayDataEntityExample stReceivableDayDataEntityExample = new StPayableDayDataEntityExample();
            stReceivableDayDataEntityExample.createCriteria().andDetailIdEqualTo(payableDayDataVo.getDetailId());
            Integer stDayDataNum =  stPayableDayDataEntityMapper.selectByExample(stReceivableDayDataEntityExample).size();
            if(stDayDataNum == 0){ //明细数据Id 在每日数据里为唯一

                //重复判断
                stPayableDayDataEntityMapper.insert(stReceivableDayDataEntity);

                //明细数据 反写状态 入账日期-入账状态
                //credit_id + finish_time;
                String detailId = payableDayDataVo.getDetailId();
                String [] detailIds =  detailId.split(",");
                for(String id : detailIds){

                    StPayableDetailDataEntity updateDataEntity = new StPayableDetailDataEntity();
                    updateDataEntity.setId(Long.parseLong(id));
                    updateDataEntity.setAccountAt(payableDayDataVo.getAccountAt());
                    updateDataEntity.setAccountState(Byte.valueOf("1"));//入账状态 0未入账 1已入账 3撤销入账 4已撤销
                    updateDataEntity.setPayableDayId(stReceivableDayDataEntity.getId());//入账id
                    updateDataEntity.setAccountingOrderSn(stReceivableDayDataEntity.getAccountingOrderSn());//流水所属对账单编号

                    updateDataEntity.setUpdateUserId(loginSysUser.getSysUserId());
                    updateDataEntity.setUpdateTime(new Date());
                    updateDataEntity.setUpdateUserName(loginSysUser.getFullName());
                    stPayableDetailDataEntityMapper.updateByPrimaryKeySelective(updateDataEntity);
                }
            }else{
                log.info("\n===>应付明细数据定时任务到每日数据-savePrayableDetailDataToDayData detailId-明细数据Id:{} 存在入每日数据 请检查程序\n",payableDayDataVo.getDetailId());
            }
        }


        //保存应付明细数据到 应收每日数据

    }

    @Override
    public R<List<PayableStatisticsPageVo>> getPayableStatisticsPageVoList(ReceivableStatisticsPageQueryParam queryParam) {

        PageHelper.startPage(queryParam.getPageNumber(), queryParam.getPageSize());
        //获得应收报表分页后的settlementId
        List<Integer> listSettlementId =  payableStatisticsMapper.getPayableStatisticsPageLimitSettlementId(queryParam);
        PageHelper.clearPage();


        queryParam.setListSettlementId(listSettlementId);
        //应收报表List
        List<PayableStatisticsPageVo> resultList = payableStatisticsMapper.getPayableStatisticsPageVoList(queryParam);
        for(PayableStatisticsPageVo receivableStatisticsPageVo : resultList){
            if(receivableStatisticsPageVo.getSettlementName().equals("小计")){
                receivableStatisticsPageVo.setMerchTaxRate(null);
            }
        }


        //查询应收报表总页数
        Integer totalPageNum =  payableStatisticsMapper.getPayableStatisticsTotalPageNum(queryParam);

        //合计行
        List<Map<String, Object>> totalDataList = payableStatisticsMapper.getPayableStatisticsTotalData(queryParam);
        Map<String, Object> headData = new HashMap<>();
        if(null != totalDataList && totalDataList.size() >=1 ){
            headData = totalDataList.get(0);
        }

        return new R<List<PayableStatisticsPageVo>>(queryParam.getPageNumber(), queryParam.getPageSize(), totalPageNum, resultList,headData);
    }

    @Override
    public SysNotify getPayableStatisExcel(ReceivableStatisticsPageQueryParam queryParam) {

        //汇总数据 导出excel 使用
        List<PayableStatisticsPageVo>  receivableStatisticsPageVoList = this.getPayableStatisticsPageVoByExcel(queryParam);

        //每日数数据 导出excel 使用
        List<PayableStatisticsDayDataByExcelVo> receivableStatisticsDayDataByExcelVoList = payableStatisticsMapper.getPayableStatisticsDayDataByExcel(queryParam);
        log.info("\n===>getPayableStatisExcel-每日数数据:有{} 条", receivableStatisticsDayDataByExcelVoList.size());
        log.info("\n===>getPayableStatisExcel-每日数数据:{}", JSON.toJSONString(receivableStatisticsDayDataByExcelVoList));



        //明细数据 导出excel 使用
        List<PayableStatisticsDetailDataByExcelVo> receivableStatisticsDetailDataByExcelVoList = payableStatisticsMapper.getPayableStatisticsDetailDataByExcel(queryParam);
        log.info("\n===>getPayableStatisExcel-明细数据:有{} 条", receivableStatisticsDetailDataByExcelVoList.size());


        ReceivableStatisticsExportDateExcelVo receivableStatisticsExportDateExcelVo = new ReceivableStatisticsExportDateExcelVo();
        try {
            if(StringUtils.isNotEmpty(queryParam.getStartTime())){
                Date startTime = AnDateUtils.parseDate(queryParam.getStartTime());
                receivableStatisticsExportDateExcelVo.setStartTime(AnDateUtils.format(startTime, "yyyy年MM月dd日"));
            }
            if(StringUtils.isNotEmpty(queryParam.getEndTime())){
                Date endTime = AnDateUtils.parseDate(queryParam.getEndTime());
                receivableStatisticsExportDateExcelVo.setEndTime(AnDateUtils.format(endTime, "yyyy年MM月dd日"));
            }
        }catch (Exception e){
            log.info("\n===>getReceivableStatisExcel-格式化导出日期异常 {},{}", queryParam.getStartTime(),queryParam.getEndTime());
        }



        Map<String, Object> exportDateMap = AnBeanUtils.beanToMap(receivableStatisticsExportDateExcelVo, "exportDate");
        log.info("\n ===>导出日期exportDateMap :{}",JSON.toJSONString(exportDateMap));


        String excelExportPathRoot             = excelExportConstant.getPathRoot();
        String excelExportRelativePathTemplate = excelExportConstant.getPathTemplate();
        String excelExportRelativePathStorage  = excelExportConstant.getPathStorage();

        //excelExportPathRoot = "C:\\Users\\linjinyu\\tmp";
        //excelExportRelativePathTemplate = "\\templat";
        //excelExportRelativePathStorage = "\\_storage";

        String relativePath = File.separator + "excel" + File.separator + "statistic" + File.separator + "receivable" + File.separator;

        String templateRelativePath = excelExportPathRoot + excelExportRelativePathTemplate + relativePath;
        String templateFullPath;

        String targetFullPath          = excelExportPathRoot + excelExportRelativePathStorage;
        String targetFileName          = "汇总(应付账款)" + "_" + "sheet_应付账款" + ExcelResponse.addTail() + ".xlsx";
        String targetWriteFileFullPath = targetFullPath + relativePath + targetFileName;

        FileUtil.touch(targetWriteFileFullPath);

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

        ExcelWriterBuilder excelWriterBuilder = EasyExcel.write(targetWriteFileFullPath);
        ExcelWriter excelWriter        = null;

        //WriteSheet writeSheet0 = EasyExcel.writerSheet(0, "汇总").registerWriteHandler(new MyMergeStrategy()).build();
        WriteSheet writeSheet0 = EasyExcel.writerSheet(0, "应付账款").build();
        WriteSheet writeSheet1 = EasyExcel.writerSheet(1, "应付汇总数据").build();
        WriteSheet writeSheet2 = EasyExcel.writerSheet(2, "应付流水数据").build();
        FillConfig fillConfig  = FillConfig.builder().forceNewRow(Boolean.FALSE).build();


        // 文件
        templateFullPath = templateRelativePath + TEMPLATE_EXPORT_EXCEL_PAYABLE_STATISTIC;

        excelWriter = excelWriterBuilder.withTemplate(templateFullPath).build();

        excelWriter.fill(new FillWrapper("detail", receivableStatisticsPageVoList), fillConfig, writeSheet0).fill(exportDateMap,writeSheet0);
        excelWriter.fill(new FillWrapper("day", receivableStatisticsDayDataByExcelVoList), fillConfig, writeSheet1);//每日数据
        excelWriter.fill(new FillWrapper("detail", receivableStatisticsDetailDataByExcelVoList), fillConfig, writeSheet2);


        // 别忘记关闭流
        excelWriter.finish();


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

        return NotifyUtils.createSysNotify(targetFileName, relativePath + targetFileName, SysQuartzScheduleTaskStatementOfAccountRunStateEnum.成功);
    }

    /**
     * 导出excel汇总数据
     * @param queryParam
     * @return
     */
    public List<PayableStatisticsPageVo> getPayableStatisticsPageVoByExcel(ReceivableStatisticsPageQueryParam queryParam) {

        List<PayableStatisticsPageVo> receivableStatisticsPageVoList = new ArrayList<>();
        queryParam.setExportExcel(true);  //导出参数 不做分页处理
        R<List<PayableStatisticsPageVo>>  exportReceivableStatisticsData = this.getPayableStatisticsPageVoList(queryParam);
        if(null != exportReceivableStatisticsData && StringUtils.isNotEmpty(exportReceivableStatisticsData.getCode()) && exportReceivableStatisticsData.getCode().equals("200")) {

            receivableStatisticsPageVoList = exportReceivableStatisticsData.getData();
            Integer seq = 0;
            BigDecimal divideParam = new BigDecimal("100");
            List<String> listSettlementId = new ArrayList<>();

            for (PayableStatisticsPageVo receivableStatisticsPageVo : receivableStatisticsPageVoList) {

                if(null != receivableStatisticsPageVo.getMerchTaxRate()){
                    receivableStatisticsPageVo.setFormatMerchTaxRate(receivableStatisticsPageVo.getMerchTaxRate().divide(divideParam,2, BigDecimal.ROUND_HALF_DOWN));
                }

                String  settlementId = receivableStatisticsPageVo.getSettlementId().toString();
                if(!listSettlementId.contains(settlementId)){
                    listSettlementId.add(settlementId);
                    ++seq;
                }
                receivableStatisticsPageVo.setSeq(String.valueOf(seq));

            }


            if(null != exportReceivableStatisticsData && null != exportReceivableStatisticsData.getHeadData()){

                Map<String, Object> headMap = exportReceivableStatisticsData.getHeadData();

                PayableStatisticsPageVo headMapVo = new PayableStatisticsPageVo();
                headMapVo.setSeq("合计");

                if(null != headMap){

                    if (headMap.containsKey("costNotax")) {
                        headMapVo.setCostNotax((BigDecimal) headMap.get("costNotax"));
                    }
                    if (headMap.containsKey("taxAmount")) {
                        headMapVo.setTaxAmount((BigDecimal) headMap.get("taxAmount"));
                    }
                    if (headMap.containsKey("payableAmount")) {
                        headMapVo.setPayableAmount((BigDecimal) headMap.get("payableAmount"));
                    }
                }

                receivableStatisticsPageVoList.add(headMapVo);
            }

        }
        return  receivableStatisticsPageVoList;

    }

    /**
     * 实付_积分结算_对账单_回款状态变更为“已回款”时
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void payableReturnedMoney(ReceivableDetailDataQueryParam queryParam,LoginSysUser loginSysUser) {


        //（1）将该供应商结算对账单中所有的商品订单数据在“应付流水表”中匹配对应的应付流水：
        //A、该应付流水所属该商品订单&该应付流水的冲销状态为“未冲销”；
        //B、一条供应商结算对账单的商品订单数据可能匹配多个应付流水或当前无对应应付流水；

        log.info("\n===>应付已回款-payableReturnedMoney 参数:{}", JSON.toJSONString(queryParam));

        //应付回款对冲数据
        List<PayableDetailDataVo> payableReturnedMoneyDetailDataList = payableStatisticsMapper.queryPayableReturnedMoneyDetailData(queryParam);

        //①满足该商品订单所有的应付流水，即进行关联处理：
        //·冲销商品订单id：填充该商品订单结算中心系统id；
        //·付款冲销对账单编号：填充为该付款状态变更为“已付款”的对账单编号内容；
        //·冲销人id&冲销人&冲销时间：均取当前对账单变更为已付款状态的操作人及操作时间；
        //·更新人&更新人id&更新时间：均取当前对账单变更为已付款状态的操作人及操作时间；

        //②若该商品订单未找到符合条件的应付流水，即跳过该商品订单，执行下一条商品订单，直到最后一条执行完成；


        //根据当前对帐单编码 查询用于对冲的流水数据

        StPayableDetailDataEntityExample example = new StPayableDetailDataEntityExample();
        example.createCriteria().andChargeStatusEqualTo(Byte.valueOf("1"));
        List<StPayableDetailDataEntity> listStReceivableDetailDataEntitys = stPayableDetailDataEntityMapper.selectByExample(example);


        for(PayableDetailDataVo payableDetailDataVo : payableReturnedMoneyDetailDataList){ //循环对冲

            Long creditId = payableDetailDataVo.getCreditId(); //客户结算中心id

            //在未冲销 数据中找数据
            List<StPayableDetailDataEntity> matchingList = listStReceivableDetailDataEntitys.stream().filter(t->t.getCreditId().equals(creditId)).collect(Collectors.toList());

            if(null != matchingList && matchingList.size() >= 1){


                StPayableDetailDataEntity  matchingStPayableDetailDataEntity =  matchingList.get(0); //匹配到流水

                log.info("\n===>应付已回款-当前流水 creditId :{} 匹配到流水:{} ---- ", creditId, JSON.toJSONString(matchingStPayableDetailDataEntity));


                //更新商品-应收统计状态 为 已统计
                StPayableDetailDataEntity updateStReceivableDetailDataEntity = new StPayableDetailDataEntity();
                updateStReceivableDetailDataEntity.setId(matchingStPayableDetailDataEntity.getId());
                updateStReceivableDetailDataEntity.setChargeStatus(Byte.valueOf("2"));//冲销状态 1-未冲销 2-已冲销 3-已撤销
                updateStReceivableDetailDataEntity.setChargeUserId(loginSysUser.getSysUserId());
                updateStReceivableDetailDataEntity.setChargeUserName(loginSysUser.getFullName());
                updateStReceivableDetailDataEntity.setChargeCreatedAt(new Date());
                updateStReceivableDetailDataEntity.setChargeGoodsId(payableDetailDataVo.getGoodsId());//冲销商品订单id


                updateStReceivableDetailDataEntity.setCollectionOrderSn(queryParam.getAccountingOrderSn());//付款冲销对账单编号
                updateStReceivableDetailDataEntity.setUpdateUserId(loginSysUser.getSysUserId());
                updateStReceivableDetailDataEntity.setUpdateTime(new Date());
                updateStReceivableDetailDataEntity.setUpdateUserName(loginSysUser.getFullName());

                stPayableDetailDataEntityMapper.updateByPrimaryKeySelective(updateStReceivableDetailDataEntity);

            }else{ //没有匹配到流水 记录到数据库



                StPayableChargeAgainstRecordEntity  record = AnBeanUtils.copy(payableDetailDataVo, StPayableChargeAgainstRecordEntity.class);
                record.setAccountingOrderSn(queryParam.getAccountingOrderSn());
                record.setChargeJson(JSON.toJSONString(payableDetailDataVo));

                log.info("\n===>应付已回款-当前流水没有对冲到 :{}", JSON.toJSONString(record));

                stPayableChargeAgainstRecordEntityMapper.insert(record);
            }

        }



        log.info("\n 应付已回款时 应付流水---> 应付汇总 ===>");

        //②汇总对象：将“应付流水表”中所属冲销该对账单&入账状态“已入账”&冲销状态为“未冲销”的应付流水进行汇总，
        // 不含非该冲销对账单或入账状态非“已入账”或冲销状态非“未冲销”的应付流水；

        //入账状态 0未入账 1已入账 3撤销入账 4已撤销
        //冲销状态 1-未冲销 2-已冲销 3-已撤销
        example.createCriteria().andChargeStatusEqualTo(Byte.valueOf("1")).andAccountStateEqualTo(Byte.valueOf("1"));
        List<PayableDayDataVo> receivableDayDataVoList = payableStatisticsMapper.queryPrayableDayData(queryParam);

        log.info("\n===>应付已回款时 应付流水---> 应付汇总-查询应收每日数据 条数:{}", receivableDayDataVoList.size());

        int num = 1;
        for(PayableDayDataVo receivableDayDataVo : receivableDayDataVoList){

            log.info("\n===>应付已回款时 应付流水---> 应付汇总-当前处理第:{} 条", num);
            ++ num;



            //·“收入(不含税)、税额、应收账款”金额：负值[该字段的汇总数据总和]；


            //应收每日数据
            StPayableDayDataEntity  stReceivableDayDataEntity = AnBeanUtils.copy(receivableDayDataVo, StPayableDayDataEntity.class);
            //入账类型 1系统入账 2手工记账
            stReceivableDayDataEntity.setAccountType(Byte.valueOf("1"));
            stReceivableDayDataEntity.setCreateUserId(loginSysUser.getSysUserId());
            stReceivableDayDataEntity.setCreatedAt(new Date());
            stReceivableDayDataEntity.setCreateUserName(loginSysUser.getFullName());
            stReceivableDayDataEntity.setAccountType(Byte.valueOf("3"));//入账类型 1-正常入账 2-撤销入账 3-冲销入账
            //stReceivableDayDataEntity.setAccountingOrderSn(receivableDayDataVo.getAccountingOrderSn());
            //stReceivableDayDataEntity.setCostNoTax(receivableDayDataVo.getIncomeNoTax().negate());
            //stReceivableDayDataEntity.setTaxAmount(receivableDayDataVo.getTaxAmount().negate());
            //stReceivableDayDataEntity.setPayableAmount(receivableDayDataVo.getReceivableAmount().negate());
            //stReceivableDayDataEntity.setServiceNoName(receivableDayDataVo.getServiceNoName());
            stReceivableDayDataEntity.setAccountWay(Byte.valueOf("0"));//入账方式 0系统入账 1手工记账


            StPayableDayDataEntityExample stReceivableDayDataEntityExample = new StPayableDayDataEntityExample();
            stReceivableDayDataEntityExample.createCriteria().andDetailIdEqualTo(receivableDayDataVo.getDetailId()).andAccountTypeEqualTo(Byte.valueOf("3"));//入账类型 1-正常入账 2-撤销入账 3-冲销账款;;
            Integer stDayDataNum =  stPayableDayDataEntityMapper.selectByExample(stReceivableDayDataEntityExample).size();
            if(stDayDataNum == 0){ //明细数据Id 在每日数据里为唯一



                //重复判断
                stPayableDayDataEntityMapper.insert(stReceivableDayDataEntity);

                //明细数据 反写状态 入账日期-入账状态
                //credit_id + finish_time;
                String detailId = receivableDayDataVo.getDetailId();
                String [] detailIds =  detailId.split(",");
                for(String id : detailIds){

                    //        该汇总数据所关联的应收流水_入账状态：变更为“已撤销”；
                    //        该汇总数据所关联的应收流水_入账id：保持原入账id不变；
                    //        该汇总数据所关联的应收流水_冲销/撤销入账id：取该汇总数据的入账id；
                    //        该汇总数据所关联的应收流水_更新时间：填充该汇总数据的创建时间；

                    StPayableDetailDataEntity updateDataEntity = new StPayableDetailDataEntity();
                    updateDataEntity.setId(Long.parseLong(id));
                    updateDataEntity.setAccountAt(receivableDayDataVo.getAccountAt());
                    updateDataEntity.setAccountState(Byte.valueOf("2"));//入账状态 0未入账 1已入账 3撤销入账 4已撤销
                    updateDataEntity.setPayableDayId(stReceivableDayDataEntity.getId());//入账id
                    updateDataEntity.setAccountingOrderSn(stReceivableDayDataEntity.getAccountingOrderSn());//流水所属对账单编号

                    updateDataEntity.setUpdateUserId(loginSysUser.getSysUserId());
                    updateDataEntity.setUpdateTime(new Date());
                    updateDataEntity.setUpdateUserName(loginSysUser.getFullName());
                    stPayableDetailDataEntityMapper.updateByPrimaryKeySelective(updateDataEntity);
                }
            }else{
                log.info("\n===>应收明细数据定时任务到每日数据-saveReceivableDetailDataToDayData detailId-明细数据Id:{} 存在入每日数据 请检查程序\n",receivableDayDataVo.getDetailId());
            }
        }



        log.info("\n===>应付已回款-payableReturnedMoney  END----------");



    }

    /**
     * 3.2.1.2 积分结算_对账单状态变更为“已取消”时
     */
    //@Override
    @Transactional(rollbackFor = Exception.class)
    public void payableCancelAccounting(ReceivableDetailDataQueryParam queryParam,LoginSysUser loginSysUser) {

        log.info("\n===>应付_积分结算_对账单状态变更为“已取消”时-receivableCancelAccounting 参数:{}", JSON.toJSONString(queryParam));

        //第一步：该对账单“应收流水”处理
        //（1）将“应收流水表”所属该对账单编号的应收流水所对应的所有订单流水（订单流水id）：其应收统计状态变更为“未统计”；
        //根据账单编号 更新 所有订单流水 其应收统计状态变更为“未统计” where = "已统计" 部分
        //UniorderAccountingScoreCustomerStrategy.opCancelAccounting



        //（2）将“应收流水表”所属该对账单编号下所有应收流水：
        //·对账单状态：变更为“已取消”；
        //·冲销状态：变更为“已撤销”；
        //·冲销人id&冲销人&冲销时间：均取该对账单变更为已取消状态的操作人及时间；

        //（3）检查“应收流水表”所属该对账单编号下所有应收流水的入账状态：
        // ①若该应收流水的入账状态为“未入账”：
        // ·该应收流水的入账状态：变更为“已撤销”；
        // ·该应收流水的更新人&更新人id&更新时间：均取当前已取消对账单的操作人及操作时间；
        // ②若该应收流水的入账状态为“已入账”&撤销入账id为空：将该应收流水的入账状态变更为“撤销入账”


        StPayableDetailDataEntityExample example = new StPayableDetailDataEntityExample();
        example.createCriteria().andAccountingOrderSnEqualTo(queryParam.getAccountingOrderSn());
        List<StPayableDetailDataEntity> listStReceivableDetailDataEntitys = stPayableDetailDataEntityMapper.selectByExample(example);

        //查询应收明细数据
        //List<ReceivableDetailDataVo> receivableDetailDataVoList = this.queryReceivableDetailData(queryParam);
        for (StPayableDetailDataEntity stReceivableDetailDataEntity:listStReceivableDetailDataEntitys){


            //更新商品-应收统计状态 为 已统计
            StPayableDetailDataEntity updateStReceivableDetailDataEntity = new StPayableDetailDataEntity();
            updateStReceivableDetailDataEntity.setId(stReceivableDetailDataEntity.getId());
            updateStReceivableDetailDataEntity.setAccountingState(Byte.valueOf("-1"));//对账状态 1-已确认;-1-已取消
            updateStReceivableDetailDataEntity.setChargeStatus(Byte.valueOf("3"));//冲销状态 1-未冲销 2-已冲销 3-已撤销
            updateStReceivableDetailDataEntity.setChargeUserId(loginSysUser.getSysUserId());
            updateStReceivableDetailDataEntity.setChargeUserName(loginSysUser.getFullName());

            //入账状态 0未入账 1已入账 3撤销入账 4已撤销
            if(stReceivableDetailDataEntity.getAccountState().equals(Byte.valueOf("0"))){//未入账
                updateStReceivableDetailDataEntity.setAccountState(Byte.valueOf("4"));//已撤销
            }else  if(stReceivableDetailDataEntity.getAccountState().equals(Byte.valueOf("1")) && null == stReceivableDetailDataEntity.getChargePayableDayId()){// ②若该应收流水的入账状态为“已入账”&撤销入账id为空：
                updateStReceivableDetailDataEntity.setAccountState(Byte.valueOf("3"));//撤销入账
            }

            updateStReceivableDetailDataEntity.setUpdateUserId(loginSysUser.getSysUserId());
            updateStReceivableDetailDataEntity.setUpdateTime(new Date());
            updateStReceivableDetailDataEntity.setUpdateUserName(loginSysUser.getFullName());

            stPayableDetailDataEntityMapper.updateByPrimaryKeySelective(updateStReceivableDetailDataEntity);

        }




//        （4）入账状态处理完成后，对该对账单编号下所有入账状态为“撤销入账”的应收流水处理：
//        ①若无撤销入账的应收流水：即无需处理；
//        ②若有，对该对账单编号下所有入账状态“撤销入账”的应收流水数据：按同流水所属对账单编号&同客户（客户结算中心id）&同订单类型&同积分类型（积分支付/微信支付）&同税率的应收流水数据进行汇总统计出“应收汇总”数据；
//        ·入账类型：默认为“撤销入账”；
//        ·入账方式：默认为“系统入账”；
//        ·入账日期：取该组汇总数据汇总时第一条应收流水的冲销时间，年-月-日，即该对账单取消的时间；
//        ·“收入(不含税)、税额、应收账款”金额：负值[该字段的汇总数据总和]；
//        ·其他应收汇总字段：请参照《3.1.4 应收汇总》需求；
//        ·每条“撤销入账”应收汇总数据创建成功时：

//        该汇总数据所关联的应收流水_入账状态：变更为“已撤销”；
//        该汇总数据所关联的应收流水_入账id：保持原入账id不变；
//        该汇总数据所关联的应收流水_冲销/撤销入账id：取该汇总数据的入账id；
//        该汇总数据所关联的应收流水_更新时间：填充该汇总数据的创建时间；


        //入账状态0未入账 1已入账 3撤销入账 4已撤销
        //查询应收明细数据_已汇总
        log.info("\n===>应收明细数据定时任务到每日数据-saveReceivableDetailDataToDayData 参数:{}", JSON.toJSONString(queryParam));

        queryParam.setAccountingOrderSn(queryParam.getAccountingOrderSn());
        queryParam.setAccountState(Byte.valueOf("3"));
        List<PayableDayDataVo> receivableDayDataVoList = payableStatisticsMapper.queryPrayableDayData(queryParam);

        log.info("\n===>应收明细数据定时任务到每日数据-查询应收每日数据 条数:{}", receivableDayDataVoList.size());

        int num = 1;
        for(PayableDayDataVo receivableDayDataVo : receivableDayDataVoList){

            log.info("\n===>应收明细数据定时任务到每日数据-当前处理第:{} 条", num);
            ++ num;



            //·“收入(不含税)、税额、应收账款”金额：负值[该字段的汇总数据总和]；


            //应收每日数据
            StPayableDayDataEntity  stReceivableDayDataEntity = AnBeanUtils.copy(receivableDayDataVo, StPayableDayDataEntity.class);
            //入账类型 1系统入账 2手工记账
            stReceivableDayDataEntity.setCreateUserId(loginSysUser.getSysUserId());
            stReceivableDayDataEntity.setCreatedAt(new Date());
            stReceivableDayDataEntity.setCreateUserName(loginSysUser.getFullName());
            stReceivableDayDataEntity.setAccountType(Byte.valueOf("2"));//入账类型 1-正常入账 2-撤销入账 3-冲销入账
            stReceivableDayDataEntity.setAccountingOrderSn(receivableDayDataVo.getAccountingOrderSn());
            stReceivableDayDataEntity.setCostNoTax(receivableDayDataVo.getCostNoTax().negate());
            stReceivableDayDataEntity.setTaxAmount(receivableDayDataVo.getTaxAmount().negate());
            stReceivableDayDataEntity.setPayableAmount(receivableDayDataVo.getPayableAmount().negate());
            stReceivableDayDataEntity.setServiceNoName(receivableDayDataVo.getServiceNoName());
            stReceivableDayDataEntity.setAccountWay(Byte.valueOf("0"));//入账方式 0系统入账 1手工记账


            StPayableDayDataEntityExample stReceivableDayDataEntityExample = new StPayableDayDataEntityExample();
            stReceivableDayDataEntityExample.createCriteria().andDetailIdEqualTo(receivableDayDataVo.getDetailId()).andDetailIdEqualTo(receivableDayDataVo.getDetailId()).andAccountTypeEqualTo(Byte.valueOf("2"));//入账类型 1-正常入账 2-撤销入账 3-冲销账款;;
            Integer stDayDataNum =  stPayableDayDataEntityMapper.selectByExample(stReceivableDayDataEntityExample).size();
            if(stDayDataNum == 0){ //明细数据Id 在每日数据里为唯一



                //重复判断
                stPayableDayDataEntityMapper.insert(stReceivableDayDataEntity);

                //明细数据 反写状态 入账日期-入账状态
                //credit_id + finish_time;
                String detailId = receivableDayDataVo.getDetailId();
                String [] detailIds =  detailId.split(",");
                for(String id : detailIds){

                    //        该汇总数据所关联的应收流水_入账状态：变更为“已撤销”；
                    //        该汇总数据所关联的应收流水_入账id：保持原入账id不变；
                    //        该汇总数据所关联的应收流水_冲销/撤销入账id：取该汇总数据的入账id；
                    //        该汇总数据所关联的应收流水_更新时间：填充该汇总数据的创建时间；

                    StPayableDetailDataEntity updateDataEntity = new StPayableDetailDataEntity();
                    updateDataEntity.setId(Long.parseLong(id));
                    updateDataEntity.setAccountAt(receivableDayDataVo.getAccountAt());
                    updateDataEntity.setAccountState(Byte.valueOf("4"));//入账状态 0未入账 1已入账 3撤销入账 4已撤销
                    updateDataEntity.setPayableDayId(stReceivableDayDataEntity.getId());//入账id
                    updateDataEntity.setAccountingOrderSn(stReceivableDayDataEntity.getAccountingOrderSn());//流水所属对账单编号

                    updateDataEntity.setUpdateUserId(loginSysUser.getSysUserId());
                    updateDataEntity.setUpdateTime(new Date());
                    updateDataEntity.setUpdateUserName(loginSysUser.getFullName());
                    stPayableDetailDataEntityMapper.updateByPrimaryKeySelective(updateDataEntity);
                }
            }else{
                log.info("\n===>应收明细数据定时任务到每日数据-saveReceivableDetailDataToDayData detailId-明细数据Id:{} 存在入每日数据 请检查程序\n",receivableDayDataVo.getDetailId());
            }
        }


        log.info("\n===>应付_积分结算_对账单状态变更为“已取消”时-END-----");

    }

}
