明磊中间键代码仓库

ht f402ec817b 接口开发10.27 1 週間 前
.mvn db8939c1db chore: sync minglei project 1 ヶ月 前
src f402ec817b 接口开发10.27 1 週間 前
.gitignore db8939c1db chore: sync minglei project 1 ヶ月 前
DATA-DICTIONARY-API.md 830ebd898b 接口开发10.27 1 週間 前
ERP-YIDA-PUSH-API.md ecd3ab5699 接口开发 4 週間 前
README.md 830ebd898b 接口开发10.27 1 週間 前
SKILL.md be33582068 lzq-1 1 ヶ月 前
pom.xml 43aff05850 接口开发10.20 2 週間 前

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
|   |-- ApprovalTransferDepartmentController.java
|   |-- EmployeeRosterController.java
|   |-- ErpYidaPushController.java
|   |-- GlobalExceptionHandler.java
|   |-- MingleiPortController.java
|   `-- YidaProcessController.java
|-- dto
`-- service
    |-- approval
    |-- employee
    |-- port
    |-- yida
    `-- impl
        |-- approval
        |-- employee
        |-- port
        `-- yida

2.1 分层职责

层级 职责
controller 暴露 HTTP 接口,处理请求校验和响应包装
dto 请求体、响应体和业务数据模型
service.approval 钉钉审批实例查询、表单解析,以及通过宜搭审批矩阵(按"部门"字段匹配)解析转入部门各级别负责人与部门负责人
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.coordination-office.process-instance-query-user-id YIDA_COORDINATION_OFFICE_PROCESS_INSTANCE_QUERY_USER_ID 查询宜搭流程实例时用于数据权限校验的钉钉用户 ID,默认 41603502201288023
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.banking.base-url MINGLEI_BANKING_BASE_URL 除回单外的银企接口地址,默认沙盒环境
minglei.banking.receipt-base-url MINGLEI_BANKING_RECEIPT_BASE_URL 电子回单下载地址,默认正式环境 https://open.nexbankapi.com
minglei.banking.app-id MINGLEI_BANKING_APP_ID NexBank 应用标识
minglei.banking.app-secret MINGLEI_BANKING_APP_SECRET NexBank API Key
minglei.banking.customer-code MINGLEI_BANKING_CUSTOMER_CODE NexBank 客户编号
minglei.banking.default-from-account-no MINGLEI_BANKING_DEFAULT_FROM_ACCOUNT_NO 默认付款账号;支付请求未传 fromAccountNo 时使用
minglei.banking.default-from-account-name MINGLEI_BANKING_DEFAULT_FROM_ACCOUNT_NAME 默认付款账户名称;支付请求未传 fromAccountName 时使用
minglei.banking.intra-bank-name MINGLEI_BANKING_INTRA_BANK_NAME 本行名称;匹配收款银行时自动发送 crossBank=0
minglei.banking.payment-encryption-enabled MINGLEI_BANKING_PAYMENT_ENCRYPTION_ENABLED 单笔支付是否启用 SM2/SM4 加密,默认 true
minglei.banking.xencio-public-key MINGLEI_BANKING_XENCIO_PUBLIC_KEY NexBank 的 SM2 十六进制公钥,仅支付制单需要
minglei.banking.enterprise-private-key MINGLEI_BANKING_ENTERPRISE_PRIVATE_KEY 企业 SM2 十六进制私钥,仅支付制单需要
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 驱动类
minglei.dictionary.datasource.url MINGLEI_DICTIONARY_DATASOURCE_URL 数据字典 Oracle JDBC 地址
minglei.dictionary.datasource.username MINGLEI_DICTIONARY_DATASOURCE_USERNAME 数据字典 Oracle 用户名
minglei.dictionary.datasource.password MINGLEI_DICTIONARY_DATASOURCE_PASSWORD 数据字典 Oracle 密码
minglei.dictionary.datasource.driver-class-name MINGLEI_DICTIONARY_DATASOURCE_DRIVER_CLASS_NAME Oracle JDBC 驱动类,默认 oracle.jdbc.OracleDriver
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 按流程实例 ID 查询宜搭数据

GET /api/yida/process-instances/{processInstanceId}

该接口直接返回钉钉宜搭流程实例详情,仅用于核对实例表单数据和字段映射,不会发起 ERP 推送。processInstanceId 使用宜搭流程实例 ID。

4.3 宜搭主数据表单查询

分页查询:

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_id、user_id、dept_name。传入 user_id 时,服务端会先查询人员所属部门,再按部门 ID 查询主数据。响应固定包含 employeeField_mszdqrl8、employeeField_mszdqrl9、employeeField_mszdqrla、employeeField_mszdqrlb、employeeField_mualkf6a(部门负责人)和 employeeField_mszdqrl3;未匹配到审批矩阵记录或字段未配置时,对应字段值为 null。

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 员工花名册

本地表 employee_roster 的 is_resigned 字段以 1 表示在职、0 表示离职。同步读取到钉钉通讯录用户的 active=false 时,会将该人员更新为离职;花名册按钉钉用户 ID 或工号的查询会自动排除离职人员。

同步还会按钉钉花名册字段名读取“入职时间”“职位”“银行卡号”“开户行”“支行联行号”,分别写入 hire_date、position_name、bank_card_no、bank_name、bank_branch_code。

每次同步完成后,服务会按 username 检查在职重名人员。存在重名时,服务从主数据宜搭表单 FORM-66F0B2216DD64580834D75815BFEF24138F7 的首条记录读取成员字段 employeeField_mv94lty1,并向其中配置的人事人员发送钉钉工作通知。

同步指定部门:

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

响应的 result 包含 hireDate(入职时间)、positionName(职位)、bank_card_no(银行卡号)、bank_name(开户行)和 bank_branch_code(支行联行号)。

4.5 创建钉钉自建企业账号

POST /api/yida/minglei/employee-roster/dingtalk-dedicated-accounts
Content-Type: application/json

接口调用钉钉 topapi/v2/user/create 创建自建企业账号,仅已购买并开通该能力的组织可使用。请求中的 departmentList 支持钉钉 OA 部门名称、部门 ID 或部门选择器原始对象。传入名称时,服务从根部门开始通过钉钉 topapi/v2/department/listsub 逐级查询直属子部门并解析为 dept_id_list,不会遍历全部部门树;支持以 - 或 / 连接的层级名称,例如 集团运营中心-人力资源部。非根级部门应传入完整路径。路径未匹配或当前层级存在同名部门时接口返回 400,不创建账号。

{
  "name": "张三",
  "positionName": "研发工程师",
  "gender": "男",
  "age": 28,
  "expectedArrivalDate": "2026-11-01",
  "jobTitle": "高级工程师",
  "jobGrade": "P6",
  "idCardNo": "330101199801010011",
  "departmentList": ["集团运营中心-人力资源部"],
  "employeeNo": "1001"
}

employeeNo 为可选字段:传入时直接作为员工工号;未传或为空时,服务端从 employee_roster.employee_no 读取当日最大工号,按 YYMMDD 加当日四位流水号生成,例如 2610260001。无论工号来自入参还是自动生成,钉钉登录名和初始登录密码均为 ML_ 加工号(例如 ML_2610260001)。岗位、年龄、职等和身份证号通过钉钉 extension 推送;职称、性别和预计到岗日期分别映射为钉钉 title、gender 和 hired_date,其中日期按上海时区转换为毫秒时间戳。性别支持 1/2、男/女 或 male/female。本地仅写入 employee_roster 已存在的列;性别、年龄和身份证号不写入本地表。成功时返回 HTTP 201 Created;result.userId 为钉钉创建的用户 ID,result.employeeNo 为实际使用的员工工号,result.departmentIds 为实际提交的部门 ID。接口不回显登录密码。

{
  "code": 200,
  "isSuccess": true,
  "result": {
    "userId": "ding-user-1",
    "employeeNo": "2610260001",
    "departmentIds": [1, 2]
  }
}

4.6 数据字典

完整调用说明见 数据字典接口文档。

按字典编码查询已注册的数据字典,筛选条件通过 URL 查询参数传入。当前支持:

字典编码 查询对象 返回字段 筛选条件
erp-supplier DSDATA.erp_apmt440_pmaauc_v 视图全部字段 必填:t100id、ent;可选:pmaal004
erp-packaging-b9-window-view DSDATA.imaf_t、DSDATA.imaal_t imaf001、imaal003、imaal004 必填:t100id、ent;可选:keyword
erp-packaging-material DSDATA.pmaauc_t pmaauc001、pmaauc002、tp 必填:ent;可选:keyword
erp-material-original-price DSDATA.pmaauc_t pmaauc002、pmaauc015、pmaauc001、pmaaucent 必填:czbh、ent
erp-item-view DSDATA.erp_apmt440_imaauc_v 视图全部字段 必填:ent;可选:keyword(匹配 imaa001、imaal003)
erp-sales-order DSDATA.xmda_t、DSDATA.xmdc_t、DSDATA.xmdd_t、DSDATA.ooff_t 销售订单、客户、料件、未交数量和开票信息 必填:t100id;可选:keyword(匹配 xmdadocno)
erp-production-order DSDATA.xmda_t、DSDATA.xmdc_t、DSDATA.xmdd_t、DSDATA.ooff_t 生产令、客户、料件、数量和开票信息 必填:t100id、qx
erp-supplier-disabled DSDATA.ERP_APMT440_PMAAUC_N 禁用供应商视图全部字段 必填:t100id、ent;可选:keyword(匹配 pmaal004)
erp-active-item DSDATA.imaa_t、DSDATA.imaf_t、DSDATA.imaal_t imaa001、imaal003、imaal004 可选:keyword(匹配 imaa001、imaal003)
erp-template-item DSDATA.imaa_t、DSDATA.imaal_t imaa001、imaal003、imaal004 可选:keyword(匹配 imaa001、imaal003)
erp-template-orders DSDATA.xmda_t、DSDATA.xmdc_t 范本料号关联订单及料件明细 必填:bgfblh;可选:keyword(匹配 xmdadocno)
erp-last-price DSDATA.pmdi_t、DSDATA.pmdj_t pmdj011 必填:main.pmdi004、detail_1.ljbh
erp-unfulfilled-order DSDATA.xmdg_t、DSDATA.xmdh_t、DSDATA.xmda_t、DSDATA.xmdc_t、DSDATA.imaal_t、DSDATA.pmaal_t xmdgdocno、xmdhseq、xmda048、xmdcud010、xmdh006、imaal003、imaal004、xmdg005、pmaal003 必填:ent、site、keyword
erp-delivery-order DSDATA.xmdg_t、DSDATA.xmdh_t、DSDATA.xmdc_t xmdgdocno、xmdcud010、xmdc019、k 必填:ent、site;可选:keyword(匹配 出通单号-项次)
erp-outsourced-purchase-order-window DSDATA.pmdp_t、DSDATA.imaal_t、DSDATA.sfaa_t pmdpseq、pmdp003、pmdp001、imaal003、imaal004、pmdp023、sfaaud009 必填:formtable_main_158_dt1_wwcgdh
erp-outsourced-bom DSDATA.pmdp_t、DSDATA.sfba_t、DSDATA.imaal_t sfba006、imaal003、imaal004、sfba013 必填:formtable_main_158_dt1_wwcgdh、formtable_main_158_dt1_cgxc

供应商视图:

GET /api/dictionary/erp-supplier?t100id=ML&ent=明磊&pmaal004=供应商

明磊包材B9开窗视图:

GET /api/dictionary/erp-packaging-b9-window-view?t100id=ML&ent=明磊&keyword=B9开窗

包材材质:

GET /api/dictionary/erp-packaging-material?ent=明磊&keyword=彩盒

根据材料编号取原单价:

GET /api/dictionary/erp-material-original-price?czbh=B9-001&ent=明磊

ERP 料件视图:

GET /api/dictionary/erp-item-view?ent=明磊&keyword=电池

销售订单开窗:

GET /api/dictionary/erp-sales-order?t100id=ML&keyword=SO-001

生产令开窗:

GET /api/dictionary/erp-production-order?t100id=ML&qx=OWNER-A,OWNER-B

ERP 供应商禁用视图:

GET /api/dictionary/erp-supplier-disabled?t100id=ML&ent=明磊&keyword=供应商

T100 有效料号:

GET /api/dictionary/erp-active-item?keyword=B9

范本料号开窗:

GET /api/dictionary/erp-template-item?keyword=B9

范本料号开窗对应所有订单:

GET /api/dictionary/erp-template-orders?bgfblh=B9&keyword=SO-001

取料号上次价格:

GET /api/dictionary/erp-last-price?main.pmdi004=SUP-001&detail_1.ljbh=B9-001

已审核未发齐出通单:

GET /api/dictionary/erp-unfulfilled-order?ent=明磊&site=ML&keyword=MLCT6261023002-1

出通单列表:

GET /api/dictionary/erp-delivery-order?ent=明磊&site=ML&keyword=110001-1

委外采购单开窗:

GET /api/dictionary/erp-outsourced-purchase-order-window?formtable_main_158_dt1_wwcgdh=WWCG-001

委外采购对应工单备料:

GET /api/dictionary/erp-outsourced-bom?formtable_main_158_dt1_wwcgdh=WWCG-001&formtable_main_158_dt1_cgxc=10

erp-supplier 的 pmaal004 按供应商名称模糊匹配。erp-packaging-b9-window-view 使用单一 keyword 参数,后端会将其分别与 imaf001(料件编号)、imaal003(中文品名)和 imaal004(规格)进行模糊匹配,任一字段命中即可返回。明磊包材B9开窗视图仅返回中文料件信息,排除 imaf016 为 TY 或 LTY 的记录,并只包含编码以 B9、VB9 或 J 开头的料件。

erp-supplier、erp-packaging-b9-window-view 和 erp-supplier-disabled 的 t100id、ent 均为必填筛选条件;erp-packaging-material 和 erp-item-view 仅需传入 ent。销售订单开窗仅需传入 t100id,固定查询公司 86 中已审核、存在未交数量且不属于指定排除客户的订单。生产令开窗需传入 t100id 与 qx,其中 qx 为逗号分隔的拥有者权限值,固定查询公司 86 中已审核的订单。范本料号关联订单需传入 bgfblh,服务端按该料号前缀匹配 ML 据点未作废订单。取料号上次价格需同时传入 main.pmdi004(主表料号)和 detail_1.ljbh(子表料件编号),服务端返回有效采购价格单中最新确认时间的 pmdj011。已审核未发齐出通单需传入 ent、site 和 keyword,其中 keyword 按“出通单号-项次”精确匹配,返回项次、内外销、料号、料件中文名称、规格、客户编号及客户中文名称。有效料号和范本料号均可选 keyword,同时模糊匹配 imaa001(料号)和 imaal003(中文品名);范本料号关联订单可选 keyword 模糊匹配 xmdadocno(订单号);ERP 供应商禁用视图可选 keyword 模糊匹配 pmaal004(供应商名称)。包材材质可用单一 keyword 对 pmaauc001(包材编号)、pmaauc002(包材名称)和 tp(中文材质类型)进行模糊匹配,任一字段命中即可返回;ERP 料件视图的 keyword 会同时模糊匹配 imaa001(料号)和 imaal003(中文品名)。委外采购单开窗仅需传入 formtable_main_158_dt1_wwcgdh;委外采购对应工单备料需同时传入采购单号 formtable_main_158_dt1_wwcgdh 和采购项次 formtable_main_158_dt1_cgxc。两者 SQL 均固定查询公司 86、据点 ML。ent=明磊 映射为 ERP 公司编号 86,ent=越南 映射为 ERP 公司编号 60,其他公司名称会返回 400。十五个字典接口不接收 page 和 pageSize,服务端固定返回符合条件的前 100 条记录。包材材质的 tp 字段会将 pmaauc016 转换为 说明书、彩盒、纸箱 或 标贴。

成功响应的 result 统一为:

{
  "page": 1,
  "pageSize": 100,
  "total": 238,
  "records": []
}

数据字典实现约定:固定 SQL、字典编码和允许的筛选参数统一维护在 DictionaryQueryServiceImpl,Controller 只处理 HTTP 参数与响应封装;SQL 必须使用 NamedParameterJdbcTemplate 绑定参数,不得拼接外部输入;新增字典时在同一 ServiceImpl 中增加路由分支、参数校验、单元测试和本节文档。未注册的字典编码或未声明的筛选条件会返回 400。

4.6.1 差旅标准查询

POST /api/minglei/ports/travel-standards
Content-Type: application/json

请求体:

{
  "userId": "ding-user-001",
  "city": "海口"
}

userId 和 city 均为必填参数;为兼容已有调用,userID 也可作为 userId 传入。接口先从本地员工花名册查询用户职等,再按职等精确查询宜搭差旅标准表单 FORM-47ED3C35E3C34A9CA275039F93FA5ED1VR2J,最后依据国内城市类别或国外国家类别返回住宿标准。金额不再由后端固定维护。

  • 一类城市:北京、天津、上海、重庆、深圳、珠海、汕头、厦门。
  • 二类城市:省会城市、计划单列市及海南省全域城市。
  • 三类城市:除一类、二类城市外的其他城市。
  • 一类国家:美国、加拿大、英国、法国、德国、意大利、日本、澳大利亚,读取宜搭字段 numberField_mvevi2d3(一类国家标准,人民币)。
  • 其他国家:中国以外的其他已识别国家,读取宜搭字段 numberField_mvevi2d4(其他国家标准,人民币)。

国外城市会先匹配常用城市名称;城市值也可附带国家名称,例如 巴黎(法国),以支持未预置的国外城市。响应的 country 字段返回命中的国家,cityClass 对国外分别返回 一类国家 或 其他国家。无法识别国家的中文城市维持原有国内三类城市逻辑,保障已接入的国内调用不受影响。

差旅标准表单与审批矩阵复用主数据宜搭应用配置 minglei.yida.master-data,无需新增 system-token。员工不存在、职等未维护、职等不是数值或宜搭未配置该职等的标准时,接口返回 400。

响应示例:

{
  "code": 200,
  "isSuccess": true,
  "result": {
    "userID": "ding-user-001",
    "jobGrade": "8",
    "city": "海口",
    "country": "中国",
    "cityClass": "二类城市",
    "amount": 400,
    "currency": "CNY"
  }
}

4.6.2 机票报销标准查询

POST /api/expense-reimbursement/flight-standards/resolve
Content-Type: application/json

请求体:

{
  "userId": "728378541",
  "travelRegion": "东南亚",
  "ticketType": "往返",
  "tripCount": 2,
  "budgetAmount": 8001
}

userId 为必填项。服务先按 userId 查询本地员工花名册中的职等,再按职等精确查询同一份宜搭差旅标准主表。机票标准全部从主表字段读取,不查询子表;travelRegion 或 ticketType 为空或不符合预置选项时,接口正常返回,标准相关字段为 null。

传入 tripCount(次数)和 budgetAmount(预算金额)时,接口按 budgetAmount > limitAmount × tripCount 返回 isOverStandard:严格大于返回 是,小于或等于返回 否。任一计算参数或机票标准为空时,isOverStandard 返回 null。

travelRegion ticketType 名称 宜搭主表字段
国内 单程 国内机票-单程 numberField_mvevi2dd
国内 往返 国内机票-往返 numberField_mvevi2dc
东南亚 单程 东南亚机票-单程 numberField_mvevi2dg
东南亚 往返 东南亚机票-往返 numberField_mvevi2de
欧美及其它 单程 欧美及其他机票-单程 numberField_mvevi2dl
欧美及其它 往返 欧美及其他机票-往返 numberField_mvevi2dj

响应示例:

{
  "code": 200,
  "isSuccess": true,
  "result": {
    "expenseType": "FLIGHT",
    "userId": "728378541",
    "jobGrade": "8",
    "jobGradeId": "GRADE-8",
    "travelRegion": "东南亚",
    "ticketType": "往返",
    "flightOption": "SOUTHEAST_ASIA_ROUND_TRIP",
    "flightOptionName": "东南亚机票-往返",
    "limitAmount": 4000,
    "tripCount": 2,
    "budgetAmount": 8001,
    "isOverStandard": "是",
    "currency": "CNY",
    "unit": "PER_TRIP"
  }
}

员工不存在、职等未维护、职等不是数值、未找到对应职等的宜搭主表记录或对应金额未维护时,接口返回 400。出差区域或机票类型不支持时不返回错误,标准相关字段为 null。

4.6.3 OA 出差申请推送

POST /api/minglei/ports/travel-applications
Content-Type: application/json

钉钉 OA 连接器在审批通过后调用本接口。服务使用请求中的 userId 作为宜搭流程发起人,departmentId 写入申请部门,并复用审批矩阵所在的主数据宜搭应用配置,发起“出差申请流程”。附件字段不处理;oaProcessInstanceId 仅用于调用链路追踪和响应回传,当前不做重复拦截。

请求示例:

{
  "oaProcessInstanceId": "oa-process-001",
  "userId": "ding-user-001",
  "departmentId": "123",
  "title": "北京客户拜访",
  "company": "明磊",
  "applyDate": "2026-10-26",
  "position": "业务经理",
  "mobile": "13800000000",
  "actualTravelerUserIds": ["ding-user-001"],
  "employeeNo": "E001",
  "jobGrade": "8",
  "travelType": "工作出差",
  "customerName": "客户名称",
  "travelReason": "客户拜访",
  "transportation": "飞机",
  "tripMode": "往返",
  "itineraries": [
    {
      "departureCity": "北京",
      "destinationCity": "上海",
      "startDate": "2026-10-27",
      "startPeriod": "上午",
      "endDate": "2026-10-29",
      "endPeriod": "下午",
      "durationDays": 3,
      "travelDays": 3,
      "remark": "客户拜访",
      "companionUserIds": ["ding-user-002"],
      "externalPersonnel": "客户代表"
    }
  ],
  "flights": [
    {
      "ticketReserved": "是",
      "travelRegion": "国内",
      "ticketType": "往返",
      "tripCount": 1,
      "budgetAmount": 5600,
      "unitPrice": 5600,
      "overStandard": "否",
      "standardAmount": 6000,
      "remark": ""
    }
  ],
  "budgets": [
    {
      "departureLocation": "北京",
      "arrivalLocation": "上海",
      "accommodationDays": 2,
      "groundTransportationCost": 300,
      "accommodationCost": 1200,
      "accommodationStandard": 600,
      "businessEntertainmentCost": 1000,
      "travelAllowance": 300,
      "totalCost": 7800
    }
  ]
}

oaProcessInstanceId、userId、departmentId、title 必填。日期字段支持 yyyy-MM-dd 或毫秒时间戳;人员字段必须传钉钉 userId,部门必须传钉钉部门 ID。三个子表均为可选,空数组不会写入宜搭。

成功响应示例:

{
  "code": 200,
  "isSuccess": true,
  "result": {
    "oaProcessInstanceId": "oa-process-001",
    "yidaProcessInstanceId": "yida-process-001",
    "formUuid": "FORM-E1A24F72B06247ADAC36335CF7E1FEAC6DJX"
  }
}

4.6 审批转入部门主管查询

POST /api/dingtalk/approval/transfer-department/managers
Content-Type: application/json

请求示例:

{
  "processInstanceId": "YuRRlAutRFi4CcsrPkqvQg05031789886060"
}

服务端处理链路:

  1. 调用钉钉审批开放接口 GET https://api.dingtalk.com/v1.0/workflow/processInstances,通过 x-acs-dingtalk-access-token 请求头传入应用凭证。
  2. 从 result.formComponentValues 中查找 name 为 转入部门 的表单组件;未匹配到时回退匹配 bizAlias 为 transferDepartment 的组件。
  3. 解析该组件的 extValue,取第一个元素的 id 作为转入部门 ID,deptName 或 name 作为部门名称。extValue 中的 id 可能是字符串或数字,服务端统一按字符串处理。
  4. 复用工程内 MingleiDocumentService.queryDepartmentManagersByDepartmentId(宜搭审批矩阵表单 FORM-8F527F696C5B4AF7AB7A53979527FBA23USO)按"部门"选择字段 departmentSelectField_mszdqrks 内嵌的部门 ID 精确匹配,查询各级别负责人,不再调用钉钉通讯录部门详情接口。

注意:第 4 步改为按"部门"选择字段匹配(而非原先的"部门编号"文本字段 textField_msztwhs2),且返回结果新增"部门负责人"字段(审批矩阵 employeeField_mualkf6a)。

响应中各级别负责人按字段分开返回,分别对应审批矩阵表单中的 employeeField_mszdqrl8(一级部门主管)、employeeField_mszdqrl9(二级部门主管)、employeeField_mszdqrla(三级部门主管)、employeeField_mszdqrlb(四级部门主管)、employeeField_mualkf6a(部门负责人)与 employeeField_mszdqrl3(部门分管领导)。

成功响应:

{
  "code": 200,
  "isSuccess": true,
  "result": {
    "departmentId": "972414534",
    "departmentName": "合作伙伴",
    "firstLevelManagerUserId": "manager-1",
    "secondLevelManagerUserId": "manager-2",
    "thirdLevelManagerUserId": "manager-3",
    "fourthLevelManagerUserId": "manager-4",
    "departmentHeadUserId": "manager-head",
    "departmentLeaderUserId": "manager-5"
  }
}

各部门负责人字段为对应级别审批人的钉钉 userid,审批矩阵未配置该级别负责人时该字段为 null。getAllManagerUserIds() 按一级至四级部门主管、部门负责人、部门分管领导的顺序返回所有非空的负责人 ID。

异常场景 HTTP 状态码 说明
processInstanceId 为空 400 请求参数不合法
审批实例无表单数据或未包含转入部门字段 400 表单结构与预期不一致
转入部门 extValue 缺少部门 ID 400 无法解析部门 ID
审批实例接口调用失败或宜搭审批矩阵查询失败 502 返回 DINGTALK_APPROVAL_CALL_FAILED 或 YIDA_CALL_FAILED 及上游错误码
宜搭应用或钉钉凭证配置缺失 412 返回配置缺失信息

4.7 外部 T100 接口转发

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

宜搭连接器调用时传表单 ID 和宜搭流程实例 ID。服务端按 formId 选择字段映射规则,再通过钉钉开放平台 GET /v2.0/yida/processes/instancesInfos/{id} 读取顶层 data(支持对象或 JSON 字符串,同时兼容旧响应的 formData),后转换为 T100 核价单,并补齐 T100 协议外层的 key、host、service、datakey、type,以及生成 17 位毫秒时间戳。推送 T100 时使用 Content-Type: application/json;charset=UTF-8。该请求使用钉钉应用 access token,并传入 appType、systemToken、查询用户 ID;配置项见上表。不要在连接器请求体中传入表头、明细、密钥或 T100 外层字段。

{
  "formId": "FORM-468B6FB2D5BF490A8BC6DBD6FAF9BCCA28R9",
  "processInstanceId": "宜搭流程实例 ID"
}

接口按 formId 选择对应字段映射,当前已注册表单如下:

表单 formId 明细字段映射
供应商价格审批单(核价) FORM-468B6FB2D5BF490A8BC6DBD6FAF9BCCA28R9 tableField_mszqctqd:料件编号、核价、备注
供应商价格审批单(暂估) FORM-F906C997A4A44DC8B9180198C0B2E55F6W0S tableField_msh186sv:料件编号、材料价格、备注
供应商价格审批单-核价(子公司) FORM-C09818E73B1640A9AA9F6D7F55C47612EFV8 tableField_mszqctqd:料件编号、核价、备注
供应商价格审批单-暂估(子公司) FORM-EC46C7109182497796AA0B70F3848576UYBU tableField_msh186sv:料件编号、暂估单价、备注
包材材质核价 FORM-69A12600F87349D3B653BF86E419224DLIX9 tableField_mt1av9od:材质编号、单价(克)
供应商暂停/退出流程 FORM-0A05D30C6E0745EC9F4B74D0E038EE73O7B6 主表:变更类型、供应商编号、企业代码;不发送企业据点
包材料号清单维护审核流程 FORM-F88BDA6B3A114E668AD5A6347AE4E01C91O9 tableField_msh186sv:包材料号清单字段

四个供应商价格审批表单都会将单据编号、委外否、单号、报价单日期、核价供应商、生效日期、失效日期、使用部门、申请人映射至 T100 表头;其中申请人由宜搭成员数组的第一项姓名查询本地在职花名册后,使用对应的 employee_no 写入 T100 pmdi002。明细的料件编号、价格、备注分别映射至 pmdj002、pmdj011、pmdj030。宜搭委外否字段为“是”时,T100 pmdi001 传 Y;为“否”时传 N(兼容历史 Y/N 值)。暂估表单 FORM-F906C997A4A44DC8B9180198C0B2E55F6W0S 和 FORM-EC46C7109182497796AA0B70F3848576UYBU 的 pmdiud001 传 Y,其余供应商价格审批表单传 N;pmdistus 固定传 I。新增的三张表单按照各自 T100 请求体层级组装 parameter,并填充对应的 datakey.type 与 service.name=DingTalk To T100;包材材质核价以 textField_mviyetxy 判断 pmaaucent,供应商暂停/退出流程以 textField_mvewj97z 判断 pmaaent、pmabent,包材料号清单维护以 selectField_msy2rh6q 判断 pmabucent,字段值为“明磊”时均传 87,其余值传 60;包材料号清单子表的 textField_mvix39fn、textField_mvix39fm、numberField_mvjb17mf 分别映射至 pmabuc001、pmabuc002、pmabuc024,且 pmabucsite 固定传 ML,供应商暂停/退出流程的 selectField_mt82p09c 为“正常供应商”时 pmaa083、pmab074 传 1,为“停用”时传 0,并保留 pmabsite;包材料号清单维护固定传 pmabucstus=Y。未注册的 formId 会返回参数错误,不会访问宜搭或 T100。外部 T100 接口地址与密钥分别由 MINGLEI_SUPPLIER_PRICE_APPROVAL_URL、MINGLEI_SUPPLIER_PRICE_APPROVAL_KEY 配置。

当四张供应商价格审批单推送 T100 且返回 success=true 时,服务会从 content.payload.std_data.parameter.pmdidocno 读取 T100 单号,并按原流程实例 ID 调用宜搭流程更新接口回写单号。回写字段分别为:核价与核价(子公司)使用 textField_mszqctqb,暂估与暂估(子公司)使用 textField_mt7yf5wu。T100 未成功时不会回写;T100 已成功但宜搭回写失败时接口返回失败,避免单据状态被误判为已完整同步。

4.8 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
aqct300 Aqct300FormPushHandler 检验情况审批流程 FORM-38C8592E7F5F45B3A388DA3FEFBA67C2GCEV TPROC--LX766PC193N85EWUJ9ZLACNJNPSW3HBRG78TM1
axmt510 Axmt510FormPushHandler 订单变更申请流程 FORM-8F318292B70D4ED39080EE0C631DC74BG3MD TPROC--BHC66W71Q1N87Q0YFD7FVBNYXRJ62OIA378TM4
apmt100 Apmt100FormPushHandler 供应商导入流程 FORM-9EE14CA14D8D4AEE8102944E669E6B0CFUKS TPROC--75G66PD15YG82766OFSWD8BS4ZJ33YPRFOZSM2

5.2 mainData 规则

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

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

5.3 detailData 规则

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

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

不同单据的约定:

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

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

5.4 发起人解析

  1. ErpYidaPushServiceImpl 优先使用顶层 tjr,其次使用 mainData.tjr。
  2. 服务端通过员工花名册查询工号对应的 dingtalkId。
  3. dingtalkId 会作为 originatorUserId、userId 和 applicant 写入请求上下文或明细行。
  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-dd 或 yyyy/MM/dd 格式。

5.6 aqct300 检验情况审批流程

调用 POST /api/erp/yida/push 时传入 type: "aqct300"。表头使用 ERP 原始字段;明细分别放入 detailData1(检验项目)、detailData2(缺点原因)、detailData3(计量检验)、detailData4(来源明细)。

当前仅发起宜搭流程,不做 ERP 回写。以下字段宜搭无对应控件,推送时丢弃:qcba005(交易对象编号)、qcba010(料件编号)、qcba027(不良数)、detailData3.qcbd002(检验位置)。qcba000 需直接传宜搭选项值:IQC / FQC / Inventory QC。

{
  "type": "aqct300",
  "bm": "123456789",
  "gs": "87",
  "tjr": "EMP0001",
  "mainData": {
    "rq": "2026-09-21",
    "bm": "123456789",
    "gs": "87",
    "tjr": "EMP0001",
    "qcbaent": "87",
    "qcbadocno": "QC-20260921-001",
    "qcbadocdt": "2026/09/21",
    "qcba000": "IQC",
    "qcba008": 100,
    "qcba009": "PCS",
    "imaal003": "料件品名",
    "imaal004": "规格",
    "qcba012": "产品特征",
    "qcba016": "EA",
    "qcba017": 80,
    "qcba022": "PASS",
    "qcba023": 75,
    "qcba024": "张三",
    "qcba034": "LOT-001"
  },
  "detailData": {
    "detailData1": [
      {
        "qcbdent": "87",
        "qcbddocno": "QC-20260921-001",
        "qcbdseq": "10",
        "qcbd001": "DIM",
        "oocql004": "尺寸检验",
        "qcbd009": 20,
        "qcbd010": 1,
        "qcbd011": "NG",
        "qcbd021": 1
      }
    ],
    "detailData2": [
      {
        "qcbeent": "87",
        "qcbedocno": "QC-20260921-001",
        "qcbeseq": "10",
        "qcbe001": "划伤",
        "qcbe002": 2,
        "qcbe003": "备注",
        "qcbe004": 2
      }
    ],
    "detailData3": [
      {
        "qcbdent": "87",
        "qcbddocno": "QC-20260921-001",
        "qcbdseq": "10",
        "qcbd013": 10.5,
        "qcbd015": 9.5,
        "qcbg002": 10.1,
        "qcbd017": "mm",
        "qcbg003": "Y",
        "qcbd001": "SIZE",
        "oocql004": "检验标准",
        "qcbd019": "备注"
      }
    ],
    "detailData4": [
      {
        "qcbaucseq": "1",
        "qcbauc014": "PO",
        "qcbauc001": "PO-001",
        "qcbauc002": "10",
        "qcbauc003": "REF-001",
        "qcbauc004": "20",
        "qcbauc005": "SUP-001",
        "qcbauc008": 100,
        "qcbauc009": "PCS",
        "qcbauc010": "ITEM-001",
        "imaal003": "料件品名",
        "imaal004": "规格"
      }
    ]
  }
}

tjr 为员工工号,服务端从花名册解析钉钉用户作为发起人与申请人;bm 为钉钉部门 ID;qcbadocdt / rq 支持 yyyy-MM-dd 或 yyyy/MM/dd。

5.7 axmt510 订单变更申请流程

调用 POST /api/erp/yida/push 时传入 type: "axmt510"。表头使用 ERP 原始字段;明细分别放入 detailData1(订单变更单身)、detailData2(交期明细)、detailData3(配件明细)。

当前仅发起宜搭流程,不做 ERP 回写。表头「变更事件」、附件与已到物料相关字段无对应 ERP 字段,推送时不填。子表1 xmegkk 映射到「变更事件」选项:数量变更 / 交期变更 / 其他变更。

{
  "type": "axmt510",
  "bm": "123456789",
  "gs": "87",
  "tjr": "EMP0001",
  "mainData": {
    "rq": "2026-09-23",
    "bm": "123456789",
    "gs": "87",
    "tjr": "EMP0001",
    "xmeeent": "87",
    "xmeedocno": "SO-20260923-001",
    "xmee900": "1",
    "xmeedocdt": "2026/09/20",
    "xmee001": 2,
    "xmee002": "dingtalk-sales-user",
    "xmee003": "dingtalk-dept-id",
    "xmee004": "C001",
    "pmaal004": "客户简称",
    "xmee013": "Y",
    "xmee042": 12800.5,
    "xmee901": "2",
    "xmee902": "2026/09/23",
    "xmee903": "R01",
    "xmee904": "交期调整"
  },
  "detailData": {
    "detailData1": [
      {
        "xmegent": "87",
        "xmegdocno": "SO-20260923-001",
        "xmegseq": "10",
        "xmeg900": "1",
        "xmeg001": "ITEM-001",
        "xmeg002": "feature-a",
        "imaal003": "品名",
        "imaal004": "规格",
        "xmdc007": 100,
        "xmdc012": "2026/09/30",
        "xmdc015": 10.5,
        "xmeg006": "PCS",
        "xmeg007": 120,
        "xmeg012": "2026/10/15",
        "xmeg015": 11,
        "xmeg046": 1100,
        "xmeg047": 1243,
        "xmeg048": 143,
        "xmeg049": "RC01",
        "xmeg053": "HC01",
        "xmeg901": "2",
        "xmegud010": "MO-001",
        "xmegkk": "交期变更"
      }
    ],
    "detailData2": [
      {
        "xmehent": "87",
        "xmehdocno": "SO-20260923-001",
        "xmehseq": "10",
        "xmehseq1": "1",
        "xmehseq2": "1",
        "xmeh900": "1",
        "xmeh001": "ITEM-001",
        "xmeh004": "PCS",
        "xmeh005": 120,
        "xmeh009": "1",
        "xmeh011": "2026/10/15"
      }
    ],
    "detailData3": [
      {
        "xmfwucent": "87",
        "xmfwucdocno": "SO-20260923-001",
        "xmfwucseq": "10",
        "xmfwucseq1": "1",
        "xmfwuc001": "PART-001",
        "imaal003": "配件品名",
        "imaal004": "配件规格",
        "xmfwucud001": "feat-p",
        "xmfwuc006": 2,
        "xmfwuc007": 1,
        "xmfwuc008": "PCS",
        "xmfwuc009": 240,
        "xmfwuc900": "1",
        "xmfwuc901": "2"
      }
    ]
  }
}

tjr 为员工工号;xmee002 / xmee003 需传钉钉用户 ID / 部门 ID。日期字段支持 yyyy-MM-dd 或 yyyy/MM/dd。流程标题为 订单变更申请流程-{订单单号}-{变更序}。

5.8 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 用于生成流程标题;若其为空,可使用 docno。clsj 支持 yyyy-MM-dd 或 yyyy/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,并对 password、secret、token、authorization、accessToken、systemToken、key 等字段脱敏。

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: 52, 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。