ERP对接模块.md 14 KB

ERP对接模块说明

本文档描述企得宝 ERP 系统集成方案,涵盖 SDK 封装、数据同步、商品/店铺关联管理的完整架构。 帮助开发人员理解 ERP 对接的设计决策和关键流程。


一、模块概述

1.1 对接目标

通过企得宝 ERP 开放平台 API(https://api.7debao.com/router/api),实现:

  • 将本地商品与 ERP 商品建立一对一关联
  • 将本地门店与 ERP 店铺建立一对一绑定
  • 后续补货单可推送至 ERP 生成采购单据

1.2 架构总览

┌─────────────────────────────────────────────────────┐
│                   haha-admin-web                     │
│  erp-goods/index.vue     erp-shop/index.vue          │
└──────────────────┬──────────────────────────────────┘
                   │ HTTP API
┌──────────────────▼──────────────────────────────────┐
│                   haha-admin                         │
│  ErpGoodsController     ErpShopController            │
│  QdbSdkConfig (QdbClient Bean)                      │
└──────────────────┬──────────────────────────────────┘
                   │
┌──────────────────▼──────────────────────────────────┐
│                   haha-service                       │
│  ErpGoodsService        ErpShopService               │
│  (sync / bind / unbind / autoBind)                   │
└──────────────────┬──────────────────────────────────┘
                   │
┌──────────────────▼──────────────────────────────────┐
│                   qdb-sdk (子模块)                    │
│  QdbClient → HttpUtil (签名 + HTTP)                  │
│  GoodsApi     ShopApi     OrderApi                   │
└──────────────────┬──────────────────────────────────┘
                   │
┌──────────────────▼──────────────────────────────────┐
│              企得宝 ERP API                           │
│          api.7debao.com/router/api                   │
│  foonsu.erp.sysGoods.list    (系统商品查询)           │
│  foonsu.erp.sysGoods.save    (系统商品上传)           │
│  foonsu.erp.sysShop.list     (店铺查询)               │
│  foonsu.erp.order.save       (订单上传)               │
└─────────────────────────────────────────────────────┘

二、数据库设计

2.1 ER图(核心表)

t_product                    t_erp_goods              企得宝ERP
┌──────────────┐            ┌──────────────────┐      ┌──────────┐
│ id           │            │ id               │      │ goodsId  │
│ code         │            │ erp_goods_id ◄───┼──────┤ goodsCode │
│ name ◄───────┼────────────┤ goods_code       │      │ goodsName│
│ erp_goods_id ├───────────►│ goods_name       │      │ specs    │
│ barcode      │            │ specs            │      │ skUnit   │
│ pic          │            │ sale_price       │      │ picPath  │
│ ...          │            │ bar_code(JSON)   │      │ ...      │
└──────────────┘            │ modify_date      │      └──────────┘
                            │ status           │
t_shop                      └──────────────────┘      企得宝ERP
┌──────────────┐            t_erp_shop                 ┌──────────┐
│ id           │            ┌──────────────────┐      │ shopId   │
│ shop_code    │            │ id               │      │ shopCode │
│ erp_shop_id  ├───────────►│ erp_shop_id ◄────┼──────┤ shopName │
│ name         │            │ shop_code        │      │ ...      │
│ ...          │            │ shop_name        │      └──────────┘
└──────────────┘            │ status           │
                            └──────────────────┘

2.2 关联关系

  • t_product.erp_goods_idt_erp_goods.erp_goods_id:本地商品与 ERP 商品的一对一关联
  • t_shop.erp_shop_idt_erp_shop.erp_shop_id:本地门店与 ERP 店铺的一对一绑定
  • t_product.name = t_erp_goods.goods_code:两者业务上的对应关系(商品名称即为 ERP 编码),是一键自动关联的依据

2.3 DDL脚本

脚本 用途
docs/database/create_erp_goods.sql 创建 t_erp_goods 缓存表
docs/database/create_erp_shop.sql 创建 t_erp_shop 缓存表
docs/database/add_erp_goods_id.sql t_product 增加 erp_goods_id 字段
docs/database/add_erp_shop_id.sql t_shop 增加 erp_shop_id 字段
docs/database/add_erp_goods_bar_code.sql t_erp_goods 增加 bar_codemodify_date
docs/database/menu_add_erp_goods.sql 插入"ERP商品关联"菜单
docs/database/menu_add_erp_shop.sql 插入"ERP店铺管理"菜单
docs/database/add_erp_permissions.sql 插入 ERP 功能权限数据

三、SDK集成 (qdb-sdk)

3.1 模块定位

qdb-sdkhaha-parent 的子模块(com.haha:qdb-sdk),统一版本管理。提供企得宝 ERP 开放 API 的 Java SDK 封装。

3.2 核心类

职责
QdbConfig SDK 配置(clientId、clientSecret、apiUrl、超时等)
QdbClient SDK 入口,持有各业务 API 实例 + HttpUtil
HttpUtil HTTP 请求封装(签名、OkHttp 调用)
SignUtil MD5 签名算法
BaseQdbApi API 基类,提供 execute() 通用调用方法
GoodsApi 商品管理 API(查询、上传)
ShopApi 店铺管理 API(查询)
OrderApi 订单管理 API(上传、查询)

3.3 Bean 配置

QdbSdkConfig(haha-admin 模块):

@Configuration
public class QdbSdkConfig {
    @Value("${qdb.client-id:}")
    private String clientId;
    @Value("${qdb.client-secret:}")
    private String clientSecret;
    @Value("${qdb.api-url:https://api.7debao.com/router/api}")
    private String apiUrl;

    @Bean
    @ConditionalOnProperty(prefix = "qdb", name = {"client-id", "client-secret"})
    public QdbClient qdbClient() { ... }
}

配置项(application.yml):

qdb:
  client-id: fs2009263
  client-secret: your_secret_here
  api-url: https://api.7debao.com/router/api

安全提醒client-idclient-secret 应使用环境变量或外部配置文件管理,避免提交到代码仓库。

3.4 API 调用方式

ERP API 统一 POST 到 https://api.7debao.com/router/api

  • 公共参数(client_id, method, timestamp, sign...)拼接到 URL Query String
  • 业务参数以 JSON 放入 Request Body
  • 签名:公共参数按 key 字典序排列 → 拼接 &key=clientSecret → MD5

四、ERP商品同步

4.1 同步策略

不是拉取 ERP 全量商品,而是以本地商品为基准逐条反查

原因:ERP 中有多个客户的数据,全量拉取无法区分哪些是本系统需要的。系统只关心已在哈哈平台上架的商品。

4.2 同步流程

① SELECT t_product WHERE is_deleted=0 AND name IS NOT NULL
     → 获取所有本地商品(name 作为 ERP goodsCode)

② 逐条调用 foonsu.erp.sysGoods.list
     参数: { pageIndex:1, pageSize:1, goodsCode: product.name, status:1, combination:0 }
     频率控制: 每 10 条暂停 200ms

③ ERP 返回: { data: { total: N, data: [{ goodsId, goodsCode, goodsName, ... }] } }
     → GoodsApi 自动拆包提取内层数组 → List<SysGoodsVO>

④ 命中 → upsert 到 t_erp_goods(按 erp_goods_id 判断新增/更新)
   未命中 → 记入日志,在同步完成后整齐打印清单

4.3 异步执行

ErpGoodsServiceImpl.syncFromErp() 标注 @Async("taskExecutor"),接口 POST /erp-goods/sync 立即返回"同步任务已启动",后台线程池执行。

4.4 保存字段

同步时保存:goodsId, goodsCode, goodsName, shortGoodsName, specs, skUnit, goodsKindCode, goodsKindName, brand, salePrice, costPrice, providerName, batchType, combination, articleNo, picPath, weight, barCodeList(JSON), modifyDate


五、商品关联

5.1 手动关联/解除

  • POST /erp-goods/bind — 选择本地商品与 ERP 商品一对一关联
  • POST /erp-goods/unbind — 解除关联(使用 LambdaUpdateWrapper.set(null) 强制写 NULL,避免 MP 默认跳过 null 字段)

5.2 一键自动关联

  • POST /erp-goods/auto-bind — 遍历所有 ERP 缓存商品,用 goodsCode 匹配本地 product.name
  • 唯一匹配 → 自动绑定;0 个或多于 1 个匹配 → 跳过
  • 批量优化
    • 查询已绑定:1 次 WHERE erp_goods_id IN (...)
    • 查询匹配:每 100 个 code 一批 WHERE name IN (...)
    • 批量 UPDATE:CASE WHEN SQL,每 100 条一批

六、ERP店铺管理

6.1 同步

  • POST /erp-shop/sync — 从 ERP 查询店铺列表,缓存到 t_erp_shop
  • 当前实现为全量拉取(翻页),与商品同步类似采用异步执行

6.2 绑定

  • POST /erp-shop/bind — 将本地门店与 ERP 店铺建立一对一绑定
  • POST /erp-shop/unbind — 解除绑定

七、权限配置

7.1 权限码

权限码 说明 类型
erp:goods:sync ERP商品同步 execute
erp:goods:read ERP商品查看 read
erp:goods:bind ERP商品关联/解绑/一键关联 update
erp:shop:sync ERP店铺同步 execute
erp:shop:read ERP店铺查看 read
erp:shop:bind ERP店铺绑定/解绑 update

7.2 菜单

菜单ID 父菜单 路径 名称
404 商品管理(400) /product/erp-goods ERP商品关联
305 运营管理(300) /operation/erp-shop ERP店铺管理

7.3 权限校验机制

  • @RequirePermission 注解通过 AOP 切面(PermissionAspect)校验
  • 超级管理员(role_id=1)直接放行,不查权限表
  • 非超管角色需在 t_data_permission 表有对应权限码,且在 t_role_menu 表有菜单授权

八、前端页面

8.1 ERP商品关联 erp-goods/index.vue

功能 描述
列表 分页展示 ERP 商品(图片、编码、名称、规格、单位、售价、关联状态)
搜索 按商品名称/编码搜索
同步 异步后台执行,完成后需手动刷新
一键关联 按 goodsCode 自动匹配本地商品
手动关联弹窗 展示 ERP 商品信息卡片 + 带缩略图的下拉选择框
解除关联 确认弹窗后解除
关联浮窗 悬停已关联标签时展示本地商品详情(含图片预览)

8.2 ERP店铺管理 erp-shop/index.vue

类似商品关联页,提供店铺的同步、绑定、解除绑定功能。

8.3 Vite 代理配置

/erp-goods/erp-shop 路径需在 vite.config.tsapiPaths 数组中注册,否则开发环境请求不会被转发到后端。


九、关键设计决策

9.1 为什么不用 GoodsApi 的泛型直接解析?

ERP 的 foonsu.erp.sysGoods.list 返回的 data 字段是嵌套结构 { total: N, data: [...] },不是扁平数组。GoodsApi.listSysGoods() 内部用 JSONObject 接收原始 data,再手动提取内层数组,避免 fastjson2 泛型解析的类型不匹配。

9.2 为什么同步用 goodsCode 逐条查而不是全量翻页?

ERP 中有多客户的商品数据,全量拉取无法过滤。只有本地商品的 name 字段才对应 ERP 的 goodsCode,以此为 key 逐条精确查询是最准确的方式。

9.3 为什么解除关联用 LambdaUpdateWrapper.set(null)?

MyBatis-Plus 默认 FieldStrategy.NOT_NULLupdateById(entity) 会跳过 null 值字段。设置 erpGoodsId = null 时需要使用 LambdaUpdateWrapper.set(Product::getErpGoodsId, null) 强制写入。

9.4 为什么 qdb-sdk 改为 haha-parent 子模块?

com.qdb:qdb-sdk:1.0.0 是独立模块,与 com.haha:qdb-sdk 并存会导致 classpath 上有两份 GoodsApi.class,旧版本优先加载 → NoSuchMethodError / ClassCastException。改为子模块统一 version,删除 Maven 本地旧 jar 后解决。


十、待完成

项目 状态 说明
补货单推送 ERP TODO ReplenishmentOrderServiceImpl.syncToErp() 当前为 no-op
ERP 店铺同步 已实现 待前端完善
增量同步 未实现 每次全量遍历本地商品,无时间戳过滤
qdb-sdk 编译 已验证 mvn clean install 后 classpath 唯一

创建日期:2026-07-09 维护者:开发团队