| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060 |
- import { describe, it, expect, beforeEach } from 'vitest';
- import { testClient } from 'hono/testing';
- import { IntegrationTestDatabase, setupIntegrationDatabaseHooksWithEntities } from '@d8d/shared-test-util';
- import { JWTUtil } from '@d8d/shared-utils';
- import { UserEntityMt, RoleMt } from '@d8d/user-module-mt';
- import { DeliveryAddressMt } from '@d8d/delivery-address-module-mt';
- import { AreaEntityMt } from '@d8d/geo-areas-mt';
- import { MerchantMt } from '@d8d/merchant-module-mt';
- import { SupplierMt } from '@d8d/supplier-module-mt';
- import { FileMt } from '@d8d/file-module-mt';
- import { GoodsMt, GoodsCategoryMt } from '@d8d/goods-module-mt';
- import userOrderRoutes from '../../src/routes/user/orders.mt';
- import { OrderMt, OrderGoodsMt } from '../../src/entities';
- import { OrdersTestFactory } from '../factories/orders-test-factory';
- // 设置集成测试钩子
- setupIntegrationDatabaseHooksWithEntities([
- UserEntityMt, RoleMt, OrderMt, OrderGoodsMt, DeliveryAddressMt, MerchantMt, SupplierMt, FileMt, AreaEntityMt, GoodsMt, GoodsCategoryMt
- ])
- describe('多租户用户订单管理API集成测试', () => {
- let client: ReturnType<typeof testClient<typeof userOrderRoutes>>;
- let testFactory: OrdersTestFactory;
- let userToken: string;
- let otherUserToken: string;
- let otherTenantUserToken: string;
- let testUser: UserEntityMt;
- let otherUser: UserEntityMt;
- let otherTenantUser: UserEntityMt;
- beforeEach(async () => {
- // 创建测试客户端
- client = testClient(userOrderRoutes);
- // 获取数据源并创建测试工厂
- const dataSource = await IntegrationTestDatabase.getDataSource();
- testFactory = new OrdersTestFactory(dataSource);
- // 创建测试用户
- testUser = await testFactory.createTestUser(1);
- otherUser = await testFactory.createTestUser(1);
- otherTenantUser = await testFactory.createTestUser(2);
- // 生成JWT令牌
- userToken = JWTUtil.generateToken({ id: testUser.id, username: testUser.username, tenantId: 1 });
- otherUserToken = JWTUtil.generateToken({ id: otherUser.id, username: otherUser.username, tenantId: 1 });
- otherTenantUserToken = JWTUtil.generateToken({ id: otherTenantUser.id, username: otherTenantUser.username, tenantId: 2 });
- });
- describe('租户数据隔离验证', () => {
- it('应该只能访问自己租户的订单', async () => {
- // 创建租户1的订单
- const tenant1Order = await testFactory.createTestOrder(testUser.id, { tenantId: 1 });
- // 创建租户2的订单
- const tenant2Order = await testFactory.createTestOrder(otherTenantUser.id, { tenantId: 2 });
- // 使用租户1的用户查询订单列表
- const response = await client.index.$get({
- query: {}
- }, {
- headers: {
- 'Authorization': `Bearer ${userToken}`
- }
- });
- expect(response.status).toBe(200);
- if(response.status === 200){
- const data = await response.json();
- // 应该只返回租户1的订单
- expect(data.data).toHaveLength(1);
- expect(data.data[0].tenantId).toBe(1);
- expect(data.data[0].id).toBe(tenant1Order.id);
- }
- });
- it('不应该访问其他租户的订单详情', async () => {
- // 创建租户2的订单
- const otherTenantOrder = await testFactory.createTestOrder(otherTenantUser.id, { tenantId: 2 });
- // 使用租户1的用户尝试访问租户2的订单
- const response = await client[':id'].$get({
- param: { id: otherTenantOrder.id }
- }, {
- headers: {
- 'Authorization': `Bearer ${userToken}`
- }
- });
- // 应该返回404,因为订单不在当前租户
- expect(response.status).toBe(404);
- });
- it('应该正确过滤跨租户订单访问', async () => {
- // 创建租户1的订单
- const tenant1Order = await testFactory.createTestOrder(testUser.id, { tenantId: 1 });
- // 使用租户2的用户尝试访问租户1的订单
- const response = await client[':id'].$get({
- param: { id: tenant1Order.id }
- }, {
- headers: {
- 'Authorization': `Bearer ${otherTenantUserToken}`
- }
- });
- // 应该返回404,因为订单不在当前租户
- expect(response.status).toBe(404);
- });
- });
- describe('用户数据权限验证', () => {
- it('应该只能访问自己的订单', async () => {
- // 创建当前用户的订单
- const myOrder = await testFactory.createTestOrder(testUser.id, { tenantId: 1 });
- // 创建其他用户的订单(同一租户)
- const otherUserOrder = await testFactory.createTestOrder(otherUser.id, { tenantId: 1 });
- // 使用当前用户查询订单列表
- const response = await client.index.$get({
- query: {}
- }, {
- headers: {
- 'Authorization': `Bearer ${userToken}`
- }
- });
- expect(response.status).toBe(200);
- if (response.status === 200) {
- const data = await response.json();
- // 应该只返回当前用户的订单
- expect(data.data).toHaveLength(1);
- expect(data.data[0].userId).toBe(testUser.id);
- expect(data.data[0].id).toBe(myOrder.id);
- }
- });
- it('不应该访问其他用户的订单详情', async () => {
- // 创建其他用户的订单
- const otherUserOrder = await testFactory.createTestOrder(otherUser.id, { tenantId: 1 });
- console.debug('创建的订单:', { id: otherUserOrder.id, userId: otherUserOrder.userId, tenantId: otherUserOrder.tenantId });
- // 使用当前用户尝试访问其他用户的订单
- const response = await client[':id'].$get({
- param: { id: otherUserOrder.id }
- }, {
- headers: {
- 'Authorization': `Bearer ${userToken}`
- }
- });
- // 应该返回403,因为无权访问其他用户的订单
- console.debug('响应状态码:', response.status);
- expect(response.status).toBe(403);
- });
- });
- describe('订单商品关联验证', () => {
- it('应该返回包含订单商品信息的订单详情', async () => {
- // 创建测试订单和订单商品
- const order = await testFactory.createTestOrder(testUser.id, { tenantId: 1 });
- const testGoods = await testFactory.createTestGoods(testUser.id, { tenantId: 1 });
- const orderGoods = await testFactory.createTestOrderGoods(order.id, testGoods.id, { tenantId: 1 });
- // 查询订单详情
- const response = await client[':id'].$get({
- param: { id: order.id }
- }, {
- headers: {
- 'Authorization': `Bearer ${userToken}`
- }
- });
- expect(response.status).toBe(200);
- if (response.status === 200) {
- const orderDetail = await response.json();
- // 验证订单详情包含订单商品信息
- expect(orderDetail.orderGoods).toBeDefined();
- expect(Array.isArray(orderDetail.orderGoods)).toBe(true);
- expect(orderDetail.orderGoods).toHaveLength(1);
- const goods = orderDetail.orderGoods![0];
- expect(goods.id).toBe(orderGoods.id);
- expect(goods.goodsId).toBe(orderGoods.goodsId);
- expect(goods.goodsName).toBe(orderGoods.goodsName);
- expect(goods.price).toBe(Number(orderGoods.price));
- expect(goods.num).toBe(orderGoods.num);
- }
- });
- it('应该返回包含订单商品信息的订单列表', async () => {
- // 创建测试订单和订单商品
- const order = await testFactory.createTestOrder(testUser.id, { tenantId: 1 });
- const testGoods = await testFactory.createTestGoods(testUser.id, { tenantId: 1 });
- await testFactory.createTestOrderGoods(order.id, testGoods.id, { tenantId: 1 });
- // 查询订单列表
- const response = await client.index.$get({
- query: {}
- }, {
- headers: {
- 'Authorization': `Bearer ${userToken}`
- }
- });
- expect(response.status).toBe(200);
- if (response.status === 200) {
- const data = await response.json();
- // 验证订单列表包含订单商品信息
- expect(data.data).toHaveLength(1);
- expect(data.data[0].orderGoods).toBeDefined();
- expect(Array.isArray(data.data[0].orderGoods)).toBe(true);
- expect(data.data[0].orderGoods).toHaveLength(1);
- const goods = data.data[0].orderGoods![0];
- expect(goods.goodsId).toBeGreaterThan(0);
- expect(goods.goodsName).toBeDefined();
- expect(goods.price).toBeGreaterThan(0);
- expect(goods.num).toBeGreaterThan(0);
- }
- });
- });
- describe('订单创建验证', () => {
- it('应该自动设置租户ID', async () => {
- // 创建必要的关联实体
- const testSupplier = await testFactory.createTestSupplier(testUser.id, { tenantId: 1 });
- const testMerchant = await testFactory.createTestMerchant(testUser.id, { tenantId: 1 });
- const testDeliveryAddress = await testFactory.createTestDeliveryAddress(testUser.id, { tenantId: 1 });
- const testGoods = await testFactory.createTestGoods(testUser.id, {
- tenantId: 1,
- merchantId: testMerchant.id,
- supplierId: testSupplier.id
- });
- const orderData = {
- addressId: testDeliveryAddress.id,
- productOwn: '自营',
- consumeFrom: '积分兑换',
- products: [
- { id: testGoods.id, num: 2 }
- ]
- };
- const response = await client['create-order'].$post({
- json: orderData
- }, {
- headers: {
- 'Authorization': `Bearer ${userToken}`
- }
- });
- console.debug('订单创建响应状态码:', response.status);
- if (response.status !== 201) {
- const errorResult = await response.json();
- console.debug('订单创建错误响应:', errorResult);
- }
- expect(response.status).toBe(201);
- if (response.status === 201) {
- const createdOrder = await response.json();
- // 验证订单创建成功
- expect(createdOrder.success).toBe(true);
- expect(createdOrder.orderId).toBeGreaterThan(0);
- expect(createdOrder.orderNo).toBeDefined();
- expect(createdOrder.amount).toBeGreaterThan(0);
- expect(createdOrder.payAmount).toBeGreaterThan(0);
- }
- });
- it('应该为子商品订单快照生成包含父商品名称的商品名称', async () => {
- // 创建必要的关联实体
- const testSupplier = await testFactory.createTestSupplier(testUser.id, { tenantId: 1 });
- const testMerchant = await testFactory.createTestMerchant(testUser.id, { tenantId: 1 });
- const testDeliveryAddress = await testFactory.createTestDeliveryAddress(testUser.id, { tenantId: 1 });
- // 创建父商品
- const parentGoods = await testFactory.createTestGoods(testUser.id, {
- tenantId: 1,
- merchantId: testMerchant.id,
- supplierId: testSupplier.id,
- name: '连衣裙'
- });
- // 创建子商品(规格商品)
- const childGoods = await testFactory.createTestGoods(testUser.id, {
- tenantId: 1,
- merchantId: testMerchant.id,
- supplierId: testSupplier.id,
- name: '红色 大码',
- spuId: parentGoods.id
- });
- const orderData = {
- addressId: testDeliveryAddress.id,
- productOwn: '自营',
- consumeFrom: '积分兑换',
- products: [
- { id: childGoods.id, num: 1 }
- ]
- };
- const response = await client['create-order'].$post({
- json: orderData
- }, {
- headers: {
- 'Authorization': `Bearer ${userToken}`
- }
- });
- console.debug('子商品订单创建响应状态码:', response.status);
- if (response.status !== 201) {
- const errorResult = await response.json();
- console.debug('子商品订单创建错误响应:', errorResult);
- }
- expect(response.status).toBe(201);
- if (response.status === 201) {
- const createdOrder = await response.json();
- // 验证订单创建成功
- expect(createdOrder.success).toBe(true);
- expect(createdOrder.orderId).toBeGreaterThan(0);
- // 查询订单商品明细,验证商品名称格式
- const dataSource = await IntegrationTestDatabase.getDataSource();
- const orderGoods = await dataSource.getRepository(OrderGoodsMt).find({
- where: { orderId: createdOrder.orderId, tenantId: 1 }
- });
- expect(orderGoods).toHaveLength(1);
- expect(orderGoods[0].goodsName).toBe('连衣裙 红色 大码');
- }
- });
- it('应该为单规格商品保持原有商品名称', async () => {
- // 创建必要的关联实体
- const testSupplier = await testFactory.createTestSupplier(testUser.id, { tenantId: 1 });
- const testMerchant = await testFactory.createTestMerchant(testUser.id, { tenantId: 1 });
- const testDeliveryAddress = await testFactory.createTestDeliveryAddress(testUser.id, { tenantId: 1 });
- // 创建单规格商品(spuId = 0)
- const singleSpecGoods = await testFactory.createTestGoods(testUser.id, {
- tenantId: 1,
- merchantId: testMerchant.id,
- supplierId: testSupplier.id,
- name: '单规格商品',
- spuId: 0
- });
- const orderData = {
- addressId: testDeliveryAddress.id,
- productOwn: '自营',
- consumeFrom: '积分兑换',
- products: [
- { id: singleSpecGoods.id, num: 1 }
- ]
- };
- const response = await client['create-order'].$post({
- json: orderData
- }, {
- headers: {
- 'Authorization': `Bearer ${userToken}`
- }
- });
- console.debug('单规格商品订单创建响应状态码:', response.status);
- expect(response.status).toBe(201);
- if (response.status === 201) {
- const createdOrder = await response.json();
- // 验证订单创建成功
- expect(createdOrder.success).toBe(true);
- expect(createdOrder.orderId).toBeGreaterThan(0);
- // 查询订单商品明细,验证商品名称保持不变
- const dataSource = await IntegrationTestDatabase.getDataSource();
- const orderGoods = await dataSource.getRepository(OrderGoodsMt).find({
- where: { orderId: createdOrder.orderId, tenantId: 1 }
- });
- expect(orderGoods).toHaveLength(1);
- expect(orderGoods[0].goodsName).toBe('单规格商品');
- }
- });
- it('应该正确处理规格商品的价格计算和库存', async () => {
- // 创建必要的关联实体
- const testSupplier = await testFactory.createTestSupplier(testUser.id, { tenantId: 1 });
- const testMerchant = await testFactory.createTestMerchant(testUser.id, { tenantId: 1 });
- const testDeliveryAddress = await testFactory.createTestDeliveryAddress(testUser.id, { tenantId: 1 });
- // 创建父商品
- const parentGoods = await testFactory.createTestGoods(testUser.id, {
- tenantId: 1,
- merchantId: testMerchant.id,
- supplierId: testSupplier.id,
- name: '智能手机',
- price: 2999.00, // 父商品价格
- stock: 100
- });
- // 创建规格商品(子商品)- 256GB版本
- const specGoods256GB = await testFactory.createTestGoods(testUser.id, {
- tenantId: 1,
- merchantId: testMerchant.id,
- supplierId: testSupplier.id,
- name: '256GB 黑色',
- spuId: parentGoods.id,
- price: 3299.00, // 规格特有价格
- stock: 50, // 规格特有库存
- originalPrice: 3499.00 // 规格原价
- });
- // 创建规格商品(子商品)- 512GB版本
- const specGoods512GB = await testFactory.createTestGoods(testUser.id, {
- tenantId: 1,
- merchantId: testMerchant.id,
- supplierId: testSupplier.id,
- name: '512GB 黑色',
- spuId: parentGoods.id,
- price: 3799.00, // 规格特有价格
- stock: 30, // 规格特有库存
- originalPrice: 3999.00 // 规格原价
- });
- const orderData = {
- addressId: testDeliveryAddress.id,
- productOwn: '自营',
- consumeFrom: '积分兑换',
- products: [
- { id: specGoods256GB.id, num: 2 }, // 购买2件256GB版本
- { id: specGoods512GB.id, num: 1 } // 购买1件512GB版本
- ]
- };
- const response = await client['create-order'].$post({
- json: orderData
- }, {
- headers: {
- 'Authorization': `Bearer ${userToken}`
- }
- });
- console.debug('规格商品订单创建响应状态码:', response.status);
- if (response.status !== 201) {
- const errorResult = await response.json();
- console.debug('规格商品订单创建错误响应:', errorResult);
- }
- expect(response.status).toBe(201);
- if (response.status === 201) {
- const createdOrder = await response.json();
- // 验证订单创建成功
- expect(createdOrder.success).toBe(true);
- expect(createdOrder.orderId).toBeGreaterThan(0);
- expect(createdOrder.orderNo).toBeDefined();
- // 验证订单总金额计算正确
- // 256GB: 3299.00 * 2 = 6598.00
- // 512GB: 3799.00 * 1 = 3799.00
- // 总计: 6598.00 + 3799.00 = 10397.00
- expect(createdOrder.amount).toBe(10397.00);
- expect(createdOrder.payAmount).toBe(10397.00);
- // 查询订单商品明细,验证规格信息正确保存
- const dataSource = await IntegrationTestDatabase.getDataSource();
- const orderGoods = await dataSource.getRepository(OrderGoodsMt).find({
- where: { orderId: createdOrder.orderId, tenantId: 1 },
- order: { goodsId: 'ASC' }
- });
- expect(orderGoods).toHaveLength(2);
- // 验证第一个商品(256GB)
- const goods256GB = orderGoods.find(og => og.goodsId === specGoods256GB.id);
- expect(goods256GB).toBeDefined();
- expect(goods256GB?.goodsName).toBe('智能手机 256GB 黑色');
- expect(Number(goods256GB?.price)).toBe(3299.00);
- expect(goods256GB?.num).toBe(2);
- // totalPrice字段在OrderGoodsMt实体中不存在,移除验证
- // 验证第二个商品(512GB)
- const goods512GB = orderGoods.find(og => og.goodsId === specGoods512GB.id);
- expect(goods512GB).toBeDefined();
- expect(goods512GB?.goodsName).toBe('智能手机 512GB 黑色');
- expect(Number(goods512GB?.price)).toBe(3799.00);
- expect(goods512GB?.num).toBe(1);
- // totalPrice字段在OrderGoodsMt实体中不存在,移除验证
- }
- });
- it('应该拒绝创建库存不足的规格商品订单', async () => {
- // 创建必要的关联实体
- const testSupplier = await testFactory.createTestSupplier(testUser.id, { tenantId: 1 });
- const testMerchant = await testFactory.createTestMerchant(testUser.id, { tenantId: 1 });
- const testDeliveryAddress = await testFactory.createTestDeliveryAddress(testUser.id, { tenantId: 1 });
- // 创建父商品
- const parentGoods = await testFactory.createTestGoods(testUser.id, {
- tenantId: 1,
- merchantId: testMerchant.id,
- supplierId: testSupplier.id,
- name: '限量版商品',
- price: 100.00,
- stock: 100
- });
- // 创建规格商品(子商品)- 库存较少
- const specGoods = await testFactory.createTestGoods(testUser.id, {
- tenantId: 1,
- merchantId: testMerchant.id,
- supplierId: testSupplier.id,
- name: '红色',
- spuId: parentGoods.id,
- price: 120.00,
- stock: 5 // 只有5件库存
- });
- // 尝试购买6件,超过库存数量
- const orderData = {
- addressId: testDeliveryAddress.id,
- productOwn: '自营',
- consumeFrom: '积分兑换',
- products: [
- { id: specGoods.id, num: 6 } // 库存只有5,尝试购买6件
- ]
- };
- const response = await client['create-order'].$post({
- json: orderData
- }, {
- headers: {
- 'Authorization': `Bearer ${userToken}`
- }
- });
- console.debug('库存不足订单创建响应状态码:', response.status);
- // 应该返回错误状态码(不是201),如400、422等
- expect(response.status).not.toBe(201);
- // 验证错误消息包含库存不足的信息
- if (response.status !== 201) {
- const errorResult = await response.json();
- console.debug('库存不足错误响应:', errorResult);
- // 错误响应结构为 { error: '商品 红色 库存不足' }
- expect(errorResult.error).toContain('库存');
- }
- });
- });
- describe('取消订单功能验证', () => {
- it('应该成功取消未支付订单', async () => {
- // 创建未支付订单
- const order = await testFactory.createTestOrder(testUser.id, {
- tenantId: 1,
- payState: 0, // 未支付
- state: 0
- });
- const cancelData = {
- orderId: order.id,
- reason: '用户主动取消'
- };
- const response = await client['cancel-order'].$post({
- json: cancelData
- }, {
- headers: {
- 'Authorization': `Bearer ${userToken}`
- }
- });
- expect(response.status).toBe(200);
- if (response.status === 200) {
- const result = await response.json();
- expect(result.success).toBe(true);
- expect(result.message).toBe('订单取消成功');
- }
- // 验证订单状态已更新
- const dataSource = await IntegrationTestDatabase.getDataSource();
- const updatedOrder = await dataSource.getRepository(OrderMt).findOne({
- where: { id: order.id, tenantId: 1 }
- });
- expect(updatedOrder?.payState).toBe(5); // 订单关闭
- expect(updatedOrder?.cancelReason).toBe('用户主动取消');
- expect(updatedOrder?.cancelTime).toBeInstanceOf(Date);
- });
- it('应该成功取消已支付订单', async () => {
- // 创建已支付订单
- const order = await testFactory.createTestOrder(testUser.id, {
- tenantId: 1,
- payState: 2, // 支付成功
- state: 0
- });
- const cancelData = {
- orderId: order.id,
- reason: '用户主动取消(已支付)'
- };
- const response = await client['cancel-order'].$post({
- json: cancelData
- }, {
- headers: {
- 'Authorization': `Bearer ${userToken}`
- }
- });
- expect(response.status).toBe(200);
- if (response.status === 200) {
- const result = await response.json();
- expect(result.success).toBe(true);
- expect(result.message).toBe('订单取消成功');
- }
- // 验证订单状态已更新
- const dataSource = await IntegrationTestDatabase.getDataSource();
- const updatedOrder = await dataSource.getRepository(OrderMt).findOne({
- where: { id: order.id, tenantId: 1 }
- });
- expect(updatedOrder?.payState).toBe(5); // 订单关闭
- expect(updatedOrder?.cancelReason).toBe('用户主动取消(已支付)');
- expect(updatedOrder?.cancelTime).toBeInstanceOf(Date);
- });
- it('应该拒绝取消不允许的订单状态', async () => {
- // 创建已发货订单(支付状态=2,订单状态=1)
- const order = await testFactory.createTestOrder(testUser.id, {
- tenantId: 1,
- payState: 2, // 支付成功
- state: 1 // 已发货
- });
- const cancelData = {
- orderId: order.id,
- reason: '尝试取消已发货订单'
- };
- const response = await client['cancel-order'].$post({
- json: cancelData
- }, {
- headers: {
- 'Authorization': `Bearer ${userToken}`
- }
- });
- // 应该返回403,因为已发货订单不允许取消
- expect(response.status).toBe(403);
- if (response.status === 403) {
- const result = await response.json();
- expect(result.message).toBe('当前订单状态不允许取消');
- }
- });
- it('应该拒绝取消不存在的订单', async () => {
- const cancelData = {
- orderId: 99999, // 不存在的订单ID
- reason: '取消不存在的订单'
- };
- const response = await client['cancel-order'].$post({
- json: cancelData
- }, {
- headers: {
- 'Authorization': `Bearer ${userToken}`
- }
- });
- // 应该返回404
- expect(response.status).toBe(404);
- if (response.status === 404) {
- const result = await response.json();
- expect(result.message).toBe('订单不存在');
- }
- });
- it('应该拒绝跨租户取消订单', async () => {
- // 创建租户2的订单
- const otherTenantOrder = await testFactory.createTestOrder(otherTenantUser.id, {
- tenantId: 2,
- payState: 0
- });
- const cancelData = {
- orderId: otherTenantOrder.id,
- reason: '跨租户取消尝试'
- };
- const response = await client['cancel-order'].$post({
- json: cancelData
- }, {
- headers: {
- 'Authorization': `Bearer ${userToken}`
- }
- });
- // 应该返回404,因为订单不在当前租户
- expect(response.status).toBe(404);
- if (response.status === 404) {
- const result = await response.json();
- expect(result.message).toBe('订单不存在');
- }
- });
- it('应该拒绝跨用户取消订单', async () => {
- // 创建其他用户的订单(同一租户)
- const otherUserOrder = await testFactory.createTestOrder(otherUser.id, {
- tenantId: 1,
- payState: 0
- });
- const cancelData = {
- orderId: otherUserOrder.id,
- reason: '跨用户取消尝试'
- };
- const response = await client['cancel-order'].$post({
- json: cancelData
- }, {
- headers: {
- 'Authorization': `Bearer ${userToken}`
- }
- });
- // 应该返回404,因为无权访问其他用户的订单
- expect(response.status).toBe(404);
- const result = await response.json();
- expect(result.message).toBe('订单不存在');
- });
- });
- describe('订单超时自动取消功能验证', () => {
- it('应该自动取消超过24小时未支付的订单', async () => {
- // 创建未支付订单,设置创建时间为25小时前
- const twentyFiveHoursAgo = new Date();
- twentyFiveHoursAgo.setHours(twentyFiveHoursAgo.getHours() - 25);
- const order = await testFactory.createTestOrder(testUser.id, {
- tenantId: 1,
- payState: 0, // 未支付
- state: 0,
- createdAt: twentyFiveHoursAgo,
- updatedAt: twentyFiveHoursAgo,
- expireTime: new Date() // 设置为当前时间,表示已过期
- });
- console.debug(`创建的超时订单: ID=${order.id}, createdAt=${order.createdAt}, expireTime=${order.expireTime}`);
- // 验证订单初始状态
- expect(order.payState).toBe(0);
- expect(order.state).toBe(0);
- // 创建调度器服务并手动触发超时订单处理
- const { OrderTimeoutSchedulerService } = await import('../../src/services/order-timeout-scheduler.service');
- const dataSource = await IntegrationTestDatabase.getDataSource();
- const schedulerService = new OrderTimeoutSchedulerService(dataSource, 1);
- const result = await schedulerService.triggerManualProcess(1);
- console.debug(`手动处理结果:`, result);
- expect(result.success).toBe(true);
- expect(result.processedOrders).toBe(1);
- expect(result.message).toContain('成功处理 1 个超时订单');
- // 验证订单状态已更新为取消
- const updatedOrder = await dataSource.getRepository(OrderMt).findOne({
- where: { id: order.id, tenantId: 1 }
- });
- expect(updatedOrder).toBeDefined();
- expect(updatedOrder?.payState).toBe(5); // 订单关闭
- expect(updatedOrder?.cancelReason).toBe('订单超时未支付,系统自动取消');
- expect(updatedOrder?.cancelTime).toBeInstanceOf(Date);
- });
- it('不应该取消未超过24小时的订单', async () => {
- // 创建未支付订单,设置创建时间为23小时前(未超过24小时)
- const twentyThreeHoursAgo = new Date();
- twentyThreeHoursAgo.setHours(twentyThreeHoursAgo.getHours() - 23);
- const order = await testFactory.createTestOrder(testUser.id, {
- tenantId: 1,
- payState: 0,
- state: 0,
- createdAt: twentyThreeHoursAgo,
- updatedAt: twentyThreeHoursAgo,
- expireTime: new Date(Date.now() + 3600000) // 1小时后过期
- });
- console.debug(`创建的未超时订单: ID=${order.id}, createdAt=${order.createdAt}, expireTime=${order.expireTime}`);
- // 创建调度器服务并手动触发超时订单处理
- const { OrderTimeoutSchedulerService } = await import('../../src/services/order-timeout-scheduler.service');
- const dataSource = await IntegrationTestDatabase.getDataSource();
- const schedulerService = new OrderTimeoutSchedulerService(dataSource, 1);
- const result = await schedulerService.triggerManualProcess(1);
- console.debug(`手动处理结果:`, result);
- // 应该没有处理任何订单
- expect(result.success).toBe(true);
- expect(result.processedOrders).toBe(0);
- expect(result.message).toContain('成功处理 0 个超时订单');
- // 验证订单状态未改变
- const updatedOrder = await dataSource.getRepository(OrderMt).findOne({
- where: { id: order.id, tenantId: 1 }
- });
- expect(updatedOrder).toBeDefined();
- expect(updatedOrder?.payState).toBe(0); // 保持未支付状态
- expect(updatedOrder?.cancelReason).toBeNull();
- expect(updatedOrder?.cancelTime).toBeNull();
- });
- it('不应该取消已支付的订单,即使超过24小时', async () => {
- // 创建已支付订单,设置创建时间为25小时前
- const twentyFiveHoursAgo = new Date();
- twentyFiveHoursAgo.setHours(twentyFiveHoursAgo.getHours() - 25);
- const order = await testFactory.createTestOrder(testUser.id, {
- tenantId: 1,
- payState: 2, // 支付成功
- state: 0,
- createdAt: twentyFiveHoursAgo,
- updatedAt: twentyFiveHoursAgo,
- expireTime: new Date() // 已过期
- });
- console.debug(`创建的已支付超时订单: ID=${order.id}, payState=${order.payState}, createdAt=${order.createdAt}`);
- // 创建调度器服务并手动触发超时订单处理
- const { OrderTimeoutSchedulerService } = await import('../../src/services/order-timeout-scheduler.service');
- const dataSource = await IntegrationTestDatabase.getDataSource();
- const schedulerService = new OrderTimeoutSchedulerService(dataSource, 1);
- const result = await schedulerService.triggerManualProcess(1);
- console.debug(`手动处理结果:`, result);
- // 应该没有处理已支付的订单
- expect(result.success).toBe(true);
- expect(result.processedOrders).toBe(0);
- expect(result.message).toContain('成功处理 0 个超时订单');
- // 验证订单状态未改变
- const updatedOrder = await dataSource.getRepository(OrderMt).findOne({
- where: { id: order.id, tenantId: 1 }
- });
- expect(updatedOrder).toBeDefined();
- expect(updatedOrder?.payState).toBe(2); // 保持支付成功状态
- expect(updatedOrder?.cancelReason).toBeNull();
- expect(updatedOrder?.cancelTime).toBeNull();
- });
- it('不应该取消已发货的订单,即使超过24小时未支付', async () => {
- // 创建已发货订单,设置创建时间为25小时前
- const twentyFiveHoursAgo = new Date();
- twentyFiveHoursAgo.setHours(twentyFiveHoursAgo.getHours() - 25);
- const order = await testFactory.createTestOrder(testUser.id, {
- tenantId: 1,
- payState: 0, // 未支付
- state: 1, // 已发货
- createdAt: twentyFiveHoursAgo,
- updatedAt: twentyFiveHoursAgo,
- expireTime: new Date() // 已过期
- });
- console.debug(`创建的已发货超时订单: ID=${order.id}, state=${order.state}, createdAt=${order.createdAt}`);
- // 创建调度器服务并手动触发超时订单处理
- const { OrderTimeoutSchedulerService } = await import('../../src/services/order-timeout-scheduler.service');
- const dataSource = await IntegrationTestDatabase.getDataSource();
- const schedulerService = new OrderTimeoutSchedulerService(dataSource, 1);
- const result = await schedulerService.triggerManualProcess(1);
- console.debug(`手动处理结果:`, result);
- // 应该没有处理已发货的订单
- expect(result.success).toBe(true);
- expect(result.processedOrders).toBe(0);
- expect(result.message).toContain('成功处理 0 个超时订单');
- // 验证订单状态未改变
- const updatedOrder = await dataSource.getRepository(OrderMt).findOne({
- where: { id: order.id, tenantId: 1 }
- });
- expect(updatedOrder).toBeDefined();
- expect(updatedOrder?.payState).toBe(0); // 保持未支付状态
- expect(updatedOrder?.state).toBe(1); // 保持已发货状态
- expect(updatedOrder?.cancelReason).toBeNull();
- expect(updatedOrder?.cancelTime).toBeNull();
- });
- it('应该恢复未支付超时订单的商品库存', async () => {
- // 创建测试商品
- const testGoods = await testFactory.createTestGoods(testUser.id, {
- tenantId: 1,
- stock: 100,
- salesNum: 0
- });
- // 创建未支付订单,设置创建时间为25小时前
- const twentyFiveHoursAgo = new Date();
- twentyFiveHoursAgo.setHours(twentyFiveHoursAgo.getHours() - 25);
- const order = await testFactory.createTestOrder(testUser.id, {
- tenantId: 1,
- payState: 0,
- state: 0,
- createdAt: twentyFiveHoursAgo,
- updatedAt: twentyFiveHoursAgo,
- expireTime: new Date()
- });
- // 创建订单商品记录
- const orderGoods = await testFactory.createTestOrderGoods(order.id, testGoods.id, {
- tenantId: 1,
- num: 2
- });
- console.debug(`创建带商品的超时订单: orderId=${order.id}, goodsId=${testGoods.id}, num=${orderGoods.num}`);
- // 获取商品初始库存
- const dataSource = await IntegrationTestDatabase.getDataSource();
- const goodsRepository = dataSource.getRepository(GoodsMt);
- const initialGoods = await goodsRepository.findOne({
- where: { id: testGoods.id, tenantId: 1 }
- });
- console.debug(`商品初始库存: stock=${initialGoods?.stock}, salesNum=${initialGoods?.salesNum}`);
- // 模拟订单创建时的库存减少:在真实订单创建流程中,库存会减少,销售量会增加
- // 这里我们手动更新库存,模拟订单创建后的状态
- await goodsRepository.update(
- { id: testGoods.id, tenantId: 1 },
- {
- stock: () => `stock - ${orderGoods.num}`,
- salesNum: () => `sales_num + ${orderGoods.num}`
- }
- );
- // 验证库存已减少
- const afterOrderCreationGoods = await goodsRepository.findOne({
- where: { id: testGoods.id, tenantId: 1 }
- });
- console.debug(`订单创建后商品库存: stock=${afterOrderCreationGoods?.stock}, salesNum=${afterOrderCreationGoods?.salesNum}`);
- // 创建调度器服务并手动触发超时订单处理
- const { OrderTimeoutSchedulerService } = await import('../../src/services/order-timeout-scheduler.service');
- const schedulerService = new OrderTimeoutSchedulerService(dataSource, 1);
- const result = await schedulerService.triggerManualProcess(1);
- console.debug(`手动处理结果:`, result);
- expect(result.success).toBe(true);
- expect(result.processedOrders).toBe(1);
- // 验证商品库存已恢复(取消订单后库存应恢复到初始值)
- const updatedGoods = await goodsRepository.findOne({
- where: { id: testGoods.id, tenantId: 1 }
- });
- console.debug(`订单取消后商品库存: stock=${updatedGoods?.stock}, salesNum=${updatedGoods?.salesNum}`);
- expect(updatedGoods).toBeDefined();
- // 库存应该恢复到100(初始值)
- expect(Number(updatedGoods?.stock)).toBe(100);
- // 销售量应该恢复到0(初始值)
- expect(Number(updatedGoods?.salesNum)).toBe(0);
- });
- it('应该支持跨租户订单超时处理', async () => {
- // 创建租户1的超时订单
- const twentyFiveHoursAgo = new Date();
- twentyFiveHoursAgo.setHours(twentyFiveHoursAgo.getHours() - 25);
- const tenant1Order = await testFactory.createTestOrder(testUser.id, {
- tenantId: 1,
- payState: 0,
- state: 0,
- createdAt: twentyFiveHoursAgo,
- updatedAt: twentyFiveHoursAgo,
- expireTime: new Date()
- });
- // 创建租户2的超时订单
- const tenant2Order = await testFactory.createTestOrder(otherTenantUser.id, {
- tenantId: 2,
- payState: 0,
- state: 0,
- createdAt: twentyFiveHoursAgo,
- updatedAt: twentyFiveHoursAgo,
- expireTime: new Date()
- });
- console.debug(`跨租户测试: 租户1订单ID=${tenant1Order.id}, 租户2订单ID=${tenant2Order.id}`);
- // 创建调度器服务(tenantId = null,处理所有租户)
- const { OrderTimeoutSchedulerService } = await import('../../src/services/order-timeout-scheduler.service');
- const dataSource = await IntegrationTestDatabase.getDataSource();
- const schedulerService = new OrderTimeoutSchedulerService(dataSource); // 不指定租户ID
- // 获取所有有超时订单的租户
- const tenantIds = await (schedulerService as any).getTenantsWithTimeoutOrders();
- console.debug(`有超时订单的租户:`, tenantIds);
- // 应该包含两个租户
- expect(tenantIds).toContain(1);
- expect(tenantIds).toContain(2);
- expect(tenantIds.length).toBeGreaterThanOrEqual(2);
- // 手动处理租户1的超时订单
- const result1 = await schedulerService.triggerManualProcess(1);
- console.debug(`租户1处理结果:`, result1);
- expect(result1.success).toBe(true);
- expect(result1.processedOrders).toBe(1);
- // 验证租户1订单已取消
- const updatedTenant1Order = await dataSource.getRepository(OrderMt).findOne({
- where: { id: tenant1Order.id, tenantId: 1 }
- });
- expect(updatedTenant1Order?.payState).toBe(5);
- // 手动处理租户2的超时订单
- const result2 = await schedulerService.triggerManualProcess(2);
- console.debug(`租户2处理结果:`, result2);
- expect(result2.success).toBe(true);
- expect(result2.processedOrders).toBe(1);
- // 验证租户2订单已取消
- const updatedTenant2Order = await dataSource.getRepository(OrderMt).findOne({
- where: { id: tenant2Order.id, tenantId: 2 }
- });
- expect(updatedTenant2Order?.payState).toBe(5);
- });
- });
- });
|