## Context

在 `add-force-recharge-system` 功能归档后，发现两个关键遗漏：

1. **套餐系列分配强充配置不可管理**：
   - 数据库字段已添加：`enable_force_recharge`、`force_recharge_amount`、`force_recharge_trigger_type`
   - Service 层已使用这些字段进行强充验证（`RechargeService.GetRechargeCheck`、`OrderService.GetPurchaseCheck`）
   - 但 DTO 层完全没有暴露这些字段，管理员无法通过 API 配置

2. **后台订单创建逻辑重复**：
   - 存在两套 DTO：`CreateOrderRequest` 和 `CreatePurchaseOnBehalfRequest`（字段完全相同）
   - 存在两个 Service 方法：`Create` 和 `CreatePurchaseOnBehalf`（核心逻辑相似，仅支付方式和成本价计算不同）
   - 实际业务中，后台订单只有两种支付方式：
     - `wallet`：扣代理钱包，需要强充验证，触发佣金
     - `offline`：线下已收款，不扣钱包，不触发佣金（即代购）

**现有架构**：
- 强充验证逻辑完整：`RechargeService`、`OrderService` 已实现
- 数据模型完整：`ShopSeriesAllocation.enable_force_recharge` 等字段已存在
- 仅缺少管理接口暴露

## Goals / Non-Goals

**Goals:**
- 暴露强充配置字段到套餐系列分配的 CRUD 接口
- 统一后台订单创建接口，使用 `payment_method` 字段区分普通订单和代购订单
- 删除重复代码和冗余 DTO
- 保持现有业务逻辑不变（强充验证、佣金计算、成本价计算）

**Non-Goals:**
- 不修改强充验证逻辑（已在 `add-force-recharge-system` 中实现）
- 不修改数据库结构（字段已存在）
- 不修改 H5 订单接口（H5 仅支持微信/支付宝支付，不涉及 offline）
- 不修改佣金计算逻辑（`CommissionCalculationService` 已正确处理 `is_purchase_on_behalf`）

## Decisions

### 决策 1：强充配置字段作为可选字段暴露

**决策**：在套餐系列分配的 DTO 中增加强充配置字段，作为可选字段（`omitempty`）

**理由**：
- 强充是累计充值强充的**可选配置**（`enable_force_recharge` 默认 false）
- 与一次性佣金配置保持一致（也是可选配置）
- 向后兼容：现有数据默认值为 false/0，不影响现有逻辑

**实现**：
```go
// CreateShopSeriesAllocationRequest
type CreateShopSeriesAllocationRequest struct {
    // ... 现有字段
    EnableForceRecharge      *bool  `json:"enable_force_recharge" description:"是否启用强充(累计充值强充)"`
    ForceRechargeAmount      *int64 `json:"force_recharge_amount" description:"强充金额(分,0表示使用阈值金额)"`
    ForceRechargeTriggerType *int   `json:"force_recharge_trigger_type" description:"强充触发类型(1:单次充值, 2:累计充值)"`
}

// UpdateShopSeriesAllocationRequest (同上)

// ShopSeriesAllocationResponse
type ShopSeriesAllocationResponse struct {
    // ... 现有字段
    EnableForceRecharge      bool  `json:"enable_force_recharge" description:"是否启用强充"`
    ForceRechargeAmount      int64 `json:"force_recharge_amount" description:"强充金额(分)"`
    ForceRechargeTriggerType int   `json:"force_recharge_trigger_type" description:"强充触发类型"`
}
```

**替代方案**：
- ❌ 独立接口配置强充：增加接口复杂度，与现有设计不一致
- ❌ 强制字段：破坏向后兼容性，现有创建请求会失败

### 决策 2：使用 payment_method 字段统一订单创建

**决策**：在 `CreateOrderRequest` 增加 `payment_method` 必填字段，删除 `CreatePurchaseOnBehalfRequest`

**理由**：
- 后台订单本质上只有两种支付方式：`wallet` 和 `offline`
- `is_purchase_on_behalf` 是业务标识，应由系统自动设置，不应由前端传递
- 减少 DTO 冗余，统一接口设计

**映射关系**：
```
payment_method = "wallet"  → is_purchase_on_behalf = false (普通订单)
payment_method = "offline" → is_purchase_on_behalf = true  (代购订单)
```

**实现**：
```go
type CreateOrderRequest struct {
    OrderType     string `json:"order_type" validate:"required,oneof=single_card device"`
    IotCardID     *uint  `json:"iot_card_id" validate:"required_if=OrderType single_card"`
    DeviceID      *uint  `json:"device_id" validate:"required_if=OrderType device"`
    PackageIDs    []uint `json:"package_ids" validate:"required,min=1,max=10"`
    PaymentMethod string `json:"payment_method" validate:"required,oneof=wallet offline"` // 新增
}
```

**替代方案**：
- ❌ 保留两个 DTO：代码重复，维护成本高
- ❌ 使用 `is_purchase_on_behalf` 字段：业务标识不应由前端控制，存在安全风险

### 决策 3：Service 层合并逻辑但保留代码分支

**决策**：合并 `Service.Create` 和 `Service.CreatePurchaseOnBehalf` 为统一方法，内部使用 `if/else` 分支处理

**理由**：
- 两个方法核心流程相似（验证 → 计算价格 → 创建订单 → 激活套餐 → 触发佣金）
- 关键差异仅在：
  - 成本价计算：普通订单用卖家成本价，代购用买家成本价
  - 支付状态：普通订单待支付，代购直接已支付
  - 佣金触发：通过 `is_purchase_on_behalf` 标识控制
- 统一方法减少接口暴露，降低复杂度

**实现结构**：
```go
func (s *Service) Create(ctx context.Context, req *dto.CreateOrderRequest, userType string, shopID, userID uint) (*dto.OrderResponse, error) {
    // 1. 通用验证（资源存在、套餐有效）
    validationResult, err := s.validatePurchase(ctx, req)
    
    // 2. 根据 payment_method 分支处理
    var order *model.Order
    if req.PaymentMethod == model.PaymentMethodOffline {
        // 代购逻辑
        order = s.buildPurchaseOnBehalfOrder(ctx, req, validationResult, userID)
    } else {
        // 普通逻辑
        order = s.buildNormalOrder(ctx, req, validationResult, shopID, userID)
    }
    
    // 3. 通用创建流程（保存订单 → 激活套餐 → 触发佣金）
    return s.createOrderCommon(ctx, order, validationResult)
}
```

**替代方案**：
- ❌ 保留两个独立方法：Handler 需要路由逻辑，接口复杂度高
- ❌ 完全合并为一个线性方法：可读性差，分支逻辑混乱

### 决策 4：Handler 层权限验证前置

**决策**：在 `OrderHandler.Create` 中根据 `payment_method` 进行权限验证，再调用 Service

**理由**：
- 权限验证是 Handler 层职责
- 提前拦截非法请求，避免无效的 Service 调用
- 明确业务规则：offline 仅平台可用，wallet 代理和平台都可用

**实现**：
```go
func (h *OrderHandler) Create(c *fiber.Ctx) error {
    var req dto.CreateOrderRequest
    // ... 解析请求
    
    ctx := c.UserContext()
    userType := middleware.GetUserTypeFromContext(ctx)
    shopID := middleware.GetShopIDFromContext(ctx)
    userID := middleware.GetUserIDFromContext(ctx)
    
    // 权限验证
    if req.PaymentMethod == model.PaymentMethodOffline {
        if userType != constants.UserTypeSuperAdmin && userType != constants.UserTypePlatform {
            return errors.New(errors.CodeForbidden, "只有平台可以使用线下支付")
        }
    } else if req.PaymentMethod == model.PaymentMethodWallet {
        if userType != constants.UserTypeAgent && 
           userType != constants.UserTypePlatform && 
           userType != constants.UserTypeSuperAdmin {
            return errors.New(errors.CodeForbidden, "无权创建订单")
        }
    }
    
    // 调用统一方法
    order, err := h.service.Create(ctx, &req, userType, shopID, userID)
    return response.Success(c, order)
}
```

**替代方案**：
- ❌ Service 层验证：违反分层原则，Handler 应负责权限
- ❌ 中间件验证：无法访问请求体字段

## Risks / Trade-offs

### 风险 1：`CreateOrderRequest` 字段变更可能影响前端

**风险**：新增 `payment_method` 必填字段后，现有前端调用会失败

**缓解措施**：
- 这是后台管理接口，前端由团队控制，可同步修改
- 如需兼容，可设置默认值（wallet），但不推荐（隐式行为会引起混淆）

**推荐**：要求前端同步修改，明确传递 `payment_method`

### 风险 2：删除 `CreatePurchaseOnBehalfRequest` 可能影响现有调用

**风险**：如果其他代码引用了 `CreatePurchaseOnBehalfRequest` DTO，会编译失败

**缓解措施**：
- 通过 `grep` 搜索确认无引用（仅在 Service 测试中使用）
- 修改测试用例，使用 `CreateOrderRequest` 替代

**验证步骤**：
```bash
grep -r "CreatePurchaseOnBehalfRequest" internal/
```

### 风险 3：Service 方法签名变更可能影响现有调用

**风险**：`Service.Create` 方法签名变更（增加 `userType`、`userID` 参数），现有调用方可能失败

**缓解措施**：
- 通过 LSP 查找所有调用方
- 仅有 `OrderHandler.Create` 和测试用例调用，影响范围可控

**影响范围**：
- `internal/handler/admin/order.go`
- `internal/handler/h5/order.go`（H5 订单不使用 offline，不受影响）
- `internal/service/order/service_test.go`

### 权衡 4：合并方法增加了单个方法的复杂度

**权衡**：`Service.Create` 方法内部有 if/else 分支，复杂度略微增加

**接受理由**：
- 两个独立方法的维护成本更高（重复代码、接口复杂）
- 内部分支清晰，使用辅助方法拆分逻辑（`buildPurchaseOnBehalfOrder`、`buildNormalOrder`）
- 测试覆盖两种分支场景，确保正确性

## Migration Plan

### 部署步骤

1. **代码变更**：
   - 修改 DTO（3 个文件）
   - 修改 Service（2 个文件）
   - 修改 Handler（1 个文件）
   - 修改测试用例（2 个文件）

2. **测试验证**：
   - 运行单元测试确保所有测试通过
   - 运行 `lsp_diagnostics` 检查类型错误
   - 本地验证接口功能

3. **部署**：
   - 无数据库迁移，直接部署即可
   - 通知前端团队同步修改 `POST /api/admin/orders` 调用

4. **验证**：
   - 测试套餐系列分配的创建/更新/查询，确认强充配置正常显示
   - 测试后台订单创建（wallet 和 offline），确认业务逻辑正确

### 回滚策略

如果发现问题，可以：
1. 回滚代码到上一版本（Git revert）
2. 无数据库变更，回滚无风险
3. 强充配置字段可选，即使旧代码未传递也不会出错

### 兼容性保障

- **强充配置字段**：可选字段，默认值 false/0，现有数据不受影响
- **订单创建接口**：`payment_method` 必填，需前端同步修改（可控）
- **删除的 DTO 和方法**：仅内部使用，无外部依赖

## Open Questions

无待解决问题。
