Explorar el Código

🐛 fix(orders-module): 修复订单创建测试的数据结构匹配问题

- 修复订单创建API返回数据结构与测试期望不匹配的问题
- 在schema中使用coerce.number()自动转换数字类型
- 修复用户订单测试中的外键约束和导入问题
- 添加AreaLevel.TOWN枚举值以支持完整的地区层级
- 标准化订单创建API返回状态码为201

🤖 Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
yourname hace 1 mes
padre
commit
c2ba7b4067

+ 3 - 2
packages/geo-areas/src/modules/areas/area.entity.ts

@@ -4,7 +4,8 @@ import { DeleteStatus, DisabledStatus } from '@d8d/shared-types';
 export enum AreaLevel {
   PROVINCE = 1, // 省/直辖市
   CITY = 2,     // 市
-  DISTRICT = 3  // 区/县
+  DISTRICT = 3, // 区/县
+  TOWN = 4      // 街道/乡镇
 }
 
 @Entity({ name: 'areas' })
@@ -22,7 +23,7 @@ export class AreaEntity {
     name: 'level',
     type: 'enum',
     enum: AreaLevel,
-    comment: '层级: 1:省/直辖市, 2:市, 3:区/县'
+    comment: '层级: 1:省/直辖市, 2:市, 3:区/县, 4:街道/乡镇'
   })
   level!: AreaLevel;
 

+ 1 - 1
packages/orders-module/src/routes/create-order.ts

@@ -49,7 +49,7 @@ createOrderRoutes.openapi(
       const orderService = new OrderService(AppDataSource);
       const result = await orderService.createOrder(data, user.id);
 
-      return c.json(result, 200);
+      return c.json(result, 201);
     } catch (error) {
       console.error('创建订单失败:', error);
       return c.json(

+ 2 - 2
packages/orders-module/src/schemas/create-order.schema.ts

@@ -46,11 +46,11 @@ export const CreateOrderResponseDto = z.object({
     description: '订单号',
     example: 'ORD20240101123456'
   }),
-  amount: z.number().openapi({
+  amount: z.coerce.number().openapi({
     description: '订单总金额',
     example: 199.98
   }),
-  payAmount: z.number().openapi({
+  payAmount: z.coerce.number().openapi({
     description: '实际支付金额',
     example: 199.98
   }),

+ 173 - 126
packages/orders-module/tests/integration/create-order.integration.test.ts

@@ -9,7 +9,7 @@ import { Goods, GoodsCategory } from '@d8d/goods-module';
 import { Supplier } from '@d8d/supplier-module';
 import { File } from '@d8d/file-module';
 import { Merchant } from '@d8d/merchant-module';
-import { createOrderRoutes } from '../../src/routes/create-order';
+import createOrderRoutes from '../../src/routes/create-order';
 import { Order, OrderGoods } from '../../src/entities';
 
 // 设置集成测试钩子
@@ -50,23 +50,34 @@ describe('订单创建API集成测试', () => {
       roles: [{name:'user'}]
     });
 
-    // 创建测试商品
-    const goodsRepository = dataSource.getRepository(Goods);
-    testGoods = goodsRepository.create({
-      name: '测试商品',
-      price: 100.00,
-      costPrice: 80.00,
-      categoryId1: 1,
-      categoryId2: 1,
-      categoryId3: 1,
-      goodsType: 1,
-      supplierId: 1,
+    // 创建测试商品分类
+    const goodsCategoryRepository = dataSource.getRepository(GoodsCategory);
+    const testCategory1 = goodsCategoryRepository.create({
+      name: '一级分类',
+      level: 1,
+      sort: 1,
       state: 1,
-      stock: 100,
-      lowestBuy: 1,
       createdBy: testUser.id
     });
-    await goodsRepository.save(testGoods);
+    await goodsCategoryRepository.save(testCategory1);
+
+    const testCategory2 = goodsCategoryRepository.create({
+      name: '二级分类',
+      level: 2,
+      sort: 1,
+      state: 1,
+      createdBy: testUser.id
+    });
+    await goodsCategoryRepository.save(testCategory2);
+
+    const testCategory3 = goodsCategoryRepository.create({
+      name: '三级分类',
+      level: 3,
+      sort: 1,
+      state: 1,
+      createdBy: testUser.id
+    });
+    await goodsCategoryRepository.save(testCategory3);
 
     // 创建测试供应商
     const supplierRepository = dataSource.getRepository(Supplier);
@@ -81,6 +92,38 @@ describe('订单创建API集成测试', () => {
     });
     await supplierRepository.save(testSupplier);
 
+    // 创建测试商户
+    const merchantRepository = dataSource.getRepository(Merchant);
+    const testMerchant = merchantRepository.create({
+      name: '测试商户',
+      username: `test_merchant_${Math.floor(Math.random() * 100000)}`,
+      password: 'password123',
+      phone: '13800138000',
+      realname: '测试商户',
+      state: 1,
+      createdBy: testUser.id
+    });
+    await merchantRepository.save(testMerchant);
+
+    // 创建测试商品
+    const goodsRepository = dataSource.getRepository(Goods);
+    testGoods = goodsRepository.create({
+      name: '测试商品',
+      price: 100.00,
+      costPrice: 80.00,
+      categoryId1: testCategory1.id,
+      categoryId2: testCategory2.id,
+      categoryId3: testCategory3.id,
+      goodsType: 1,
+      supplierId: testSupplier.id,
+      merchantId: testMerchant.id,
+      state: 1,
+      stock: 100,
+      lowestBuy: 1,
+      createdBy: testUser.id
+    });
+    await goodsRepository.save(testGoods);
+
     // 创建测试文件
     const fileRepository = dataSource.getRepository(File);
     testFile = fileRepository.create({
@@ -95,15 +138,61 @@ describe('订单创建API集成测试', () => {
     });
     await fileRepository.save(testFile);
 
+    // 创建测试地区数据
+    const areaRepository = dataSource.getRepository(AreaEntity);
+    const testProvince = areaRepository.create({
+      name: '广东省',
+      level: 1,
+      code: '440000',
+      isDisabled: 0,
+      isDeleted: 0,
+      createdBy: testUser.id
+    });
+    await areaRepository.save(testProvince);
+
+    const testCity = areaRepository.create({
+      name: '深圳市',
+      level: 2,
+      code: '440300',
+      parentId: testProvince.id,
+      isDisabled: 0,
+      isDeleted: 0,
+      createdBy: testUser.id
+    });
+    await areaRepository.save(testCity);
+
+    const testDistrict = areaRepository.create({
+      name: '南山区',
+      level: 3,
+      code: '440305',
+      parentId: testCity.id,
+      isDisabled: 0,
+      isDeleted: 0,
+      createdBy: testUser.id
+    });
+    await areaRepository.save(testDistrict);
+
+    const testTown = areaRepository.create({
+      name: '粤海街道',
+      level: 4,
+      code: '440305001',
+      parentId: testDistrict.id,
+      isDisabled: 0,
+      isDeleted: 0,
+      createdBy: testUser.id
+    });
+    await areaRepository.save(testTown);
+
     // 创建测试配送地址
     const deliveryAddressRepository = dataSource.getRepository(DeliveryAddress);
     testDeliveryAddress = deliveryAddressRepository.create({
       userId: testUser.id,
       name: '收货人姓名',
       phone: '13800138000',
-      province: '广东省',
-      city: '深圳市',
-      district: '南山区',
+      receiverProvince: testProvince.id,
+      receiverCity: testCity.id,
+      receiverDistrict: testDistrict.id,
+      receiverTown: testTown.id,
       address: '测试地址',
       isDefault: 1,
       state: 1,
@@ -115,35 +204,17 @@ describe('订单创建API集成测试', () => {
   describe('POST /create-order', () => {
     it('应该成功创建订单并关联商品', async () => {
       const createData = {
-        orderNo: `ORDER_${Math.floor(Math.random() * 100000)}`,
-        amount: 150.00,
-        costAmount: 120.00,
-        payAmount: 150.00,
-        orderType: 1,
-        payType: 1,
-        payState: 0,
-        state: 0,
-        deliveryAddressId: testDeliveryAddress.id,
-        merchantId: 1,
-        supplierId: testSupplier.id,
-        orderGoods: [
+        addressId: testDeliveryAddress.id,
+        productOwn: '自营',
+        consumeFrom: '积分兑换',
+        products: [
           {
-            goodsId: testGoods.id,
-            goodsName: '测试商品1',
-            price: 50.00,
-            num: 2,
-            state: 0,
-            supplierId: testSupplier.id,
-            imageFileId: testFile.id
+            id: testGoods.id,
+            num: 2
           },
           {
-            goodsId: testGoods.id,
-            goodsName: '测试商品2',
-            price: 25.00,
-            num: 2,
-            state: 0,
-            supplierId: testSupplier.id,
-            imageFileId: testFile.id
+            id: testGoods.id,
+            num: 1
           }
         ]
       };
@@ -165,22 +236,27 @@ describe('订单创建API集成测试', () => {
 
       if (response.status === 201) {
         const data = await response.json();
-        expect(data).toHaveProperty('id');
-        expect(data.orderNo).toBe(createData.orderNo);
-        expect(parseFloat(data.amount)).toBe(createData.amount);
-        expect(data.userId).toBe(testUser.id); // 验证自动设置当前用户权限
-        expect(data.createdBy).toBe(testUser.id); // 验证自动设置创建用户
+        expect(data).toHaveProperty('orderId');
+        expect(data).toHaveProperty('orderNo');
+        expect(data).toHaveProperty('amount');
+        expect(data).toHaveProperty('payAmount');
 
-        // 验证订单商品被正确创建
-        expect(data.orderGoods).toBeDefined();
-        expect(Array.isArray(data.orderGoods)).toBe(true);
-        expect(data.orderGoods.length).toBe(2);
+        // 验证订单商品被正确创建(需要从数据库查询验证)
+        const dataSource = await IntegrationTestDatabase.getDataSource();
+        const orderGoodsRepository = dataSource.getRepository(OrderGoods);
+        const createdOrderGoods = await orderGoodsRepository.find({
+          where: { orderId: data.orderId }
+        });
+
+        expect(createdOrderGoods).toBeDefined();
+        expect(Array.isArray(createdOrderGoods)).toBe(true);
+        expect(createdOrderGoods.length).toBe(2);
 
         // 验证商品信息
-        data.orderGoods.forEach((orderGoods: any, index: number) => {
-          expect(orderGoods.goodsName).toBe(createData.orderGoods[index].goodsName);
-          expect(parseFloat(orderGoods.price)).toBe(createData.orderGoods[index].price);
-          expect(orderGoods.num).toBe(createData.orderGoods[index].num);
+        createdOrderGoods.forEach((orderGoods: any, index: number) => {
+          expect(orderGoods.goodsName).toBe(testGoods.name);
+          expect(orderGoods.price).toBe(testGoods.price);
+          expect(orderGoods.num).toBe(createData.products[index].num);
           expect(orderGoods.createdBy).toBe(testUser.id); // 验证商品创建用户
         });
       }
@@ -298,26 +374,13 @@ describe('订单创建API集成测试', () => {
   describe('事务性测试', () => {
     it('应该确保订单和商品创建的事务一致性', async () => {
       const createData = {
-        orderNo: `ORDER_${Math.floor(Math.random() * 100000)}`,
-        amount: 200.00,
-        costAmount: 160.00,
-        payAmount: 200.00,
-        orderType: 1,
-        payType: 1,
-        payState: 0,
-        state: 0,
-        deliveryAddressId: testDeliveryAddress.id,
-        merchantId: 1,
-        supplierId: testSupplier.id,
-        orderGoods: [
+        addressId: testDeliveryAddress.id,
+        productOwn: '自营',
+        consumeFrom: '积分兑换',
+        products: [
           {
-            goodsId: testGoods.id,
-            goodsName: '测试商品1',
-            price: 100.00,
-            num: 2,
-            state: 0,
-            supplierId: testSupplier.id,
-            imageFileId: testFile.id
+            id: testGoods.id,
+            num: 2
           }
         ]
       };
@@ -342,22 +405,21 @@ describe('订单创建API集成测试', () => {
 
         // 验证订单存在
         const createdOrder = await orderRepository.findOne({
-          where: { id: data.id },
-          relations: ['orderGoods']
+          where: { id: data.orderId }
         });
 
         expect(createdOrder).toBeDefined();
-        expect(createdOrder?.orderNo).toBe(createData.orderNo);
+        expect(createdOrder?.orderNo).toBe(data.orderNo);
         expect(createdOrder?.userId).toBe(testUser.id);
 
         // 验证订单商品存在
         const createdOrderGoods = await orderGoodsRepository.find({
-          where: { orderId: data.id }
+          where: { orderId: data.orderId }
         });
 
         expect(createdOrderGoods.length).toBe(1);
-        expect(createdOrderGoods[0].goodsName).toBe(createData.orderGoods[0].goodsName);
-        expect(createdOrderGoods[0].num).toBe(createData.orderGoods[0].num);
+        expect(createdOrderGoods[0].goodsName).toBe(testGoods.name);
+        expect(createdOrderGoods[0].num).toBe(createData.products[0].num);
       }
     });
 
@@ -366,26 +428,13 @@ describe('订单创建API集成测试', () => {
       const purchaseQuantity = 2;
 
       const createData = {
-        orderNo: `ORDER_${Math.floor(Math.random() * 100000)}`,
-        amount: 200.00,
-        costAmount: 160.00,
-        payAmount: 200.00,
-        orderType: 1,
-        payType: 1,
-        payState: 0,
-        state: 0,
-        deliveryAddressId: testDeliveryAddress.id,
-        merchantId: 1,
-        supplierId: testSupplier.id,
-        orderGoods: [
+        addressId: testDeliveryAddress.id,
+        productOwn: '自营',
+        consumeFrom: '积分兑换',
+        products: [
           {
-            goodsId: testGoods.id,
-            goodsName: '测试商品',
-            price: 100.00,
-            num: purchaseQuantity,
-            state: 0,
-            supplierId: testSupplier.id,
-            imageFileId: testFile.id
+            id: testGoods.id,
+            num: purchaseQuantity
           }
         ]
       };
@@ -409,7 +458,7 @@ describe('订单创建API集成测试', () => {
         });
 
         expect(updatedGoods).toBeDefined();
-        expect(updatedGoods?.stock).toBe(initialStock - purchaseQuantity);
+        expect(Number(updatedGoods?.stock)).toBe(initialStock - purchaseQuantity);
       }
     });
   });
@@ -417,26 +466,13 @@ describe('订单创建API集成测试', () => {
   describe('数据权限测试', () => {
     it('应该自动设置当前用户权限', async () => {
       const createData = {
-        orderNo: `ORDER_${Math.floor(Math.random() * 100000)}`,
-        amount: 100.00,
-        costAmount: 80.00,
-        payAmount: 100.00,
-        orderType: 1,
-        payType: 1,
-        payState: 0,
-        state: 0,
-        deliveryAddressId: testDeliveryAddress.id,
-        merchantId: 1,
-        supplierId: testSupplier.id,
-        orderGoods: [
+        addressId: testDeliveryAddress.id,
+        productOwn: '自营',
+        consumeFrom: '积分兑换',
+        products: [
           {
-            goodsId: testGoods.id,
-            goodsName: '测试商品',
-            price: 100.00,
-            num: 1,
-            state: 0,
-            supplierId: testSupplier.id,
-            imageFileId: testFile.id
+            id: testGoods.id,
+            num: 1
           }
         ]
       };
@@ -454,12 +490,23 @@ describe('订单创建API集成测试', () => {
       if (response.status === 201) {
         const data = await response.json();
 
-        // 验证订单和商品都设置了正确的用户权限
-        expect(data.userId).toBe(testUser.id);
-        expect(data.createdBy).toBe(testUser.id);
+        // 验证订单和商品都设置了正确的用户权限(需要从数据库查询验证)
+        const dataSource = await IntegrationTestDatabase.getDataSource();
+        const orderRepository = dataSource.getRepository(Order);
+        const orderGoodsRepository = dataSource.getRepository(OrderGoods);
+
+        // 验证订单权限
+        const createdOrder = await orderRepository.findOne({
+          where: { id: data.orderId }
+        });
+        expect(createdOrder?.userId).toBe(testUser.id);
+        expect(createdOrder?.createdBy).toBe(testUser.id);
 
-        // 验证订单商品也设置了正确的用户权限
-        data.orderGoods.forEach((orderGoods: any) => {
+        // 验证订单商品权限
+        const createdOrderGoods = await orderGoodsRepository.find({
+          where: { orderId: data.orderId }
+        });
+        createdOrderGoods.forEach((orderGoods: any) => {
           expect(orderGoods.createdBy).toBe(testUser.id);
         });
       }

+ 13 - 13
packages/orders-module/tests/integration/user-orders.integration.test.ts

@@ -8,7 +8,7 @@ import { AreaEntity } from '@d8d/geo-areas';
 import { Merchant } from '@d8d/merchant-module';
 import { Supplier } from '@d8d/supplier-module';
 import { File } from '@d8d/file-module';
-import { userOrderRoutes } from '../../src/routes/user/orders';
+import userOrderRoutes from '../../src/routes/user/orders';
 import { Order } from '../../src/entities';
 
 // 设置集成测试钩子
@@ -160,7 +160,7 @@ describe('用户订单管理API集成测试', () => {
         payType: 1,
         payState: 2,
         state: 0,
-        deliveryAddressId: testDeliveryAddress.id,
+        addressId: testDeliveryAddress.id,
         merchantId: testMerchant.id,
         supplierId: testSupplier.id,
         createdBy: testUser.id
@@ -177,7 +177,7 @@ describe('用户订单管理API集成测试', () => {
         payType: 1,
         payState: 2,
         state: 1,
-        deliveryAddressId: testDeliveryAddress.id,
+        addressId: testDeliveryAddress.id,
         merchantId: testMerchant.id,
         supplierId: testSupplier.id,
         createdBy: testUser.id
@@ -195,7 +195,7 @@ describe('用户订单管理API集成测试', () => {
         payType: 1,
         payState: 2,
         state: 0,
-        deliveryAddressId: testDeliveryAddress.id,
+        addressId: testDeliveryAddress.id,
         merchantId: testMerchant.id,
         supplierId: testSupplier.id,
         createdBy: otherUser.id
@@ -258,7 +258,7 @@ describe('用户订单管理API集成测试', () => {
         payType: 1,
         payState: 0,
         state: 0,
-        deliveryAddressId: testDeliveryAddress.id,
+        addressId: testDeliveryAddress.id,
         merchantId: testMerchant.id,
         supplierId: testSupplier.id
       };
@@ -322,7 +322,7 @@ describe('用户订单管理API集成测试', () => {
         payType: 1,
         payState: 2,
         state: 0,
-        deliveryAddressId: testDeliveryAddress.id,
+        addressId: testDeliveryAddress.id,
         merchantId: testMerchant.id,
         supplierId: testSupplier.id,
         createdBy: testUser.id
@@ -366,7 +366,7 @@ describe('用户订单管理API集成测试', () => {
         payType: 1,
         payState: 2,
         state: 0,
-        deliveryAddressId: testDeliveryAddress.id,
+        addressId: testDeliveryAddress.id,
         merchantId: testMerchant.id,
         supplierId: testSupplier.id,
         createdBy: otherUser.id
@@ -412,7 +412,7 @@ describe('用户订单管理API集成测试', () => {
         payType: 1,
         payState: 2,
         state: 0,
-        deliveryAddressId: testDeliveryAddress.id,
+        addressId: testDeliveryAddress.id,
         merchantId: testMerchant.id,
         supplierId: testSupplier.id,
         createdBy: testUser.id
@@ -458,7 +458,7 @@ describe('用户订单管理API集成测试', () => {
         payType: 1,
         payState: 2,
         state: 0,
-        deliveryAddressId: testDeliveryAddress.id,
+        addressId: testDeliveryAddress.id,
         merchantId: testMerchant.id,
         supplierId: testSupplier.id,
         createdBy: otherUser.id
@@ -497,7 +497,7 @@ describe('用户订单管理API集成测试', () => {
         payType: 1,
         payState: 2,
         state: 0,
-        deliveryAddressId: testDeliveryAddress.id,
+        addressId: testDeliveryAddress.id,
         merchantId: testMerchant.id,
         supplierId: testSupplier.id,
         createdBy: testUser.id
@@ -530,7 +530,7 @@ describe('用户订单管理API集成测试', () => {
         payType: 1,
         payState: 2,
         state: 0,
-        deliveryAddressId: testDeliveryAddress.id,
+        addressId: testDeliveryAddress.id,
         merchantId: testMerchant.id,
         supplierId: testSupplier.id,
         createdBy: otherUser.id
@@ -568,7 +568,7 @@ describe('用户订单管理API集成测试', () => {
         payType: 1,
         payState: 2,
         state: 0,
-        deliveryAddressId: testDeliveryAddress.id,
+        addressId: testDeliveryAddress.id,
         merchantId: testMerchant.id,
         supplierId: testSupplier.id,
         createdBy: testUser.id
@@ -585,7 +585,7 @@ describe('用户订单管理API集成测试', () => {
         payType: 1,
         payState: 2,
         state: 0,
-        deliveryAddressId: testDeliveryAddress.id,
+        addressId: testDeliveryAddress.id,
         merchantId: testMerchant.id,
         supplierId: testSupplier.id,
         createdBy: otherUser.id