sinake
2 天以前 e24ab2fc4d092b4599ef44ddce5ebdbbc0bd8f9a
ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceReimbursementServiceImpl.java
@@ -17,7 +17,9 @@
import com.ruoyi.common.utils.HttpClientKit;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.DtoConversionUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.project.common.FundNotifyMessageBuilder;
import com.ruoyi.project.common.IdGeneratorUtils;
import com.ruoyi.project.domain.*;
import com.ruoyi.project.domain.dto.ServiceReimbursementDto;
import com.ruoyi.project.domain.vo.CheckFundVO;
@@ -25,7 +27,9 @@
import com.ruoyi.project.domain.vo.SpFinancialExpensesReimbursementOut;
import com.ruoyi.project.mapper.*;
import com.ruoyi.project.service.*;
import com.ruoyi.system.mapper.SysUserMapper;
import com.ruoyi.system.mapper.SysUserRoleMapper;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysPostService;
import com.ruoyi.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
@@ -78,6 +82,12 @@
    IServiceReimbursementpayeeSharedService payeeSharedService;
    @Autowired
    IServiceReimbursementpayeeService payeeService;
    @Autowired
    SysUserMapper sysUserMapper;
    @Autowired
    IServiceFundflowruleService serviceFundflowruleService;
    @Autowired
@@ -110,6 +120,35 @@
    @Value("${spring.profiles.active}")
    private String active;
    @Autowired
    private ISysConfigService sysConfigService;
    /**
     * 审批单是否上传医院协友(致远)系统:0=不上传(测试环境),1=上传(正式环境)。
     *
     * <p>2026-10-09 新增:原来用 {@code spring.profiles.active == druid} 来判断是否推送,
     * 导致测试环境与正式环境无法通过参数区分。改为系统参数控制,环境各自配置。
     */
    private static final String CFG_UPLOAD_OA = "sys.approval.upload.oa";
    /** 参数缺省值:上传(保持正式环境原有行为) */
    private static final boolean DEFAULT_UPLOAD_OA = true;
    /** 审批单是否需要上传医院协友(致远)系统 */
    private boolean isUploadOaEnabled() {
        String value = null;
        try {
            value = sysConfigService.selectConfigByKey(CFG_UPLOAD_OA);
        } catch (Exception e) {
            log.warn("读取参数 {} 失败,按默认值 {} 处理", CFG_UPLOAD_OA, DEFAULT_UPLOAD_OA, e);
        }
        if (value == null || value.trim().isEmpty()) {
            return DEFAULT_UPLOAD_OA;
        }
        String v = value.trim();
        return "1".equals(v) || "true".equalsIgnoreCase(v) || "y".equalsIgnoreCase(v) || "on".equalsIgnoreCase(v);
    }
    /**
     * 查询报销申请列表
@@ -129,7 +168,7 @@
        if (serviceReimbursement.getCreateTime() != null) {
            wrappers.eq(ServiceReimbursement::getCreateTime, serviceReimbursement.getCreateTime());
        }
        if (StringUtils.isNotBlank(serviceReimbursement.getUsername())) {
        if (StringUtils.isNotBlank(serviceReimbursement.getUsername()) && !serviceReimbursement.getUsername().equals("shenji")) {
            wrappers.like(ServiceReimbursement::getUsername, serviceReimbursement.getUsername());
        }
        if (StringUtils.isNotBlank(serviceReimbursement.getTravelers())) {
@@ -158,6 +197,7 @@
            wrappers.between(ServiceReimbursement::getCreateTime ,serviceReimbursement.getStarttime(),serviceReimbursement.getEndtime());
        }*/
        wrappers.orderByDesc(ServiceReimbursement::getApplyTime);
        return this.list(wrappers);
    }
@@ -210,7 +250,17 @@
        List<ServiceReimbursementShared> serviceReimbursementShareds = sharedService.queryList(reimbursementShared1);
        log.info("serviceReimbursementShareds的查询结果 :{}", serviceReimbursementShareds.size());
        if (!CollectionUtils.isEmpty(serviceReimbursementShareds)) {
            return true;
            //如果不为空,则将分享表里的数据删除(因为接下去,老数据上传的附件,可能不是想要的了,还用老附件,是有问题的;所以需要将老的share数据删除,然后再新增,上传新附件)
            for (ServiceReimbursementShared serviceReimbursementShared : serviceReimbursementShareds) {
                sharedService.removeById(serviceReimbursementShared.getId());
                ServiceReimbursementdetailShared srds = new ServiceReimbursementdetailShared();
                srds.setRbid(serviceReimbursementShared.getId());
                List<ServiceReimbursementdetailShared> serviceReimbursementdetailShareds = detailSharedService.queryList(srds);
                for (ServiceReimbursementdetailShared serviceReimbursementdetailShared : serviceReimbursementdetailShareds) {
                    detailSharedService.removeById(serviceReimbursementdetailShared.getId());
                }
            }
        }
        //如果没有插入,则走下面的流程
@@ -234,21 +284,21 @@
//        //上传OA文件
        //将serviceReimbursementdetail表里的id赋值给Rdid; 将serviceReimbursementShared里的ID赋值给RBID,并将serviceReimbursementdetailShared表里的id置空,由数据库重新生成
        for (int i = 0; i < details.size(); i++) {
            serviceReimbursementdetailShareds.get(i).setRdid(serviceReimbursementdetailShareds.get(i).getId());
            serviceReimbursementdetailShareds.get(i).setRdid(details.get(i).getId());
            serviceReimbursementdetailShareds.get(i).setRbid(serviceReimbursementShared.getId());
            serviceReimbursementdetailShareds.get(i).setId(null);
            //上传OA文件
            log.info("上传OA文件方法的入参:{}", serviceReimbursementdetailShareds.get(i));
            try {
                //如果是本地环境,就不调这个了
                if (!active.equals("druid")) uploadOAFileAndUpdateDb(serviceReimbursementdetailShareds.get(i));
                if (isUploadOaEnabled()) uploadOAFileAndUpdateDb(serviceReimbursementdetailShareds.get(i));
            } catch (Exception e) {
                log.error("Exception中reimShare的入参id为:{}", serviceReimbursementShared.getId());
                log.error("差旅附件上传医院协友系统失败:分享id={},明细={}(本次报销单上传整体失败,审批不生效)",
                        serviceReimbursementShared.getId(), serviceReimbursementdetailShareds.get(i), e);
                if (serviceReimbursementShared.getId() != null) {
                    Boolean aBoolean = sharedService.delResharedInfoById(serviceReimbursementShared.getId());
                    log.error("文件上传失败,将分享表数据回滚:{}", aBoolean);
                    log.error("已回滚分享表数据:{}", aBoolean);
                }
                e.getMessage();
                return false;
            }
@@ -257,7 +307,16 @@
//        detailSharedService.saveBatch(serviceReimbursementdetailShareds);
        for (ServiceReimbursementdetailShared serviceReimbursementdetailShared : serviceReimbursementdetailShareds) {
            if (ObjectUtils.isNotEmpty(serviceReimbursementdetailShared)) {
                log.info("更新serviceReimbursementdetail表里的值为:{}", serviceReimbursementdetailShared);
                detailSharedService.save(serviceReimbursementdetailShared);
                log.info("更新serviceReimbursementdetail表里的附件字段:{},{}", serviceReimbursementdetailShared.getAnnexfiles(), serviceReimbursementdetailShared.getInvoicefiles());
                //更新serviceReimbursementdetail表里的附件字段
                ServiceReimbursementdetail serviceReimbursementdetail = new ServiceReimbursementdetail();
                serviceReimbursementdetail.setId(serviceReimbursementdetailShared.getRdid());
                serviceReimbursementdetail.setAnnexfiles(serviceReimbursementdetailShared.getAnnexfiles());
                serviceReimbursementdetail.setInvoicefiles(serviceReimbursementdetailShared.getInvoicefiles());
                serviceReimbursementdetailMapper.updateById(serviceReimbursementdetail);
            } else {
                log.info("serviceReimbursementdetailShared为空了");
            }
@@ -306,6 +365,7 @@
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, String> checkFund(LoginUser loginUser, CheckFundVO checkFundVO) {
        Map<String, String> allMap = new HashMap<>();
@@ -359,7 +419,7 @@
                    log.info("出差补贴被 财务退回再提交,出纳再次审批,之后提交到财务:{}", serviceReimbursement.getId());
                    //说明是财务退回再提交的.需要出纳再看一遍,没问题之后,往分享表里新增
//                    serviceReimbursementService.addSharedData(serviceReimbursement.getId());
//                    serviceReimbursement.setFinancechecher("审批人:" + user.getUserName() + " & 审批时间" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + " & 审批结果:通过");
//                    serviceReimbursement.setFinancechecher("审批人:" + user.getNickName() + " & 审批时间" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + " & 审批结果:通过");
                    serviceReimbursement.setFinancechecher(user.getNickName());
                    serviceReimbursement.setFlowlevel(serviceFundflowrules.get(0).getTotallevel().longValue());
                    serviceReimbursement.setRecordstatus(99);
@@ -370,8 +430,9 @@
                    if (newSwitch == 1) {
                        aBoolean1 = sendData(serviceReimbursement);
                        if (!aBoolean1) {
                            allMap.put("500", "发送失败");
                            return allMap;
                            // 推送医院协友系统失败:整个审批不生效(事务回滚),允许下次重新审批
                            log.error("差旅审批单上传医院协友系统失败,审批不生效,id={},请重新审批", serviceReimbursement.getId());
                            throw new ServiceException("医院协友系统接收失败,本次审批未生效,请稍后重新审批");
                        }
                    }
                    //保存审批流程表
@@ -380,6 +441,7 @@
                    serviceFundflow.setCheckuserno(user.getUserName());
                    serviceFundflow.setCheckusername(user.getNickName());
                    serviceFundflow.setFundtype(1);
                    serviceFundflow.setCheckTime(new Date());
                    serviceFundflow.setApplytype("0");
                    serviceFundflow.setFlowconclusion(CheckFlag);
                    serviceFundflow.setFlowcontent("通过");
@@ -395,7 +457,7 @@
                List<Integer> roleIds = sysUserRoleMapper.getUserRoleByUserId(user.getUserId());
                if (roleIds != null && roleIds.contains(11)) {
                    //11为财务
//                    serviceReimbursement.setFinancechecher("审批人:" + user.getUserName() + " & 审批时间" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " & 审批结果:通过");
//                    serviceReimbursement.setFinancechecher("审批人:" + user.getNickName() + " & 审批时间" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " & 审批结果:通过");
                    serviceReimbursement.setFinancechecher(user.getNickName());
                }
@@ -415,18 +477,26 @@
                    }
                }
                SysUser sysUser = sysUserService.selectUserByUserName(serviceReimbursement.getUserno());
                ArrayList<ConcurrentHashMap<String, Object>> contentList = new ArrayList<>();
                ConcurrentHashMap map = new ConcurrentHashMap();
                map.put("审批人:", loginUser.getUser().getUserName());
                map.put("审批时间:", new Date());
                map.put("意见:", "不通过");
                if (StringUtils.isNotBlank(checkFundVO.getFlowcontent())) map.put("意见:", checkFundVO.getFlowcontent());
                contentList.add(map);
                DingTalkReqVo dingTalkReqVo = new DingTalkReqVo();
                dingTalkReqVo.setTitle("财务系统驳回信息");
                dingTalkReqVo.setNumber(sysUser.getPhonenumber());
                dingTalkReqVo.setContents(contentList);
                dingTalkService.sendNotification(dingTalkReqVo);
                //审批未通过:单据信息 + 出差信息 + 审批人/审批时间/意见(意见 = "审批未通过。" + 驳回意见)
                List<ConcurrentHashMap<String, Object>> contentList = FundNotifyMessageBuilder.newRows();
                FundNotifyMessageBuilder.addBillInfo(contentList, "0", serviceReimbursement.getUsername(),
                        serviceReimbursement.getAmountrequested(), null,
                        FundNotifyMessageBuilder.billNo(serviceReimbursement.getBh(),
                                serviceReimbursement.getId()));
                FundNotifyMessageBuilder.addTravelInfo(contentList, serviceReimbursement.getTravelers(),
                        serviceReimbursement.getReason());
                FundNotifyMessageBuilder.addAuditResult(contentList, loginUser.getUser().getNickName(), new Date(),
                        FundNotifyMessageBuilder.opinion(FundNotifyMessageBuilder.CONCLUSION_REJECT,
                                checkFundVO.getFlowcontent()));
                try {
                    DingTalkReqVo dingTalkReqVo = new DingTalkReqVo();
                    dingTalkReqVo.setTitle(FundNotifyMessageBuilder.TITLE);
                    dingTalkReqVo.setNumber(sysUser.getPhonenumber());
                    dingTalkReqVo.setContents(contentList);
                    dingTalkService.sendNotification(dingTalkReqVo);
                } catch (Exception e) {
                    log.error("差旅---审批未通过钉钉通知失败,id={}", serviceReimbursement.getId(), e);
                }
            }
            serviceReimbursement.setRecordstatus(RecordStatus);
@@ -436,6 +506,7 @@
            serviceFundflow.setFundid(serviceReimbursement.getId());
            serviceFundflow.setCheckuserno(user.getUserName());
            serviceFundflow.setCheckusername(user.getNickName());
            serviceFundflow.setCheckTime(new Date());
            serviceFundflow.setFundtype(1);
            serviceFundflow.setApplytype("0");
            serviceFundflow.setFlowconclusion(CheckFlag);
@@ -465,21 +536,39 @@
                }
            }
            //053审批通过之后,就需要把“办公室主任”的名字填上
            if (checkFundVO.getFlowconclusion() == 1 && user.getUserName().equals("053")) {
                serviceReimbursement.setOfficedirector(user.getNickName());
            //办公室主任审批通过之后,就需要把“办公室主任”的名字填上
            SysUser sysUser = null;
            if (StringUtils.isNotEmpty(user.getUserName())) {
                sysUser = sysUserMapper.selectUserByUserName(user.getUserName());
                log.info("差旅sysUsers返回的值为:{}", sysUser);
            }
            // 2026-10-09:推送条件由"当前审核人有 officedirector 角色"改为"本次审批后到达最后一级"。
            // 原写法在"最后一级审核人没有该角色"时永远不会推送,而"非最后一级的 officedirector"会提前推送。
            boolean uploadAtLastLevel = checkFundVO.getFlowconclusion() == 1
                    && totalLevel != null && totalLevel != 0 && totalLevel == OriginalFlowLevel + 1;
            if (uploadAtLastLevel) {
                // 仍只在该角色审批时记录办公室主任,保持字段语义不变
                if (Objects.nonNull(sysUser) && sysUser.getRoles() != null
                        && sysUser.getRoles().stream().anyMatch(role -> "officedirector".equals(role.getRoleKey()))) {
                    serviceReimbursement.setOfficedirector(user.getNickName());
                }
                serviceReimbursement.setUploadStates(1);
                Boolean aBoolean1 = null;
                if (newSwitch == 1) {
                    log.info("差旅newSwitch返回的值为:{}", newSwitch);
                    aBoolean1 = sendData(serviceReimbursement);
                    if (!aBoolean1) {
                        allMap.put("500", "发送失败");
                        return allMap;
                        // 推送医院协友系统失败:整个审批不生效(事务回滚),允许下次重新审批
                        log.error("差旅审批单上传医院协友系统失败,审批不生效,id={},请重新审批", serviceReimbursement.getId());
                        throw new ServiceException("医院协友系统接收失败,本次审批未生效,请稍后重新审批");
                    }
                }
            }
//            if (StringUtils.isNotEmpty(serviceReimbursement.getManagername()) && serviceReimbursement.getManagername().equals(loginUser.getUser().getNickName())) {
//                serviceReimbursement.setManagername("审批人:" + serviceReimbursement.getManagername() + " & 审批时间" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + " & 审批结果:通过");
//            }
            updateById(serviceReimbursement);
            ServiceSystemmessage serviceSystemmessage = new ServiceSystemmessage();
@@ -518,23 +607,75 @@
    }
    public Boolean sendData(ServiceReimbursement serviceReimbursement) {
        // fund和funddetail的数据获取
        addSharedData(serviceReimbursement.getId());
        List<ServiceReimbursementShared> serviceReimbursementSharedList = sharedService.getRemShareInfoByRemId(serviceReimbursement.getId());
        if (org.springframework.util.CollectionUtils.isEmpty(serviceReimbursementSharedList)) return false;
    public String getLastApprovalInfo(List<ServiceFundflow> serviceFundflows, String managerName) {
        if (StringUtils.isEmpty(managerName)) return null;
        if (org.springframework.util.CollectionUtils.isEmpty(serviceFundflows)) {
            //如果是最后一个人审批,这个时候可能flow里还没有生成进去
            SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return "审批人:" + managerName + " & 审批时间:" + sd.format(new Date()) + " & 审批结果:通过";
        }
        String mn = managerName.trim();
        Optional<ServiceFundflow> lastApproval = serviceFundflows.stream().filter(flow -> flow.getCheckusername().contains(mn)).max(Comparator.comparing(ServiceFundflow::getCreateTime));
        if (lastApproval.isPresent()) {
            ServiceFundflow flow = lastApproval.get();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            if (flow.getCheckTime() == null) {
                flow.setCheckTime(new Date());
            }
            String formattedTime = sdf.format(flow.getCheckTime());
            return "审批人:" + managerName + " & 审批时间:" + formattedTime + " & 审批结果:通过";
        }
        return "未找到审批记录";
    }
    /**
     * 审批单上传医院协友(致远)系统。
     *
     * <p>2026-10-09:外层包一层兜底,保证**任何异常都不会向外抛**(原来 strRes 为 null 时
     * 会在 parseObject 后取 code 触发 NPE,把整个审批请求打成 500)。
     * 返回 false 表示推送失败,调用方按"审批不生效、允许下次重新审批"处理。
     */
    public Boolean sendData(ServiceReimbursement serviceReimbursement) {
        if (!isUploadOaEnabled()) {
            // 上传开关关闭(如测试环境):跳过上传并视为成功,绝不能因此阻断审批
            log.info("审批单上传医院协友系统已关闭(sys.approval.upload.oa != 1),跳过上传并视为成功,id={}",
                    serviceReimbursement == null ? null : serviceReimbursement.getId());
            return true;
        }
        try {
            return doSendData(serviceReimbursement);
        } catch (Throwable t) {
            log.error("差旅审批单上传医院协友系统异常,审批不生效,id={}",
                    serviceReimbursement == null ? null : serviceReimbursement.getId(), t);
            return false;
        }
    }
    private Boolean doSendData(ServiceReimbursement serviceReimbursement) {
        // fund和funddetail的数据获取
        // 2026-10-09:接住 addSharedData 的失败信号(附件上传失败时它会回滚分享表并返回 false)
        Boolean sharedOk = addSharedData(serviceReimbursement.getId());
        if (sharedOk == null || !sharedOk) {
            log.error("差旅报销单上传失败:分享表/附件环节失败,审批不生效,id={}", serviceReimbursement.getId());
            return false;
        }
        List<ServiceReimbursementShared> serviceReimbursementSharedList = sharedService.getRemShareInfoByRemId(serviceReimbursement.getId());
        if (org.springframework.util.CollectionUtils.isEmpty(serviceReimbursementSharedList)) {
            log.error("差旅报销单上传失败:分享表为空(附件或组装环节异常),审批不生效,id={}", serviceReimbursement.getId());
            return false;
        }
        log.info("serviceReimbursementSharedList的数据量为:{}", serviceReimbursementSharedList.size());
        //detail详情
        ServiceReimbursementdetailShared serviceReimbursementdetailShared = new ServiceReimbursementdetailShared();
        serviceReimbursementdetailShared.setRbid(serviceReimbursementSharedList.get(0).getId());
        List<ServiceReimbursementdetailShared> serviceReimbursementdetailShareds = detailSharedService.queryList(serviceReimbursementdetailShared);
        List<ServiceReimbursementdetail> serviceReimbursementdetailList = serviceReimbursementdetailMapper.getAllDetailsByRBID(serviceReimbursement.getId());
        //payee详情
        ServiceReimbursementpayeeShared serviceReimbursementpayeeShared = new ServiceReimbursementpayeeShared();
        serviceReimbursementpayeeShared.setRbid(serviceReimbursementSharedList.get(0).getId());
        List<ServiceReimbursementpayeeShared> serviceReimbursementpayeeShareds = payeeSharedService.queryList(serviceReimbursementpayeeShared);
        ServiceReimbursementpayee serviceReimbursementpayee = new ServiceReimbursementpayee();
        serviceReimbursementpayee.setRbid(serviceReimbursement.getId());
        List<ServiceReimbursementpayee> serviceReimbursementpayees = payeeService.queryList(serviceReimbursementpayee);
        // 数据的封装
@@ -545,14 +686,13 @@
        // 主表字段数据
        Map<String, Object> data2 = new HashMap<>();
        data2.put("formmain_1209", formmain_1209(serviceReimbursementSharedList.get(0)));
        ServiceReimbursement sr = serviceReimbursementMapper.selectById(serviceReimbursement.getId());
        data2.put("formmain_1209", formmain_1209(sr));
        // 明细表字段数据,与附件的处理
        Map<String, List<Map<String, Object>>> map1 = formson_1210(serviceReimbursementdetailShareds);
        Map<String, List<Map<String, Object>>> map1 = formson_1210(serviceReimbursementdetailList);
        data2.put("formson_1210", map1.get("formson_1210"));
        data2.put("thirdAttachments", map1.get("annexfilesList"));
        data2.put("formson_1211", formson_1211(serviceReimbursementpayeeShareds));
        data2.put("formson_1211", formson_1211(serviceReimbursementpayees));
        data.put("data", data2);
        //模板编号,由致远方提供,该参数决定发起协同系统中哪个流程
        data.put("templateCode", "cyfbxd_rzhc_ceshi");
@@ -566,15 +706,13 @@
        data.put("subject", "");
        ServiceReimbursement serviceReimbursement1 = serviceReimbursementMapper.selectById(serviceReimbursement.getId());
        data.put("summaryId", serviceReimbursement1.getSummaryId() == null ? "" : serviceReimbursement1.getSummaryId());
        map.put("data", data);
        String strRes = null;
        if (!active.equals("druid")) {
        if (isUploadOaEnabled()) {
            //如果是本地环境,就不调这个了
            String token = getToken();
            JSONObject json1 = JSONObject.parseObject(token);
            token = json1.get("id").toString();
            ObjectMapper objectMapper = new ObjectMapper();
            String json = null;
            try {
@@ -601,53 +739,70 @@
            }
        }
        log.error("-----Reimbursement-------------strRes的值为:{}", strRes);
        JSONObject jsonObject = JSONObject.parseObject(strRes);
        if (strRes == null || strRes.trim().isEmpty()) {
            // 医院协友系统无返回(超时/异常/未配置):推送失败,由调用方回滚整个审批
            log.error("差旅审批单上传医院协友系统失败:接口无返回内容,id={}", serviceReimbursement.getId());
            return false;
        }
        JSONObject jsonObject = null;
        try {
            jsonObject = JSONObject.parseObject(strRes);
        } catch (Exception e) {
            log.error("差旅审批单上传医院协友系统失败:返回内容无法解析,id={},strRes={}",
                    serviceReimbursement.getId(), strRes, e);
            return false;
        }
        if (jsonObject == null) {
            log.error("差旅审批单上传医院协友系统失败:返回内容为空,id={},strRes={}",
                    serviceReimbursement.getId(), strRes);
            return false;
        }
        String code = jsonObject.getString("code");
        if (!code.equals("0")) {
        if (code == null || !"0".equals(code)) {
            log.error("差旅审批单上传医院协友系统失败:code={},id={},strRes={}",
                    code, serviceReimbursement.getId(), strRes);
            return false;
        }
        return true;
    }
    private static final AtomicLong COUNTER = new AtomicLong(System.currentTimeMillis());
    private Map<String, List<Map<String, Object>>> formson_1210(List<ServiceReimbursementdetailShared> serviceReimbursementdetailSharedList) {
    private Map<String, List<Map<String, Object>>> formson_1210(List<ServiceReimbursementdetail> serviceReimbursementdetailList) {
        Map<String, List<Map<String, Object>>> allMap = new HashMap<>();
        List<Map<String, Object>> list = new ArrayList<>();
        List<Map<String, Object>> annexfilesList = new ArrayList<>();
        for (ServiceReimbursementdetailShared reimbursementdetailShared : serviceReimbursementdetailSharedList) {
        for (ServiceReimbursementdetail reimbursementdetail : serviceReimbursementdetailList) {
            Map<String, Object> map = new HashMap<>();
            map.put("交通工具", reimbursementdetailShared.getTraffictype());
            map.put("交通费", reimbursementdetailShared.getTrafficexpense());
            map.put("市内交通", reimbursementdetailShared.getCityfee());
            map.put("住宿费", reimbursementdetailShared.getHotelexpense());
            map.put("杂费", reimbursementdetailShared.getOtherexpense());
            map.put("伙食费报销", reimbursementdetailShared.getFoodexpenses());
            map.put("伙食费补助", reimbursementdetailShared.getFoodallowance());
            map.put("其他费用", reimbursementdetailShared.getOtherfeeamount());
            map.put("其他费用说明", reimbursementdetailShared.getOtherfeedesc());
            map.put("交通工具", reimbursementdetail.getTraffictype());
            map.put("交通费", reimbursementdetail.getTrafficexpense());
            map.put("市内交通", reimbursementdetail.getCityfee());
            map.put("住宿费", reimbursementdetail.getHotelexpense());
            map.put("杂费", reimbursementdetail.getOtherexpense());
            map.put("伙食费报销", reimbursementdetail.getFoodexpenses());
            map.put("伙食费补助", reimbursementdetail.getFoodallowance());
            map.put("其他费用", reimbursementdetail.getOtherfeeamount());
            map.put("其他费用说明", reimbursementdetail.getOtherfeedesc());
            map.put("金额合计", "");
            map.put("出差时间起", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(reimbursementdetailShared.getStarttime()));
            map.put("出发地点", reimbursementdetailShared.getDeparture());
            map.put("出差时间止", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(reimbursementdetailShared.getEndtime()));
            map.put("出差目的地", reimbursementdetailShared.getDestination());
            map.put("天数", reimbursementdetailShared.getDays());
            BigDecimal total = safe(reimbursementdetailShared.getCityfee()).add(safe(reimbursementdetailShared.getTrafficexpense())).add(safe(reimbursementdetailShared.getHotelexpense())).add(safe(reimbursementdetailShared.getOtherexpense())).add(safe(reimbursementdetailShared.getFoodexpenses())).add(safe(reimbursementdetailShared.getFoodallowance())).add(safe(reimbursementdetailShared.getOtherfeeamount()));
            map.put("出差时间起", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(reimbursementdetail.getStarttime()));
            map.put("出发地点", reimbursementdetail.getDeparture());
            map.put("出差时间止", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(reimbursementdetail.getEndtime()));
            map.put("出差目的地", reimbursementdetail.getDestination());
            map.put("天数", reimbursementdetail.getDays());
            BigDecimal total = safe(reimbursementdetail.getCityfee()).add(safe(reimbursementdetail.getTrafficexpense())).add(safe(reimbursementdetail.getHotelexpense())).add(safe(reimbursementdetail.getOtherexpense())).add(safe(reimbursementdetail.getFoodexpenses())).add(safe(reimbursementdetail.getFoodallowance())).add(safe(reimbursementdetail.getOtherfeeamount()));
            map.put("实际报销金额", total);
            map.put("财务备注", reimbursementdetailShared.getRemark());
            map.put("id", reimbursementdetailShared.getRdid());
            map.put("出差人", reimbursementdetailShared.getPersonname());
            map.put("财务备注", reimbursementdetail.getRemark());
            map.put("id", reimbursementdetail.getId());
            map.put("出差人", reimbursementdetail.getPersonname());
            map.put("回交通工具", "");
            map.put("人员类别", reimbursementdetailShared.getPersontype());
            map.put("人员类别", reimbursementdetail.getPersontype());
            map.put("住宿费标准", "");
            map.put("住宿费标准合计", reimbursementdetailShared.getHotelexpense());
            Long fpuuid = COUNTER.incrementAndGet();
            map.put("住宿费标准合计", reimbursementdetail.getHotelexpense());
            Long fpuuid = IdGeneratorUtils.nextId();
            map.put("发票附件", fpuuid);
            map.put("票据识别", "");
            map.put("识别人", "");
            map.put("序号1", "");
            Long qtuuid = COUNTER.incrementAndGet();
            Long qtuuid = IdGeneratorUtils.nextId();
            map.put("其他附件", qtuuid);
            map.put("个人票夹用户", "");
            map.put("识别票据", "");
@@ -655,8 +810,8 @@
            list.add(map);
            //附件处理
            String annexfiles = reimbursementdetailShared.getAnnexfiles();
            String invoicefiles = reimbursementdetailShared.getInvoicefiles();
            String annexfiles = reimbursementdetail.getAnnexfiles();
            String invoicefiles = reimbursementdetail.getInvoicefiles();
            int i = 0;
            if (StringUtils.isNotEmpty(annexfiles)) {
@@ -691,18 +846,18 @@
        return val == null ? BigDecimal.ZERO : val;
    }
    private List<Map<String, Object>> formson_1211(List<ServiceReimbursementpayeeShared> serviceReimbursementpayeeShareds) {
    private List<Map<String, Object>> formson_1211(List<ServiceReimbursementpayee> serviceReimbursementpayees) {
        Map<String, List<Map<String, Object>>> allMap = new HashMap<>();
        List<Map<String, Object>> list = new ArrayList<>();
        for (ServiceReimbursementpayeeShared serviceReimbursementpayeeShared : serviceReimbursementpayeeShareds) {
        for (ServiceReimbursementpayee serviceReimbursementpayee : serviceReimbursementpayees) {
            Map<String, Object> map = new HashMap<>();
            map.put("收款人", serviceReimbursementpayeeShared.getPersonname());
            map.put("卡号", serviceReimbursementpayeeShared.getBankcardno());
            map.put("开户银行", serviceReimbursementpayeeShared.getBankname());
            map.put("打款金额", serviceReimbursementpayeeShared.getAmount());
            map.put("人员类别打款", serviceReimbursementpayeeShared.getPersontype());
            map.put("收款人", serviceReimbursementpayee.getPersonname());
            map.put("卡号", serviceReimbursementpayee.getBankcardno());
            map.put("开户银行", serviceReimbursementpayee.getBankname());
            map.put("打款金额", serviceReimbursementpayee.getAmount());
            map.put("人员类别打款", serviceReimbursementpayee.getPersontype());
            map.put("核算项目", "");
            map.put("预算项目", "");
            map.put("借方摘要", "");
@@ -712,43 +867,53 @@
        return list;
    }
    private Map<String, Object> formmain_1209(ServiceReimbursementShared serviceReimbursementShared) {
    private Map<String, Object> formmain_1209(ServiceReimbursement serviceReimbursement) {
        ServiceFundflow serviceFundflow = new ServiceFundflow();
        serviceFundflow.setFundid(serviceReimbursement.getId());
        serviceFundflow.setFundtype(1);
        List<ServiceFundflow> serviceFundflows = serviceFundflowService.queryList(serviceFundflow);
        Map<String, Object> formmain_1209 = new HashMap<>();
        formmain_1209.put("报销日期", new SimpleDateFormat("yyyy-MM-dd HH:mm").format(serviceReimbursementShared.getApplyTime()));
        formmain_1209.put("报销日期", new SimpleDateFormat("yyyy-MM-dd HH:mm").format(serviceReimbursement.getApplyTime()));
        formmain_1209.put("出差人-作废", "");
        formmain_1209.put("报销人", serviceReimbursementShared.getUsername());
        formmain_1209.put("区域组长", serviceReimbursementShared.getManagername());
        formmain_1209.put("出差事由", serviceReimbursementShared.getReason());
        formmain_1209.put("报销人", serviceReimbursement.getUsername());
        formmain_1209.put("区域组长", serviceReimbursement.getManagername());
        formmain_1209.put("出差事由", serviceReimbursement.getReason());
        formmain_1209.put("天数合计", 0.00);
        formmain_1209.put("交通费合计", serviceReimbursementShared.getTotalamount());
        formmain_1209.put("交通费合计", serviceReimbursement.getTotalamount());
        formmain_1209.put("市内交通合计", 0.00);
        formmain_1209.put("住宿费合计", 0.00);
        formmain_1209.put("杂费合计", 0.00);
        formmain_1209.put("伙食费报销合计", 0.00);
        formmain_1209.put("伙食费补助合计", 0.00);
        formmain_1209.put("其他费用合计", 0.00);
        formmain_1209.put("领款金额大写", serviceReimbursementShared.getBigstrmoney());
        formmain_1209.put("领款金额", serviceReimbursementShared.getAmountrequested());
        formmain_1209.put("领款金额大写", serviceReimbursement.getBigstrmoney());
        formmain_1209.put("领款金额", serviceReimbursement.getAmountrequested());
        formmain_1209.put("财务审批", "");
        formmain_1209.put("财务部负责人审批", serviceReimbursementShared.getFinancedirector());
        formmain_1209.put("办公室主任审批", serviceReimbursementShared.getOfficedirector());
        formmain_1209.put("备注", serviceReimbursementShared.getRemark());
        formmain_1209.put("业务副院长审批", serviceReimbursementShared.getBusvicepresident());
        formmain_1209.put("财务副院长审批", serviceReimbursementShared.getFinvicepresident());
        formmain_1209.put("中心负责人审批", serviceReimbursementShared.getOpochecker());
        formmain_1209.put("财务部负责人审批", getLastApprovalInfo(serviceFundflows, serviceReimbursement.getFinancedirector()));
        if (serviceReimbursement.getBackflowlevel() == 3)
            formmain_1209.put("办公室主任审批", "审批人:吴志强 & 审批时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " & 审批结果:通过");
        else formmain_1209.put("办公室主任审批", getLastApprovalInfo(serviceFundflows, "吴志强"));
        formmain_1209.put("备注", serviceReimbursement.getRemark());
        formmain_1209.put("业务副院长审批", serviceReimbursement.getBusvicepresident());
        formmain_1209.put("财务副院长审批", serviceReimbursement.getFinvicepresident());
        formmain_1209.put("中心负责人审批", serviceReimbursement.getOpochecker());
        formmain_1209.put("开户银行-作废", "");
        formmain_1209.put("卡号-作废", "");
        formmain_1209.put("支付方式", serviceReimbursementShared.getZffs());
        formmain_1209.put("组长", serviceReimbursementShared.getManagername());
        formmain_1209.put("审批人员", serviceReimbursementShared.getFinancechecher());
        formmain_1209.put("支付日期", serviceReimbursementShared.getRiqi());
        formmain_1209.put("支付方式", serviceReimbursement.getZffs());
        String lastApprovalInfo = getLastApprovalInfo(serviceFundflows, serviceReimbursement.getManagername());
        formmain_1209.put("组长", lastApprovalInfo.contains("吴志强") ? null : lastApprovalInfo);
        formmain_1209.put("审批人员", getLastApprovalInfo(serviceFundflows, "陈慕华"));
        formmain_1209.put("支付日期", serviceReimbursement.getRiqi());
        formmain_1209.put("上传附件", "");
        formmain_1209.put("打款合计", 0.00);
        formmain_1209.put("发票识别-作废", "");
        formmain_1209.put("识别人-作废", "");
        formmain_1209.put("财务审批签字", "");
        formmain_1209.put("财务部负责人审批签字", serviceReimbursementShared.getFinancedirector());
        formmain_1209.put("财务部负责人审批签字", getLastApprovalInfo(serviceFundflows, serviceReimbursement.getFinancedirector()));
        formmain_1209.put("表单编号1", "");
        formmain_1209.put("CIF账套配置1", "");
        formmain_1209.put("院区", "");
@@ -762,13 +927,13 @@
        formmain_1209.put("表单附件", "");
        formmain_1209.put("10204", "");
        formmain_1209.put("现金流量分析", "");
        formmain_1209.put("捐献者", serviceReimbursementShared.getDonorname());
        formmain_1209.put("捐献者", serviceReimbursement.getDonorname());
        formmain_1209.put("凭证类别", "");
        formmain_1209.put("合计", 0.00);
        formmain_1209.put("实际合计", 0.00);
        formmain_1209.put("伙食补助合计", 0.00);
        formmain_1209.put("历史审批记录", "");
        formmain_1209.put("表单编号", serviceReimbursementShared.getReimid());
        formmain_1209.put("表单编号", serviceReimbursement.getId());
        formmain_1209.put("历史审批巨鹿查询", "");
        return formmain_1209;
    }
@@ -776,7 +941,6 @@
    public int uploadOAFileAndUpdateDb(ServiceReimbursementdetailShared remShare) throws Exception {
        log.info("uploadOAFileAndUpdate方法的入参:{}", remShare);
        System.out.println("uploadOAFileAndUpdate方法的入参:" + remShare);
        //上传OA文件
        String strRes = getToken();
@@ -814,6 +978,7 @@
        System.out.println("uploadOAFileAndUpdateDb + jsonObject" + jsonObj.toString() + "\r\n" + jsonObj.toJSONString());
        String strRes = HttpClientKit.postOpr(strUrl, jsonObj.toString());
        log.info("-----------------strRes-----的值为:{}", strRes);
        return strRes;
    }
@@ -825,9 +990,17 @@
                log.info("filePath的修改:{}", filePath);
                String url = rbDetailFile.getUrl();
                //file用的是绝对位置
                String fileName = url.substring(url.indexOf("/profile/upload") + "/profile/upload".length());
                // 2026-10-09:附件地址解析加固,避免 url 异常/文件缺失时抛 NPE 导致看不到失败原因
                int profileIdx = url == null ? -1 : url.indexOf("/profile/upload");
                if (profileIdx < 0) {
                    throw new ServiceException("附件地址格式不正确(缺少 /profile/upload),无法上传协友:" + url);
                }
                String fileName = url.substring(profileIdx + "/profile/upload".length());
                String strFile = rbDetailFile.getUrl().replace(filePath, "/profile/upload");
                File fileUpload = new File(filePath + fileName);
                if (!fileUpload.exists()) {
                    throw new ServiceException("附件文件在服务器上不存在,无法上传协友:" + fileUpload.getAbsolutePath());
                }
                log.info("请求第三方的入参strFile : {}, strFUrl : {}", strFile, filePath);
                String struploadResult = HttpClientKit.sendPostWithFile(fileUpload, strFUrl);
                log.info("第三方传回的数据: {}", struploadResult);