明磊中间键代码仓库

ht 2237a82dfb 接口开发 2 days ago
.mvn db8939c1db chore: sync minglei project 4 days ago
src 2237a82dfb 接口开发 2 days ago
.gitignore db8939c1db chore: sync minglei project 4 days ago
ERP-YIDA-PUSH-API.md db8939c1db chore: sync minglei project 4 days ago
README.md 2237a82dfb 接口开发 2 days ago
pom.xml db8939c1db chore: sync minglei project 4 days ago

README.md

mjava-minglei

明磊业务集成服务。项目基于 Spring Boot 2.7 构建,用于对接钉钉、宜搭、员工花名册以及明磊外部 T100 接口。

本文档说明当前工程的模块边界、配置项、REST 接口、ERP 推送规则和本地构建方式。文档中的凭证均使用占位符,真实密钥必须通过环境变量或部署配置注入。

1. 技术栈

技术 说明
Java JDK 8
Spring Boot 2.7.18
Spring MVC REST Controller、参数绑定、异常处理
Spring Validation 请求参数校验
Maven 构建和依赖管理
com.malk:mjava 钉钉、宜搭客户端和基础模型,当前版本 0.0.3
Jackson / Fastjson JSON 绑定、序列化和表单字段组装
RestTemplate 调用外部 T100 HTTP 接口
Logback + SLF4J 应用日志、错误日志和请求响应日志
JUnit 5 + Mockito 单元测试

2. 工程结构

src/main/java/com/malk/minglei
|-- MjavaMingleiApplication.java
|-- config
|   |-- DingTalkRosterConfiguration.java
|   |-- EmployeeRosterConfiguration.java
|   |-- EmployeeRosterProperties.java
|   |-- HttpRequestResponseLoggingFilter.java
|   |-- MingleiPortConfiguration.java
|   |-- MingleiPortProperties.java
|   |-- MjavaYidaConfiguration.java
|   `-- YidaApplicationsProperties.java
|-- controller
|   |-- EmployeeRosterController.java
|   |-- ErpYidaPushController.java
|   |-- GlobalExceptionHandler.java
|   |-- MingleiPortController.java
|   `-- YidaProcessController.java
|-- dto
`-- service
    |-- employee
    |-- port
    |-- yida
    `-- impl
        |-- employee
        |-- port
        `-- yida

2.1 分层职责

层级 职责
controller 暴露 HTTP 接口,处理请求校验和响应包装
dto 请求体、响应体和业务数据模型
service.employee 员工花名册同步、查询和钉钉人员数据处理
service.port 明磊外部 T100 接口转发
service.yida 宜搭流程、宜搭表单查询、ERP 推送分发
service.impl.* 各业务实现、处理器和内部辅助类

新增能力时优先放入现有业务域。只有出现清晰的新业务边界、独立生命周期或独立外部依赖时,才新增新的 Service 分类。

3. 配置说明

配置文件位于 src/main/resources/application.yml。生产环境不要使用文件中的默认示例值,应通过环境变量覆盖。

配置项 环境变量 用途
server.port SERVER_PORT HTTP 服务端口
spring.profiles.active SPRING_PROFILES_ACTIVE Spring Profile
dingtalk.agent-id DINGTALK_AGENT_ID 钉钉应用 AgentId
dingtalk.app-key DINGTALK_APP_KEY 钉钉应用 Key
dingtalk.app-secret DINGTALK_APP_SECRET 钉钉应用 Secret
minglei.yida.coordination-office.app-type YIDA_COORDINATION_OFFICE_APP_TYPE 协同办公宜搭应用编码
minglei.yida.coordination-office.system-token YIDA_COORDINATION_OFFICE_SYSTEM_TOKEN 协同办公宜搭应用 System Token
minglei.yida.master-data.app-type YIDA_MASTER_DATA_APP_TYPE 主数据宜搭应用编码
minglei.yida.master-data.system-token YIDA_MASTER_DATA_SYSTEM_TOKEN 主数据宜搭应用 System Token
minglei.port.supplier-price-approval-url MINGLEI_SUPPLIER_PRICE_APPROVAL_URL 外部 T100 接口地址
minglei.port.supplier-price-approval-key MINGLEI_SUPPLIER_PRICE_APPROVAL_KEY 外部 T100 接口接入密钥
minglei.employee-roster.datasource.url MINGLEI_EMPLOYEE_ROSTER_DATASOURCE_URL 员工花名册 MySQL JDBC 地址
minglei.employee-roster.datasource.username MINGLEI_EMPLOYEE_ROSTER_DATASOURCE_USERNAME 员工花名册数据库用户名
minglei.employee-roster.datasource.password MINGLEI_EMPLOYEE_ROSTER_DATASOURCE_PASSWORD 员工花名册数据库密码
minglei.employee-roster.datasource.driver-class-name MINGLEI_EMPLOYEE_ROSTER_DATASOURCE_DRIVER_CLASS_NAME JDBC 驱动类
logging.file.path LOGGING_FILE_PATH 日志输出目录

MjavaYidaConfiguration 注册两套宜搭客户端:

Bean 用途
coordinationOfficeYidaClient 协同办公应用,主要用于发起流程
masterDataYidaClient 主数据应用,主要用于查询主数据表单

4. REST 接口

4.1 宜搭流程发起

POST /api/yida/process-instances
Content-Type: application/json

请求示例:

{
  "type": "cpmp402",
  "userId": "41603502201288023",
  "dataTitle": "包材核价单",
  "fields": {
    "mainData": {
      "rq": "2026-09-08",
      "bm": "ML07000000",
      "tjr": "3075",
      "gs": "ML",
      "t100id": "ML",
      "ent": "87",
      "t100bm": "ML07000000"
    },
    "detailData": {
      "detailData": [
        {
          "hjdh": "MLCH326090800001",
          "gysbh": "113009",
          "gysmc": "供应商名称",
          "t100id": "ML",
          "ent": "87",
          "yy": "zh_CN"
        }
      ]
    }
  }
}

成功响应为 HTTP 201 Created

{
  "code": 200,
  "isSuccess": true,
  "result": {
    "processInstanceId": "process-instance-id"
  }
}

4.2 宜搭主数据表单查询

分页查询:

GET /api/yida/minglei/forms/instances?page=1&size=20

精确查询:

POST /api/yida/minglei/forms/instances/query
Content-Type: application/json

请求示例:

{
  "dept_id": "123456",
  "user_id": "dingTalkUserId",
  "dept_name": "明磊锂能技术部"
}

精确查询优先级为 dept_iduser_iddept_name。传入 user_id 时,服务端会先查询人员所属部门,再按部门 ID 查询主数据。

4.3 部门成员查询

POST /api/yida/minglei/departments/users
Content-Type: application/json

请求示例:

{
  "dept_Id": "123456,234567",
  "type": 0,
  "userIds": ["user-1", "user-2"]
}

userIds 为可选的用户 ID 列表。未传或传入空数组时不影响部门成员查询结果;传入非空列表时,列表中的用户 ID 会按传入顺序追加在部门成员列表之后,并与部门成员及列表内其他 ID 一并去重。

dept_Id 支持单个部门 ID,或多个以英文逗号分隔的部门 ID;返回结果为各部门查询范围内人员的去重合集。

type 取值:

说明
0 查询指定部门和所有子部门
1 仅查询指定部门

4.4 员工花名册

同步指定部门:

POST /api/yida/minglei/employee-roster/sync?departmentId=1&type=0

全量同步:

POST /api/yida/minglei/employee-roster/sync-full

按钉钉用户 ID 查询花名册:

POST /api/yida/minglei/employee-roster/getUserRoster
Content-Type: application/json

4.5 外部 T100 接口转发

POST /api/minglei/ports/supplier-price-approvals
Content-Type: application/json

请求体只需要提供 headdetail,服务端会补齐外部接口协议固定字段。

{
  "head": {
    "pmdidocno": "CH3",
    "pmdi001": "N",
    "pmdi034": "605188",
    "pmdidocdt": "2026-08-06"
  },
  "detail": [
    {
      "pmdj011": "0.5000",
      "pmdj002": "524000059517022000000"
    }
  ]
}

4.6 ERP 推送宜搭

POST /api/erp/yida/push
Content-Type: application/json

请求示例:

{
  "type": "axmt140",
  "mainData": {
    "rq": "2026-09-08",
    "bm": "123456",
    "tjr": "3075",
    "gs": "ML"
  },
  "detailData": {
    "detailData1": [
      {
        "xmfyseq": "10",
        "xmfy002": "DN-001",
        "xmfy003": "2026-09-08",
        "xmfy004": "CUS-001",
        "pmaal004": "客户名称"
      }
    ]
  }
}

成功响应使用 McR.success()

{
  "success": true,
  "code": "200",
  "message": "SUCCESS"
}

5. ERP 推送规则

5.1 支持的类型

type 会去除首尾空格并转为大写后匹配,调用方传入大小写不敏感。

type 或别名 处理器 单据或流程 表单 UUID 流程编码
cpmp402 Cpmp402YidaProcessHandler 包材核价单 FORM-A3D4889187E54697A59590BE54F350E7AOO5 TPROC--98G66QB1NTF8E1R1LI0OK4D6JI9437HC92YSM1
FORM-4403B45A7F184CB79088FCDAFD2FD925LZ3K MlWorkOrderCraftPriceFormPushHandler ML-工单工艺工价审定 FORM-4403B45A7F184CB79088FCDAFD2FD925LZ3K TPROC--WG966BA1VWF8Q1K4OGF8H9KW47RR3ZREH0YSM2
axmt500 ApproveOrderFormPushHandler 客户订单审批 FORM-8454FA17732746058A2D90B1C559CC19G5SR TPROC--9VD66QA18AJ8317KK3NXM54W1HIT30C7N28TM7
axmt140 CustomerReleaseFormPushHandler 客户放行审批 FORM-3BA9FE18494F4FDD85FE6ABF7DE741BAE30C TPROC--6TG66381N8G8Y7L9GBEEY7QVXTUY2LBBGZ7TMU
cint301 MiscReceiptIssueFormPushHandler 杂收杂发审批 FORM-4B08ADABCDAA45788C043729A855E03ED76G TPROC--MQD66371C1N84FPSJZO4W79IN4BW2AE7I08TM0
asft800 Asft800FormPushHandler 包装工单变更审批流程 FORM-40D6FBBBF4A94864A2AF9535AAC7924CRBH2 TPROC--U2I66F719HF854X6PIGK5A2AP9VC2LODB7YSM1
apmt100 Apmt100FormPushHandler 供应商导入流程 FORM-9EE14CA14D8D4AEE8102944E669E6B0CFUKS TPROC--75G66PD15YG82766OFSWD8BS4ZJ33YPRFOZSM2

5.2 mainData 规则

字段 说明
rq 申请日期,通常为 yyyy-MM-dd 或毫秒时间戳
bm 钉钉部门 ID
tjr 提交人工号,用于查询员工花名册并解析钉钉 userId
gs 公司或组织编码
t100id T100 业务标识
ent 地区或企业编号
t100bm T100 部门

顶层 bmgstjr 非空时,会覆盖写入 mainData。服务端会将 mainData 中的通用字段补入各明细行,便于表单处理器复用。

5.3 detailData 规则

detailData 外层必须是对象,内部至少包含一个数组字段。数组字段名支持:

  • detailData
  • detailData1
  • detailData2
  • 其他满足 detailData\d* 格式的字段

不同单据的约定:

类型 明细字段
cpmp402 detailData
FORM-4403B45A7F184CB79088FCDAFD2FD925LZ3K detailData
axmt500 detailData1detailData2,兼容历史 detailData
axmt140 优先 detailData1,缺失时回退到 detailData
cint301 detailData1
asft800 detailData1
apmt100 无明细,传入空对象 {}

明细对象中可以直接传入宜搭 fieldId。服务端会保留包含 Field_ 的字段值,用于补充默认字段映射。

5.4 发起人解析

  1. ErpYidaPushServiceImpl 优先使用顶层 tjr,其次使用 mainData.tjr
  2. 服务端通过员工花名册查询工号对应的 dingtalkId
  3. dingtalkId 会作为 originatorUserIduserIdapplicant 写入请求上下文或明细行。
  4. 匹配到 YidaFormPushHandler 时,提交人工号允许为空,具体处理器可以使用默认发起人兜底。
  5. 未匹配到表单处理器并走通用 YidaProcessService 时,提交人工号不能为空。

5.5 asft800 包装工单变更审批流程

调用 POST /api/erp/yida/push 时传入 type: "asft800"。表头使用 ERP 原始字段,明细必须放在 detailData.detailData1

{
  "type": "asft800",
  "bm": "123456789",
  "gs": "87",
  "tjr": "EMP0001",
  "mainData": {
    "rq": "2026-09-16",
    "bm": "123456789",
    "gs": "87",
    "tjr": "EMP0001",
    "t100id": "EMP0001",
    "ent": "87",
    "t100bm": "PACK",
    "sfkaent": "87",
    "sfkasite": "ML",
    "sfkadocno": "WO-20260916-001",
    "sfka900": "2",
    "sfka902": "2026/09/16",
    "sfka057": "包装工单",
    "sfka010": "ITEM-001",
    "imaal003": "锂电池包装组件",
    "imaal004": "标准规格",
    "sfka012": 100.5,
    "sfka006": "SOURCE-001",
    "sfkaud009": "MO-001",
    "sfka906": "变更物料及数量",
    "ooagud004": "dingtalk-user-id"
  },
  "detailData": {
    "detailData1": [
      {
        "sfkgent": "87",
        "sfkgdocno": "WO-20260916-001",
        "sfkg900": "2",
        "sfkgseq": "10",
        "sfkg901": "变更",
        "sfkg006": "MAT-002",
        "imaal003": "新物料名称",
        "imaal004": "新物料规格",
        "sfkg013": 101.5,
        "sfkg014": "PCS",
        "sfba006": "MAT-001",
        "o_imaal003": "原物料名称",
        "o_imaal004": "原物料规格",
        "sfba013": 100.0
      }
    ]
  }
}

tjr 是员工工号,服务端会从员工花名册解析对应钉钉用户作为发起人;未传时,处理器使用 mainData.ooagud004 作为钉钉用户 ID。bm 为钉钉部门 ID,sfka902 支持 yyyy-MM-ddyyyy/MM/dd 格式。

5.6 apmt100 供应商导入流程

调用 POST /api/erp/yida/push 时传入 type: "apmt100"。该流程无明细,detailData 必须为 {}

{
  "type": "apmt100",
  "bm": "123456789",
  "gs": "ML",
  "tjr": "EMP0001",
  "mainData": {
    "rq": "2026-09-16",
    "sqlx": "NEW",
    "gysmc": "供应商名称",
    "gysbm": "SUP-001",
    "sh": "91330100TEST",
    "gczczj": "1000000.50",
    "clsj": "2026/09/16",
    "zysccp": "锂电池包装组件",
    "gcgm": "120",
    "lcbh": "PM-001",
    "smzq": "ACTIVE",
    "pmbb033all": "CNY",
    "pmbb034all": "VAT",
    "pmbb053all": "NET30",
    "pmbb033": "CNY",
    "pmbb034": "VAT",
    "pmbb053": "NET30",
    "pmbb037": "NET30",
    "gst100": "ML",
    "lxr": "张三",
    "gsdz": "浙江省杭州市",
    "lxfs": "13800000000"
  },
  "detailData": {}
}

lcbh 用于生成流程标题;若其为空,可使用 docnoclsj 支持 yyyy-MM-ddyyyy/MM/dd。所有 pmbb***all 字段映射到集团惯用数据,未带 all 后缀的 pmbb*** 映射到据点惯用数据。

6. 日志和异常

6.1 日志

Logback 输出:

  • 控制台日志。
  • ${LOGGING_FILE_PATH}/application.log
  • ${LOGGING_FILE_PATH}/error.log
  • archive 目录下的滚动归档日志。

HttpRequestResponseLoggingFilter 会记录 HTTP 方法、URI、状态码、耗时、请求体和响应体。单个载荷最大记录 10KB,并对 passwordsecrettokenauthorizationaccessTokensystemTokenkey 等字段脱敏。

6.2 异常响应

场景 HTTP 状态码 说明
请求体格式错误或参数校验失败 400 请求不合法
配置缺失 412 必要配置未提供
宜搭或钉钉上游业务错误 502 返回上游错误码和错误信息
外部 T100 调用失败 502 返回 MINGLEI_PORT_CALL_FAILED

7. 构建和运行

环境要求:

  • JDK 8
  • Maven 3.6+
  • 可访问项目依赖仓库和内部 malk 依赖

本地构建:

mvn clean package

本地运行:

$env:SERVER_PORT = "8080"
$env:DINGTALK_APP_KEY = "<dingTalk-app-key>"
$env:DINGTALK_APP_SECRET = "<dingTalk-app-secret>"
$env:YIDA_COORDINATION_OFFICE_APP_TYPE = "<coordination-office-app-type>"
$env:YIDA_COORDINATION_OFFICE_SYSTEM_TOKEN = "<coordination-office-system-token>"
$env:YIDA_MASTER_DATA_APP_TYPE = "<master-data-app-type>"
$env:YIDA_MASTER_DATA_SYSTEM_TOKEN = "<master-data-system-token>"

mvn spring-boot:run

运行打包产物:

java -jar target\mjava-minglei-1.0.0-SNAPSHOT.jar

8. 测试

执行完整测试:

mvn clean test

当前测试覆盖:

  • Spring Boot 上下文加载。
  • Controller 请求和响应结构。
  • 员工花名册同步、查询和字段提取。
  • 宜搭流程处理器分发。
  • ERP 推送到不同宜搭表单处理器的字段映射。
  • 外部 T100 请求组装和响应转发。

当前验证结果:

Tests run: 36, Failures: 0, Errors: 0, Skipped: 1

9. 扩展规范

9.1 新增宜搭流程处理器

新增可由 /api/yida/process-instances 触发的通用流程时:

  1. 新建 XxxYidaProcessHandler
  2. 实现 YidaProcessHandler
  3. getType() 返回业务路由编码。
  4. 在处理器中维护表单 UUID、流程编码和字段映射。
  5. 补充对应单元测试。
  6. 更新 README 的支持类型说明。

9.2 新增 ERP 表单推送处理器

新增可由 /api/erp/yida/push 路由的表单流程时:

  1. 新建 XxxFormPushHandler
  2. 实现 YidaFormPushHandler
  3. getTypes() 返回主 type 和必要别名。
  4. 在处理器中维护表单 UUID、流程编码和字段映射。
  5. src/test/java 中补充字段映射和异常测试。
  6. 更新 README 的 ERP 推送类型表。

9.3 字段映射原则

  • 业务 type 是路由键,不等于表单 UUID。
  • 应用凭证、表单 UUID、流程编码由服务端维护,调用方不传。
  • 表单处理器优先使用 ERP 原始字段名映射。
  • 调用方确需补充时,可以传入宜搭 fieldId 字段。
  • 不要在日志、文档或测试数据中写入真实密钥、Token、Cookie 或数据库密码。

10. 运维注意事项

  • 部署账号必须对 LOGGING_FILE_PATH 有写权限。
  • 宜搭和钉钉接口所需的网络连通性、权限范围、组织数据权限由部署环境保证。
  • 当前 Controller 未内置业务鉴权。如需访问控制,应在网关或统一认证层配置。
  • 发生宜搭配置不匹配时,确认应用编码、System Token 和处理器选择的客户端属于同一应用。
  • 员工花名册依赖数据库连接和数据完整性。若 mainData.tjr 无法解析,优先检查花名册同步状态和员工 dingtalkId