### 文档说明
本文档描述 `api_v2` 的 **BusinessObject 克隆**接口与约束，用于在不影响原对象的情况下，克隆一个“流程实例数据完全一致”的新对象（包含日志与工艺参数历史），同时要求绑定到新的业务对象（`content_type + object_id`）。

---

## 1. 背景与目的
`stateflow.BusinessObject` 通过：
- `process` 指定流程模板；
- `state_logs (StateFlowRecord)` 记录每一步完成情况；
- `StateLogParameterRecord` 记录每次提交的工艺参数 JSON；
- `content_type + object_id`（GenericForeignKey）可选关联到“订单/工单/任务”等业务对象。

克隆的目的：
- **完整复制流程实例的历史数据**（含已撤销记录、含参数记录）用于“另起一份流程实例继续/重跑/复盘”；
- **不影响原对象**；
- **必须绑定新的业务对象 ID**，否则克隆出的对象与原对象在业务关联上无差异，容易造成误用。

---

## 2. API 概览
### 2.1 Endpoint
- **POST** `/api/v2/stateflow/business-objects/clone/`

### 2.2 权限
- 需要登录：`IsAuthenticated`
- 鉴权方式：项目统一 JWT（同其他 api_v2 端点）

### 2.3 请求参数（必须）
请求体 JSON：
- `business_object_id`：源 BusinessObject 的 ID
- `content_type`：源对象的 `content_type_id`（仅用于一致性校验）
- `object_id`：克隆后新对象要绑定的业务对象 ID（必须是新的）

> 说明：
> - **content_type 仅做 “与源对象是否一致” 校验**，不做额外业务校验。
> - **object_id 必须与源对象不同**；否则克隆没有业务意义，后端会拒绝。

### 2.4 响应
成功：
- 返回 `business_object_id`（克隆后新对象 ID）

---

## 3. 请求/响应示例
### 3.1 成功克隆
请求：
```json
{
  "business_object_id": 123,
  "content_type": 9,
  "object_id": 456
}
```

响应（200）：
```json
{
  "business_object_id": 789
}
```

含义：
- `123` 是源流程实例
- `789` 是新的流程实例（日志与参数完整复制）
- 新实例会绑定到新的业务对象：`content_type_id=9, object_id=456`

---

## 4. 重要校验规则与错误码
### 4.1 404：源对象不存在
当 `business_object_id` 不存在时：
- 返回 **404**
```json
{ "detail": "business_object 不存在" }
```

### 4.2 400：content_type 不一致
当请求体 `content_type` 与源对象的 `content_type_id` 不一致：
- 返回 **400**
```json
{ "detail": "content_type 与源对象不一致，拒绝克隆" }
```

### 4.3 400：object_id 相关校验失败
当源对象存在 `content_type_id`（即已绑定业务对象）时：
- **必须提供** `object_id`；
- 且 `object_id` **必须与源对象不同**。

可能返回的 400：
```json
{ "detail": "必须提供新的 object_id" }
```
或
```json
{ "detail": "object_id 必须与源对象不同" }
```

### 4.4 400：源对象未绑定业务对象但传了 object_id
当源对象 `content_type_id` 为 `null` 时，要求 `object_id` 也为 `null`：
```json
{ "detail": "源对象未绑定 content_type，object_id 必须为空" }
```

---

## 5. 克隆范围与语义（后端实现约定）
后端通过 `stateflow.services.clone_business_object(...)` 实现克隆，核心语义：
- **克隆 BusinessObject 的基础字段**：`name / process / description / content_type`；
- **克隆后的 object_id 使用请求体传入的 `object_id`**；
- **复制所有 StateFlowRecord（state_logs）**：
  - 包含已撤销记录（`is_cancelled=True`）
  - 保持 `completed_at / cancelled_at` 等关键字段一致
- **复制每条 StateFlowRecord 的 StateLogParameterRecord（parameter_records）**：
  - 复制 `parameters`（深拷贝 JSON）
  - 复制 `remark`
  - 保持 `created_at/updated_at` 一致
- **时间戳一致性（严格）**：
  - `BusinessObject.created_at/updated_at` 也会被同步为源对象值（通过 update 绕过 auto_now/auto_now_add）
- **互不影响**：
  - 修改克隆对象的参数记录/日志不会影响源对象（复制的是新记录）

---

## 6. 与测试的对应关系
强校验与数据一致性主要由 **service 层严格测试**保证：
- `stateflow/tests/test_clone_business_object.py`

API 层仅做轻量测试：
- `api_v2/tests.py`（成功/404/401/ct不一致）

---

## 7. 变更提示（给前端/调用方）
如果你之前使用旧版接口仅传 `business_object_id`：
- 现在必须补齐 `content_type` 与新的 `object_id`；
- 并且 `object_id` 必须是“新业务对象”的 id（例如新订单、复制出来的订单等）。


