Files
douba_shop/商城商品推送到聚水潭分析.md
Karlcarlo c7f85ffbda feat: 添加阿里云短信服务支持并优化验证码逻辑
- 引入 alibabacloud/dysmsapi-20170525 依赖,集成阿里云短信服务
- 将短信验证码从6位改为4位,优化用户体验
- 添加聚水潭商品按时间范围同步功能,支持分页拉取
- 增强Cron任务异常处理,添加错误日志记录
- 修复系统附件服务中图片路径处理逻辑
- 更新阿里云SDK相关组件至最新版本
- 添加think-trace调试扩展,便于问题排查
- 优化跨域中间件,使用str_contains替代strpos
2026-04-30 15:19:40 +08:00

466 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 商城商品推送到聚水潭分析
## 一、答案
### ❌ 当前状态:**推送功能已禁用**
在 [CreateSuccess.php#L80-99](file:///home/jone/workspace/CRMEB_PRO/app/listener/product/CreateSuccess.php#L80-99) 中,推送到ERP的代码**被注释掉了**:
```php
//ERP功能开启
// if (sys_config('erp_open') && $data['product_type'] == 0) {
// //上传商品至ERP平台
// ProductSyncErp::dispatchDo('upProductToErp', [$id]);
// ...
// }
```
---
## 二、推送功能架构
### 2.1 推送流程图
```
商城商品创建成功
↓
触发 CreateSuccess 事件监听器
↓
检查 ERP 功能是否开启 (erp_open = 1)
↓
├─ 未开启 → 不推送
│
└─ 开启 → ProductSyncErp::dispatchDo('upProductToErp', [$id])
↓
┌──────────────┐
│ 商品数据转换 │
│ │
│ 商品主数据 │
│ SPU编码 │
│ 商品名称 │
│ SKU规格 │
│ 价格信息 │
└──────┬───────┘
↓
调用聚水潭API
/open/jushuitan/itemsku/upload
↓
推送商品到聚水潭平台
```
### 2.2 核心文件
| 文件 | 职责 |
|------|------|
| [CreateSuccess.php](file:///home/jone/workspace/CRMEB_PRO/app/listener/product/CreateSuccess.php#L80-99) | 商品创建事件监听器 |
| [ProductSyncErp.php](file:///home/jone/workspace/CRMEB_PRO/app/jobs/product/ProductSyncErp.php#L31-61) | 推送任务(upProductToErp方法)|
| [Product.php](file:///home/jone/workspace/CRMEB_PRO/crmeb/services/erp/storage/jushuitan/Product.php#L36-54) | 聚水潭API调用封装 |
---
## 三、推送逻辑详解
### 3.1 商品创建监听器
**文件**: [CreateSuccess.php#L79-99](file:///home/jone/workspace/CRMEB_PRO/app/listener/product/CreateSuccess.php#L79-99)
```php
//ERP功能开启
if (sys_config('erp_open') && $data['product_type'] == 0) {
// 1. 上传商品至ERP平台
ProductSyncErp::dispatchDo('upProductToErp', [$id]);
// 2. 上传商品至ERP默认门店
ProductSyncErp::dispatchDo('upBranchProductToErp', [
$id,
['erp_shop_id' => sys_config('jst_default_shopid')]
]);
// 3. 给所有绑定了ERP店铺的门店增加该商品
$systemStoreServices = app()->make(SystemStoreServices::class);
$erpStoreList = $systemStoreServices->getStoreList([
['erp_shop_id', '>', 0]
]);
foreach ($erpStoreList['list'] as $item) {
if ($item['erp_shop_id'] < 1) continue;
ProductSyncErp::dispatchDo('upBranchProductToErp', [$id, $item]);
}
// 4. 如果是新商品,同步库存
if ($is_new) {
ProductSyncErp::dispatchDo('stockFromErp', [[$id]]);
}
}
```
**触发条件**:
- ✅ `erp_open` 配置已开启
- ✅ 商品类型为 `product_type == 0`(普通商品,非虚拟商品等)
- ✅ 商品创建成功事件被触发
### 3.2 数据转换逻辑
**文件**: [ProductSyncErp.php#L31-61](file:///home/jone/workspace/CRMEB_PRO/app/jobs/product/ProductSyncErp.php#L31-61)
```php
public function upProductToErp($id)
{
try {
// 1. 获取商品信息
$productServices = app()->make(StoreProductServices::class);
$productInfo = $productServices->getInfo($id)['productInfo'];
// 2. 准备数据
$data = [];
$attrs = $productInfo['attrs'] ?? [$productInfo['attr']];
foreach ($attrs as $item) {
// 处理图片URL
if ($item['pic'] && strstr($item['pic'], 'http') === false) {
$siteUrl = sys_config('site_url');
$item['pic'] = $siteUrl . $item['pic'];
}
// 3. 构建推送数据
$data[] = [
'i_id' => $productInfo['code'], // SPU编码
'sku_id' => $item['code'], // SKU编码
'name' => $productInfo['store_name'], // 商品名称
'properties_value' => str_replace(',', ' ', $item['values']), // 规格属性
's_price' => $item['price'], // 售价
'pic' => $item['pic'], // 图片URL
'c_price' => $item['cost'], // 成本价
'market_price' => $item['ot_price'], // 划线价
];
}
// 4. 调用聚水潭API
(new erpServices())->serviceDriver('product')->updateProduct($data);
} catch (\Exception $e) {
response_log_write([
'message' => '上传商品到ERP失败, 原因: ' . $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine()
]);
}
}
```
### 3.3 API调用
**文件**: [Product.php#L36-54](file:///home/jone/workspace/CRMEB_PRO/crmeb/services/erp/storage/jushuitan/Product.php#L36-54)
```php
public function updateProduct($data)
{
$url = $this->accessToken->getApiUrl("/open/jushuitan/itemsku/upload");
// 业务参数
$biz['items'] = $data;
// 拼装请求参数
$params = $this->getParams($biz);
// 请求平台接口
$request = $this->postRequest($url, $params);
if ($request['code'] == 0) {
return true;
} else {
return false;
}
}
```
**调用API**: `POST /open/jushuitan/itemsku/upload`
---
## 四、数据映射关系
### 4.1 推送数据格式
```json
{
"items": [
{
"i_id": "4651127369", // SPU编码(来自CRMEB的code字段)
"sku_id": "1N55001102", // SKU编码(来自CRMEB的attrs.code字段)
"name": "贝肽斯夏季儿童防晒帽", // 商品名称
"properties_value": "卡其布黄;M码:头围50-54cm", // 规格属性
"s_price": 35.9, // 售价
"pic": "https://img.yzcdn.cn/...", // 图片URL
"c_price": 0, // 成本价
"market_price": 0 // 划线价
}
]
}
```
### 4.2 字段对应关系
| 聚水潭字段 | CRMEB字段 | 说明 |
|-----------|-----------|------|
| `i_id` | `productInfo.code` | SPU编码(商品唯一标识)|
| `sku_id` | `attrs[].code` | SKU编码 |
| `name` | `productInfo.store_name` | 商品名称 |
| `properties_value` | `attrs[].values` | 规格属性(逗号替换为空格)|
| `s_price` | `attrs[].price` | 售价 |
| `pic` | `attrs[].pic` | SKU图片 |
| `c_price` | `attrs[].cost` | 成本价 |
| `market_price` | `attrs[].ot_price` | 划线价 |
---
## 五、推送触发场景
### 5.1 自动推送(已禁用)
**触发时机**: 商品创建成功
```php
// 在 CreateSuccess.php 中被注释
if (sys_config('erp_open') && $data['product_type'] == 0) {
ProductSyncErp::dispatchDo('upProductToErp', [$id]);
}
```
### 5.2 手动推送
**触发方式**: 后台手动操作
可以通过后台页面触发,调用接口:
```bash
POST /adminapi/product/sync_jst_product
{
"spu_str": "商品SPU编码"
}
```
### 5.3 门店商品推送
除了主商品库,还会推送到绑定了ERP店铺的门店:
```php
// 上传到ERP默认门店
ProductSyncErp::dispatchDo('upBranchProductToErp', [
$id,
['erp_shop_id' => sys_config('jst_default_shopid')]
]);
// 上传到所有绑定ERP店铺的门店
foreach ($erpStoreList['list'] as $item) {
ProductSyncErp::dispatchDo('upBranchProductToErp', [$id, $item]);
}
```
---
## 六、当前状态分析
### 6.1 为什么推送功能被禁用?
查看代码注释,ERP推送功能是被有意注释掉的,可能原因:
1. **测试阶段** - 功能尚未完善,避免生产环境误操作
2. **数据同步策略** - 可能改为只从聚水潭拉取,不推送到聚水潭
3. **业务调整** - 业务方向改变,暂不需要此功能
4. **数据一致性** - 避免双向同步导致的数据冲突
### 6.2 如何启用推送功能?
**步骤1**: 取消注释推送代码
编辑 [CreateSuccess.php#L80-99](file:///home/jone/workspace/CRMEB_PRO/app/listener/product/CreateSuccess.php#L80-99),取消注释:
```php
//ERP功能开启
if (sys_config('erp_open') && $data['product_type'] == 0) {
//上传商品至ERP平台
ProductSyncErp::dispatchDo('upProductToErp', [$id]);
//上传商品至ERP默认门店
ProductSyncErp::dispatchDo('upBranchProductToErp', [
$id,
['erp_shop_id' => sys_config('jst_default_shopid')]
]);
//给所有绑定了ERP店铺的门店增加该商品
$systemStoreServices = app()->make(SystemStoreServices::class);
$erpStoreList = $systemStoreServices->getStoreList([['erp_shop_id', '>', 0]]);
foreach ($erpStoreList['list'] as $item) {
if ($item['erp_shop_id'] < 1) continue;
ProductSyncErp::dispatchDo('upBranchProductToErp', [$id, $item]);
}
if ($is_new) {
ProductSyncErp::dispatchDo('stockFromErp', [[$id]]);
}
}
```
**步骤2**: 确保ERP配置正确
在后台配置:
- ✅ 开启ERP功能
- ✅ 配置聚水潭AppKey和Secret
- ✅ 配置默认门店ID
**步骤3**: 测试推送功能
```bash
# 创建测试商品
POST /adminapi/product/save
{
"store_name": "测试商品",
"price": 99.00
}
# 检查日志
tail -f runtime/log/xxx.log | grep "upProductToErp"
```
---
## 七、推送 vs 拉取
### 7.1 对比表
| 特性 | 拉取(已有)| 推送(已禁用)|
|------|-----------|-------------|
| **触发方式** | 手动/定时任务 | 商品创建时自动 |
| **数据流向** | 聚水潭 → CRMEB | CRMEB → 聚水潭 |
| **代码状态** | ✅ 正常 | ❌ 被注释 |
| **使用场景** | 从ERP同步商品 | 上传新品到ERP |
| **功能完整性** | ✅ 完善 | ⚠️ 需启用 |
### 7.2 推荐策略
#### 方案A: 仅拉取(当前)
**适用场景**:
- 聚水潭是主数据源
- CRMEB作为销售前端
- 商品信息在聚水潭维护
**优点**:
- ✅ 数据单一来源,避免冲突
- ✅ 商品信息统一管理
- ✅ 降低系统复杂度
#### 方案B: 仅推送
**适用场景**:
- CRMEB是主数据源
- 聚水潭仅用于库存/订单管理
- 商品信息在CRMEB维护
**优点**:
- ✅ 快速响应商品变化
- ✅ 统一商品发布渠道
- ✅ 便于营销活动管理
#### 方案C: 双向同步
**适用场景**:
- 两边都需要管理商品
- 有专业团队分别维护
- 需要数据一致性保障机制
**挑战**:
- ⚠️ 数据冲突解决策略
- ⚠️ 同步延迟处理
- ⚠️ 异常情况处理
---
## 八、启用推送的注意事项
### 8.1 数据一致性
```php
// 推送时,确保商品编码唯一
$productInfo['code'] 必须在聚水潭中是唯一的
// 如果推送失败,需要记录日志并重试
if (!(new erpServices())->serviceDriver('product')->updateProduct($data)) {
// 记录失败日志
Log::error('商品推送失败', ['product_id' => $id]);
// 可以加入重试队列
}
```
### 8.2 性能考虑
```php
// 当前是异步队列推送,无需担心性能
ProductSyncErp::dispatchDo('upProductToErp', [$id]);
// 但需要注意:
// 1. 批量创建商品时,可能产生大量队列任务
// 2. 建议限制推送频率
// 3. 添加推送限流机制
```
### 8.3 错误处理
```php
try {
(new erpServices())->serviceDriver('product')->updateProduct($data);
} catch (\Exception $e) {
// 1. 记录错误日志
Log::error('推送商品到聚水潭失败', [
'product_id' => $id,
'error' => $e->getMessage()
]);
// 2. 可以加入失败重试队列
ProductSyncErp::dispatchDo('upProductToErp', [$id]);
// 3. 通知管理员
// sendNotify('商品推送失败,需要人工处理');
}
```
---
## 九、总结
### ❌ 当前状态
**商城创建的商品推送到聚水潭的功能已被禁用**
### ✅ 推送功能已实现
代码逻辑完整,包括:
- ✅ 商品数据转换
- ✅ SKU规格处理
- ✅ 聚水潭API调用
- ✅ 门店商品推送
- ✅ 库存同步
### 🔧 如何启用
1. 取消 [CreateSuccess.php](file:///home/jone/workspace/CRMEB_PRO/app/listener/product/CreateSuccess.php#L80-99) 中的注释
2. 配置ERP功能
3. 测试推送流程
### 💡 建议
根据业务需求选择合适的数据同步策略:
- **推荐仅拉取**:单数据源,避免冲突
- **慎用双向同步**:需要完善冲突处理机制
---
## 十、相关文件清单
| 文件路径 | 说明 | 状态 |
|---------|------|------|
| [CreateSuccess.php](file:///home/jone/workspace/CRMEB_PRO/app/listener/product/CreateSuccess.php) | 商品创建监听器 | ⚠️ 推送代码被注释 |
| [ProductSyncErp.php](file:///home/jone/workspace/CRMEB_PRO/app/jobs/product/ProductSyncErp.php) | 推送任务 | ✅ 已实现 |
| [Product.php](file:///home/jone/workspace/CRMEB_PRO/crmeb/services/erp/storage/jushuitan/Product.php) | API调用 | ✅ 已实现 |
| [Jushuitan.php](file:///home/jone/workspace/CRMEB_PRO/crmeb/services/erp/storage/Jushuitan.php) | 聚水潭SDK | ✅ 已实现 |
| [HaichaoJstServices.php](file:///home/jone/workspace/CRMEB_PRO/app/haichao/HaichaoJstServices.php) | 业务封装 | ✅ 已实现 |