package com.sunxung.factoring.service.fundmanagement.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sunxung.factoring.component.exception.BusinessException;
import com.sunxung.factoring.component.exception.ValidatorException;
import com.sunxung.factoring.component.util.*;
import com.sunxung.factoring.dict.impl.FileModuleDict;
import com.sunxung.factoring.dict.impl.FinancialCustomerStatusDict;
import com.sunxung.factoring.entity.ResponseJson;
import com.sunxung.factoring.entity.fundmanagement.*;
import com.sunxung.factoring.entity.fundmanagement.vo.*;
import com.sunxung.factoring.entity.project.BusinessProcessingLog;
import com.sunxung.factoring.entity.project.vo.BusinessProcessingTaskVo;
import com.sunxung.factoring.entity.project.vo.SearchBusinessProcessingTask;
import com.sunxung.factoring.entity.sys.Dictionary;
import com.sunxung.factoring.entity.sys.FileStorage;
import com.sunxung.factoring.entity.sys.Role;
import com.sunxung.factoring.entity.sys.UserRoleRel;
import com.sunxung.factoring.mapper.fundmanagement.FinancialCustomerExpenditureMapper;
import com.sunxung.factoring.service.fundmanagement.*;
import com.sunxung.factoring.service.project.BusinessAssigneeService;
import com.sunxung.factoring.service.project.BusinessProcessingLogService;
import com.sunxung.factoring.service.sys.DictionaryService;
import com.sunxung.factoring.service.sys.FileStorageService;
import com.sunxung.factoring.service.sys.ISysAttachmentRefService;
import com.sunxung.factoring.service.sys.RoleService;
import com.sunxung.factoring.service.sys.dto.AttachmentDto;
import com.sunxung.factoring.service.sys.flowable.FlowableService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description :
 * @Author : L.Jia
 * @Date: 2023-02-23 10:14
 */
@Service("financialCustomerExpenditureService")
public class FinancialCustomerExpenditureServiceImpl implements FinancialCustomerExpenditureService {

    @Autowired
    private FinancialCustomerExpenditureMapper mapper;

    @Autowired
    private DictionaryService dictService;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private FinancialCustomerExpenditureInfoService expenditureInfoService;

    @Autowired
    private FinancialCustomerExpenditureContractInfoService expenditureContractInfoService;

    @Autowired
    private FinancialCustomerExpenditureHisInfoService expenditureHisInfoService;

    @Autowired
    private FinancialCustomerExpenditureContractHisInfoService expenditureContractHisInfoService;

    @Autowired
    private FinancialCustomerExpenditureApprovalInfoService expenditureApprovalInfoService;

    @Value("${config.financial.findRecordList.url}")
    private String findRecordListUrl;

    @Autowired
    private FileStorageService fileStorageService;

    @Autowired
    private ISysAttachmentRefService sysAttachmentRefService;

    @Autowired
    private FlowableService flowableService;

    @Autowired
    private BusinessAssigneeService assigneeService;

    @Autowired
    private BusinessProcessingLogService processingLogService;

    @Autowired
    private FinancialRelationCustomerDisburseService financialRelationCustomerDisburseService;

    @Autowired
    private FinancialCustomerInfoService financialCustomerInfoService;

    @Autowired
    private RoleService roleService;


    @Override
    public FinancialCustomerExpenditureInfo get(Long id) {
        FinancialCustomerExpenditureInfo customerExpenditureInfo = mapper.getDetail(id);
        if (customerExpenditureInfo != null) {
            //填充状态
            if (customerExpenditureInfo.getStatusDictionary() != null) {
                customerExpenditureInfo.setStatusDictionary(dictService.get(customerExpenditureInfo.getStatusDictionary().getId()));
            }
        }
        return customerExpenditureInfo;
    }

    @Override
    public FinancialCustomerExpenditureInfo getDetail(Long id) {
        return mapper.getDetail(id);
    }


    @Override
    public FinancialCustomerExpenditureDetailVo edit(Long id) {
        FinancialCustomerExpenditureInfo customerExpenditureInfo = mapper.getDetail(id);

        FinancialCustomerExpenditureDetailVo detailVo = new FinancialCustomerExpenditureDetailVo();
        if (customerExpenditureInfo != null) {
            detailVo.setId(customerExpenditureInfo.getId());
            //客户名称
            detailVo.setCustomerName(customerExpenditureInfo.getCustomerName());
            //到期日
            detailVo.setExpireDate(customerExpenditureInfo.getExpireDate());
            //调用sop查询业务放款信息
            LoanInfoSearch loanInfoSearch = new LoanInfoSearch(customerExpenditureInfo);
            LoanInfoVo loanInfoVo = getLoanInfoVo(loanInfoSearch);

            List<Date> loanDateList = new ArrayList<>();
            if (loanInfoVo != null) {
                List<LoanRecordVo> loanRecordList = loanInfoVo.getLoanRecordList();
                if (CollectionUtil.isNotEmpty(loanRecordList)) {
                    loanDateList = loanRecordList.stream().map(LoanRecordVo::getLoanDate).distinct().collect(Collectors.toList());
                    BigDecimal loanAmountTotal = loanRecordList.stream().map(LoanRecordVo::getLoanAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                    //放款金额
                    detailVo.setLoanAmountTotal(NumberFormatUtil.convertDecimal(loanAmountTotal, NumberFormatUtil.THOUSAND_SEPARATOR_TWO_DECIMAL));
                    //币种
                    detailVo.setCurrencyCode(loanRecordList.get(0).getCurrencyCode());
                }
            }
            //放款日
            detailVo.setLoanDateList(loanDateList);
            List<FinancialCustomerExpenditureContractInfo> expenditureContractInfoList = expenditureContractInfoService.list(new QueryWrapper<FinancialCustomerExpenditureContractInfo>()
                    .eq("financial_customer_expenditure_info_id", customerExpenditureInfo.getId()));
            List<UpstreamDetailVo> upstreamDetailList = new ArrayList<>();
            List<DownstreamDetailVo> downstreamDetailList = new ArrayList<>();

            Boolean upstreamShow = false;
            if (CollectionUtil.isNotEmpty(expenditureContractInfoList)) {
                for (FinancialCustomerExpenditureContractInfo contractInfo : expenditureContractInfoList) {
                    if (contractInfo.getUpstreamContractNo() != null && contractInfo.getUpstreamContractAmount() != null
                            && contractInfo.getUpstreamContractPaymentDays() != null
                            && contractInfo.getUpstreamAccountsReceivableAmount() != null) {

                        upstreamShow = true;
                        UpstreamDetailVo upstreamDetailVo = new UpstreamDetailVo();
                        upstreamDetailVo.setContractInfoId(contractInfo.getId());
                        //上游合同编号
                        upstreamDetailVo.setUpstreamContractNo(contractInfo.getUpstreamContractNo());
                        //上游合同金额
                        upstreamDetailVo.setUpstreamContractAmount(NumberFormatUtil.convertDecimal(contractInfo.getUpstreamContractAmount(), NumberFormatUtil.THOUSAND_SEPARATOR_TWO_DECIMAL));
                        //上游合同账期
                        upstreamDetailVo.setUpstreamContractPaymentDays(contractInfo.getUpstreamContractPaymentDays());
                        //上游应收账款金额
                        upstreamDetailVo.setUpstreamAccountsReceivableAmount(NumberFormatUtil.convertDecimal(contractInfo.getUpstreamAccountsReceivableAmount(), NumberFormatUtil.THOUSAND_SEPARATOR_TWO_DECIMAL));
                        //上游采购合同
                        List<FileStorage> upstreamPurchFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(contractInfo.getId())
                                .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_UPSTREAM_PURCH_FILE).build());
                        upstreamDetailVo.setUpstreamPurchContractFiles(upstreamPurchFileList);
                        //上游结算单
                        List<FileStorage> upstreamSettleFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(contractInfo.getId())
                                .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_UPSTREAM_SETTLEMENT_FILE).build());
                        upstreamDetailVo.setUpstreamSettlementFiles(upstreamSettleFileList);
                        //上游发票
                        List<FileStorage> upstreamInvoiceFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(contractInfo.getId())
                                .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_UPSTREAM_INVOICE_FILE).build());
                        upstreamDetailVo.setUpstreamInvoiceFiles(upstreamInvoiceFileList);
                        upstreamDetailList.add(upstreamDetailVo);
                    }

                    DownstreamDetailVo downstreamDetailVo = new DownstreamDetailVo();
                    downstreamDetailVo.setContractInfoId(contractInfo.getId());
                    //下游合同编号
                    downstreamDetailVo.setDownstreamContractNo(contractInfo.getDownstreamContractNo());
                    //下游合同金额
                    downstreamDetailVo.setDownstreamContractAmount(NumberFormatUtil.convertDecimal(contractInfo.getDownstreamContractAmount(), NumberFormatUtil.THOUSAND_SEPARATOR_TWO_DECIMAL));
                    //下游合同账期
                    downstreamDetailVo.setDownstreamContractPaymentDays(contractInfo.getDownstreamContractPaymentDays());
                    //下游应收账款金额
                    downstreamDetailVo.setDownstreamAccountsReceivableAmount(NumberFormatUtil.convertDecimal(contractInfo.getDownstreamAccountsReceivableAmount(), NumberFormatUtil.THOUSAND_SEPARATOR_TWO_DECIMAL));
                    //下游采购合同
                    List<FileStorage> salesFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(contractInfo.getId())
                            .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_DOWNSTREAM_SALES_FILE).build());
                    downstreamDetailVo.setDownstreamSalesContractFiles(salesFileList);
                    //下游结算单
                    List<FileStorage> downstreamSettleFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(contractInfo.getId())
                            .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_DOWNSTREAM_SETTLEMENT_FILE).build());
                    downstreamDetailVo.setDownstreamSettlementFiles(downstreamSettleFileList);
                    //下游发票
                    List<FileStorage> downstreamInvoiceFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(contractInfo.getId())
                            .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_DOWNSTREAM_INVOICE_FILE).build());
                    downstreamDetailVo.setDownstreamInvoiceFiles(downstreamInvoiceFileList);
                    downstreamDetailList.add(downstreamDetailVo);
                }
            }
            detailVo.setUpstreamDetailList(upstreamDetailList);
            detailVo.setDownstreamDetailList(downstreamDetailList);
            //附件
            List<FileStorage> attachmentFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(customerExpenditureInfo.getId())
                    .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_ATTACHMENT_FILE).build());
            detailVo.setAttachmentFiles(attachmentFileList);
            //其它
            List<FileStorage> otherFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(customerExpenditureInfo.getId())
                    .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_OTHER_FILE).build());
            detailVo.setOtherFiles(otherFileList);
            detailVo.setUpstreamShow(upstreamShow);
        }
        return detailVo;
    }

    /**
     * 获取对应业务支用信息
     *
     * @param loanInfoSearch
     * @return
     */
    private LoanInfoVo getLoanInfoVo(LoanInfoSearch loanInfoSearch) {
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(findRecordListUrl, loanInfoSearch, String.class);
        ResponseJson responseJson = JSONUtil.toBean(responseEntity.getBody(), ResponseJson.class);

        LoanInfoVo loanInfoVo = null;
        if (responseEntity.getStatusCode().value() == HttpStatus.OK.value() && responseJson.isSuccess()) {
            JSONObject jsonObject = (JSONObject) responseJson.getData();
            if (jsonObject != null) {
                loanInfoVo = jsonObject.toBean(LoanInfoVo.class);
            }
        }
        return loanInfoVo;
    }

    @Override
    public void claimFinancialCustomerExpenditureTask(String taskId) {
        ArrayList<String> roleNames = new ArrayList<>();
        roleNames.add(ConstantUtil.REFINANCING_OPERATION_OWNER);
        roleNames.add(ConstantUtil.PROJECT_MANAGER);
        roleNames.add(ConstantUtil.FINANCIAL_MANAGER);
        flowableService.claimTask(taskId, ThreadLocalUtil.getUserId(), roleNames);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doEdit(FinancialCustomerExpenditureDetailVo detailVo) {
        FinancialCustomerExpenditureInfo customerExpenditureInfo = expenditureInfoService.getById(detailVo.getId());
        if (customerExpenditureInfo == null) {
            throw new BusinessException(CodeUtil.FAIL, "根据Id获取不到对应的客户支用信息");
        }

        //移除附件和业务关联关系
        List<UpstreamDetailVo> upstreamDetailList = detailVo.getUpstreamDetailList();
        if (CollectionUtil.isNotEmpty(upstreamDetailList)) {
            upstreamDetailList.forEach(upstreamDetail -> {

                Long contractInfoId = upstreamDetail.getContractInfoId();
                if (contractInfoId == null) {
                    throw new BusinessException(CodeUtil.FAIL, "合同Id不能为空");
                }
                AttachmentDto upstreamPurchDto = AttachmentDto.builder().setEntityId(contractInfoId).setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_UPSTREAM_PURCH_FILE).build();
                sysAttachmentRefService.removeRef(upstreamPurchDto);
                List<Long> upstreamPurchContractFileIds = upstreamDetail.getUpstreamPurchContractFileIds();
                if (CollectionUtil.isNotEmpty(upstreamPurchContractFileIds)) {
                    sysAttachmentRefService.saveRef(upstreamPurchContractFileIds, upstreamPurchDto);
                }

                AttachmentDto upstreamSettlementDto = AttachmentDto.builder().setEntityId(contractInfoId).setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_UPSTREAM_SETTLEMENT_FILE).build();
                sysAttachmentRefService.removeRef(upstreamSettlementDto);
                List<Long> upstreamSettlementFileIds = upstreamDetail.getUpstreamSettlementFileIds();
                if (CollectionUtil.isNotEmpty(upstreamSettlementFileIds)) {
                    sysAttachmentRefService.saveRef(upstreamSettlementFileIds, upstreamSettlementDto);
                }

                AttachmentDto upstreamInvoiceDto = AttachmentDto.builder().setEntityId(contractInfoId).setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_UPSTREAM_INVOICE_FILE).build();
                sysAttachmentRefService.removeRef(upstreamInvoiceDto);
                List<Long> upstreamInvoiceFileIds = upstreamDetail.getUpstreamInvoiceFileIds();
                if (CollectionUtil.isNotEmpty(upstreamInvoiceFileIds)) {
                    sysAttachmentRefService.saveRef(upstreamInvoiceFileIds, upstreamInvoiceDto);
                }
            });
        }

        List<DownstreamDetailVo> downstreamDetailList = detailVo.getDownstreamDetailList();
        if (CollectionUtil.isNotEmpty(downstreamDetailList)) {
            downstreamDetailList.forEach(downstreamDetail -> {
                Long contractInfoId = downstreamDetail.getContractInfoId();
                if (contractInfoId == null) {
                    throw new BusinessException(CodeUtil.FAIL, "合同Id不能为空");
                }
                AttachmentDto downstreamSalesDto = AttachmentDto.builder().setEntityId(contractInfoId).setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_DOWNSTREAM_SALES_FILE).build();
                sysAttachmentRefService.removeRef(downstreamSalesDto);
                List<Long> downstreamSalesContractFileIds = downstreamDetail.getDownstreamSalesContractFileIds();
                if (CollectionUtil.isNotEmpty(downstreamSalesContractFileIds)) {
                    sysAttachmentRefService.saveRef(downstreamSalesContractFileIds, downstreamSalesDto);
                }

                AttachmentDto downstreamSettlementDto = AttachmentDto.builder().setEntityId(contractInfoId).setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_DOWNSTREAM_SETTLEMENT_FILE).build();
                sysAttachmentRefService.removeRef(downstreamSettlementDto);
                List<Long> downstreamSettlementFileIds = downstreamDetail.getDownstreamSettlementFileIds();
                if (CollectionUtil.isNotEmpty(downstreamSettlementFileIds)) {
                    sysAttachmentRefService.saveRef(downstreamSettlementFileIds, downstreamSettlementDto);
                }

                AttachmentDto downstreamInvoice = AttachmentDto.builder().setEntityId(contractInfoId).setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_DOWNSTREAM_INVOICE_FILE).build();
                sysAttachmentRefService.removeRef(downstreamInvoice);
                List<Long> downstreamInvoiceFileIds = downstreamDetail.getDownstreamInvoiceFileIds();
                if (CollectionUtil.isNotEmpty(downstreamInvoiceFileIds)) {
                    sysAttachmentRefService.saveRef(downstreamInvoiceFileIds, downstreamInvoice);
                }
            });
        }

        AttachmentDto attachmentDto = AttachmentDto.builder().setEntityId(customerExpenditureInfo.getId()).setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_ATTACHMENT_FILE).build();
        sysAttachmentRefService.removeRef(attachmentDto);
        if (CollectionUtil.isNotEmpty(detailVo.getAttachmentFileIds())) {
            sysAttachmentRefService.saveRef(detailVo.getAttachmentFileIds(), attachmentDto);
        }

        AttachmentDto otherDto = AttachmentDto.builder().setEntityId(customerExpenditureInfo.getId()).setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_OTHER_FILE).build();
        sysAttachmentRefService.removeRef(otherDto);
        if (CollectionUtil.isNotEmpty(detailVo.getOtherFileIds())) {
            sysAttachmentRefService.saveRef(detailVo.getOtherFileIds(), otherDto);
        }
        //提交开启流程
        if (detailVo.getSubmit() == 1) {
            FinancialRelationCustomerDisburse customerDisburse = financialRelationCustomerDisburseService.getById(customerExpenditureInfo
                    .getFinancialRelationCustomerDisburseId());
            FinancialCustomerInfo financialCustomerInfo = financialCustomerInfoService.getOne(new QueryWrapper<FinancialCustomerInfo>()
                    .eq("financial_relation_customer_id", customerDisburse.getFinancialRelationCustomerId()));
            if (financialCustomerInfo != null) {
                //填充状态
                financialCustomerInfo.setStatusDictionary(dictService.get(financialCustomerInfo.getCustomerStatus()));
            }
            if (financialCustomerInfo == null || financialCustomerInfo.getStatusDictionary().getCode().equals(FinancialCustomerStatusDict.ChildEnum.FINANCIAL_CUSTOMER_PASS.getCode())) {
                //保存历史数据
                FinancialCustomerExpenditureHisInfo customerExpenditureHisInfo = addFinancialCustomerExpenditureHis(customerExpenditureInfo, detailVo);
                //流程处理
                completeProcess(detailVo.getTaskId(), customerExpenditureInfo, customerExpenditureHisInfo);
            } else {
                throw new ValidatorException(CodeUtil.FAIL, "支用对应的客户信息未通过审批！");
            }

        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doApproval(FinancialCustomerExpenditureApprovalInfo approvalInfo) {
        if (approvalInfo.getApprovalConclusion() == null) {
            throw new ValidatorException(CodeUtil.FAIL, "审核结论不能为空！");
        }
        if (approvalInfo.getFinancialCustomerExpenditureInfoId() == null) {
            throw new ValidatorException(CodeUtil.FAIL, "对应的客户支用信息ID不能为空！");
        }
        //保存审核信息
        approvalInfo.setAssigneeId(ThreadLocalUtil.getUserId());
        expenditureApprovalInfoService.save(approvalInfo);

        //退回时流程处理人
        String candidate = assigneeService.getCandidateByBusiness(approvalInfo.getFinancialCustomerExpenditureInfoId(),
                ConstantUtil.FINANCIAL_CUSTOMER_EXPENDITURE_PROCESS, ConstantUtil.ASSIGNEE_REFINANCIAL_OPERATOR);
        String[] split = candidate.split(",");
        List<Long> users = new ArrayList<>();
        for (String s : split) {
            users.add(Long.valueOf(s));
        }

        FinancialCustomerExpenditureInfo customerExpenditureInfo = mapper.getDetail(approvalInfo.getFinancialCustomerExpenditureInfoId());
        if (customerExpenditureInfo == null) {
            throw new ValidatorException(CodeUtil.FAIL, "根据Id获取不到对应的客户支用信息！");
        }
        //流程处理
        Map<String, Object> msgVariables = new HashMap<>(2);

        msgVariables.put(ConstantUtil.FLOWABLE_MSG_TITLE, customerExpenditureInfo.getCustomerName() + "--" + customerExpenditureInfo.getBusinessNumber() + "--" + customerExpenditureInfo.getContractNo());

        if (approvalInfo.getApprovalConclusion().equals(ConstantConversionUtil.APPROVAL_RESULT_PASS)) {
            msgVariables.put(ConstantUtil.FLOWABLE_MSG_CONTENT,
                    "客户名称为“" + customerExpenditureInfo.getCustomerName() + "--业务编号为" + customerExpenditureInfo.getBusinessNumber()
                            + "--合同编号为" + customerExpenditureInfo.getContractNo()
                            + "--批次号为" + customerExpenditureInfo.getQuotaDisburseBatch() + "”的项目已进入“"
                            + ConstantConversionUtil.flowBusinessKeyNames.get(ConstantUtil.FINANCIAL_CUSTOMER_EXPENDITURE_PROCESS) + "—formBusiness”阶段，"
                            + ConstantUtil.FLOWABLE_MSG_ASSIGNEE);
        } else if (approvalInfo.getApprovalConclusion().equals(ConstantConversionUtil.APPROVAL_RESULT_BACK)) {
            msgVariables.put(ConstantUtil.FLOWABLE_MSG_CONTENT,
                    "客户名称为“" + customerExpenditureInfo.getCustomerName() + "--业务编号为" + customerExpenditureInfo.getBusinessNumber()
                            + "--合同编号为" + customerExpenditureInfo.getContractNo()
                            + "--批次号为" + customerExpenditureInfo.getQuotaDisburseBatch() + "”的项目支用信息已审核完成“");
        }
        Boolean result = flowableService.completeMyTask(approvalInfo.getTaskId(), customerExpenditureInfo, null,
                ConstantConversionUtil.processApprovalResult.get(approvalInfo.getApprovalConclusion()), approvalInfo.getId(), msgVariables, ConstantUtil.FINANCIAL_CUSTOMER_EXPENDITURE_PROCESS, users);
        if (result == null || !result) {
            throw new ValidatorException(CodeUtil.FAIL, "支用信息审核时出错啦！");
        }
        //修改状态
        Dictionary dict = null;
        if (approvalInfo.getApprovalConclusion().equals(ConstantConversionUtil.APPROVAL_RESULT_PASS)) {
            dict = dictService.getByCode(FinancialCustomerStatusDict.ChildEnum.FINANCIAL_CUSTOMER_PASS.getCode());
        } else if (approvalInfo.getApprovalConclusion().equals(ConstantConversionUtil.APPROVAL_RESULT_VETO)) {
            //如果审核结论为拒绝、修改状态为拒绝
            dict = dictService.getByCode(FinancialCustomerStatusDict.ChildEnum.FINANCIAL_CUSTOMER_REFUSE.getCode());
        } else if (approvalInfo.getApprovalConclusion().equals(ConstantConversionUtil.APPROVAL_RESULT_BACK)) {
            //如果审核结论为退回、修改状态为待编辑
            dict = dictService.getByCode(FinancialCustomerStatusDict.ChildEnum.FINANCIAL_CUSTOMER_TO_BE_EDIT.getCode());
        }
        customerExpenditureInfo.setDisburseStatus(dict.getId());
        expenditureInfoService.updateById(customerExpenditureInfo);
    }

    @Override
    public List<BusinessProcessingTaskVo> findAllList(SearchBusinessProcessingTask search) {
        List<BusinessProcessingTaskVo> taskVos = mapper.findAllList(search);
        taskVos.stream().forEach(t -> {
            //调用sop查询业务放款信息
            LoanInfoSearch loanInfoSearch = new LoanInfoSearch(t);
            LoanInfoVo loanInfoVo = getLoanInfoVo(loanInfoSearch);
            if (loanInfoVo != null) {
                List<LoanRecordVo> loanRecordList = loanInfoVo.getLoanRecordList();
                if (CollectionUtil.isNotEmpty(loanRecordList)) {
                    List<Date> loanDateList = loanRecordList.stream().map(LoanRecordVo::getLoanDate).distinct().collect(Collectors.toList());
                    //放款日
                    t.setLoanDateList(loanDateList);
                    //币种
                    t.setCurrencyCode(loanRecordList.get(0).getCurrencyCode());
                    BigDecimal loanAmountTotal = loanRecordList.stream().map(LoanRecordVo::getLoanAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                    //放款金额
                    t.setLoanAmountTotal(NumberFormatUtil.convertDecimal(loanAmountTotal, NumberFormatUtil.THOUSAND_SEPARATOR_TWO_DECIMAL));
                }
            }
            //填充状态
            t.setStatus(dictService.get(t.getStatus().getId()));
            //判断上传合同清单按钮是否显示
            t.setButtonFlag(autoButtonFlag(t.getId(), t.getStatus()));
        });
        return taskVos;
    }

    @Override
    public void downloadAllFile(HttpServletResponse response, Long id) {
        //查询所有文件
        FinancialCustomerExpenditureInfo financialCustomerExpenditureInfo = mapper.getDetail(id);

        List<FileStorage> fileStorageList = new ArrayList<>();
        if (financialCustomerExpenditureInfo != null) {
            List<FinancialCustomerExpenditureContractInfo> expenditureContractInfoList = expenditureContractInfoService.list(new QueryWrapper<FinancialCustomerExpenditureContractInfo>()
                    .eq("financial_customer_expenditure_info_id", financialCustomerExpenditureInfo.getId()));
            if (CollectionUtil.isNotEmpty(expenditureContractInfoList)) {
                for (FinancialCustomerExpenditureContractInfo contractInfo : expenditureContractInfoList) {

                    //上游采购合同
                    List<FileStorage> upstreamPurchFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(contractInfo.getId())
                            .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_UPSTREAM_PURCH_FILE).build());
                    fileStorageList.addAll(upstreamPurchFileList);
                    //上游结算单
                    List<FileStorage> upstreamSettleFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(contractInfo.getId())
                            .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_UPSTREAM_SETTLEMENT_FILE).build());
                    fileStorageList.addAll(upstreamSettleFileList);
                    //上游发票
                    List<FileStorage> upstreamInvoiceFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(contractInfo.getId())
                            .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_UPSTREAM_INVOICE_FILE).build());
                    fileStorageList.addAll(upstreamInvoiceFileList);

                    //下游采购合同
                    List<FileStorage> salesFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(contractInfo.getId())
                            .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_DOWNSTREAM_SALES_FILE).build());
                    fileStorageList.addAll(salesFileList);
                    //下游结算单
                    List<FileStorage> downstreamSettleFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(contractInfo.getId())
                            .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_DOWNSTREAM_SETTLEMENT_FILE).build());
                    fileStorageList.addAll(downstreamSettleFileList);
                    //下游发票
                    List<FileStorage> downstreamInvoiceFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(contractInfo.getId())
                            .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_DOWNSTREAM_INVOICE_FILE).build());
                    fileStorageList.addAll(downstreamInvoiceFileList);
                }
            }

            //附件
            List<FileStorage> attachmentFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(financialCustomerExpenditureInfo.getId())
                    .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_ATTACHMENT_FILE).build());
            fileStorageList.addAll(attachmentFileList);
            //其它
            List<FileStorage> otherFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(financialCustomerExpenditureInfo.getId())
                    .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_OTHER_FILE).build());
            fileStorageList.addAll(otherFileList);
            //合同清单附件
            List<FileStorage> checklistFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(financialCustomerExpenditureInfo.getId())
                    .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_CONTRACT_CHECKLIST_FILE).build());
            fileStorageList.addAll(checklistFileList);
        }
        if (CollectionUtil.isNotEmpty(fileStorageList)) {
            String fileName = financialCustomerExpenditureInfo.getCustomerName() + "-" + financialCustomerExpenditureInfo.getContractNo()
                    + "-" + financialCustomerExpenditureInfo.getQuotaDisburseBatch();
            fileStorageService.renameFileStorageList(fileStorageList);
            //文件打包下载
            fileStorageService.downloadZipFile(fileStorageList, fileName, FileModuleDict.ChildEnum.FINANCIAL_ZIP_FILE, response);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void uploadContractList(FinancialCustomerExpenditureDetailVo detailVo) {

        if (detailVo.getId() == null) {
            throw new ValidatorException(CodeUtil.FAIL, "客户支用信息Id不能为空!");
        }

        List<Long> contractChecklistFileIds = detailVo.getContractChecklistFileIds();
        if (CollectionUtil.isNotEmpty(contractChecklistFileIds)) {
            AttachmentDto contractChecklistDto = AttachmentDto.builder().setEntityId(detailVo.getId()).setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_CONTRACT_CHECKLIST_FILE).build();
            sysAttachmentRefService.saveRef(contractChecklistFileIds, contractChecklistDto);
        }
        //添加流程处理日志
        BusinessProcessingLog processingLog = new BusinessProcessingLog();
        processingLog.setBusnessKey(detailVo.getId());
        processingLog.setBusinessType(ConstantUtil.FINANCIAL_CUSTOMER_EXPENDITURE_PROCESS);
        processingLog.setHistoricTaskId("888888");
        processingLog.setTaskName("合同清单上传");
        processingLog.setTaskDefKey("financial_customer_expenditure_contract_checklist_upload");
        processingLog.setFormBusinessId(detailVo.getId());
        processingLog.setAssignee(ThreadLocalUtil.getUser());
        processingLog.setStartTime(new Date());
        processingLog.setEndTime(new Date());
        processingLog.setStatus("通过");
        processingLog.setWorkingDay(false);
        processingLogService.add(processingLog);
    }

    /**
     * 判断上传合同清单按钮是否显示
     *
     * @param customerExpenditureInfoId
     * @param statusDict
     */
    private Boolean autoButtonFlag(Long customerExpenditureInfoId, Dictionary statusDict) {
        Boolean flag = false;
        //判断是否有上传合同清单流程
        List<BusinessProcessingLog> processingLogs = processingLogService.findCompletedByBusiness(customerExpenditureInfoId, ConstantUtil.FINANCIAL_CUSTOMER_EXPENDITURE_PROCESS);

        List<String> taskNameList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(processingLogs)) {
            taskNameList = processingLogs.stream().filter(p -> p.getTaskName() != null).map(BusinessProcessingLog::getTaskName).collect(Collectors.toList());
        }
        List<UserRoleRel> userRoleRels = roleService.getUserRoleByUserId(ThreadLocalUtil.getUserId());

        Boolean rolePermission = flag;
        if (CollectionUtil.isNotEmpty(userRoleRels)) {
            for (UserRoleRel userRoleRel : userRoleRels) {
                Role role = roleService.get(userRoleRel.getRoleId());
                if (ConstantUtil.REFINANCING_OPERATION_OWNER.equals(role.getName()) || ConstantUtil.FINANCIAL_MANAGER.equals(role.getName())) {
                    rolePermission = true;
                }
            }
        }

        if (statusDict != null && FinancialCustomerStatusDict.ChildEnum.FINANCIAL_CUSTOMER_PASS.getCode().equals(statusDict.getCode())
                && !taskNameList.contains("合同清单上传") && rolePermission) {
            flag = true;
        }
        return flag;
    }

    /**
     * 完成当前task,流转到审批节点
     *
     * @param taskId
     * @param customerExpenditureInfo
     */
    private void completeProcess(String taskId, FinancialCustomerExpenditureInfo customerExpenditureInfo, FinancialCustomerExpenditureHisInfo customerExpenditureHisInfo) {
        //变更状态
        customerExpenditureInfo.setDisburseStatus(dictService.getByCode(FinancialCustomerStatusDict.ChildEnum.FINANCIAL_CUSTOMER_UNDER_APPROVAL.getCode()).getId());
        expenditureInfoService.updateById(customerExpenditureInfo);

        customerExpenditureInfo = mapper.getDetail(customerExpenditureInfo.getId());
        //完成流程第一步支用资料附件上传，开启资方审核
        Map<String, Object> procVariables = new HashMap<>(1);
        procVariables.put(ConstantUtil.FINANCIAL_CUSTOMER_EXPENDITURE_APPROVAL,
                assigneeService.getIdByBusiness(customerExpenditureInfo.getId(), ConstantUtil.FINANCIAL_CUSTOMER_EXPENDITURE_PROCESS, ConstantUtil.ASSIGNEE_FINANCIAL_BACKER));
        Map<String, Object> msgVariables = new HashMap<>(2);
        msgVariables.put(ConstantUtil.FLOWABLE_MSG_TITLE, customerExpenditureInfo.getCustomerName() + "--" + customerExpenditureInfo.getBusinessNumber() + "--" + customerExpenditureInfo.getContractNo());
        msgVariables.put(ConstantUtil.FLOWABLE_MSG_CONTENT,
                "客户名称为“" + customerExpenditureInfo.getCustomerName() + "--业务编号为" + customerExpenditureInfo.getBusinessNumber()
                        + "--合同编号为" + customerExpenditureInfo.getContractNo()
                        + "--批次号为" + customerExpenditureInfo.getQuotaDisburseBatch() + "”的项目已进入“"
                        + ConstantConversionUtil.flowBusinessKeyNames.get(ConstantUtil.FINANCIAL_CUSTOMER_EXPENDITURE_PROCESS) + "—formBusiness”阶段，"
                        + ConstantUtil.FLOWABLE_MSG_ASSIGNEE);

        Boolean result = flowableService.completeMyTask(taskId, customerExpenditureInfo, procVariables,
                ConstantConversionUtil.processApprovalResult.get("pass"), customerExpenditureHisInfo.getId(), msgVariables, ConstantUtil.FINANCIAL_CUSTOMER_EXPENDITURE_PROCESS);
        if (result == null || !result) {
            throw new ValidatorException(CodeUtil.FAIL, "基础资料提交时出错啦！");
        }
    }

    /**
     * 保存支用历史数据
     *
     * @param customerExpenditureInfo
     */
    private FinancialCustomerExpenditureHisInfo addFinancialCustomerExpenditureHis(FinancialCustomerExpenditureInfo customerExpenditureInfo,
                                                                                   FinancialCustomerExpenditureDetailVo detailVo) {
        if (customerExpenditureInfo != null) {
            //保存历史信息
            FinancialCustomerExpenditureHisInfo expenditureHisInfo = new FinancialCustomerExpenditureHisInfo();
            expenditureHisInfo.setFinancialCustomerExpenditureInfoId(customerExpenditureInfo.getId());
            expenditureHisInfo.setCustomerName(detailVo.getCustomerName());
            if (detailVo.getLoanAmountTotal() != null) {
                expenditureHisInfo.setLoanAmountTotal(new BigDecimal(detailVo.getLoanAmountTotal()));
            }
            if (detailVo.getExpireDate() != null) {
                expenditureHisInfo.setExpireDate(DateUtil.format(detailVo.getExpireDate(), "yyyy-MM-dd"));
            }

            List<Date> loanDateList = detailVo.getLoanDateList();
            if (CollectionUtil.isNotEmpty(loanDateList)) {
                List<String> strDateList = loanDateList.stream().map(date -> DateUtil.format(detailVo.getExpireDate(), "yyyy-MM-dd")).collect(Collectors.toList());
                expenditureHisInfo.setLoanDate(StringUtils.join(strDateList, ","));
            }
            expenditureHisInfoService.save(expenditureHisInfo);

            //保存历史合同信息
            List<FinancialCustomerExpenditureContractInfo> expenditureContractInfoList = expenditureContractInfoService.list(new QueryWrapper<FinancialCustomerExpenditureContractInfo>()
                    .eq("financial_customer_expenditure_info_id", customerExpenditureInfo.getId()));
            if (CollectionUtil.isNotEmpty(expenditureContractInfoList)) {
                for (FinancialCustomerExpenditureContractInfo contractInfo : expenditureContractInfoList) {
                    FinancialCustomerExpenditureContractHisInfo contractHisInfo = new FinancialCustomerExpenditureContractHisInfo(contractInfo);
                    contractHisInfo.setFinancialCustomerExpenditureHisInfoId(expenditureHisInfo.getId());
                    expenditureContractHisInfoService.save(contractHisInfo);

                    //上游采购合同
                    List<FileStorage> upstreamPurchFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(contractInfo.getId())
                            .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_UPSTREAM_PURCH_FILE).build());
                    sysAttachmentRefService.saveFileAndRefHis(upstreamPurchFileList, AttachmentDto.builder().setEntityId(contractHisInfo.getId())
                            .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_UPSTREAM_PURCH_HIS_FILE).build());
                    //上游结算单
                    List<FileStorage> upstreamSettleFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(contractInfo.getId())
                            .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_UPSTREAM_SETTLEMENT_FILE).build());
                    sysAttachmentRefService.saveFileAndRefHis(upstreamSettleFileList, AttachmentDto.builder().setEntityId(contractHisInfo.getId())
                            .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_UPSTREAM_SETTLEMENT_HIS_FILE).build());
                    //上游发票
                    List<FileStorage> upstreamInvoiceFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(contractInfo.getId())
                            .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_UPSTREAM_INVOICE_FILE).build());
                    sysAttachmentRefService.saveFileAndRefHis(upstreamInvoiceFileList, AttachmentDto.builder().setEntityId(contractHisInfo.getId())
                            .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_UPSTREAM_INVOICE_HIS_FILE).build());

                    //下游采购合同
                    List<FileStorage> salesFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(contractInfo.getId())
                            .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_DOWNSTREAM_SALES_FILE).build());
                    sysAttachmentRefService.saveFileAndRefHis(salesFileList, AttachmentDto.builder().setEntityId(contractHisInfo.getId())
                            .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_DOWNSTREAM_SALES_HIS_FILE).build());
                    //下游结算单
                    List<FileStorage> downstreamSettleFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(contractInfo.getId())
                            .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_DOWNSTREAM_SETTLEMENT_FILE).build());
                    sysAttachmentRefService.saveFileAndRefHis(downstreamSettleFileList, AttachmentDto.builder().setEntityId(contractHisInfo.getId())
                            .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_DOWNSTREAM_SETTLEMENT_HIS_FILE).build());
                    //下游发票
                    List<FileStorage> downstreamInvoiceFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(contractInfo.getId())
                            .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_DOWNSTREAM_INVOICE_FILE).build());
                    sysAttachmentRefService.saveFileAndRefHis(downstreamInvoiceFileList, AttachmentDto.builder().setEntityId(contractHisInfo.getId())
                            .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_DOWNSTREAM_INVOICE_HIS_FILE).build());
                }
            }
            //附件
            List<FileStorage> attachmentFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(customerExpenditureInfo.getId())
                    .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_ATTACHMENT_FILE).build());
            sysAttachmentRefService.saveFileAndRefHis(attachmentFileList, AttachmentDto.builder().setEntityId(expenditureHisInfo.getId())
                    .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_ATTACHMENT_HIS_FILE).build());
            //其它
            List<FileStorage> otherFileList = sysAttachmentRefService.getFiles(AttachmentDto.builder().setEntityId(customerExpenditureInfo.getId())
                    .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_OTHER_FILE).build());
            sysAttachmentRefService.saveFileAndRefHis(otherFileList, AttachmentDto.builder().setEntityId(expenditureHisInfo.getId())
                    .setChildEnum(FileModuleDict.ChildEnum.FINANCIAL_EXPENDITURE_OTHER_HIS_FILE).build());
            return expenditureHisInfo;
        }
        return null;
    }
}
