package com.jwipc.finance.logic.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jwipc.exception.DaoException;
import com.jwipc.finance.convert.ReceiptVoucherConvert;
import com.jwipc.finance.dto.ReceiveVoucherDTO;
import com.jwipc.finance.dto.StatementItemDTO;
import com.jwipc.finance.dto.StatisticVoucherDTO;
import com.jwipc.finance.entity.Deduction;
import com.jwipc.finance.entity.ReceiveVoucher;
import com.jwipc.finance.logic.ReceiptVoucherLogic;
import com.jwipc.finance.model.po.ReceiveVoucherPO;
import com.jwipc.finance.model.po.StatementItemPO;
import com.jwipc.finance.model.po.WriteOffVoucherCheckPO;
import com.jwipc.finance.model.query.ReceiveVoucherQuery;
import com.jwipc.finance.service.IDeductionService;
import com.jwipc.finance.service.IReceiveVoucherService;
import com.jwipc.page.PageUtil;
import com.jwipc.page.PageView;
import com.jwipc.prop.PriceHandle;
import com.jwipc.query.BasePageQuery;
import com.jwipc.security.LoginUtil;
import com.jwipc.sys.client.DictClient;
import com.jwipc.sys.entity.StatementPaymentSetting;
import com.jwipc.sys.service.IPurchaseGroupService;
import com.jwipc.sys.service.IStatementPaymentSettingService;
import com.jwipc.sys.service.IUserPurchaseGroupService;
import com.jwipc.util.EasyExcelImportUtils;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

import static com.baomidou.dynamic.datasource.support.DdConstants.SLAVE;

/**
 * @author shenyang.ou
 * @date 2024/3/4 10:32
 * @desc
 */
@Service
@RequiredArgsConstructor
public class ReceiptVoucherLogicImpl implements ReceiptVoucherLogic {
    private final ReceiptVoucherConvert receiptVoucherConvert;
    private final IReceiveVoucherService receiveVoucherService;
    private final IDeductionService deductionService;
    private final DictClient dictClient;
    private final PriceHandle priceHandle;
    private final IStatementPaymentSettingService statementPaymentSettingService;
   // private final IUserPurchaseGroupService userPurchaseGroupService;
   // private final IPurchaseGroupService purchaseGroupService;
    @Override
    public PageView findByPage(ReceiveVoucherQuery query) {
        final Page<ReceiveVoucher> dbPage = PageUtil.toPage(query);

        List<ReceiveVoucherPO> receiveVoucherPOS = receiveVoucherService.findPageByQuery(dbPage, query);
        List<ReceiveVoucherDTO> receiveVoucherDTOS = receiptVoucherConvert.po2PageListDTO(receiveVoucherPOS);
        receiveVoucherDTOS.forEach(receiveVoucherDTO -> {
            receiveVoucherDTO.setOriginalTaxAmount(receiveVoucherDTO.getOriginalTaxPrice().multiply(receiveVoucherDTO.getMvNum()));
        });
        return PageUtil.getPV(receiveVoucherDTOS, dbPage.getTotal());
    }

    @Override
    public List<ReceiveVoucherDTO> listAll(ReceiveVoucherQuery query) {
        List<ReceiveVoucherPO> receiveVoucherPOS = receiveVoucherService.findPageByQuery(null, query);
        return receiptVoucherConvert.po2PageListDTO(receiveVoucherPOS);
    }

    /**
     * 修改扣款比例（其他折扣）
     * @param idList
     * @param deductionRatio
     */
    @Override
    @DS(SLAVE)
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void updateRatio(List<String> idList, BigDecimal deductionRatio) {
        List<ReceiveVoucher> receiveVoucherList = receiveVoucherService.listByIds(idList);
        if (CollectionUtils.isNotEmpty(receiveVoucherList)){
            for (ReceiveVoucher receiveVoucher : receiveVoucherList){
                receiveVoucher.setDeductionRatio(deductionRatio);
                if(deductionRatio.compareTo(BigDecimal.ZERO)==0){
                    //不含税金额 不含税单价*数量
                    receiveVoucher.setNotTaxAmount(receiveVoucher.getNotTaxPrice().multiply(receiveVoucher.getMvNum()));
                    //含税金额 原含税单价*数量
                    receiveVoucher.setTaxAmount(receiveVoucher.getOriginalTaxPrice().multiply(receiveVoucher.getMvNum()));
                }else {
                    //不含税金额 不含税单价*数量-其他折扣
                    receiveVoucher.setNotTaxAmount(receiveVoucher.getNotTaxPrice().multiply(receiveVoucher.getMvNum()).subtract(deductionRatio));
                    //不含税单价 不含税金额/数量
//                receiveVoucher.setNotTaxPrice(receiveVoucher.getNotTaxAmount().divide(receiveVoucher.getMvNum(), priceHandle.getPrecision(), priceHandle.getCutType()==0?RoundingMode.HALF_UP:RoundingMode.HALF_DOWN));

                    BigDecimal taxAdd = receiveVoucher.getTaxValue().add(new BigDecimal(1));
                    //含税单价 未税单价*（1+税率）
//                receiveVoucher.setTaxPrice(receiveVoucher.getNotTaxPrice().multiply(taxAdd));
                    //含税金额 含税单价*数量
//                receiveVoucher.setTaxAmount(receiveVoucher.getMvNum().multiply(receiveVoucher.getTaxPrice()));
                    //含税金额 未税金额*（1+税率）
                    receiveVoucher.setTaxAmount(receiveVoucher.getNotTaxAmount().multiply(taxAdd));
                    //税额 含税金额-未税金额
                    receiveVoucher.setDiffTaxAmount(receiveVoucher.getTaxAmount().subtract(receiveVoucher.getNotTaxAmount()));
                }
                receiveVoucherService.update(receiveVoucher,Wrappers.lambdaQuery(ReceiveVoucher.class)
                        .eq(ReceiveVoucher::getId,receiveVoucher.getId())
                        .eq(ReceiveVoucher::getFactoryCode,receiveVoucher.getFactoryCode())
                );
//                //含税单价 取原含税单价-原含税单价*扣款比例
//                BigDecimal deduction = receiveVoucher.getOriginalTaxPrice().multiply(deductionRatio);
//                receiveVoucher.setTaxPrice(receiveVoucher.getOriginalTaxPrice().subtract(deduction));
//                //含税金额 含税单价*数量
//                receiveVoucher.setTaxAmount(receiveVoucher.getMvNum().multiply(receiveVoucher.getTaxPrice()));
//                BigDecimal tax = new BigDecimal(String.valueOf(receiveVoucher.getTaxValue())).divide(new BigDecimal(100), 2,
//                        BigDecimal.ROUND_HALF_UP);
//                //不含税金额 含税金额/(1+税率)
//                BigDecimal taxAdd = tax.add(new BigDecimal(1));
//                receiveVoucher.setNotTaxAmount(receiveVoucher.getTaxAmount().divide(taxAdd, 4, BigDecimal.ROUND_DOWN));
//                //税额 含税金额-未税金额
//                receiveVoucher.setDiffTaxAmount(receiveVoucher.getTaxAmount().subtract(receiveVoucher.getNotTaxAmount()));
//                //不含税单价 未税金额/数量
//                receiveVoucher.setNotTaxPrice(receiveVoucher.getTaxPrice().divide(taxAdd, 4, BigDecimal.ROUND_DOWN));
//                receiveVoucher.setDeductionRatio(deductionRatio);
            }
        }

    }

    @Override
    public void updatePayment(List<String> idList, String paymentTermCode) {
        if (StringUtils.isEmpty(paymentTermCode)){
            throw new DaoException("付款条件不能为空");
        }
        List<ReceiveVoucher> receiveVoucherList = receiveVoucherService.listByIds(idList);
        if (CollectionUtils.isNotEmpty(receiveVoucherList)){
            for (ReceiveVoucher receiveVoucher : receiveVoucherList){
                receiveVoucher.setPaymentTermCode(paymentTermCode);
            }
        }
        receiveVoucherService.updateBatchById(receiveVoucherList);
    }

    /**
     * 统计凭证在SRM中的使用情况
     *
     * @param asId    对账单ID
     * @param list    对账单明细数据
     * @param optType 操作类型 0:对账单查看/编辑 1:新增/添加新行
     */
    @Override
    public void statisticVoucherData(Long asId, List<StatementItemDTO> list, Integer optType) {
        List<Long> rvIdList = Lists.newArrayList();
        for (StatementItemDTO dto : list) {
            rvIdList.add(dto.getReceiveId());
        }

        List<StatisticVoucherDTO> dtoList = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(rvIdList)) {
            // 1.获取开票申请中凭证数量及金额
            dtoList.addAll(receiptVoucherConvert.statisticVoucherpo2DtoList(receiveVoucherService.findInvoicedApply(asId, rvIdList)));

            // 2.获取对账单中凭证数量及金额
            if (CollectionUtils.isNotEmpty(dtoList)) {
                List<Long> asdIdList = Lists.newArrayList();
                for (StatisticVoucherDTO dto : dtoList) {
                    asdIdList.add(dto.getAsdId());
                }

                dtoList.addAll(receiptVoucherConvert.statisticVoucherpo2DtoList(receiveVoucherService.findStatementDetail(asId, asdIdList, rvIdList)));
            } else {
                dtoList.addAll(receiptVoucherConvert.statisticVoucherpo2DtoList(receiveVoucherService.findStatementDetail(asId, Lists.newArrayList(), rvIdList)));
            }
        }

        final Map<Long, List<StatisticVoucherDTO>> map = dtoList.stream().collect(Collectors.groupingBy(StatisticVoucherDTO::getReceiveId));

        Map<Long, StatisticVoucherDTO> result = Maps.newHashMap();
        for (Map.Entry<Long, List<StatisticVoucherDTO>> in : map.entrySet()) {
            BigDecimal invoicedAmount = BigDecimal.ZERO, usedQuantity = BigDecimal.ZERO;
            final List<StatisticVoucherDTO> svList = in.getValue();
            for (StatisticVoucherDTO sv : svList) {
                invoicedAmount = invoicedAmount.add(sv.getInvoicedAmount());
                usedQuantity = usedQuantity.add(sv.getUsedQuantity());
            }
            StatisticVoucherDTO dto = new StatisticVoucherDTO();
            dto.setInvoicedAmount(invoicedAmount);
            dto.setUsedQuantity(usedQuantity);
            dto.setReceiveId(in.getKey());

            result.put(in.getKey(), dto);
        }

        for (StatementItemDTO dto : list) {
            final StatisticVoucherDTO sv = result.get(dto.getReceiveId());
            if (null != sv) {
                // 最终剩余数量 = 凭证剩余数量(结合SAP的过账数量及过账申请数据) - SRM中使用数量
                BigDecimal surplusNum = BigDecimal.ZERO;
                if (sv.getUsedQuantity().compareTo(BigDecimal.ZERO) >= 0) {
                    surplusNum = dto.getSurplusNum().subtract(sv.getUsedQuantity());
                }

                dto.setSurplusNum(surplusNum);

                // 新增对账单
                if (null == asId) {
                    dto.setAsQuantity(surplusNum);
                }
                // TODO 剩余可开票金额计算存在问题
                dto.setSurplusAmount(surplusNum.multiply(dto.getOrderTaxPrice()).setScale(4, BigDecimal.ROUND_HALF_UP));
                dto.setInvoicedAmount(dto.getInvoicedAmount().add(sv.getInvoicedAmount()));
            }
        }

        for (int i = list.size() - 1; i >= 0; i--) {
            StatementItemDTO dto = list.get(i);
            if (dto.getAsQuantity().compareTo(BigDecimal.ZERO) == 0) {
                list.remove(dto);
            }
            if (1 == optType) {
                if (dto.getSurplusNum().compareTo(BigDecimal.ZERO) == 0) {
                    list.remove(dto);
                }
            }
        }
    }

    /**
     * 检查对账单入库明细中编辑标识和最低对账数量
     *
     * @param list 待检查数据
     */
    private void checkEditFlag(List<StatementItemDTO> list){
        List<ReceiveVoucher> rvList = Lists.newArrayList();
        for(StatementItemDTO dto: list){
            rvList.add(dto.toRv());
        }

        BigDecimal negOne = new BigDecimal("-1");
        final Map<Long, WriteOffVoucherCheckPO> checkResult = receiveVoucherService.handleWriteOffVoucherData(rvList);
        for(StatementItemDTO item: list){
            // System.out.println(item.getReceiveId());
            // 默认每一个行项目都有检查到数据
            WriteOffVoucherCheckPO dto = checkResult.get(item.getReceiveId());
            item.setEditFlag(dto.getEditFlag());
            item.setMinStatementQuantity(dto.getMinStatementQuantity());

            if("H".equals(item.getVoucherFlag())){
                item.setReceiveNum(item.getReceiveNum().multiply(negOne));
                item.setAsQuantity(item.getAsQuantity().multiply(negOne));
                item.setNotTaxAmount(item.getNotTaxAmount().multiply(negOne));
                item.setTaxAmount(item.getTaxAmount().multiply(negOne));
                item.setDiffTaxAmount(item.getDiffTaxAmount().multiply(negOne));
                item.setOrderNotTaxAmount(item.getNotTaxAmount().multiply(negOne));
                if (item.getOrderTaxAmount()!=null){
                    item.setOrderTaxAmount(item.getOrderTaxAmount().multiply(negOne));
                }
                if (item.getOrderDiffTaxAmount()!=null){
                    item.setOrderDiffTaxAmount(item.getOrderDiffTaxAmount().multiply(negOne));
                }
                item.setSurplusAmount(item.getSurplusAmount().multiply(negOne));
                item.setInvoicedAmount(item.getInvoicedAmount().multiply(negOne));
            }
        }
    }
    /**
     * 提供创建对账单时获取入库凭证数据
     *
     * @param query 查询条件
     * @return 结果
     */
    @Override
    public PageView provideCreateStatement(ReceiveVoucherQuery query) {
        if(StringUtils.isNotEmpty(query.getAlreadyExistId())){
            List<Long> alreadyExistIdList = Lists.newArrayList();
            final String[] aeIdArray = StringUtils.split(query.getAlreadyExistId(), ",");
            for(String receiveId: aeIdArray){
                alreadyExistIdList.add(Long.parseLong(receiveId));
            }

            query.setAlreadyExistIdList(alreadyExistIdList);
        }
        if (StringUtils.isNotEmpty(query.getPoTypes())){
            query.setPoTypeList(Arrays.asList(query.getPoTypes().split(",")));
        }
        //查询全部
        List<StatementItemPO> statementItemPOS = receiveVoucherService.provideCreateStatement(query);
        List<StatementItemDTO> list = receiptVoucherConvert.statementItemPo2DtoList(statementItemPOS);
        list.forEach(statementItemDTO -> {
            statementItemDTO.setOriginalTaxAmount(statementItemDTO.getOriginalTaxPrice().multiply(statementItemDTO.getMvNum()));
        });
        //移除某些符合的项
        if (StringUtils.isNotEmpty(query.getRemoveLists())){
            List<String> removeList = StrUtil.split(query.getRemoveLists(), ',');
            if (CollectionUtils.isNotEmpty(removeList)){
                for (String remove : removeList){
                    list.removeIf(statementItemDTO -> (statementItemDTO.getReceiveId().toString()).equals(remove));
                }
            }
        }

        //2025-02-07 最新逻辑
        //供应商，采购都需要在配置表中进行新业务的配置
        //查询全部的的，需要进行配置表有权限的可以查出来，没权限的不能查出来
        //查询旧业务，就是把配置表里配置的采购组入库凭证全部删除
        //查询新的业务，就是只查自己id+采购组的入库凭证
        //2025-02-04新增校验一个供应商对应多个对账采购组查询逻辑
        //获取当前登录用户id
        Long userId = LoginUtil.getUserId();
        List<StatementPaymentSetting> statementPaymentSettings = statementPaymentSettingService.findStatementPaymentSettingBySupplierCodeList(query.getSupplierCode());
        if(CollectionUtils.isNotEmpty(statementPaymentSettings)){//按照条件查询到了配置数据则需要关联订单上的采购组去查询数据
            List<String> purchaseGroupCodes = statementPaymentSettings.stream()
                    .filter(setting -> setting.getUserId().equals(userId))
                    .map(StatementPaymentSetting::getPurchaseGroupCode)
                    .collect(Collectors.toList());
            //供应商全部采购组
            List<String> allPurchaseGroupCode = statementPaymentSettings.stream()
                    .map(StatementPaymentSetting::getPurchaseGroupCode)
                    .collect(Collectors.toList());
            //排除采购组
            List<String> excludePurchaseGroupCodes = statementPaymentSettings.stream()
                    .map(StatementPaymentSetting::getPurchaseGroupCode)
                    .collect(Collectors.toList());
            //删除自己的留下的采购组再去到全部数据里去删除
            if(CollectionUtils.isNotEmpty(purchaseGroupCodes)){
                excludePurchaseGroupCodes.removeAll(purchaseGroupCodes);
            }

            if(StringUtils.isNotEmpty(query.getBusinessFalg())){
                if(query.getBusinessFalg().equals("1")){//查询新业务 只保留凭证明细中采购组只存在配置的对账采购组
                    if(CollectionUtils.isNotEmpty(purchaseGroupCodes)){
                        Set<String> pgCodeSet = new HashSet<>(purchaseGroupCodes);
                        // 使用流过滤并生成新的列表
                        list = list.stream()
                                .filter(dto -> pgCodeSet.contains(dto.getPgCode()))
                                .collect(Collectors.toList());
                    }else{
                        list.clear();
                    }
                }
                if(query.getBusinessFalg().equals("2")){//查询旧业务 只保留凭证明细中采购组不存在配置的对账采购组
                    if(CollectionUtils.isNotEmpty(allPurchaseGroupCode)){
                        for (String remove : allPurchaseGroupCode){
                            list.removeIf(statementItemDTO -> (statementItemDTO.getPgCode()).equals(remove));
                        }
                    }
                }
                if(query.getBusinessFalg().equals("0")){
                  //保留自己有权限的+旧的业务数据
                    if(CollectionUtils.isNotEmpty(excludePurchaseGroupCodes)){
                        Set<String> pgCodeSet = new HashSet<>(excludePurchaseGroupCodes);
                        // 使用流过滤并生成新的列表
                        list = list.stream()
                                .filter(dto -> !pgCodeSet.contains(dto.getPgCode()))
                                .collect(Collectors.toList());
                    }
                }
            }


        }
//        final Page<ReceiveVoucher> dbPage = PageUtil.toPage(query);
//        List<StatementItemPO> statementItemPagePOS = receiveVoucherService.provideCreateStatementPage(dbPage,query);
//        List<StatementItemDTO> pageList = receiptVoucherConvert.statementItemPo2DtoList(statementItemPagePOS);

        // 实时调用接口检查已开票数量和已开票金额(含税)
//        accountStatementDetailLogic.realTimeReceiveVoucher(query, list);

        // 处理入库凭证剩余数量及金额信息
        this.statisticVoucherData(query.getAsId(), list, 1);
        // 检查对账单入库明细中编辑标识和最低对账数量
        this.checkEditFlag(list);
        BigDecimal notTaxAmount = BigDecimal.ZERO, taxAmount = BigDecimal.ZERO, diffTaxAmount = BigDecimal.ZERO,
                invoicedAmount = BigDecimal.ZERO, surplusAmount = BigDecimal.ZERO;
        String supplierCode2 = "";
        String supplierName2 = "";
        for(StatementItemDTO dto: list){
            if(dto.getTaxPrice() == null){
                continue;
            }

            if (StringUtils.isNotEmpty(dto.getSupplierCode2())){
                supplierCode2 = dto.getSupplierCode2();
            }
            if (StringUtils.isNotEmpty(dto.getSupplierName2())){
                supplierName2 = dto.getSupplierName2();
            }
            // 计算时的税率
            BigDecimal tax = dto.getTaxValue().add(BigDecimal.ONE);
//            BigDecimal itAmount = dto.getTaxPrice().multiply(dto.getAsQuantity()).setScale(priceHandle.getPrecision(), priceHandle.getCutType()==0?RoundingMode.HALF_UP:RoundingMode.HALF_DOWN);
//            BigDecimal ntAmount = itAmount.divide(tax, priceHandle.getPrecision(), priceHandle.getCutType()==0?RoundingMode.HALF_UP:RoundingMode.HALF_DOWN);

            BigDecimal itAmount = dto.getTaxAmount();
            BigDecimal ntAmount = dto.getNotTaxAmount();
            BigDecimal dtAmount = itAmount.subtract(ntAmount);
            dto.setTaxAmount(itAmount);
            dto.setNotTaxAmount(ntAmount);
            dto.setDiffTaxAmount(dtAmount);

//            if("S".equals(dto.getVoucherFlag())){
//                notTaxAmount = (notTaxAmount.add(ntAmount)).setScale(2, RoundingMode.HALF_UP);
//                taxAmount =  (taxAmount.add(itAmount)).setScale(2, RoundingMode.HALF_UP);
//                diffTaxAmount = (diffTaxAmount.add(dtAmount)).setScale(2, RoundingMode.HALF_UP);;
            notTaxAmount = notTaxAmount.add(ntAmount);
            taxAmount = taxAmount.add(itAmount);
            diffTaxAmount = diffTaxAmount.add(dtAmount);
//            }else {
//                notTaxAmount = notTaxAmount.subtract(ntAmount);
//                taxAmount = taxAmount.subtract(itAmount);
//                diffTaxAmount = diffTaxAmount.subtract(dtAmount);
//            }
            invoicedAmount = invoicedAmount.add(dto.getInvoicedAmount());
            surplusAmount = surplusAmount.add(dto.getSurplusAmount());
            dto.setAsNtAmount(dto.getNotTaxPrice().multiply(dto.getAsQuantity()));
            dto.setAsItAmount(dto.getTaxPrice().multiply(dto.getAsQuantity()));
        }

        JSONArray footer = new JSONArray();
        JSONObject obj = new JSONObject();
        obj.put("notTaxAmount", notTaxAmount);
        obj.put("taxAmount", taxAmount);
        obj.put("diffTaxAmount", diffTaxAmount);
        obj.put("invoicedAmount", invoicedAmount);
        obj.put("surplusAmount", surplusAmount);
        obj.put("supplierCode2", supplierCode2);
        obj.put("supplierName2", supplierName2);

        footer.add(obj);
        BasePageQuery basePageQuery = new BasePageQuery();
        basePageQuery.setPage(1);
        basePageQuery.setRows(list.size());
        final Page<ReceiveVoucher> dbPage = PageUtil.toPage(basePageQuery);
        PageView pageView = PageUtil.getPV(list, list.size());
        pageView.setFooter(footer);
        return pageView;
    }
    @Override
    public List<StatementItemDTO> provideCreateStatementList(ReceiveVoucherQuery query) {
        //查询全部
        List<StatementItemPO> statementItemPOS = receiveVoucherService.provideCreateStatement(query);
        List<StatementItemDTO> list = receiptVoucherConvert.statementItemPo2DtoList(statementItemPOS);

        // 处理入库凭证剩余数量及金额信息
        this.statisticVoucherData(query.getAsId(), list, 1);
        // 检查对账单入库明细中编辑标识和最低对账数量
        this.checkEditFlag(list);
        return receiptVoucherConvert.statementItemPo2DtoList(statementItemPOS);
    }

    @Override
    public PageView provideCreatePaymentMatching(ReceiveVoucherQuery query) {
        //查询全部
        List<StatementItemPO> statementItemPOS = receiveVoucherService.provideCreatePaymentMatching(query);
        List<StatementItemDTO> list = receiptVoucherConvert.statementItemPo2DtoList(statementItemPOS);
        list.forEach(dto -> {
            if (dto.getVoucherFlag().equals("H")){
                if (dto.getTaxAmount().compareTo(BigDecimal.ZERO) > 0) { // 只有正数才取负
                    dto.setTaxAmount(dto.getTaxAmount().negate());
                    dto.setMvNum(dto.getMvNum().negate());
                }
            }
        });
        JSONArray footer = new JSONArray();
        JSONObject obj = new JSONObject();
        footer.add(obj);
        PageView pageView = PageUtil.getPV(list, list.size());
        pageView.setFooter(footer);
        return pageView;
    }
    @Override
    public PageView provideCreateCostMatching(ReceiveVoucherQuery query) {
        //查询全部
        List<StatementItemPO> statementItemPOS = receiveVoucherService.provideCreateCostMatching(query);
        List<StatementItemDTO> list = receiptVoucherConvert.statementItemPo2DtoList(statementItemPOS);
        list.forEach(dto -> {
            if (dto.getVoucherFlag().equals("H")){
                if (dto.getTaxAmount().compareTo(BigDecimal.ZERO) > 0) { // 只有正数才取负
                    dto.setTaxAmount(dto.getTaxAmount().negate());
                    dto.setMvNum(dto.getMvNum().negate());
                }
            }
        });
        JSONArray footer = new JSONArray();
        JSONObject obj = new JSONObject();
        footer.add(obj);
        PageView pageView = PageUtil.getPV(list, list.size());
        pageView.setFooter(footer);
        return pageView;
    }

    @Override
    public PageView provideDetailByPaymentMatchingId(Long paymentMatchingId) {
        //查询全部
        List<StatementItemPO> statementItemPOS = receiveVoucherService.provideDetailByPaymentMatchingId(paymentMatchingId);
        List<StatementItemDTO> list = receiptVoucherConvert.statementItemPo2DtoList(statementItemPOS);
        list.forEach(dto -> {
            if (dto.getVoucherFlag().equals("H")){
                if (dto.getTaxAmount().compareTo(BigDecimal.ZERO) > 0) { // 只有正数才取负
                    dto.setTaxAmount(dto.getTaxAmount().negate());
                    dto.setMvNum(dto.getMvNum().negate());
                }
            }
        });
        JSONArray footer = new JSONArray();
        JSONObject obj = new JSONObject();
        footer.add(obj);
        PageView pageView = PageUtil.getPV(list, list.size());
        pageView.setFooter(footer);
        return pageView;
    }

    @Override
    public PageView provideDetailByCostMatchingId(Long costMatchingId) {
        //查询全部
        List<StatementItemPO> statementItemPOS = receiveVoucherService.provideDetailByCostMatchingId(costMatchingId);
        List<StatementItemDTO> list = receiptVoucherConvert.statementItemPo2DtoList(statementItemPOS);
        list.forEach(dto -> {
            if (dto.getVoucherFlag().equals("H")){
                if (dto.getTaxAmount().compareTo(BigDecimal.ZERO) > 0) { // 只有正数才取负
                    dto.setTaxAmount(dto.getTaxAmount().negate());
                    dto.setMvNum(dto.getMvNum().negate());
                }
            }
        });
        JSONArray footer = new JSONArray();
        JSONObject obj = new JSONObject();
        footer.add(obj);
        PageView pageView = PageUtil.getPV(list, list.size());
        pageView.setFooter(footer);
        return pageView;
    }

    /**
     * 根据物料凭证号检验凭证的参考凭证是否在内
     *
     * @param rvIdList     待检查的物料凭证ID
     * @param supplierCode 供应商编码
     * @param voucherType  凭证类型 1:材料类 2:运费类
     * @return 结果
     */
    @Override
    @DS(SLAVE)
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public String checkConsultVoucher(List<Long> rvIdList, String supplierCode, Integer voucherType) {
        // 获取本次保存的开票申请明细对应的入库凭证数据
        ReceiveVoucherQuery query = new ReceiveVoucherQuery();
        query.setRecIdList(rvIdList);

        List<ReceiveVoucherPO> receiveVoucherPOS = receiveVoucherService.findPageByQuery(null, query);
        List<ReceiveVoucherDTO> rvList = receiptVoucherConvert.po2PageListDTO(receiveVoucherPOS);
        // 获取参考凭证数据
        List<String> cvKeyList = Lists.newArrayList();
        for (ReceiveVoucherDTO rv : rvList) {
            String cvKey = rv.getCvYear() + "#" + rv.getCvCode() + "#" + rv.getCvItemNo();
            cvKeyList.add(cvKey);
        }

        if (CollectionUtils.isEmpty(cvKeyList)) {
            return "";
        }

        // 根据参考获取对应的入库凭证数据
        final List<ReceiveVoucher> cvList = receiveVoucherService.findByConsultVoucher(supplierCode, cvKeyList, voucherType);
        // 校验结果
        StringBuilder result = new StringBuilder();
        // 是否返回空字符
        boolean isEmptyFlag = true;
        for (ReceiveVoucher cv : cvList) {
            if (rvIdList.indexOf(cv.getId()) == -1) {
                isEmptyFlag = false;
                result.append(cv.getMvCode()).append("#").append(cv.getMvItemNo()).append("(").append(cv.getCvCode()).append("#").append(cv.getCvItemNo()).append(")").append("</br>");
            }
        }

        if (!isEmptyFlag) {
            return "必须选择以下相关入库凭证: </br>" + result.toString();
        }

        return "";
    }

    @Override
    @DS(SLAVE)
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public ReceiveVoucherDTO getByIdAndFactoryCode(Long receiveId,String factoryCode) {
        ReceiveVoucher receiveVoucher =  receiveVoucherService.getOne(Wrappers.lambdaQuery(ReceiveVoucher.class).eq(ReceiveVoucher::getId,receiveId).eq(ReceiveVoucher::getFactoryCode,factoryCode));
        return receiptVoucherConvert.entity2DTO(receiveVoucher);
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    @DS(SLAVE)
    public void priceImport(MultipartFile file) {
        try {
            List<Map<String,String>> dataList = EasyExcelImportUtils.parseExcelToData(file.getInputStream(), 2);
            if (CollectionUtils.isNotEmpty(dataList)){
                for (Map<String,String> map : dataList){
                    if (StringUtils.isNotEmpty(map.get("mvCode"))&&StringUtils.isNotEmpty(map.get("mvItemNo"))&&StringUtils.isNotEmpty(map.get("factoryCode"))&&StringUtils.isNotEmpty(map.get("deductionRatio"))){
                        ReceiveVoucher receiveVoucher = receiveVoucherService.getOne(Wrappers.lambdaQuery(ReceiveVoucher.class)
                                .eq(ReceiveVoucher::getMvCode,map.get("mvCode"))
                                .eq(ReceiveVoucher::getFactoryCode,map.get("factoryCode"))
                                .eq(ReceiveVoucher::getMvItemNo,map.get("mvItemNo")).last(" limit 1"));
                        if (ObjectUtil.isNotNull(receiveVoucher)){
//                            //含税单价
//                            receiveVoucher.setTaxPrice(new BigDecimal(map.get("taxPrice")));
//                            //含税金额 含税单价*数量
//                            receiveVoucher.setTaxAmount(receiveVoucher.getMvNum().multiply(receiveVoucher.getTaxPrice()));
//                            BigDecimal tax = receiveVoucher.getTaxValue().divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
//                            //不含税金额 含税金额/(1+税率)
//                            BigDecimal taxAdd = tax.add(new BigDecimal(1));
//                            receiveVoucher.setNotTaxAmount(receiveVoucher.getTaxAmount().divide(taxAdd, 4, BigDecimal.ROUND_DOWN));
//                            //税额 含税金额-未税金额
//                            receiveVoucher.setDiffTaxAmount(receiveVoucher.getTaxAmount().subtract(receiveVoucher.getNotTaxAmount()));
//                            //不含税单价 未税金额/数量
//                            receiveVoucher.setNotTaxPrice(receiveVoucher.getTaxPrice().divide(taxAdd, 4, BigDecimal.ROUND_DOWN));
//                            receiveVoucherService.update(receiveVoucher,Wrappers.lambdaQuery(ReceiveVoucher.class)
//                                    .eq(ReceiveVoucher::getId,receiveVoucher.getId())
//                                    .eq(ReceiveVoucher::getFactoryCode,map.get("factoryCode"))
//                            );
//

                            receiveVoucher.setDeductionRatio((new BigDecimal(map.get("deductionRatio"))));
                            //不含税金额 不含税金额-其他折扣
                            receiveVoucher.setNotTaxAmount(receiveVoucher.getNotTaxAmount().subtract(receiveVoucher.getDeductionRatio()));
                            //不含税单价 不含税金额/数量
                            receiveVoucher.setNotTaxPrice(receiveVoucher.getNotTaxAmount().divide(receiveVoucher.getMvNum(), priceHandle.getPrecision(), priceHandle.getCutType()==0?RoundingMode.HALF_UP:RoundingMode.HALF_DOWN));

                            BigDecimal taxAdd = receiveVoucher.getTaxValue().add(new BigDecimal(1));
                            //含税单价 未税单价*（1+税率）
                            receiveVoucher.setTaxPrice(receiveVoucher.getNotTaxPrice().multiply(taxAdd));
                            //含税金额 含税单价*数量
                            receiveVoucher.setTaxAmount(receiveVoucher.getMvNum().multiply(receiveVoucher.getTaxPrice()));
                            //税额 含税金额-未税金额
                            receiveVoucher.setDiffTaxAmount(receiveVoucher.getTaxAmount().subtract(receiveVoucher.getNotTaxAmount()));
                            receiveVoucherService.update(receiveVoucher,Wrappers.lambdaQuery(ReceiveVoucher.class)
                                    .eq(ReceiveVoucher::getId,receiveVoucher.getId())
                                    .eq(ReceiveVoucher::getFactoryCode,map.get("factoryCode"))
                            );
                        }
                    }
                }
            }
        } catch (IOException e) {
            throw new DaoException("读取Excel失败");
        }
    }

    @Override
    public List<ReceiveVoucherDTO> findByPoAndAsNoNotNull(String poCode, String poItemNo,String factoryCode) {
        return receiptVoucherConvert.po2PageListDTO(receiveVoucherService.findByPoAndAsNoNotNull(poCode,poItemNo,factoryCode));
    }

    @Override
    public List<ReceiveVoucherDTO> findByPoAndItemNo(String poCode, String poItemNo,String factoryCode) {
        return receiptVoucherConvert.po2PageListDTO(receiveVoucherService.findByPoAndItemNo(poCode,poItemNo,factoryCode));
    }

    /**
     * 更新凭证信息
     *
     * @param receiveVoucherId  凭证ID
     * @param factoryCode       工厂编码
     * @param invoiceVoucher    凭证号
     * @param paymentExpireDate 付款到期日
     */
    @Override
    @DS(SLAVE)
    public void updateInvoiceVoucherAndPaymentExpireDate(Long receiveVoucherId, String factoryCode, String invoiceVoucher, String paymentExpireDate) {
        receiveVoucherService.update(Wrappers.lambdaUpdate(ReceiveVoucher.class)
                .set(ReceiveVoucher::getInvoicedCode,invoiceVoucher)
                .set(ReceiveVoucher::getPaymentExpireDate,paymentExpireDate)
                .eq(ReceiveVoucher::getId,receiveVoucherId)
                .eq(ReceiveVoucher::getFactoryCode,factoryCode));
    }

    @Override
    @DS(SLAVE)
    public List<ReceiveVoucherDTO> getReturnVoucherData(String supplierCode, String factoryCode) {
        return receiptVoucherConvert.po2PageListDTO(receiveVoucherService.getReturnVoucherData(supplierCode,factoryCode));
    }
    @Override
    @DS(SLAVE)
    public BigDecimal getPoReturnVoucherData(String supplierCode, String factoryCode,String companyCode) {
        return receiveVoucherService.getPoReturnVoucherData(supplierCode,factoryCode,companyCode);
    }

    /**
     * 获取在途退款金额
     *
     * @param supplierCode 供应商编码
     * @param factoryCode  工厂编码
     * @return 退款金额
     */
    @Override
    @DS(SLAVE)
    public BigDecimal getReturnVoucherRefundAmount(String supplierCode, String factoryCode,String companyCode,Boolean deductionFlag) {
        //统计“在途退款金额”
        BigDecimal poTaxAmount = this.getPoReturnVoucherData(supplierCode,factoryCode,companyCode)==null?BigDecimal.ZERO:this.getPoReturnVoucherData(supplierCode,factoryCode,companyCode);
        BigDecimal originalTaxAmount = BigDecimal.ZERO;
        List<ReceiveVoucherDTO> receiveVoucherDTOS = this.getReturnVoucherData(supplierCode,factoryCode);
        if (CollectionUtils.isNotEmpty(receiveVoucherDTOS)){
            for (ReceiveVoucherDTO receiveVoucherDTO : receiveVoucherDTOS){
//                if (receiveVoucherDTO.getDeductionRatio().compareTo(BigDecimal.ZERO)!=0){
                    receiveVoucherDTO.setOriginalTaxAmount(receiveVoucherDTO.getTaxAmount());
//                }else{
//                    receiveVoucherDTO.setOriginalTaxAmount(receiveVoucherDTO.getOriginalTaxPrice().multiply(receiveVoucherDTO.getMvNum()));
//                }
                if (receiveVoucherDTO.getPoTaxAmount()!=null){
                    if (receiveVoucherDTO.getPoTaxAmount().compareTo(BigDecimal.ZERO) > 0){
                        receiveVoucherDTO.setPoTaxAmount(receiveVoucherDTO.getPoTaxAmount().negate());
                    }
                    if (receiveVoucherDTO.getOriginalTaxAmount().compareTo(BigDecimal.ZERO) > 0){
                        receiveVoucherDTO.setOriginalTaxAmount(receiveVoucherDTO.getOriginalTaxAmount().negate());
                    }
                    originalTaxAmount = originalTaxAmount.add(receiveVoucherDTO.getOriginalTaxAmount());
//                    poTaxAmount = poTaxAmount.add(receiveVoucherDTO.getPoTaxAmount());
                }
            }
        }
        BigDecimal dntAmount = BigDecimal.ZERO;
        if (deductionFlag){
            List<Deduction> deductionList = deductionService.list(new LambdaQueryWrapper<>(Deduction.class)
                    .eq(Deduction::getSupplierCode, supplierCode)
                    .eq(Deduction::getCompanyCode, companyCode)
                    .ne(Deduction::getStatus, 3)
            );
            if (CollectionUtils.isNotEmpty(deductionList)){
                for (Deduction deduction : deductionList){
                    if (deduction.getDeductionAmount().compareTo(BigDecimal.ZERO) > 0){
                        deduction.setDeductionAmount(deduction.getDeductionAmount().negate());
                    }
                    dntAmount = dntAmount.add(deduction.getDeductionAmount());
                }
            }
        }
        BigDecimal result = poTaxAmount.subtract(originalTaxAmount).add(dntAmount).setScale(2, RoundingMode.HALF_UP).stripTrailingZeros();
        return result;
    }
}

