|
|
@@ -0,0 +1,1037 @@
|
|
|
+import { describe, it, expect, beforeEach } from 'vitest';
|
|
|
+import { testClient } from 'hono/testing';
|
|
|
+import { IntegrationTestDatabase, setupIntegrationDatabaseHooksWithEntities } from '@d8d/shared-test-util';
|
|
|
+import { UserEntityMt, RoleMt } from '@d8d/core-module-mt/user-module-mt/entities';
|
|
|
+import { FileMt } from '@d8d/core-module-mt/file-module-mt/entities';
|
|
|
+import { OrderMt, OrderGoodsMt, OrderRefundMt } from '@d8d/orders-module-mt';
|
|
|
+import { PayStatus, PayType } from '@d8d/orders-module-mt';
|
|
|
+import { MerchantMt } from '@d8d/merchant-module-mt';
|
|
|
+import { SupplierMt } from '@d8d/supplier-module-mt';
|
|
|
+import { DeliveryAddressMt } from '@d8d/delivery-address-module-mt';
|
|
|
+import { AreaEntityMt } from '@d8d/geo-areas-mt';
|
|
|
+import { SystemConfigMt } from '@d8d/core-module-mt/system-config-module-mt/entities';
|
|
|
+import { GoodsMt, GoodsCategoryMt } from '@d8d/goods-module-mt';
|
|
|
+import creditBalanceRoutes from '../../src/routes';
|
|
|
+import { CreditBalanceMt, CreditBalanceLogMt, CreditBalanceChangeType } from '../../src/entities';
|
|
|
+import { CreditBalanceTestDataFactory } from '../utils/test-data-factory';
|
|
|
+
|
|
|
+// 设置集成测试钩子
|
|
|
+setupIntegrationDatabaseHooksWithEntities([
|
|
|
+ UserEntityMt, RoleMt, FileMt, CreditBalanceMt, CreditBalanceLogMt, OrderMt, OrderGoodsMt, OrderRefundMt,
|
|
|
+ MerchantMt, SupplierMt, DeliveryAddressMt, AreaEntityMt, SystemConfigMt, GoodsMt, GoodsCategoryMt
|
|
|
+])
|
|
|
+
|
|
|
+describe('多租户信用额度API集成测试', () => {
|
|
|
+ let client: ReturnType<typeof testClient<typeof creditBalanceRoutes>>;
|
|
|
+ let userToken: string;
|
|
|
+ let adminToken: string;
|
|
|
+ let otherTenantUserToken: string;
|
|
|
+ let testUser: UserEntityMt;
|
|
|
+ let otherUser: UserEntityMt;
|
|
|
+ let otherTenantUser: UserEntityMt;
|
|
|
+
|
|
|
+ beforeEach(async () => {
|
|
|
+ // 创建测试客户端
|
|
|
+ client = testClient(creditBalanceRoutes);
|
|
|
+
|
|
|
+ // 获取数据源并创建测试用户
|
|
|
+ const dataSource = await IntegrationTestDatabase.getDataSource();
|
|
|
+
|
|
|
+ // 创建租户1的测试用户
|
|
|
+ testUser = await CreditBalanceTestDataFactory.createTestUser(dataSource, 1);
|
|
|
+ otherUser = await CreditBalanceTestDataFactory.createTestUser(dataSource, 1);
|
|
|
+
|
|
|
+ // 创建租户2的测试用户
|
|
|
+ otherTenantUser = await CreditBalanceTestDataFactory.createTestUser(dataSource, 2);
|
|
|
+
|
|
|
+ // 生成JWT令牌
|
|
|
+ userToken = CreditBalanceTestDataFactory.generateUserToken(testUser);
|
|
|
+ adminToken = CreditBalanceTestDataFactory.generateAdminToken(1);
|
|
|
+ otherTenantUserToken = CreditBalanceTestDataFactory.generateUserToken(otherTenantUser);
|
|
|
+ });
|
|
|
+
|
|
|
+ describe('查询用户信用额度', () => {
|
|
|
+ it('应该返回404当用户信用额度记录不存在时', async () => {
|
|
|
+ const response = await client[':userId'].$get({
|
|
|
+ param: { userId: '9999' }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${userToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(404);
|
|
|
+ if (response.status === 404) {
|
|
|
+ const data = await response.json();
|
|
|
+ expect(data.message).toBe('用户信用额度记录不存在');
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it('应该返回用户的信用额度', async () => {
|
|
|
+ // 先创建信用额度记录
|
|
|
+ const dataSource = await IntegrationTestDatabase.getDataSource();
|
|
|
+ const creditBalanceRepo = dataSource.getRepository(CreditBalanceMt);
|
|
|
+ await creditBalanceRepo.save({
|
|
|
+ tenantId: 1,
|
|
|
+ userId: testUser.id,
|
|
|
+ totalLimit: 10000.00, // 明确使用小数形式
|
|
|
+ usedAmount: 0.00,
|
|
|
+ isEnabled: 1
|
|
|
+ });
|
|
|
+
|
|
|
+ const response = await client[':userId'].$get({
|
|
|
+ param: { userId: testUser.id.toString() }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${userToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(200);
|
|
|
+ if (response.status === 200) {
|
|
|
+ const data = await response.json();
|
|
|
+ expect(data.id).toBeDefined();
|
|
|
+ expect(data.tenantId).toBe(1);
|
|
|
+ expect(data.userId).toBe(testUser.id);
|
|
|
+
|
|
|
+ // 验证金额字段的类型(应该是数字,不是字符串)
|
|
|
+ expect(typeof data.totalLimit).toBe('number');
|
|
|
+ expect(typeof data.usedAmount).toBe('number');
|
|
|
+ expect(typeof data.availableAmount).toBe('number');
|
|
|
+
|
|
|
+ // 验证金额值
|
|
|
+ expect(data.totalLimit).toBe(10000);
|
|
|
+ expect(data.availableAmount).toBe(10000);
|
|
|
+
|
|
|
+ // 验证可以安全调用toFixed方法
|
|
|
+ expect(() => data.totalLimit.toFixed(2)).not.toThrow();
|
|
|
+ expect(() => data.usedAmount.toFixed(2)).not.toThrow();
|
|
|
+ expect(() => data.availableAmount.toFixed(2)).not.toThrow();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ describe('查询当前用户信用额度 (/me)', () => {
|
|
|
+ it('应该返回404当当前用户信用额度记录不存在时', async () => {
|
|
|
+ const response = await client.me.$get({}, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${userToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(404);
|
|
|
+ if (response.status === 404) {
|
|
|
+ const data = await response.json();
|
|
|
+ expect(data.message).toBe('用户信用额度记录不存在');
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it('应该返回当前用户的信用额度', async () => {
|
|
|
+ // 先创建信用额度记录
|
|
|
+ const dataSource = await IntegrationTestDatabase.getDataSource();
|
|
|
+ const creditBalanceRepo = dataSource.getRepository(CreditBalanceMt);
|
|
|
+ await creditBalanceRepo.save({
|
|
|
+ tenantId: 1,
|
|
|
+ userId: testUser.id,
|
|
|
+ totalLimit: 8000.00,
|
|
|
+ usedAmount: 2000.00,
|
|
|
+ isEnabled: 1
|
|
|
+ });
|
|
|
+
|
|
|
+ const response = await client.me.$get({}, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${userToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(200);
|
|
|
+ if (response.status === 200) {
|
|
|
+ const data = await response.json();
|
|
|
+ expect(data.id).toBeDefined();
|
|
|
+ expect(data.tenantId).toBe(1);
|
|
|
+ expect(data.userId).toBe(testUser.id);
|
|
|
+
|
|
|
+ // 验证金额字段的类型(应该是数字,不是字符串)
|
|
|
+ expect(typeof data.totalLimit).toBe('number');
|
|
|
+ expect(typeof data.usedAmount).toBe('number');
|
|
|
+ expect(typeof data.availableAmount).toBe('number');
|
|
|
+
|
|
|
+ // 验证金额值
|
|
|
+ expect(data.totalLimit).toBe(8000);
|
|
|
+ expect(data.usedAmount).toBe(2000);
|
|
|
+ expect(data.availableAmount).toBe(6000);
|
|
|
+
|
|
|
+ // 验证可以安全调用toFixed方法
|
|
|
+ expect(() => data.totalLimit.toFixed(2)).not.toThrow();
|
|
|
+ expect(() => data.usedAmount.toFixed(2)).not.toThrow();
|
|
|
+ expect(() => data.availableAmount.toFixed(2)).not.toThrow();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it('应该正确计算可用额度', async () => {
|
|
|
+ // 先创建信用额度记录
|
|
|
+ const dataSource = await IntegrationTestDatabase.getDataSource();
|
|
|
+ const creditBalanceRepo = dataSource.getRepository(CreditBalanceMt);
|
|
|
+ await creditBalanceRepo.save({
|
|
|
+ tenantId: 1,
|
|
|
+ userId: testUser.id,
|
|
|
+ totalLimit: 5000.00,
|
|
|
+ usedAmount: 1500.00,
|
|
|
+ isEnabled: 1
|
|
|
+ });
|
|
|
+
|
|
|
+ const response = await client.me.$get({}, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${userToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(200);
|
|
|
+ if (response.status === 200) {
|
|
|
+ const data = await response.json();
|
|
|
+ expect(data.availableAmount).toBe(3500); // 5000 - 1500
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ describe('设置用户信用额度', () => {
|
|
|
+ it('应该成功设置用户信用额度', async () => {
|
|
|
+ const response = await client[':userId'].$put({
|
|
|
+ param: { userId: testUser.id.toString() },
|
|
|
+ json: {
|
|
|
+ totalLimit: 5000,
|
|
|
+ operatorId: 1,
|
|
|
+ remark: '初始设置额度'
|
|
|
+ }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${adminToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(200);
|
|
|
+ if (response.status === 200) {
|
|
|
+ const data = await response.json();
|
|
|
+ expect(data.totalLimit).toBe(5000);
|
|
|
+ expect(data.availableAmount).toBe(5000);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ describe('调整用户信用额度', () => {
|
|
|
+ it('应该成功调整用户信用额度', async () => {
|
|
|
+ // 先创建信用额度记录
|
|
|
+ const dataSource = await IntegrationTestDatabase.getDataSource();
|
|
|
+ const creditBalanceRepo = dataSource.getRepository(CreditBalanceMt);
|
|
|
+ await creditBalanceRepo.save({
|
|
|
+ tenantId: 1,
|
|
|
+ userId: testUser.id,
|
|
|
+ totalLimit: 10000.00, // 明确使用小数形式
|
|
|
+ usedAmount: 0.00,
|
|
|
+ isEnabled: 1
|
|
|
+ });
|
|
|
+
|
|
|
+ const response = await client[':userId'].adjust.$post({
|
|
|
+ param: { userId: testUser.id.toString() },
|
|
|
+ json: {
|
|
|
+ adjustAmount: 2000,
|
|
|
+ operatorId: 1,
|
|
|
+ remark: '增加额度'
|
|
|
+ }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${adminToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(200);
|
|
|
+ if (response.status === 200) {
|
|
|
+ const data = await response.json();
|
|
|
+ expect(data.totalLimit).toBeCloseTo(12000, 2); // 10000 + 2000,允许2位小数误差
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ describe('额度支付', () => {
|
|
|
+ it('应该成功扣减额度', async () => {
|
|
|
+ // 先创建信用额度记录
|
|
|
+ const dataSource = await IntegrationTestDatabase.getDataSource();
|
|
|
+ const creditBalanceRepo = dataSource.getRepository(CreditBalanceMt);
|
|
|
+ await creditBalanceRepo.save({
|
|
|
+ tenantId: 1,
|
|
|
+ userId: testUser.id,
|
|
|
+ totalLimit: 10000.00, // 明确使用小数形式
|
|
|
+ usedAmount: 0.00,
|
|
|
+ isEnabled: 1
|
|
|
+ });
|
|
|
+
|
|
|
+ // 创建测试订单
|
|
|
+ const merchant = await CreditBalanceTestDataFactory.createTestMerchant(dataSource, 1, testUser.id);
|
|
|
+ const supplier = await CreditBalanceTestDataFactory.createTestSupplier(dataSource, 1, testUser.id);
|
|
|
+ const address = await CreditBalanceTestDataFactory.createTestDeliveryAddress(dataSource, 1, testUser.id);
|
|
|
+
|
|
|
+ const testOrder = await CreditBalanceTestDataFactory.createTestOrder(
|
|
|
+ dataSource,
|
|
|
+ 1,
|
|
|
+ testUser.id,
|
|
|
+ merchant.id,
|
|
|
+ supplier.id,
|
|
|
+ address.id,
|
|
|
+ {
|
|
|
+ orderNo: 'TEST_ORDER_003',
|
|
|
+ amount: 500.00,
|
|
|
+ payAmount: 500.00,
|
|
|
+ payState: PayStatus.UNPAID
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ const response = await client.payment.$post({
|
|
|
+ json: {
|
|
|
+ referenceId: testOrder.id.toString(), // 使用订单ID
|
|
|
+ operatorId: 1,
|
|
|
+ remark: '订单支付'
|
|
|
+ }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${userToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(200);
|
|
|
+ if (response.status === 200) {
|
|
|
+ const data = await response.json();
|
|
|
+ expect(data.usedAmount).toBeCloseTo(500, 2);
|
|
|
+ expect(data.availableAmount).toBeCloseTo(9500, 2); // 10000 - 500
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it('应该成功扣减额度并更新订单状态', async () => {
|
|
|
+ // 先创建信用额度记录
|
|
|
+ const dataSource = await IntegrationTestDatabase.getDataSource();
|
|
|
+ const creditBalanceRepo = dataSource.getRepository(CreditBalanceMt);
|
|
|
+ await creditBalanceRepo.save({
|
|
|
+ tenantId: 1,
|
|
|
+ userId: testUser.id,
|
|
|
+ totalLimit: 10000.00,
|
|
|
+ usedAmount: 0.00,
|
|
|
+ isEnabled: 1
|
|
|
+ });
|
|
|
+
|
|
|
+ // 使用测试数据工厂创建商户、供货商、地址和订单
|
|
|
+ const merchant = await CreditBalanceTestDataFactory.createTestMerchant(dataSource, 1, testUser.id);
|
|
|
+ const supplier = await CreditBalanceTestDataFactory.createTestSupplier(dataSource, 1, testUser.id);
|
|
|
+ const address = await CreditBalanceTestDataFactory.createTestDeliveryAddress(dataSource, 1, testUser.id);
|
|
|
+
|
|
|
+ const testOrder = await CreditBalanceTestDataFactory.createTestOrder(
|
|
|
+ dataSource,
|
|
|
+ 1,
|
|
|
+ testUser.id,
|
|
|
+ merchant.id,
|
|
|
+ supplier.id,
|
|
|
+ address.id,
|
|
|
+ {
|
|
|
+ orderNo: 'TEST_ORDER_001',
|
|
|
+ amount: 500.00,
|
|
|
+ payAmount: 500.00,
|
|
|
+ payState: PayStatus.UNPAID
|
|
|
+ }
|
|
|
+ );
|
|
|
+ const orderRepo = dataSource.getRepository(OrderMt);
|
|
|
+
|
|
|
+ const response = await client.payment.$post({
|
|
|
+ json: {
|
|
|
+ amount: 500.00,
|
|
|
+ referenceId: testOrder.id.toString(), // 使用订单ID作为referenceId
|
|
|
+ operatorId: 1,
|
|
|
+ remark: '订单支付'
|
|
|
+ }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${userToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(200);
|
|
|
+ if (response.status === 200) {
|
|
|
+ const data = await response.json();
|
|
|
+ expect(data.usedAmount).toBeCloseTo(500, 2);
|
|
|
+ expect(data.availableAmount).toBeCloseTo(9500, 2);
|
|
|
+
|
|
|
+ // 验证订单状态已更新
|
|
|
+ const updatedOrder = await orderRepo.findOne({
|
|
|
+ where: { id: testOrder.id, tenantId: 1 }
|
|
|
+ });
|
|
|
+ expect(updatedOrder).toBeDefined();
|
|
|
+ expect(updatedOrder!.payState).toBe(PayStatus.SUCCESS);
|
|
|
+ expect(updatedOrder!.payType).toBe(PayType.CREDIT);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it('额度扣减失败时应该回滚订单状态更新', async () => {
|
|
|
+ // 先创建信用额度记录,但设置较低的额度
|
|
|
+ const dataSource = await IntegrationTestDatabase.getDataSource();
|
|
|
+ const creditBalanceRepo = dataSource.getRepository(CreditBalanceMt);
|
|
|
+ await creditBalanceRepo.save({
|
|
|
+ tenantId: 1,
|
|
|
+ userId: testUser.id,
|
|
|
+ totalLimit: 100.00, // 只有100额度
|
|
|
+ usedAmount: 0.00,
|
|
|
+ isEnabled: 1
|
|
|
+ });
|
|
|
+
|
|
|
+ // 使用测试数据工厂创建商户、供货商、地址和订单
|
|
|
+ const merchant = await CreditBalanceTestDataFactory.createTestMerchant(dataSource, 1, testUser.id);
|
|
|
+ const supplier = await CreditBalanceTestDataFactory.createTestSupplier(dataSource, 1, testUser.id);
|
|
|
+ const address = await CreditBalanceTestDataFactory.createTestDeliveryAddress(dataSource, 1, testUser.id);
|
|
|
+
|
|
|
+ const testOrder = await CreditBalanceTestDataFactory.createTestOrder(
|
|
|
+ dataSource,
|
|
|
+ 1,
|
|
|
+ testUser.id,
|
|
|
+ merchant.id,
|
|
|
+ supplier.id,
|
|
|
+ address.id,
|
|
|
+ {
|
|
|
+ orderNo: 'TEST_ORDER_002',
|
|
|
+ amount: 500.00, // 订单金额500,超过额度
|
|
|
+ payAmount: 500.00,
|
|
|
+ payState: PayStatus.UNPAID
|
|
|
+ }
|
|
|
+ );
|
|
|
+ const orderRepo = dataSource.getRepository(OrderMt);
|
|
|
+
|
|
|
+ const response = await client.payment.$post({
|
|
|
+ json: {
|
|
|
+ amount: 500.00,
|
|
|
+ referenceId: testOrder.id.toString(),
|
|
|
+ operatorId: 1,
|
|
|
+ remark: '订单支付'
|
|
|
+ }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${userToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 应该返回错误,因为额度不足
|
|
|
+ expect(response.status).toBe(500);
|
|
|
+
|
|
|
+ // 验证订单状态未更新
|
|
|
+ const updatedOrder = await orderRepo.findOne({
|
|
|
+ where: { id: testOrder.id, tenantId: 1 }
|
|
|
+ });
|
|
|
+ expect(updatedOrder).toBeDefined();
|
|
|
+ expect(updatedOrder!.payState).toBe(PayStatus.UNPAID); // 仍然是未支付状态
|
|
|
+ expect(updatedOrder!.payType).toBe(0); // 支付类型未改变
|
|
|
+ });
|
|
|
+
|
|
|
+ it('应该拒绝支付已支付成功的订单', async () => {
|
|
|
+ // 先创建信用额度记录
|
|
|
+ const dataSource = await IntegrationTestDatabase.getDataSource();
|
|
|
+ const creditBalanceRepo = dataSource.getRepository(CreditBalanceMt);
|
|
|
+ await creditBalanceRepo.save({
|
|
|
+ tenantId: 1,
|
|
|
+ userId: testUser.id,
|
|
|
+ totalLimit: 10000.00,
|
|
|
+ usedAmount: 0.00,
|
|
|
+ isEnabled: 1
|
|
|
+ });
|
|
|
+
|
|
|
+ // 创建已支付成功的测试订单
|
|
|
+ const merchant = await CreditBalanceTestDataFactory.createTestMerchant(dataSource, 1, testUser.id);
|
|
|
+ const supplier = await CreditBalanceTestDataFactory.createTestSupplier(dataSource, 1, testUser.id);
|
|
|
+ const address = await CreditBalanceTestDataFactory.createTestDeliveryAddress(dataSource, 1, testUser.id);
|
|
|
+
|
|
|
+ const testOrder = await CreditBalanceTestDataFactory.createTestOrder(
|
|
|
+ dataSource,
|
|
|
+ 1,
|
|
|
+ testUser.id,
|
|
|
+ merchant.id,
|
|
|
+ supplier.id,
|
|
|
+ address.id,
|
|
|
+ {
|
|
|
+ orderNo: 'TEST_ORDER_004',
|
|
|
+ amount: 500.00,
|
|
|
+ payAmount: 500.00,
|
|
|
+ payState: PayStatus.SUCCESS, // 已支付成功
|
|
|
+ payType: PayType.CREDIT
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ const response = await client.payment.$post({
|
|
|
+ json: {
|
|
|
+ referenceId: testOrder.id.toString(),
|
|
|
+ operatorId: 1,
|
|
|
+ remark: '订单支付'
|
|
|
+ }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${userToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 应该返回错误,因为订单已支付成功
|
|
|
+ expect(response.status).toBe(400);
|
|
|
+ if (response.status === 400) {
|
|
|
+ const data = await response.json();
|
|
|
+ expect(data.message).toContain('订单已支付成功');
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it('应该拒绝支付不存在的订单', async () => {
|
|
|
+ // 先创建信用额度记录
|
|
|
+ const dataSource = await IntegrationTestDatabase.getDataSource();
|
|
|
+ const creditBalanceRepo = dataSource.getRepository(CreditBalanceMt);
|
|
|
+ await creditBalanceRepo.save({
|
|
|
+ tenantId: 1,
|
|
|
+ userId: testUser.id,
|
|
|
+ totalLimit: 10000.00,
|
|
|
+ usedAmount: 0.00,
|
|
|
+ isEnabled: 1
|
|
|
+ });
|
|
|
+
|
|
|
+ const response = await client.payment.$post({
|
|
|
+ json: {
|
|
|
+ referenceId: '99999', // 不存在的订单ID
|
|
|
+ operatorId: 1,
|
|
|
+ remark: '订单支付'
|
|
|
+ }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${userToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 应该返回404错误
|
|
|
+ expect(response.status).toBe(404);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('应该拒绝支付无效的订单ID', async () => {
|
|
|
+ // 先创建信用额度记录
|
|
|
+ const dataSource = await IntegrationTestDatabase.getDataSource();
|
|
|
+ const creditBalanceRepo = dataSource.getRepository(CreditBalanceMt);
|
|
|
+ await creditBalanceRepo.save({
|
|
|
+ tenantId: 1,
|
|
|
+ userId: testUser.id,
|
|
|
+ totalLimit: 10000.00,
|
|
|
+ usedAmount: 0.00,
|
|
|
+ isEnabled: 1
|
|
|
+ });
|
|
|
+
|
|
|
+ const response = await client.payment.$post({
|
|
|
+ json: {
|
|
|
+ referenceId: 'invalid-order-id', // 无效的订单ID格式
|
|
|
+ operatorId: 1,
|
|
|
+ remark: '订单支付'
|
|
|
+ }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${userToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 应该返回400错误
|
|
|
+ expect(response.status).toBe(400);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('应该拒绝支付金额为0的订单', async () => {
|
|
|
+ // 先创建信用额度记录
|
|
|
+ const dataSource = await IntegrationTestDatabase.getDataSource();
|
|
|
+ const creditBalanceRepo = dataSource.getRepository(CreditBalanceMt);
|
|
|
+ await creditBalanceRepo.save({
|
|
|
+ tenantId: 1,
|
|
|
+ userId: testUser.id,
|
|
|
+ totalLimit: 10000.00,
|
|
|
+ usedAmount: 0.00,
|
|
|
+ isEnabled: 1
|
|
|
+ });
|
|
|
+
|
|
|
+ // 创建支付金额为0的测试订单
|
|
|
+ const merchant = await CreditBalanceTestDataFactory.createTestMerchant(dataSource, 1, testUser.id);
|
|
|
+ const supplier = await CreditBalanceTestDataFactory.createTestSupplier(dataSource, 1, testUser.id);
|
|
|
+ const address = await CreditBalanceTestDataFactory.createTestDeliveryAddress(dataSource, 1, testUser.id);
|
|
|
+
|
|
|
+ const testOrder = await CreditBalanceTestDataFactory.createTestOrder(
|
|
|
+ dataSource,
|
|
|
+ 1,
|
|
|
+ testUser.id,
|
|
|
+ merchant.id,
|
|
|
+ supplier.id,
|
|
|
+ address.id,
|
|
|
+ {
|
|
|
+ orderNo: 'TEST_ORDER_005',
|
|
|
+ amount: 0.00,
|
|
|
+ payAmount: 0.00, // 支付金额为0
|
|
|
+ payState: PayStatus.UNPAID
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ const response = await client.payment.$post({
|
|
|
+ json: {
|
|
|
+ referenceId: testOrder.id.toString(),
|
|
|
+ operatorId: 1,
|
|
|
+ remark: '订单支付'
|
|
|
+ }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${userToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 应该返回400错误
|
|
|
+ expect(response.status).toBe(400);
|
|
|
+ if (response.status === 400) {
|
|
|
+ const data = await response.json();
|
|
|
+ expect(data.message).toContain('订单支付金额无效');
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it('应该成功扣减额度当用户已有欠款时', async () => {
|
|
|
+ // 先创建信用额度记录,用户已有欠款
|
|
|
+ const dataSource = await IntegrationTestDatabase.getDataSource();
|
|
|
+ const creditBalanceRepo = dataSource.getRepository(CreditBalanceMt);
|
|
|
+ await creditBalanceRepo.save({
|
|
|
+ tenantId: 1,
|
|
|
+ userId: testUser.id,
|
|
|
+ totalLimit: 1000.00,
|
|
|
+ usedAmount: 198.01, // 用户已有欠款
|
|
|
+ isEnabled: 1
|
|
|
+ });
|
|
|
+
|
|
|
+ // 创建测试订单
|
|
|
+ const merchant = await CreditBalanceTestDataFactory.createTestMerchant(dataSource, 1, testUser.id);
|
|
|
+ const supplier = await CreditBalanceTestDataFactory.createTestSupplier(dataSource, 1, testUser.id);
|
|
|
+ const address = await CreditBalanceTestDataFactory.createTestDeliveryAddress(dataSource, 1, testUser.id);
|
|
|
+
|
|
|
+ const testOrder = await CreditBalanceTestDataFactory.createTestOrder(
|
|
|
+ dataSource,
|
|
|
+ 1,
|
|
|
+ testUser.id,
|
|
|
+ merchant.id,
|
|
|
+ supplier.id,
|
|
|
+ address.id,
|
|
|
+ {
|
|
|
+ orderNo: 'TEST_ORDER_006',
|
|
|
+ amount: 99.00,
|
|
|
+ payAmount: 99.00,
|
|
|
+ payState: PayStatus.UNPAID
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ const response = await client.payment.$post({
|
|
|
+ json: {
|
|
|
+ referenceId: testOrder.id.toString(),
|
|
|
+ operatorId: 1,
|
|
|
+ remark: '订单支付'
|
|
|
+ }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${userToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(200);
|
|
|
+ if (response.status === 200) {
|
|
|
+ const data = await response.json();
|
|
|
+ // 已用额度应该是 198.01 + 99.00 = 297.01
|
|
|
+ expect(data.usedAmount).toBeCloseTo(297.01, 2);
|
|
|
+ // 可用额度应该是 1000.00 - 297.01 = 702.99
|
|
|
+ expect(data.availableAmount).toBeCloseTo(702.99, 2);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it('应该正确处理decimal字段的字符串类型', async () => {
|
|
|
+ // 测试TypeORM decimal字段返回字符串的情况
|
|
|
+ // 先创建信用额度记录,使用字符串格式的金额
|
|
|
+ const dataSource = await IntegrationTestDatabase.getDataSource();
|
|
|
+ const creditBalanceRepo = dataSource.getRepository(CreditBalanceMt);
|
|
|
+
|
|
|
+ // 直接使用SQL插入,模拟TypeORM返回字符串的情况
|
|
|
+ await dataSource.query(`
|
|
|
+ INSERT INTO credit_balance_mt (tenant_id, user_id, total_limit, used_amount, is_enabled)
|
|
|
+ VALUES (1, $1, '500.00', '150.75', 1)
|
|
|
+ `, [testUser.id]);
|
|
|
+
|
|
|
+ // 创建测试订单,使用字符串格式的金额
|
|
|
+ const merchant = await CreditBalanceTestDataFactory.createTestMerchant(dataSource, 1, testUser.id);
|
|
|
+ const supplier = await CreditBalanceTestDataFactory.createTestSupplier(dataSource, 1, testUser.id);
|
|
|
+ const address = await CreditBalanceTestDataFactory.createTestDeliveryAddress(dataSource, 1, testUser.id);
|
|
|
+
|
|
|
+ const testOrder = await CreditBalanceTestDataFactory.createTestOrder(
|
|
|
+ dataSource,
|
|
|
+ 1,
|
|
|
+ testUser.id,
|
|
|
+ merchant.id,
|
|
|
+ supplier.id,
|
|
|
+ address.id,
|
|
|
+ {
|
|
|
+ orderNo: 'TEST_ORDER_007',
|
|
|
+ amount: 50.25,
|
|
|
+ payAmount: 50.25,
|
|
|
+ payState: PayStatus.UNPAID
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ const response = await client.payment.$post({
|
|
|
+ json: {
|
|
|
+ referenceId: testOrder.id.toString(),
|
|
|
+ operatorId: 1,
|
|
|
+ remark: '订单支付'
|
|
|
+ }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${userToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(200);
|
|
|
+ if (response.status === 200) {
|
|
|
+ const data = await response.json();
|
|
|
+ // 已用额度应该是 150.75 + 50.25 = 201.00
|
|
|
+ expect(data.usedAmount).toBeCloseTo(201.00, 2);
|
|
|
+ // 可用额度应该是 500.00 - 201.00 = 299.00
|
|
|
+ expect(data.availableAmount).toBeCloseTo(299.00, 2);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it('应该拒绝支付其他用户的订单(越权访问防护)', async () => {
|
|
|
+ // 先为testUser创建信用额度记录
|
|
|
+ const dataSource = await IntegrationTestDatabase.getDataSource();
|
|
|
+ const creditBalanceRepo = dataSource.getRepository(CreditBalanceMt);
|
|
|
+ await creditBalanceRepo.save({
|
|
|
+ tenantId: 1,
|
|
|
+ userId: testUser.id,
|
|
|
+ totalLimit: 10000.00,
|
|
|
+ usedAmount: 0.00,
|
|
|
+ isEnabled: 1
|
|
|
+ });
|
|
|
+
|
|
|
+ // 为otherUser创建信用额度记录
|
|
|
+ await creditBalanceRepo.save({
|
|
|
+ tenantId: 1,
|
|
|
+ userId: otherUser.id,
|
|
|
+ totalLimit: 5000.00,
|
|
|
+ usedAmount: 0.00,
|
|
|
+ isEnabled: 1
|
|
|
+ });
|
|
|
+
|
|
|
+ // 为otherUser创建测试订单(注意:订单的用户ID是otherUser.id)
|
|
|
+ const merchant = await CreditBalanceTestDataFactory.createTestMerchant(dataSource, 1, otherUser.id);
|
|
|
+ const supplier = await CreditBalanceTestDataFactory.createTestSupplier(dataSource, 1, otherUser.id);
|
|
|
+ const address = await CreditBalanceTestDataFactory.createTestDeliveryAddress(dataSource, 1, otherUser.id);
|
|
|
+
|
|
|
+ const otherUserOrder = await CreditBalanceTestDataFactory.createTestOrder(
|
|
|
+ dataSource,
|
|
|
+ 1,
|
|
|
+ otherUser.id, // 这是关键:订单属于otherUser
|
|
|
+ merchant.id,
|
|
|
+ supplier.id,
|
|
|
+ address.id,
|
|
|
+ {
|
|
|
+ orderNo: 'OTHER_USER_ORDER',
|
|
|
+ amount: 300.00,
|
|
|
+ payAmount: 300.00,
|
|
|
+ payState: PayStatus.UNPAID
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ // testUser尝试支付otherUser的订单
|
|
|
+ const response = await client.payment.$post({
|
|
|
+ json: {
|
|
|
+ referenceId: otherUserOrder.id.toString(),
|
|
|
+ operatorId: 1,
|
|
|
+ remark: '尝试支付其他用户的订单'
|
|
|
+ }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${userToken}` // testUser的token
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 应该返回404,因为订单查询会失败(userId不匹配)
|
|
|
+ expect(response.status).toBe(404);
|
|
|
+ if (response.status === 404) {
|
|
|
+ const data = await response.json();
|
|
|
+ expect(data.message).toContain('订单不存在或无权访问');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证订单状态没有改变
|
|
|
+ const orderRepo = dataSource.getRepository(OrderMt);
|
|
|
+ const orderAfterAttempt = await orderRepo.findOne({
|
|
|
+ where: { id: otherUserOrder.id }
|
|
|
+ });
|
|
|
+ expect(orderAfterAttempt).toBeDefined();
|
|
|
+ expect(orderAfterAttempt!.payState).toBe(PayStatus.UNPAID); // 应该还是未支付状态
|
|
|
+ });
|
|
|
+
|
|
|
+ it('应该拒绝跨租户支付订单(租户隔离防护)', async () => {
|
|
|
+ // 为otherTenantUser创建信用额度记录(租户2)
|
|
|
+ const dataSource = await IntegrationTestDatabase.getDataSource();
|
|
|
+ const creditBalanceRepo = dataSource.getRepository(CreditBalanceMt);
|
|
|
+ await creditBalanceRepo.save({
|
|
|
+ tenantId: 2,
|
|
|
+ userId: otherTenantUser.id,
|
|
|
+ totalLimit: 8000.00,
|
|
|
+ usedAmount: 0.00,
|
|
|
+ isEnabled: 1
|
|
|
+ });
|
|
|
+
|
|
|
+ // 为otherTenantUser创建测试订单(租户2)
|
|
|
+ const merchant = await CreditBalanceTestDataFactory.createTestMerchant(dataSource, 2, otherTenantUser.id);
|
|
|
+ const supplier = await CreditBalanceTestDataFactory.createTestSupplier(dataSource, 2, otherTenantUser.id);
|
|
|
+ const address = await CreditBalanceTestDataFactory.createTestDeliveryAddress(dataSource, 2, otherTenantUser.id);
|
|
|
+
|
|
|
+ const otherTenantOrder = await CreditBalanceTestDataFactory.createTestOrder(
|
|
|
+ dataSource,
|
|
|
+ 2, // 租户2
|
|
|
+ otherTenantUser.id,
|
|
|
+ merchant.id,
|
|
|
+ supplier.id,
|
|
|
+ address.id,
|
|
|
+ {
|
|
|
+ orderNo: 'OTHER_TENANT_ORDER',
|
|
|
+ amount: 400.00,
|
|
|
+ payAmount: 400.00,
|
|
|
+ payState: PayStatus.UNPAID
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ // testUser(租户1)尝试支付otherTenantUser(租户2)的订单
|
|
|
+ const response = await client.payment.$post({
|
|
|
+ json: {
|
|
|
+ referenceId: otherTenantOrder.id.toString(),
|
|
|
+ operatorId: 1,
|
|
|
+ remark: '尝试支付其他租户的订单'
|
|
|
+ }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${userToken}` // 租户1的用户
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 应该返回404,因为租户ID不匹配
|
|
|
+ expect(response.status).toBe(404);
|
|
|
+ if (response.status === 404) {
|
|
|
+ const data = await response.json();
|
|
|
+ expect(data.message).toContain('订单不存在或无权访问');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证订单状态没有改变
|
|
|
+ const orderRepo = dataSource.getRepository(OrderMt);
|
|
|
+ const orderAfterAttempt = await orderRepo.findOne({
|
|
|
+ where: { id: otherTenantOrder.id }
|
|
|
+ });
|
|
|
+ expect(orderAfterAttempt).toBeDefined();
|
|
|
+ expect(orderAfterAttempt!.payState).toBe(PayStatus.UNPAID);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('应该正确处理订单状态更新时的用户ID验证', async () => {
|
|
|
+ // 这个测试验证订单状态更新也包含用户ID检查
|
|
|
+ // 先创建信用额度记录
|
|
|
+ const dataSource = await IntegrationTestDatabase.getDataSource();
|
|
|
+ const creditBalanceRepo = dataSource.getRepository(CreditBalanceMt);
|
|
|
+ await creditBalanceRepo.save({
|
|
|
+ tenantId: 1,
|
|
|
+ userId: testUser.id,
|
|
|
+ totalLimit: 10000.00,
|
|
|
+ usedAmount: 0.00,
|
|
|
+ isEnabled: 1
|
|
|
+ });
|
|
|
+
|
|
|
+ // 创建测试订单
|
|
|
+ const merchant = await CreditBalanceTestDataFactory.createTestMerchant(dataSource, 1, testUser.id);
|
|
|
+ const supplier = await CreditBalanceTestDataFactory.createTestSupplier(dataSource, 1, testUser.id);
|
|
|
+ const address = await CreditBalanceTestDataFactory.createTestDeliveryAddress(dataSource, 1, testUser.id);
|
|
|
+
|
|
|
+ const testOrder = await CreditBalanceTestDataFactory.createTestOrder(
|
|
|
+ dataSource,
|
|
|
+ 1,
|
|
|
+ testUser.id,
|
|
|
+ merchant.id,
|
|
|
+ supplier.id,
|
|
|
+ address.id,
|
|
|
+ {
|
|
|
+ orderNo: 'USER_ID_VALIDATION_ORDER',
|
|
|
+ amount: 250.00,
|
|
|
+ payAmount: 250.00,
|
|
|
+ payState: PayStatus.UNPAID
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ // 正常支付应该成功
|
|
|
+ const response = await client.payment.$post({
|
|
|
+ json: {
|
|
|
+ referenceId: testOrder.id.toString(),
|
|
|
+ operatorId: 1,
|
|
|
+ remark: '正常支付测试用户ID验证'
|
|
|
+ }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${userToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(200);
|
|
|
+ if (response.status === 200) {
|
|
|
+ const data = await response.json();
|
|
|
+ expect(data.usedAmount).toBeCloseTo(250, 2);
|
|
|
+
|
|
|
+ // 验证订单状态已更新
|
|
|
+ const orderRepo = dataSource.getRepository(OrderMt);
|
|
|
+ const updatedOrder = await orderRepo.findOne({
|
|
|
+ where: { id: testOrder.id }
|
|
|
+ });
|
|
|
+ expect(updatedOrder).toBeDefined();
|
|
|
+ expect(updatedOrder!.payState).toBe(PayStatus.SUCCESS);
|
|
|
+ expect(updatedOrder!.payType).toBe(PayType.CREDIT);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ describe('结账恢复额度', () => {
|
|
|
+ it('应该成功恢复额度', async () => {
|
|
|
+ // 先创建信用额度记录并扣减
|
|
|
+ const dataSource = await IntegrationTestDatabase.getDataSource();
|
|
|
+ const creditBalanceRepo = dataSource.getRepository(CreditBalanceMt);
|
|
|
+ await creditBalanceRepo.save({
|
|
|
+ tenantId: 1,
|
|
|
+ userId: testUser.id,
|
|
|
+ totalLimit: 10000,
|
|
|
+ usedAmount: 500, // 已使用500
|
|
|
+ isEnabled: 1
|
|
|
+ });
|
|
|
+
|
|
|
+ const response = await client.checkout.$post({
|
|
|
+ json: {
|
|
|
+ userId: testUser.id,
|
|
|
+ amount: 300.00,
|
|
|
+ referenceId: 'ORD202412010001',
|
|
|
+ operatorId: 1,
|
|
|
+ remark: '结账恢复'
|
|
|
+ }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${adminToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(200);
|
|
|
+ if (response.status === 200) {
|
|
|
+ const data = await response.json();
|
|
|
+ expect(data.usedAmount).toBe(200); // 500 - 300
|
|
|
+ expect(data.availableAmount).toBe(9800); // 10000 - 200
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ describe('查询额度变更记录', () => {
|
|
|
+ it('应该返回额度变更记录', async () => {
|
|
|
+ // 先创建信用额度记录和变更记录
|
|
|
+ const dataSource = await IntegrationTestDatabase.getDataSource();
|
|
|
+ const creditBalanceRepo = dataSource.getRepository(CreditBalanceMt);
|
|
|
+ const creditBalanceLogRepo = dataSource.getRepository(CreditBalanceLogMt);
|
|
|
+
|
|
|
+ await creditBalanceRepo.save({
|
|
|
+ tenantId: 1,
|
|
|
+ userId: testUser.id,
|
|
|
+ totalLimit: 10000,
|
|
|
+ usedAmount: 500,
|
|
|
+ isEnabled: 1
|
|
|
+ });
|
|
|
+
|
|
|
+ await creditBalanceLogRepo.save({
|
|
|
+ tenantId: 1,
|
|
|
+ userId: testUser.id,
|
|
|
+ changeType: CreditBalanceChangeType.PAYMENT,
|
|
|
+ changeAmount: -500,
|
|
|
+ beforeTotal: 10000,
|
|
|
+ afterTotal: 10000,
|
|
|
+ beforeUsed: 0,
|
|
|
+ afterUsed: 500,
|
|
|
+ referenceId: 'ORD202412010001',
|
|
|
+ operatorId: 1,
|
|
|
+ remark: '订单支付'
|
|
|
+ });
|
|
|
+
|
|
|
+ const response = await client[':userId'].logs.$get({
|
|
|
+ param: { userId: testUser.id.toString() },
|
|
|
+ query: { page: 1, pageSize: 10 }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${userToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(200);
|
|
|
+ if (response.status === 200) {
|
|
|
+ const data = await response.json();
|
|
|
+ expect(data.data).toHaveLength(1);
|
|
|
+
|
|
|
+ const log = data.data[0];
|
|
|
+
|
|
|
+ // 验证变更记录金额字段的类型(应该是数字,不是字符串)
|
|
|
+ expect(typeof log.changeAmount).toBe('number');
|
|
|
+ expect(typeof log.beforeTotal).toBe('number');
|
|
|
+ expect(typeof log.afterTotal).toBe('number');
|
|
|
+ expect(typeof log.beforeUsed).toBe('number');
|
|
|
+ expect(typeof log.afterUsed).toBe('number');
|
|
|
+
|
|
|
+ // 验证金额值
|
|
|
+ expect(log.changeAmount).toBeCloseTo(-500, 2);
|
|
|
+ expect(log.beforeTotal).toBeCloseTo(10000, 2);
|
|
|
+ expect(log.afterTotal).toBeCloseTo(10000, 2);
|
|
|
+ expect(log.beforeUsed).toBeCloseTo(0, 2);
|
|
|
+ expect(log.afterUsed).toBeCloseTo(500, 2);
|
|
|
+
|
|
|
+ // 验证可以安全调用toFixed方法
|
|
|
+ expect(() => log.changeAmount.toFixed(2)).not.toThrow();
|
|
|
+ expect(() => log.beforeTotal.toFixed(2)).not.toThrow();
|
|
|
+ expect(() => log.afterTotal.toFixed(2)).not.toThrow();
|
|
|
+ expect(() => log.beforeUsed.toFixed(2)).not.toThrow();
|
|
|
+ expect(() => log.afterUsed.toFixed(2)).not.toThrow();
|
|
|
+
|
|
|
+ expect(data.pagination.total).toBe(1);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ describe('租户数据隔离验证', () => {
|
|
|
+ it('应该只能访问自己租户的信用额度', async () => {
|
|
|
+ // 创建租户1的信用额度记录
|
|
|
+ const dataSource = await IntegrationTestDatabase.getDataSource();
|
|
|
+ const creditBalanceRepo = dataSource.getRepository(CreditBalanceMt);
|
|
|
+ await creditBalanceRepo.save({
|
|
|
+ tenantId: 1,
|
|
|
+ userId: testUser.id,
|
|
|
+ totalLimit: 10000,
|
|
|
+ usedAmount: 0,
|
|
|
+ isEnabled: 1
|
|
|
+ });
|
|
|
+
|
|
|
+ // 创建租户2的信用额度记录
|
|
|
+ await creditBalanceRepo.save({
|
|
|
+ tenantId: 2,
|
|
|
+ userId: otherTenantUser.id,
|
|
|
+ totalLimit: 5000,
|
|
|
+ usedAmount: 0,
|
|
|
+ isEnabled: 1
|
|
|
+ });
|
|
|
+
|
|
|
+ // 使用租户1的用户查询
|
|
|
+ const response = await client[':userId'].$get({
|
|
|
+ param: { userId: testUser.id.toString() }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${userToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(200);
|
|
|
+ if (response.status === 200) {
|
|
|
+ const data = await response.json();
|
|
|
+ expect(data.tenantId).toBe(1);
|
|
|
+ expect(data.userId).toBe(testUser.id);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+});
|