|
|
@@ -0,0 +1,506 @@
|
|
|
+package com.malk.minglei.service.impl.yida;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.malk.minglei.config.YidaApplicationsProperties;
|
|
|
+import com.malk.minglei.dto.ErpYidaPushMainData;
|
|
|
+import com.malk.minglei.dto.ErpYidaPushRequest;
|
|
|
+import com.malk.minglei.service.yida.YidaFormPushHandler;
|
|
|
+import com.malk.minglei.service.yida.YidaProcessOpenApiClient;
|
|
|
+import com.malk.server.common.McException;
|
|
|
+import com.malk.server.dingtalk.DDR_New;
|
|
|
+import com.malk.server.dingtalk.DDConf;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.time.ZoneId;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.LinkedHashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 检验情况审批流程(aqct300)ERP 推送到宜搭的处理器。
|
|
|
+ * <p>
|
|
|
+ * 仅负责发起流程;交易对象编号、料件编号、表头不良数、检验位置等缺口字段按约定丢弃。
|
|
|
+ */
|
|
|
+@Service
|
|
|
+public class Aqct300FormPushHandler implements YidaFormPushHandler {
|
|
|
+
|
|
|
+ public static final String TYPE = "aqct300";
|
|
|
+
|
|
|
+ private static final Logger LOGGER = LoggerFactory.getLogger(Aqct300FormPushHandler.class);
|
|
|
+ private static final String START_PROCESS_ENDPOINT = "/v1.0/yida/processes/instances/start";
|
|
|
+ private static final String FORM_NAME = "\u68c0\u9a8c\u60c5\u51b5\u5ba1\u6279\u6d41\u7a0b";
|
|
|
+ private static final String FORM_UUID = "FORM-38C8592E7F5F45B3A388DA3FEFBA67C2GCEV";
|
|
|
+ private static final String PROCESS_CODE = "TPROC--LX766PC193N85EWUJ9ZLACNJNPSW3HBRG78TM1";
|
|
|
+
|
|
|
+ private static final String TITLE_FIELD_ID = "textField_msh27unu";
|
|
|
+ private static final String APPLICANT_FIELD_ID = "employeeField_msh186rr";
|
|
|
+ private static final String COMPANY_FIELD_ID = "selectField_mtxpfhhe";
|
|
|
+ private static final String DEPARTMENT_FIELD_ID = "departmentSelectField_msh186ry";
|
|
|
+ private static final String APPLY_DATE_FIELD_ID = "dateField_msh186rs";
|
|
|
+ private static final String FORM_TITLE_FIELD_ID = "textField_mspcpz92";
|
|
|
+
|
|
|
+ private static final String ENTERPRISE_FIELD_ID = "textField_mt82p09i";
|
|
|
+ private static final String DOC_NO_FIELD_ID = "textField_mt87k1g0";
|
|
|
+ private static final String INSPECTION_TYPE_FIELD_ID = "selectField_mt87k1g3";
|
|
|
+ private static final String DOC_DATE_FIELD_ID = "dateField_mt82p09f";
|
|
|
+ private static final String SOURCE_QTY_FIELD_ID = "numberField_mt87k1g1";
|
|
|
+ private static final String UNIT_FIELD_ID = "textField_mt87k1g2";
|
|
|
+ private static final String SPEC_FIELD_ID = "textField_mt80nq6v";
|
|
|
+ private static final String ITEM_NAME_FIELD_ID = "textField_mt82p08x";
|
|
|
+ private static final String INSPECTION_UNIT_FIELD_ID = "textField_mt82p091";
|
|
|
+ private static final String PRODUCT_FEATURE_FIELD_ID = "textField_mt82p092";
|
|
|
+ private static final String JUDGEMENT_FIELD_ID = "textField_mt82p094";
|
|
|
+ private static final String INSPECTOR_NAME_FIELD_ID = "textField_mt87k1g4";
|
|
|
+ private static final String SEND_QTY_FIELD_ID = "numberField_mt87k1ga";
|
|
|
+ private static final String LOT_NO_FIELD_ID = "textField_mt87k1gb";
|
|
|
+ private static final String PASS_QTY_FIELD_ID = "numberField_mt87k1gc";
|
|
|
+
|
|
|
+ private static final String TABLE1_FIELD_ID = "tableField_psd31ws6n";
|
|
|
+ private static final String T1_ENT_FIELD_ID = "textField_psd32acoo";
|
|
|
+ private static final String T1_DOC_NO_FIELD_ID = "textField_psd43y52l";
|
|
|
+ private static final String T1_SEQ_FIELD_ID = "textField_psd44ub6a";
|
|
|
+ private static final String T1_ITEM_FIELD_ID = "textField_psd45i4rr";
|
|
|
+ private static final String T1_ITEM_DESC_FIELD_ID = "textField_psd47bc9z";
|
|
|
+ private static final String T1_SAMPLE_QTY_FIELD_ID = "numberField_psd48zc2c";
|
|
|
+ private static final String T1_DEFECT_COUNT_FIELD_ID = "numberField_psd492g6k";
|
|
|
+ private static final String T1_ITEM_RESULT_FIELD_ID = "textField_psd4aboib";
|
|
|
+ private static final String T1_BAD_QTY_FIELD_ID = "numberField_psd4bkuxd";
|
|
|
+
|
|
|
+ private static final String TABLE2_FIELD_ID = "tableField_psd4cepjb";
|
|
|
+ private static final String T2_ENT_FIELD_ID = "textField_psd4d0x9h";
|
|
|
+ private static final String T2_DOC_NO_FIELD_ID = "textField_psd4eu9ds";
|
|
|
+ private static final String T2_SEQ_FIELD_ID = "textField_psd4fqqt8";
|
|
|
+ private static final String T2_REASON_FIELD_ID = "textField_psd4ge7ws";
|
|
|
+ private static final String T2_QTY_FIELD_ID = "numberField_psd4ipqfh";
|
|
|
+ private static final String T2_REMARK_FIELD_ID = "textField_psd4jg5l7";
|
|
|
+ private static final String T2_BAD_QTY_FIELD_ID = "numberField_psd4klpby";
|
|
|
+
|
|
|
+ private static final String TABLE3_FIELD_ID = "tableField_psd5lhkd9";
|
|
|
+ private static final String T3_ENT_FIELD_ID = "textField_psd5mj42d";
|
|
|
+ private static final String T3_DOC_NO_FIELD_ID = "textField_psd5nzcrr";
|
|
|
+ private static final String T3_SEQ_FIELD_ID = "textField_psd5o26sl";
|
|
|
+ private static final String T3_UPPER_FIELD_ID = "numberField_psd5pwsp0";
|
|
|
+ private static final String T3_LOWER_FIELD_ID = "numberField_psd5q5ti2";
|
|
|
+ private static final String T3_MEASURE_FIELD_ID = "numberField_psd5reahw";
|
|
|
+ private static final String T3_UNIT_FIELD_ID = "textField_psd5sxmwd";
|
|
|
+ private static final String T3_PASS_FLAG_FIELD_ID = "textField_psd5tpt5q";
|
|
|
+ private static final String T3_ITEM_FIELD_ID = "textField_psd5vxs6b";
|
|
|
+ private static final String T3_STANDARD_FIELD_ID = "textField_psd5wy2x0";
|
|
|
+ private static final String T3_REMARK_FIELD_ID = "textField_psd5xt4zr";
|
|
|
+
|
|
|
+ private static final String TABLE4_FIELD_ID = "tableField_psd5yvj22";
|
|
|
+ private static final String T4_SEQ_FIELD_ID = "textField_psd5z49u7";
|
|
|
+ private static final String T4_SOURCE_TYPE_FIELD_ID = "textField_psd510o7sr";
|
|
|
+ private static final String T4_SOURCE_DOC_FIELD_ID = "textField_psd511xgy1";
|
|
|
+ private static final String T4_SOURCE_SEQ_FIELD_ID = "textField_psd5127rvd";
|
|
|
+ private static final String T4_REF_DOC_FIELD_ID = "textField_psd513ufnr";
|
|
|
+ private static final String T4_REF_SEQ_FIELD_ID = "textField_psd514yvch";
|
|
|
+ private static final String T4_SUPPLIER_FIELD_ID = "textField_psd515qf23";
|
|
|
+ private static final String T4_SOURCE_QTY_FIELD_ID = "numberField_psd516nsm3";
|
|
|
+ private static final String T4_UNIT_FIELD_ID = "textField_psd517x778";
|
|
|
+ private static final String T4_ITEM_CODE_FIELD_ID = "textField_psd518e40f";
|
|
|
+ private static final String T4_ITEM_NAME_FIELD_ID = "textField_psd519lkbj";
|
|
|
+ private static final String T4_SPEC_FIELD_ID = "textField_psd51ao5h9";
|
|
|
+
|
|
|
+ private final YidaProcessOpenApiClient yidaProcessOpenApiClient;
|
|
|
+ private final DDConf dingTalkConfiguration;
|
|
|
+ private final YidaApplicationsProperties applications;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建检验情况审批推送处理器。
|
|
|
+ *
|
|
|
+ * @param yidaProcessOpenApiClient 宜搭流程 OpenAPI 客户端
|
|
|
+ * @param dingTalkConfiguration 钉钉应用配置
|
|
|
+ * @param applications 宜搭应用配置
|
|
|
+ */
|
|
|
+ public Aqct300FormPushHandler(YidaProcessOpenApiClient yidaProcessOpenApiClient,
|
|
|
+ DDConf dingTalkConfiguration,
|
|
|
+ YidaApplicationsProperties applications) {
|
|
|
+ this.yidaProcessOpenApiClient = yidaProcessOpenApiClient;
|
|
|
+ this.dingTalkConfiguration = dingTalkConfiguration;
|
|
|
+ this.applications = applications;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 返回检验情况审批支持的 ERP 推送类型。
|
|
|
+ *
|
|
|
+ * @return 支持的 type 列表
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public List<String> getTypes() {
|
|
|
+ return Collections.singletonList(TYPE);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将检验情况单据转换为宜搭流程表单并发起流程。
|
|
|
+ *
|
|
|
+ * @param request ERP 推送请求,需已由上层解析 {@code mainData.tjr} 为发起人
|
|
|
+ * @return 宜搭流程实例 ID 或成功标识
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public String push(ErpYidaPushRequest request) {
|
|
|
+ validateConfiguration();
|
|
|
+
|
|
|
+ Map<String, Object> mainData = toMainDataMap(request.getMainData());
|
|
|
+ String operatorUserId = requireText(resolveOperatorUserId(request), "aqct300 requires mainData.tjr");
|
|
|
+ Map<String, Object> formData = toYidaFormData(request, mainData, operatorUserId);
|
|
|
+ String title = requireText(toText(formData.get(TITLE_FIELD_ID)), "aqct300 requires mainData.qcbadocno");
|
|
|
+
|
|
|
+ Map<String, Object> body = new LinkedHashMap<String, Object>();
|
|
|
+ body.put("appType", requireText(applications.getCoordinationOffice().getAppType(), "YIDA_COORDINATION_OFFICE_APP_TYPE is not configured"));
|
|
|
+ body.put("systemToken", requireText(applications.getCoordinationOffice().getSystemToken(), "YIDA_COORDINATION_OFFICE_SYSTEM_TOKEN is not configured"));
|
|
|
+ body.put("userId", operatorUserId);
|
|
|
+ body.put("processCode", PROCESS_CODE);
|
|
|
+ body.put("formUuid", FORM_UUID);
|
|
|
+ body.put("formDataJson", JSON.toJSONString(formData));
|
|
|
+ body.put("executeExpression", true);
|
|
|
+ body.put("noExecuteExpression", false);
|
|
|
+ body.put("title", title);
|
|
|
+ body.put("dataTitle", title);
|
|
|
+
|
|
|
+ LOGGER.info("Yida process start request endpoint={} formName={} body={}",
|
|
|
+ START_PROCESS_ENDPOINT, FORM_NAME, JSON.toJSONString(maskSensitive(body)));
|
|
|
+ try {
|
|
|
+ return extractProcessInstanceId(yidaProcessOpenApiClient.startProcess(body));
|
|
|
+ } catch (McException exception) {
|
|
|
+ throw exception;
|
|
|
+ } catch (Exception exception) {
|
|
|
+ LOGGER.error("Yida process start failed formName={} body={}",
|
|
|
+ FORM_NAME, JSON.toJSONString(maskSensitive(body)), exception);
|
|
|
+ throw new McException("DINGTALK_YIDA_ERROR", "Yida process start failed: " + rootMessage(exception));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将 ERP 主表与四张明细映射为宜搭 formData。
|
|
|
+ */
|
|
|
+ private Map<String, Object> toYidaFormData(ErpYidaPushRequest request,
|
|
|
+ Map<String, Object> mainData,
|
|
|
+ String operatorUserId) {
|
|
|
+ String docNo = toText(mainData.get("qcbadocno"));
|
|
|
+ String title = docNo == null ? null : FORM_NAME + "-" + docNo;
|
|
|
+ Object company = toCompanyName(firstNonBlank(mainData.get("gs"), mainData.get("qcbaent"), mainData.get("ent")));
|
|
|
+
|
|
|
+ Map<String, Object> formData = new LinkedHashMap<String, Object>();
|
|
|
+ putIfNotBlank(formData, TITLE_FIELD_ID, title);
|
|
|
+ putIfNotBlank(formData, APPLICANT_FIELD_ID, Collections.singletonList(operatorUserId));
|
|
|
+ putIfNotBlank(formData, COMPANY_FIELD_ID, company);
|
|
|
+ putIfNotBlank(formData, DEPARTMENT_FIELD_ID, toStringList(mainData.get("bm")));
|
|
|
+ putIfNotBlank(formData, APPLY_DATE_FIELD_ID, toDateMillis(firstNonBlank(mainData.get("rq"), mainData.get("qcbadocdt"))));
|
|
|
+ putIfNotBlank(formData, FORM_TITLE_FIELD_ID, title);
|
|
|
+
|
|
|
+ putIfNotBlank(formData, ENTERPRISE_FIELD_ID, mainData.get("qcbaent"));
|
|
|
+ putIfNotBlank(formData, DOC_NO_FIELD_ID, docNo);
|
|
|
+ putIfNotBlank(formData, INSPECTION_TYPE_FIELD_ID, mainData.get("qcba000"));
|
|
|
+ putIfNotBlank(formData, DOC_DATE_FIELD_ID, toDateMillis(mainData.get("qcbadocdt")));
|
|
|
+ putIfNotBlank(formData, SOURCE_QTY_FIELD_ID, toDecimal(mainData.get("qcba008")));
|
|
|
+ putIfNotBlank(formData, UNIT_FIELD_ID, mainData.get("qcba009"));
|
|
|
+ putIfNotBlank(formData, SPEC_FIELD_ID, mainData.get("imaal004"));
|
|
|
+ putIfNotBlank(formData, ITEM_NAME_FIELD_ID, mainData.get("imaal003"));
|
|
|
+ putIfNotBlank(formData, INSPECTION_UNIT_FIELD_ID, mainData.get("qcba016"));
|
|
|
+ putIfNotBlank(formData, PRODUCT_FEATURE_FIELD_ID, mainData.get("qcba012"));
|
|
|
+ putIfNotBlank(formData, JUDGEMENT_FIELD_ID, mainData.get("qcba022"));
|
|
|
+ putIfNotBlank(formData, INSPECTOR_NAME_FIELD_ID, mainData.get("qcba024"));
|
|
|
+ putIfNotBlank(formData, SEND_QTY_FIELD_ID, toDecimal(mainData.get("qcba017")));
|
|
|
+ putIfNotBlank(formData, LOT_NO_FIELD_ID, mainData.get("qcba034"));
|
|
|
+ putIfNotBlank(formData, PASS_QTY_FIELD_ID, toDecimal(mainData.get("qcba023")));
|
|
|
+
|
|
|
+ Map<String, Object> detailWrapper = objectToMap(request.getDetailData());
|
|
|
+ List<Map<String, Object>> table1 = toTable1Rows(toMapRows(detailWrapper.get("detailData1")));
|
|
|
+ if (!table1.isEmpty()) {
|
|
|
+ formData.put(TABLE1_FIELD_ID, table1);
|
|
|
+ }
|
|
|
+ List<Map<String, Object>> table2 = toTable2Rows(toMapRows(detailWrapper.get("detailData2")));
|
|
|
+ if (!table2.isEmpty()) {
|
|
|
+ formData.put(TABLE2_FIELD_ID, table2);
|
|
|
+ }
|
|
|
+ List<Map<String, Object>> table3 = toTable3Rows(toMapRows(detailWrapper.get("detailData3")));
|
|
|
+ if (!table3.isEmpty()) {
|
|
|
+ formData.put(TABLE3_FIELD_ID, table3);
|
|
|
+ }
|
|
|
+ List<Map<String, Object>> table4 = toTable4Rows(toMapRows(detailWrapper.get("detailData4")));
|
|
|
+ if (!table4.isEmpty()) {
|
|
|
+ formData.put(TABLE4_FIELD_ID, table4);
|
|
|
+ }
|
|
|
+ return formData;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 映射子表1(检验项目判定)。
|
|
|
+ */
|
|
|
+ private List<Map<String, Object>> toTable1Rows(List<Map<String, Object>> sourceRows) {
|
|
|
+ List<Map<String, Object>> rows = new ArrayList<Map<String, Object>>();
|
|
|
+ for (Map<String, Object> source : sourceRows) {
|
|
|
+ Map<String, Object> row = new LinkedHashMap<String, Object>();
|
|
|
+ putIfNotBlank(row, T1_ENT_FIELD_ID, source.get("qcbdent"));
|
|
|
+ putIfNotBlank(row, T1_DOC_NO_FIELD_ID, source.get("qcbddocno"));
|
|
|
+ putIfNotBlank(row, T1_SEQ_FIELD_ID, source.get("qcbdseq"));
|
|
|
+ putIfNotBlank(row, T1_ITEM_FIELD_ID, source.get("qcbd001"));
|
|
|
+ putIfNotBlank(row, T1_ITEM_DESC_FIELD_ID, source.get("oocql004"));
|
|
|
+ putIfNotBlank(row, T1_SAMPLE_QTY_FIELD_ID, toDecimal(source.get("qcbd009")));
|
|
|
+ putIfNotBlank(row, T1_DEFECT_COUNT_FIELD_ID, toDecimal(source.get("qcbd010")));
|
|
|
+ putIfNotBlank(row, T1_ITEM_RESULT_FIELD_ID, source.get("qcbd011"));
|
|
|
+ putIfNotBlank(row, T1_BAD_QTY_FIELD_ID, toDecimal(source.get("qcbd021")));
|
|
|
+ if (!row.isEmpty()) {
|
|
|
+ rows.add(row);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return rows;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 映射子表2(缺点原因)。
|
|
|
+ */
|
|
|
+ private List<Map<String, Object>> toTable2Rows(List<Map<String, Object>> sourceRows) {
|
|
|
+ List<Map<String, Object>> rows = new ArrayList<Map<String, Object>>();
|
|
|
+ for (Map<String, Object> source : sourceRows) {
|
|
|
+ Map<String, Object> row = new LinkedHashMap<String, Object>();
|
|
|
+ putIfNotBlank(row, T2_ENT_FIELD_ID, source.get("qcbeent"));
|
|
|
+ putIfNotBlank(row, T2_DOC_NO_FIELD_ID, source.get("qcbedocno"));
|
|
|
+ putIfNotBlank(row, T2_SEQ_FIELD_ID, source.get("qcbeseq"));
|
|
|
+ putIfNotBlank(row, T2_REASON_FIELD_ID, source.get("qcbe001"));
|
|
|
+ putIfNotBlank(row, T2_QTY_FIELD_ID, toDecimal(source.get("qcbe002")));
|
|
|
+ putIfNotBlank(row, T2_REMARK_FIELD_ID, source.get("qcbe003"));
|
|
|
+ putIfNotBlank(row, T2_BAD_QTY_FIELD_ID, toDecimal(source.get("qcbe004")));
|
|
|
+ if (!row.isEmpty()) {
|
|
|
+ rows.add(row);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return rows;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 映射子表3(计量检验);检验位置 {@code qcbd002} 无宜搭字段,丢弃。
|
|
|
+ */
|
|
|
+ private List<Map<String, Object>> toTable3Rows(List<Map<String, Object>> sourceRows) {
|
|
|
+ List<Map<String, Object>> rows = new ArrayList<Map<String, Object>>();
|
|
|
+ for (Map<String, Object> source : sourceRows) {
|
|
|
+ Map<String, Object> row = new LinkedHashMap<String, Object>();
|
|
|
+ putIfNotBlank(row, T3_ENT_FIELD_ID, source.get("qcbdent"));
|
|
|
+ putIfNotBlank(row, T3_DOC_NO_FIELD_ID, source.get("qcbddocno"));
|
|
|
+ putIfNotBlank(row, T3_SEQ_FIELD_ID, source.get("qcbdseq"));
|
|
|
+ putIfNotBlank(row, T3_UPPER_FIELD_ID, toDecimal(source.get("qcbd013")));
|
|
|
+ putIfNotBlank(row, T3_LOWER_FIELD_ID, toDecimal(source.get("qcbd015")));
|
|
|
+ putIfNotBlank(row, T3_MEASURE_FIELD_ID, toDecimal(source.get("qcbg002")));
|
|
|
+ putIfNotBlank(row, T3_UNIT_FIELD_ID, source.get("qcbd017"));
|
|
|
+ putIfNotBlank(row, T3_PASS_FLAG_FIELD_ID, source.get("qcbg003"));
|
|
|
+ putIfNotBlank(row, T3_ITEM_FIELD_ID, source.get("qcbd001"));
|
|
|
+ putIfNotBlank(row, T3_STANDARD_FIELD_ID, source.get("oocql004"));
|
|
|
+ putIfNotBlank(row, T3_REMARK_FIELD_ID, source.get("qcbd019"));
|
|
|
+ if (!row.isEmpty()) {
|
|
|
+ rows.add(row);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return rows;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 映射子表4(来源明细)。
|
|
|
+ */
|
|
|
+ private List<Map<String, Object>> toTable4Rows(List<Map<String, Object>> sourceRows) {
|
|
|
+ List<Map<String, Object>> rows = new ArrayList<Map<String, Object>>();
|
|
|
+ for (Map<String, Object> source : sourceRows) {
|
|
|
+ Map<String, Object> row = new LinkedHashMap<String, Object>();
|
|
|
+ putIfNotBlank(row, T4_SEQ_FIELD_ID, source.get("qcbaucseq"));
|
|
|
+ putIfNotBlank(row, T4_SOURCE_TYPE_FIELD_ID, source.get("qcbauc014"));
|
|
|
+ putIfNotBlank(row, T4_SOURCE_DOC_FIELD_ID, source.get("qcbauc001"));
|
|
|
+ putIfNotBlank(row, T4_SOURCE_SEQ_FIELD_ID, source.get("qcbauc002"));
|
|
|
+ putIfNotBlank(row, T4_REF_DOC_FIELD_ID, source.get("qcbauc003"));
|
|
|
+ putIfNotBlank(row, T4_REF_SEQ_FIELD_ID, source.get("qcbauc004"));
|
|
|
+ putIfNotBlank(row, T4_SUPPLIER_FIELD_ID, source.get("qcbauc005"));
|
|
|
+ putIfNotBlank(row, T4_SOURCE_QTY_FIELD_ID, toDecimal(source.get("qcbauc008")));
|
|
|
+ putIfNotBlank(row, T4_UNIT_FIELD_ID, source.get("qcbauc009"));
|
|
|
+ putIfNotBlank(row, T4_ITEM_CODE_FIELD_ID, source.get("qcbauc010"));
|
|
|
+ putIfNotBlank(row, T4_ITEM_NAME_FIELD_ID, source.get("imaal003"));
|
|
|
+ putIfNotBlank(row, T4_SPEC_FIELD_ID, source.get("imaal004"));
|
|
|
+ if (!row.isEmpty()) {
|
|
|
+ rows.add(row);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return rows;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 优先使用上层已解析的发起人钉钉 userId。
|
|
|
+ */
|
|
|
+ private String resolveOperatorUserId(ErpYidaPushRequest request) {
|
|
|
+ return toText(request.getOriginatorUserId());
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<String, Object> toMainDataMap(ErpYidaPushMainData mainData) {
|
|
|
+ if (mainData == null) {
|
|
|
+ return Collections.emptyMap();
|
|
|
+ }
|
|
|
+ Map<String, Object> result = new LinkedHashMap<String, Object>();
|
|
|
+ putIfNotBlank(result, "rq", mainData.getRq());
|
|
|
+ putIfNotBlank(result, "bm", mainData.getBm());
|
|
|
+ putIfNotBlank(result, "tjr", mainData.getTjr());
|
|
|
+ putIfNotBlank(result, "gs", mainData.getGs());
|
|
|
+ putIfNotBlank(result, "t100id", mainData.getT100id());
|
|
|
+ putIfNotBlank(result, "ent", mainData.getEnt());
|
|
|
+ putIfNotBlank(result, "t100bm", mainData.getT100bm());
|
|
|
+ result.putAll(mainData.getExtraFields());
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<String, Object> objectToMap(Object value) {
|
|
|
+ if (value instanceof Map) {
|
|
|
+ Map<String, Object> result = new LinkedHashMap<String, Object>();
|
|
|
+ for (Map.Entry<?, ?> entry : ((Map<?, ?>) value).entrySet()) {
|
|
|
+ if (entry.getKey() != null) {
|
|
|
+ result.put(String.valueOf(entry.getKey()), entry.getValue());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ return Collections.emptyMap();
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<Map<String, Object>> toMapRows(Object value) {
|
|
|
+ List<Map<String, Object>> rows = new ArrayList<Map<String, Object>>();
|
|
|
+ if (!(value instanceof Iterable)) {
|
|
|
+ return rows;
|
|
|
+ }
|
|
|
+ for (Object item : (Iterable<?>) value) {
|
|
|
+ Map<String, Object> row = objectToMap(item);
|
|
|
+ if (!row.isEmpty()) {
|
|
|
+ rows.add(row);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return rows;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Object firstNonBlank(Object first, Object second) {
|
|
|
+ return isBlank(first) ? second : first;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Object firstNonBlank(Object first, Object second, Object third) {
|
|
|
+ Object value = firstNonBlank(first, second);
|
|
|
+ return isBlank(value) ? third : value;
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<String> toStringList(Object value) {
|
|
|
+ if (isBlank(value)) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+ if (value instanceof Iterable) {
|
|
|
+ List<String> values = new ArrayList<String>();
|
|
|
+ for (Object item : (Iterable<?>) value) {
|
|
|
+ if (!isBlank(item)) {
|
|
|
+ values.add(String.valueOf(item).trim());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return values;
|
|
|
+ }
|
|
|
+ return Collections.singletonList(String.valueOf(value).trim());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将 ERP 公司/企业编码转换为宜搭申请公司选项文案。
|
|
|
+ */
|
|
|
+ private String toCompanyName(Object value) {
|
|
|
+ String text = toText(value);
|
|
|
+ if (text == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ if ("87".equals(text) || "ML".equalsIgnoreCase(text) || "zh_CN".equalsIgnoreCase(text)) {
|
|
|
+ return "\u660e\u78ca";
|
|
|
+ }
|
|
|
+ if ("VN".equalsIgnoreCase(text) || "vi_VN".equalsIgnoreCase(text)) {
|
|
|
+ return "\u8d8a\u5357";
|
|
|
+ }
|
|
|
+ return text;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Long toDateMillis(Object value) {
|
|
|
+ String text = toText(value);
|
|
|
+ if (text == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ if (text.matches("\\d+")) {
|
|
|
+ return Long.valueOf(text);
|
|
|
+ }
|
|
|
+ return LocalDate.parse(text.replace('/', '-')).atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
|
|
|
+ }
|
|
|
+
|
|
|
+ private BigDecimal toDecimal(Object value) {
|
|
|
+ String text = toText(value);
|
|
|
+ return text == null ? null : new BigDecimal(text);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String toText(Object value) {
|
|
|
+ return isBlank(value) ? null : String.valueOf(value).trim();
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean isBlank(Object value) {
|
|
|
+ if (value == null) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (value instanceof Iterable) {
|
|
|
+ return !((Iterable<?>) value).iterator().hasNext();
|
|
|
+ }
|
|
|
+ if (value instanceof Map) {
|
|
|
+ return ((Map<?, ?>) value).isEmpty();
|
|
|
+ }
|
|
|
+ return String.valueOf(value).trim().isEmpty();
|
|
|
+ }
|
|
|
+
|
|
|
+ private String extractProcessInstanceId(DDR_New response) {
|
|
|
+ if (response == null) {
|
|
|
+ throw new McException("YIDA_NULL_RESPONSE", "Yida process start failed: empty response");
|
|
|
+ }
|
|
|
+ Object result = firstNonBlank(firstNonBlank(response.getResult(), response.getInstanceId()), response.getFormInstId());
|
|
|
+ if (!isBlank(result)) {
|
|
|
+ return String.valueOf(result);
|
|
|
+ }
|
|
|
+ if (response.isSuccess()) {
|
|
|
+ return "SUCCESS";
|
|
|
+ }
|
|
|
+ throw new McException(defaultText(response.getCode(), "YIDA_ERROR"),
|
|
|
+ "Yida process start failed: " + defaultText(response.getMessage(), "no process instance id"));
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<String, Object> maskSensitive(Map<String, Object> source) {
|
|
|
+ Map<String, Object> body = new LinkedHashMap<String, Object>(source);
|
|
|
+ body.put("systemToken", "******");
|
|
|
+ return body;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String rootMessage(Throwable exception) {
|
|
|
+ Throwable current = exception;
|
|
|
+ while (current.getCause() != null && current.getCause() != current) {
|
|
|
+ current = current.getCause();
|
|
|
+ }
|
|
|
+ return defaultText(current.getMessage(), current.getClass().getSimpleName());
|
|
|
+ }
|
|
|
+
|
|
|
+ private String defaultText(String value, String fallback) {
|
|
|
+ return value == null || value.trim().isEmpty() ? fallback : value.trim();
|
|
|
+ }
|
|
|
+
|
|
|
+ private String requireText(String value, String message) {
|
|
|
+ if (value == null || value.trim().isEmpty()) {
|
|
|
+ throw new IllegalArgumentException(message);
|
|
|
+ }
|
|
|
+ return value.trim();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void putIfNotBlank(Map<String, Object> target, String key, Object value) {
|
|
|
+ if (!isBlank(value)) {
|
|
|
+ target.put(key, value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void validateConfiguration() {
|
|
|
+ requireText(dingTalkConfiguration.getAppKey(), "DINGTALK_APP_KEY is not configured");
|
|
|
+ requireText(dingTalkConfiguration.getAppSecret(), "DINGTALK_APP_SECRET is not configured");
|
|
|
+ requireText(applications.getCoordinationOffice().getAppType(), "YIDA_COORDINATION_OFFICE_APP_TYPE is not configured");
|
|
|
+ requireText(applications.getCoordinationOffice().getSystemToken(), "YIDA_COORDINATION_OFFICE_SYSTEM_TOKEN is not configured");
|
|
|
+ }
|
|
|
+}
|