Commit 0a6d090c by 杨树贤

加入流程图

parent 840591bc
Showing with 335 additions and 0 deletions
# SKU价格获取完整流程文档
## 概述
本文档详细描述了从`sku_controller.go`出发的SKU价格获取完整流程,涵盖HTTP请求处理、并发执行、价格计算、缓存策略等核心环节。
## 1. 入口层 - HTTP请求处理
### 1.1 CommonController (sku_controller.go)
**文件位置**: `/controller/sku_controller.go`
**核心功能**: 接收并处理SKU查询请求
#### 1.1.1 请求参数解析
```go
GoodsIdStr := ctx.Request.FormValue("goods_id")
```
- 支持两种传参方式:
- URL参数:`goods_id=123,456,789`
- POST表单:`goods_id[0]=123&goods_id[1]=456`
#### 1.1.2 商品分类逻辑
```go
if len(goodsId) < 19 { // 自营商品
zyGoodsId = append(zyGoodsId, goodsId)
} else { // 联营商品
lyGoodsId = append(lyGoodsId, goodsId)
}
```
#### 1.1.3 并发处理机制
- **协程数量**: 每50个商品启动一个协程
- **并发控制**: 使用`sync.WaitGroup`管理协程生命周期
- **结果收集**: 通过channel异步收集结果
- **超时保护**: 20秒整体超时机制
```go
ch := make(chan sync.Map, 50) // 结果通道
timeout := time.After(time.Second * 20) // 超时控制
```
## 2. 服务层 - 商品详情处理
### 2.1 自营商品处理 (ZiyingService)
**入口方法**: `ZyGoodsDetail`
**处理特点**: 直接获取预设价格,流程相对简单
### 2.2 联营商品处理 (LyService)
**入口方法**: `LyGoodsDetail`
**文件位置**: `/service/service_ly_common.go`
**处理特点**: 完整的价格计算流程
## 3. 价格计算核心流程
### 3.1 GetCoefficientAndPrice 方法
**文件位置**: `/service/service_ly_common.go:290-501`
#### 3.1.1 前置判断
```go
// 检查是否有阶梯价格
if len(sku.LadderPrice) == 0 {
return sku
}
```
#### 3.1.2 供应商类型区分
- **专卖供应商** (SupplierId = 17): 华云等自有供应商
- **代购供应商** (其他SupplierId): MRO、Digikey等第三方供应商
### 3.3 专卖供应商价格计算
#### 3.3.1 价格获取流程
1. **读取成本价**: 从Redis获取预设成本价
2. **折扣系数**: 调用`GetDiscountRatio`获取
3. **阶梯价格**: 调用`GenerateLadderPrice`生成
4. **最终价格**: 成本价 × 折扣系数 × 阶梯系数
### 3.4 代购供应商价格计算(完整流程)
#### 3.4.1 获取折扣系数 (`GetDiscountRatio`)
**文件位置**: `/service/service_price.go:427-522`
**数据源**: Redis中的折扣系数配置
- **Key格式**: `discount_ratio_config`
- **匹配维度**: 商品名称、品牌、分类ID、ECCN
- **优先级顺序**: 商品名称 > 品牌 > 分类ID > ECCN
**匹配逻辑**:
```
1. 商品名称匹配 (最高优先级)
2. 标准品牌ID匹配
3. 分类ID匹配
4. ECCN匹配 (最低优先级)
任一条件匹配即命中并跳出
```
#### 3.4.2 获取售价组系数 (`GetPriceRatio`)
**文件位置**: `/service/service_price.go:524-679`
**配置源**: Redis中的售价组配置
- **Key格式**: `magic_cube_price_rule_v2`
- **支持维度**:
- 供应商级别
- 商品级别
- 品牌级别
- 分类级别
#### 3.4.3 获取供应商系数
**数据源**: Redis中的供应商系数配置
- **Key格式**: `pool_supplier_ratio`
- **匹配逻辑**: 支持商品名称和品牌匹配
#### 3.4.4 价格计算公式
##### 成本价计算
```
美金成本价 = 原始美金价格 × 折扣系数
人民币成本价 = 原始人民币价格 × 汇率 × 税率 (1.13)
```
##### 售价计算
```
美金售价 = 美金成本价 × 售价组系数
人民币售价 = 人民币成本价 × 售价组系数
```
##### 特殊处理
- **MRO供应商** (1688): 支持人民币价格
- **Digikey供应商** (7): 支持人民币价格
- **实时汇率**: 从`erp_rate`键获取
- **固定税率**: 1.13
## 4. 价格服务核心方法详解
### 4.1 GenerateLadderPrice - 阶梯价格生成
**适用场景**: 专卖供应商价格计算
**文件位置**: `/service/service_price.go:20-425`
#### 4.1.1 配置获取逻辑
```go
// 根据MOQ选择配置key
if sku.Moq <= 50 {
ratioDataKey = "cost_ladder_price_egt50_lt200"
} else {
ratioDataKey = "cost_ladder_price_egt200"
}
```
#### 4.1.2 多维度匹配优先级
1. **商品名称匹配**: 精确匹配商品名称
2. **品牌匹配**: 匹配品牌名称
3. **分类匹配**: 匹配分类ID
4. **ECCN匹配**: 匹配ECCN编码
### 4.2 TransformSpecialSupplierPrice - 特殊供应商价格转换
**功能**: 处理不同供应商的币种转换和价格标准化
**文件位置**: `/service/service_price.go:681-777`
#### 4.2.1 支持的币种转换
该方法专门处理以下供应商的特殊币种问题:
- **Element(6)**: 存储的是港币,需要转换为美金
- **RS(21)**: 存储的是人民币,需要转换为美金
- **Buerklin(1676)**: 存储的是欧元,需要转换为美金
#### 4.2.2 配置数据源
**Redis配置键**: `magic_cube_supplier_currency`
**配置结构**:
```json
{
"currency": 3, // 币种ID
"has_tax": true, // 是否含税
"symbol": "€", // 货币符号
"us_to_cn": false, // 是否美金转人民币
"customize_rate_rmb": 7.2, // 自定义人民币汇率
"customize_rate_usd": 1.1 // 自定义美金汇率
}
```
#### 4.2.3 转换逻辑详解
##### 1. 汇率获取优先级
```
自定义汇率 > Redis实时汇率 > 默认汇率
```
##### 2. 币种转换流程
**情况1**: 有自定义人民币汇率
```
人民币价格 = 原始价格 × 自定义人民币汇率
如含税: 人民币价格 = 人民币价格 ÷ 1.13
```
**情况2**: 无自定义汇率,需要美金转人民币
```
人民币价格 = 原始美金价格 × 实时汇率 × 1.13
```
**情况3**: 有自定义美金汇率
```
美金价格 = 原始价格 × 自定义美金汇率
如含税: 美金价格 = 美金价格 ÷ 1.13
```
**情况4**: 无自定义美金汇率(最复杂)
```
1. 获取币种对人民币汇率
2. 获取人民币对美元汇率
3. 计算币种对美元汇率 = 币种对人民币汇率 ÷ 人民币对美元汇率
4. 美金价格 = 原始价格 × 计算出的汇率
如含税: 美金价格 = 美金价格 ÷ 1.13
```
##### 3. 实际转换示例
**示例**: Element供应商(港币→美金)
```
原始数据: price_us = 100 (实际是100港币)
配置: currency=3(港币), has_tax=true
汇率: 港币对人民币=0.9, 人民币对美元=7.2
计算: 港币对美元汇率 = 0.9 ÷ 7.2 = 0.125
最终结果: price_us = 100 × 0.125 ÷ 1.13 = 11.06美金
```
#### 4.2.4 特殊处理逻辑
- **组织ID过滤**: 仅处理OrgId=1的数据
- **税率处理**: 根据has_tax标志决定是否去除13%增值税
- **符号记录**: 记录原始货币符号用于前端展示
- **汇率缓存**: 使用Redis缓存实时汇率数据
### 4.3 GetActivityPrice - 活动价格处理
**功能**: 处理限时活动价格
**数据源**: Redis中的活动价格配置
## 5. 缓存策略与数据结构
### 5.1 Redis Key结构
| Key名称 | 用途 | 数据类型 |
|---------|------|----------|
| `magic_cube_price_rule_v2` | 售价组配置 | Hash |
| `pool_supplier_ratio` | 供应商系数 | Hash |
| `erp_rate` | 实时汇率 | Hash |
| `cost_ladder_price_*` | 阶梯价格系数 | String |
| `discount_ratio_config` | 折扣系数配置 | String |
### 5.2 缓存更新策略
- **实时读取**: 每次价格计算时从Redis获取最新配置
- **配置更新**: 通过管理后台更新Redis配置
- **异常处理**: 配置缺失时使用默认值
## 6. 并发与性能优化
### 6.1 并发处理架构
```
HTTP请求 → 商品分类 → 批次划分 → 协程处理 → 结果聚合 → 响应返回
```
### 6.2 性能优化点
- **批量处理**: 50个商品一批次,减少协程数量
- **连接复用**: Redis连接池管理
- **缓存策略**: 关键配置Redis缓存
- **超时控制**: 20秒整体超时保护
## 7. 异常处理与监控
### 7.1 异常场景处理
- **空值保护**: 各种系数缺失时的默认值处理
- **格式验证**: 数据格式异常时的容错处理
- **超时保护**: 防止长时间阻塞
### 7.2 日志与监控
- **关键节点日志**: 价格计算各阶段的状态记录
- **异常日志**: 配置缺失、计算异常等场景记录
- **性能监控**: 请求耗时、缓存命中率等指标
## 8. 数据流总结
### 8.1 完整数据流
```
用户请求 → 参数解析 → 商品分类 → 并发处理 → 价格计算 → 结果聚合 → 响应返回
Redis配置 → 折扣系数 → 售价组系数 → 供应商系数 → 汇率 → 税率
成本价计算 → 售价计算 → 币种转换 → 最终价格
```
### 8.2 关键决策点
1. **供应商类型判断**: 决定价格计算路径
2. **配置匹配优先级**: 影响最终系数选择
3. **币种转换需求**: 决定是否进行汇率转换
4. **活动价格判断**: 是否使用活动价格覆盖
## 9. 使用示例
### 9.1 请求示例
```bash
# 单个商品查询
curl "http://api.example.com/sku?goods_id=123456789"
# 多个商品查询
curl "http://api.example.com/sku" -d "goods_id[0]=123&goods_id[1]=456"
```
### 9.2 响应数据结构
```json
{
"123456789": {
"goods_name": "示例商品",
"ladder_price": [
{
"purchases": 1,
"price_us": 10.50,
"price_cn": 73.50,
"price_cost_us": 8.50,
"price_cost_cn": 59.50
}
],
"discount_ratio": {
"ratio": 0.85,
"ratio_usd": 0.90
}
}
}
```
## 10. 维护与扩展
### 10.1 配置维护
- **售价组配置**: 通过管理后台更新`magic_cube_price_rule_v2`
- **折扣系数**: 更新`discount_ratio_config`
- **供应商系数**: 更新`pool_supplier_ratio`
### 10.2 扩展点
- **新供应商支持**: 在`TransformSpecialSupplierPrice`中添加转换逻辑
- **新匹配维度**: 扩展`GetDiscountRatio``GetPriceRatio`的匹配逻辑
- **新币种支持**: 扩展汇率转换逻辑
---
*本文档基于当前代码版本整理,如有更新请及时同步文档内容。*
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment