|
|
@@ -26,8 +26,10 @@ import java.util.ArrayList;
|
|
|
import java.util.Arrays;
|
|
|
import java.util.Collection;
|
|
|
import java.util.Collections;
|
|
|
+import java.util.LinkedHashSet;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
+import java.util.Set;
|
|
|
|
|
|
/** 宜搭采购合同表单推送易企报单据服务。 */
|
|
|
@Slf4j
|
|
|
@@ -41,6 +43,7 @@ public class YqbOrderPushServiceImpl implements YqbOrderPushService {
|
|
|
private static final String AMOUNT_FIELD_ID = "numberField_mpgp9h5c";
|
|
|
private static final String APPROVAL_USER_FIELD_ID = "employeeField_mt2q233g";
|
|
|
private static final String DATE_FIELD_PREFIX = "dateField";
|
|
|
+ private static final String CASCADE_DATE_FIELD_PREFIX = "cascadeDateField";
|
|
|
private static final String ATTACHMENT_FIELD_PREFIX = "attachmentField";
|
|
|
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter
|
|
|
.ofPattern("yyyy-MM-dd")
|
|
|
@@ -152,8 +155,14 @@ public class YqbOrderPushServiceImpl implements YqbOrderPushService {
|
|
|
YqbApiResponse<Object> response = yqbApiClient.post(
|
|
|
CREATE_ORDER_PATH, createRequest.toRequestBody(), "生成单据");
|
|
|
if (!response.isSuccess()) {
|
|
|
- throw new IllegalStateException("易企报生成单据失败:result=" + response.getResult()
|
|
|
- + ",message=" + response.getMessage());
|
|
|
+ String failReason = extractFailReason(response.getData());
|
|
|
+ String errorMessage = "易企报生成单据失败:result=" + response.getResult()
|
|
|
+ + ",message=" + response.getMessage();
|
|
|
+ if (!isBlank(failReason)) {
|
|
|
+ errorMessage += ",failReason=" + failReason;
|
|
|
+ }
|
|
|
+ log.error("{},formInstanceId={}", errorMessage, formInstanceId);
|
|
|
+ throw new IllegalStateException(errorMessage);
|
|
|
}
|
|
|
|
|
|
YqbOrderPushResult result = new YqbOrderPushResult();
|
|
|
@@ -167,6 +176,70 @@ public class YqbOrderPushServiceImpl implements YqbOrderPushService {
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 提取易企报生成单据失败明细中的 failReason。
|
|
|
+ * data 可能是 JSONObject / Map,也可能被反序列化为 JSON 字符串;
|
|
|
+ * failList 兼容直接数组或 {"failList": [...]} 两种形式。
|
|
|
+ */
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ private String extractFailReason(Object data) {
|
|
|
+ if (data == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ Object parsedData = data;
|
|
|
+ if (data instanceof String) {
|
|
|
+ String dataText = ((String) data).trim();
|
|
|
+ if (dataText.startsWith("{") || dataText.startsWith("[")) {
|
|
|
+ try {
|
|
|
+ parsedData = JSON.parse(dataText);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("易企报生成单据失败响应 data 不是有效 JSON:{}", dataText);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Object failListValue = parsedData;
|
|
|
+ if (parsedData instanceof Map) {
|
|
|
+ failListValue = ((Map<?, ?>) parsedData).get("failList");
|
|
|
+ }
|
|
|
+ if (failListValue instanceof String) {
|
|
|
+ String failListText = ((String) failListValue).trim();
|
|
|
+ if (failListText.startsWith("[")) {
|
|
|
+ try {
|
|
|
+ failListValue = JSON.parseArray(failListText);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("易企报生成单据失败响应 failList 不是有效 JSON:{}", failListText);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!(failListValue instanceof Collection)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Set<String> reasons = new LinkedHashSet<>();
|
|
|
+ for (Object failItem : (Collection<?>) failListValue) {
|
|
|
+ Object reason = null;
|
|
|
+ if (failItem instanceof Map) {
|
|
|
+ reason = ((Map<?, ?>) failItem).get("failReason");
|
|
|
+ } else if (failItem instanceof String) {
|
|
|
+ try {
|
|
|
+ Object parsedItem = JSON.parse((String) failItem);
|
|
|
+ if (parsedItem instanceof Map) {
|
|
|
+ reason = ((Map<?, ?>) parsedItem).get("failReason");
|
|
|
+ }
|
|
|
+ } catch (Exception ignored) {
|
|
|
+ // 单条失败信息不是 JSON 时忽略,继续读取其他条目。
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (reason != null && !String.valueOf(reason).trim().isEmpty()) {
|
|
|
+ reasons.add(String.valueOf(reason).trim());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return reasons.isEmpty() ? null : String.join(";", reasons);
|
|
|
+ }
|
|
|
+
|
|
|
private List<YqbOrderComponent> buildOrderComponents(Map<String, Object> formData) {
|
|
|
List<YqbOrderComponent> components = new ArrayList<>();
|
|
|
for (FieldMapping mapping : FIELD_MAPPINGS) {
|
|
|
@@ -262,6 +335,9 @@ public class YqbOrderPushServiceImpl implements YqbOrderPushService {
|
|
|
return DATE_FORMATTER.format(Instant.ofEpochMilli(epochMillis));
|
|
|
}
|
|
|
}
|
|
|
+ if (mapping.fieldId.startsWith(CASCADE_DATE_FIELD_PREFIX)) {
|
|
|
+ return formatCascadeDateValue(mapping.fieldId, value);
|
|
|
+ }
|
|
|
if (mapping.fieldId.startsWith(ATTACHMENT_FIELD_PREFIX)) {
|
|
|
return getAttachmentTemporaryUrls(mapping.fieldId, value);
|
|
|
}
|
|
|
@@ -271,6 +347,40 @@ public class YqbOrderPushServiceImpl implements YqbOrderPushService {
|
|
|
return String.valueOf(value);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 级联日期组件返回数组,例如 ["1760457600000", "1760544000000"]。
|
|
|
+ * 将每个可识别的毫秒时间戳转换为 yyyy-MM-dd,并保留数组结构后转成 JSON 字符串。
|
|
|
+ */
|
|
|
+ private String formatCascadeDateValue(String fieldId, Object value) {
|
|
|
+ Object cascadeDateValue = value;
|
|
|
+ if (value instanceof String) {
|
|
|
+ String text = ((String) value).trim();
|
|
|
+ if (text.startsWith("[") && text.endsWith("]")) {
|
|
|
+ try {
|
|
|
+ cascadeDateValue = JSON.parseArray(text);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("宜搭级联日期字段值不是有效 JSON 数组,按原值推送,fieldId={},value={}", fieldId, text);
|
|
|
+ return text;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!(cascadeDateValue instanceof Collection)) {
|
|
|
+ return String.valueOf(value);
|
|
|
+ }
|
|
|
+
|
|
|
+ List<Object> formattedValues = new ArrayList<>();
|
|
|
+ for (Object item : (Collection<?>) cascadeDateValue) {
|
|
|
+ Long epochMillis = getEpochMillis(item);
|
|
|
+ if (epochMillis == null) {
|
|
|
+ formattedValues.add(item);
|
|
|
+ log.warn("宜搭级联日期字段中存在非毫秒时间戳值,按原值推送,fieldId={},value={}", fieldId, item);
|
|
|
+ } else {
|
|
|
+ formattedValues.add(DATE_FORMATTER.format(Instant.ofEpochMilli(epochMillis)));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return JSON.toJSONString(formattedValues);
|
|
|
+ }
|
|
|
+
|
|
|
private List<String> getAttachmentTemporaryUrls(String fieldId, Object value) {
|
|
|
Object attachmentValue = value;
|
|
|
if (value instanceof String) {
|