|
|
@@ -9,6 +9,7 @@ import com.management.platform.constant.Constant;
|
|
|
import com.management.platform.entity.*;
|
|
|
import com.management.platform.entity.bo.*;
|
|
|
import com.management.platform.mapper.*;
|
|
|
+import com.management.platform.service.ExpenseSheetService;
|
|
|
import com.management.platform.service.FeishuInfoService;
|
|
|
import com.management.platform.service.UserFvTimeService;
|
|
|
import com.management.platform.util.HttpRespMsg;
|
|
|
@@ -28,6 +29,7 @@ import java.math.RoundingMode;
|
|
|
import java.text.SimpleDateFormat;
|
|
|
import java.time.*;
|
|
|
import java.time.format.DateTimeFormatter;
|
|
|
+import java.time.temporal.ChronoUnit;
|
|
|
import java.util.*;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
@@ -74,6 +76,13 @@ public class FeishuInfoServiceImpl extends ServiceImpl<FeishuInfoMapper, FeishuI
|
|
|
|
|
|
public static final String GET_APPROVAL_INSTANCE_LIST = "https://open.feishu.cn/open-apis/approval/v4/instances/query";
|
|
|
|
|
|
+ public static final String GET_APPROVAL_INSTANCE_INFO = "https://open.feishu.cn/open-apis/approval/v4/instances/:instance_id";
|
|
|
+
|
|
|
+ public static final Map<Integer, String> EXPENSE_APPROVAL_CODE_MAP = new HashMap<>();
|
|
|
+ static {
|
|
|
+ //医智锐科技
|
|
|
+ EXPENSE_APPROVAL_CODE_MAP.put(8484, "E17B8057-1847-4BA2-8DDF-BBD28C57B909");
|
|
|
+ }
|
|
|
|
|
|
@Resource
|
|
|
FeishuInfoMapper feishuInfoMapper;
|
|
|
@@ -88,12 +97,24 @@ public class FeishuInfoServiceImpl extends ServiceImpl<FeishuInfoMapper, FeishuI
|
|
|
UserFvTimeMapper userFvTimeMapper;
|
|
|
@Resource
|
|
|
LeaveSheetMapper leaveSheetMapper;
|
|
|
+ @Resource
|
|
|
+ ExpenseSheetMapper expenseSheetMapper;
|
|
|
+ @Resource
|
|
|
+ ExpenseItemMapper expenseItemMapper;
|
|
|
+ @Resource
|
|
|
+ ProjectMapper projectMapper;
|
|
|
@Autowired
|
|
|
private RestTemplate restTemplate;
|
|
|
@Autowired
|
|
|
private TimeTypeMapper timeTypeMapper;
|
|
|
@Autowired
|
|
|
private UserFvTimeService userFvTimeService;
|
|
|
+ @Autowired
|
|
|
+ private ExpenseSheetService expenseSheetService;
|
|
|
+ @Autowired
|
|
|
+ private ExpenseTypeMapper expenseTypeMapper;
|
|
|
+ @Autowired
|
|
|
+ private ExpenseMainTypeMapper expenseMainTypeMapper;
|
|
|
|
|
|
@Override
|
|
|
public String getAppAccessToken(FeishuInfo feishuInfo) {
|
|
|
@@ -123,6 +144,12 @@ public class FeishuInfoServiceImpl extends ServiceImpl<FeishuInfoMapper, FeishuI
|
|
|
String result = "";
|
|
|
FeishuInfo feishuInfo = getOne(new QueryWrapper<FeishuInfo>().eq("app_id", appId));
|
|
|
if (feishuInfo != null) {
|
|
|
+ //先取数据库里面的,如果过期时间小于当前时间,重新获取
|
|
|
+ LocalDateTime expireTime = feishuInfo.getExpireTime();
|
|
|
+ if (expireTime.isAfter(LocalDateTime.now())) {
|
|
|
+ System.out.println("读取到缓存的token======" + feishuInfo.getAccessToken());
|
|
|
+ return feishuInfo.getAccessToken();
|
|
|
+ }
|
|
|
String url = GET_TENANT_ACCESS_TOKEN;
|
|
|
HttpHeaders headers = new HttpHeaders();
|
|
|
RestTemplate restTemplate = new RestTemplate();
|
|
|
@@ -954,9 +981,515 @@ public class FeishuInfoServiceImpl extends ServiceImpl<FeishuInfoMapper, FeishuI
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public HttpRespMsg getExpenseFeeResult(FeishuInfo feishuInfo, User targetUser, String startDate, String endDate) {
|
|
|
+ public HttpRespMsg getExpenseFeeResult(FeishuInfo feishuInfo, User targetUser, String startDate, String endDate) throws Exception {
|
|
|
+ HttpRespMsg msg = new HttpRespMsg();
|
|
|
+
|
|
|
+ if (feishuInfo == null) {
|
|
|
+ msg.setError("飞书信息不能为空");
|
|
|
+ return msg;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 第一步:调用GET_APPROVAL_INSTANCE_LIST获取审批实例列表
|
|
|
+ System.out.println("========== 开始获取费用报销审批实例列表 ==========");
|
|
|
+ System.out.println("开始时间: " + startDate + ", 结束时间: " + endDate);
|
|
|
+ String userId = targetUser == null?null:targetUser.getJobNumber();
|
|
|
+
|
|
|
+ //日期间隔如果超过30天,需要分批查询
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
|
|
|
+ LocalDate start = LocalDate.parse(startDate, formatter);
|
|
|
+ LocalDate end = LocalDate.parse(endDate, formatter);
|
|
|
+ long daysBetween = ChronoUnit.DAYS.between(start, end);
|
|
|
+ JSONArray instanceList = null;
|
|
|
+ if (daysBetween > 29) {
|
|
|
+ instanceList = new JSONArray();
|
|
|
+ for (LocalDate fromDate = start; !fromDate.isAfter(end); fromDate = fromDate.plusDays(30)) {
|
|
|
+ LocalDate toDate = fromDate.plusDays(29);
|
|
|
+ if (toDate.isAfter(end)) {
|
|
|
+ toDate = end;
|
|
|
+ }
|
|
|
+ System.out.println("分批查询fromDate=" + fromDate + ", toDate=" + toDate);
|
|
|
+ JSONArray tmpList = getApprovalInstanceList(feishuInfo.getCompanyId(), feishuInfo.getAppId(), formatter.format(fromDate), formatter.format(toDate), userId);
|
|
|
+ if (tmpList != null && tmpList.size() > 0) {
|
|
|
+ instanceList.addAll(tmpList);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ } else{
|
|
|
+ instanceList = getApprovalInstanceList(feishuInfo.getCompanyId(), feishuInfo.getAppId(), startDate, endDate, userId);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if (instanceList == null || instanceList.size() == 0) {
|
|
|
+ System.out.println("未查询到费用报销审批实例");
|
|
|
+ msg.setData(new JSONArray());
|
|
|
+ return msg;
|
|
|
+ }
|
|
|
+
|
|
|
+ System.out.println("查询到审批实例数量: " + instanceList.size());
|
|
|
+
|
|
|
+ // 第二步:遍历实例列表,调用GET_APPROVAL_INSTANCE_INFO获取每个实例的详情并解析存储
|
|
|
+ int successCount = 0;
|
|
|
+ int skipCount = 0;
|
|
|
+ int errorCount = 0;
|
|
|
+
|
|
|
+ List<String> instanceCodeList = new ArrayList<>();
|
|
|
+ for (int i = 0; i < instanceList.size(); i++) {
|
|
|
+ JSONObject instance = instanceList.getJSONObject(i).getJSONObject("instance");
|
|
|
+ String instanceCode = instance.getString("code");
|
|
|
+ instanceCodeList.add(instanceCode);
|
|
|
+ }
|
|
|
+ List<ExpenseSheet> oldExpenseSheetList = expenseSheetMapper.selectList(
|
|
|
+ new QueryWrapper<ExpenseSheet>().eq("company_id", feishuInfo.getCompanyId()).in("instance_code", instanceCodeList));
|
|
|
+ List<ExpenseSheet> needResyncProjectExpenseSheetList = new ArrayList<>();
|
|
|
+ //查询项目没有匹配上的数据
|
|
|
+ if (oldExpenseSheetList.size() > 0) {
|
|
|
+ List<Integer> sheetIds = oldExpenseSheetList.stream().map(ExpenseSheet::getId).collect(Collectors.toList());
|
|
|
+ List<ExpenseItem> noProjectItemList = expenseItemMapper.selectList(new QueryWrapper<ExpenseItem>().select("expense_id").in("expense_id", sheetIds).isNull("project_id"));
|
|
|
+ //取到没有项目的报销单
|
|
|
+ final List<Integer> expenseIds = noProjectItemList.stream().map(ExpenseItem::getExpenseId).distinct().collect(Collectors.toList());
|
|
|
+ needResyncProjectExpenseSheetList = oldExpenseSheetList.stream().filter(es -> expenseIds.contains(es.getId())).collect(Collectors.toList());
|
|
|
+ }
|
|
|
+ for (int i = 0; i < instanceList.size(); i++) {
|
|
|
+ JSONObject instance = instanceList.getJSONObject(i).getJSONObject("instance");
|
|
|
+ String instanceCode = instance.getString("code");
|
|
|
+
|
|
|
+ System.out.println("========== 处理第 " + (i + 1) + " 个实例 ==========");
|
|
|
+ System.out.println("实例ID: " + instanceCode);
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 检查是否已存在
|
|
|
+ ExpenseSheet oldItem = oldExpenseSheetList.stream().filter(item -> item.getInstanceCode().equals(instanceCode)).findFirst().orElse(null);
|
|
|
+ boolean needRefresh = needResyncProjectExpenseSheetList.stream().anyMatch(item -> item.getInstanceCode().equals(instanceCode));
|
|
|
+ System.out.println("模板编码:"+instanceCode+", 需要刷新=" + needRefresh);
|
|
|
+ if (oldItem != null && !needRefresh) {
|
|
|
+ System.out.println("报销单已存在,且无需刷新项目,跳过处理。instance_code: " + instanceCode);
|
|
|
+ skipCount++;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 调用接口获取实例详情
|
|
|
+ JSONObject instanceDetail = getApprovalInstanceInfo(feishuInfo.getAppId(), instanceCode);
|
|
|
+
|
|
|
+ if (instanceDetail != null) {
|
|
|
+ // 解析并存储数据
|
|
|
+ boolean parseResult = parseAndSaveExpenseData(instanceDetail, feishuInfo.getCompanyId(), oldItem);
|
|
|
+ if (parseResult) {
|
|
|
+ successCount++;
|
|
|
+ System.out.println("报销单处理成功。instance_code: " + instanceCode);
|
|
|
+ } else {
|
|
|
+ errorCount++;
|
|
|
+ System.out.println("报销单处理失败。instance_code: " + instanceCode);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ errorCount++;
|
|
|
+ System.out.println("获取实例详情失败,实例ID: " + instanceCode);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ errorCount++;
|
|
|
+ System.out.println("处理实例异常,实例ID: " + instanceCode + ", 异常信息: " + e.getMessage());
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ System.out.println("========== 费用报销数据同步完成 ==========");
|
|
|
+ System.out.println("总数: " + instanceList.size() + ", 成功: " + successCount + ", 跳过: " + skipCount + ", 失败: " + errorCount);
|
|
|
+
|
|
|
+ JSONObject resultData = new JSONObject();
|
|
|
+ resultData.put("total", instanceList.size());
|
|
|
+ resultData.put("success", successCount);
|
|
|
+ resultData.put("skip", skipCount);
|
|
|
+ resultData.put("error", errorCount);
|
|
|
+ msg.setData(resultData);
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.out.println("获取费用报销数据异常: " + e.getMessage());
|
|
|
+ e.printStackTrace();
|
|
|
+ throw e;
|
|
|
+ }
|
|
|
+
|
|
|
+ return msg;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解析并保存报销单数据
|
|
|
+ * @param instanceDetail 实例详情
|
|
|
+ * @param companyId 公司ID
|
|
|
+ * @return 是否成功
|
|
|
+ */
|
|
|
+ private boolean parseAndSaveExpenseData(JSONObject instanceDetail, Integer companyId, ExpenseSheet expenseSheet) {
|
|
|
+ try {
|
|
|
+ // 解析基本信息
|
|
|
+ String instanceCode = instanceDetail.getString("instance_code");
|
|
|
+ String userId = instanceDetail.getString("user_id");
|
|
|
+ String serialNumber = instanceDetail.getString("serial_number");
|
|
|
+ String status = instanceDetail.getString("status");
|
|
|
+ Long startTime = instanceDetail.getLong("start_time");
|
|
|
+ String formStr = instanceDetail.getString("form");
|
|
|
+
|
|
|
+ // 根据user_id查询用户信息
|
|
|
+ User user = userMapper.selectOne(
|
|
|
+ new QueryWrapper<User>()
|
|
|
+ .eq("job_number", userId)
|
|
|
+ .eq("company_id", companyId)
|
|
|
+ );
|
|
|
+
|
|
|
+ if (user == null) {
|
|
|
+ System.out.println("未找到用户,job_number: " + userId);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 解析form字段
|
|
|
+ JSONArray formArray = JSONArray.parseArray(formStr);
|
|
|
+
|
|
|
+ // 提取关键字段
|
|
|
+ String expenseType = null; // 报销类型
|
|
|
+ String expenseReason = null; // 报销事由
|
|
|
+ String projectCode = null; // 项目编号
|
|
|
+ Double totalAmount = null; // 费用汇总
|
|
|
+ JSONArray expenseDetails = null; // 费用明细
|
|
|
+
|
|
|
+ for (int i = 0; i < formArray.size(); i++) {
|
|
|
+ JSONObject formItem = formArray.getJSONObject(i);
|
|
|
+ String name = formItem.getString("name");
|
|
|
+
|
|
|
+ if ("报销类型".equals(name)) {
|
|
|
+ expenseType = formItem.getString("value");
|
|
|
+ } else if ("报销事由".equals(name)) {
|
|
|
+ expenseReason = formItem.getString("value");
|
|
|
+ } else if ("项目编号".equals(name)) {
|
|
|
+ projectCode = formItem.getString("value");
|
|
|
+ } else if ("费用汇总".equals(name)) {
|
|
|
+ Object valueObj = formItem.get("value");
|
|
|
+ if (valueObj instanceof Number) {
|
|
|
+ totalAmount = ((Number) valueObj).doubleValue();
|
|
|
+ } else if (valueObj instanceof String) {
|
|
|
+ totalAmount = Double.parseDouble((String) valueObj);
|
|
|
+ }
|
|
|
+ } else if ("费用明细".equals(name)) {
|
|
|
+ expenseDetails = formItem.getJSONArray("value");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 根据项目编号查询项目ID
|
|
|
+ Integer projectId = null;
|
|
|
+ if (!StringUtils.isEmpty(projectCode)) {
|
|
|
+ Project project = projectMapper.selectOne(
|
|
|
+ new QueryWrapper<Project>()
|
|
|
+ .eq("project_code", projectCode)
|
|
|
+ .eq("company_id", companyId)
|
|
|
+ );
|
|
|
+ if (project != null) {
|
|
|
+ projectId = project.getId();
|
|
|
+ } else {
|
|
|
+ System.out.println("未找到项目,project_code: " + projectCode);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建ExpenseSheet对象
|
|
|
+ boolean sheetExists = expenseSheet != null;
|
|
|
+ if (expenseSheet == null) {
|
|
|
+ expenseSheet = new ExpenseSheet();
|
|
|
+ expenseSheet.setCompanyId(companyId);
|
|
|
+ expenseSheet.setOwnerId(user.getId());
|
|
|
+ expenseSheet.setOwnerName(user.getName());
|
|
|
+ expenseSheet.setInstanceCode(instanceCode);
|
|
|
+ expenseSheet.setTotalAmount(totalAmount);
|
|
|
+ expenseSheet.setRemark(expenseReason);
|
|
|
+ expenseSheet.setSendState(1);//已发放
|
|
|
+ //默认为差旅费用
|
|
|
+ ExpenseMainType expenseMainTypeObj = expenseMainTypeMapper.selectOne(new QueryWrapper<ExpenseMainType>().eq("name", expenseType).eq("company_id", companyId));
|
|
|
+ if (expenseMainTypeObj == null) {
|
|
|
+ String defaultExpenseType = "差旅费用";
|
|
|
+ expenseMainTypeObj = expenseMainTypeMapper.selectOne(new QueryWrapper<ExpenseMainType>().eq("name", defaultExpenseType).eq("company_id", companyId));
|
|
|
+ if (expenseMainTypeObj == null) {
|
|
|
+ //默认取第一个类型
|
|
|
+ expenseMainTypeObj = expenseMainTypeMapper.selectOne(new QueryWrapper<ExpenseMainType>().eq("company_id", companyId).last("limit 1"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ expenseSheet.setType(expenseMainTypeObj.getId());
|
|
|
+
|
|
|
+ int ticketNum = expenseDetails == null? 0: expenseDetails.size();
|
|
|
+ expenseSheet.setTicketNum(ticketNum);
|
|
|
+ // 设置创建日期(从startTime转换)
|
|
|
+ if (startTime != null) {
|
|
|
+ LocalDate createDate = Instant.ofEpochMilli(startTime)
|
|
|
+ .atZone(ZoneId.of("Asia/Shanghai"))
|
|
|
+ .toLocalDate();
|
|
|
+ expenseSheet.setCreateDate(createDate);
|
|
|
+ }
|
|
|
+ HttpRespMsg msg = expenseSheetService.getNextCode(user.getId());
|
|
|
+ expenseSheet.setCode((String)msg.getData());
|
|
|
+
|
|
|
+
|
|
|
+ // 设置状态:根据飞书审批状态映射
|
|
|
+ // PENDING-待审核, APPROVED-审核通过, REJECTED-驳回, CANCELED-已撤回
|
|
|
+ Integer sheetStatus = 1; // 默认待审核
|
|
|
+ if ("APPROVED".equals(status)) {
|
|
|
+ sheetStatus = 0; // 审核通过
|
|
|
+ } else if ("REJECTED".equals(status)) {
|
|
|
+ sheetStatus = 2; // 驳回
|
|
|
+ } else if ("CANCELED".equals(status)) {
|
|
|
+ sheetStatus = 3; // 已撤回
|
|
|
+ } else if ("PENDING".equals(status)) {
|
|
|
+ sheetStatus = 1; // 待审核
|
|
|
+ }
|
|
|
+ expenseSheet.setStatus(sheetStatus);
|
|
|
+
|
|
|
+ // 插入ExpenseSheet
|
|
|
+ int insertResult = expenseSheetMapper.insert(expenseSheet);
|
|
|
+ if (insertResult <= 0) {
|
|
|
+ System.out.println("插入ExpenseSheet失败");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ int sheetStatus = expenseSheet.getStatus();
|
|
|
+
|
|
|
+ Integer expenseSheetId = expenseSheet.getId();
|
|
|
+ System.out.println("插入ExpenseSheet成功,ID: " + expenseSheetId);
|
|
|
+
|
|
|
+ //先删除老的吧
|
|
|
+ if (sheetExists) {
|
|
|
+ expenseItemMapper.delete(new QueryWrapper<ExpenseItem>().eq("expense_id", expenseSheetId));
|
|
|
+ }
|
|
|
+ // 解析并插入费用明细
|
|
|
+ if (expenseDetails != null && expenseDetails.size() > 0) {
|
|
|
+ DateTimeFormatter dateFormatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
|
|
|
+
|
|
|
+ for (int i = 0; i < expenseDetails.size(); i++) {
|
|
|
+ JSONArray detailArray = expenseDetails.getJSONArray(i);
|
|
|
+
|
|
|
+ String content = null; // 内容
|
|
|
+ String happenDate = null; // 日期
|
|
|
+ Double amount = null; // 金额
|
|
|
+
|
|
|
+ for (int j = 0; j < detailArray.size(); j++) {
|
|
|
+ JSONObject detailItem = detailArray.getJSONObject(j);
|
|
|
+ String itemName = detailItem.getString("name");
|
|
|
+
|
|
|
+ if ("内容".equals(itemName)) {
|
|
|
+ content = detailItem.getString("value");
|
|
|
+ } else if ("日期(年-月-日)".equals(itemName)) {
|
|
|
+ String dateValue = detailItem.getString("value");
|
|
|
+ if (!StringUtils.isEmpty(dateValue)) {
|
|
|
+ try {
|
|
|
+ // 解析ISO 8601格式的日期时间
|
|
|
+ LocalDateTime dateTime = LocalDateTime.parse(dateValue, dateFormatter);
|
|
|
+ happenDate = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.out.println("日期解析失败: " + dateValue);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if ("金额".equals(itemName)) {
|
|
|
+ Object amountObj = detailItem.get("value");
|
|
|
+ if (amountObj instanceof Number) {
|
|
|
+ amount = ((Number) amountObj).doubleValue();
|
|
|
+ } else if (amountObj instanceof String) {
|
|
|
+ amount = Double.parseDouble((String) amountObj);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建ExpenseItem对象
|
|
|
+ ExpenseItem expenseItem = new ExpenseItem();
|
|
|
+ expenseItem.setExpenseId(expenseSheetId);
|
|
|
+ expenseItem.setProjectId(projectId); // 每个明细都设置项目ID
|
|
|
+ expenseItem.setProjectCode(projectCode);
|
|
|
+ expenseItem.setHappenDate(happenDate);
|
|
|
+ expenseItem.setAmount(amount);
|
|
|
+// expenseItem.setRemark(content);
|
|
|
+ expenseItem.setInvoiceType(1);//默认增值税普通发票
|
|
|
+ expenseItem.setExpenseType(expenseType);
|
|
|
+ expenseItem.setStatus(sheetStatus); // 与主表状态保持一致
|
|
|
+
|
|
|
+ // 插入ExpenseItem
|
|
|
+ int itemInsertResult = expenseItemMapper.insert(expenseItem);
|
|
|
+ if (itemInsertResult <= 0) {
|
|
|
+ System.out.println("插入ExpenseItem失败,明细索引: " + i);
|
|
|
+ } else {
|
|
|
+ System.out.println("插入ExpenseItem成功,ID: " + expenseItem.getId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.out.println("解析并保存报销单数据异常: " + e.getMessage());
|
|
|
+ e.printStackTrace();
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取审批实例列表
|
|
|
+ * @param appId 应用ID
|
|
|
+ * @param startDate 开始时间 格式:yyyyMMdd
|
|
|
+ * @param endDate 结束时间 格式:yyyyMMdd
|
|
|
+ * @return 审批实例列表
|
|
|
+ */
|
|
|
+ private JSONArray getApprovalInstanceList(Integer companyId, String appId, String startDate, String endDate, String userId) throws Exception {
|
|
|
+ JSONArray result = new JSONArray();
|
|
|
+
|
|
|
+ // 将yyyyMMdd格式转换为时间戳(秒)
|
|
|
+ DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
|
|
|
+ LocalDate startLocalDate = LocalDate.parse(startDate, dtf);
|
|
|
+ LocalDate endLocalDate = LocalDate.parse(endDate, dtf);
|
|
|
+
|
|
|
+ long startTime = startLocalDate.atStartOfDay(ZoneId.of("Asia/Shanghai")).toEpochSecond()*1000;
|
|
|
+ long endTime = endLocalDate.atTime(23, 59, 59).atZone(ZoneId.of("Asia/Shanghai")).toEpochSecond()*1000;
|
|
|
+
|
|
|
+ String url = GET_APPROVAL_INSTANCE_LIST;
|
|
|
+ //审批表单的code
|
|
|
+ String approvalCode = EXPENSE_APPROVAL_CODE_MAP.get(companyId);
|
|
|
+ HttpHeaders headers = new HttpHeaders();
|
|
|
+ MediaType type = MediaType.parseMediaType("application/json; charset=utf-8");
|
|
|
+ headers.setContentType(type);
|
|
|
+ headers.add("Authorization", "Bearer " + getTenantAccessToken(appId));
|
|
|
+
|
|
|
+ JSONObject requestBody = new JSONObject();
|
|
|
+ requestBody.put("page_size", 100);
|
|
|
+ requestBody.put("approval_code",approvalCode);
|
|
|
+ requestBody.put("instance_start_time_from", startTime);
|
|
|
+ requestBody.put("instance_start_time_to", endTime);
|
|
|
+ requestBody.put("user_id_type", "user_id");
|
|
|
+ if (!StringUtils.isEmpty(userId)) {
|
|
|
+ requestBody.put("user_id", userId);
|
|
|
+ }
|
|
|
+ requestBody.put("instance_status", "APPROVED");
|
|
|
+
|
|
|
+ HttpEntity<JSONObject> httpEntity = new HttpEntity<>(requestBody, headers);
|
|
|
+
|
|
|
+ System.out.println("请求审批实例列表URL: " + url);
|
|
|
+ System.out.println("请求参数: " + requestBody.toJSONString());
|
|
|
+
|
|
|
+ ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class);
|
|
|
+
|
|
|
+ if (responseEntity.getStatusCode() == HttpStatus.OK) {
|
|
|
+ String resp = responseEntity.getBody();
|
|
|
+ System.out.println("审批实例列表响应数据: " + resp);
|
|
|
+
|
|
|
+ JSONObject respJson = JSONObject.parseObject(resp);
|
|
|
+ if (respJson.getInteger("code") == 0) {
|
|
|
+ JSONObject data = respJson.getJSONObject("data");
|
|
|
+ if (data != null) {
|
|
|
+ JSONArray instanceList = data.getJSONArray("instance_list");
|
|
|
+ if (instanceList != null && instanceList.size() > 0) {
|
|
|
+ result.addAll(instanceList);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理分页
|
|
|
+ Boolean hasMore = data.getBoolean("has_more");
|
|
|
+ String pageToken = data.getString("page_token");
|
|
|
+
|
|
|
+ while (hasMore != null && hasMore && pageToken != null) {
|
|
|
+ System.out.println("存在更多数据,继续获取,page_token: " + pageToken);
|
|
|
+ JSONArray nextPageData = getApprovalInstanceListWithPageToken(approvalCode, appId, startTime, endTime, pageToken, userId);
|
|
|
+ if (nextPageData != null && nextPageData.size() > 0) {
|
|
|
+ result.addAll(nextPageData);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新分页信息(这里简化处理,实际需要递归或循环处理)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ System.out.println("获取审批实例列表失败: " + respJson.getInteger("code") + ", " + respJson.getString("msg"));
|
|
|
+ throw new Exception("获取审批实例列表失败: " + respJson.getInteger("code") + ", " + respJson.getString("msg"));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ System.out.println("获取审批实例列表HTTP请求失败: " + responseEntity.getStatusCode());
|
|
|
+ throw new Exception("获取审批实例列表HTTP请求失败: " + responseEntity.getStatusCode());
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 带分页token获取审批实例列表
|
|
|
+ */
|
|
|
+ private JSONArray getApprovalInstanceListWithPageToken(String approvalCode, String appId, long startTime, long endTime, String pageToken, String userId) throws Exception {
|
|
|
+ JSONArray result = new JSONArray();
|
|
|
|
|
|
- return null;
|
|
|
+ String url = GET_APPROVAL_INSTANCE_LIST;
|
|
|
+ HttpHeaders headers = new HttpHeaders();
|
|
|
+ MediaType type = MediaType.parseMediaType("application/json; charset=utf-8");
|
|
|
+ headers.setContentType(type);
|
|
|
+ headers.add("Authorization", "Bearer " + getTenantAccessToken(appId));
|
|
|
+
|
|
|
+ JSONObject requestBody = new JSONObject();
|
|
|
+ requestBody.put("page_size", 100);
|
|
|
+ requestBody.put("page_token", pageToken);
|
|
|
+ requestBody.put("approval_code",approvalCode);
|
|
|
+ requestBody.put("instance_start_time_from", startTime);
|
|
|
+ requestBody.put("instance_start_time_to", endTime);
|
|
|
+ requestBody.put("user_id_type", "user_id");
|
|
|
+ if (!StringUtils.isEmpty(userId)) {
|
|
|
+ requestBody.put("user_id", userId);
|
|
|
+ }
|
|
|
+ requestBody.put("instance_status", "APPROVED");
|
|
|
+ HttpEntity<JSONObject> httpEntity = new HttpEntity<>(requestBody, headers);
|
|
|
+
|
|
|
+ ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class);
|
|
|
+
|
|
|
+ if (responseEntity.getStatusCode() == HttpStatus.OK) {
|
|
|
+ String resp = responseEntity.getBody();
|
|
|
+ JSONObject respJson = JSONObject.parseObject(resp);
|
|
|
+ if (respJson.getInteger("code") == 0) {
|
|
|
+ JSONObject data = respJson.getJSONObject("data");
|
|
|
+ if (data != null) {
|
|
|
+ JSONArray instanceList = data.getJSONArray("instance_list");
|
|
|
+ if (instanceList != null && instanceList.size() > 0) {
|
|
|
+ result.addAll(instanceList);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取审批实例详情
|
|
|
+ * @param appId 应用ID
|
|
|
+ * @param instanceId 审批实例ID
|
|
|
+ * @return 审批实例详情
|
|
|
+ */
|
|
|
+ private JSONObject getApprovalInstanceInfo(String appId, String instanceId) throws Exception {
|
|
|
+ JSONObject result = null;
|
|
|
+
|
|
|
+ String url = GET_APPROVAL_INSTANCE_INFO.replace(":instance_id", instanceId);
|
|
|
+ HttpHeaders headers = new HttpHeaders();
|
|
|
+ MediaType type = MediaType.parseMediaType("application/json; charset=utf-8");
|
|
|
+ headers.setContentType(type);
|
|
|
+ headers.add("Authorization", "Bearer " + getTenantAccessToken(appId));
|
|
|
+
|
|
|
+ HttpEntity<JSONObject> httpEntity = new HttpEntity<>(null, headers);
|
|
|
+
|
|
|
+ System.out.println("请求审批实例详情URL: " + url);
|
|
|
+
|
|
|
+ ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
|
|
|
+
|
|
|
+ if (responseEntity.getStatusCode() == HttpStatus.OK) {
|
|
|
+ String resp = responseEntity.getBody();
|
|
|
+ System.out.println("审批实例详情响应数据: " + resp);
|
|
|
+
|
|
|
+ JSONObject respJson = JSONObject.parseObject(resp);
|
|
|
+ if (respJson.getInteger("code") == 0) {
|
|
|
+ JSONObject data = respJson.getJSONObject("data");
|
|
|
+ if (data != null) {
|
|
|
+ result = data;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ System.out.println("获取审批实例详情失败: " + respJson.getInteger("code") + ", " + respJson.getString("msg"));
|
|
|
+ throw new Exception("获取审批实例详情失败: " + respJson.getInteger("code") + ", " + respJson.getString("msg"));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ System.out.println("获取审批实例详情HTTP请求失败: " + responseEntity.getStatusCode());
|
|
|
+ throw new Exception("获取审批实例详情HTTP请求失败: " + responseEntity.getStatusCode());
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
|