|
|
@@ -32,13 +32,21 @@ public class TimeCardRepairService {
|
|
|
private static final String R_SUBMITTER = "textField_mmbffvd9";
|
|
|
private static final String R_DAY = "textField_mmbffvdb";
|
|
|
private static final String R_MONTH = "textField_mmbffvda";
|
|
|
- private static final String R_STATUS = "selectField_mre1xz9g";
|
|
|
private static final String R_SUBMITTER_EMP = "employeeField_mmacxew4";
|
|
|
private static final String R_MONTH_DATE = "dateField_mmacxewf";
|
|
|
private static final String R_DAY_DATE = "dateField_mmbffvd8";
|
|
|
private static final String R_BIL_TABLE = "tableField_mmczo634";
|
|
|
private static final String R_NON_TABLE = "tableField_mmczo63h";
|
|
|
private static final String R_OTHER_TABLE = "tableField_mmeakgid";
|
|
|
+ private static final String R_DAILY_DRAFT = "numberField_mmd1smel";
|
|
|
+ private static final String R_DAILY_SUBMITTED = "numberField_mmd1smem";
|
|
|
+ private static final String R_DAILY_APPROVED = "numberField_mmeakgi4";
|
|
|
+ private static final String R_DAILY_CHANGE = "numberField_mmeakgi5";
|
|
|
+ private static final List<String> R_TOTAL_FIELDS = Arrays.asList(
|
|
|
+ "numberField_mmacxew9", "numberField_mmacxewa", "numberField_mmacxewg", "numberField_mmad6jbc",
|
|
|
+ "numberField_mmad6jbx", "numberField_mmad6jbz", "numberField_mmad6jc1", "numberField_mmeakgia",
|
|
|
+ "numberField_mmd1smeo", "numberField_mmd1smeq", "numberField_mmd1smes", "numberField_mmeakgic",
|
|
|
+ R_DAILY_DRAFT, R_DAILY_SUBMITTED, R_DAILY_APPROVED, R_DAILY_CHANGE);
|
|
|
|
|
|
@Autowired private YDClient ydClient;
|
|
|
@Autowired private WHConf whConf;
|
|
|
@@ -73,18 +81,18 @@ public class TimeCardRepairService {
|
|
|
validateMonthRequest(request.getSubmitterUserId(), monthText);
|
|
|
McException.assertAccessException(!monthClosingService.isClosed(monthText), "补填只能保存已封账月份");
|
|
|
McException.assertAccessException(StringUtils.isBlank(whConf.getFormUuidRepairWorkHoursSummary()), "补填汇总表未配置");
|
|
|
+ McException.assertAccessException(StringUtils.isBlank(whConf.getRepairSummarySyncStatusField()), "补填汇总状态字段未配置");
|
|
|
McException.assertAccessException(request.getFormData() == null, "补填工时数据不能为空");
|
|
|
assertSourceDateAvailable(request.getSubmitterUserId(), request.getDayText());
|
|
|
- assertRepairRecordMutable(request.getSubmitterUserId(), request.getDayText());
|
|
|
Map<String, Object> data = new LinkedHashMap<>(request.getFormData());
|
|
|
data.put(R_SUBMITTER, request.getSubmitterUserId());
|
|
|
data.put(R_DAY, request.getDayText());
|
|
|
data.put(R_MONTH, request.getDayText().substring(0, 6));
|
|
|
- data.put(R_STATUS, "暂存");
|
|
|
+ data.put(whConf.getRepairSummarySyncStatusField(), "暂存");
|
|
|
ydClient.operateData(YDParam.builder().appType(whConf.getYidaAppType())
|
|
|
.systemToken(whConf.getYidaSystemToken()).formUuid(whConf.getFormUuidRepairWorkHoursSummary())
|
|
|
.searchCondition(JSON.toJSONString(mapOf(R_SUBMITTER, request.getSubmitterUserId(), R_DAY, request.getDayText())))
|
|
|
- .formDataJson(JSON.toJSONString(data)).noExecuteExpression(true).build(), YDConf.FORM_OPERATION.upsert);
|
|
|
+ .formDataJson(JSON.toJSONString(data)).noExecuteExpression(false).build(), YDConf.FORM_OPERATION.upsert);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
@@ -121,7 +129,7 @@ public class TimeCardRepairService {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 补填审批补发起:只扫描近期修改的补填汇总,按批次补齐缺失的审批分组。
|
|
|
+ * 补填审批补发起:只扫描近期修改的补填汇总,按员工、月份和补填提交日期补齐缺失明细。
|
|
|
* 正常 TimeCard 补发逻辑仍由 ReSubmitApprovalService 独立处理。
|
|
|
*
|
|
|
* @param lookbackDays 最近修改自然日数量
|
|
|
@@ -132,22 +140,14 @@ public class TimeCardRepairService {
|
|
|
List<Map> records = queryModified(
|
|
|
whConf.getFormUuidRepairWorkHoursSummary(), window[0], window[1]);
|
|
|
Map<String, RepairBatch> batches = buildPendingBatches(records);
|
|
|
+ Map<String, Set<String>> coverageByMonth = new HashMap<>();
|
|
|
int started = 0;
|
|
|
for (RepairBatch batch : batches.values()) {
|
|
|
- Set<String> covered = loadRepairApprovalGroupCoverage(batch.monthText, batch.batchId);
|
|
|
- Map<String, Object> missingProjects = new LinkedHashMap<>();
|
|
|
- for (Map.Entry<String, Object> entry : batch.projectGroups.entrySet()) {
|
|
|
- if (!covered.contains("P|" + entry.getKey())) {
|
|
|
- missingProjects.put(entry.getKey(), entry.getValue());
|
|
|
- }
|
|
|
- }
|
|
|
- Map<String, Object> missingOther = Collections.emptyMap();
|
|
|
- if (!batch.otherGroup.isEmpty()) {
|
|
|
- String managerId = text(batch.otherGroup.get("managerId"));
|
|
|
- if (!covered.contains("O|" + managerId)) {
|
|
|
- missingOther = batch.otherGroup;
|
|
|
- }
|
|
|
- }
|
|
|
+ Set<String> covered = coverageByMonth.computeIfAbsent(
|
|
|
+ batch.monthText, this::loadRepairApprovalDetailCoverage);
|
|
|
+ removeCoveredRows(batch, covered);
|
|
|
+ Map<String, Object> missingProjects = batch.projectGroups;
|
|
|
+ Map<String, Object> missingOther = batch.otherGroup;
|
|
|
if (missingProjects.isEmpty() && missingOther.isEmpty()) continue;
|
|
|
TimeCardRepairSubmitRequest request = new TimeCardRepairSubmitRequest();
|
|
|
request.setSourceMonthText(batch.monthText);
|
|
|
@@ -164,16 +164,24 @@ public class TimeCardRepairService {
|
|
|
}
|
|
|
|
|
|
private void upsertRepairRow(TimeCardRepairSubmitRequest request, Map row, String category,
|
|
|
- String managerId,
|
|
|
- String batch, long submitDate) {
|
|
|
+ String managerId, String batch, long submitDate) {
|
|
|
String day = text(row.get("dateStr"));
|
|
|
if (StringUtils.isBlank(day)) day = text(row.get("dayText"));
|
|
|
String key = day;
|
|
|
+ List<Map> found = query(whConf.getFormUuidRepairWorkHoursSummary(),
|
|
|
+ mapOf(R_SUBMITTER, request.getSubmitterUserId(), R_DAY, key));
|
|
|
+ McException.assertAccessException(found.size() != 1, "补填汇总完整记录不存在或重复,请先保存后提交 userId="
|
|
|
+ + request.getSubmitterUserId() + ", day=" + key);
|
|
|
+ String instanceId = text(found.get(0).get("formInstId"));
|
|
|
+ if (StringUtils.isBlank(instanceId)) instanceId = text(found.get(0).get("formInstanceId"));
|
|
|
+ McException.assertAccessException(StringUtils.isBlank(instanceId), "补填汇总实例ID为空");
|
|
|
+ Map existing = detail(instanceId);
|
|
|
+
|
|
|
Map<String, Object> data = new LinkedHashMap<>();
|
|
|
data.put(R_SUBMITTER, request.getSubmitterUserId());
|
|
|
data.put(R_DAY, day);
|
|
|
data.put(R_MONTH, request.getSourceMonthText());
|
|
|
- data.put(R_STATUS, "审批中");
|
|
|
+ data.put(whConf.getRepairSummarySyncStatusField(), "审批中");
|
|
|
data.put(whConf.getRepairSummaryFillTypeField(), "补填");
|
|
|
data.put(whConf.getRepairSummarySubmitDateField(), submitDate);
|
|
|
data.put(whConf.getRepairSummaryBatchField(), batch);
|
|
|
@@ -218,24 +226,66 @@ public class TimeCardRepairService {
|
|
|
data.put("employeeField_mh8xhqc3", Collections.singletonList(managerId));
|
|
|
}
|
|
|
}
|
|
|
- List<Map> current = new ArrayList<>();
|
|
|
- List<Map> found = query(whConf.getFormUuidRepairWorkHoursSummary(), mapOf(R_SUBMITTER, request.getSubmitterUserId(), R_DAY, key));
|
|
|
- McException.assertAccessException(found.size() > 1, "补填汇总记录重复 userId="
|
|
|
- + request.getSubmitterUserId() + ", day=" + key);
|
|
|
- if (found.size() == 1) {
|
|
|
- String id = text(found.get(0).get("formInstId"));
|
|
|
- if (StringUtils.isBlank(id)) id = text(found.get(0).get("formInstanceId"));
|
|
|
- current = new ArrayList<>(list(detail(id).get(tableField)));
|
|
|
- }
|
|
|
+ List<Map> current = copyRows(existing.get(tableField));
|
|
|
String submittedField = "billableRows".equals(category)
|
|
|
? "numberField_mmczo636"
|
|
|
: ("nonBillableRows".equals(category) ? "numberField_mmczo63c" : "numberField_mmeakgij");
|
|
|
+ // prd 与原 TimeCard 一致:提交值覆盖 submitted,draft 保留供拒绝后恢复编辑。
|
|
|
mergeSubmittedRow(current, child, keyField, submittedField, hours);
|
|
|
data.put(tableField, current);
|
|
|
- ydClient.operateData(YDParam.builder().appType(whConf.getYidaAppType()).systemToken(whConf.getYidaSystemToken())
|
|
|
- .formUuid(whConf.getFormUuidRepairWorkHoursSummary())
|
|
|
- .searchCondition(JSON.toJSONString(mapOf(R_SUBMITTER, request.getSubmitterUserId(), R_DAY, key)))
|
|
|
- .formDataJson(JSON.toJSONString(data)).noExecuteExpression(true).build(), YDConf.FORM_OPERATION.upsert);
|
|
|
+ Map snapshot = new LinkedHashMap(existing);
|
|
|
+ snapshot.put(tableField, current);
|
|
|
+ applySummaryTotals(data, snapshot);
|
|
|
+ final String targetInstanceId = instanceId;
|
|
|
+ operateAndVerify(
|
|
|
+ () -> ydClient.operateData(YDParam.builder().appType(whConf.getYidaAppType())
|
|
|
+ .systemToken(whConf.getYidaSystemToken()).formInstanceId(targetInstanceId)
|
|
|
+ .updateFormDataJson(JSON.toJSONString(data)).ignoreEmpty(false).useLatestVersion(true).build(),
|
|
|
+ YDConf.FORM_OPERATION.update),
|
|
|
+ () -> verifySubmittedRepairRow(targetInstanceId, tableField, keyField,
|
|
|
+ text(child.get(keyField)), submittedField, hours, data));
|
|
|
+ }
|
|
|
+
|
|
|
+ private void verifySubmittedRepairRow(String instanceId, String tableField, String keyField,
|
|
|
+ String rowKey, String submittedField, double hours,
|
|
|
+ Map<String, Object> expected) {
|
|
|
+ Map actual = detail(instanceId);
|
|
|
+ Map actualRow = null;
|
|
|
+ for (Map row : list(actual.get(tableField))) {
|
|
|
+ if (rowKey.equals(text(row.get(keyField)))) {
|
|
|
+ actualRow = row;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ McException.assertAccessException(actualRow == null
|
|
|
+ || !sameHours(num(actualRow.get(submittedField)), hours),
|
|
|
+ "补填汇总提交子表回读不一致 instanceId=" + instanceId + ", key=" + rowKey);
|
|
|
+ for (String field : R_TOTAL_FIELDS) {
|
|
|
+ McException.assertAccessException(!sameHours(num(actual.get(field)), num(expected.get(field))),
|
|
|
+ "补填汇总主表合计回读不一致 instanceId=" + instanceId + ", field=" + field);
|
|
|
+ }
|
|
|
+ String statusField = whConf.getRepairSummarySyncStatusField();
|
|
|
+ McException.assertAccessException(!text(expected.get(statusField)).equals(text(actual.get(statusField))),
|
|
|
+ "补填汇总审批状态回读不一致 instanceId=" + instanceId);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void operateAndVerify(Runnable operation, Runnable verification) {
|
|
|
+ try {
|
|
|
+ operation.run();
|
|
|
+ } catch (RuntimeException operationException) {
|
|
|
+ try {
|
|
|
+ verification.run();
|
|
|
+ return;
|
|
|
+ } catch (RuntimeException verificationException) {
|
|
|
+ operationException.addSuppressed(verificationException);
|
|
|
+ throw operationException;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ verification.run();
|
|
|
+ }
|
|
|
+
|
|
|
+ private static boolean sameHours(double actual, double expected) {
|
|
|
+ return Math.abs(actual - expected) <= 1e-6;
|
|
|
}
|
|
|
|
|
|
private Map detail(String id) {
|
|
|
@@ -256,7 +306,7 @@ public class TimeCardRepairService {
|
|
|
fd.put(whConf.getApprovalFillTypeField(), "补填");
|
|
|
fd.put(whConf.getApprovalRepairSubmitDateField(), submitDate);
|
|
|
fd.put(whConf.getApprovalRepairBatchField(), batch);
|
|
|
- fd.put(whConf.getApprovalSourceMonthField(), request.getSourceMonthText());
|
|
|
+ fd.put(whConf.getApprovalRepairSourceMonthField(), request.getSourceMonthText());
|
|
|
fd.put("textField_mmd2lv0y", request.getSourceMonthText());
|
|
|
fd.put("numberField_mmd2z155", sumRows(group.get("billableRows")));
|
|
|
fd.put("numberField_mmd2z156", sumRows(group.get("nonBillableRows")));
|
|
|
@@ -272,9 +322,9 @@ public class TimeCardRepairService {
|
|
|
fd.put("dateField_mmacxewf", parseMonth(request.getSourceMonthText()));
|
|
|
fd.put("employeeField_moi9pvt1", Collections.singletonList(request.getSubmitterUserId()));
|
|
|
fd.put(whConf.getApprovalFillTypeField(), "补填");
|
|
|
- fd.put(whConf.getApprovalRepairSubmitDateField(), submitDate);
|
|
|
- fd.put(whConf.getApprovalRepairBatchField(), batch);
|
|
|
- fd.put(whConf.getApprovalSourceMonthField(), request.getSourceMonthText());
|
|
|
+ fd.put(whConf.getOtherApprovalRepairSubmitDateField(), submitDate);
|
|
|
+ fd.put(whConf.getOtherApprovalRepairBatchField(), batch);
|
|
|
+ fd.put(whConf.getOtherApprovalRepairSourceMonthField(), request.getSourceMonthText());
|
|
|
fd.put("textField_mmd2lv0y", request.getSourceMonthText());
|
|
|
fd.put("numberField_mmd5b5gl", sumRows(other.get("otherRows")));
|
|
|
fd.put("employeeField_mh8xhqc3", Collections.singletonList(
|
|
|
@@ -336,7 +386,7 @@ public class TimeCardRepairService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void validateRepairRow(TimeCardRepairSubmitRequest request, Map row) {
|
|
|
+ private void validateRepairRow(TimeCardRepairSubmitRequest request, Map row, String category) {
|
|
|
String day = text(row.get("dateStr"));
|
|
|
if (StringUtils.isBlank(day)) day = text(row.get("dayText"));
|
|
|
McException.assertAccessException(!day.matches("\\d{8}")
|
|
|
@@ -349,7 +399,7 @@ public class TimeCardRepairService {
|
|
|
double hours = num(row.get("hours"));
|
|
|
McException.assertAccessException(hours <= 0d || hours > 24d, "补填工时必须大于0且不超过24小时");
|
|
|
assertSourceDateAvailable(request.getSubmitterUserId(), day);
|
|
|
- assertRepairRecordMutable(request.getSubmitterUserId(), day);
|
|
|
+ assertRepairRowMutable(request.getSubmitterUserId(), day, row, category);
|
|
|
}
|
|
|
|
|
|
private int validateSubmitRows(TimeCardRepairSubmitRequest request,
|
|
|
@@ -362,14 +412,14 @@ public class TimeCardRepairService {
|
|
|
for (String category : new String[]{"billableRows", "nonBillableRows"}) {
|
|
|
for (Object rawRow : list(group.get(category))) {
|
|
|
if (!(rawRow instanceof Map)) continue;
|
|
|
- validateRepairRow(request, (Map) rawRow);
|
|
|
+ validateRepairRow(request, (Map) rawRow, category);
|
|
|
count++;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
for (Object rawRow : list(otherGroup.get("otherRows"))) {
|
|
|
if (!(rawRow instanceof Map)) continue;
|
|
|
- validateRepairRow(request, (Map) rawRow);
|
|
|
+ validateRepairRow(request, (Map) rawRow, "otherRows");
|
|
|
count++;
|
|
|
}
|
|
|
return count;
|
|
|
@@ -380,15 +430,32 @@ public class TimeCardRepairService {
|
|
|
McException.assertAccessException(original.size() > 0, "来源日期已有原工时记录,不能补填 userId=" + userId + ", day=" + day);
|
|
|
}
|
|
|
|
|
|
- private void assertRepairRecordMutable(String userId, String day) {
|
|
|
+ private void assertRepairRowMutable(String userId, String day, Map row, String category) {
|
|
|
List<Map> existing = query(whConf.getFormUuidRepairWorkHoursSummary(), mapOf(R_SUBMITTER, userId, R_DAY, day));
|
|
|
McException.assertAccessException(existing.size() > 1, "补填汇总记录重复 userId=" + userId + ", day=" + day);
|
|
|
if (existing.size() != 1) return;
|
|
|
- Map fd = (Map) existing.get(0).get("formData");
|
|
|
- if (fd == null) fd = existing.get(0);
|
|
|
- String status = text(fd.get(R_STATUS));
|
|
|
- McException.assertAccessException("审批中".equals(status) || "已审批".equals(status),
|
|
|
- "该日期已提交或审批完成,不能再次补填");
|
|
|
+ String id = text(existing.get(0).get("formInstId"));
|
|
|
+ if (StringUtils.isBlank(id)) id = text(existing.get(0).get("formInstanceId"));
|
|
|
+ Map fd = detail(id);
|
|
|
+ String projectCode = text(row.get("projectCode"));
|
|
|
+ String activityName = text(row.get("activityName"));
|
|
|
+ boolean other = "otherRows".equals(category);
|
|
|
+ String table = other ? R_OTHER_TABLE
|
|
|
+ : ("billableRows".equals(category) ? R_BIL_TABLE : R_NON_TABLE);
|
|
|
+ String keyField = other ? "selectField_mmeakgie"
|
|
|
+ : (R_BIL_TABLE.equals(table) ? "textField_mmacxew3" : "textField_mmczo639");
|
|
|
+ String submittedField = other ? "numberField_mmeakgij"
|
|
|
+ : (R_BIL_TABLE.equals(table) ? "numberField_mmczo636" : "numberField_mmczo63c");
|
|
|
+ String approvedField = other ? "numberField_mmeakgii"
|
|
|
+ : (R_BIL_TABLE.equals(table) ? "numberField_mmczo637" : "numberField_mmczo63d");
|
|
|
+ String key = other ? activityName : projectCode;
|
|
|
+ for (Map child : list(fd.get(table))) {
|
|
|
+ if (key.equals(text(child.get(keyField)))) {
|
|
|
+ McException.assertAccessException(num(child.get(submittedField)) > 1e-6
|
|
|
+ || num(child.get(approvedField)) > 1e-6,
|
|
|
+ "该补填明细已提交或审批完成,不能再次补填 day=" + day + ", key=" + key);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
private long parseMonth(String month) {
|
|
|
@@ -400,20 +467,19 @@ public class TimeCardRepairService {
|
|
|
Map<String, RepairBatch> batches = new LinkedHashMap<>();
|
|
|
for (Map item : records) {
|
|
|
Map fd = formData(item);
|
|
|
- if (!"审批中".equals(text(fd.get(R_STATUS)))) continue;
|
|
|
- String batchId = text(fd.get(whConf.getRepairSummaryBatchField()));
|
|
|
+ if (!"审批中".equals(text(fd.get(whConf.getRepairSummarySyncStatusField())))) continue;
|
|
|
String userId = text(fd.get(R_SUBMITTER));
|
|
|
String monthText = text(fd.get(R_MONTH));
|
|
|
- if (StringUtils.isAnyBlank(batchId, userId, monthText)) continue;
|
|
|
- RepairBatch batch = batches.computeIfAbsent(batchId, key -> {
|
|
|
+ String batchId = text(fd.get(whConf.getRepairSummaryBatchField()));
|
|
|
+ long submitDate = (long) num(fd.get(whConf.getRepairSummarySubmitDateField()));
|
|
|
+ if (StringUtils.isAnyBlank(userId, monthText, batchId) || submitDate <= 0) continue;
|
|
|
+ String submissionKey = userId + "|" + monthText + "|" + batchId;
|
|
|
+ RepairBatch batch = batches.computeIfAbsent(submissionKey, key -> {
|
|
|
RepairBatch value = new RepairBatch();
|
|
|
value.batchId = batchId;
|
|
|
value.userId = userId;
|
|
|
value.monthText = monthText;
|
|
|
- value.submitDate = (long) num(fd.get(whConf.getRepairSummarySubmitDateField()));
|
|
|
- if (value.submitDate <= 0) {
|
|
|
- value.submitDate = LocalDate.now(ZONE).atStartOfDay(ZONE).toInstant().toEpochMilli();
|
|
|
- }
|
|
|
+ value.submitDate = submitDate;
|
|
|
value.submitterName = text(fd.get("textField_mmoazo1b"));
|
|
|
return value;
|
|
|
});
|
|
|
@@ -468,23 +534,85 @@ public class TimeCardRepairService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private Set<String> loadRepairApprovalGroupCoverage(String monthText, String batchId) {
|
|
|
+ private Set<String> loadRepairApprovalDetailCoverage(String monthText) {
|
|
|
Set<String> covered = new HashSet<>();
|
|
|
Map<String, Object> search = mapOf(
|
|
|
whConf.getApprovalFillTypeField(), "补填",
|
|
|
- whConf.getApprovalRepairBatchField(), batchId,
|
|
|
- whConf.getApprovalSourceMonthField(), monthText);
|
|
|
+ "textField_mmd2lv0y", monthText);
|
|
|
for (Map item : queryProcesses(whConf.getFormUuidApproval(), search)) {
|
|
|
- Map fd = formData(item);
|
|
|
- covered.add("P|" + firstUserId(fd, "employeeField_mkoxpswf"));
|
|
|
+ collectRepairApprovalCoverage(item, false, covered);
|
|
|
}
|
|
|
for (Map item : queryProcesses(whConf.getFormUuidOtherApproval(), search)) {
|
|
|
- Map fd = formData(item);
|
|
|
- covered.add("O|" + firstUserId(fd, "employeeField_mh8xhqc3"));
|
|
|
+ collectRepairApprovalCoverage(item, true, covered);
|
|
|
}
|
|
|
return covered;
|
|
|
}
|
|
|
|
|
|
+ private void collectRepairApprovalCoverage(Map item, boolean other, Set<String> covered) {
|
|
|
+ String status = text(item.get("instanceStatus")).toUpperCase(Locale.ROOT);
|
|
|
+ String approvedResult = text(item.get("approvedResult")).toLowerCase(Locale.ROOT);
|
|
|
+ if (!"RUNNING".equals(status)
|
|
|
+ && !("COMPLETED".equals(status) && "agree".equals(approvedResult))) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Map fd = formData(item);
|
|
|
+ if (other) {
|
|
|
+ addCoverageRows(covered, list(fd.get("tableField_mmd1wu9h")), "other",
|
|
|
+ "textField_mmd1wu9f", "textField_mmd8g655", "selectField_mmeakgie",
|
|
|
+ "radioField_mpwhk294", status);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ addCoverageRows(covered, list(fd.get("tableField_mmae8t99")), "billable",
|
|
|
+ "textField_mmd1ozk4", "textField_mmd8g654", "textField_mmacxew3",
|
|
|
+ "radioField_mpwhk294", status);
|
|
|
+ addCoverageRows(covered, list(fd.get("tableField_mmd1wu9h")), "nonBillable",
|
|
|
+ "textField_mmd1wu9f", "textField_mmd8g655", "textField_mmd1wu9d",
|
|
|
+ "radioField_mpwhk295", status);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void addCoverageRows(Set<String> covered, List<Map> rows, String category,
|
|
|
+ String userField, String dayField, String keyField,
|
|
|
+ String opinionField, String status) {
|
|
|
+ for (Map row : rows) {
|
|
|
+ if ("COMPLETED".equals(status)
|
|
|
+ && row.containsKey(opinionField)
|
|
|
+ && !"同意".equals(text(row.get(opinionField)))) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ covered.add(coverageKey(category, text(row.get(userField)),
|
|
|
+ text(row.get(dayField)), text(row.get(keyField))));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void removeCoveredRows(RepairBatch batch, Set<String> covered) {
|
|
|
+ Iterator<Map.Entry<String, Object>> iterator = batch.projectGroups.entrySet().iterator();
|
|
|
+ while (iterator.hasNext()) {
|
|
|
+ Map group = (Map) iterator.next().getValue();
|
|
|
+ removeCoveredProjectRows(batch.userId, list(group.get("billableRows")),
|
|
|
+ "billable", covered);
|
|
|
+ removeCoveredProjectRows(batch.userId, list(group.get("nonBillableRows")),
|
|
|
+ "nonBillable", covered);
|
|
|
+ if (list(group.get("billableRows")).isEmpty()
|
|
|
+ && list(group.get("nonBillableRows")).isEmpty()) {
|
|
|
+ iterator.remove();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ List<Map> otherRows = list(batch.otherGroup.get("otherRows"));
|
|
|
+ otherRows.removeIf(row -> covered.contains(coverageKey("other", batch.userId,
|
|
|
+ text(row.get("dateStr")), text(row.get("activityName")))));
|
|
|
+ if (otherRows.isEmpty()) batch.otherGroup.clear();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void removeCoveredProjectRows(String userId, List<Map> rows,
|
|
|
+ String category, Set<String> covered) {
|
|
|
+ rows.removeIf(row -> covered.contains(coverageKey(category, userId,
|
|
|
+ text(row.get("dateStr")), text(row.get("projectCode")))));
|
|
|
+ }
|
|
|
+
|
|
|
+ static String coverageKey(String category, String userId, String day, String detailKey) {
|
|
|
+ return category + "|" + userId + "|" + day + "|" + detailKey;
|
|
|
+ }
|
|
|
+
|
|
|
private List<Map> queryModified(String formUuid, String fromDate, String toDate) {
|
|
|
List<Map> all = new ArrayList<>();
|
|
|
for (int page = 1; page <= 200; page++) {
|
|
|
@@ -551,6 +679,51 @@ public class TimeCardRepairService {
|
|
|
current.add(child);
|
|
|
}
|
|
|
|
|
|
+ static void applySummaryTotals(Map<String, Object> update, Map snapshot) {
|
|
|
+ putCategoryTotals(update, snapshot, R_BIL_TABLE,
|
|
|
+ "numberField_mmczo635", "numberField_mmczo636", "numberField_mmczo637", "numberField_mmd80zae",
|
|
|
+ "numberField_mmacxew9", "numberField_mmacxewa", "numberField_mmacxewg", "numberField_mmad6jbc");
|
|
|
+ putCategoryTotals(update, snapshot, R_NON_TABLE,
|
|
|
+ "numberField_mmczo63b", "numberField_mmczo63c", "numberField_mmczo63d", "numberField_mmeakgi9",
|
|
|
+ "numberField_mmad6jbx", "numberField_mmad6jbz", "numberField_mmad6jc1", "numberField_mmeakgia");
|
|
|
+ putCategoryTotals(update, snapshot, R_OTHER_TABLE,
|
|
|
+ "numberField_mmeakgik", "numberField_mmeakgij", "numberField_mmeakgii", "numberField_mmeakgim",
|
|
|
+ "numberField_mmd1smeo", "numberField_mmd1smeq", "numberField_mmd1smes", "numberField_mmeakgic");
|
|
|
+ update.put(R_DAILY_DRAFT, categoryTotal(snapshot, R_BIL_TABLE, "numberField_mmczo635")
|
|
|
+ + categoryTotal(snapshot, R_NON_TABLE, "numberField_mmczo63b")
|
|
|
+ + categoryTotal(snapshot, R_OTHER_TABLE, "numberField_mmeakgik"));
|
|
|
+ update.put(R_DAILY_SUBMITTED, categoryTotal(snapshot, R_BIL_TABLE, "numberField_mmczo636")
|
|
|
+ + categoryTotal(snapshot, R_NON_TABLE, "numberField_mmczo63c")
|
|
|
+ + categoryTotal(snapshot, R_OTHER_TABLE, "numberField_mmeakgij"));
|
|
|
+ update.put(R_DAILY_APPROVED, categoryTotal(snapshot, R_BIL_TABLE, "numberField_mmczo637")
|
|
|
+ + categoryTotal(snapshot, R_NON_TABLE, "numberField_mmczo63d")
|
|
|
+ + categoryTotal(snapshot, R_OTHER_TABLE, "numberField_mmeakgii"));
|
|
|
+ update.put(R_DAILY_CHANGE, categoryTotal(snapshot, R_BIL_TABLE, "numberField_mmd80zae")
|
|
|
+ + categoryTotal(snapshot, R_NON_TABLE, "numberField_mmeakgi9")
|
|
|
+ + categoryTotal(snapshot, R_OTHER_TABLE, "numberField_mmeakgim"));
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void putCategoryTotals(Map<String, Object> update, Map snapshot, String table,
|
|
|
+ String draftChild, String submittedChild, String approvedChild, String changeChild,
|
|
|
+ String draftMain, String submittedMain, String approvedMain, String changeMain) {
|
|
|
+ update.put(draftMain, categoryTotal(snapshot, table, draftChild));
|
|
|
+ update.put(submittedMain, categoryTotal(snapshot, table, submittedChild));
|
|
|
+ update.put(approvedMain, categoryTotal(snapshot, table, approvedChild));
|
|
|
+ update.put(changeMain, categoryTotal(snapshot, table, changeChild));
|
|
|
+ }
|
|
|
+
|
|
|
+ private static double categoryTotal(Map snapshot, String table, String field) {
|
|
|
+ double total = 0d;
|
|
|
+ for (Map row : list(snapshot.get(table))) total += num(row.get(field));
|
|
|
+ return total;
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<Map> copyRows(Object raw) {
|
|
|
+ List<Map> rows = new ArrayList<>();
|
|
|
+ for (Map row : list(raw)) rows.add(new LinkedHashMap(row));
|
|
|
+ return rows;
|
|
|
+ }
|
|
|
+
|
|
|
private static class RepairBatch {
|
|
|
private String batchId;
|
|
|
private String userId;
|