|
@@ -0,0 +1,501 @@
|
|
|
|
|
+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;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 订单变更申请流程(axmt510)ERP 推送到宜搭的处理器。
|
|
|
|
|
+ * <p>
|
|
|
|
|
+ * 仅负责发起流程;不做 ERP 回写。宜搭表头「变更事件」、附件与已到物料区无对应 ERP 字段,推送时不填。
|
|
|
|
|
+ */
|
|
|
|
|
+@Service
|
|
|
|
|
+public class Axmt510FormPushHandler implements YidaFormPushHandler {
|
|
|
|
|
+
|
|
|
|
|
+ public static final String TYPE = "axmt510";
|
|
|
|
|
+
|
|
|
|
|
+ private static final Logger LOGGER = LoggerFactory.getLogger(Axmt510FormPushHandler.class);
|
|
|
|
|
+ private static final String START_PROCESS_ENDPOINT = "/v1.0/yida/processes/instances/start";
|
|
|
|
|
+ private static final String FORM_NAME = "\u8ba2\u5355\u53d8\u66f4\u7533\u8bf7\u6d41\u7a0b";
|
|
|
|
|
+ private static final String FORM_UUID = "FORM-8F318292B70D4ED39080EE0C631DC74BG3MD";
|
|
|
|
|
+ private static final String PROCESS_CODE = "TPROC--BHC66W71Q1N87Q0YFD7FVBNYXRJ62OIA378TM4";
|
|
|
|
|
+
|
|
|
|
|
+ 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_mso1em48";
|
|
|
|
|
+ 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 ORDER_NO_FIELD_ID = "textField_mt7zi4fy";
|
|
|
|
|
+ private static final String CHANGE_SEQ_FIELD_ID = "textField_mt82p09d";
|
|
|
|
|
+ private static final String ORDER_DATE_FIELD_ID = "dateField_mt82p09f";
|
|
|
|
|
+ private static final String VERSION_FIELD_ID = "numberField_mt82p090";
|
|
|
|
|
+ private static final String SALES_PERSON_FIELD_ID = "employeeField_mt82p08t";
|
|
|
|
|
+ private static final String SALES_DEPARTMENT_FIELD_ID = "departmentSelectField_mt82p08u";
|
|
|
|
|
+ private static final String PRICE_TAX_INCLUDED_FIELD_ID = "textField_mt82p092";
|
|
|
|
|
+ private static final String CUSTOMER_SHORT_NAME_FIELD_ID = "textField_mt82p08x";
|
|
|
|
|
+ private static final String CUSTOMER_CODE_FIELD_ID = "textField_mt80nq6v";
|
|
|
|
|
+ private static final String ORDER_AMOUNT_FIELD_ID = "numberField_mt8747pu";
|
|
|
|
|
+ private static final String CHANGE_TYPE_FIELD_ID = "textField_mt82p091";
|
|
|
|
|
+ private static final String CHANGE_DATE_FIELD_ID = "dateField_mt8747pm";
|
|
|
|
|
+ private static final String CHANGE_REASON_FIELD_ID = "textField_mt8747ps";
|
|
|
|
|
+ private static final String REMARK_FIELD_ID = "textField_mt82p097";
|
|
|
|
|
+
|
|
|
|
|
+ private static final String TABLE1_FIELD_ID = "tableField_szfz1tq1x";
|
|
|
|
|
+ private static final String T1_CHANGE_TYPE_FIELD_ID = "textField_szfz22fyf";
|
|
|
|
|
+ private static final String T1_PRODUCTION_ORDER_FIELD_ID = "textField_szfz3cca2";
|
|
|
|
|
+ private static final String T1_ENT_FIELD_ID = "textField_szfz5ljgx";
|
|
|
|
|
+ private static final String T1_CHANGE_EVENT_FIELD_ID = "selectField_mt8704bs";
|
|
|
|
|
+ private static final String T1_ORDER_NO_FIELD_ID = "textField_szfz6aq91";
|
|
|
|
|
+ private static final String T1_SEQ_FIELD_ID = "textField_szg07bfcn";
|
|
|
|
|
+ private static final String T1_CHANGE_SEQ_FIELD_ID = "textField_szg08jck1";
|
|
|
|
|
+ private static final String T1_ITEM_CODE_FIELD_ID = "textField_szg09edmz";
|
|
|
|
|
+ private static final String T1_FEATURE_FIELD_ID = "textField_szg0a66fa";
|
|
|
|
|
+ private static final String T1_ITEM_NAME_FIELD_ID = "textField_szg0bss4a";
|
|
|
|
|
+ private static final String T1_SPEC_FIELD_ID = "textField_szg0ceqy1";
|
|
|
|
|
+ private static final String T1_OLD_QTY_FIELD_ID = "numberField_szg0dtccz";
|
|
|
|
|
+ private static final String T1_OLD_DATE_FIELD_ID = "dateField_szg0e4ole";
|
|
|
|
|
+ private static final String T1_OLD_PRICE_FIELD_ID = "numberField_szg0fi31q";
|
|
|
|
|
+ private static final String T1_UNIT_FIELD_ID = "textField_szg0gvyi9";
|
|
|
|
|
+ private static final String T1_QTY_FIELD_ID = "numberField_szg0hxy1p";
|
|
|
|
|
+ private static final String T1_NEW_DATE_FIELD_ID = "dateField_szg0i15qu";
|
|
|
|
|
+ private static final String T1_PRICE_FIELD_ID = "numberField_szg0jbz6d";
|
|
|
|
|
+ private static final String T1_PRE_TAX_FIELD_ID = "numberField_szg0kq9ry";
|
|
|
|
|
+ private static final String T1_TAX_INCLUDED_FIELD_ID = "numberField_szg0l0qa8";
|
|
|
|
|
+ private static final String T1_TAX_FIELD_ID = "numberField_szg0mi5ng";
|
|
|
|
|
+ private static final String T1_REASON_CODE_FIELD_ID = "textField_szg0nvyt1";
|
|
|
|
|
+ private static final String T1_HOLD_REASON_FIELD_ID = "textField_szg0oijvw";
|
|
|
|
|
+
|
|
|
|
|
+ private static final String TABLE2_FIELD_ID = "tableField_szg0ppgwk";
|
|
|
|
|
+ private static final String T2_ENT_FIELD_ID = "textField_szg0qj321";
|
|
|
|
|
+ private static final String T2_ORDER_NO_FIELD_ID = "textField_szg0rxeaq";
|
|
|
|
|
+ private static final String T2_ORDER_ITEM_FIELD_ID = "textField_szg0sweog";
|
|
|
|
|
+ private static final String T2_ITEM_SEQ_FIELD_ID = "textField_szg0tr9pg";
|
|
|
|
|
+ private static final String T2_BATCH_SEQ_FIELD_ID = "textField_szg0utkgt";
|
|
|
|
|
+ private static final String T2_CHANGE_SEQ_FIELD_ID = "textField_szg0vnkgp";
|
|
|
|
|
+ private static final String T2_ITEM_CODE_FIELD_ID = "textField_szg0wmfd6";
|
|
|
|
|
+ private static final String T2_UNIT_FIELD_ID = "textField_szg0xdr6b";
|
|
|
|
|
+ private static final String T2_TOTAL_QTY_FIELD_ID = "numberField_szg0ycu5y";
|
|
|
|
|
+ private static final String T2_DELIVERY_TYPE_FIELD_ID = "textField_szg0zywse";
|
|
|
|
|
+ private static final String T2_DELIVERY_DATE_FIELD_ID = "dateField_szg010bkcz";
|
|
|
|
|
+
|
|
|
|
|
+ private static final String TABLE3_FIELD_ID = "tableField_szg011or3m";
|
|
|
|
|
+ private static final String T3_ENT_FIELD_ID = "textField_szg012wixs";
|
|
|
|
|
+ private static final String T3_DOC_NO_FIELD_ID = "textField_szg113yzwu";
|
|
|
|
|
+ private static final String T3_SEQ_FIELD_ID = "textField_szg114dozi";
|
|
|
|
|
+ private static final String T3_ITEM_SEQ_FIELD_ID = "textField_szg1150r3z";
|
|
|
|
|
+ private static final String T3_ITEM_CODE_FIELD_ID = "textField_szg116f94y";
|
|
|
|
|
+ private static final String T3_ITEM_NAME_FIELD_ID = "textField_szg117vhha";
|
|
|
|
|
+ private static final String T3_SPEC_FIELD_ID = "textField_szg118b8ug";
|
|
|
|
|
+ private static final String T3_FEATURE_FIELD_ID = "textField_szg119ljxs";
|
|
|
|
|
+ private static final String T3_COMPOSE_QTY_FIELD_ID = "numberField_szg11agf56";
|
|
|
|
|
+ private static final String T3_BASE_QTY_FIELD_ID = "numberField_szg11be5cl";
|
|
|
|
|
+ private static final String T3_UNIT_FIELD_ID = "textField_szg11cnr1x";
|
|
|
|
|
+ private static final String T3_DEMAND_QTY_FIELD_ID = "numberField_szg11dw9lj";
|
|
|
|
|
+ private static final String T3_CHANGE_SEQ_FIELD_ID = "textField_szg11evyco";
|
|
|
|
|
+ private static final String T3_CHANGE_TYPE_FIELD_ID = "textField_szg11f15ze";
|
|
|
|
|
+
|
|
|
|
|
+ private final YidaProcessOpenApiClient yidaProcessOpenApiClient;
|
|
|
|
|
+ private final DDConf dingTalkConfiguration;
|
|
|
|
|
+ private final YidaApplicationsProperties applications;
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 创建订单变更申请推送处理器。
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param yidaProcessOpenApiClient 宜搭流程 OpenAPI 客户端
|
|
|
|
|
+ * @param dingTalkConfiguration 钉钉应用配置
|
|
|
|
|
+ * @param applications 宜搭应用配置
|
|
|
|
|
+ */
|
|
|
|
|
+ public Axmt510FormPushHandler(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), "axmt510 requires mainData.tjr");
|
|
|
|
|
+ Map<String, Object> formData = toYidaFormData(request, mainData, operatorUserId);
|
|
|
|
|
+ String title = requireText(toText(formData.get(TITLE_FIELD_ID)), "axmt510 requires mainData.xmeedocno");
|
|
|
|
|
+
|
|
|
|
|
+ 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("xmeedocno"));
|
|
|
|
|
+ String changeSeq = toText(mainData.get("xmee900"));
|
|
|
|
|
+ String titleSuffix = docNo == null ? null
|
|
|
|
|
+ : (changeSeq == null ? docNo : docNo + "-" + changeSeq);
|
|
|
|
|
+ String title = titleSuffix == null ? null : FORM_NAME + "-" + titleSuffix;
|
|
|
|
|
+ Object company = toCompanyName(firstNonBlank(mainData.get("gs"), mainData.get("xmeeent"), 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("xmee902"), mainData.get("xmeedocdt"))));
|
|
|
|
|
+ putIfNotBlank(formData, FORM_TITLE_FIELD_ID, title);
|
|
|
|
|
+
|
|
|
|
|
+ putIfNotBlank(formData, ENTERPRISE_FIELD_ID, mainData.get("xmeeent"));
|
|
|
|
|
+ putIfNotBlank(formData, ORDER_NO_FIELD_ID, docNo);
|
|
|
|
|
+ putIfNotBlank(formData, CHANGE_SEQ_FIELD_ID, mainData.get("xmee900"));
|
|
|
|
|
+ putIfNotBlank(formData, ORDER_DATE_FIELD_ID, toDateMillis(mainData.get("xmeedocdt")));
|
|
|
|
|
+ putIfNotBlank(formData, VERSION_FIELD_ID, toDecimal(mainData.get("xmee001")));
|
|
|
|
|
+ putIfNotBlank(formData, SALES_PERSON_FIELD_ID, toStringList(mainData.get("xmee002")));
|
|
|
|
|
+ putIfNotBlank(formData, SALES_DEPARTMENT_FIELD_ID, toStringList(mainData.get("xmee003")));
|
|
|
|
|
+ putIfNotBlank(formData, CUSTOMER_CODE_FIELD_ID, mainData.get("xmee004"));
|
|
|
|
|
+ putIfNotBlank(formData, CUSTOMER_SHORT_NAME_FIELD_ID, mainData.get("pmaal004"));
|
|
|
|
|
+ putIfNotBlank(formData, PRICE_TAX_INCLUDED_FIELD_ID, mainData.get("xmee013"));
|
|
|
|
|
+ putIfNotBlank(formData, ORDER_AMOUNT_FIELD_ID, toDecimal(mainData.get("xmee042")));
|
|
|
|
|
+ putIfNotBlank(formData, CHANGE_TYPE_FIELD_ID, mainData.get("xmee901"));
|
|
|
|
|
+ putIfNotBlank(formData, CHANGE_DATE_FIELD_ID, toDateMillis(mainData.get("xmee902")));
|
|
|
|
|
+ putIfNotBlank(formData, CHANGE_REASON_FIELD_ID, mainData.get("xmee903"));
|
|
|
|
|
+ putIfNotBlank(formData, REMARK_FIELD_ID, mainData.get("xmee904"));
|
|
|
|
|
+
|
|
|
|
|
+ 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);
|
|
|
|
|
+ }
|
|
|
|
|
+ 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_CHANGE_TYPE_FIELD_ID, source.get("xmeg901"));
|
|
|
|
|
+ putIfNotBlank(row, T1_PRODUCTION_ORDER_FIELD_ID, source.get("xmegud010"));
|
|
|
|
|
+ putIfNotBlank(row, T1_ENT_FIELD_ID, source.get("xmegent"));
|
|
|
|
|
+ putIfNotBlank(row, T1_CHANGE_EVENT_FIELD_ID, source.get("xmegkk"));
|
|
|
|
|
+ putIfNotBlank(row, T1_ORDER_NO_FIELD_ID, source.get("xmegdocno"));
|
|
|
|
|
+ putIfNotBlank(row, T1_SEQ_FIELD_ID, source.get("xmegseq"));
|
|
|
|
|
+ putIfNotBlank(row, T1_CHANGE_SEQ_FIELD_ID, source.get("xmeg900"));
|
|
|
|
|
+ putIfNotBlank(row, T1_ITEM_CODE_FIELD_ID, source.get("xmeg001"));
|
|
|
|
|
+ putIfNotBlank(row, T1_FEATURE_FIELD_ID, source.get("xmeg002"));
|
|
|
|
|
+ putIfNotBlank(row, T1_ITEM_NAME_FIELD_ID, source.get("imaal003"));
|
|
|
|
|
+ putIfNotBlank(row, T1_SPEC_FIELD_ID, source.get("imaal004"));
|
|
|
|
|
+ putIfNotBlank(row, T1_OLD_QTY_FIELD_ID, toDecimal(source.get("xmdc007")));
|
|
|
|
|
+ putIfNotBlank(row, T1_OLD_DATE_FIELD_ID, toDateMillis(source.get("xmdc012")));
|
|
|
|
|
+ putIfNotBlank(row, T1_OLD_PRICE_FIELD_ID, toDecimal(source.get("xmdc015")));
|
|
|
|
|
+ putIfNotBlank(row, T1_UNIT_FIELD_ID, source.get("xmeg006"));
|
|
|
|
|
+ putIfNotBlank(row, T1_QTY_FIELD_ID, toDecimal(source.get("xmeg007")));
|
|
|
|
|
+ putIfNotBlank(row, T1_NEW_DATE_FIELD_ID, toDateMillis(source.get("xmeg012")));
|
|
|
|
|
+ putIfNotBlank(row, T1_PRICE_FIELD_ID, toDecimal(source.get("xmeg015")));
|
|
|
|
|
+ putIfNotBlank(row, T1_PRE_TAX_FIELD_ID, toDecimal(source.get("xmeg046")));
|
|
|
|
|
+ putIfNotBlank(row, T1_TAX_INCLUDED_FIELD_ID, toDecimal(source.get("xmeg047")));
|
|
|
|
|
+ putIfNotBlank(row, T1_TAX_FIELD_ID, toDecimal(source.get("xmeg048")));
|
|
|
|
|
+ putIfNotBlank(row, T1_REASON_CODE_FIELD_ID, source.get("xmeg049"));
|
|
|
|
|
+ putIfNotBlank(row, T1_HOLD_REASON_FIELD_ID, source.get("xmeg053"));
|
|
|
|
|
+ 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("xmehent"));
|
|
|
|
|
+ putIfNotBlank(row, T2_ORDER_NO_FIELD_ID, source.get("xmehdocno"));
|
|
|
|
|
+ putIfNotBlank(row, T2_ORDER_ITEM_FIELD_ID, source.get("xmehseq"));
|
|
|
|
|
+ putIfNotBlank(row, T2_ITEM_SEQ_FIELD_ID, source.get("xmehseq1"));
|
|
|
|
|
+ putIfNotBlank(row, T2_BATCH_SEQ_FIELD_ID, source.get("xmehseq2"));
|
|
|
|
|
+ putIfNotBlank(row, T2_CHANGE_SEQ_FIELD_ID, source.get("xmeh900"));
|
|
|
|
|
+ putIfNotBlank(row, T2_ITEM_CODE_FIELD_ID, source.get("xmeh001"));
|
|
|
|
|
+ putIfNotBlank(row, T2_UNIT_FIELD_ID, source.get("xmeh004"));
|
|
|
|
|
+ putIfNotBlank(row, T2_TOTAL_QTY_FIELD_ID, toDecimal(source.get("xmeh005")));
|
|
|
|
|
+ putIfNotBlank(row, T2_DELIVERY_TYPE_FIELD_ID, source.get("xmeh009"));
|
|
|
|
|
+ putIfNotBlank(row, T2_DELIVERY_DATE_FIELD_ID, toDateMillis(source.get("xmeh011")));
|
|
|
|
|
+ if (!row.isEmpty()) {
|
|
|
|
|
+ rows.add(row);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return rows;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 映射子表3(订单变更配件明细)。
|
|
|
|
|
+ */
|
|
|
|
|
+ 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("xmfwucent"));
|
|
|
|
|
+ putIfNotBlank(row, T3_DOC_NO_FIELD_ID, source.get("xmfwucdocno"));
|
|
|
|
|
+ putIfNotBlank(row, T3_SEQ_FIELD_ID, source.get("xmfwucseq"));
|
|
|
|
|
+ putIfNotBlank(row, T3_ITEM_SEQ_FIELD_ID, source.get("xmfwucseq1"));
|
|
|
|
|
+ putIfNotBlank(row, T3_ITEM_CODE_FIELD_ID, source.get("xmfwuc001"));
|
|
|
|
|
+ putIfNotBlank(row, T3_ITEM_NAME_FIELD_ID, source.get("imaal003"));
|
|
|
|
|
+ putIfNotBlank(row, T3_SPEC_FIELD_ID, source.get("imaal004"));
|
|
|
|
|
+ putIfNotBlank(row, T3_FEATURE_FIELD_ID, source.get("xmfwucud001"));
|
|
|
|
|
+ putIfNotBlank(row, T3_COMPOSE_QTY_FIELD_ID, toDecimal(source.get("xmfwuc006")));
|
|
|
|
|
+ putIfNotBlank(row, T3_BASE_QTY_FIELD_ID, toDecimal(source.get("xmfwuc007")));
|
|
|
|
|
+ putIfNotBlank(row, T3_UNIT_FIELD_ID, source.get("xmfwuc008"));
|
|
|
|
|
+ putIfNotBlank(row, T3_DEMAND_QTY_FIELD_ID, toDecimal(source.get("xmfwuc009")));
|
|
|
|
|
+ putIfNotBlank(row, T3_CHANGE_SEQ_FIELD_ID, source.get("xmfwuc900"));
|
|
|
|
|
+ putIfNotBlank(row, T3_CHANGE_TYPE_FIELD_ID, source.get("xmfwuc901"));
|
|
|
|
|
+ if (!row.isEmpty()) {
|
|
|
|
|
+ rows.add(row);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return rows;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ 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());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ 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");
|
|
|
|
|
+ }
|
|
|
|
|
+}
|