### 13.1 功能验收 - [ ] 合伙人可以开始采购订单 - [ ] 合伙人可以标记订单已采购 - [ ] 扫码入库后自动跳转到质检页面 - [ ] 所有状态变更自动通知买家 - [ ] 异常情况自动通知管理员 - [ ] 管理员可以查看时效统计 - [ ] 管理员可以查看质量统计 - [ ] 管理员可以查看预警订单 ### 13.2 性能验收 - [ ] API响应时间 < 500ms (P95) - [ ] 页面加载时间 < 2s - [ ] 通知发送延迟 < 5s ### 13.3 安全验收 - [ ] 权限控制正确 - [ ] 输入验证完整 - [ ] 审计日志完整 --- ## 附录 ### A. 术语表 | 术语 | 说明 | |------|------| | 合伙人 | Partner,负责采购和仓库的角色 | | 买家 | Client,下单购买商品的用户 | | 管理员 | Admin,平台管理员 | | QC | Quality Check,质检 | | 时效 | 处理订单的速度 | | 质量 | 订单处理的准确性和成功率 | ### B. 参考文档 - [合伙人工作流程优化方案](./partner-workflow-optimization.md) - [项目进度追踪](./project-progress.md) - [API文档](./api-documentation.md) --- ## 14. 包裹管理流程 ### 14.1 包裹生命周期 包裹是订单中多个商品的集合,用于统一打包和发货。 ``` in_warehouse (商品在库) ↓ 客户申请打包 packing_requested (打包中) ↓ 合伙人提交打包信息(重量、尺寸) awaiting_shipment (待发货-等报价) ↓ 管理员报价 payment_pending (待支付运费) ↓ 客户支付运费 paid (已支付-待发货) ↓ 合伙人发货(填写内部单号) shipped_waiting (已发货-等转单) ↓ 管理员填写国际单号 shipped (已发货) ↓ 客户确认 delivered (已签收) ``` ### 14.2 包裹状态触发条件 | 状态 | 触发条件 | 操作者 | 说明 | |------|---------|--------|------| | `packing_requested` | 客户申请打包 | 客户 | 初始状态 | | `awaiting_shipment` | 提交打包信息 | 合伙人 | 已称重量尺寸 | | `payment_pending` | 管理员报价 | 管理员 | 等待客户支付 | | `paid` | 客户支付运费 | 客户 | 已支付,等待发货 | | `shipped_waiting` | 合伙人发货 | 合伙人 | 已发货,等待国际单号 | | `shipped` | 填写国际单号 | 管理员 | 运输中 | | `delivered` | 客户确认签收 | 客户 | 终态 | ### 14.3 追踪单号管理 系统使用两种追踪单号: #### 14.3.1 内部追踪单号 (internal_tracking_no) - **用途**: 内部物流追踪 - **填写者**: 合伙人 - **可见性**: 仅内部可见,**不显示给客户** - **示例**: 国内快递单号(SF1234567890) - **填写时机**: 合伙人发货时 #### 14.3.2 国际追踪单号 (international_tracking_no) - **用途**: 国际物流追踪 - **填写者**: 管理员 - **可见性**: **显示给客户** - **示例**: UPS、DHL、FedEx 单号 - **填写时机**: 管理员确认国际段物流后 ### 14.4 滞留费计算规则 #### 14.4.1 计算方式 - 滞留费按**商品**计算,不是按包裹 - 每个商品入库后开始计时(`warehouse_date`) - 超过免费期后,每天收取固定费用 - 打包时自动汇总所有商品的滞留费 #### 14.4.2 费率标准 - **免费期**: 入库后 30 天 - **超期费用**: $0.50/商品/天 #### 14.4.3 计算示例 **场景**: 包裹包含 3 个商品 | 商品 | 入库天数 | 超期天数 | 滞留费 | |------|---------|---------|--------| | 商品A | 35天 | 5天 | (35-30) × $0.50 = $2.50 | | 商品B | 40天 | 10天 | (40-30) × $0.50 = $5.00 | | 商品C | 25天 | 0天 | $0(未超期) | | **合计** | - | - | **$7.50** | #### 14.4.4 业务规则 1. 滞留费在管理员报价时自动计算 2. 滞留费与运费一起向客户收取 3. 客户支付后,滞留费记录在包裹的 `storage_fee_usd` 字段 4. 滞留费不可退款(除非平台责任) ### 14.5 包裹管理 API #### 14.5.1 合伙人发货 ``` POST /api/v1/partner/parcels/{parcel_id}/ship ``` **权限**: Partner **请求体**: ```json { "internal_tracking_no": "SF1234567890" } ``` **业务逻辑**: 1. 验证包裹状态为 `paid` 2. 更新 `internal_tracking_no` 3. 更新状态为 `shipped_waiting` 4. 记录发货时间 5. 发送通知给管理员(需要填写国际单号) --- #### 14.5.2 管理员获取包裹详情 ``` GET /api/v1/admin/parcels/{parcel_id}/details ``` **权限**: Admin **响应**: 包含包裹完整信息,包括: - 基本信息(编号、状态、用户) - 尺寸重量 - 价格信息(运费、滞留费) - 追踪单号(内部、国际) - 地址快照 - 商品列表 - 时间戳 --- #### 14.5.3 管理员报价 ``` POST /api/v1/admin/parcels/{parcel_id}/quote ``` **权限**: Admin **请求体**: ```json { "shipping_quote_usd": 45.00, "storage_fee_usd": 5.00 } ``` **业务逻辑**: 1. 验证包裹状态为 `awaiting_shipment` 2. 更新运费和滞留费 3. 更新状态为 `payment_pending` 4. 发送邮件通知客户支付 5. 记录报价时间 **注意事项**: - `storage_fee_usd` 通常由系统自动计算,管理员可手动调整 - 报价后客户会收到邮件通知 - 客户支付后状态自动变为 `paid` --- #### 14.5.4 管理员发货 ``` POST /api/v1/admin/parcels/{parcel_id}/ship ``` **权限**: Admin **请求体**: ```json { "international_tracking_no": "UPS1234567890", "carrier": "UPS" } ``` **业务逻辑**: 1. 验证包裹状态为 `paid` 或 `shipped_waiting` 2. 更新 `international_tracking_no` 和 `carrier` 3. 更新状态为 `shipped` 4. 记录发货时间 `shipped_at` 5. 发送邮件通知客户(包含追踪单号) **注意事项**: - 国际单号会显示给客户 - 客户可以使用此单号追踪包裹 - 发货后客户会收到邮件通知 ### 14.6 包裹数据模型 #### 14.6.1 Parcel 表关键字段 | 字段名 | 类型 | 说明 | |--------|------|------| | `id` | UUID | 包裹ID | | `parcel_number` | VARCHAR(30) | 包裹编号(展示用) | | `user_id` | UUID | 所属用户 | | `address_id` | UUID | 收货地址 | | `parcel_status` | VARCHAR(50) | 包裹状态 | | `weight_kg` | DECIMAL(8,3) | 重量(千克) | | `length_cm` | DECIMAL(8,2) | 长度(厘米) | | `width_cm` | DECIMAL(8,2) | 宽度(厘米) | | `height_cm` | DECIMAL(8,2) | 高度(厘米) | | `shipping_quote_usd` | DECIMAL(12,2) | 运费报价 | | `storage_fee_usd` | DECIMAL(12,2) | 滞留费 | | `internal_tracking_no` | VARCHAR(50) | 内部追踪单号 | | `international_tracking_no` | VARCHAR(50) | 国际追踪单号 | | `packed_by` | UUID | 打包人ID | | `awaiting_shipment_at` | DATETIME | 等待发货时间 | | `shipped_at` | DATETIME | 发货时间 | #### 14.6.2 地址快照字段 为确保地址信息不因用户删除地址而丢失,包裹创建时会保存地址快照: | 字段名 | 类型 | 说明 | |--------|------|------| | `snapshot_recipient_name` | VARCHAR(100) | 收件人姓名 | | `snapshot_phone` | VARCHAR(30) | 电话号码 | | `snapshot_address_line1` | VARCHAR(255) | 地址行1 | | `snapshot_address_line2` | VARCHAR(255) | 地址行2 | | `snapshot_city` | VARCHAR(100) | 城市 | | `snapshot_state_province` | VARCHAR(100) | 省/州 | | `snapshot_country` | VARCHAR(100) | 国家 | | `snapshot_postal_code` | VARCHAR(20) | 邮编 | ### 14.7 常见问题和解决方案 #### Q1: 为什么需要两个追踪单号? **A**: - 内部单号用于追踪国内段物流(仓库到国际转运点) - 国际单号用于追踪国际段物流(转运点到客户) - 分离管理避免客户看到内部物流信息 #### Q2: 滞留费如何计算? **A**: - 按商品计算,不是按包裹 - 入库后30天免费 - 超期后每天$0.50/商品 - 打包时自动汇总 #### Q3: 客户支付运费后多久发货? **A**: - 客户支付后状态变为 `paid` - 合伙人会在1-2个工作日内发货 - 发货后状态变为 `shipped_waiting` - 管理员填写国际单号后状态变为 `shipped` #### Q4: 如果客户地址填错了怎么办? **A**: - 包裹创建时会保存地址快照 - 即使客户修改或删除原地址,快照仍然保留 - 如需修改地址,需要联系管理员手动更新快照 #### Q5: 包裹状态卡在 `shipped_waiting` 怎么办? **A**: - 这表示合伙人已发货,但管理员还未填写国际单号 - 管理员需要在后台填写国际追踪单号 - 填写后状态会自动变为 `shipped`,客户会收到通知