006.014.order-submit-goods-name-optimization.story.md 8.9 KB

Story 006.014: 订单提交快照商品名称优化

Status

Ready for Review

Story

As a 用户, I want 订单快照中的商品名称包含完整的父商品名称和规格信息, so that 订单页面能正确显示商品信息,与购物车显示逻辑保持一致

Acceptance Criteria

  1. 提交订单时,子商品的快照商品名称包含完整的父商品名称和规格信息(例如:"连衣裙 红色 大码")
  2. 单规格商品的快照商品名称保持不变
  3. 订单详情页面正确显示完整的商品信息
  4. 现有功能不受影响,无回归问题

Tasks / Subtasks

  • 任务1:分析当前订单商品快照逻辑 (AC: 1, 2, 3, 4)
    • 检查 packages/orders-module-mt/src/services/order.mt.service.ts 中的 createOrder 方法
    • 分析当前 goodsName 字段的赋值逻辑(第139行:goodsName: info.goods.name
    • 理解商品实体结构,确认 spuId 字段的使用方式
    • 检查购物车商品名称显示逻辑,确保与订单快照逻辑保持一致
  • 任务2:实现子商品快照名称优化逻辑 (AC: 1, 2, 4)
    • createOrder 方法的商品循环中,判断商品是否为子商品(通过 spuId 字段)
    • 如果是子商品(spuId > 0),通过 spuId 查询父商品实体,获取父商品名称
    • 将父商品名称和子商品名称拼接后赋值给 goodsName 字段(例如:goodsName =${parentGoods.name} ${goods.name}``)
    • 确保多租户过滤:父子商品在同一租户下
    • 确保单规格商品(spuId = 0)保持现有逻辑不变
  • 任务3:添加单元测试和集成测试 (AC: 1, 2, 3, 4)
    • createOrder 方法中的商品名称拼接逻辑添加单元测试
    • 在现有集成测试文件 packages/orders-module-mt/tests/integration/user-orders-routes.integration.test.ts 中新增针对父子商品的订单创建测试用例
    • 在集成测试中验证子商品订单快照的商品名称格式
    • 验证单规格商品的现有行为保持不变
  • 任务4:验证功能完整性和性能 (AC: 3, 4)
    • 验证订单详情页面正确显示完整的商品信息
    • 测试父子商品在不同租户下的隔离性
    • 确保没有额外的数据库查询影响性能
    • 运行现有测试套件,确保无回归问题

Dev Notes

问题分析

  • 当前问题:在 packages/orders-module-mt/src/services/order.mt.service.tscreateOrder 方法中,goodsName 字段直接使用商品实体的 name 字段(第139行)。对于子商品,这会导致订单快照中存储的是子商品的规格名称,而不是父商品名称+规格名称的组合。
  • 影响:订单页面显示的商品名称与购物车显示逻辑不一致。购物车中商品名称显示父商品名称,规格名称显示子商品规格名称,但订单快照只存储子商品的名称。
  • 技术背景
    • 商品实体(GoodsMt)包含 spuId 字段,用于标识父子商品关系(spuId = 0 表示父商品,spuId > 0 表示子商品)
    • 购物车显示逻辑已优化:显示父商品名称 + 子商品规格名称
    • 需要保持订单快照与购物车显示逻辑的一致性

技术实现细节

  • 文件位置
    • 主要修改文件:packages/orders-module-mt/src/services/order.mt.service.ts [Source: architecture/source-tree.md#实际项目结构]
    • 测试文件:在现有集成测试文件 packages/orders-module-mt/tests/integration/user-orders-routes.integration.test.ts 中新增测试用例
  • 商品实体结构
    • GoodsMt 实体包含 spuId: number 字段(父商品ID)[Source: packages/goods-module-mt/src/entities/goods.entity.mt.ts:77-78]
    • spuId = 0:父商品或无父子关系的商品
    • spuId > 0:子商品,指向父商品的ID
    • 商品名称字段:name: string [Source: packages/goods-module-mt/src/entities/goods.entity.mt.ts:17-18]
  • 当前实现分析
    • createOrder 方法在第134-152行创建订单商品明细
    • 第139行:goodsName: info.goods.name 直接使用商品名称
    • 需要修改:对于子商品,使用父商品名称 + 子商品名称的组合
  • 多租户要求
    • 所有查询必须包含 tenantId 过滤条件 [Source: architecture/coding-standards.md#架构原则]
    • 父子商品必须在同一租户下
  • 性能考虑
    • 避免N+1查询问题:批量查询父商品信息
    • 考虑在事务中缓存父商品查询结果

解决方案设计

  1. 修改 createOrder 方法

    // 在商品循环中收集需要查询的父商品ID
    const parentGoodsIds = new Set<number>();
    for (const item of products) {
     const goods = await this.goodsRepository.findOne({
       where: { id: item.id, tenantId }
     });
     // ... 现有验证逻辑
    
     if (goods.spuId > 0) {
       parentGoodsIds.add(goods.spuId);
     }
    }
    
    // 批量查询父商品信息
    const parentGoodsMap = new Map<number, GoodsMt>();
    if (parentGoodsIds.size > 0) {
     const parentGoods = await this.goodsRepository.find({
       where: { id: In([...parentGoodsIds]), tenantId }
     });
     parentGoods.forEach(g => parentGoodsMap.set(g.id, g));
    }
    
    // 创建订单商品明细时使用正确的商品名称
    const orderGoodsList = goodsInfo.map(info => {
     let goodsName = info.goods.name;
     if (info.goods.spuId > 0) {
       const parentGoods = parentGoodsMap.get(info.goods.spuId);
       if (parentGoods) {
         goodsName = `${parentGoods.name} ${info.goods.name}`;
       }
     }
    
     return {
       // ... 其他字段
       goodsName,
       // ... 其他字段
     };
    });
    
  2. 测试策略

    • 单元测试:验证商品名称拼接逻辑
    • 集成测试:验证完整订单创建流程
    • 测试父子商品、单规格商品的不同场景

文件位置

  • 主要修改文件
    • packages/orders-module-mt/src/services/order.mt.service.ts - 修改 createOrder 方法中的商品名称拼接逻辑
  • 测试文件
    • packages/orders-module-mt/tests/integration/user-orders-routes.integration.test.ts - 在现有集成测试中新增针对父子商品的订单创建测试用例,验证订单快照商品名称格式

技术约束

  • 多租户隔离:所有数据库查询必须包含 tenantId 条件 [Source: architecture/coding-standards.md#架构原则]
  • TypeORM使用:使用 In 操作符进行批量查询,避免N+1问题
  • 事务安全:修改在现有事务中,确保数据一致性
  • 向后兼容性:单规格商品(spuId = 0)的行为保持不变

Testing

  • 测试框架:Vitest [Source: architecture/tech-stack.md#新技术添加]
  • 集成测试框架:hono/testing [Source: architecture/tech-stack.md#新技术添加]
  • 测试位置
    • 单元测试:packages/orders-module-mt/tests/unit/**/*.test.ts [Source: architecture/testing-strategy.md#单元测试]
    • 集成测试:packages/orders-module-mt/tests/integration/**/*.test.ts [Source: architecture/testing-strategy.md#集成测试]
  • 测试标准
    • 单元测试覆盖率目标:≥ 80% [Source: architecture/testing-strategy.md#单元测试]
    • 集成测试覆盖率目标:≥ 60% [Source: architecture/testing-strategy.md#集成测试]
  • 具体测试要求
    • 验证子商品订单快照的商品名称格式
    • 验证单规格商品的现有行为不变
    • 验证多租户数据隔离
    • 验证事务回滚场景

Change Log

Date Version Description Author
2025-12-15 1.0 初始故事创建 Bob (Scrum Master)

Dev Agent Record

此部分由开发代理在实施过程中填写

Agent Model Used

  • Claude Code (sonnet)

Debug Log References

Completion Notes List

  • 分析了当前订单商品快照逻辑,确认了 goodsName 字段直接使用商品名称的问题
  • 修改了 packages/orders-module-mt/src/services/order.mt.service.ts 中的 createOrder 方法,实现了子商品快照名称优化逻辑
  • 添加了批量查询父商品信息的逻辑,避免N+1查询问题
  • 确保多租户过滤,父子商品在同一租户下
  • 确保单规格商品(spuId = 0)保持现有逻辑不变
  • 在集成测试文件中新增了两个测试用例,验证子商品和单规格商品的订单快照商品名称
  • 运行了完整的测试套件,所有测试通过,无回归问题

File List

  • packages/orders-module-mt/src/services/order.mt.service.ts - 修改了 createOrder 方法,添加了父商品批量查询和商品名称拼接逻辑
  • packages/orders-module-mt/tests/integration/user-orders-routes.integration.test.ts - 新增了两个集成测试用例,验证子商品和单规格商品的订单快照商品名称
  • docs/stories/006.014.order-submit-goods-name-optimization.story.md - 更新了任务状态和开发记录

QA Results

此部分由QA代理在审查完成后填写