package com.ruoyi.hywz.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.uuid.UUID;
import com.ruoyi.hywz.common.enums.ApplyTypeEnum;
import com.ruoyi.hywz.common.enums.InvoiceNodeEnum;
import com.ruoyi.hywz.common.enums.MsgTemplateEnum;
import com.ruoyi.hywz.entity.*;
import com.ruoyi.hywz.entity.po.*;
import com.ruoyi.hywz.entity.vo.InvoiceAuditDetailVo;
import com.ruoyi.hywz.listener.ImportExcelHelper;
import com.ruoyi.hywz.service.*;
import com.ruoyi.hywz.utils.IdGen;
import com.ruoyi.hywz.utils.PDFUtil;
import com.ruoyi.system.service.ISysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;

/**
 * @author: jxh
 * @description:
 * @create: 2024/4/8
 */
@RestController
@RequestMapping("adsMatHyxtInvoiceD")
@AllArgsConstructor
@Api(value = "adsMatHyxtInvoiceD", tags = "开票申请流程管控")
public class AdsMatHyxtInvoiceDController {

    private final IAdsMatHyxtInvoiceApplyDService adsMatHyxtInvoiceApplyDService;
    private final IAdsMatHyxtTaskHistoryDService adsMatHyxtTaskHistoryDService;
    private final IAdsMatHyxtTaskRunDService adsMatHyxtTaskRunDService;
    private final IAdsMatHyxtInvoiceDService adsMatHyxtInvoiceDService;
    private final IAdsMatHyxtInvoiceFileDService adsMatHyxtInvoiceFileDService;
    private final ISysUserService sysUserService;
    private final IAdsMatHyxtIAppService adsMatHyxtIAppService;
    private final IAdsMatHyxtTaskSendMsgDService adsMatHyxtTaskSendMsgDService;
    private final IAdsMatHyxtInvoiceUserApplyPermissionDService adsMatHyxtInvoiceUserApplyPermissionDService;
    private final IAdsPrjHywzqlcPrjFunInfoDfService adsPrjHywzqlcPrjFunInfoDfService;
    private final IAdsMatHyxtOcrService adsMatHyxtOcrService;

    @ApiOperation(value = "【申请单】分页查询", notes = "【申请单】分页查询")
    @PostMapping("/applyPage")
    public R<Page<AdsMatHyxtInvoiceApplyD>> applyPage(@RequestParam(defaultValue = "10") Long pageSize,
                                                      @RequestParam(defaultValue = "1") Long pageNo,
                                                      @RequestBody(required = false) InvoiceApplyQueryPO param) {
        Page<AdsMatHyxtInvoiceApplyD> page = new Page<>();
        page.setSize(pageSize);
        page.setCurrent(pageNo);

        LambdaQueryWrapper<AdsMatHyxtInvoiceApplyD> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(AdsMatHyxtInvoiceApplyD::getIsDeleted, 0);
        if (null != param) {
            queryWrapper.like(StringUtils.isNotBlank(param.getAppNo()), AdsMatHyxtInvoiceApplyD::getAppNo, param.getAppNo());
            queryWrapper.like(StringUtils.isNotBlank(param.getCreateUserOrgNo()), AdsMatHyxtInvoiceApplyD::getCreateUserOrgNo, param.getCreateUserOrgNo());
            queryWrapper.eq(ObjectUtils.isNotEmpty(param.getCurrentNode()), AdsMatHyxtInvoiceApplyD::getCurrentNode, param.getCurrentNode());
            if (ObjectUtils.isNotEmpty(param.getStatus())) {
                if (param.getStatus() == 5) {
                    queryWrapper.notIn(AdsMatHyxtInvoiceApplyD::getStatus, 4);
                } else {
                    queryWrapper.eq(ObjectUtils.isNotEmpty(param.getStatus()), AdsMatHyxtInvoiceApplyD::getStatus, param.getStatus());
                }
            }
        }

        queryWrapper.orderByDesc(AdsMatHyxtInvoiceApplyD::getStatus);
        queryWrapper.orderByDesc(AdsMatHyxtInvoiceApplyD::getCreateTime);
        Page<AdsMatHyxtInvoiceApplyD> pageResult = adsMatHyxtInvoiceApplyDService.page(page, queryWrapper);
        LoginUser loginUser = SecurityUtils.getLoginUser();
        Integer permission = adsMatHyxtInvoiceUserApplyPermissionDService.checkHaveCommitPermission(loginUser.getUserId());
        for (AdsMatHyxtInvoiceApplyD record : pageResult.getRecords()) {
            record.setHaveCommitPermission(permission);
        }
        return R.ok(pageResult);
    }

    @ApiOperation(value = "【申请单】保存", notes = "【申请单】保存")
    @PostMapping("/applySave")
    public R applySave(@RequestBody InvoiceApplyPO param) {
        List<AdsMatHyxtInvoiceD> list = param.getList();
        if (list.isEmpty()) {
            return R.fail("请填写开票信息！");
        }
        int index = 0;
        for (AdsMatHyxtInvoiceD invoiceD : list) {
            index++;
//            if (StringUtils.isEmpty(invoiceD.getApplyDate())) {
//                R.fail("申请日期不能为空，");
//            }
            if (StringUtils.isEmpty(invoiceD.getApplyType())) {
                return R.fail("第" + index + "行, 必填项【申请单分类】不能为空，");
            }
            String applyType = invoiceD.getApplyType();
            if (!applyType.equals(ApplyTypeEnum.XM.getType()) && !applyType.equals(ApplyTypeEnum.FXM.getType())) {
                return R.fail("申请单分类只支持填写项目类与非项目类！请检查第" + index + "行数据！");
            }

            if (StringUtils.isEmpty(invoiceD.getSeller())) {
                return R.fail("第" + index + "行, 必填项【销售方】不能为空，");
            }
            if (StringUtils.isEmpty(invoiceD.getBuyer())) {
                return R.fail("第" + index + "行, 必填项【购买方】不能为空，");
            }
            if (applyType.equals(ApplyTypeEnum.XM.getType())) {
                if (StringUtils.isEmpty(invoiceD.getProjectNo())) {
                    return R.fail("【项目类】第" + index + "行, 必填项【主业WBS编码】不能为空，");
                }
                if (StringUtils.isEmpty(invoiceD.getProjectName())) {
                    return R.fail("【项目类】第" + index + "行, 必填项【主业项目名称】不能为空，");
                }
//                if (StringUtils.isEmpty(invoiceD.getYnProjectNo())) {
//                    return R.fail("【项目类】第" + index + "行, 必填项【产业项目编码】不能为空，");
//                }
//                if (StringUtils.isEmpty(invoiceD.getYnProjectName())) {
//                    return R.fail("【项目类】第" + index + "行, 必填项【产业项目名称】不能为空，");
//                }
            }
            if (StringUtils.isEmpty(invoiceD.getContractAmount())) {
                return R.fail("第" + index + "行, 必填项【合同金额】不能为空，");
            }
//            if (StringUtils.isEmpty(invoiceD.getValidBudgetAmount())) {
//                return R.fail("第" + index + "行, 必填项【可用预算】不能为空，");
//            }
            if (StringUtils.isEmpty(invoiceD.getCostType())) {
                return R.fail("第" + index + "行, 必填项【费用类型】不能为空，");
            }
            if (StringUtils.isEmpty(invoiceD.getTaxAmount())) {
                return R.fail("第" + index + "行, 必填项【本次开票金额（含税）】不能为空，");
            }
            if (StringUtils.isEmpty(invoiceD.getTaxRate())) {
                return R.fail("第" + index + "行, 必填项【税率】不能为空，");
            }
            if (StringUtils.isEmpty(invoiceD.getTaker())) {
                return R.fail("第" + index + "行, 必填项【收票人（业务人员）】不能为空，");
            }
            if (StringUtils.isEmpty(invoiceD.getTakerUnit())) {
                return R.fail("第" + index + "行, 必填项【收票单位（部门）】不能为空，");
            }
            if (StringUtils.isEmpty(invoiceD.getTelephone())) {
                return R.fail("第" + index + "行, 必填项【联系电话】不能为空，");
            }
        }

        // 预算稽核
//        int idx = 0;
//        for (AdsMatHyxtInvoiceD invoiceD : param.getList()) {
//            LocalDate now = LocalDate.now();
//            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
//            invoiceD.setApplyDate(now.format(formatter));
//            idx++;
//            // 项目类：可用预算（年度投资预算-累计已入账金额）-本次入账成本（本次开票金额含税/(1+税率））>0
//            if (invoiceD.getApplyType().equals(ApplyTypeEnum.XM.getType())) {
//                AdsPrjHywzqlcPrjFunInfoDf infoDf = adsPrjHywzqlcPrjFunInfoDfService.getByWbsNo(invoiceD.getProjectNo());
//                if (null != infoDf) {
//                    // 金额换算成元进行校验
//                    BigDecimal investPlanAmt = new BigDecimal(infoDf.getInvestPlanAmt()).multiply(new BigDecimal(10000));   // 年度投资预算
//                    BigDecimal engineCost = new BigDecimal(infoDf.getEngineCost()).multiply(new BigDecimal(10000)); // 累计已入账金额
//                    BigDecimal taxAmount = new BigDecimal(invoiceD.getTaxAmount()); // 本次开票金额含税
//                    BigDecimal taxRate = new BigDecimal(invoiceD.getTaxRate().replace(" ", "").replace("%", "")); // 税率
//
//                    // 入账成本
//                    BigDecimal cost = taxAmount.divide(BigDecimal.ONE.add(taxRate.divide(new BigDecimal(100))), 2, RoundingMode.HALF_UP);
//
//                    BigDecimal subtract = investPlanAmt.subtract(engineCost).subtract(cost);
//                    if (subtract.compareTo(BigDecimal.ZERO) < 0) {
//                        return R.fail("第" + idx + "行数据，本次入账成本大于可用预算，不能保存！");
//                    }
//                }
//
//            }
//
//            // 非项目类： 可用预算 - 本次入账成本（本次开票金额含税/(1+税率））>0
//            if (invoiceD.getApplyType().equals(ApplyTypeEnum.FXM.getType())) {
//                BigDecimal validBudgetAmount = new BigDecimal(invoiceD.getValidBudgetAmount()); // 可用预算
//                BigDecimal taxAmount = new BigDecimal(invoiceD.getTaxAmount()); // 本次开票金额含税
//                BigDecimal taxRate = new BigDecimal(invoiceD.getTaxRate().replace(" ", "").replace("%", "")); // 税率
//
//                // 入账成本
//                BigDecimal cost = taxAmount.divide(BigDecimal.ONE.add(taxRate.divide(new BigDecimal(100))), 2, RoundingMode.HALF_UP);
//
//                BigDecimal subtract = validBudgetAmount.subtract(cost);
//                if (subtract.compareTo(BigDecimal.ZERO) < 0) {
//                    return R.fail("第" + idx + "行数据，本次入账成本大于可用预算，不能保存！");
//                }
//            }
//        }

        adsMatHyxtInvoiceApplyDService.applySave(param);
        return R.ok();
    }

    @ApiOperation(value = "【申请单】更新", notes = "【申请单】更新")
    @PostMapping("/applyUpdate")
    @Transactional(rollbackFor = Exception.class)
    public R applyUpdate(@RequestBody AdsMatHyxtInvoiceApplyD param) {
        if (StringUtils.isBlank(param.getId())) {
            return R.fail("参数id不能为空");
        }
        AdsMatHyxtInvoiceApplyD applyD = adsMatHyxtInvoiceApplyDService.getById(param.getId());
        if (null == applyD) {
            return R.fail("申请单不存在！");
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        int updateNum = 0;
        Date date = new Date();
        LambdaUpdateWrapper<AdsMatHyxtInvoiceApplyD> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(AdsMatHyxtInvoiceApplyD::getId, param.getId());
        // 是否接收发票
        if (ObjectUtils.isNotEmpty(param.getIsReceiptInvoice())) {
            updateWrapper.set(AdsMatHyxtInvoiceApplyD::getIsReceiptInvoice, param.getIsReceiptInvoice());
            updateNum++;
            AdsMatHyxtTaskRunD fpjs = new AdsMatHyxtTaskRunD();
            fpjs.setNodeLabel("接收发票");
            fpjs.setBusinessId(applyD.getId());
            fpjs.setOwnerUserId(loginUser.getUserId());
            fpjs.setOwnerUser(loginUser.getUsername());
            fpjs.setOwnerUserName(loginUser.getUser().getNickName());
            fpjs.setOwnerUserPhone(loginUser.getUser().getPhonenumber());
            fpjs.setCreateTime(new Date());
            adsMatHyxtTaskHistoryDService.auditOkSave(fpjs);
        }
        // 是否接收报账
        if (ObjectUtils.isNotEmpty(param.getIsReceiptBz())) {
            updateWrapper.set(AdsMatHyxtInvoiceApplyD::getIsReceiptBz, param.getIsReceiptBz());
            updateNum++;
            AdsMatHyxtTaskRunD jsbz = new AdsMatHyxtTaskRunD();
            jsbz.setNodeLabel("接收报账");
            jsbz.setBusinessId(applyD.getId());
            jsbz.setOwnerUserId(loginUser.getUserId());
            jsbz.setOwnerUser(loginUser.getUsername());
            jsbz.setOwnerUserName(loginUser.getUser().getNickName());
            jsbz.setOwnerUserPhone(loginUser.getUser().getPhonenumber());
            jsbz.setCreateTime(new Date());
            adsMatHyxtTaskHistoryDService.auditOkSave(jsbz);
        }
        if (updateNum > 0) {
            updateWrapper.set(AdsMatHyxtInvoiceApplyD::getUpdateTime, date);
            adsMatHyxtInvoiceApplyDService.update(updateWrapper);
        }
        return R.ok();
    }

    @PostMapping("/downloadTemplate")
    @ApiOperation(value = "【申请单】下载模板")
    public void downloadTemplate(HttpServletResponse response) {
        String filePath = "excelTemplate/invoiceImport.xlsx";
        byte[] buffer = new byte[1024];
        InputStream fis = Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath);
        BufferedInputStream bis = null;
        try {
            response.setHeader("Content-Disposition", "attachment;filename*=UTF-8''" + URLEncoder.encode(UUID.fastUUID().toString(), "UTF-8"));
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
            response.setCharacterEncoding("UTF-8");
            bis = new BufferedInputStream(fis);
            OutputStream os = response.getOutputStream();
            int i = bis.read(buffer);
            while (i != -1) {
                os.write(buffer, 0, i);
                i = bis.read(buffer);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                bis.close();
                fis.close();
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        }
    }

    @PostMapping("/invoiceImport")
    @ApiOperation(value = "【申请单】开票导入", notes = "【申请单】开票导入")
    public R invoiceImport(@RequestParam("file") MultipartFile file) throws IOException {
        ImportExcelHelper<InvoiceImportPO> helper = new ImportExcelHelper<>();
        List<InvoiceImportPO> list = helper.getList(file.getInputStream(), InvoiceImportPO.class, 0, 1);
        if (list.size() == 0) {
            return R.fail("导入失败，未解析到正确数据!");
        } else {
            String rMsg = "";
            for (int i = 0; i < list.size(); i++) {
                StringBuffer sbf = new StringBuffer("第" + (1 + i) + "行");
                Boolean flag = true;
                InvoiceImportPO importPO = list.get(i);
                importPO.setNumberPar(1 + i);
                String applyType = importPO.getApplyType();
                if (StringUtils.isEmpty(applyType)) {
                    sbf.append("申请单分类不能为空，");
                    flag = false;
                    rMsg = sbf.substring(0, sbf.length() - 1);
                    break;
                }
                if (!applyType.equals(ApplyTypeEnum.XM.getType()) && !applyType.equals(ApplyTypeEnum.FXM.getType())) {
                    sbf.append("申请单分类只支持填写项目类与非项目类！");
                    flag = false;
                }
//                if (StringUtils.isEmpty(importPO.getApplyDate())) {
//                    sbf.append("申请日期不能为空，");
//                    flag = false;
//                }
                if (StringUtils.isEmpty(importPO.getSeller())) {
                    sbf.append("销售方不能为空，");
                    flag = false;
                }
                if (StringUtils.isEmpty(importPO.getBuyer())) {
                    sbf.append("购买方不能为空，");
                    flag = false;
                }
                if (applyType.equals("项目类")) {
                    if (StringUtils.isEmpty(importPO.getProjectNo())) {
                        sbf.append("主业WBS编码不能为空，");
                        flag = false;
                    }
                    if (StringUtils.isEmpty(importPO.getProjectName())) {
                        sbf.append("主业项目名称不能为空，");
                        flag = false;
                    }
//                    if (StringUtils.isEmpty(importPO.getYnProjectNo())) {
//                        sbf.append("产业项目编码不能为空，");
//                        flag = false;
//                    }
//                    if (StringUtils.isEmpty(importPO.getYnProjectName())) {
//                        sbf.append("产业项目名称不能为空，");
//                        flag = false;
//                    }
                }
                if (StringUtils.isEmpty(importPO.getContractAmount())) {
                    sbf.append("合同金额不能为空，");
                    flag = false;
                }
//                if (StringUtils.isEmpty(importPO.getValidBudgetAmount())) {
//                    sbf.append("可用预算不能为空，");
//                    flag = false;
//                }
                if (StringUtils.isEmpty(importPO.getCostType())) {
                    sbf.append("费用类型不能为空，");
                    flag = false;
                }
                if (StringUtils.isEmpty(importPO.getTaxAmount())) {
                    sbf.append("本次开票金额（含税）不能为空，");
                    flag = false;
                }
                if (StringUtils.isEmpty(importPO.getTaxRate())) {
                    sbf.append("税率不能为空，");
                    flag = false;
                }
                if (StringUtils.isEmpty(importPO.getTaker())) {
                    sbf.append("收票人（业务人员）不能为空，");
                    flag = false;
                }
                if (StringUtils.isEmpty(importPO.getTakerUnit())) {
                    sbf.append("收票单位（部门）不能为空，");
                    flag = false;
                }
                if (StringUtils.isEmpty(importPO.getTelephone())) {
                    sbf.append("联系电话不能为空，");
                    flag = false;
                }
                if (!flag) {
                    rMsg = sbf.substring(0, sbf.length() - 1);
                    break;
                }
            }
            if (StringUtils.isNotEmpty(rMsg)) {
                return R.fail(rMsg);
            }
        }
        return R.ok(list);
    }

    @ApiOperation(value = "【申请单】详情", notes = "【申请单】详情")
    @PostMapping("/applyDetail")
    public R applyDetail(@RequestBody InvoiceApplyDetailPO param) {
        AdsMatHyxtInvoiceApplyD applyD = adsMatHyxtInvoiceApplyDService.getById(param.getId());
        if (null == applyD) {
            return R.fail("申请单不存在！请刷新后再试！");
        }
        InvoiceAuditDetailVo result = new InvoiceAuditDetailVo();
        result.setCurrentNodeIndex(InvoiceNodeEnum.getIndex(applyD.getCurrentNode()));
        result.setCurrentNode(applyD.getCurrentNode());
        result.setNodeList(InvoiceNodeEnum.getNodeList());
        result.setAuditLog(adsMatHyxtTaskHistoryDService.getLogList(param.getId()));
        result.setInvoiceList(adsMatHyxtInvoiceDService.getListByApplyId(param.getId()));
        return R.ok(result);
    }

    @ApiOperation(value = "【申请单】提交审核", notes = "【申请单】提交审核")
    @PostMapping("/commitAudit")
    public R commitAudit(@RequestBody InvoiceApplyDetailPO param) {
//        if (StringUtils.isBlank(param.getId())) {
//            return R.fail("id不能为空");
//        }
        if (ObjectUtils.isEmpty(param.getIds()) || param.getIds().isEmpty()) {
            return R.fail("ids参数不能为空");
        }
        if (StringUtils.isBlank(param.getAuditUser1())) {
            return R.fail("财务审核人员不能为空！");
        }
        return adsMatHyxtInvoiceApplyDService.commitAudit(param);
    }

    @ApiOperation(value = "【申请单】撤回", notes = "【申请单】撤回")
    @PostMapping("/withdraw")
    public R withdraw(@RequestBody InvoiceApplyDetailPO param) {
        if (StringUtils.isBlank(param.getId())) {
            return R.fail("id不能为空");
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        AdsMatHyxtInvoiceApplyD applyD = adsMatHyxtInvoiceApplyDService.getById(param.getId());
        if (null == applyD) {
            return R.fail("单据不存在，请刷新页面后再试！");
        }
        if (!loginUser.getUsername().equals("admin")) {
            if (!loginUser.getUsername().equals(applyD.getCreateUser())) {
                return R.fail("申请编号【" + applyD.getAppNo() + "】不是您账号创建的，无权限撤回！");
            }
        }
        adsMatHyxtInvoiceApplyDService.withdraw(param);

        // 关闭定时任务
        adsMatHyxtTaskSendMsgDService.closeTask(param.getId());
        return R.ok();
    }

    @ApiOperation(value = "【申请单】删除", notes = "【申请单】删除")
    @PostMapping("/deleteApply")
    @Transactional(rollbackFor = Exception.class)
    public R deleteApply(@RequestBody InvoiceApplyDetailPO param) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (ObjectUtils.isEmpty(param.getIds()) || param.getIds().isEmpty()) {
            return R.fail("ids参数不能为空");
        }
        LambdaQueryWrapper<AdsMatHyxtInvoiceApplyD> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.in(AdsMatHyxtInvoiceApplyD::getId, param.getIds());
        List<AdsMatHyxtInvoiceApplyD> list = adsMatHyxtInvoiceApplyDService.list(queryWrapper);
        if (list.isEmpty()) {
            return R.fail("没有可删除的数据，请刷新页面后再试!");
        }

        for (AdsMatHyxtInvoiceApplyD applyD : list) {
            if (!loginUser.getUsername().equals("admin")) {
                if (!loginUser.getUsername().equals(applyD.getCreateUser())) {
                    return R.fail("申请编号【" + applyD.getAppNo() + "】不是您账号创建的，无权限删除！");
                }
            }
        }

        for (AdsMatHyxtInvoiceApplyD applyD : list) {
            adsMatHyxtInvoiceApplyDService.removeById(applyD.getId());
            adsMatHyxtInvoiceDService.logicDelete(applyD.getId());
            // 关闭定时任务
            adsMatHyxtTaskSendMsgDService.closeTask(applyD.getId());
        }

        return R.ok();
    }

    @ApiOperation(value = "【申请单】审核详情", notes = "【申请单】审核详情")
    @PostMapping("/applyAuditDetail")
    public R<InvoiceAuditDetailVo> applyAuditDetail(@RequestBody InvoiceApplyDetailPO param) {
        if (StringUtils.isBlank(param.getId())) {
            return R.fail("任务id不能为空！");
        }
        if (StringUtils.isBlank(param.getId())) {
            return R.fail("businessId不能为空！");
        }
        InvoiceAuditDetailVo result = new InvoiceAuditDetailVo();
        AdsMatHyxtTaskRunD one = adsMatHyxtTaskRunDService.getOneByBusinessId(param.getBusinessId());
        if (null == one) {
            // 判断申请单表是否为空
            AdsMatHyxtInvoiceApplyD applyD = adsMatHyxtInvoiceApplyDService.getById(param.getBusinessId());
            if (null != applyD) {
                result.setCurrentNodeIndex(InvoiceNodeEnum.getIndex(applyD.getCurrentNode()));
                result.setCurrentNode(applyD.getCurrentNode());
            } else {
                result.setCurrentNodeIndex(InvoiceNodeEnum.END.getIndex());
                result.setCurrentNode(InvoiceNodeEnum.END.getNode());
            }
        } else {
            result.setCurrentNodeIndex(InvoiceNodeEnum.getIndex(one.getCurrentNode()));
            result.setCurrentNode(one.getCurrentNode());
            result.setBranchType(one.getBranchType());
        }

        result.setTaskId(param.getId());
        result.setBusinessId(param.getBusinessId());
        result.setNodeList(InvoiceNodeEnum.getNodeList());
        result.setAuditLog(adsMatHyxtTaskHistoryDService.getLogList(param.getBusinessId()));
        result.setInvoiceList(adsMatHyxtInvoiceDService.getListByApplyId(param.getBusinessId()));
        return R.ok(result);
    }

    @ApiOperation(value = "【申请单】审核", notes = "【申请单】审核")
    @PostMapping("/audit")
    @Transactional(rollbackFor = Exception.class)
    public R audit(@RequestBody InvoiceApplyAuditPO param) {
        String taskId = param.getTaskId();
        String businessId = param.getBusinessId();
        Integer auditState = param.getAuditState();
        if (StringUtils.isBlank(taskId)) {
            return R.fail("taskId参数不能为空！");
        }
        if (StringUtils.isBlank(businessId)) {
            return R.fail("businessId参数不能为空");
        }
        if (ObjectUtils.isEmpty(auditState)) {
            return R.fail("auditState参数不能为空");
        }

        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUser user = loginUser.getUser();
        AdsMatHyxtTaskRunD taskRunD = adsMatHyxtTaskRunDService.getById(param.getTaskId());
        if (null == taskRunD) {
            return R.fail("当前任务不存在，请刷新页面！");
        }
        // 判断是否有权限（当前任务拥有者与当前登录用户是否匹配）
        if (!user.getUserName().equals(taskRunD.getOwnerUser())) {
            return R.fail("没有权限操作当前任务，或任务已被审核，请刷新页面！");
        }

        // 当前节点
        Integer currentNode = taskRunD.getCurrentNode();
        SysUser nextUser = null;
        SysUser nextUser2 = null;
        if (auditState == 1) {
            if (currentNode != InvoiceNodeEnum.NODE_12.getNode()) {
                if (StringUtils.isBlank(param.getNextAuditUser())) {
                    return R.fail("请选择下一岗审核人！");
                }
                nextUser = sysUserService.selectUserByUserName(param.getNextAuditUser());
                if (ObjectUtils.isEmpty(nextUser)) {
                    return R.fail("下一岗审核不存在！");
                }
                if (currentNode == InvoiceNodeEnum.NODE_10.getNode()) {
                    nextUser2 = sysUserService.selectUserByUserName(param.getNextAuditUser2());
                    if (ObjectUtils.isEmpty(nextUser2)) {
                        return R.fail("销售方财务人员不存在！");
                    }
                }
            }
        }
        return this.audit(currentNode, auditState, businessId, taskRunD, param, taskId, user, nextUser, nextUser2);
    }

    @ApiOperation(value = "【申请单】批量审核", notes = "【申请单】批量审核")
    @PostMapping("/batchAudit")
    @Transactional(rollbackFor = Exception.class)
    public R batchAudit(@RequestBody InvoiceApplyAuditPO param) {
        List<String> taskIds = param.getTaskIds();
        if (ObjectUtils.isEmpty(taskIds) || taskIds.isEmpty()) {
            return R.fail("taskIds参数不能为空！");
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUser user = loginUser.getUser();
        for (String taskId : param.getTaskIds()) {
            AdsMatHyxtTaskRunD taskRunD = adsMatHyxtTaskRunDService.getById(taskId);
            if (null == taskRunD) {
                continue;
            }
            // 判断是否有权限（当前任务拥有者与当前登录用户是否匹配）
            if (!user.getUserName().equals(taskRunD.getOwnerUser())) {
                continue;
            }
            // 当前节点
            Integer currentNode = taskRunD.getCurrentNode();
            SysUser nextUser = null;
            SysUser nextUser2 = null;
            if (currentNode != InvoiceNodeEnum.NODE_12.getNode()) {
                if (StringUtils.isBlank(param.getNextAuditUser())) {
                    return R.fail("请选择下一岗审核人！");
                }
                nextUser = sysUserService.selectUserByUserName(param.getNextAuditUser());
                if (ObjectUtils.isEmpty(nextUser)) {
                    return R.fail("下一岗审核不存在！");
                }
                if (currentNode == InvoiceNodeEnum.NODE_10.getNode()) {
                    nextUser2 = sysUserService.selectUserByUserName(param.getNextAuditUser2());
                    if (ObjectUtils.isEmpty(nextUser2)) {
                        return R.fail("销售方财务人员不存在！");
                    }
                }
            }

            R audit = this.audit(currentNode, 1, taskRunD.getBusinessId(), taskRunD, param, taskId, user, nextUser, nextUser2);
            if (R.ok().getCode() != audit.getCode()) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return audit;
            }
        }

        return R.ok();
    }

    private R audit(Integer currentNode, Integer auditState, String businessId, AdsMatHyxtTaskRunD taskRunD, InvoiceApplyAuditPO param,
                    String taskId, SysUser user, SysUser nextUser, SysUser nextUser2) {
        // TODO 代码优化
        // 业务审核
        if (currentNode == InvoiceNodeEnum.NODE_2.getNode()) {
            if (auditState != 1) {
                // 【退回】开票申请
                adsMatHyxtTaskRunDService.delete(businessId);
                adsMatHyxtTaskHistoryDService.auditFailSave(taskRunD, param.getAuditMsg());
                adsMatHyxtInvoiceApplyDService.updateNode(businessId, InvoiceNodeEnum.NODE_0, "", "","");
                // i国网短信提醒
                AdsMatHyxtInvoiceApplyD applyD = adsMatHyxtInvoiceApplyDService.getById(businessId);
                if (null != applyD) {
                    SysUser sysUser = sysUserService.selectUserByUserName(applyD.getCreateUser());
                    if (null != sysUser) {
                        adsMatHyxtIAppService.sendApp(businessId, MsgTemplateEnum.TMP_2.getMsg(taskRunD.getOwnerUserName()), InvoiceNodeEnum.NODE_0.getDesc(), sysUser, true, true);
                    }
                }
            } else {
                // 【通过】财务审核
                adsMatHyxtTaskRunDService.updateTask(taskId, InvoiceNodeEnum.NODE_4.getNode(), InvoiceNodeEnum.NODE_4.getDesc(), user, nextUser);
                adsMatHyxtTaskHistoryDService.auditOkSave(taskRunD);
                adsMatHyxtInvoiceApplyDService.updateAuditUser(businessId, null, nextUser.getUserName(), null, null, null, null);
                adsMatHyxtInvoiceApplyDService.updateNode(businessId, InvoiceNodeEnum.NODE_4, nextUser.getUserName(), nextUser.getNickName(), nextUser.getPhonenumber());
                adsMatHyxtIAppService.sendApp(businessId, MsgTemplateEnum.TMP_1.getMsg(nextUser.getNickName()), InvoiceNodeEnum.NODE_4.getDesc(), nextUser, true, true);
            }
        } else if (currentNode == InvoiceNodeEnum.NODE_4.getNode()) {
            if (auditState != 1) {
                // 【退回】node2 业务审核
                // i国网短信提醒
                adsMatHyxtTaskHistoryDService.auditFailSave(taskRunD, param.getAuditMsg());
                AdsMatHyxtTaskHistoryD prevNode = adsMatHyxtTaskHistoryDService.getOneNode(businessId, InvoiceNodeEnum.NODE_2.getNode());
                adsMatHyxtTaskRunDService.auditRollback(prevNode, taskRunD);
                adsMatHyxtInvoiceApplyDService.updateNode(businessId, InvoiceNodeEnum.NODE_2, prevNode.getOwnerUser(), prevNode.getOwnerUserName(), prevNode.getOwnerUserPhone());
                SysUser sysUser = sysUserService.selectUserByUserName(prevNode.getOwnerUser());
                if (null != sysUser) {
                    adsMatHyxtIAppService.sendApp(businessId, MsgTemplateEnum.TMP_2.getMsg(taskRunD.getOwnerUserName()), InvoiceNodeEnum.NODE_2.getDesc(), sysUser, true, true);
                }
            } else {
                List<AdsMatHyxtInvoiceD> invoiceList = adsMatHyxtInvoiceDService.getListByApplyId(businessId);
                int index = 0;
                for (AdsMatHyxtInvoiceD item : invoiceList) {
                    index++;
                    // 检查是否填写可用预算
                    if (StringUtils.isEmpty(item.getValidBudgetAmount())) {
                        return R.fail("第 "+ index + " 行数据未填写可用预算金额，请填写可用预算金额！");
                    }
                    BigDecimal v1 = revert(item.getValidBudgetAmount());// 可用预算金额
                    BigDecimal v2 = revert(item.getTaxAmount());// 本次开票金额
                    if (null == v1) {
                        return R.fail("第 "+ index + " 行数据可用预算金额未填写或填写了错误类型的金额，请重新填写！");
                    }
                    if (null == v2) {
                        return R.fail("第 "+ index + " 行数据本次开票金额未填写或填写了错误类型的金额，请重新填写！");
                    }
                    // 预算稽核
                    if (v2.compareTo(v1) > 0) {
                        return R.fail("第 "+ index + " 行数据【可用预算金额 大于 本次开票金额】，不允许进行确认！");
                    }
                }



                // 【通过】node6 财务确认
                adsMatHyxtTaskRunDService.updateTask(taskId, InvoiceNodeEnum.NODE_6.getNode(), InvoiceNodeEnum.NODE_6.getDesc(), user, nextUser);
                adsMatHyxtTaskHistoryDService.auditOkSave(taskRunD);
                adsMatHyxtInvoiceApplyDService.updateAuditUser(businessId, null, null, nextUser.getUserName(), null, null, null);
                adsMatHyxtInvoiceApplyDService.updateNode(businessId, InvoiceNodeEnum.NODE_6, nextUser.getUserName(), nextUser.getNickName(), nextUser.getPhonenumber());
                adsMatHyxtIAppService.sendApp(businessId, MsgTemplateEnum.TMP_1.getMsg(nextUser.getNickName()), InvoiceNodeEnum.NODE_6.getDesc(), nextUser, true, true);
            }
        } else if (currentNode == InvoiceNodeEnum.NODE_6.getNode()) {
            if (auditState != 1) {
                // 【退回】node4 财务审核
                // i国网短信提醒
                adsMatHyxtTaskHistoryDService.auditFailSave(taskRunD, param.getAuditMsg());
                AdsMatHyxtTaskHistoryD prevNode = adsMatHyxtTaskHistoryDService.getOneNode(businessId, InvoiceNodeEnum.NODE_4.getNode());
                adsMatHyxtTaskRunDService.auditRollback(prevNode, taskRunD);
                adsMatHyxtInvoiceApplyDService.updateNode(businessId, InvoiceNodeEnum.NODE_4, prevNode.getOwnerUser(), prevNode.getOwnerUserName(), prevNode.getOwnerUserPhone());
                SysUser sysUser = sysUserService.selectUserByUserName(prevNode.getOwnerUser());
                if (null != sysUser) {
                    adsMatHyxtIAppService.sendApp(businessId, MsgTemplateEnum.TMP_2.getMsg(taskRunD.getOwnerUserName()), InvoiceNodeEnum.NODE_4.getDesc(), sysUser, true, true);
                }
            } else {
                // 【通过】node8 开票上传
                adsMatHyxtTaskRunDService.updateTask(taskId, InvoiceNodeEnum.NODE_8.getNode(), InvoiceNodeEnum.NODE_8.getDesc(), user, nextUser);
                adsMatHyxtTaskHistoryDService.auditOkSave(taskRunD);
                adsMatHyxtInvoiceApplyDService.updateAuditUser(businessId, null, null, null, nextUser.getUserName(), null, null);
                adsMatHyxtInvoiceApplyDService.updateNode(businessId, InvoiceNodeEnum.NODE_8, nextUser.getUserName(), nextUser.getNickName(), nextUser.getPhonenumber());
                adsMatHyxtIAppService.sendApp(businessId, MsgTemplateEnum.TMP_3.getMsg(nextUser.getNickName()), InvoiceNodeEnum.NODE_8.getDesc(), nextUser, true, true);
            }
        } else if (currentNode == InvoiceNodeEnum.NODE_8.getNode()) {
            if (auditState != 1) {
                // 【退回】node8 财务确认
                // i国网短信提醒
                adsMatHyxtTaskHistoryDService.auditFailSave(taskRunD, param.getAuditMsg());
                AdsMatHyxtTaskHistoryD prevNode = adsMatHyxtTaskHistoryDService.getOneNode(businessId, InvoiceNodeEnum.NODE_6.getNode());
                adsMatHyxtTaskRunDService.auditRollback(prevNode, taskRunD);
                adsMatHyxtInvoiceApplyDService.updateNode(businessId, InvoiceNodeEnum.NODE_6, prevNode.getOwnerUser(), prevNode.getOwnerUserName(), prevNode.getOwnerUserPhone());
                SysUser sysUser = sysUserService.selectUserByUserName(prevNode.getOwnerUser());
                if (null != sysUser) {
                    adsMatHyxtIAppService.sendApp(businessId, MsgTemplateEnum.TMP_2.getMsg(taskRunD.getOwnerUserName()), InvoiceNodeEnum.NODE_6.getDesc(), sysUser, false, true);
                }
            } else {
                // 发票都上传后才能确认
                List<AdsMatHyxtInvoiceD> invoiceList = adsMatHyxtInvoiceDService.getListByApplyId(businessId);
                int index = 0;
                for (AdsMatHyxtInvoiceD invoiceD : invoiceList) {
                    index++;
                    if (invoiceD.getIsUploadInvoice() == 0) {
//                        return R.fail("【"+taskRunD.getTaskName()+"】发票还未全部上传，不能进行确认！请检查第 " + index + "行数据！");
                        return R.fail("【"+taskRunD.getTaskName()+"】发票还未全部上传，不能进行确认！请先上传发票信息！");
                    }
                }

                // 【通过】node10 业务部门接收
                adsMatHyxtTaskRunDService.updateTask(taskId, InvoiceNodeEnum.NODE_10.getNode(), InvoiceNodeEnum.NODE_10.getDesc(), user, nextUser);
                adsMatHyxtTaskHistoryDService.auditOkSave(taskRunD);
                adsMatHyxtInvoiceApplyDService.updateAuditUser(businessId, null, null, null, null, nextUser.getUserName(), null);
                adsMatHyxtInvoiceApplyDService.updateNode(businessId, InvoiceNodeEnum.NODE_10, nextUser.getUserName(), nextUser.getNickName(), nextUser.getPhonenumber());
                adsMatHyxtIAppService.sendApp(businessId, MsgTemplateEnum.TMP_4.getMsg(nextUser.getNickName()), InvoiceNodeEnum.NODE_10.getDesc(), nextUser, true, true);
            }
        } else if (currentNode == InvoiceNodeEnum.NODE_10.getNode()) {
//            if (auditState == -1) {
//                // 开票申请
//                adsMatHyxtTaskRunDService.delete(businessId);
//                adsMatHyxtTaskHistoryDService.auditFailSave(taskRunD, param.getAuditMsg());
//                adsMatHyxtInvoiceApplyDService.updateNode(businessId, InvoiceNodeEnum.NODE_0,"","");
//            } else if (auditState == 0) {
            if (auditState == 0) {
                // 开票上传
                // i国网短信提醒
                adsMatHyxtTaskHistoryDService.auditFailSave(taskRunD, param.getAuditMsg());
                AdsMatHyxtTaskHistoryD prevNode = adsMatHyxtTaskHistoryDService.getOneNode(businessId, InvoiceNodeEnum.NODE_8.getNode());
                adsMatHyxtTaskRunDService.auditRollback(prevNode, taskRunD);
                adsMatHyxtInvoiceApplyDService.updateNode(businessId, InvoiceNodeEnum.NODE_8, prevNode.getOwnerUser(), prevNode.getOwnerUserName(), prevNode.getOwnerUserPhone());
                SysUser sysUser = sysUserService.selectUserByUserName(prevNode.getOwnerUser());
                if (null != sysUser) {
                    adsMatHyxtIAppService.sendApp(businessId, MsgTemplateEnum.TMP_2.getMsg(taskRunD.getOwnerUserName()), InvoiceNodeEnum.NODE_8.getDesc(), sysUser, true, true);
                }
            } else {
                // 请先确认发票是否接收
                AdsMatHyxtInvoiceApplyD applyD = adsMatHyxtInvoiceApplyDService.getById(businessId);
                Integer isReceiptInvoice = applyD.getIsReceiptInvoice();
                if (isReceiptInvoice != 1) {
                    return R.fail("【"+taskRunD.getTaskName()+"】请先确认发票是否接收！");
                }

                // 财务入账及凭证生成
                adsMatHyxtTaskRunDService.updateTask(taskId, InvoiceNodeEnum.NODE_12.getNode(), InvoiceNodeEnum.NODE_12.getDesc(), user, nextUser);
                adsMatHyxtTaskHistoryDService.auditOkSave(taskRunD);
                adsMatHyxtInvoiceApplyDService.updateAuditUser(businessId, null, null, null, null, nextUser.getUserName(), null);
                adsMatHyxtInvoiceApplyDService.updateNode(businessId, InvoiceNodeEnum.NODE_12, nextUser.getUserName(), nextUser.getNickName(), nextUser.getPhonenumber());
                adsMatHyxtIAppService.sendApp(businessId, MsgTemplateEnum.TMP_5.getMsg(nextUser.getNickName()), InvoiceNodeEnum.NODE_12.getDesc(), nextUser, true, true);

                // 【任务】销售方财务人员
                adsMatHyxtTaskRunDService.createTask(taskId, nextUser2);
            }
        } else if (currentNode == InvoiceNodeEnum.NODE_12.getNode()) {
            if (auditState != 1) {
                // 发票接收
                // i国网短信提醒
                adsMatHyxtTaskHistoryDService.auditFailSave(taskRunD, param.getAuditMsg());
                AdsMatHyxtTaskHistoryD prevNode = adsMatHyxtTaskHistoryDService.getOneNode(businessId, InvoiceNodeEnum.NODE_10.getNode());
                adsMatHyxtTaskRunDService.auditRollback(prevNode, taskRunD);
                adsMatHyxtInvoiceApplyDService.updateNode(businessId, InvoiceNodeEnum.NODE_10, prevNode.getOwnerUser(), prevNode.getOwnerUserName(), prevNode.getOwnerUserPhone());
                SysUser sysUser = sysUserService.selectUserByUserName(prevNode.getOwnerUser());
                if (null != sysUser) {
                    adsMatHyxtIAppService.sendApp(businessId, MsgTemplateEnum.TMP_2.getMsg(taskRunD.getOwnerUserName()), InvoiceNodeEnum.NODE_10.getDesc(), sysUser, true, true);
                }
                adsMatHyxtTaskRunDService.delete(businessId, InvoiceNodeEnum.NODE_12);
            } else {
                // 请先确认是否接收报账
                AdsMatHyxtInvoiceApplyD applyD = adsMatHyxtInvoiceApplyDService.getById(businessId);
                Integer isReceiptBz = applyD.getIsReceiptBz();
                if (isReceiptBz != 1) {
                    return R.fail("【"+taskRunD.getTaskName()+"】请先确认是否收到报销资料！已收到请先点击【接收报账】按钮！");
                }

                // 入账凭证号都上传后才能确认
                List<AdsMatHyxtInvoiceD> invoiceList = adsMatHyxtInvoiceDService.getListByApplyId(businessId);
                int index = 0;
                for (AdsMatHyxtInvoiceD invoiceD : invoiceList) {
                    index++;
                    if (invoiceD.getIsGenerateCode() == 0) {
//                        return R.fail("【"+taskRunD.getTaskName()+"入账凭证号还未上传，不能进行确认！请检查第 " + index + "行数据！");
                        return R.fail("【"+taskRunD.getTaskName()+"】入账凭证号还未上传，不能进行确认！");
                    }
                }

                // 流程结束
                adsMatHyxtTaskRunDService.delete(businessId);
                adsMatHyxtTaskHistoryDService.auditOkSave(taskRunD);
                adsMatHyxtInvoiceApplyDService.updateNode(businessId, InvoiceNodeEnum.END, "/", "/", "/");

                // 关闭定时任务
                adsMatHyxtTaskSendMsgDService.closeTask(businessId);
            }
        } else {
            return R.fail("审核节点错误，请刷新后再试！");
        }
        return R.ok();
    }

    @PostMapping("/applyInvoiceExport")
    @ApiOperation(value = "【申请单】发票导出")
    public void applyInvoiceExport(@RequestBody InvoiceApplyDetailPO param, HttpServletResponse response) throws IOException {
        InputStream fis = null;
        OutputStream ops = null;

        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        String fileName = java.util.UUID.randomUUID() + ".xlsx";
        response.setHeader("Content-disposition", "attachment;filename=" + fileName);
        String templateFileName = "excelTemplate/invoiceExport.xlsx";
        fis = Thread.currentThread().getContextClassLoader().getResourceAsStream(templateFileName);
        ops = response.getOutputStream();

        LambdaQueryWrapper<AdsMatHyxtInvoiceD> queryWrapper = Wrappers.lambdaQuery();
        if (StringUtils.isNotBlank(param.getApplyId())) {
            queryWrapper.eq(AdsMatHyxtInvoiceD::getApplyId, param.getApplyId());
        }
        queryWrapper.orderByDesc(AdsMatHyxtInvoiceD::getCreateTime);
        List<AdsMatHyxtInvoiceD> list = adsMatHyxtInvoiceDService.list(queryWrapper);
        int idx = 1;
        for (AdsMatHyxtInvoiceD invoiceD : list) {
            invoiceD.setIdx(idx++);
        }

        //填充导出信息
        ExcelWriter excelWriter = EasyExcel.write(ops, AdsMatHyxtInvoiceD.class).withTemplate(fis).build();
        WriteSheet writeSheet = EasyExcel.writerSheet().build();
        FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
        excelWriter.fill(list, fillConfig, writeSheet);
        excelWriter.finish();
    }

    @PostMapping("/applyInvoiceExportDetail")
    @ApiOperation(value = "【申请单】发票导出")
    public void applyInvoiceExportDetail(HttpServletResponse response) throws IOException {
        InputStream fis = null;
        OutputStream ops = null;

        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        String fileName = java.util.UUID.randomUUID() + ".xlsx";
        response.setHeader("Content-disposition", "attachment;filename=" + fileName);
        String templateFileName = "excelTemplate/invoiceExport.xlsx";
        fis = Thread.currentThread().getContextClassLoader().getResourceAsStream(templateFileName);
        ops = response.getOutputStream();

        LambdaQueryWrapper<AdsMatHyxtInvoiceD> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.orderByDesc(AdsMatHyxtInvoiceD::getCreateTime);
        List<AdsMatHyxtInvoiceD> list = adsMatHyxtInvoiceDService.list(queryWrapper);
        int idx = 1;
        for (AdsMatHyxtInvoiceD invoiceD : list) {
            invoiceD.setIdx(idx++);
        }

        //填充导出信息
        ExcelWriter excelWriter = EasyExcel.write(ops, AdsMatHyxtInvoiceD.class).withTemplate(fis).build();
        WriteSheet writeSheet = EasyExcel.writerSheet().build();
        FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
        excelWriter.fill(list, fillConfig, writeSheet);
        excelWriter.finish();
    }

    @ApiOperation(value = "2【发票】详情", notes = "【发票】详情")
    @PostMapping("/invoiceDetail")
    public R<AdsMatHyxtInvoiceD> invoiceDetail(@RequestBody InvoiceApplyDetailPO param) {
        if (StringUtils.isBlank(param.getId())) {
            return R.fail("参数id不能为空");
        }
        AdsMatHyxtInvoiceD invoiceD = adsMatHyxtInvoiceDService.getById(param.getId());
        if (null != invoiceD) {
            invoiceD.setFileList(adsMatHyxtInvoiceFileDService.getListByInvoiceId(invoiceD.getId()));
        }
        return R.ok(invoiceD);
    }

    @ApiOperation(value = "【发票上传环节】【发票上传】详情,回显发票信息", notes = "【发票上传环节】【发票上传】详情")
    @PostMapping("/invoiceUploadDetail")
    @Deprecated
    public R<AdsMatHyxtInvoiceD> invoiceUploadDetail(@RequestBody InvoiceApplyDetailPO param) {
        if (StringUtils.isBlank(param.getBusinessId())) {
            return R.fail("参数businessId不能为空");
        }
        LambdaQueryWrapper<AdsMatHyxtInvoiceD> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(AdsMatHyxtInvoiceD::getApplyId, param.getBusinessId());
        queryWrapper.eq(AdsMatHyxtInvoiceD::getIsDeleted, 0);
        List<AdsMatHyxtInvoiceD> list = adsMatHyxtInvoiceDService.list(queryWrapper);
        if (!list.isEmpty()) {
            AdsMatHyxtInvoiceD invoiceD = list.get(0);
            if (null != invoiceD) {
                invoiceD.setFileList(adsMatHyxtInvoiceFileDService.getListByInvoiceId(invoiceD.getId()));
            }
            return R.ok(invoiceD);
        }

        return R.ok(null);
    }

    @ApiOperation(value = "【发票上传环节】保存发票", notes = "【发票上传环节】保存发票")
    @PostMapping("/invoiceUploadSave")
    @Deprecated
    public R invoiceUploadSave(@RequestBody AdsMatHyxtInvoiceD param) {
        if (StringUtils.isBlank(param.getBusinessId())) {
            return R.fail("参数businessId不能为空");
        }
        if (StringUtils.isBlank(param.getInvoiceCode())) {
            return R.fail("请填写发票代码！");
        }
        if (ObjectUtils.isEmpty(param.getMakeInvoiceDate())) {
            return R.fail("请填写开票日期！");
        }
        LambdaUpdateWrapper<AdsMatHyxtInvoiceD> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(AdsMatHyxtInvoiceD::getApplyId, param.getBusinessId());
        updateWrapper.set(AdsMatHyxtInvoiceD::getMakeInvoiceDate, param.getMakeInvoiceDate());
        updateWrapper.set(AdsMatHyxtInvoiceD::getInvoiceCode, param.getInvoiceCode());
        if (ObjectUtils.isNotEmpty(param.getMakeInvoiceDate()) && StringUtils.isNotBlank(param.getInvoiceCode())) {
            updateWrapper.set(AdsMatHyxtInvoiceD::getIsUploadInvoice, 1);
        }
        adsMatHyxtInvoiceDService.update(updateWrapper);

        LambdaQueryWrapper<AdsMatHyxtInvoiceD> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(AdsMatHyxtInvoiceD::getApplyId, param.getBusinessId());
        queryWrapper.eq(AdsMatHyxtInvoiceD::getIsDeleted, 0);
        List<AdsMatHyxtInvoiceD> list = adsMatHyxtInvoiceDService.list(queryWrapper);

        Date date = new Date();
        for (AdsMatHyxtInvoiceD invoiceD : list) {
            List<AdsMatHyxtInvoiceFileD> fileList = param.getFileList();
            if (null != fileList && !fileList.isEmpty()) {
                for (AdsMatHyxtInvoiceFileD invoiceFileD : fileList) {
                    invoiceFileD.setId(IdGen.get32UUID());
                    invoiceFileD.setInvoiceId(invoiceD.getId());
                    invoiceFileD.setApplyId(param.getBusinessId());
                    invoiceFileD.setCreateTime(date);
                }
                adsMatHyxtInvoiceFileDService.logicDeleteByInvoiceId(invoiceD.getId());
                adsMatHyxtInvoiceFileDService.saveBatch(fileList);
            }
        }
        return R.ok();
    }

    @ApiOperation(value = "2【发票】保存", notes = "【发票】保存")
    @PostMapping("/invoiceSave")
    public R invoiceDetail(@RequestBody AdsMatHyxtInvoiceD param) {
        if (StringUtils.isBlank(param.getId())) {
            return R.fail("参数id不能为空");
        }
//        if (StringUtils.isBlank(param.getInvoiceCode())) {
//            return R.fail("请填写发票代码！");
//        }
//        if (ObjectUtils.isEmpty(param.getMakeInvoiceDate())) {
//            return R.fail("请填写开票日期！");
//        }
        Date date = new Date();
        AdsMatHyxtInvoiceD invoiceD = adsMatHyxtInvoiceDService.getById(param.getId());
        if (null == invoiceD) {
            return R.fail("开票信息不存在！");
        }
        int updateNum = 0;
        LambdaUpdateWrapper<AdsMatHyxtInvoiceD> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(AdsMatHyxtInvoiceD::getId, param.getId());
        if (ObjectUtils.isNotEmpty(param.getMakeInvoiceDate())) {
            updateWrapper.set(AdsMatHyxtInvoiceD::getMakeInvoiceDate, param.getMakeInvoiceDate());
            updateNum++;
        }
        if (StringUtils.isNotBlank(param.getInvoiceCode())) {
            updateWrapper.set(AdsMatHyxtInvoiceD::getInvoiceCode, param.getInvoiceCode());
            updateNum++;
        }
        if (StringUtils.isNotBlank(param.getVoucherCode())) {
            updateWrapper.set(AdsMatHyxtInvoiceD::getVoucherCode, param.getVoucherCode());
            updateNum++;
        }
        if (StringUtils.isNotBlank(param.getYnVoucherCode())) {
            updateWrapper.set(AdsMatHyxtInvoiceD::getYnVoucherCode, param.getYnVoucherCode());
            updateNum++;
        }
        if (updateNum > 0) {
            updateWrapper.set(AdsMatHyxtInvoiceD::getUpdateTime, date);
            if (ObjectUtils.isNotEmpty(param.getMakeInvoiceDate()) && StringUtils.isNotBlank(param.getInvoiceCode())) {
                updateWrapper.set(AdsMatHyxtInvoiceD::getIsUploadInvoice, 1);
            }
            if (StringUtils.isNotBlank(param.getVoucherCode()) && StringUtils.isNotBlank(param.getYnVoucherCode())) {
                updateWrapper.set(AdsMatHyxtInvoiceD::getIsGenerateCode, 1);
            }
            adsMatHyxtInvoiceDService.update(updateWrapper);
        }
        AdsMatHyxtInvoiceD invoiceD2 = adsMatHyxtInvoiceDService.getById(param.getId());
        if (StringUtils.isNotBlank(invoiceD2.getVoucherCode()) && StringUtils.isNotBlank(invoiceD2.getYnVoucherCode())) {
            LambdaUpdateWrapper<AdsMatHyxtInvoiceD> updateWrapper1 = Wrappers.lambdaUpdate();
            updateWrapper1.eq(AdsMatHyxtInvoiceD::getId, invoiceD2.getId());
            updateWrapper1.set(AdsMatHyxtInvoiceD::getIsGenerateCode, 1);
            adsMatHyxtInvoiceDService.update(updateWrapper1);
        }

        List<AdsMatHyxtInvoiceFileD> fileList = param.getFileList();
        if (null != fileList && !fileList.isEmpty()) {
            for (AdsMatHyxtInvoiceFileD invoiceFileD : fileList) {
                invoiceFileD.setId(IdGen.get32UUID());
                invoiceFileD.setInvoiceId(invoiceD.getId());
                invoiceFileD.setApplyId(invoiceD.getApplyId());
                invoiceFileD.setCreateTime(date);
            }
            adsMatHyxtInvoiceFileDService.logicDeleteByInvoiceId(invoiceD.getId());
            adsMatHyxtInvoiceFileDService.saveBatch(fileList);
        }
        return R.ok();
    }

    @ApiOperation(value = "可用预算金额保存", notes = "可用预算金额保存")
    @PostMapping("/validBudgetAmountSave")
    public R validBudgetAmountSave(@RequestBody AdsMatHyxtInvoiceD param) {
        if (StringUtils.isEmpty(param.getId())) {
            return R.fail("id不能为空！");
        }
        if (StringUtils.isEmpty(param.getValidBudgetAmount())) {
            return R.fail("可用预算金额不能为空！");
        }
        if (StringUtils.isEmpty(param.getTaxAmount())) {
            return R.fail("本次开票金额不能为空！");
        }
        if (!checkIsDouble(param.getValidBudgetAmount())) {
            return R.fail("可用预算金额请填写正确的金额！");
        }
        if (!checkIsDouble(param.getTaxAmount())) {
            return R.fail("本次开票金额填写正确的金额！");
        }
        LambdaUpdateWrapper<AdsMatHyxtInvoiceD> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(AdsMatHyxtInvoiceD::getId, param.getId());
        updateWrapper.set(AdsMatHyxtInvoiceD::getValidBudgetAmount, param.getValidBudgetAmount());
        updateWrapper.set(AdsMatHyxtInvoiceD::getTaxAmount, param.getTaxAmount());
        adsMatHyxtInvoiceDService.update(updateWrapper);
        return R.ok();
    }

    @ApiOperation(value = "可用预算金额保存", notes = "可用预算金额保存")
    @PostMapping("/validBudgetAmountBatchSave")
    public R validBudgetAmountBatchSave(@RequestBody AdsMatHyxtInvoiceD param) {
        if (StringUtils.isEmpty(param.getBusinessId())) {
            return R.fail("businessId不能为空！");
        }
        if (StringUtils.isEmpty(param.getValidBudgetAmount())) {
            return R.fail("可用预算金额不能为空！");
        }
        if (!checkIsDouble(param.getValidBudgetAmount())) {
            return R.fail("可用预算金额请填写正确的金额！");
        }
        LambdaUpdateWrapper<AdsMatHyxtInvoiceD> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(AdsMatHyxtInvoiceD::getApplyId, param.getBusinessId());
        updateWrapper.set(AdsMatHyxtInvoiceD::getValidBudgetAmount, param.getValidBudgetAmount());
        adsMatHyxtInvoiceDService.update(updateWrapper);
        return R.ok();
    }

    private boolean checkIsDouble(String str) {
        try {
            BigDecimal decimal = new BigDecimal(str);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    private BigDecimal revert(String str) {
        try {
            return new BigDecimal(str);
        } catch (Exception e) {
            return null;
        }
    }

    @ApiOperation(value = "入账凭证号保存", notes = "入账凭证号保存")
    @PostMapping("/codeSave")
    public R codeSave(@RequestBody AdsMatHyxtInvoiceD param) {
        List<AdsMatHyxtInvoiceD> ids = param.getIds();
        if (ids.isEmpty()) {
            return R.fail("请选择数据！");
        }
        for (AdsMatHyxtInvoiceD item : param.getIds()) {
            AdsMatHyxtInvoiceD invoiceD = adsMatHyxtInvoiceDService.getById(item.getId());
            if (null != invoiceD) {
                LambdaUpdateWrapper<AdsMatHyxtInvoiceD> updateWrapper = Wrappers.lambdaUpdate();
                if (StringUtils.isNotBlank(param.getVoucherCode())) {
                    updateWrapper.set(AdsMatHyxtInvoiceD::getVoucherCode, param.getVoucherCode());
                    invoiceD.setVoucherCode(param.getVoucherCode());
                }
                if (StringUtils.isNotBlank(param.getYnVoucherCode())) {
                    updateWrapper.set(AdsMatHyxtInvoiceD::getYnVoucherCode, param.getYnVoucherCode());
                    invoiceD.setYnVoucherCode(param.getYnVoucherCode());
                }
                if (StringUtils.isNotBlank(param.getVoucherCode()) && StringUtils.isNotBlank(param.getYnVoucherCode())) {
                    updateWrapper.set(AdsMatHyxtInvoiceD::getIsGenerateCode, 1);
                }
                if (StringUtils.isNotBlank(invoiceD.getVoucherCode()) && StringUtils.isNotBlank(invoiceD.getYnVoucherCode())) {
                    updateWrapper.set(AdsMatHyxtInvoiceD::getIsGenerateCode, 1);
                }
                adsMatHyxtInvoiceDService.update(updateWrapper);
            }
        }
        return R.ok();
    }

    @ApiOperation("【发票】orc识别")
    @PostMapping("/invoiceOcrScan")
    public R invoiceOcrScan(@RequestParam("file") MultipartFile file) {
        if (null == file || file.isEmpty()) {
            return R.fail("上传的文件不能为空！");
        }
        if (PDFUtil.isImageFile(file) || PDFUtil.isPdfFile(file)) {
            return adsMatHyxtOcrService.invoiceOcrScan(file);
        } else {
            return R.fail("文件类型暂不支持上传!");
        }
    }

}
